From dc9b1333fe05b998695e94b905c53c6521498f47 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sun, 25 Nov 2018 21:26:19 +0000 Subject: Fix [509cafafae]: ttk::treeview tag options ignored in 8.6.9 --- generic/ttk/ttkTreeview.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/generic/ttk/ttkTreeview.c b/generic/ttk/ttkTreeview.c index bef84f3..a1ee325 100644 --- a/generic/ttk/ttkTreeview.c +++ b/generic/ttk/ttkTreeview.c @@ -1709,8 +1709,17 @@ static void PrepareItem( Ttk_Style style = Ttk_LayoutStyle(tv->core.layout); Ttk_State state = ItemState(tv, item); - Ttk_TagSetValues(tv->tree.tagTable, item->tagset, displayItem); - Ttk_TagSetApplyStyle(tv->tree.tagTable, style, state, displayItem); + /* + * Tag options have precedence over the style, unless in selected state. + */ + + if (state & TTK_STATE_SELECTED) { + Ttk_TagSetValues(tv->tree.tagTable, item->tagset, displayItem); + Ttk_TagSetApplyStyle(tv->tree.tagTable, style, state, displayItem); + } else { + Ttk_TagSetApplyStyle(tv->tree.tagTable, style, state, displayItem); + Ttk_TagSetValues(tv->tree.tagTable, item->tagset, displayItem); + } } /* + DrawCells -- -- cgit v0.12 From 23de751222730f4e3b2e403c433e7c94f400ee8e Mon Sep 17 00:00:00 2001 From: fvogel Date: Sun, 25 Nov 2018 21:38:18 +0000 Subject: Document precedence between tags and style, and priority order of tags. --- doc/ttk_treeview.n | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/ttk_treeview.n b/doc/ttk_treeview.n index b81bc62..6cb801e 100644 --- a/doc/ttk_treeview.n +++ b/doc/ttk_treeview.n @@ -432,8 +432,12 @@ Specifies the font to use when drawing text. .\" ??? Maybe: .IP \-text .IP \fB\-image\fR Specifies the item image, in case the item's \fB\-image\fR option is empty. -.\" .PP -.\" \fI(@@@ TODO: sort out order of precedence for options)\fR +.PP +Tag options \fB\-foreground\fR and \fB\-background\fR take precedence over +the style, except in the \fBselected\fR state. +.PP +Tag priority is decided by the creation order: tags created first receive +higher priority. .SH "COLUMN IDENTIFIERS" .PP Column identifiers take any of the following forms: -- cgit v0.12 From 9d46acafed8ba7109f4c1b49eff4b12b7009f1fc Mon Sep 17 00:00:00 2001 From: fvogel Date: Tue, 1 Jan 2019 16:30:11 +0000 Subject: Better fix for [509cafafae]: ttk::treeview tag options ignored in 8.6.9. This solution was suggested by cjmcdonald: Revert [d378ad72], partially revert [07b0114e] (keep documentation of tag priority order), and remove the {!disabled !selected} statespec from the -background and -foreground state map of the ttk::treeview since they are not needed and provide regressions. --- doc/ttk_treeview.n | 5 ++--- generic/ttk/ttkTreeview.c | 13 ++----------- library/ttk/altTheme.tcl | 2 -- library/ttk/aquaTheme.tcl | 2 -- library/ttk/clamTheme.tcl | 2 -- library/ttk/classicTheme.tcl | 2 -- library/ttk/defaults.tcl | 2 -- library/ttk/vistaTheme.tcl | 2 -- library/ttk/winTheme.tcl | 2 -- library/ttk/xpTheme.tcl | 2 -- 10 files changed, 4 insertions(+), 30 deletions(-) diff --git a/doc/ttk_treeview.n b/doc/ttk_treeview.n index 6cb801e..96565a3 100644 --- a/doc/ttk_treeview.n +++ b/doc/ttk_treeview.n @@ -432,9 +432,8 @@ Specifies the font to use when drawing text. .\" ??? Maybe: .IP \-text .IP \fB\-image\fR Specifies the item image, in case the item's \fB\-image\fR option is empty. -.PP -Tag options \fB\-foreground\fR and \fB\-background\fR take precedence over -the style, except in the \fBselected\fR state. +.\" .PP +.\" \fI(@@@ TODO: sort out order of precedence for options)\fR .PP Tag priority is decided by the creation order: tags created first receive higher priority. diff --git a/generic/ttk/ttkTreeview.c b/generic/ttk/ttkTreeview.c index a1ee325..bef84f3 100644 --- a/generic/ttk/ttkTreeview.c +++ b/generic/ttk/ttkTreeview.c @@ -1709,17 +1709,8 @@ static void PrepareItem( Ttk_Style style = Ttk_LayoutStyle(tv->core.layout); Ttk_State state = ItemState(tv, item); - /* - * Tag options have precedence over the style, unless in selected state. - */ - - if (state & TTK_STATE_SELECTED) { - Ttk_TagSetValues(tv->tree.tagTable, item->tagset, displayItem); - Ttk_TagSetApplyStyle(tv->tree.tagTable, style, state, displayItem); - } else { - Ttk_TagSetApplyStyle(tv->tree.tagTable, style, state, displayItem); - Ttk_TagSetValues(tv->tree.tagTable, item->tagset, displayItem); - } + Ttk_TagSetValues(tv->tree.tagTable, item->tagset, displayItem); + Ttk_TagSetApplyStyle(tv->tree.tagTable, style, state, displayItem); } /* + DrawCells -- diff --git a/library/ttk/altTheme.tcl b/library/ttk/altTheme.tcl index 6fc76f8..80ef415 100644 --- a/library/ttk/altTheme.tcl +++ b/library/ttk/altTheme.tcl @@ -96,10 +96,8 @@ namespace eval ttk::theme::alt { ttk::style configure Treeview -background $colors(-window) ttk::style map Treeview \ -background [list disabled $colors(-frame)\ - {!disabled !selected} $colors(-window) \ selected $colors(-selectbg)] \ -foreground [list disabled $colors(-disabledfg) \ - {!disabled !selected} black \ selected $colors(-selectfg)] ttk::style configure TScale \ diff --git a/library/ttk/aquaTheme.tcl b/library/ttk/aquaTheme.tcl index d6be5a3..a548d65 100644 --- a/library/ttk/aquaTheme.tcl +++ b/library/ttk/aquaTheme.tcl @@ -42,11 +42,9 @@ namespace eval ttk::theme::aqua { ttk::style configure Treeview -rowheight 18 -background White ttk::style map Treeview \ -background [list disabled systemDialogBackgroundInactive \ - {!disabled !selected} systemWindowBody \ {selected background} systemHighlightSecondary \ selected systemHighlight] \ -foreground [list disabled systemModelessDialogInactiveText \ - {!disabled !selected} black \ selected systemModelessDialogActiveText] # Enable animation for ttk::progressbar widget: diff --git a/library/ttk/clamTheme.tcl b/library/ttk/clamTheme.tcl index 3c6f5c3..6935fc7 100644 --- a/library/ttk/clamTheme.tcl +++ b/library/ttk/clamTheme.tcl @@ -132,10 +132,8 @@ namespace eval ttk::theme::clam { ttk::style configure Treeview -background $colors(-window) ttk::style map Treeview \ -background [list disabled $colors(-frame)\ - {!disabled !selected} $colors(-window) \ selected $colors(-selectbg)] \ -foreground [list disabled $colors(-disabledfg) \ - {!disabled !selected} black \ selected $colors(-selectfg)] ttk::style configure TLabelframe \ diff --git a/library/ttk/classicTheme.tcl b/library/ttk/classicTheme.tcl index fefdb99..f237fba 100644 --- a/library/ttk/classicTheme.tcl +++ b/library/ttk/classicTheme.tcl @@ -99,10 +99,8 @@ namespace eval ttk::theme::classic { ttk::style configure Treeview -background $colors(-window) ttk::style map Treeview \ -background [list disabled $colors(-frame)\ - {!disabled !selected} $colors(-window) \ selected $colors(-selectbg)] \ -foreground [list disabled $colors(-disabledfg) \ - {!disabled !selected} black \ selected $colors(-selectfg)] # diff --git a/library/ttk/defaults.tcl b/library/ttk/defaults.tcl index 4c1753d..a15d1d9 100644 --- a/library/ttk/defaults.tcl +++ b/library/ttk/defaults.tcl @@ -111,10 +111,8 @@ namespace eval ttk::theme::default { -foreground $colors(-text) ; ttk::style map Treeview \ -background [list disabled $colors(-frame)\ - {!disabled !selected} $colors(-window) \ selected $colors(-selectbg)] \ -foreground [list disabled $colors(-disabledfg) \ - {!disabled !selected} black \ selected $colors(-selectfg)] # Combobox popdown frame diff --git a/library/ttk/vistaTheme.tcl b/library/ttk/vistaTheme.tcl index ecb39c9..094288c 100644 --- a/library/ttk/vistaTheme.tcl +++ b/library/ttk/vistaTheme.tcl @@ -48,10 +48,8 @@ namespace eval ttk::theme::vista { ttk::style configure Treeview -background SystemWindow ttk::style map Treeview \ -background [list disabled SystemButtonFace \ - {!disabled !selected} SystemWindow \ selected SystemHighlight] \ -foreground [list disabled SystemGrayText \ - {!disabled !selected} SystemWindowText \ selected SystemHighlightText] # Label and Toolbutton diff --git a/library/ttk/winTheme.tcl b/library/ttk/winTheme.tcl index a7a2c79..db05b45 100644 --- a/library/ttk/winTheme.tcl +++ b/library/ttk/winTheme.tcl @@ -74,10 +74,8 @@ namespace eval ttk::theme::winnative { ttk::style configure Treeview -background SystemWindow ttk::style map Treeview \ -background [list disabled SystemButtonFace \ - {!disabled !selected} SystemWindow \ selected SystemHighlight] \ -foreground [list disabled SystemGrayText \ - {!disabled !selected} SystemWindowText \ selected SystemHighlightText] ttk::style configure TProgressbar \ diff --git a/library/ttk/xpTheme.tcl b/library/ttk/xpTheme.tcl index 5d8d09b..4c4f680 100644 --- a/library/ttk/xpTheme.tcl +++ b/library/ttk/xpTheme.tcl @@ -67,10 +67,8 @@ namespace eval ttk::theme::xpnative { ttk::style configure Treeview -background SystemWindow ttk::style map Treeview \ -background [list disabled SystemButtonFace \ - {!disabled !selected} SystemWindow \ selected SystemHighlight] \ -foreground [list disabled SystemGrayText \ - {!disabled !selected} SystemWindowText \ selected SystemHighlightText]; } } -- cgit v0.12 From 79864b3cecd15cecaaeeded2d301de7b1d96511c Mon Sep 17 00:00:00 2001 From: fvogel Date: Sat, 5 Jan 2019 20:55:12 +0000 Subject: Fix [3003895fff] and [1899040fff]: TkRoundToResolution doesn't account for -from --- generic/tkScale.c | 56 ++++++++++++++++++++++++++++++++++-------------------- generic/tkScale.h | 3 ++- tests/scale.test | 46 ++++++++++++++++++++++++++++++++------------ unix/tkUnixScale.c | 8 ++++---- 4 files changed, 75 insertions(+), 38 deletions(-) diff --git a/generic/tkScale.c b/generic/tkScale.c index af45afa..547f698 100644 --- a/generic/tkScale.c +++ b/generic/tkScale.c @@ -611,7 +611,7 @@ ConfigureScale( TCL_GLOBAL_ONLY); if ((valuePtr != NULL) && (Tcl_GetDoubleFromObj(NULL, valuePtr, &value) == TCL_OK)) { - scalePtr->value = TkRoundToResolution(scalePtr, value); + scalePtr->value = TkRoundValueToResolution(scalePtr, value); } } @@ -620,10 +620,10 @@ ConfigureScale( * orientation and creating GCs. */ - scalePtr->fromValue = TkRoundToResolution(scalePtr, + scalePtr->fromValue = TkRoundValueToResolution(scalePtr, scalePtr->fromValue); - scalePtr->toValue = TkRoundToResolution(scalePtr, scalePtr->toValue); - scalePtr->tickInterval = TkRoundToResolution(scalePtr, + scalePtr->toValue = TkRoundValueToResolution(scalePtr, scalePtr->toValue); + scalePtr->tickInterval = TkRoundIntervalToResolution(scalePtr, scalePtr->tickInterval); /* @@ -1119,10 +1119,14 @@ TkEventuallyRedrawScale( /* *-------------------------------------------------------------- * - * TkRoundToResolution -- + * TkRoundValueToResolution, TkRoundIntervalToResolution -- * * Round a given floating-point value to the nearest multiple of the * scale's resolution. + * TkRoundValueToResolution rounds an absolute value based on the from + * value as a reference. + * TkRoundIntervalToResolution rounds a relative value without + * reference, i.e. it rounds an interval. * * Results: * The return value is the rounded result. @@ -1134,28 +1138,38 @@ TkEventuallyRedrawScale( */ double -TkRoundToResolution( +TkRoundValueToResolution( TkScale *scalePtr, /* Information about scale widget. */ double value) /* Value to round. */ { - double rem, rounded, tick; + double rem, start; if (scalePtr->resolution <= 0) { return value; } - tick = floor(value/scalePtr->resolution); - rounded = scalePtr->resolution * tick; - rem = value - rounded; + start = fmod(scalePtr->fromValue, scalePtr->resolution); + rem = fmod(value - start + scalePtr->resolution/2, scalePtr->resolution); if (rem < 0) { - if (rem <= -scalePtr->resolution/2) { - rounded = (tick - 1.0) * scalePtr->resolution; - } - } else { - if (rem >= scalePtr->resolution/2) { - rounded = (tick + 1.0) * scalePtr->resolution; - } + rem += scalePtr->resolution; + } + return value + scalePtr->resolution/2 - rem; +} + +double +TkRoundIntervalToResolution( + TkScale *scalePtr, /* Information about scale widget. */ + double value) /* Value to round. */ +{ + double rem; + + if (scalePtr->resolution <= 0) { + return value; + } + rem = fmod(value + scalePtr->resolution/2, scalePtr->resolution); + if (rem < 0) { + rem += scalePtr->resolution; } - return rounded; + return value + scalePtr->resolution/2 - rem; } /* @@ -1238,7 +1252,7 @@ ScaleVarProc( resultStr = "can't assign non-numeric value to scale variable"; ScaleSetVariable(scalePtr); } else { - scalePtr->value = TkRoundToResolution(scalePtr, value); + scalePtr->value = TkRoundValueToResolution(scalePtr, value); /* * This code is a bit tricky because it sets the scale's value before @@ -1282,7 +1296,7 @@ TkScaleSetValue( int invokeCommand) /* Non-zero means invoked -command option to * notify of new value, 0 means don't. */ { - value = TkRoundToResolution(scalePtr, value); + value = TkRoundValueToResolution(scalePtr, value); if ((value < scalePtr->fromValue) ^ (scalePtr->toValue < scalePtr->fromValue)) { value = scalePtr->fromValue; @@ -1402,7 +1416,7 @@ TkScalePixelToValue( } value = scalePtr->fromValue + value * (scalePtr->toValue - scalePtr->fromValue); - return TkRoundToResolution(scalePtr, value); + return TkRoundValueToResolution(scalePtr, value); } /* diff --git a/generic/tkScale.h b/generic/tkScale.h index aa0feff..6756e73 100644 --- a/generic/tkScale.h +++ b/generic/tkScale.h @@ -219,7 +219,8 @@ typedef struct TkScale { */ MODULE_SCOPE void TkEventuallyRedrawScale(TkScale *scalePtr, int what); -MODULE_SCOPE double TkRoundToResolution(TkScale *scalePtr, double value); +MODULE_SCOPE double TkRoundValueToResolution(TkScale *scalePtr, double value); +MODULE_SCOPE double TkRoundIntervalToResolution(TkScale *scalePtr, double value); MODULE_SCOPE TkScale * TkpCreateScale(Tk_Window tkwin); MODULE_SCOPE void TkpDestroyScale(TkScale *scalePtr); MODULE_SCOPE void TkpDisplayScale(ClientData clientData); diff --git a/tests/scale.test b/tests/scale.test index 79524eb..6344eef 100644 --- a/tests/scale.test +++ b/tests/scale.test @@ -1104,78 +1104,78 @@ test scale-13.6 {SetScaleValue procedure} -body { destroy .s pack [scale .s] update -test scale-14.1 {RoundToResolution procedure} -body { +test scale-14.1 {RoundValueToResolution procedure} -body { .s configure -from 0 -to 100 -sliderlength 10 -length 114 -bd 2 \ -orient horizontal -resolution 4.0 update .s get 84 152 } -result 72 -test scale-14.2 {RoundToResolution procedure} -body { +test scale-14.2 {RoundValueToResolution procedure} -body { .s configure -from 0 -to 100 -sliderlength 10 -length 114 -bd 2 \ -orient horizontal -resolution 4.0 update .s get 86 152 } -result 76 -test scale-14.3 {RoundToResolution procedure} -body { +test scale-14.3 {RoundValueToResolution procedure} -body { .s configure -from 100 -to 0 -sliderlength 10 -length 114 -bd 2 \ -orient horizontal -resolution 4.0 update .s get 84 152 } -result 28 -test scale-14.4 {RoundToResolution procedure} -body { +test scale-14.4 {RoundValueToResolution procedure} -body { .s configure -from 100 -to 0 -sliderlength 10 -length 114 -bd 2 \ -orient horizontal -resolution 4.0 update .s get 86 152 } -result 24 -test scale-14.5 {RoundToResolution procedure} -body { +test scale-14.5 {RoundValueToResolution procedure} -body { .s configure -from -100 -to 0 -sliderlength 10 -length 114 -bd 2 \ -orient horizontal -resolution 4.0 update .s get 84 152 } -result {-28} -test scale-14.6 {RoundToResolution procedure} -body { +test scale-14.6 {RoundValueToResolution procedure} -body { .s configure -from -100 -to 0 -sliderlength 10 -length 114 -bd 2 \ -orient horizontal -resolution 4.0 update .s get 86 152 } -result {-24} -test scale-14.7 {RoundToResolution procedure} -body { +test scale-14.7 {RoundValueToResolution procedure} -body { .s configure -from 0 -to -100 -sliderlength 10 -length 114 -bd 2 \ -orient horizontal -resolution 4.0 update .s get 84 152 } -result {-72} -test scale-14.8 {RoundToResolution procedure} -body { +test scale-14.8 {RoundValueToResolution procedure} -body { .s configure -from 0 -to -100 -sliderlength 10 -length 114 -bd 2 \ -orient horizontal -resolution 4.0 update .s get 86 152 } -result {-76} -test scale-14.9 {RoundToResolution procedure} -body { +test scale-14.9 {RoundValueToResolution procedure} -body { .s configure -from 0 -to 2.25 -sliderlength 10 -length 114 -bd 2 \ -orient horizontal -resolution 0 update .s get 84 152 } -result {1.64} -test scale-14.10 {RoundToResolution procedure} -body { +test scale-14.10 {RoundValueToResolution procedure} -body { .s configure -from 0 -to 2.25 -sliderlength 10 -length 114 -bd 2 \ -orient horizontal -resolution 0 update .s get 86 152 } -result {1.69} -test scale-14.11 {RoundToResolution procedure} -body { +test scale-14.11 {RoundValueToResolution procedure} -body { .s configure -from 0 -to 225 -sliderlength 10 -length 114 -bd 2 \ -orient horizontal -resolution 0 -digits 5 update .s get 84 152 } -result {164.25} -test scale-14.12 {RoundToResolution procedure} -body { +test scale-14.12 {RoundValueToResolution procedure} -body { .s configure -from 0 -to 225 -sliderlength 10 -length 114 -bd 2 \ -orient horizontal -resolution 0 -digits 5 update @@ -1183,6 +1183,28 @@ test scale-14.12 {RoundToResolution procedure} -body { } -result {168.75} destroy .s +test scale-14a.1 {RoundValueToResolution, RoundIntervalToResolution procedures} -setup { + pack [scale .s -orient horizontal] + update +} -body { + .s configure -length 400 -bd 0 -from 1 -to 9 -resolution 2 -tickinterval 1 + update + .s get 200 0 +} -cleanup { + destroy .s +} -result {5} +test scale-14a.2 {RoundValueToResolution, RoundIntervalToResolution procedures} -setup { + pack [scale .s -orient horizontal] + update +} -body { + .s configure -length 400 -bd 0 -from -1.5 -to 1.5 -resolution 1 \ + -tickinterval 1 -digits 2 + update + .s get 250 0 +} -cleanup { + destroy .s +} -result {0.5} + test scale-15.1 {ScaleVarProc procedure} -setup { deleteWindows diff --git a/unix/tkUnixScale.c b/unix/tkUnixScale.c index 8f88018..2009288 100644 --- a/unix/tkUnixScale.c +++ b/unix/tkUnixScale.c @@ -150,11 +150,11 @@ DisplayVerticalScale( for (tickValue = scalePtr->fromValue; ; tickValue += tickInterval) { /* - * The TkRoundToResolution call gets rid of accumulated + * The TkRoundValueToResolution call gets rid of accumulated * round-off errors, if any. */ - tickValue = TkRoundToResolution(scalePtr, tickValue); + tickValue = TkRoundValueToResolution(scalePtr, tickValue); if (scalePtr->toValue >= scalePtr->fromValue) { if (tickValue > scalePtr->toValue) { break; @@ -370,11 +370,11 @@ DisplayHorizontalScale( for (tickValue = scalePtr->fromValue; ; tickValue += tickInterval) { /* - * The TkRoundToResolution call gets rid of accumulated + * The TkRoundValueToResolution call gets rid of accumulated * round-off errors, if any. */ - tickValue = TkRoundToResolution(scalePtr, tickValue); + tickValue = TkRoundValueToResolution(scalePtr, tickValue); if (scalePtr->toValue >= scalePtr->fromValue) { if (tickValue > scalePtr->toValue) { break; -- cgit v0.12 From d155557faa7d1e039c912fc21ffccaf160c26b8e Mon Sep 17 00:00:00 2001 From: culler Date: Wed, 9 Jan 2019 14:28:09 +0000 Subject: Fix bug [70e531918e]: geometry issues with menubuttons on macOS --- library/menu.tcl | 19 +++- macosx/tkMacOSXDefault.h | 8 +- macosx/tkMacOSXMenu.c | 55 ++++-------- macosx/tkMacOSXMenubutton.c | 208 +++++++++++++++++++------------------------- tests/menubut.test | 26 +++--- 5 files changed, 142 insertions(+), 174 deletions(-) diff --git a/library/menu.tcl b/library/menu.tcl index ba66b92..a406ae3 100644 --- a/library/menu.tcl +++ b/library/menu.tcl @@ -274,8 +274,13 @@ proc ::tk::MbPost {w {x {}} {y {}}} { if {[tk windowingsystem] ne "aqua"} { set Priv(relief) [$w cget -relief] $w configure -relief raised + set xoffset {0 0 0 0 0} + set yoffset {0 0 0 0 0} } else { $w configure -state active + # Compensate for offsets created by the macOS window manager. + set xoffset {9 9 18 9 0} + set yoffset {6 13 13 13 9} } set Priv(postedMb) $w @@ -291,22 +296,26 @@ proc ::tk::MbPost {w {x {}} {y {}}} { if {[catch { switch [$w cget -direction] { above { - set x [winfo rootx $w] + set x [expr {[winfo rootx $w]}] set y [expr {[winfo rooty $w] - [winfo reqheight $menu]}] # if we go offscreen to the top, show as 'below' if {$y < [winfo vrooty $w]} { set y [expr {[winfo vrooty $w] + [winfo rooty $w] + [winfo reqheight $w]}] } + incr x [lindex $xoffset 0] + incr y [lindex $yoffset 0] PostOverPoint $menu $x $y } below { - set x [winfo rootx $w] + set x [expr {[winfo rootx $w]}] set y [expr {[winfo rooty $w] + [winfo height $w]}] # if we go offscreen to the bottom, show as 'above' set mh [winfo reqheight $menu] if {($y + $mh) > ([winfo vrooty $w] + [winfo vrootheight $w])} { set y [expr {[winfo vrooty $w] + [winfo vrootheight $w] + [winfo rooty $w] - $mh}] } + incr x [lindex $xoffset 1] + incr y [lindex $yoffset 1] PostOverPoint $menu $x $y } left { @@ -325,6 +334,8 @@ proc ::tk::MbPost {w {x {}} {y {}}} { + [$menu yposition [expr {$entry+1}]])/2}] } } + incr x [lindex $xoffset 2] + incr y [lindex $yoffset 2] PostOverPoint $menu $x $y if {$entry ne "" \ && [$menu entrycget $entry -state] ne "disabled"} { @@ -348,6 +359,8 @@ proc ::tk::MbPost {w {x {}} {y {}}} { + [$menu yposition [expr {$entry+1}]])/2}] } } + incr x [lindex $xoffset 3] + incr y [lindex $yoffset 3] PostOverPoint $menu $x $y if {$entry ne "" \ && [$menu entrycget $entry -state] ne "disabled"} { @@ -356,6 +369,8 @@ proc ::tk::MbPost {w {x {}} {y {}}} { } } default { + incr x [lindex $xoffset 4] + incr y [lindex $yoffset 4] if {[$w cget -indicatoron]} { if {$y eq ""} { set x [expr {[winfo rootx $w] + [winfo width $w]/2}] diff --git a/macosx/tkMacOSXDefault.h b/macosx/tkMacOSXDefault.h index b749673..48ddd66 100644 --- a/macosx/tkMacOSXDefault.h +++ b/macosx/tkMacOSXDefault.h @@ -334,7 +334,7 @@ * Defaults for menubuttons: */ -#define DEF_MENUBUTTON_ANCHOR "center" +#define DEF_MENUBUTTON_ANCHOR "w" #define DEF_MENUBUTTON_ACTIVE_BG_COLOR ACTIVE_BG #define DEF_MENUBUTTON_ACTIVE_BG_MONO BLACK #define DEF_MENUBUTTON_ACTIVE_FG_COLOR ACTIVE_FG @@ -342,7 +342,7 @@ #define DEF_MENUBUTTON_BG_COLOR NORMAL_BG #define DEF_MENUBUTTON_BG_MONO WHITE #define DEF_MENUBUTTON_BITMAP "" -#define DEF_MENUBUTTON_BORDER_WIDTH "2" +#define DEF_MENUBUTTON_BORDER_WIDTH "0" #define DEF_MENUBUTTON_CURSOR "" #define DEF_MENUBUTTON_DIRECTION "below" #define DEF_MENUBUTTON_DISABLED_FG_COLOR DISABLED @@ -358,8 +358,8 @@ #define DEF_MENUBUTTON_INDICATOR "1" #define DEF_MENUBUTTON_JUSTIFY "left" #define DEF_MENUBUTTON_MENU "" -#define DEF_MENUBUTTON_PADX "4" -#define DEF_MENUBUTTON_PADY "3" +#define DEF_MENUBUTTON_PADX "0" +#define DEF_MENUBUTTON_PADY "0" #define DEF_MENUBUTTON_RELIEF "flat" #define DEF_MENUBUTTON_STATE "normal" #define DEF_MENUBUTTON_TAKE_FOCUS "0" diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index ec32a78..6315638 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -799,7 +799,7 @@ TkpPostMenu( int oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE); NSView *view = [win contentView]; - NSRect frame = NSMakeRect(x + 9, tkMacOSXZeroScreenHeight - y - 9, 1, 1); + NSRect frame = NSMakeRect(x, tkMacOSXZeroScreenHeight - y, 1, 1); frame.origin = [view convertPoint: [win tkConvertPointFromScreen:frame.origin] fromView:nil]; @@ -1092,9 +1092,9 @@ TkpComputeStandardMenuGeometry( int modifierCharWidth, menuModifierCharWidth; int x, y, modifierWidth, labelWidth, indicatorSpace; int windowWidth, windowHeight, accelWidth; - int i, j, lastColumnBreak, maxWidth; + int i, maxWidth; int entryWidth, maxIndicatorSpace, borderWidth, activeBorderWidth; - TkMenuEntry *mePtr, *columnEntryPtr; + TkMenuEntry *mePtr; int haveAccel = 0; if (menuPtr->tkwin == NULL) { @@ -1106,7 +1106,7 @@ TkpComputeStandardMenuGeometry( Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->activeBorderWidthPtr, &activeBorderWidth); x = y = borderWidth; - windowHeight = maxWidth = lastColumnBreak = 0; + windowHeight = maxWidth = 0; maxIndicatorSpace = 0; /* @@ -1130,9 +1130,12 @@ TkpComputeStandardMenuGeometry( break; } } - + for (i = 0; i < menuPtr->numEntries; i++) { mePtr = menuPtr->entries[i]; + if (mePtr->type == TEAROFF_ENTRY) { + continue; + } if (mePtr->fontPtr == NULL) { tkfont = menuFont; fmPtr = &menuMetrics; @@ -1143,26 +1146,8 @@ TkpComputeStandardMenuGeometry( fmPtr = &entryMetrics; modifierCharWidth = ModifierCharWidth(tkfont); } - - if ((i > 0) && mePtr->columnBreak) { - if (maxIndicatorSpace != 0) { - maxIndicatorSpace += 2; - } - for (j = lastColumnBreak; j < i; j++) { - columnEntryPtr = menuPtr->entries[j]; - columnEntryPtr->indicatorSpace = maxIndicatorSpace; - columnEntryPtr->width = maxIndicatorSpace + maxWidth - + 2 * activeBorderWidth; - columnEntryPtr->x = x; - columnEntryPtr->entryFlags &= ~ENTRY_LAST_COLUMN; - } - x += maxIndicatorSpace + maxWidth + 2 * activeBorderWidth; - maxWidth = maxIndicatorSpace = 0; - lastColumnBreak = i; - y = borderWidth; - } accelWidth = modifierWidth = indicatorSpace = 0; - if (mePtr->type == SEPARATOR_ENTRY || mePtr->type == TEAROFF_ENTRY) { + if (mePtr->type == SEPARATOR_ENTRY) { mePtr->height = menuSeparatorHeight; } else { /* @@ -1176,16 +1161,16 @@ TkpComputeStandardMenuGeometry( NSMenuItem *menuItem = (NSMenuItem *) mePtr->platformEntryData; int haveImage = 0, width = 0, height = 0; - if (mePtr->image) { Tk_SizeOfImage(mePtr->image, &width, &height); haveImage = 1; + height += 2; /* tweak */ } else if (mePtr->bitmapPtr) { Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin, mePtr->bitmapPtr); - Tk_SizeOfBitmap(menuPtr->display, bitmap, &width, &height); haveImage = 1; + height += 2; /* tweak */ } if (!haveImage || (mePtr->compound != COMPOUND_NONE)) { NSAttributedString *attrTitle = [menuItem attributedTitle]; @@ -1197,11 +1182,8 @@ TkpComputeStandardMenuGeometry( size = [[menuItem title] sizeWithAttributes: TkMacOSXNSFontAttributesForFont(tkfont)]; } - size.width += menuTextLeadingEdgeMargin + - menuTextTrailingEdgeMargin; - if (size.height < fmPtr->linespace) { - size.height = fmPtr->linespace; - } + size.width += menuTextLeadingEdgeMargin + menuTextTrailingEdgeMargin; + size.height -= 1; /* tweak */ if (haveImage && (mePtr->compound != COMPOUND_NONE)) { int margin = width + menuIconTrailingEdgeMargin; @@ -1219,7 +1201,6 @@ TkpComputeStandardMenuGeometry( } labelWidth = width + menuItemExtraWidth; mePtr->height = height + menuItemExtraHeight; - if (mePtr->type == CASCADE_ENTRY) { modifierWidth = modifierCharWidth; } else if (mePtr->accelLength == 0) { @@ -1250,8 +1231,10 @@ TkpComputeStandardMenuGeometry( if (entryWidth > maxWidth) { maxWidth = entryWidth; } + menuPtr->entries[i]->width = entryWidth; mePtr->height += 2 * activeBorderWidth; } + mePtr->x = x; mePtr->y = y; y += menuPtr->entries[i]->height + borderWidth; if (y > windowHeight) { @@ -1259,14 +1242,6 @@ TkpComputeStandardMenuGeometry( } } - for (j = lastColumnBreak; j < menuPtr->numEntries; j++) { - columnEntryPtr = menuPtr->entries[j]; - columnEntryPtr->indicatorSpace = maxIndicatorSpace; - columnEntryPtr->width = maxIndicatorSpace + maxWidth - + 2 * activeBorderWidth; - columnEntryPtr->x = x; - columnEntryPtr->entryFlags |= ENTRY_LAST_COLUMN; - } windowWidth = x + maxIndicatorSpace + maxWidth + 2 * activeBorderWidth + borderWidth; windowHeight += borderWidth; diff --git a/macosx/tkMacOSXMenubutton.c b/macosx/tkMacOSXMenubutton.c index 1acefe5..4df23b4 100644 --- a/macosx/tkMacOSXMenubutton.c +++ b/macosx/tkMacOSXMenubutton.c @@ -47,17 +47,23 @@ typedef struct MacMenuButton { } MacMenuButton; /* - * Forward declarations for procedures defined later in this file: + * Forward declarations for static functions defined later in this file: */ static void MenuButtonEventProc(ClientData clientData, XEvent *eventPtr); -static void MenuButtonBackgroundDrawCB ( MacMenuButton *ptr, SInt16 depth, Boolean isColorDev); -static void MenuButtonContentDrawCB ( ThemeButtonKind kind, const HIThemeButtonDrawInfo * info, MacMenuButton *ptr, SInt16 depth, Boolean isColorDev); +static void MenuButtonBackgroundDrawCB (MacMenuButton *ptr, SInt16 depth, + Boolean isColorDev); +static void MenuButtonContentDrawCB (ThemeButtonKind kind, + const HIThemeButtonDrawInfo * info, + MacMenuButton *ptr, SInt16 depth, + Boolean isColorDev); static void MenuButtonEventProc ( ClientData clientData, XEvent *eventPtr); -static void TkMacOSXComputeMenuButtonParams (TkMenuButton * butPtr, ThemeButtonKind* btnkind, HIThemeButtonDrawInfo* drawinfo); -static int TkMacOSXComputeMenuButtonDrawParams (TkMenuButton * butPtr, DrawParams * dpPtr); -static void TkMacOSXDrawMenuButton (MacMenuButton *butPtr, - GC gc, Pixmap pixmap); +static void TkMacOSXComputeMenuButtonParams (TkMenuButton * butPtr, + ThemeButtonKind* btnkind, + HIThemeButtonDrawInfo* drawinfo); +static void TkMacOSXComputeMenuButtonDrawParams (TkMenuButton * butPtr, + DrawParams * dpPtr); +static void TkMacOSXDrawMenuButton (MacMenuButton *butPtr, GC gc, Pixmap pixmap); static void DrawMenuButtonImageAndText(TkMenuButton* butPtr); /* @@ -70,11 +76,46 @@ Tk_ClassProcs tkpMenubuttonClass = { TkMenuButtonWorldChanged, /* worldChangedProc */ }; +/* + * We use Apple's Pop-Up Button widget to represent the Tk Menubutton. + * However, we do not use the NSPopUpButton class for this control. Instead we + * render the Pop-Up Button using the HITheme library. This imposes some + * constraints on what can be done. The HITheme renderer allows only specific + * dimensions for the button. + * + * The HITheme library allows drawing a Pop-Up Button with an arbitrary bounds + * rectangle. However the button is always drawn as a rounded box which is 22 + * pixels high. If the bounds rectangle is less than 22 pixels high, the + * button is drawn at the top of the rectangle and the bottom of the button is + * clipped away. So we set a minimum height of 22 pixels for a Menubutton. If + * the bounds rectangle is more than 22 pixels high, then the button is drawn + * centered vertically in the bounds rectangle. + * + * The content rectangle of the button is inset by 14 pixels on the left and 28 + * pixels on the right. The rightmost part of the button contains the blue + * double-arrow symbol which is 28 pixels wide. + * + * To maintain compatibility with code that runs on multiple operating systems, + * the width and height of the content rectangle includes the borderWidth, the + * highlightWidth and the padX and padY dimensions of the Menubutton. However, + * to be consistent with the standard Apple appearance, the content is always + * be drawn at the left side of the content rectangle. All of the excess space + * appears on the right side of the content, and the anchor property is + * ignored. The easiest way to comply with Apple's Human Interface Guidelines + * would be to set bd = highlightthickness = padx = 0 and to specify an + * explicit width for the button. Apple also recommends using the same width + * for all Pop-Up Buttons in a given window. + */ + +#define LEFT_INSET 8 +#define RIGHT_INSET 28 +#define MIN_HEIGHT 22 + /* *---------------------------------------------------------------------- * - * TkpCreateMenuButton -- + * TkpCreateMenuButton -- * * Allocate a new TkMenuButton structure. * @@ -93,13 +134,12 @@ TkpCreateMenuButton( { MacMenuButton *mbPtr = (MacMenuButton *) ckalloc(sizeof(MacMenuButton)); - Tk_CreateEventHandler(tkwin, ActivateMask, - MenuButtonEventProc, (ClientData) mbPtr); + Tk_CreateEventHandler(tkwin, ActivateMask, MenuButtonEventProc, + (ClientData) mbPtr); mbPtr->flags = FIRST_DRAW; mbPtr->btnkind = kThemePopupButton; bzero(&mbPtr->drawinfo, sizeof(mbPtr->drawinfo)); bzero(&mbPtr->lastdrawinfo, sizeof(mbPtr->lastdrawinfo)); - return (TkMenuButton *) mbPtr; } @@ -165,12 +205,13 @@ TkpDisplayMenuButton( * TkpDestroyMenuButton -- * * Free data structures associated with the menubutton control. + * This is a no-op on the Mac. * * Results: * None. * * Side effects: - * Restores the default control state. + * None. * *---------------------------------------------------------------------- */ @@ -204,15 +245,12 @@ TkpComputeMenuButtonGeometry(butPtr) register TkMenuButton *butPtr; /* Widget record for menu button. */ { int width, height, avgWidth, haveImage = 0, haveText = 0; - MacMenuButton *mbPtr = (MacMenuButton*)butPtr; int txtWidth, txtHeight; Tk_FontMetrics fm; - DrawParams drawParams; - int paddingx = 0; - int paddingy = 0; + int highlightWidth = butPtr->highlightWidth > 0 ? butPtr->highlightWidth : 0; /* - * First figure out the size of the contents of the button. + * First compute the size of the contents of the button. */ width = 0; @@ -221,8 +259,6 @@ TkpComputeMenuButtonGeometry(butPtr) txtHeight = 0; avgWidth = 0; - TkMacOSXComputeMenuButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo); - if (butPtr->image != NULL) { Tk_SizeOfImage(butPtr->image, &width, &height); haveImage = 1; @@ -241,7 +277,7 @@ TkpComputeMenuButtonGeometry(butPtr) txtHeight = butPtr->textHeight; avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1); Tk_GetFontMetrics(butPtr->tkfont, &fm); - haveText = (txtWidth != 0 && txtHeight != 0); + haveText = (txtWidth != 0 && txtHeight != 2); } /* @@ -304,65 +340,18 @@ TkpComputeMenuButtonGeometry(butPtr) width = txtWidth; height = txtHeight; if (butPtr->width > 0) { - width = butPtr->width * avgWidth; + width = butPtr->width * avgWidth + 2*butPtr->padX; } if (butPtr->height > 0) { - height = butPtr->height * fm.linespace; + height = butPtr->height * fm.linespace + 2*butPtr->padY; } } } - width += 2 * butPtr->padX - 2; - height += 2 * butPtr->padY - 2; - - /*Add padding for button arrows.*/ - width += 22; - - /* - * Now figure out the size of the border decorations for the button. - */ - - if (butPtr->highlightWidth < 0) { - butPtr->highlightWidth = 0; - } - butPtr->inset = 0; - butPtr->inset += butPtr->highlightWidth; - - TkMacOSXComputeMenuButtonDrawParams(butPtr,&drawParams); - - HIRect tmpRect; - HIRect contBounds; - - tmpRect = CGRectMake(0, 0, width, height); - - HIThemeGetButtonContentBounds(&tmpRect, &mbPtr->drawinfo, &contBounds); - - - - /* If the content region has a minimum height, match it. */ - if (height < contBounds.size.height) { - height = contBounds.size.height; - } - - /* If the content region has a minimum width, match it. */ - if (width < contBounds.size.width) { - width = contBounds.size.width; - } - - /* Pad to fill difference between content bounds and button bounds. */ - paddingx = tmpRect.origin.x - contBounds.origin.x; - paddingy = tmpRect.origin.y - contBounds.origin.y; - - if (paddingx > 0) { - width += paddingx; - } - if (paddingy > 0) { - height += paddingy; - } - - width += butPtr->inset*2; - height += butPtr->inset*2; - - + + butPtr->inset = highlightWidth + butPtr->borderWidth; + width += LEFT_INSET + RIGHT_INSET + 2*butPtr->inset; + height += 2*butPtr->inset; + height = height < MIN_HEIGHT ? MIN_HEIGHT : height; Tk_GeometryRequest(butPtr->tkwin, width, height); Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset); } @@ -446,8 +435,8 @@ DrawMenuButtonImageAndText( imageYOffset = butPtr->textHeight + butPtr->padY; } fullHeight = height + butPtr->textHeight + butPtr->padY; - fullWidth = (width > butPtr->textWidth ? width : - butPtr->textWidth); + fullWidth = (width > butPtr->textWidth ? + width : butPtr->textWidth); textXOffset = (fullWidth - butPtr->textWidth)/2; imageXOffset = (fullWidth - width)/2; break; @@ -489,10 +478,10 @@ DrawMenuButtonImageAndText( } TkComputeAnchor(butPtr->anchor, tkwin, - butPtr->padX + butPtr->borderWidth, - butPtr->padY + butPtr->borderWidth, + butPtr->padX + butPtr->inset, + butPtr->padY + butPtr->inset, fullWidth, fullHeight, &x, &y); - imageXOffset += x; + imageXOffset = LEFT_INSET; imageYOffset += y; textYOffset -= 1; @@ -517,36 +506,32 @@ DrawMenuButtonImageAndText( butPtr->underline); } else { if (haveImage) { - int x = 0; - int y; + int x, y; TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX + butPtr->borderWidth, butPtr->padY + butPtr->borderWidth, width, height, &x, &y); - imageXOffset += x; - imageYOffset += y; - - if (butPtr->image != NULL) { - Tk_RedrawImage(butPtr->image, 0, 0, width, height, - pixmap, imageXOffset, imageYOffset); + imageXOffset = LEFT_INSET; + imageYOffset += y; + if (butPtr->image != NULL) { + Tk_RedrawImage(butPtr->image, 0, 0, width, height, + pixmap, imageXOffset, imageYOffset); } else { XSetClipOrigin(butPtr->display, dpPtr->gc, x, y); XCopyPlane(butPtr->display, butPtr->bitmap, - pixmap, dpPtr->gc, - 0, 0, (unsigned int) width, - (unsigned int) height, - imageXOffset, imageYOffset, 1); + pixmap, dpPtr->gc, + 0, 0, (unsigned int) width, + (unsigned int) height, + imageXOffset, imageYOffset, 1); XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0); } } else { - /*Move x back by eight pixels to give the menubutton arrows room.*/ - int x = 0; - int y; - textXOffset = 8; + int x, y; + textXOffset = LEFT_INSET; TkComputeAnchor(butPtr->anchor, tkwin, butPtr->padX, butPtr->padY, butPtr->textWidth, butPtr->textHeight, &x, &y); Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, - butPtr->textLayout, x - textXOffset, y, 0, -1); + butPtr->textLayout, textXOffset, y, 0, -1); y += butPtr->textHeight/2; } } @@ -578,7 +563,6 @@ TkMacOSXDrawMenuButton( * the bevel button */ Pixmap pixmap) /* The pixmap we are drawing into - needed * for the bevel button */ - { TkMenuButton * butPtr = ( TkMenuButton *)mbPtr; TkWindow * winPtr; @@ -591,10 +575,9 @@ TkMacOSXDrawMenuButton( TkMacOSXComputeMenuButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo); - cntrRect = CGRectMake(winPtr->privatePtr->xOff, winPtr->privatePtr->yOff, Tk_Width(butPtr->tkwin),Tk_Height(butPtr->tkwin)); - - cntrRect = CGRectInset(cntrRect, butPtr->inset, butPtr->inset); - + cntrRect = CGRectMake(winPtr->privatePtr->xOff, winPtr->privatePtr->yOff, + Tk_Width(butPtr->tkwin), + Tk_Height(butPtr->tkwin)); if (useNewerHITools == 1) { HIRect contHIRec; @@ -618,16 +601,12 @@ TkMacOSXDrawMenuButton( } HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, kHIThemeOrientationNormal, &contHIRec); - TkMacOSXRestoreDrawingContext(&dc); - MenuButtonContentDrawCB( mbPtr->btnkind, &mbPtr->drawinfo, (MacMenuButton *)mbPtr, 32, true); } else { if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) { return; } - - TkMacOSXRestoreDrawingContext(&dc); } mbPtr->lastdrawinfo = mbPtr->drawinfo; @@ -696,8 +675,7 @@ MenuButtonContentDrawCB ( if (tkwin == NULL || !Tk_IsMapped(tkwin)) { return; } - - DrawMenuButtonImageAndText( butPtr); + DrawMenuButtonImageAndText(butPtr); } /* @@ -812,24 +790,22 @@ TkMacOSXComputeMenuButtonParams(TkMenuButton * butPtr, ThemeButtonKind* btnkind, * * TkMacOSXComputeMenuButtonDrawParams -- * - * This procedure computes the various parameters used - * when drawing a button - * These are determined by the various tk button parameters + * This procedure selects an appropriate drawing context for + * drawing a menubutton. * * Results: - * 1 if control will be used, 0 otherwise. + * None. * * Side effects: - * Sets the button draw parameters + * Sets the button draw parameters. * *---------------------------------------------------------------------- */ -static int +static void TkMacOSXComputeMenuButtonDrawParams(TkMenuButton * butPtr, DrawParams * dpPtr) { - dpPtr->hasImageOrBitmap = ((butPtr->image != NULL) - || (butPtr->bitmap != None)); + dpPtr->hasImageOrBitmap = ((butPtr->image != NULL) || (butPtr->bitmap != None)); dpPtr->border = butPtr->normalBorder; if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) { dpPtr->gc = butPtr->disabledGC; @@ -839,8 +815,6 @@ TkMacOSXComputeMenuButtonDrawParams(TkMenuButton * butPtr, DrawParams * dpPtr) } else { dpPtr->gc = butPtr->normalTextGC; } - - return 1; } /* diff --git a/tests/menubut.test b/tests/menubut.test index 6efdb0f..88f4330 100644 --- a/tests/menubut.test +++ b/tests/menubut.test @@ -542,7 +542,11 @@ test menubutton-6.1 {MenuButtonCmdDeletedProc procedure} -setup { deleteWindows } -result {{} {}} - +if {[tk windowingsystem] == "aqua"} { + set extraWidth 36 +} else { + set extraWidth 0 +} test menubutton-7.1 {ComputeMenuButtonGeometry procedure} -constraints { testImageType } -setup { @@ -555,33 +559,33 @@ test menubutton-7.1 {ComputeMenuButtonGeometry procedure} -constraints { } -cleanup { deleteWindows imageCleanup -} -result {38 23} +} -result [list [expr {38 + $extraWidth}] 23] test menubutton-7.2 {ComputeMenuButtonGeometry procedure} -constraints { testImageType } -setup { deleteWindows image create test image1 } -body { - menubutton .mb -image image1 -bd 1 -highlightthickness 2 + menubutton .mb -image image1 -bd 3 -highlightthickness 1 pack .mb list [winfo reqwidth .mb] [winfo reqheight .mb] } -cleanup { deleteWindows imageCleanup -} -result {36 21} +} -result [list [expr {38 + $extraWidth}] 23] test menubutton-7.3 {ComputeMenuButtonGeometry procedure} -constraints { testImageType } -setup { deleteWindows image create test image1 } -body { - menubutton .mb -image image1 -bd 0 -highlightthickness 2 -padx 5 -pady 5 + menubutton .mb -image image1 -bd 1 -highlightthickness 3 -padx 5 -pady 5 pack .mb list [winfo reqwidth .mb] [winfo reqheight .mb] } -cleanup { deleteWindows imageCleanup -} -result {34 19} +} -result [list [expr {38 + $extraWidth}] 23] test menubutton-7.4 {ComputeMenuButtonGeometry procedure} -constraints { testImageType } -setup { @@ -595,7 +599,7 @@ test menubutton-7.4 {ComputeMenuButtonGeometry procedure} -constraints { } -cleanup { deleteWindows imageCleanup -} -result {48 23} +} -result [list [expr {48 + $extraWidth}] 23] test menubutton-7.5 {ComputeMenuButtonGeometry procedure} -constraints { testImageType } -setup { @@ -609,7 +613,7 @@ test menubutton-7.5 {ComputeMenuButtonGeometry procedure} -constraints { } -cleanup { deleteWindows imageCleanup -} -result {38 38} +} -result [list [expr {38 + $extraWidth}] 38] test menubutton-7.6 {ComputeMenuButtonGeometry procedure} -setup { deleteWindows } -body { @@ -619,7 +623,7 @@ test menubutton-7.6 {ComputeMenuButtonGeometry procedure} -setup { list [winfo reqwidth .mb] [winfo reqheight .mb] } -cleanup { deleteWindows -} -result {25 35} +} -result [list [expr {25 + $extraWidth}] 35] test menubutton-7.7 {ComputeMenuButtonGeometry procedure} -setup { deleteWindows } -body { @@ -629,7 +633,7 @@ test menubutton-7.7 {ComputeMenuButtonGeometry procedure} -setup { list [winfo reqwidth .mb] [winfo reqheight .mb] } -cleanup { deleteWindows -} -result {46 33} +} -result [list [expr {46 + $extraWidth}] 33] test menubutton-7.8 {ComputeMenuButtonGeometry procedure} -setup { deleteWindows } -body { @@ -639,7 +643,7 @@ test menubutton-7.8 {ComputeMenuButtonGeometry procedure} -setup { list [winfo reqwidth .mb] [winfo reqheight .mb] } -cleanup { deleteWindows -} -result {23 56} +} -result [list [expr {23 + $extraWidth}] 56] test menubutton-7.9 {ComputeMenuButtonGeometry procedure} -constraints { fonts } -setup { -- cgit v0.12 From 3866cadb1cfcaf4145fed26ace23efb3a0d16254 Mon Sep 17 00:00:00 2001 From: fvogel Date: Wed, 9 Jan 2019 21:58:56 +0000 Subject: Add new test scale-14.13 to guard against regressions with [220665ffff], and duplicates [220265ffff] and [779559ffff]. This test currently fails in the present bugfix branch but passes in core-8-6-branch --- tests/scale.test | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/scale.test b/tests/scale.test index 6344eef..7fa3a62 100644 --- a/tests/scale.test +++ b/tests/scale.test @@ -1183,6 +1183,19 @@ test scale-14.12 {RoundValueToResolution procedure} -body { } -result {168.75} destroy .s +test scale-14.13 {RoundValueToResolution procedure, round-off errors} -setup { + # see [220665ffff], and duplicates [220265ffff] and [779559ffff] + set x NotSet + pack [scale .s -orient horizontal -resolution .1 -from -180 -to 180 -command "set x"] + update +} -body { + .s configure -background red + update + set x +} -cleanup { + destroy .s +} -result {NotSet} + test scale-14a.1 {RoundValueToResolution, RoundIntervalToResolution procedures} -setup { pack [scale .s -orient horizontal] update -- cgit v0.12 From da7c298f108280140fbbec81f67705f684bf5fe6 Mon Sep 17 00:00:00 2001 From: culler Date: Fri, 11 Jan 2019 21:47:27 +0000 Subject: Fix related menubutton issues on linux and Windows. --- doc/menu.n | 21 +++-- generic/tkMenu.c | 32 +++++-- generic/tkMenu.h | 2 +- library/menu.tcl | 257 ++++++++++++++++++++++++++------------------------ macosx/tkMacOSXMenu.c | 73 +++++++------- tests/menu.test | 2 +- unix/tkUnixMenu.c | 14 ++- win/tkWinMenu.c | 18 ++-- 8 files changed, 231 insertions(+), 188 deletions(-) diff --git a/doc/menu.n b/doc/menu.n index ac60e65..338ce6a 100644 --- a/doc/menu.n +++ b/doc/menu.n @@ -470,18 +470,19 @@ a menu entry does not automatically unpost the menu; the default bindings normally take care of this before invoking the \fBinvoke\fR widget command. .TP -\fIpathName \fBpost \fIx y\fR +\fIpathName \fBpost \fIx y\fR ?\fIindex\fR? . Arrange for the menu to be displayed on the screen at the root-window -coordinates given by \fIx\fR and \fIy\fR. These coordinates are -adjusted if necessary to guarantee that the entire menu is visible on -the screen. This command normally returns an empty string. -If the \fB\-postcommand\fR option has been specified, then its value is -executed as a Tcl script before posting the menu and the result of -that script is returned as the result of the \fBpost\fR widget -command. -If an error returns while executing the command, then the error is -returned without posting the menu. +coordinates given by \fIx\fR and \fIy\fR. If an index is specified +the menu will be located so that the entry with that index is +displayed at the point. These coordinates are adjusted if necessary to +guarantee that the entire menu is visible on the screen. This command +normally returns an empty string. If the \fB\-postcommand\fR option +has been specified, then its value is executed as a Tcl script before +posting the menu and the result of that script is returned as the +result of the \fBpost\fR widget command. If an error returns while +executing the command, then the error is returned without posting the +menu. .TP \fIpathName \fBpostcascade \fIindex\fR . diff --git a/generic/tkMenu.c b/generic/tkMenu.c index 26ffc88..f1ea8ff 100644 --- a/generic/tkMenu.c +++ b/generic/tkMenu.c @@ -870,32 +870,46 @@ MenuWidgetObjCmd( break; } case MENU_POST: { - int x, y; + int x, y, entry = -1; - if (objc != 4) { - Tcl_WrongNumArgs(interp, 2, objv, "x y"); + if (objc != 4 && objc != 5) { + Tcl_WrongNumArgs(interp, 2, objv, "x y ?entry?"); goto error; } if ((Tcl_GetIntFromObj(interp, objv[2], &x) != TCL_OK) || (Tcl_GetIntFromObj(interp, objv[3], &y) != TCL_OK)) { goto error; } + if (objc == 5) { + if (menuPtr->menuType == TEAROFF_MENU) { + Tcl_AppendResult(interp, + "the index option is invalid for tearoff menus", NULL); + return TCL_ERROR; + } + if (Tcl_GetIntFromObj(interp, objv[4], &entry) != TCL_OK) { + goto error; + } + } /* - * Tearoff menus are posted differently on Mac and Windows than - * non-tearoffs. TkpPostMenu does not actually map the menu's window - * on those platforms, and popup menus have to be handled specially. - * Also, menubar menues are not intended to be posted (bug 1567681, - * 2160206). + * Tearoff menus are the same as ordinary menus on the Mac and are + * posted differently on Windows than non-tearoffs. TkpPostMenu + * does not actually map the menu's window on those platforms, and + * popup menus have to be handled specially. Also, menubar menus are + * not intended to be posted (bug 1567681, 2160206). */ if (menuPtr->menuType == MENUBAR) { Tcl_AppendResult(interp, "a menubar menu cannot be posted", NULL); return TCL_ERROR; } else if (menuPtr->menuType != TEAROFF_MENU) { - result = TkpPostMenu(interp, menuPtr, x, y); + result = TkpPostMenu(interp, menuPtr, x, y, entry); } else { +#ifdef TK_MAC_OSX + result = TkpPostMenu(interp, menuPtr, x, y, entry); +#else result = TkPostTearoffMenu(interp, menuPtr, x, y); +#endif } break; } diff --git a/generic/tkMenu.h b/generic/tkMenu.h index bac51aa..92bf8b2 100644 --- a/generic/tkMenu.h +++ b/generic/tkMenu.h @@ -543,7 +543,7 @@ MODULE_SCOPE void TkpMenuInit(void); MODULE_SCOPE int TkpMenuNewEntry(TkMenuEntry *mePtr); MODULE_SCOPE int TkpNewMenu(TkMenu *menuPtr); MODULE_SCOPE int TkpPostMenu(Tcl_Interp *interp, TkMenu *menuPtr, - int x, int y); + int x, int y, int entry); MODULE_SCOPE void TkpSetWindowMenuBar(Tk_Window tkwin, TkMenu *menuPtr); #endif /* _TKMENU */ diff --git a/library/menu.tcl b/library/menu.tcl index a406ae3..cdfcc13 100644 --- a/library/menu.tcl +++ b/library/menu.tcl @@ -234,6 +234,7 @@ proc ::tk::MbLeave w { } } + # ::tk::MbPost -- # Given a menubutton, this procedure does all the work of posting # its associated menu and unposting any other menu that is currently @@ -274,124 +275,25 @@ proc ::tk::MbPost {w {x {}} {y {}}} { if {[tk windowingsystem] ne "aqua"} { set Priv(relief) [$w cget -relief] $w configure -relief raised - set xoffset {0 0 0 0 0} - set yoffset {0 0 0 0 0} } else { $w configure -state active - # Compensate for offsets created by the macOS window manager. - set xoffset {9 9 18 9 0} - set yoffset {6 13 13 13 9} } set Priv(postedMb) $w set Priv(focus) [focus] $menu activate none GenerateMenuSelect $menu - - # If this looks like an option menubutton then post the menu so - # that the current entry is on top of the mouse. Otherwise post - # the menu just below the menubutton, as for a pull-down. - update idletasks - if {[catch { - switch [$w cget -direction] { - above { - set x [expr {[winfo rootx $w]}] - set y [expr {[winfo rooty $w] - [winfo reqheight $menu]}] - # if we go offscreen to the top, show as 'below' - if {$y < [winfo vrooty $w]} { - set y [expr {[winfo vrooty $w] + [winfo rooty $w] + [winfo reqheight $w]}] - } - incr x [lindex $xoffset 0] - incr y [lindex $yoffset 0] - PostOverPoint $menu $x $y - } - below { - set x [expr {[winfo rootx $w]}] - set y [expr {[winfo rooty $w] + [winfo height $w]}] - # if we go offscreen to the bottom, show as 'above' - set mh [winfo reqheight $menu] - if {($y + $mh) > ([winfo vrooty $w] + [winfo vrootheight $w])} { - set y [expr {[winfo vrooty $w] + [winfo vrootheight $w] + [winfo rooty $w] - $mh}] - } - incr x [lindex $xoffset 1] - incr y [lindex $yoffset 1] - PostOverPoint $menu $x $y - } - left { - set x [expr {[winfo rootx $w] - [winfo reqwidth $menu]}] - set y [expr {(2 * [winfo rooty $w] + [winfo height $w]) / 2}] - set entry [MenuFindName $menu [$w cget -text]] - if {$entry eq ""} { - set entry 0 - } - if {[$w cget -indicatoron]} { - if {$entry == [$menu index last]} { - incr y [expr {-([$menu yposition $entry] \ - + [winfo reqheight $menu])/2}] - } else { - incr y [expr {-([$menu yposition $entry] \ - + [$menu yposition [expr {$entry+1}]])/2}] - } - } - incr x [lindex $xoffset 2] - incr y [lindex $yoffset 2] - PostOverPoint $menu $x $y - if {$entry ne "" \ - && [$menu entrycget $entry -state] ne "disabled"} { - $menu activate $entry - GenerateMenuSelect $menu - } - } - right { - set x [expr {[winfo rootx $w] + [winfo width $w]}] - set y [expr {(2 * [winfo rooty $w] + [winfo height $w]) / 2}] - set entry [MenuFindName $menu [$w cget -text]] - if {$entry eq ""} { - set entry 0 - } - if {[$w cget -indicatoron]} { - if {$entry == [$menu index last]} { - incr y [expr {-([$menu yposition $entry] \ - + [winfo reqheight $menu])/2}] - } else { - incr y [expr {-([$menu yposition $entry] \ - + [$menu yposition [expr {$entry+1}]])/2}] - } - } - incr x [lindex $xoffset 3] - incr y [lindex $yoffset 3] - PostOverPoint $menu $x $y - if {$entry ne "" \ - && [$menu entrycget $entry -state] ne "disabled"} { - $menu activate $entry - GenerateMenuSelect $menu - } - } - default { - incr x [lindex $xoffset 4] - incr y [lindex $yoffset 4] - if {[$w cget -indicatoron]} { - if {$y eq ""} { - set x [expr {[winfo rootx $w] + [winfo width $w]/2}] - set y [expr {[winfo rooty $w] + [winfo height $w]/2}] - } - PostOverPoint $menu $x $y [MenuFindName $menu [$w cget -text]] - } else { - PostOverPoint $menu [winfo rootx $w] [expr {[winfo rooty $w]+[winfo height $w]}] - } - } - } - } msg opt]} { + + if {[catch {PostMenubuttonMenu $w $menu} msg opt]} { # Error posting menu (e.g. bogus -postcommand). Unpost it and # reflect the error. - MenuUnpost {} return -options $opt $msg } set Priv(tearoff) $tearoff - if {$tearoff != 0} { + if {$tearoff != 0 && [tk windowingsystem] ne "aqua"} { focus $menu if {[winfo viewable $w]} { SaveGrabInfo $w @@ -1223,10 +1125,118 @@ proc ::tk::MenuFindName {menu s} { return "" } +# ::tk::PostMenubuttonMenu -- +# +# Given a menubutton and a menu, this procedure posts the menu at the +# appropriate location. If the menubutton looks like an option +# menubutton, meaning that the indicator is on and the direction is +# neither above nor below, then the menu is posted so that the current +# entry is vertically aligned with the menubutton. On the Mac this +# will expose a small amount of the blue indicator on the right hand +# side. On other platforms the entry is centered over the button. + +if {[tk windowingsystem] eq "aqua"} { + proc ::tk::PostMenubuttonMenu {button menu} { + set entry "" + if {[$button cget -indicatoron]} { + set entry [MenuFindName $menu [$button cget -text]] + if {$entry eq ""} { + set entry 0 + } + } + set x [winfo rootx $button] + set y [expr {2 + [winfo rooty $button]}] + switch [$button cget -direction] { + above { + set entry "" + incr y [expr {4 - [winfo reqheight $menu]}] + } + below { + set entry "" + incr y [expr {2 + [winfo height $button]}] + } + left { + incr x [expr {-[winfo reqwidth $menu]}] + } + right { + incr x [winfo width $button] + } + default { + incr x [expr {[winfo width $button] - [winfo reqwidth $menu] - 5}] + } + } + PostOverPoint $menu $x $y $entry + } +} else { + proc ::tk::PostMenubuttonMenu {button menu} { + set entry "" + if {[$button cget -indicatoron]} { + set entry [MenuFindName $menu [$button cget -text]] + if {$entry eq ""} { + set entry 0 + } + } + if {$entry ne ""} { + if {$entry == [$menu index last]} { + set entryHeight [expr {[winfo reqheight $menu] \ + - [$menu yposition $entry]}] + } else { + set entryHeight [expr {[$menu yposition [expr {$entry+1}]] \ + - [$menu yposition $entry]}] + } + } + set x [winfo rootx $button] + set y [winfo rooty $button] + switch [$button cget -direction] { + above { + incr y [expr {-[winfo reqheight $menu]}] + # if we go offscreen to the top, show as 'below' + if {$y < [winfo vrooty $button]} { + set y [expr {[winfo vrooty $button] + [winfo rooty $button]\ + + [winfo reqheight $button]}] + } + set entry {} + } + below { + incr y [winfo height $button] + # if we go offscreen to the bottom, show as 'above' + set mh [winfo reqheight $menu] + if {($y + $mh) > ([winfo vrooty $button] + [winfo vrootheight $button])} { + set y [expr {[winfo vrooty $button] + [winfo vrootheight $button] \ + + [winfo rooty $button] - $mh}] + } + set entry {} + } + left { + # It is not clear why this is needed. + if {[tk windowingsystem] eq "win32"} { + incr x [expr {-4 - [winfo reqwidth $button] / 2}] + } + incr x [expr {- [winfo reqwidth $menu]}] + } + right { + incr x [expr {[winfo width $button]}] + } + default { + if {[$button cget -indicatoron]} { + incr x [expr {([winfo width $button] - \ + [winfo reqwidth $menu])/ 2}] + } else { + incr y [winfo height $button] + } + } + } + PostOverPoint $menu $x $y $entry + } +} + # ::tk::PostOverPoint -- -# This procedure posts a given menu such that a given entry in the -# menu is centered over a given point in the root window. It also -# activates the given entry. +# +# This procedure posts a menu on the screen so that a given entry in +# the menu is positioned with its upper left corner at a given point +# in the root window. The procedure also activates that entry. If no +# entry is specified the upper left corner of the entire menu is +# placed at the point. # # Arguments: # menu - Menu to post. @@ -1235,19 +1245,24 @@ proc ::tk::MenuFindName {menu s} { # If omitted or specified as {}, then the menu's # upper-left corner goes at (x,y). -proc ::tk::PostOverPoint {menu x y {entry {}}} { - if {$entry ne ""} { - if {$entry == [$menu index last]} { - incr y [expr {-([$menu yposition $entry] \ - + [winfo reqheight $menu])/2}] +if {[tk windowingsystem] ne "win32"} { + proc ::tk::PostOverPoint {menu x y {entry {}}} { + if {$entry ne ""} { + $menu post $x $y $entry + if {[$menu entrycget $entry -state] ne "disabled"} { + $menu activate $entry + GenerateMenuSelect $menu + } } else { - incr y [expr {-([$menu yposition $entry] \ - + [$menu yposition [expr {$entry+1}]])/2}] + $menu post $x $y } - incr x [expr {-[winfo reqwidth $menu]/2}] + return } - - if {[tk windowingsystem] eq "win32"} { +} else { + proc ::tk::PostOverPoint {menu x y {entry {}}} { + if {$entry ne ""} { + incr y [expr {-[$menu yposition $entry]}] + } # osVersion is not available in safe interps set ver 5 if {[info exists ::tcl_platform(osVersion)]} { @@ -1263,7 +1278,7 @@ proc ::tk::PostOverPoint {menu x y {entry {}}} { # manager provided with Vista and Windows 7. if {$ver < 6} { set yoffset [expr {[winfo screenheight $menu] \ - - $y - [winfo reqheight $menu] - 10}] + - $y - [winfo reqheight $menu] - 10}] if {$yoffset < [winfo vrooty $menu]} { # The bottom of the menu is offscreen, so adjust upwards incr y [expr {$yoffset - [winfo vrooty $menu]}] @@ -1275,11 +1290,11 @@ proc ::tk::PostOverPoint {menu x y {entry {}}} { set y [winfo vrooty $menu] } } - } - $menu post $x $y - if {$entry ne "" && [$menu entrycget $entry -state] ne "disabled"} { - $menu activate $entry - GenerateMenuSelect $menu + $menu post $x $y + if {$entry ne "" && [$menu entrycget $entry -state] ne "disabled"} { + $menu activate $entry + GenerateMenuSelect $menu + } } } diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index 6315638..c7610fc 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -755,7 +755,10 @@ TkpDestroyMenuEntry( * * TkpPostMenu -- * - * Posts a menu on the screen + * Posts a menu on the screen. If entry is < 0 then the menu is + * drawn so its top left corner is located at the point with + * screen coordinates (x, y). Otherwise the top left corner of + * the specified entry is located at that point. * * Results: * None. @@ -770,49 +773,47 @@ int TkpPostMenu( Tcl_Interp *interp, /* The interpreter this menu lives in */ TkMenu *menuPtr, /* The menu we are posting */ - int x, /* The global x-coordinate of the top, left- - * hand corner of where the menu is supposed - * to be posted. */ - int y) /* The global y-coordinate */ + int x, int y, /* The screen coordinates where the top left + * corner of the menu, or of the specified + * entry, will be located. */ + int entry) { - - /* Get the object that holds this Tk Window.*/ - Tk_Window root; - root = Tk_MainWindow(interp); + Tk_Window root = Tk_MainWindow(interp); + if (root == NULL) { return TCL_ERROR; } + if (menuPtr->menuType == TEAROFF_MENU) { + entry -= 1; + } Drawable d = Tk_WindowId(root); NSView *rootview = TkMacOSXGetRootControl(d); NSWindow *win = [rootview window]; - int result; + NSView *view = [win contentView]; + NSMenu *menu = (NSMenu *) menuPtr->platformData; + NSMenuItem *item = nil; + NSInteger index = entry; + NSPoint location = NSMakePoint(x, tkMacOSXZeroScreenHeight - y); + int result, oldMode; inPostMenu = 1; - result = TkPreprocessMenu(menuPtr); if (result != TCL_OK) { inPostMenu = 0; return result; } - - int oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE); - NSView *view = [win contentView]; - NSRect frame = NSMakeRect(x, tkMacOSXZeroScreenHeight - y, 1, 1); - - frame.origin = [view convertPoint: - [win tkConvertPointFromScreen:frame.origin] fromView:nil]; - - NSMenu *menu = (NSMenu *) menuPtr->platformData; - NSPopUpButtonCell *popUpButtonCell = [[NSPopUpButtonCell alloc] - initTextCell:@"" pullsDown:NO]; - - [popUpButtonCell setAltersStateOfSelectedItem:NO]; - [popUpButtonCell setMenu:menu]; - [popUpButtonCell selectItem:nil]; - [popUpButtonCell performClickWithFrame:frame inView:view]; - [popUpButtonCell release]; + if (index >= [menu numberOfItems]) { + index = [menu numberOfItems] - 1; + } + if (index >= 0) { + item = [menu itemAtIndex:index]; + } + oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE); + [menu popUpMenuPositioningItem:item + atLocation:[win tkConvertPointFromScreen:location] + inView:view]; Tcl_SetServiceMode(oldMode); inPostMenu = 0; return TCL_OK; @@ -1087,6 +1088,7 @@ void TkpComputeStandardMenuGeometry( TkMenu *menuPtr) /* Structure describing menu. */ { + NSSize menuSize = [(NSMenu *)menuPtr->platformData size]; Tk_Font tkfont, menuFont; Tk_FontMetrics menuMetrics, entryMetrics, *fmPtr; int modifierCharWidth, menuModifierCharWidth; @@ -1130,7 +1132,7 @@ TkpComputeStandardMenuGeometry( break; } } - + for (i = 0; i < menuPtr->numEntries; i++) { mePtr = menuPtr->entries[i]; if (mePtr->type == TEAROFF_ENTRY) { @@ -1199,6 +1201,9 @@ TkpComputeStandardMenuGeometry( height = size.height; } } + else { + /* image only. */ + } labelWidth = width + menuItemExtraWidth; mePtr->height = height + menuItemExtraHeight; if (mePtr->type == CASCADE_ENTRY) { @@ -1237,18 +1242,12 @@ TkpComputeStandardMenuGeometry( mePtr->x = x; mePtr->y = y; y += menuPtr->entries[i]->height + borderWidth; - if (y > windowHeight) { - windowHeight = y; - } } - - windowWidth = x + maxIndicatorSpace + maxWidth - + 2 * activeBorderWidth + borderWidth; - windowHeight += borderWidth; - + windowWidth = menuSize.width; if (windowWidth <= 0) { windowWidth = 1; } + windowHeight = menuSize.height; if (windowHeight <= 0) { windowHeight = 1; } diff --git a/tests/menu.test b/tests/menu.test index 95699ff..dcc578f 100644 --- a/tests/menu.test +++ b/tests/menu.test @@ -1606,7 +1606,7 @@ test menu-3.47 {MenuWidgetCmd procedure, "post" option} -setup { .m1 post } -cleanup { destroy .m1 -} -returnCodes error -result {wrong # args: should be ".m1 post x y"} +} -returnCodes error -result {wrong # args: should be ".m1 post x y ?entry?"} test menu-3.48 {MenuWidgetCmd procedure, "post" option} -setup { destroy .m1 } -body { diff --git a/unix/tkUnixMenu.c b/unix/tkUnixMenu.c index 38b6c58..f701819 100644 --- a/unix/tkUnixMenu.c +++ b/unix/tkUnixMenu.c @@ -889,7 +889,10 @@ DrawMenuUnderline( * * TkpPostMenu -- * - * Posts a menu on the screen + * Posts a menu on the screen so that the top left corner of the + * specified entry is located at the point (x, y) in screen coordinates. + * If the entry parameter is negative, the upper left corner of the + * menu itself is placed at the point. * * Results: * None. @@ -904,8 +907,14 @@ int TkpPostMenu( Tcl_Interp *interp, TkMenu *menuPtr, - int x, int y) + int x, int y, int entry) { + if (entry >= menuPtr->numEntries) { + entry = menuPtr->numEntries - 1; + } + if (entry >= 0) { + y -= menuPtr->entries[entry]->y; + } return TkPostTearoffMenu(interp, menuPtr, x, y); } @@ -1721,7 +1730,6 @@ TkpComputeStandardMenuGeometry( } windowWidth = x + indicatorSpace + labelWidth + accelWidth + 2 * activeBorderWidth + borderWidth; - windowHeight += borderWidth; /* diff --git a/win/tkWinMenu.c b/win/tkWinMenu.c index a409764..2957b0e 100644 --- a/win/tkWinMenu.c +++ b/win/tkWinMenu.c @@ -743,7 +743,10 @@ ReconfigureWindowsMenu( * * TkpPostMenu -- * - * Posts a menu on the screen + * Posts a menu on the screen so that the top left corner of the + * specified entry is located at the point (x, y) in screen coordinates. + * If the entry parameter is negative, the upper left corner of the + * menu itself is placed at the point. * * Results: * None. @@ -758,7 +761,7 @@ int TkpPostMenu( Tcl_Interp *interp, TkMenu *menuPtr, - int x, int y) + int x, int y, int entry) { HMENU winMenuHdl = (HMENU) menuPtr->platformData; int result, flags; @@ -770,7 +773,6 @@ TkpPostMenu( Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); tsdPtr->inPostMenu++; - CallPendingReconfigureImmediately(menuPtr); result = TkPreprocessMenu(menuPtr); @@ -779,6 +781,13 @@ TkpPostMenu( return result; } + if (entry >= menuPtr->numEntries) { + entry = menuPtr->numEntries - 1; + } + if (entry >= 0) { + y -= menuPtr->entries[entry]->y; + } + /* * The post commands could have deleted the menu, which means * we are dead and should go away. @@ -2897,7 +2906,6 @@ TkpComputeStandardMenuGeometry( GetTearoffEntryGeometry(menuPtr, menuPtr->entries[i], tkfont, fmPtr, &width, &height); menuPtr->entries[i]->height = height; - } else { /* * For each entry, compute the height required by that particular @@ -2955,8 +2963,6 @@ TkpComputeStandardMenuGeometry( } windowWidth = x + indicatorSpace + labelWidth + accelWidth + 2 * activeBorderWidth + borderWidth; - - windowHeight += borderWidth; /* -- cgit v0.12 From cff021b2dc7bf601b37714ae36bfa4fd510dbd1d Mon Sep 17 00:00:00 2001 From: fvogel Date: Sun, 13 Jan 2019 14:35:13 +0000 Subject: Fix [3003895fff] and [1899040fff] with a different fix, this time it does not resurrect [220665ffff] or duplicates [220265ffff] [779559ffff]. All scale.test tests do pass now. --- generic/tkScale.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/generic/tkScale.c b/generic/tkScale.c index 547f698..979d39d 100644 --- a/generic/tkScale.c +++ b/generic/tkScale.c @@ -1142,17 +1142,8 @@ TkRoundValueToResolution( TkScale *scalePtr, /* Information about scale widget. */ double value) /* Value to round. */ { - double rem, start; - - if (scalePtr->resolution <= 0) { - return value; - } - start = fmod(scalePtr->fromValue, scalePtr->resolution); - rem = fmod(value - start + scalePtr->resolution/2, scalePtr->resolution); - if (rem < 0) { - rem += scalePtr->resolution; - } - return value + scalePtr->resolution/2 - rem; + return TkRoundIntervalToResolution(scalePtr, value - scalePtr->fromValue) + + scalePtr->fromValue; } double @@ -1160,16 +1151,24 @@ TkRoundIntervalToResolution( TkScale *scalePtr, /* Information about scale widget. */ double value) /* Value to round. */ { - double rem; + double rem, rounded, tick; if (scalePtr->resolution <= 0) { return value; } - rem = fmod(value + scalePtr->resolution/2, scalePtr->resolution); + tick = floor(value/scalePtr->resolution); + rounded = scalePtr->resolution * tick; + rem = value - rounded; if (rem < 0) { - rem += scalePtr->resolution; + if (rem <= -scalePtr->resolution/2) { + rounded = (tick - 1.0) * scalePtr->resolution; + } + } else { + if (rem >= scalePtr->resolution/2) { + rounded = (tick + 1.0) * scalePtr->resolution; + } } - return value + scalePtr->resolution/2 - rem; + return rounded; } /* -- cgit v0.12 From c5018a98c472597e3f6e1bb4717bdf89b89c2cf2 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Sun, 13 Jan 2019 14:44:54 +0000 Subject: Not actually necessary to fix those (they don't give warnings because those are switched off), but while on it it's better to correct those ill-usages of 'None' too --- generic/tkCanvPoly.c | 2 +- generic/tkRectOval.c | 2 +- generic/tkSquare.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/generic/tkCanvPoly.c b/generic/tkCanvPoly.c index 630400f..7171e9f 100644 --- a/generic/tkCanvPoly.c +++ b/generic/tkCanvPoly.c @@ -524,7 +524,7 @@ ConfigurePolygon( * Mac OS X CG drawing needs access to the outline linewidth * even for fills (as linewidth controls antialiasing). */ - gcValues.line_width = polyPtr->outline.gc != None ? + gcValues.line_width = polyPtr->outline.gc != NULL ? polyPtr->outline.gc->line_width : 0; mask |= GCLineWidth; #endif diff --git a/generic/tkRectOval.c b/generic/tkRectOval.c index 4431341..55c2a61 100644 --- a/generic/tkRectOval.c +++ b/generic/tkRectOval.c @@ -522,7 +522,7 @@ ConfigureRectOval( * Mac OS X CG drawing needs access to the outline linewidth * even for fills (as linewidth controls antialiasing). */ - gcValues.line_width = rectOvalPtr->outline.gc != None ? + gcValues.line_width = rectOvalPtr->outline.gc != NULL ? rectOvalPtr->outline.gc->line_width : 0; mask |= GCLineWidth; #endif diff --git a/generic/tkSquare.c b/generic/tkSquare.c index 355a447..b8a4fad 100644 --- a/generic/tkSquare.c +++ b/generic/tkSquare.c @@ -332,7 +332,7 @@ SquareConfigure( Tk_SetWindowBackground(squarePtr->tkwin, Tk_3DBorderColor(bgBorder)->pixel); Tcl_GetBooleanFromObj(NULL, squarePtr->doubleBufferPtr, &doubleBuffer); - if ((squarePtr->gc == None) && (doubleBuffer)) { + if ((squarePtr->gc == NULL) && doubleBuffer) { XGCValues gcValues; gcValues.function = GXcopy; gcValues.graphics_exposures = False; @@ -397,7 +397,7 @@ SquareObjEventProc( if (squarePtr->tkwin != NULL) { Tk_FreeConfigOptions((char *) squarePtr, squarePtr->optionTable, squarePtr->tkwin); - if (squarePtr->gc != None) { + if (squarePtr->gc != NULL) { Tk_FreeGC(squarePtr->display, squarePtr->gc); } squarePtr->tkwin = NULL; -- cgit v0.12 From 2d798f8f6006c84bc6f4042e618ce5d7e905412c Mon Sep 17 00:00:00 2001 From: culler Date: Sun, 13 Jan 2019 16:43:19 +0000 Subject: Avoid errors when a menu is destroyed before its postcommand is run. --- library/menu.tcl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/menu.tcl b/library/menu.tcl index cdfcc13..8d06868 100644 --- a/library/menu.tcl +++ b/library/menu.tcl @@ -493,11 +493,13 @@ proc ::tk::MenuMotion {menu x y state} { if {[string is false $mode]} { set delay [expr {[$menu cget -type] eq "menubar" ? 0 : 50}] if {[$menu type $index] eq "cascade"} { + # Catch these postcascade commands since the menu could be + # destroyed before they run. set Priv(menuActivatedTimer) \ - [after $delay [list $menu postcascade active]] + [after $delay "catch {$menu postcascade active}"] } else { set Priv(menuDeactivatedTimer) \ - [after $delay [list $menu postcascade none]] + [after $delay "catch {$menu postcascade none}"] } } } -- cgit v0.12 From 2f5b18681b5ac4100ef19d65ae31babbc0e840b4 Mon Sep 17 00:00:00 2001 From: culler Date: Sun, 13 Jan 2019 18:02:47 +0000 Subject: Add TkpPostTearoffMenu, called by TkPostTearoffMenu and used in the menu post command; eliminates #ifdef in the generic code. --- generic/tkMenu.c | 11 +----- generic/tkMenu.h | 4 ++- generic/tkMenuDraw.c | 64 ++--------------------------------- macosx/tkMacOSXMenu.c | 21 ++++++++---- unix/tkUnixMenu.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++- win/tkWinMenu.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 206 insertions(+), 79 deletions(-) diff --git a/generic/tkMenu.c b/generic/tkMenu.c index f1ea8ff..e798337 100644 --- a/generic/tkMenu.c +++ b/generic/tkMenu.c @@ -881,11 +881,6 @@ MenuWidgetObjCmd( goto error; } if (objc == 5) { - if (menuPtr->menuType == TEAROFF_MENU) { - Tcl_AppendResult(interp, - "the index option is invalid for tearoff menus", NULL); - return TCL_ERROR; - } if (Tcl_GetIntFromObj(interp, objv[4], &entry) != TCL_OK) { goto error; } @@ -905,11 +900,7 @@ MenuWidgetObjCmd( } else if (menuPtr->menuType != TEAROFF_MENU) { result = TkpPostMenu(interp, menuPtr, x, y, entry); } else { -#ifdef TK_MAC_OSX - result = TkpPostMenu(interp, menuPtr, x, y, entry); -#else - result = TkPostTearoffMenu(interp, menuPtr, x, y); -#endif + result = TkpPostTearoffMenu(interp, menuPtr, x, y, entry); } break; } diff --git a/generic/tkMenu.h b/generic/tkMenu.h index 92bf8b2..2c4e051 100644 --- a/generic/tkMenu.h +++ b/generic/tkMenu.h @@ -520,7 +520,7 @@ MODULE_SCOPE int TkPostCommand(TkMenu *menuPtr); MODULE_SCOPE int TkPostSubmenu(Tcl_Interp *interp, TkMenu *menuPtr, TkMenuEntry *mePtr); MODULE_SCOPE int TkPostTearoffMenu(Tcl_Interp *interp, TkMenu *menuPtr, - int x, int y); + int x, int y); MODULE_SCOPE int TkPreprocessMenu(TkMenu *menuPtr); MODULE_SCOPE void TkRecomputeMenu(TkMenu *menuPtr); @@ -544,6 +544,8 @@ MODULE_SCOPE int TkpMenuNewEntry(TkMenuEntry *mePtr); MODULE_SCOPE int TkpNewMenu(TkMenu *menuPtr); MODULE_SCOPE int TkpPostMenu(Tcl_Interp *interp, TkMenu *menuPtr, int x, int y, int entry); +MODULE_SCOPE int TkpPostTearoffMenu(Tcl_Interp *interp, TkMenu *menuPtr, + int x, int y, int entry); MODULE_SCOPE void TkpSetWindowMenuBar(Tk_Window tkwin, TkMenu *menuPtr); #endif /* _TKMENU */ diff --git a/generic/tkMenuDraw.c b/generic/tkMenuDraw.c index 3f492db..e954559 100644 --- a/generic/tkMenuDraw.c +++ b/generic/tkMenuDraw.c @@ -807,9 +807,8 @@ TkMenuImageProc( * * TkPostTearoffMenu -- * - * Posts a menu on the screen. Used to post tearoff menus. On Unix, all - * menus are posted this way. Adjusts the menu's position so that it fits - * on the screen, and maps and raises the menu. + * Posts a tearoff menu on the screen. Adjusts the menu's position so + * that it fits on the screen, and maps and raises the menu. * * Results: * Returns a standard Tcl Error. @@ -827,64 +826,7 @@ TkPostTearoffMenu( int x, int y) /* The root X,Y coordinates where we are * posting */ { - int vRootX, vRootY, vRootWidth, vRootHeight; - int result; - - TkActivateMenuEntry(menuPtr, -1); - TkRecomputeMenu(menuPtr); - result = TkPostCommand(menuPtr); - if (result != TCL_OK) { - return result; - } - - /* - * The post commands could have deleted the menu, which means we are dead - * and should go away. - */ - - if (menuPtr->tkwin == NULL) { - return TCL_OK; - } - - /* - * Adjust the position of the menu if necessary to keep it visible on the - * screen. There are two special tricks to make this work right: - * - * 1. If a virtual root window manager is being used then the coordinates - * are in the virtual root window of menuPtr's parent; since the menu - * uses override-redirect mode it will be in the *real* root window for - * the screen, so we have to map the coordinates from the virtual root - * (if any) to the real root. Can't get the virtual root from the menu - * itself (it will never be seen by the wm) so use its parent instead - * (it would be better to have an an option that names a window to use - * for this...). - * 2. The menu may not have been mapped yet, so its current size might be - * the default 1x1. To compute how much space it needs, use its - * requested size, not its actual size. - */ - - Tk_GetVRootGeometry(Tk_Parent(menuPtr->tkwin), &vRootX, &vRootY, - &vRootWidth, &vRootHeight); - vRootWidth -= Tk_ReqWidth(menuPtr->tkwin); - if (x > vRootX + vRootWidth) { - x = vRootX + vRootWidth; - } - if (x < vRootX) { - x = vRootX; - } - vRootHeight -= Tk_ReqHeight(menuPtr->tkwin); - if (y > vRootY + vRootHeight) { - y = vRootY + vRootHeight; - } - if (y < vRootY) { - y = vRootY; - } - Tk_MoveToplevelWindow(menuPtr->tkwin, x, y); - if (!Tk_IsMapped(menuPtr->tkwin)) { - Tk_MapWindow(menuPtr->tkwin); - } - TkWmRestackToplevel((TkWindow *) menuPtr->tkwin, Above, NULL); - return TCL_OK; + return TkpPostTearoffMenu(interp, menuPtr, x, y, -1); } /* diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index c7610fc..044b20c 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -753,9 +753,10 @@ TkpDestroyMenuEntry( /* *---------------------------------------------------------------------- * - * TkpPostMenu -- + * TkpPostMenu, TkPostTearoffMenu -- * - * Posts a menu on the screen. If entry is < 0 then the menu is + * Posts a menu on the screen. (Tearoff menus are the same as + * ordinary menus on the mac.) If entry is < 0 then the menu is * drawn so its top left corner is located at the point with * screen coordinates (x, y). Otherwise the top left corner of * the specified entry is located at that point. @@ -784,10 +785,6 @@ TkpPostMenu( if (root == NULL) { return TCL_ERROR; } - if (menuPtr->menuType == TEAROFF_MENU) { - entry -= 1; - } - Drawable d = Tk_WindowId(root); NSView *rootview = TkMacOSXGetRootControl(d); NSWindow *win = [rootview window]; @@ -818,6 +815,18 @@ TkpPostMenu( inPostMenu = 0; return TCL_OK; } + +int +TkpPostTearoffMenu( + Tcl_Interp *interp, /* The interpreter this menu lives in */ + TkMenu *menuPtr, /* The menu we are posting */ + int x, int y, /* The screen coordinates where the top left + * corner of the menu, or of the specified + * entry, will be located. */ + int entry) +{ + return TkpPostMenu(interp, menuPtr, x, y, entry); +} /* *---------------------------------------------------------------------- diff --git a/unix/tkUnixMenu.c b/unix/tkUnixMenu.c index f701819..c5c83ce 100644 --- a/unix/tkUnixMenu.c +++ b/unix/tkUnixMenu.c @@ -909,13 +909,102 @@ TkpPostMenu( TkMenu *menuPtr, int x, int y, int entry) { + return TkpPostTearoffMenu(interp, menuPtr, x, y, entry); +} + +/* + *---------------------------------------------------------------------- + * + * TkpPostTearoffMenu -- + * + * Posts a tearoff menu on the screen so that the top left corner of the + * specified entry is located at the point (x, y) in screen coordinates. + * If the entry parameter is negative, the upper left corner of the menu + * itself is placed at the point. On unix this is called when posting + * any menu. Adjusts the menu's position so that it fits on the screen, + * and maps and raises the menu. + * + * Results: + * Returns a standard Tcl Error. + * + * Side effects: + * The menu is posted. + * + *---------------------------------------------------------------------- + */ + +int +TkpPostTearoffMenu( + Tcl_Interp *interp, /* The interpreter of the menu */ + TkMenu *menuPtr, /* The menu we are posting */ + int x, int y, int entry) /* The root X,Y coordinates where the + * specified entry will be posted */ +{ + int vRootX, vRootY, vRootWidth, vRootHeight; + int result; + if (entry >= menuPtr->numEntries) { entry = menuPtr->numEntries - 1; } if (entry >= 0) { y -= menuPtr->entries[entry]->y; } - return TkPostTearoffMenu(interp, menuPtr, x, y); + + TkActivateMenuEntry(menuPtr, -1); + TkRecomputeMenu(menuPtr); + result = TkPostCommand(menuPtr); + if (result != TCL_OK) { + return result; + } + + /* + * The post commands could have deleted the menu, which means we are dead + * and should go away. + */ + + if (menuPtr->tkwin == NULL) { + return TCL_OK; + } + + /* + * Adjust the position of the menu if necessary to keep it visible on the + * screen. There are two special tricks to make this work right: + * + * 1. If a virtual root window manager is being used then the coordinates + * are in the virtual root window of menuPtr's parent; since the menu + * uses override-redirect mode it will be in the *real* root window for + * the screen, so we have to map the coordinates from the virtual root + * (if any) to the real root. Can't get the virtual root from the menu + * itself (it will never be seen by the wm) so use its parent instead + * (it would be better to have an an option that names a window to use + * for this...). + * 2. The menu may not have been mapped yet, so its current size might be + * the default 1x1. To compute how much space it needs, use its + * requested size, not its actual size. + */ + + Tk_GetVRootGeometry(Tk_Parent(menuPtr->tkwin), &vRootX, &vRootY, + &vRootWidth, &vRootHeight); + vRootWidth -= Tk_ReqWidth(menuPtr->tkwin); + if (x > vRootX + vRootWidth) { + x = vRootX + vRootWidth; + } + if (x < vRootX) { + x = vRootX; + } + vRootHeight -= Tk_ReqHeight(menuPtr->tkwin); + if (y > vRootY + vRootHeight) { + y = vRootY + vRootHeight; + } + if (y < vRootY) { + y = vRootY; + } + Tk_MoveToplevelWindow(menuPtr->tkwin, x, y); + if (!Tk_IsMapped(menuPtr->tkwin)) { + Tk_MapWindow(menuPtr->tkwin); + } + TkWmRestackToplevel((TkWindow *) menuPtr->tkwin, Above, NULL); + return TCL_OK; } /* diff --git a/win/tkWinMenu.c b/win/tkWinMenu.c index 2957b0e..f1ac9b7 100644 --- a/win/tkWinMenu.c +++ b/win/tkWinMenu.c @@ -850,6 +850,100 @@ TkpPostMenu( /* *---------------------------------------------------------------------- * + * TkpPostTearoffMenu -- + * + * Posts a tearoff menu on the screen so that the top left corner of the + * specified entry is located at the point (x, y) in screen coordinates. + * If the entry parameter is negative, the upper left corner of the menu + * itself is placed at the point. Adjusts the menu's position so that it + * fits on the screen, and maps and raises the menu. + * + * Results: + * Returns a standard Tcl Error. + * + * Side effects: + * The menu is posted. + * + *---------------------------------------------------------------------- + */ + +int +TkpPostTearoffMenu( + Tcl_Interp *interp, /* The interpreter of the menu */ + TkMenu *menuPtr, /* The menu we are posting */ + int x, int y, int entry) /* The root X,Y coordinates where we are + * posting */ +{ + int vRootX, vRootY, vRootWidth, vRootHeight; + int result; + + if (entry >= menuPtr->numEntries) { + entry = menuPtr->numEntries - 1; + } + if (entry >= 0) { + y -= menuPtr->entries[entry]->y; + } + + TkActivateMenuEntry(menuPtr, -1); + TkRecomputeMenu(menuPtr); + result = TkPostCommand(menuPtr); + if (result != TCL_OK) { + return result; + } + + /* + * The post commands could have deleted the menu, which means we are dead + * and should go away. + */ + + if (menuPtr->tkwin == NULL) { + return TCL_OK; + } + + /* + * Adjust the position of the menu if necessary to keep it visible on the + * screen. There are two special tricks to make this work right: + * + * 1. If a virtual root window manager is being used then the coordinates + * are in the virtual root window of menuPtr's parent; since the menu + * uses override-redirect mode it will be in the *real* root window for + * the screen, so we have to map the coordinates from the virtual root + * (if any) to the real root. Can't get the virtual root from the menu + * itself (it will never be seen by the wm) so use its parent instead + * (it would be better to have an an option that names a window to use + * for this...). + * 2. The menu may not have been mapped yet, so its current size might be + * the default 1x1. To compute how much space it needs, use its + * requested size, not its actual size. + */ + + Tk_GetVRootGeometry(Tk_Parent(menuPtr->tkwin), &vRootX, &vRootY, + &vRootWidth, &vRootHeight); + vRootWidth -= Tk_ReqWidth(menuPtr->tkwin); + if (x > vRootX + vRootWidth) { + x = vRootX + vRootWidth; + } + if (x < vRootX) { + x = vRootX; + } + vRootHeight -= Tk_ReqHeight(menuPtr->tkwin); + if (y > vRootY + vRootHeight) { + y = vRootY + vRootHeight; + } + if (y < vRootY) { + y = vRootY; + } + Tk_MoveToplevelWindow(menuPtr->tkwin, x, y); + if (!Tk_IsMapped(menuPtr->tkwin)) { + Tk_MapWindow(menuPtr->tkwin); + } + TkWmRestackToplevel((TkWindow *) menuPtr->tkwin, Above, NULL); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * * TkpMenuNewEntry -- * * Adds a pointer to a new menu entry structure with the platform- -- cgit v0.12 From cd265b13ef5f38b99caf9727279b7a68ccceac2a Mon Sep 17 00:00:00 2001 From: culler Date: Sun, 13 Jan 2019 19:24:18 +0000 Subject: Deal with empty menubuttons on the mac. --- macosx/tkMacOSXMenubutton.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/macosx/tkMacOSXMenubutton.c b/macosx/tkMacOSXMenubutton.c index 4df23b4..66bb4dd 100644 --- a/macosx/tkMacOSXMenubutton.c +++ b/macosx/tkMacOSXMenubutton.c @@ -244,7 +244,7 @@ void TkpComputeMenuButtonGeometry(butPtr) register TkMenuButton *butPtr; /* Widget record for menu button. */ { - int width, height, avgWidth, haveImage = 0, haveText = 0; + int width, height, avgWidth, haveImage = 0; int txtWidth, txtHeight; Tk_FontMetrics fm; int highlightWidth = butPtr->highlightWidth > 0 ? butPtr->highlightWidth : 0; @@ -267,6 +267,16 @@ TkpComputeMenuButtonGeometry(butPtr) haveImage = 1; } + /* + * Mac menubuttons do not display correctly with no image and empty text. + */ + + if (haveImage == 0 && strlen(butPtr->text) == 0) { + ckfree(butPtr->text); + butPtr->text = ckalloc(2); + strcpy(butPtr->text, " "); + } + if (haveImage == 0 || butPtr->compound != COMPOUND_NONE) { Tk_FreeTextLayout(butPtr->textLayout); butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont, @@ -277,7 +287,6 @@ TkpComputeMenuButtonGeometry(butPtr) txtHeight = butPtr->textHeight; avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1); Tk_GetFontMetrics(butPtr->tkfont, &fm); - haveText = (txtWidth != 0 && txtHeight != 2); } /* @@ -287,7 +296,7 @@ TkpComputeMenuButtonGeometry(butPtr) * image, because otherwise it is not really a compound button. */ - if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) { + if (butPtr->compound != COMPOUND_NONE && haveImage) { switch ((enum compound) butPtr->compound) { case COMPOUND_TOP: case COMPOUND_BOTTOM: { -- cgit v0.12 From fe7e4b1e7f825147345d7e42707be7d53b72c904 Mon Sep 17 00:00:00 2001 From: culler Date: Mon, 14 Jan 2019 13:57:38 +0000 Subject: Fix the underlying problem with empty menubuttons on the mac, rather than the symptom. --- macosx/tkMacOSXMenubutton.c | 48 +++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/macosx/tkMacOSXMenubutton.c b/macosx/tkMacOSXMenubutton.c index 66bb4dd..8e22fd8 100644 --- a/macosx/tkMacOSXMenubutton.c +++ b/macosx/tkMacOSXMenubutton.c @@ -110,7 +110,6 @@ Tk_ClassProcs tkpMenubuttonClass = { #define LEFT_INSET 8 #define RIGHT_INSET 28 #define MIN_HEIGHT 22 - /* *---------------------------------------------------------------------- @@ -267,22 +266,11 @@ TkpComputeMenuButtonGeometry(butPtr) haveImage = 1; } - /* - * Mac menubuttons do not display correctly with no image and empty text. - */ - - if (haveImage == 0 && strlen(butPtr->text) == 0) { - ckfree(butPtr->text); - butPtr->text = ckalloc(2); - strcpy(butPtr->text, " "); - } - if (haveImage == 0 || butPtr->compound != COMPOUND_NONE) { Tk_FreeTextLayout(butPtr->textLayout); butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont, butPtr->text, -1, butPtr->wrapLength, butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight); - txtWidth = butPtr->textWidth; txtHeight = butPtr->textHeight; avgWidth = Tk_TextWidth(butPtr->tkfont, "0", 1); @@ -358,8 +346,8 @@ TkpComputeMenuButtonGeometry(butPtr) } butPtr->inset = highlightWidth + butPtr->borderWidth; - width += LEFT_INSET + RIGHT_INSET + 2*butPtr->inset; - height += 2*butPtr->inset; + width += LEFT_INSET + RIGHT_INSET + 2*butPtr->inset; + height += 2*butPtr->inset; height = height < MIN_HEIGHT ? MIN_HEIGHT : height; Tk_GeometryRequest(butPtr->tkwin, width, height); Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset); @@ -425,8 +413,8 @@ DrawMenuButtonImageAndText( pressed = 1; } - haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0); - if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) { + haveText = (butPtr->textWidth != 0 && butPtr->textHeight != 0); + if (butPtr->compound != COMPOUND_NONE && haveImage && haveText) { int x = 0; int y = 0; textXOffset = 0; @@ -609,9 +597,11 @@ TkMacOSXDrawMenuButton( hiinfo.animation.time.start = hiinfo.animation.time.current; } - HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, kHIThemeOrientationNormal, &contHIRec); + HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, + kHIThemeOrientationNormal, &contHIRec); TkMacOSXRestoreDrawingContext(&dc); - MenuButtonContentDrawCB( mbPtr->btnkind, &mbPtr->drawinfo, (MacMenuButton *)mbPtr, 32, true); + MenuButtonContentDrawCB( mbPtr->btnkind, &mbPtr->drawinfo, + (MacMenuButton *)mbPtr, 32, true); } else { if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) { return; @@ -748,19 +738,18 @@ MenuButtonEventProc( */ static void -TkMacOSXComputeMenuButtonParams(TkMenuButton * butPtr, ThemeButtonKind* btnkind, HIThemeButtonDrawInfo *drawinfo) +TkMacOSXComputeMenuButtonParams( + TkMenuButton * butPtr, + ThemeButtonKind* btnkind, + HIThemeButtonDrawInfo *drawinfo) { MacMenuButton *mbPtr = (MacMenuButton *)butPtr; - if (butPtr->image || butPtr->bitmap) { + if (butPtr->image || butPtr->bitmap || butPtr->text) { /* TODO: allow for Small and Mini menubuttons. */ *btnkind = kThemePopupButton; - } else { - if (!butPtr->text || !*butPtr->text) { - *btnkind = kThemeArrowButton; - } else { - *btnkind = kThemePopupButton; - } + } else { /* This should never happen. */ + *btnkind = kThemeArrowButton; } drawinfo->value = kThemeButtonOff; @@ -812,9 +801,12 @@ TkMacOSXComputeMenuButtonParams(TkMenuButton * butPtr, ThemeButtonKind* btnkind, */ static void -TkMacOSXComputeMenuButtonDrawParams(TkMenuButton * butPtr, DrawParams * dpPtr) +TkMacOSXComputeMenuButtonDrawParams( + TkMenuButton * butPtr, + DrawParams * dpPtr) { - dpPtr->hasImageOrBitmap = ((butPtr->image != NULL) || (butPtr->bitmap != None)); + dpPtr->hasImageOrBitmap = ((butPtr->image != NULL) || + (butPtr->bitmap != None)); dpPtr->border = butPtr->normalBorder; if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) { dpPtr->gc = butPtr->disabledGC; -- cgit v0.12 From 4330a830cd514bf17caac0cfe5b29fef47022df7 Mon Sep 17 00:00:00 2001 From: culler Date: Tue, 15 Jan 2019 14:00:45 +0000 Subject: Use TkGetMenuIndex to parse the index argument to the post command. --- generic/tkMenu.c | 14 +++++++------- generic/tkMenu.h | 4 ++-- macosx/tkMacOSXMenu.c | 8 ++++---- unix/tkUnixMenu.c | 16 ++++++++-------- win/tkWinMenu.c | 22 +++++++++++----------- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/generic/tkMenu.c b/generic/tkMenu.c index e798337..2c0f9a9 100644 --- a/generic/tkMenu.c +++ b/generic/tkMenu.c @@ -870,10 +870,10 @@ MenuWidgetObjCmd( break; } case MENU_POST: { - int x, y, entry = -1; + int x, y, index = -1; if (objc != 4 && objc != 5) { - Tcl_WrongNumArgs(interp, 2, objv, "x y ?entry?"); + Tcl_WrongNumArgs(interp, 2, objv, "x y ?index?"); goto error; } if ((Tcl_GetIntFromObj(interp, objv[2], &x) != TCL_OK) @@ -881,9 +881,9 @@ MenuWidgetObjCmd( goto error; } if (objc == 5) { - if (Tcl_GetIntFromObj(interp, objv[4], &entry) != TCL_OK) { - goto error; - } + if (TkGetMenuIndex(interp, menuPtr, objv[4], 0, &index) != TCL_OK) { + goto error; + } } /* @@ -898,9 +898,9 @@ MenuWidgetObjCmd( Tcl_AppendResult(interp, "a menubar menu cannot be posted", NULL); return TCL_ERROR; } else if (menuPtr->menuType != TEAROFF_MENU) { - result = TkpPostMenu(interp, menuPtr, x, y, entry); + result = TkpPostMenu(interp, menuPtr, x, y, index); } else { - result = TkpPostTearoffMenu(interp, menuPtr, x, y, entry); + result = TkpPostTearoffMenu(interp, menuPtr, x, y, index); } break; } diff --git a/generic/tkMenu.h b/generic/tkMenu.h index 2c4e051..6d1fe5a 100644 --- a/generic/tkMenu.h +++ b/generic/tkMenu.h @@ -543,9 +543,9 @@ MODULE_SCOPE void TkpMenuInit(void); MODULE_SCOPE int TkpMenuNewEntry(TkMenuEntry *mePtr); MODULE_SCOPE int TkpNewMenu(TkMenu *menuPtr); MODULE_SCOPE int TkpPostMenu(Tcl_Interp *interp, TkMenu *menuPtr, - int x, int y, int entry); + int x, int y, int index); MODULE_SCOPE int TkpPostTearoffMenu(Tcl_Interp *interp, TkMenu *menuPtr, - int x, int y, int entry); + int x, int y, int index); MODULE_SCOPE void TkpSetWindowMenuBar(Tk_Window tkwin, TkMenu *menuPtr); #endif /* _TKMENU */ diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index 044b20c..1d3bd34 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -777,7 +777,7 @@ TkpPostMenu( int x, int y, /* The screen coordinates where the top left * corner of the menu, or of the specified * entry, will be located. */ - int entry) + int index) { /* Get the object that holds this Tk Window.*/ Tk_Window root = Tk_MainWindow(interp); @@ -791,7 +791,7 @@ TkpPostMenu( NSView *view = [win contentView]; NSMenu *menu = (NSMenu *) menuPtr->platformData; NSMenuItem *item = nil; - NSInteger index = entry; + NSInteger index = index; NSPoint location = NSMakePoint(x, tkMacOSXZeroScreenHeight - y); int result, oldMode; @@ -823,9 +823,9 @@ TkpPostTearoffMenu( int x, int y, /* The screen coordinates where the top left * corner of the menu, or of the specified * entry, will be located. */ - int entry) + int index) { - return TkpPostMenu(interp, menuPtr, x, y, entry); + return TkpPostMenu(interp, menuPtr, x, y, index); } /* diff --git a/unix/tkUnixMenu.c b/unix/tkUnixMenu.c index c5c83ce..d7ed873 100644 --- a/unix/tkUnixMenu.c +++ b/unix/tkUnixMenu.c @@ -907,9 +907,9 @@ int TkpPostMenu( Tcl_Interp *interp, TkMenu *menuPtr, - int x, int y, int entry) + int x, int y, int index) { - return TkpPostTearoffMenu(interp, menuPtr, x, y, entry); + return TkpPostTearoffMenu(interp, menuPtr, x, y, index); } /* @@ -919,7 +919,7 @@ TkpPostMenu( * * Posts a tearoff menu on the screen so that the top left corner of the * specified entry is located at the point (x, y) in screen coordinates. - * If the entry parameter is negative, the upper left corner of the menu + * If the index parameter is negative, the upper left corner of the menu * itself is placed at the point. On unix this is called when posting * any menu. Adjusts the menu's position so that it fits on the screen, * and maps and raises the menu. @@ -937,17 +937,17 @@ int TkpPostTearoffMenu( Tcl_Interp *interp, /* The interpreter of the menu */ TkMenu *menuPtr, /* The menu we are posting */ - int x, int y, int entry) /* The root X,Y coordinates where the + int x, int y, int index) /* The root X,Y coordinates where the * specified entry will be posted */ { int vRootX, vRootY, vRootWidth, vRootHeight; int result; - if (entry >= menuPtr->numEntries) { - entry = menuPtr->numEntries - 1; + if (index >= menuPtr->numEntries) { + index = menuPtr->numEntries - 1; } - if (entry >= 0) { - y -= menuPtr->entries[entry]->y; + if (index >= 0) { + y -= menuPtr->entries[index]->y; } TkActivateMenuEntry(menuPtr, -1); diff --git a/win/tkWinMenu.c b/win/tkWinMenu.c index f1ac9b7..af127bf 100644 --- a/win/tkWinMenu.c +++ b/win/tkWinMenu.c @@ -761,7 +761,7 @@ int TkpPostMenu( Tcl_Interp *interp, TkMenu *menuPtr, - int x, int y, int entry) + int x, int y, int index) { HMENU winMenuHdl = (HMENU) menuPtr->platformData; int result, flags; @@ -781,11 +781,11 @@ TkpPostMenu( return result; } - if (entry >= menuPtr->numEntries) { - entry = menuPtr->numEntries - 1; + if (index >= menuPtr->numEntries) { + index = menuPtr->numEntries - 1; } - if (entry >= 0) { - y -= menuPtr->entries[entry]->y; + if (index >= 0) { + y -= menuPtr->entries[index]->y; } /* @@ -854,7 +854,7 @@ TkpPostMenu( * * Posts a tearoff menu on the screen so that the top left corner of the * specified entry is located at the point (x, y) in screen coordinates. - * If the entry parameter is negative, the upper left corner of the menu + * If the index parameter is negative, the upper left corner of the menu * itself is placed at the point. Adjusts the menu's position so that it * fits on the screen, and maps and raises the menu. * @@ -871,17 +871,17 @@ int TkpPostTearoffMenu( Tcl_Interp *interp, /* The interpreter of the menu */ TkMenu *menuPtr, /* The menu we are posting */ - int x, int y, int entry) /* The root X,Y coordinates where we are + int x, int y, int index) /* The root X,Y coordinates where we are * posting */ { int vRootX, vRootY, vRootWidth, vRootHeight; int result; - if (entry >= menuPtr->numEntries) { - entry = menuPtr->numEntries - 1; + if (index >= menuPtr->numEntries) { + index = menuPtr->numEntries - 1; } - if (entry >= 0) { - y -= menuPtr->entries[entry]->y; + if (index >= 0) { + y -= menuPtr->entries[index]->y; } TkActivateMenuEntry(menuPtr, -1); -- cgit v0.12 From c30080a5540a2fd71dae2122cfd926a7ead68461 Mon Sep 17 00:00:00 2001 From: culler Date: Tue, 15 Jan 2019 14:48:31 +0000 Subject: Fix name collision on macOS. Clarify some logic in the geometry computation. --- macosx/tkMacOSXMenu.c | 3 +-- macosx/tkMacOSXMenubutton.c | 11 ++++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index 1d3bd34..f36da42 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -791,7 +791,6 @@ TkpPostMenu( NSView *view = [win contentView]; NSMenu *menu = (NSMenu *) menuPtr->platformData; NSMenuItem *item = nil; - NSInteger index = index; NSPoint location = NSMakePoint(x, tkMacOSXZeroScreenHeight - y); int result, oldMode; @@ -805,7 +804,7 @@ TkpPostMenu( index = [menu numberOfItems] - 1; } if (index >= 0) { - item = [menu itemAtIndex:index]; + item = [menu itemAtIndex:(NSInteger)index]; } oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE); [menu popUpMenuPositioningItem:item diff --git a/macosx/tkMacOSXMenubutton.c b/macosx/tkMacOSXMenubutton.c index 8e22fd8..b2b4b76 100644 --- a/macosx/tkMacOSXMenubutton.c +++ b/macosx/tkMacOSXMenubutton.c @@ -243,7 +243,7 @@ void TkpComputeMenuButtonGeometry(butPtr) register TkMenuButton *butPtr; /* Widget record for menu button. */ { - int width, height, avgWidth, haveImage = 0; + int width, height, avgWidth, haveImage = 0, haveText = 0; int txtWidth, txtHeight; Tk_FontMetrics fm; int highlightWidth = butPtr->highlightWidth > 0 ? butPtr->highlightWidth : 0; @@ -266,7 +266,8 @@ TkpComputeMenuButtonGeometry(butPtr) haveImage = 1; } - if (haveImage == 0 || butPtr->compound != COMPOUND_NONE) { + if (butPtr->text && strlen(butPtr->text) > 0) { + haveText = 1; Tk_FreeTextLayout(butPtr->textLayout); butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont, butPtr->text, -1, butPtr->wrapLength, @@ -284,7 +285,7 @@ TkpComputeMenuButtonGeometry(butPtr) * image, because otherwise it is not really a compound button. */ - if (butPtr->compound != COMPOUND_NONE && haveImage) { + if (haveImage && haveText) { switch ((enum compound) butPtr->compound) { case COMPOUND_TOP: case COMPOUND_BOTTOM: { @@ -326,14 +327,14 @@ TkpComputeMenuButtonGeometry(butPtr) } } else { - if (haveImage) { + if (haveImage) { /* Image only */ if (butPtr->width > 0) { width = butPtr->width; } if (butPtr->height > 0) { height = butPtr->height; } - } else { + } else { /* Text only */ width = txtWidth; height = txtHeight; if (butPtr->width > 0) { -- cgit v0.12 From 0108f0519ddb45089bcd6e5e1e1b62112214df24 Mon Sep 17 00:00:00 2001 From: culler Date: Tue, 15 Jan 2019 21:22:45 +0000 Subject: For macOS, guard against a crash in TkpPostMenu and fix TkPostTearoffMenu. Adjust menu.test for the new argument name. --- macosx/tkMacOSXMenu.c | 26 +++++++++++++++----------- tests/menu.test | 2 +- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index f36da42..ed8d0c3 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -779,7 +779,7 @@ TkpPostMenu( * entry, will be located. */ int index) { - /* Get the object that holds this Tk Window.*/ + int result, oldMode; Tk_Window root = Tk_MainWindow(interp); if (root == NULL) { @@ -790,9 +790,10 @@ TkpPostMenu( NSWindow *win = [rootview window]; NSView *view = [win contentView]; NSMenu *menu = (NSMenu *) menuPtr->platformData; + NSInteger itemIndex = index; + NSInteger numItems = [menu numberOfItems]; NSMenuItem *item = nil; NSPoint location = NSMakePoint(x, tkMacOSXZeroScreenHeight - y); - int result, oldMode; inPostMenu = 1; result = TkPreprocessMenu(menuPtr); @@ -800,17 +801,19 @@ TkpPostMenu( inPostMenu = 0; return result; } - if (index >= [menu numberOfItems]) { - index = [menu numberOfItems] - 1; + if (itemIndex >= numItems) { + itemIndex = numItems - 1; + } + if (itemIndex >= 0) { + item = [menu itemAtIndex:itemIndex]; } - if (index >= 0) { - item = [menu itemAtIndex:(NSInteger)index]; + if (menu != nil && item != nil) { + oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE); + [menu popUpMenuPositioningItem:item + atLocation:[win tkConvertPointFromScreen:location] + inView:view]; + Tcl_SetServiceMode(oldMode); } - oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE); - [menu popUpMenuPositioningItem:item - atLocation:[win tkConvertPointFromScreen:location] - inView:view]; - Tcl_SetServiceMode(oldMode); inPostMenu = 0; return TCL_OK; } @@ -824,6 +827,7 @@ TkpPostTearoffMenu( * entry, will be located. */ int index) { + menuPtr->active = -1; return TkpPostMenu(interp, menuPtr, x, y, index); } diff --git a/tests/menu.test b/tests/menu.test index dcc578f..9ad2a0c 100644 --- a/tests/menu.test +++ b/tests/menu.test @@ -1606,7 +1606,7 @@ test menu-3.47 {MenuWidgetCmd procedure, "post" option} -setup { .m1 post } -cleanup { destroy .m1 -} -returnCodes error -result {wrong # args: should be ".m1 post x y ?entry?"} +} -returnCodes error -result {wrong # args: should be ".m1 post x y ?index?"} test menu-3.48 {MenuWidgetCmd procedure, "post" option} -setup { destroy .m1 } -body { -- cgit v0.12 From c910f94eaaf0390532bf9b6f96c43e89c2e7939d Mon Sep 17 00:00:00 2001 From: culler Date: Wed, 16 Jan 2019 03:41:10 +0000 Subject: Fix bug [e733d3770f]: geometry issues with buttons on macOS --- library/demos/puzzle.tcl | 2 +- macosx/tkMacOSXButton.c | 141 ++++++++++++++++++----------------------------- tests/unixButton.test | 24 ++++++-- 3 files changed, 74 insertions(+), 93 deletions(-) diff --git a/library/demos/puzzle.tcl b/library/demos/puzzle.tcl index 4f7f955..eebe87a 100644 --- a/library/demos/puzzle.tcl +++ b/library/demos/puzzle.tcl @@ -73,7 +73,7 @@ for {set i 0} {$i < 15} {set i [expr {$i+1}]} { set num [lindex $order $i] set xpos($num) [expr {($i%4)*.25}] set ypos($num) [expr {($i/4)*.25}] - button $w.frame.$num -relief raised -text $num -highlightthickness 0 \ + button $w.frame.$num -relief raised -text $num -bd 0 -highlightthickness 0 \ -command "puzzleSwitch $w $num" place $w.frame.$num -relx $xpos($num) -rely $ypos($num) \ -relwidth .25 -relheight .25 diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index ea78d43..d387b83 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -29,19 +29,10 @@ * be allowed when drawing the HITheme button. */ -#define HI_PADX 2 +#define HI_PADX 14 #define HI_PADY 1 /* - * Some defines used to control what type of control is drawn. - */ - -#define DRAW_LABEL 0 /* Labels are treated genericly. */ -#define DRAW_CONTROL 1 /* Draw using the Native control. */ -#define DRAW_CUSTOM 2 /* Make our own button drawing. */ -#define DRAW_BEVEL 3 - -/* * The delay in milliseconds between pulsing default button redraws. */ #define PULSE_TIMER_MSECS 62 /* Largest value that didn't look stuttery */ @@ -52,7 +43,6 @@ typedef struct { - int drawType; Tk_3DBorder border; int relief; int offset; /* 0 means this is a normal widget. 1 means @@ -271,11 +261,7 @@ TkpComputeButtonGeometry( int txtWidth = 0, txtHeight = 0; MacButton *mbPtr = (MacButton*)butPtr; Tk_FontMetrics fm; - DrawParams drawParams; - - /* - * First figure out the size of the contents of the button. - */ + char *text = Tcl_GetString(butPtr->textPtr); TkMacOSXComputeButtonParams(butPtr, &mbPtr->btnkind, &mbPtr->drawinfo); @@ -283,7 +269,7 @@ TkpComputeButtonGeometry( * If the indicator is on, get its size. */ - if ( butPtr->indicatorOn ) { + if (butPtr->indicatorOn) { switch (butPtr->type) { case TYPE_RADIO_BUTTON: GetThemeMetric(kThemeMetricRadioButtonWidth, (SInt32 *)&butPtr->indicatorDiameter); @@ -309,23 +295,22 @@ TkpComputeButtonGeometry( haveImage = 1; } - if (haveImage == 0 || butPtr->compound != COMPOUND_NONE) { + if (strlen(text) > 0) { Tk_FreeTextLayout(butPtr->textLayout); butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont, Tcl_GetString(butPtr->textPtr), -1, butPtr->wrapLength, butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight); - txtWidth = butPtr->textWidth; - txtHeight = butPtr->textHeight; - charWidth = Tk_TextWidth(butPtr->tkfont, "0", 1); - Tk_GetFontMetrics(butPtr->tkfont, &fm); - haveText = (txtWidth != 0 && txtHeight != 0); + txtWidth = butPtr->textWidth + 2*butPtr->padX; + txtHeight = butPtr->textHeight + 2*butPtr->padY; + haveText = 1; } if (haveImage && haveText) { /* Image and Text */ switch ((enum compound) butPtr->compound) { case COMPOUND_TOP: case COMPOUND_BOTTOM: + /* * Image is above or below text. */ @@ -335,14 +320,16 @@ TkpComputeButtonGeometry( break; case COMPOUND_LEFT: case COMPOUND_RIGHT: + /* * Image is left or right of text. */ - width += txtWidth + butPtr->padX; + width += txtWidth + 2*butPtr->padX; height = (height > txtHeight ? height : txtHeight); break; case COMPOUND_CENTER: + /* * Image and text are superimposed. */ @@ -354,26 +341,27 @@ TkpComputeButtonGeometry( break; } width += butPtr->indicatorSpace; - } else if (haveImage) { /* Image only */ - width = butPtr->width > 0 ? butPtr->width : width + butPtr->indicatorSpace; - height = butPtr->height > 0 ? butPtr->height : height; - + width = butPtr->width > 0 ? butPtr->width : width + butPtr->indicatorSpace; + height = butPtr->height > 0 ? butPtr->height : height; + if (butPtr->type == TYPE_BUTTON) { + /* Allow room to shift the image. */ + width += 2; + height += 2; + } } else { /* Text only */ width = txtWidth + butPtr->indicatorSpace; height = txtHeight; if (butPtr->width > 0) { - width = butPtr->width * charWidth; + charWidth = Tk_TextWidth(butPtr->tkfont, "0", 1); + width = butPtr->width * charWidth + 2*butPtr->padX; } if (butPtr->height > 0) { - height = butPtr->height * fm.linespace; + Tk_GetFontMetrics(butPtr->tkfont, &fm); + height = butPtr->height * fm.linespace + 2*butPtr->padY; } } - /* Add padding */ - width += 2 * butPtr->padX; - height += 2 * butPtr->padY; - /* * Now figure out the size of the border decorations for the button. */ @@ -382,48 +370,35 @@ TkpComputeButtonGeometry( butPtr->highlightWidth = 0; } - butPtr->inset = 0; - butPtr->inset += butPtr->highlightWidth; + butPtr->inset = butPtr->borderWidth + butPtr->highlightWidth; - if (TkMacOSXComputeButtonDrawParams(butPtr,&drawParams)) { + width += butPtr->inset*2; + height += butPtr->inset*2; + if ([NSApp macMinorVersion] == 6) { + width += 12; + } + if (mbPtr->btnkind == kThemePushButton) { HIRect tmpRect; HIRect contBounds; - int paddingx = 0; - int paddingy = 0; + /* + * A PushButton has a minimum size. We make sure that we + * are not underestimating the size by requesting the content + * size of a Pushbutton whose overall size is our content size + * expanded by the standard padding. + */ + tmpRect = CGRectMake(0, 0, width + 2*HI_PADX, height + 2*HI_PADY); - HIThemeGetButtonContentBounds(&tmpRect, &mbPtr->drawinfo, &contBounds); - /* If the content region has a minimum height, match it. */ if (height < contBounds.size.height) { - height = contBounds.size.height; + height = contBounds.size.height; } - - /* If the content region has a minimum width, match it. */ if (width < contBounds.size.width) { - width = contBounds.size.width; + width = contBounds.size.width; } - - /* Pad to fill difference between content bounds and button bounds. */ - paddingx = contBounds.origin.x; - paddingy = contBounds.origin.y; - - if (height < paddingx - 4) { - /* can't have buttons much shorter than button side diameter. */ - height = paddingx - 4; - } - - } else { - height += butPtr->borderWidth*2; - width += butPtr->borderWidth*2; - } - - width += butPtr->inset*2; - height += butPtr->inset*2; - if ([NSApp macMinorVersion] == 6) { - width += 12; + height += 2*HI_PADY; + width += 2*HI_PADX; } - Tk_GeometryRequest(butPtr->tkwin, width, height); Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset); } @@ -1119,7 +1094,6 @@ TkMacOSXComputeButtonDrawParams( } } - dpPtr->border = butPtr->normalBorder; if ((butPtr->state == STATE_DISABLED) && (butPtr->disabledFg != NULL)) { dpPtr->gc = butPtr->disabledGC; @@ -1149,29 +1123,22 @@ TkMacOSXComputeButtonDrawParams( } } - /* - * Determine the draw type - */ - - if (butPtr->type == TYPE_LABEL) { - dpPtr->drawType = DRAW_LABEL; - } else if (butPtr->type == TYPE_BUTTON) { - if (!dpPtr->hasImageOrBitmap) { - dpPtr->drawType = DRAW_CONTROL; - } else { - dpPtr->drawType = DRAW_BEVEL; - } - } else if (butPtr->indicatorOn) { - dpPtr->drawType = DRAW_CONTROL; - } else if (dpPtr->hasImageOrBitmap) { - dpPtr->drawType = DRAW_BEVEL; - } else { - dpPtr->drawType = DRAW_CUSTOM; - } - - if ((dpPtr->drawType == DRAW_CONTROL) || (dpPtr->drawType == DRAW_BEVEL)) { + if (butPtr->type != TYPE_LABEL && + (butPtr->type == TYPE_BUTTON || + butPtr->indicatorOn || + dpPtr->hasImageOrBitmap)) { + + /* + * Draw this widget as a native control. + */ + return 1; } else { + + /* + * Draw this widget from scratch. + */ + return 0; } } diff --git a/tests/unixButton.test b/tests/unixButton.test index 137ef33..c7b7b1d 100644 --- a/tests/unixButton.test +++ b/tests/unixButton.test @@ -35,7 +35,15 @@ proc bogusTrace args { error "trace aborted" } - +if {[tk windowingsystem] eq "aqua"} { + set smallIndicator 20 + set bigIndicator 20 + set defaultBorder 10 +} else { + set smallIndicator 27 + set bigindicator 40 + set defaultBorder 20 +} test unixbutton-1.1 {TkpComputeButtonGeometry procedure} -constraints { unix testImageType } -setup { @@ -57,7 +65,10 @@ test unixbutton-1.1 {TkpComputeButtonGeometry procedure} -constraints { } -cleanup { deleteWindows image delete image1 -} -result {68 48 74 54 112 52 112 52} +} -result [list 68 48 \ + 74 54 \ + [expr {72 + $bigIndicator}] 52 \ + [expr {72 + $bigIndicator}] 52] test unixbutton-1.2 {TkpComputeButtonGeometry procedure} -constraints { unix } -setup { @@ -75,7 +86,10 @@ test unixbutton-1.2 {TkpComputeButtonGeometry procedure} -constraints { [winfo reqwidth .b4] [winfo reqheight .b4] } -cleanup { deleteWindows -} -result {23 33 29 39 54 37 54 37} +} -result [list 23 33 \ + 29 39 \ + [expr {27 + $smallIndicator}] 37 \ + [expr {27 + $smallIndicator}] 37] test unixbutton-1.3 {TkpComputeButtonGeometry procedure} -constraints { unix } -setup { @@ -186,7 +200,7 @@ test unixbutton-1.9 {TkpComputeButtonGeometry procedure} -constraints { list [winfo reqwidth .b2] [winfo reqheight .b2] } -cleanup { deleteWindows -} -result {37 47} +} -result [list [expr {17 + $defaultBorder}] [expr {27 + $defaultBorder}]] test unixbutton-1.10 {TkpComputeButtonGeometry procedure} -constraints { unix } -setup { @@ -196,7 +210,7 @@ test unixbutton-1.10 {TkpComputeButtonGeometry procedure} -constraints { list [winfo reqwidth .b2] [winfo reqheight .b2] } -cleanup { deleteWindows -} -result {37 47} +} -result [list [expr {17 + $defaultBorder}] [expr {27 + $defaultBorder}]] test unixbutton-1.11 {TkpComputeButtonGeometry procedure} -constraints { unix } -setup { -- cgit v0.12 From bf838a24f35ee704ccdc9b8538c32a1559f4c3e7 Mon Sep 17 00:00:00 2001 From: culler Date: Wed, 16 Jan 2019 14:06:13 +0000 Subject: Tiny adjustment to text position, to match native buttons. --- macosx/tkMacOSXButton.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index d387b83..c0b83f2 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -545,7 +545,6 @@ DrawButtonImageAndText( } imageXOffset += x; imageYOffset += y; - textYOffset -= 1; if (butPtr->image != NULL) { if ((butPtr->selectImage != NULL) && @@ -569,6 +568,7 @@ DrawButtonImageAndText( XSetClipOrigin(butPtr->display, dpPtr->gc, 0, 0); } + y += 1; /* Tweak to match native buttons. */ Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, butPtr->textLayout, x + textXOffset, y + textYOffset, 0, -1); @@ -621,6 +621,7 @@ DrawButtonImageAndText( butPtr->textWidth + butPtr->indicatorSpace, butPtr->textHeight, &x, &y); x += butPtr->indicatorSpace; + y += 1; /* Tweak to match native buttons */ Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, butPtr->textLayout, x, y, 0, -1); } -- cgit v0.12 From 32d6e2eb986ea2386dba70fe7a93cb7330a61da4 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sun, 20 Jan 2019 19:32:37 +0000 Subject: Fix typo triggering error when running unixButton tests on Windows and Linux. --- tests/unixButton.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unixButton.test b/tests/unixButton.test index c7b7b1d..325f497 100644 --- a/tests/unixButton.test +++ b/tests/unixButton.test @@ -41,7 +41,7 @@ if {[tk windowingsystem] eq "aqua"} { set defaultBorder 10 } else { set smallIndicator 27 - set bigindicator 40 + set bigIndicator 40 set defaultBorder 20 } test unixbutton-1.1 {TkpComputeButtonGeometry procedure} -constraints { -- cgit v0.12 From 375b837a661f0c2f82e6fc3c530261fedbf065d2 Mon Sep 17 00:00:00 2001 From: culler Date: Wed, 23 Jan 2019 17:45:28 +0000 Subject: Fix bug [58665b91dd]: unixEmbed tests fail on macOS due to use of dobg. --- macosx/tkMacOSXEmbed.c | 134 ++++------- macosx/tkMacOSXEvent.c | 38 +-- tests/unixEmbed.test | 619 +++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 638 insertions(+), 153 deletions(-) diff --git a/macosx/tkMacOSXEmbed.c b/macosx/tkMacOSXEmbed.c index 589475c..2dbfdc8 100644 --- a/macosx/tkMacOSXEmbed.c +++ b/macosx/tkMacOSXEmbed.c @@ -272,7 +272,14 @@ TkpUseWindow( } usePtr = (TkWindow *) Tk_IdToWindow(winPtr->display, (Window) parent); - if (usePtr != NULL && !(usePtr->flags & TK_CONTAINER)) { + if (usePtr == NULL) { + if (interp != NULL) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "couldn't create child of window \"%s\"", string)); + Tcl_SetErrorCode(interp, "TK", "EMBED", "NO_TARGET", NULL); + } + return TCL_ERROR; + } else if (!(usePtr->flags & TK_CONTAINER)) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "window \"%s\" doesn't have -container option set", usePtr->pathName)); @@ -281,15 +288,9 @@ TkpUseWindow( } /* - * The code below can probably be simplified given we have already - * discovered 'usePtr' above. - */ - - /* - * Save information about the container and the embedded window in a - * Container structure. Currently, there must already be an existing - * Container structure, since we only allow the case where both container - * and embedded app. are in the same process. + * Since we do not allow embedding into windows belonging to a different + * process, we know that a container will exist showing the parent window + * as the parent. This loop finds that container. */ for (containerPtr = firstContainerPtr; containerPtr != NULL; @@ -312,16 +313,6 @@ TkpUseWindow( } macWin->winPtr = winPtr; - winPtr->privatePtr = macWin; - - /* - * The grafPtr will be NULL for a Tk in Tk embedded window. It is none of - * our business what it is for a Tk not in Tk embedded window, but we will - * initialize it to NULL, and let the registerWinProc set it. In any case, - * you must always use TkMacOSXGetDrawablePort to get the portPtr. It will - * correctly find the container's port. - */ - macWin->view = nil; macWin->context = NULL; macWin->size = CGSizeZero; @@ -333,6 +324,7 @@ TkpUseWindow( macWin->toplevel = macWin; macWin->toplevel->referenceCount++; + winPtr->privatePtr = macWin; winPtr->flags |= TK_EMBEDDED; /* @@ -341,64 +333,28 @@ TkpUseWindow( */ macWin->flags |= TK_EMBEDDED; + macWin->xOff = parent->winPtr->privatePtr->xOff + + parent->winPtr->changes.border_width + + winPtr->changes.x; + macWin->yOff = parent->winPtr->privatePtr->yOff + + parent->winPtr->changes.border_width + + winPtr->changes.y; /* - * Now check whether it is embedded in another Tk widget. If not (the - * first case below) we see if there is an in-process embedding handler - * registered, and if so, let that fill in the rest of the macWin. + * Finish filling up the container structure with the embedded + * window's information. */ - if (containerPtr == NULL) { - /* - * If someone has registered an in-process embedding handler, then - * see if it can handle this window... - */ - - if (tkMacOSXEmbedHandler == NULL || - tkMacOSXEmbedHandler->registerWinProc((long) parent, - (Tk_Window) winPtr) != TCL_OK) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "The window ID %s does not correspond to a valid Tk Window", - string)); - Tcl_SetErrorCode(interp, "TK", "EMBED", "HANDLE", NULL); - return TCL_ERROR; - } - - containerPtr = ckalloc(sizeof(Container)); - - containerPtr->parentPtr = NULL; - containerPtr->embedded = (Window) macWin; - containerPtr->embeddedPtr = macWin->winPtr; - containerPtr->nextPtr = firstContainerPtr; - firstContainerPtr = containerPtr; - } else { - /* - * The window is embedded in another Tk window. - */ + containerPtr->embedded = (Window) macWin; + containerPtr->embeddedPtr = macWin->winPtr; - macWin->xOff = parent->winPtr->privatePtr->xOff + - parent->winPtr->changes.border_width + - winPtr->changes.x; - macWin->yOff = parent->winPtr->privatePtr->yOff + - parent->winPtr->changes.border_width + - winPtr->changes.y; - - /* - * Finish filling up the container structure with the embedded - * window's information. - */ - - containerPtr->embedded = (Window) macWin; - containerPtr->embeddedPtr = macWin->winPtr; - - /* - * Create an event handler to clean up the Container structure when - * tkwin is eventually deleted. - */ + /* + * Create an event handler to clean up the Container structure when + * tkwin is eventually deleted. + */ - Tk_CreateEventHandler(tkwin, StructureNotifyMask, EmbeddedEventProc, - winPtr); - } + Tk_CreateEventHandler(tkwin, StructureNotifyMask, EmbeddedEventProc, + winPtr); return TCL_OK; } @@ -614,6 +570,7 @@ TkpTestembedCmd( Container *containerPtr; Tcl_DString dString; char buffer[50]; + Tcl_Interp *embeddedInterp = NULL, *parentInterp = NULL; if ((objc > 1) && (strcmp(Tcl_GetString(objv[1]), "all") == 0)) { all = 1; @@ -623,30 +580,40 @@ TkpTestembedCmd( Tcl_DStringInit(&dString); for (containerPtr = firstContainerPtr; containerPtr != NULL; containerPtr = containerPtr->nextPtr) { + if (containerPtr->embeddedPtr != NULL) { + embeddedInterp = containerPtr->embeddedPtr->mainPtr->interp; + } + if (containerPtr->parentPtr != NULL) { + parentInterp = containerPtr->parentPtr->mainPtr->interp; + } + if (embeddedInterp != interp && parentInterp != interp) { + continue; + } Tcl_DStringStartSublist(&dString); + /* Parent id */ if (containerPtr->parent == None) { Tcl_DStringAppendElement(&dString, ""); } else if (all) { - sprintf(buffer, "0x%x", (int) containerPtr->parent); + sprintf(buffer, "0x%lx", containerPtr->parent); Tcl_DStringAppendElement(&dString, buffer); } else { Tcl_DStringAppendElement(&dString, "XXX"); } - if (containerPtr->parentPtr == NULL) { + /* Parent pathName */ + if (containerPtr->parentPtr == NULL || + parentInterp != interp) { Tcl_DStringAppendElement(&dString, ""); } else { Tcl_DStringAppendElement(&dString, containerPtr->parentPtr->pathName); } - if (containerPtr->embedded == None) { - Tcl_DStringAppendElement(&dString, ""); - } else if (all) { - sprintf(buffer, "0x%x", (int) containerPtr->embedded); - Tcl_DStringAppendElement(&dString, buffer); - } else { - Tcl_DStringAppendElement(&dString, "XXX"); - } - if (containerPtr->embeddedPtr == NULL) { + /* + * On X11 embedded is a wrapper, which does not exist on macOS. + */ + Tcl_DStringAppendElement(&dString, ""); + /* Embedded window pathName */ + if (containerPtr->embeddedPtr == NULL || + embeddedInterp != interp) { Tcl_DStringAppendElement(&dString, ""); } else { Tcl_DStringAppendElement(&dString, @@ -1094,6 +1061,7 @@ static void EmbedSendConfigure( Container *containerPtr) /* Information about the embedding. */ { + printf("Call to EmbedSendConfigure\n"); } /* diff --git a/macosx/tkMacOSXEvent.c b/macosx/tkMacOSXEvent.c index d866b02..b9c9b6a 100644 --- a/macosx/tkMacOSXEvent.c +++ b/macosx/tkMacOSXEvent.c @@ -114,21 +114,16 @@ enum { * * This routine is a stub called by XSync, which is called during the Tk * update command. The language specification does not require that the - * update command be synchronous but many of the tests assume that is the - * case. It is not naturally the case on macOS since many idle tasks are - * run inside of the drawRect method of a window's contentView, and that - * method will not be called until after this function returns. To make - * the tests work, we attempt to force this to be synchronous by waiting - * until drawRect has been called for each window. The mechanism we use - * for this is to have drawRect post an ApplicationDefined NSEvent on the - * AppKit event queue when it finishes drawing, and wait for it here. + * update command be synchronous but many of the tests implicitly assume + * that it is. It is definitely asynchronous on macOS since many idle + * tasks are run inside of the drawRect method of a window's contentView, + * which will not be called until after this function returns. * * Results: * None. * - * Side effects: - * Calls the drawRect method of the contentView of each visible - * window. + * Side effects: Processes all pending idle events then calls the display + * method of each visible window. * *---------------------------------------------------------------------- */ @@ -136,23 +131,12 @@ enum { MODULE_SCOPE void TkMacOSXFlushWindows(void) { - NSArray *macWindows = [NSApp orderedWindows]; - - if ([macWindows count] > 0) { - while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)){} + if (Tk_GetNumMainWindows() == 0) { + return; } - if ([NSApp isDrawing]) { - for (NSWindow *w in macWindows) { - if (TkMacOSXGetXWindow(w)) { - [w setViewsNeedDisplay:YES]; - } - } - } else { - for (NSWindow *w in macWindows) { - if (TkMacOSXGetXWindow(w)) { - [w display]; - } - } + while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)){} + for (NSWindow *w in [NSApp orderedWindows]) { + [w display]; } } diff --git a/tests/unixEmbed.test b/tests/unixEmbed.test index 8aaa3c4..0894365 100644 --- a/tests/unixEmbed.test +++ b/tests/unixEmbed.test @@ -1,4 +1,4 @@ -# This file is a Tcl script to test out the procedures in the file +# This file is a Tcl script to test out the procedures in the file # tkUnixEmbed.c. It is organized in the standard fashion for Tcl # tests. # @@ -55,14 +55,14 @@ proc colorsFree {w {red 31} {green 245} {blue 192}} { } test unixEmbed-1.1 {TkpUseWindow procedure, bad window identifier} -constraints { - unix + unix } -setup { deleteWindows } -body { toplevel .t -use xyz } -returnCodes error -result {expected integer but got "xyz"} test unixEmbed-1.2 {TkpUseWindow procedure, bad window identifier} -constraints { - unix + unix } -setup { deleteWindows } -body { @@ -97,7 +97,7 @@ test unixEmbed-1.4 {TkpUseWindow procedure, inheriting colormap} -constraints { } -result {1} test unixEmbed-1.5 {TkpUseWindow procedure, creating Container records} -constraints { - unix testembed + unix testembed notAqua } -setup { deleteWindows } -body { @@ -113,8 +113,29 @@ test unixEmbed-1.5 {TkpUseWindow procedure, creating Container records} -constra } -cleanup { deleteWindows } -result {{{XXX {} {} .t}} 0} +test unixEmbed-1.5a {TkpUseWindow procedure, creating Container records} -constraints { + unix testembed +} -setup { + deleteWindows + catch {interp delete slave} + interp create slave + load {} Tktest slave +} -body { + frame .f1 -container 1 -width 200 -height 50 + frame .f2 -container 1 -width 200 -height 50 + pack .f1 .f2 + slave alias w winfo id .f1 + slave eval { + destroy [winfo child .] + toplevel .t -use [w] + list [testembed] [expr {[lindex [lindex [testembed all] 0] 0] - [w]}] + } +} -cleanup { + interp delete slave + deleteWindows +} -result {{{XXX {} {} .t}} 0} test unixEmbed-1.6 {TkpUseWindow procedure, creating Container records} -constraints { - unix testembed + unix testembed notAqua } -setup { deleteWindows } -body { @@ -132,6 +153,29 @@ test unixEmbed-1.6 {TkpUseWindow procedure, creating Container records} -constra } -cleanup { deleteWindows } -result {{XXX {} {} .t2} {XXX {} {} .t1}} +test unixEmbed-1.6a {TkpUseWindow procedure, creating Container records} -constraints { + unix testembed +} -setup { + deleteWindows + catch {interp delete slave} + interp create slave + load {} Tktest slave +} -body { + frame .f1 -container 1 -width 200 -height 50 + frame .f2 -container 1 -width 200 -height 50 + pack .f1 .f2 + slave alias w1 winfo id .f1 + slave alias w2 winfo id .f2 + slave eval { + destroy [winfo child .] + toplevel .t1 -use [w1] + toplevel .t2 -use [w2] + testembed + } +} -cleanup { + interp delete slave + deleteWindows +} -result {{XXX {} {} .t2} {XXX {} {} .t1}} test unixEmbed-1.7 {TkpUseWindow procedure, container and embedded in same app} -constraints { unix testembed } -setup { @@ -152,7 +196,7 @@ test unixEmbed-1.7 {TkpUseWindow procedure, container and embedded in same app} test unixEmbed-2.1 {EmbeddedEventProc procedure} -constraints { - unix testembed + unix testembed notAqua } -setup { deleteWindows } -body { @@ -172,8 +216,32 @@ test unixEmbed-2.1 {EmbeddedEventProc procedure} -constraints { } -cleanup { deleteWindows } -result {} +test unixEmbed-2.1a {EmbeddedEventProc procedure} -constraints { + unix testembed +} -setup { + deleteWindows + catch {interp delete slave} + interp create slave + load {} Tktest slave +} -body { + frame .f1 -container 1 -width 200 -height 50 + pack .f1 + slave alias w1 winfo id .f1 + slave eval { + destroy [winfo child .] + toplevel .t1 -use [w1] + testembed + } + destroy .f1 + update + slave eval { + testembed + } +} -cleanup { + deleteWindows +} -result {} test unixEmbed-2.2 {EmbeddedEventProc procedure} -constraints { - unix testembed + unix testembed notAqua } -setup { deleteWindows } -body { @@ -190,8 +258,30 @@ test unixEmbed-2.2 {EmbeddedEventProc procedure} -constraints { } -cleanup { deleteWindows } -result {} +test unixEmbed-2.2a {EmbeddedEventProc procedure} -constraints { + unix testembed +} -setup { + deleteWindows + catch {interp delete slave} + interp create slave + load {} Tktest slave +} -body { + frame .f1 -container 1 -width 200 -height 50 + pack .f1 + slave alias w1 winfo id .f1 + slave eval { + destroy [winfo child .] + toplevel .t1 -use [w1] + testembed + destroy .t1 + testembed + } +} -cleanup { + interp delete slave + deleteWindows +} -result {} test unixEmbed-2.3 {EmbeddedEventProc procedure} -constraints { - unix testembed + unix testembed notAqua } -setup { deleteWindows } -body { @@ -202,26 +292,30 @@ test unixEmbed-2.3 {EmbeddedEventProc procedure} -constraints { destroy .f1 testembed } -result {} +if {[tk windowingsystem] eq "aqua"} { + set wrapperId {{}} +} else { + set wrapperId XXX +} test unixEmbed-2.4 {EmbeddedEventProc procedure} -constraints { unix testembed } -setup { deleteWindows } -body { - frame .f1 -container 1 -width 200 -height 50 - pack .f1 + pack [frame .f1 -container 1 -width 200 -height 50] toplevel .t1 -use [winfo id .f1] + set x [testembed] update destroy .t1 - set x [testembed] update - list $x [testembed] + list $x [winfo exists .t1] [winfo exists .f1] [testembed] } -cleanup { deleteWindows -} -result {{{XXX .f1 {} {}}} {}} +} -result "{{XXX .f1 $wrapperId .t1}} 0 0 {}" test unixEmbed-3.1 {ContainerEventProc procedure, detect creation} -constraints { - unix testembed nonPortable + unix testembed notPortable } -body { frame .f1 -container 1 -width 200 -height 50 pack .f1 @@ -236,21 +330,44 @@ test unixEmbed-3.1 {ContainerEventProc procedure, detect creation} -constraints } -cleanup { deleteWindows } -result {{{XXX .f1 {} {}}} {{XXX .f1 XXX {}}}} +test unixEmbed-3.1a {ContainerEventProc procedure, detect creation} -constraints { + unix testembed +} -setup { + catch {interp delete slave} + interp create slave + load {} Tktest slave +} -body { + frame .f1 -container 1 -width 200 -height 50 + pack .f1 + slave alias w1 winfo id .f1 + set x [testembed] + slave eval { + destroy [winfo child .] + toplevel .t1 -use [w1] + wm withdraw .t1 + } + list $x [testembed] +} -cleanup { + interp delete slave + deleteWindows +} -result {{{XXX .f1 {} {}}} {{XXX .f1 {} {}}}} test unixEmbed-3.2 {ContainerEventProc procedure, set size on creation} -constraints { - unix + unix } -setup { deleteWindows } -body { toplevel .t1 -container 1 wm geometry .t1 +0+0 toplevel .t2 -use [winfo id .t1] -bg red - update + while {[winfo exists .t2] == 0} { + update + } wm geometry .t2 } -cleanup { deleteWindows } -result {200x200+0+0} test unixEmbed-3.3 {ContainerEventProc procedure, disallow position changes} -constraints { - unix + unix notAqua } -setup { deleteWindows } -body { @@ -270,8 +387,31 @@ test unixEmbed-3.3 {ContainerEventProc procedure, disallow position changes} -co } -cleanup { deleteWindows } -result {200x200+0+0} +test unixEmbed-3.3a {ContainerEventProc procedure, disallow position changes} -constraints { + unix +} -setup { + deleteWindows + catch {interp delete slave} + interp create slave + load {} Tktest slave +} -body { + frame .f1 -container 1 -width 200 -height 50 + pack .f1 + slave alias w1 winfo id .f1 + slave eval { + destroy [winfo child .] + toplevel .t1 -use [w1] -bd 2 -relief raised + update + wm geometry .t1 +30+40 + update + wm geometry .t1 + } +} -cleanup { + interp delete slave + deleteWindows +} -result {200x200+0+0} test unixEmbed-3.4 {ContainerEventProc procedure, disallow position changes} -constraints { - unix + unix notAqua } -setup { deleteWindows } -body { @@ -291,8 +431,31 @@ test unixEmbed-3.4 {ContainerEventProc procedure, disallow position changes} -co } -cleanup { deleteWindows } -result {300x100+0+0} +test unixEmbed-3.4a {ContainerEventProc procedure, disallow position changes} -constraints { + unix +} -setup { + deleteWindows + catch {interp delete slave} + interp create slave + load {} Tktest slave +} -body { + frame .f1 -container 1 -width 200 -height 50 + pack .f1 + slave alias w1 winfo id .f1 + slave eval { + destroy [winfo child .] + toplevel .t1 -use [w1] + update + wm geometry .t1 300x100+30+40 + update + wm geometry .t1 + } +} -cleanup { + interp delete slave + deleteWindows +} -result {300x100+0+0} test unixEmbed-3.5 {ContainerEventProc procedure, geometry requests} -constraints { - unix + unix notAqua } -setup { deleteWindows } -body { @@ -312,8 +475,30 @@ test unixEmbed-3.5 {ContainerEventProc procedure, geometry requests} -constraint } -cleanup { deleteWindows } -result {300 80 300x80+0+0} +test unixEmbed-3.5a {ContainerEventProc procedure, geometry requests} -constraints { + unix +} -setup { + deleteWindows + catch {interp delete slave} + interp create slave + load {} Tktest slave +} -body { + frame .f1 -container 1 -width 200 -height 50 + pack .f1 + slave alias w1 winfo id .f1 + slave eval { + destroy [winfo child .] + toplevel .t1 -use [w1] + .t1 configure -width 300 -height 80 + update + } + list [winfo width .f1] [winfo height .f1] [slave eval {wm geometry .t1}] +} -cleanup { + interp delete slave + deleteWindows +} -result {300 80 300x80+0+0} test unixEmbed-3.6 {ContainerEventProc procedure, map requests} -constraints { - unix + unix notAqua } -setup { deleteWindows } -body { @@ -335,8 +520,33 @@ test unixEmbed-3.6 {ContainerEventProc procedure, map requests} -constraints { } -cleanup { deleteWindows } -result {mapped} +test unixEmbed-3.6a {ContainerEventProc procedure, map requests} -constraints { + unix +} -setup { + deleteWindows + catch {interp delete slave} + interp create slave + load {} Tktest slave +} -body { + frame .f1 -container 1 -width 200 -height 50 + pack .f1 + slave alias w1 winfo id .f1 + slave eval { + destroy [winfo child .] + toplevel .t1 -use [w1] + set x unmapped + bind .t1 {set x mapped} + update + after 100 + update + set x + } +} -cleanup { + interp delete slave + deleteWindows +} -result {mapped} test unixEmbed-3.7 {ContainerEventProc procedure, destroy events} -constraints { - unix + unix notAqua } -setup { deleteWindows } -body { @@ -358,10 +568,34 @@ test unixEmbed-3.7 {ContainerEventProc procedure, destroy events} -constraints { } -cleanup { deleteWindows } -result {dead 0} - +test unixEmbed-3.7a {ContainerEventProc procedure, destroy events} -constraints { + unix +} -setup { + deleteWindows + catch {interp delete slave} + interp create slave + load {} Tktest slave +} -body { + frame .f1 -container 1 -width 200 -height 50 + pack .f1 + slave alias w1 winfo id .f1 + bind .f1 {set x dead} + set x alive + slave eval { + destroy [winfo child .] + toplevel .t1 -use [w1] + update + destroy .t1 + } + update + list $x [winfo exists .f1] +} -cleanup { + interp delete slave + deleteWindows +} -result {dead 0} test unixEmbed-4.1 {EmbedStructureProc procedure, configure events} -constraints { - unix + unix notAqua } -setup { deleteWindows } -body { @@ -383,8 +617,31 @@ test unixEmbed-4.1 {EmbedStructureProc procedure, configure events} -constraints } -cleanup { deleteWindows } -result {180x100+0+0} +test unixEmbed-4.1a {EmbedStructureProc procedure, configure events} -constraints { + unix +} -setup { + deleteWindows + catch {interp delete slave} + interp create slave + load {} Tktest slave +} -body { + frame .f1 -container 1 -width 200 -height 50 + pack .f1 + slave alias w1 winfo id .f1 + slave eval { + destroy [winfo child .] + toplevel .t1 -use [w1] + update + .t1 configure -width 180 -height 100 + update + winfo geometry .t1 + } +} -cleanup { + interp delete slave + deleteWindows +} -result {180x100+0+0} test unixEmbed-4.2 {EmbedStructureProc procedure, destroy events} -constraints { - unix testembed + unix testembed notAqua } -setup { deleteWindows } -body { @@ -398,14 +655,38 @@ test unixEmbed-4.2 {EmbedStructureProc procedure, destroy events} -constraints { update set x [testembed] destroy .f1 + update list $x [testembed] } -cleanup { deleteWindows } -result {{{XXX .f1 XXX {}}} {}} +test unixEmbed-4.2a {EmbedStructureProc procedure, destroy events} -constraints { + unix testembed +} -setup { + deleteWindows + catch {interp delete slave} + interp create slave + load {} Tktest slave +} -body { + frame .f1 -container 1 -width 200 -height 50 + pack .f1 + update + slave alias w1 winfo id .f1 + slave eval { + destroy [winfo child .] + toplevel .t1 -use [w1] + } + set x [testembed] + destroy .f1 + list $x [testembed] +} -cleanup { + interp delete slave + deleteWindows +} -result "{{XXX .f1 {} {}}} {}" test unixEmbed-5.1 {EmbedFocusProc procedure, FocusIn events} -constraints { - unix + unix notAqua } -setup { deleteWindows } -body { @@ -425,8 +706,33 @@ test unixEmbed-5.1 {EmbedFocusProc procedure, FocusIn events} -constraints { } -cleanup { deleteWindows } -result {{focus in .t1}} +test unixEmbed-5.1a {EmbedFocusProc procedure, FocusIn events} -constraints { + unix +} -setup { + deleteWindows + catch {interp delete slave} + interp create slave + load {} Tktest slave +} -body { + frame .f1 -container 1 -width 200 -height 50 + pack .f1 + slave alias w1 winfo id .f1 + slave eval { + destroy [winfo child .] + toplevel .t1 -use [w1] + bind .t1 {lappend x "focus in %W"} + bind .t1 {lappend x "focus out %W"} + set x {} + } + focus -force .f1 + update + slave eval {set x} +} -cleanup { + interp delete slave + deleteWindows +} -result {{focus in .t1}} test unixEmbed-5.2 {EmbedFocusProc procedure, focusing on dead window} -constraints { - unix + unix notAqua } -setup { deleteWindows } -body { @@ -447,8 +753,32 @@ test unixEmbed-5.2 {EmbedFocusProc procedure, focusing on dead window} -constrai } -cleanup { deleteWindows } -result {} +test unixEmbed-5.2a {EmbedFocusProc procedure, focusing on dead window} -constraints { + unix +} -setup { + deleteWindows + catch {interp delete slave} + interp create slave + load {} Tktest slave +} -body { + frame .f1 -container 1 -width 200 -height 50 + pack .f1 + slave alias w1 winfo id .f1 + slave eval { + destroy [winfo child .] + toplevel .t1 -use [w1] + update + after 200 {destroy .t1} + } + after 400 + focus -force .f1 + update +} -cleanup { + interp delete slave + deleteWindows +} -result {} test unixEmbed-5.3 {EmbedFocusProc procedure, FocusOut events} -constraints { - unix + unix notAqua } -setup { deleteWindows } -body { @@ -471,10 +801,39 @@ test unixEmbed-5.3 {EmbedFocusProc procedure, FocusOut events} -constraints { } -cleanup { deleteWindows } -result {{{focus in .t1}} {{focus in .t1} {focus out .t1}}} +test unixEmbed-5.3a {EmbedFocusProc procedure, FocusOut events} -constraints { + unix +} -setup { + deleteWindows + catch {interp delete slave} + interp create slave + load {} Tktest slave +} -body { + frame .f1 -container 1 -width 200 -height 50 + pack .f1 + slave alias w1 winfo id .f1 + slave eval { + destroy [winfo child .] + toplevel .t1 -use [w1] + set x {} + bind .t1 {lappend x "focus in %W"} + bind .t1 {lappend x "focus out %W"} + update + } + focus -force .f1 + update + set x [slave eval {update; set x }] + focus . + update + list $x [slave eval {update; set x}] +} -cleanup { + interp delete slave + deleteWindows +} -result {{{focus in .t1}} {{focus in .t1} {focus out .t1}}} test unixEmbed-6.1 {EmbedGeometryRequest procedure, window changes size} -constraints { - unix + unix notAqua } -setup { deleteWindows } -body { @@ -496,8 +855,33 @@ test unixEmbed-6.1 {EmbedGeometryRequest procedure, window changes size} -constr } -cleanup { deleteWindows } -result {{{configure .t1 300 120}} 300x120+0+0} +test unixEmbed-6.1a {EmbedGeometryRequest procedure, window changes size} -constraints { + unix +} -setup { + deleteWindows + catch {interp delete slave} + interp create slave + load {} Tktest slave +} -body { + frame .f1 -container 1 -width 200 -height 50 + pack .f1 + slave alias w1 winfo id .f1 + slave eval { + destroy [winfo child .] + toplevel .t1 -use [w1] + update + bind .t1 {lappend x {configure .t1 %w %h}} + set x {} + .t1 configure -width 300 -height 120 + update + list $x [winfo geom .t1] + } +} -cleanup { + interp delete slave + deleteWindows +} -result {{{configure .t1 300 120}} 300x120+0+0} test unixEmbed-6.2 {EmbedGeometryRequest procedure, window changes size} -constraints { - unix + unix notAqua } -setup { deleteWindows } -body { @@ -514,18 +898,47 @@ test unixEmbed-6.2 {EmbedGeometryRequest procedure, window changes size} -constr bind .t1 {lappend x {configure .t1 %w %h}} set x {} .t1 configure -width 300 -height 120 - update + after 300 {set y done} + vwait y list $x [winfo geom .t1] } } -cleanup { deleteWindows } -result {{{configure .t1 200 200}} 200x200+0+0} +test unixEmbed-6.2a {EmbedGeometryRequest procedure, window changes size} -constraints { + unix +} -setup { + deleteWindows + catch {interp delete slave} + interp create slave + load {} Tktest slave +} -body { + frame .f1 -container 1 -width 200 -height 50 + place .f1 -width 200 -height 200 + slave alias w1 winfo id .f1 + slave eval { + destroy [winfo child .] + toplevel .t1 -use [w1] + } + after 300 {set x done} + vwait x + slave eval { + bind .t1 {lappend x {configure .t1 %w %h}} + update + set x {} + .t1 configure -width 300 -height 120 + update + list $x [winfo geom .t1] + } +} -cleanup { + interp delete slave + deleteWindows +} -result {{{configure .t1 200 200}} 200x200+0+0} # Can't think up any tests for TkpGetOtherWindow procedure. - test unixEmbed-7.1 {TkpRedirectKeyEvent procedure, forward keystroke} -constraints { - unix + unix notAqua } -setup { deleteWindows } -body { @@ -553,8 +966,41 @@ test unixEmbed-7.1 {TkpRedirectKeyEvent procedure, forward keystroke} -constrain deleteWindows bind . {} } -result {{{key a 1}} {}} +test unixEmbed-7.1a {TkpRedirectKeyEvent procedure, forward keystroke} -constraints { + unix +} -setup { + deleteWindows + catch {interp delete slave} + interp create slave + load {} Tktest slave +} -body { + deleteWindows + frame .f1 -container 1 -width 200 -height 50 + pack .f1 + slave alias w1 winfo id .f1 + slave eval { + destroy [winfo child .] + toplevel .t1 -use [w1] + } + focus -force . + bind . {lappend x {key %A %E}} + set x {} + set y [slave eval { + update + bind .t1 {lappend y {key %A}} + set y {} + event generate .t1 -keysym a + set y + }] + update + list $x $y +} -cleanup { + interp delete slave + deleteWindows + bind . {} +} -result {{{key a 1}} {}} test unixEmbed-7.2 {TkpRedirectKeyEvent procedure, don't forward keystroke width} -constraints { - unix + unix notAqua } -setup { deleteWindows } -body { @@ -583,9 +1029,44 @@ test unixEmbed-7.2 {TkpRedirectKeyEvent procedure, don't forward keystroke width deleteWindows bind . {} } -result {{} {{key b}}} +test unixEmbed-7.2a {TkpRedirectKeyEvent procedure, don't forward keystroke width} -constraints { + unix +} -setup { + deleteWindows + catch {interp delete slave} + interp create slave + load {} Tktest slave +} -body { + frame .f1 -container 1 -width 200 -height 50 + pack .f1 + slave alias w1 winfo id .f1 + slave eval { + destroy [winfo child .] + toplevel .t1 -use [w1] + } + update + focus -force .f1 + update + bind . {lappend x {key %A}} + set x {} + set y [slave eval { + update + bind .t1 {lappend y {key %A}} + set y {} + event generate .t1 -keysym b + set y + }] + update + list $x $y +} -cleanup { + interp delete slave + deleteWindows + bind . {} +} -result {{} {{key b}}} - -test unixEmbed-8.1 {TkpClaimFocus procedure} -constraints unix -setup { +test unixEmbed-8.1 {TkpClaimFocus procedure} -constraints { + unix notAqua +} -setup { deleteWindows } -body { frame .f1 -container 1 -width 200 -height 50 @@ -609,15 +1090,44 @@ test unixEmbed-8.1 {TkpClaimFocus procedure} -constraints unix -setup { } -cleanup { deleteWindows } -result {{{} .t1} .f1} -test unixEmbed-8.2 {TkpClaimFocus procedure} -constraints unix -setup { - deleteWindows - catch {interp delete child} +test unixEmbed-8.1a {TkpClaimFocus procedure} -constraints unix -setup { deleteWindows + catch {interp delete slave} + interp create slave + load {} Tktest slave } -body { frame .f1 -container 1 -width 200 -height 50 frame .f2 -width 200 -height 50 pack .f1 .f2 + slave alias w1 winfo id .f1 + slave eval { + destroy [winfo child .] + toplevel .t1 -use [w1] -highlightthickness 2 -bd 2 -relief sunken + } + focus -force .f2 + update + list [slave eval { + focus .t1 + set x [list [focus]] + update + after 500 + update + lappend x [focus] + }] [focus] +} -cleanup { + interp delete slave + deleteWindows +} -result {{{} .t1} .f1} +test unixEmbed-8.2 {TkpClaimFocus procedure} -constraints unix -setup { + deleteWindows + catch {interp delete child} interp create child +} -body { + frame .f1 -container 1 -width 200 -height 50 + frame .f2 -width 200 -height 50 + pack .f1 .f2 + update + set w1 [winfo id .f1] child eval "set argv {-use [winfo id .f1]}" load {} Tk child child eval { @@ -636,7 +1146,6 @@ test unixEmbed-8.2 {TkpClaimFocus procedure} -constraints unix -setup { } -result {{{} .} .f1} catch {interp delete child} - test unixEmbed-9.1 {EmbedWindowDeleted procedure, check parentPtr} -constraints { unix testembed } -setup { @@ -658,12 +1167,13 @@ test unixEmbed-9.1 {EmbedWindowDeleted procedure, check parentPtr} -constraints deleteWindows } -result {{{XXX .f4 {} {}} {XXX .f3 {} {}} {XXX .f2 {} {}} {XXX .f1 {} {}}} {{XXX .f4 {} {}} {XXX .f2 {} {}} {XXX .f1 {} {}}} {{XXX .f2 {} {}} {XXX .f1 {} {}}} {{XXX .f2 {} {}}} {}} test unixEmbed-9.2 {EmbedWindowDeleted procedure, check embeddedPtr} -constraints { - unix testembed + unix testembed notAqua } -setup { deleteWindows } -body { frame .f1 -container 1 -width 200 -height 50 pack .f1 + update dobg "set w1 [winfo id .f1]" dobg { eval destroy [winfo child .] @@ -676,15 +1186,39 @@ test unixEmbed-9.2 {EmbedWindowDeleted procedure, check embeddedPtr} -constraint } -cleanup { deleteWindows } -result {{{XXX {} {} .t1}} {}} +test unixEmbed-9.2a {EmbedWindowDeleted procedure, check embeddedPtr} -constraints { + unix testembed +} -setup { + deleteWindows + catch {interp delete slave} + interp create slave + load {} Tktest slave +} -body { + frame .f1 -container 1 -width 200 -height 50 + pack .f1 + slave alias w1 winfo id .f1 + slave eval { + destroy [winfo child .] + toplevel .t1 -use [w1] -highlightthickness 2 -bd 2 -relief sunken + set x {} + lappend x [testembed] + destroy .t1 + lappend x [testembed] + } +} -cleanup { + interp delete slave + deleteWindows +} -result {{{XXX {} {} .t1}} {}} test unixEmbed-10.1 {geometry propagation in tkUnixWm.c/UpdateGeometryInfo} -constraints { - unix + unix } -setup { deleteWindows } -body { frame .f1 -container 1 -width 200 -height 50 pack .f1 + update toplevel .t1 -use [winfo id .f1] -width 150 -height 80 update wm geometry .t1 +40+50 @@ -694,7 +1228,7 @@ test unixEmbed-10.1 {geometry propagation in tkUnixWm.c/UpdateGeometryInfo} -con deleteWindows } -result {150x80+0+0} test unixEmbed-10.2 {geometry propagation in tkUnixWm.c/UpdateGeometryInfo} -constraints { - unix + unix } -setup { deleteWindows } -body { @@ -714,4 +1248,3 @@ deleteWindows cleanupbg cleanupTests return - -- cgit v0.12 From f917c7ea30852f927140c2e2041d624de5518a11 Mon Sep 17 00:00:00 2001 From: culler Date: Wed, 23 Jan 2019 17:55:49 +0000 Subject: Remove debug print statement. --- macosx/tkMacOSXEmbed.c | 1 - 1 file changed, 1 deletion(-) diff --git a/macosx/tkMacOSXEmbed.c b/macosx/tkMacOSXEmbed.c index 2dbfdc8..8fcbb09 100644 --- a/macosx/tkMacOSXEmbed.c +++ b/macosx/tkMacOSXEmbed.c @@ -1061,7 +1061,6 @@ static void EmbedSendConfigure( Container *containerPtr) /* Information about the embedding. */ { - printf("Call to EmbedSendConfigure\n"); } /* -- cgit v0.12 From 3be37d2e475c04c88fe192c47cc5fcef06024aab Mon Sep 17 00:00:00 2001 From: culler Date: Wed, 23 Jan 2019 20:40:57 +0000 Subject: Constrain send.test tests which are inappropriate for macOS with notAqua. --- macosx/tkMacOSXSend.c | 2 +- tests/send.test | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/macosx/tkMacOSXSend.c b/macosx/tkMacOSXSend.c index 3b24a56..1fdf048 100644 --- a/macosx/tkMacOSXSend.c +++ b/macosx/tkMacOSXSend.c @@ -325,7 +325,7 @@ Tk_SendObjCmd( int objc, /* Number of arguments */ Tcl_Obj *const objv[]) /* The arguments */ { - const char *const sendOptions[] = {"-async", "-displayof", "-", NULL}; + const char *const sendOptions[] = {"-async", "-displayof", "--", NULL}; char *stringRep, *destName; /*int async = 0;*/ int i, index, firstArg; diff --git a/tests/send.test b/tests/send.test index 945d4d0..403a207 100644 --- a/tests/send.test +++ b/tests/send.test @@ -197,7 +197,8 @@ test send-7.4 {Tk_SetAppName procedure, name in use} {secureserver testsend} { list [tk appname foo] [testsend prop root InterpRegistry] } "{foo #4} {$commId foo #4\n$id foo\n$id foo #2\n$id foo #3\n}" -test send-8.1 {Tk_SendCmd procedure, options} {secureserver} { +#macOS does not send to other processes +test send-8.1 {Tk_SendCmd procedure, options} {secureserver notAqua} { setupbg set app [dobg {tk appname}] set a 66 @@ -222,10 +223,11 @@ test send-8.2 {Tk_SendCmd procedure, options} {secureserver altDisplay} { cleanupbg set result } {altDisplay homeDisplay} -test send-8.3 {Tk_SendCmd procedure, options} {secureserver} { +# Since macOS has no registry of interpreters, 8.3, 8.4 and 8.10 will fail. +test send-8.3 {Tk_SendCmd procedure, options} {secureserver notAqua} { list [catch {send -- -async foo bar baz} msg] $msg } {1 {no application named "-async"}} -test send-8.4 {Tk_SendCmd procedure, options} {secureserver} { +test send-8.4 {Tk_SendCmd procedure, options} {secureserver notAqua} { list [catch {send -gorp foo bar baz} msg] $msg } {1 {no application named "-gorp"}} test send-8.5 {Tk_SendCmd procedure, options} {secureserver} { @@ -253,7 +255,7 @@ test send-8.9 {Tk_SendCmd procedure, local execution} {secureserver} { "open bad_file" invoked from within "send [tk appname] open bad_file"} {posix enoent {no such file or directory}}} -test send-8.10 {Tk_SendCmd procedure, no such interpreter} {secureserver} { +test send-8.10 {Tk_SendCmd procedure, no such interpreter} {secureserver notAqua} { list [catch {send bogus_name bogus_command} msg] $msg } {1 {no application named "bogus_name"}} @@ -542,7 +544,8 @@ test send-12.1 {TimeoutProc procedure} {secureserver testsend} { catch {testsend prop root InterpRegistry ""} -test send-12.2 {TimeoutProc procedure} {secureserver} { +#macOS does not send to other processes +test send-12.2 {TimeoutProc procedure} {secureserver notAqua} { winfo interps tk appname tktest update @@ -557,16 +560,17 @@ test send-12.2 {TimeoutProc procedure} {secureserver} { set result } {1 {target application died}} +#macOS does not send to other processes winfo interps tk appname tktest -test send-13.1 {DeleteProc procedure} {secureserver} { +test send-13.1 {DeleteProc procedure} {secureserver notAqua} { setupbg set app [dobg {rename send {}; tk appname}] set result [list [catch {send $app foo} msg] $msg [winfo interps]] cleanupbg set result } {1 {no application named "tktest #2"} tktest} -test send-13.2 {DeleteProc procedure} {secureserver} { +test send-13.2 {DeleteProc procedure} {secureserver notAqua} { winfo interps tk appname tktest rename send {} -- cgit v0.12 From bcbac6d72fa593de9f7ba235102d9eedfdfe526b Mon Sep 17 00:00:00 2001 From: culler Date: Sat, 26 Jan 2019 16:17:49 +0000 Subject: Attempt to make the new unixEmbed tests work when tests are run from the build directory, without installing Tk. --- tests/unixEmbed.test | 73 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/tests/unixEmbed.test b/tests/unixEmbed.test index 0894365..dabf0a0 100644 --- a/tests/unixEmbed.test +++ b/tests/unixEmbed.test @@ -11,6 +11,37 @@ eval tcltest::configure $argv tcltest::loadTestedCommands namespace import -force tcltest::test +namespace eval ::_test_tmp {} + +# ------------------------------------------------------------------------------ +# Proc ::_test_tmp::testInterp +# ------------------------------------------------------------------------------ +# Command that creates an unsafe child interpreter and tries to load Tk. +# This code is borrowed from safePrimarySelection.test +# This is necessary for loading Tktest if the tests are done in the build +# directory without installing Tk. In that case the usual auto_path loading +# mechanism cannot work because the tk binary is not where pkgIndex.tcl says +# it is. +# ------------------------------------------------------------------------------ + +namespace eval ::_test_tmp { + variable TkLoadCmd +} + +foreach pkg [info loaded] { + if {[lindex $pkg 1] eq "Tktest"} { + set ::_test_tmp::TkLoadCmd [list load {*}$pkg] + break + } +} + +proc ::_test_tmp::testInterp {name} { + variable TkLoadCmd + interp create $name + $name eval [list set argv [list -name $name]] + catch {{*}$TkLoadCmd $name} +} + setupbg dobg {wm withdraw .} @@ -118,7 +149,7 @@ test unixEmbed-1.5a {TkpUseWindow procedure, creating Container records} -constr } -setup { deleteWindows catch {interp delete slave} - interp create slave + ::_test_tmp::testInterp slave load {} Tktest slave } -body { frame .f1 -container 1 -width 200 -height 50 @@ -158,7 +189,7 @@ test unixEmbed-1.6a {TkpUseWindow procedure, creating Container records} -constr } -setup { deleteWindows catch {interp delete slave} - interp create slave + ::_test_tmp::testInterp slave load {} Tktest slave } -body { frame .f1 -container 1 -width 200 -height 50 @@ -221,7 +252,7 @@ test unixEmbed-2.1a {EmbeddedEventProc procedure} -constraints { } -setup { deleteWindows catch {interp delete slave} - interp create slave + ::_test_tmp::testInterp slave load {} Tktest slave } -body { frame .f1 -container 1 -width 200 -height 50 @@ -263,7 +294,7 @@ test unixEmbed-2.2a {EmbeddedEventProc procedure} -constraints { } -setup { deleteWindows catch {interp delete slave} - interp create slave + ::_test_tmp::testInterp slave load {} Tktest slave } -body { frame .f1 -container 1 -width 200 -height 50 @@ -334,7 +365,7 @@ test unixEmbed-3.1a {ContainerEventProc procedure, detect creation} -constraints unix testembed } -setup { catch {interp delete slave} - interp create slave + ::_test_tmp::testInterp slave load {} Tktest slave } -body { frame .f1 -container 1 -width 200 -height 50 @@ -392,7 +423,7 @@ test unixEmbed-3.3a {ContainerEventProc procedure, disallow position changes} -c } -setup { deleteWindows catch {interp delete slave} - interp create slave + ::_test_tmp::testInterp slave load {} Tktest slave } -body { frame .f1 -container 1 -width 200 -height 50 @@ -436,7 +467,7 @@ test unixEmbed-3.4a {ContainerEventProc procedure, disallow position changes} -c } -setup { deleteWindows catch {interp delete slave} - interp create slave + ::_test_tmp::testInterp slave load {} Tktest slave } -body { frame .f1 -container 1 -width 200 -height 50 @@ -480,7 +511,7 @@ test unixEmbed-3.5a {ContainerEventProc procedure, geometry requests} -constrain } -setup { deleteWindows catch {interp delete slave} - interp create slave + ::_test_tmp::testInterp slave load {} Tktest slave } -body { frame .f1 -container 1 -width 200 -height 50 @@ -525,7 +556,7 @@ test unixEmbed-3.6a {ContainerEventProc procedure, map requests} -constraints { } -setup { deleteWindows catch {interp delete slave} - interp create slave + ::_test_tmp::testInterp slave load {} Tktest slave } -body { frame .f1 -container 1 -width 200 -height 50 @@ -573,7 +604,7 @@ test unixEmbed-3.7a {ContainerEventProc procedure, destroy events} -constraints } -setup { deleteWindows catch {interp delete slave} - interp create slave + ::_test_tmp::testInterp slave load {} Tktest slave } -body { frame .f1 -container 1 -width 200 -height 50 @@ -622,7 +653,7 @@ test unixEmbed-4.1a {EmbedStructureProc procedure, configure events} -constraint } -setup { deleteWindows catch {interp delete slave} - interp create slave + ::_test_tmp::testInterp slave load {} Tktest slave } -body { frame .f1 -container 1 -width 200 -height 50 @@ -665,7 +696,7 @@ test unixEmbed-4.2a {EmbedStructureProc procedure, destroy events} -constraints } -setup { deleteWindows catch {interp delete slave} - interp create slave + ::_test_tmp::testInterp slave load {} Tktest slave } -body { frame .f1 -container 1 -width 200 -height 50 @@ -711,7 +742,7 @@ test unixEmbed-5.1a {EmbedFocusProc procedure, FocusIn events} -constraints { } -setup { deleteWindows catch {interp delete slave} - interp create slave + ::_test_tmp::testInterp slave load {} Tktest slave } -body { frame .f1 -container 1 -width 200 -height 50 @@ -758,7 +789,7 @@ test unixEmbed-5.2a {EmbedFocusProc procedure, focusing on dead window} -constra } -setup { deleteWindows catch {interp delete slave} - interp create slave + ::_test_tmp::testInterp slave load {} Tktest slave } -body { frame .f1 -container 1 -width 200 -height 50 @@ -806,7 +837,7 @@ test unixEmbed-5.3a {EmbedFocusProc procedure, FocusOut events} -constraints { } -setup { deleteWindows catch {interp delete slave} - interp create slave + ::_test_tmp::testInterp slave load {} Tktest slave } -body { frame .f1 -container 1 -width 200 -height 50 @@ -860,7 +891,7 @@ test unixEmbed-6.1a {EmbedGeometryRequest procedure, window changes size} -const } -setup { deleteWindows catch {interp delete slave} - interp create slave + ::_test_tmp::testInterp slave load {} Tktest slave } -body { frame .f1 -container 1 -width 200 -height 50 @@ -910,7 +941,7 @@ test unixEmbed-6.2a {EmbedGeometryRequest procedure, window changes size} -const } -setup { deleteWindows catch {interp delete slave} - interp create slave + ::_test_tmp::testInterp slave load {} Tktest slave } -body { frame .f1 -container 1 -width 200 -height 50 @@ -971,7 +1002,7 @@ test unixEmbed-7.1a {TkpRedirectKeyEvent procedure, forward keystroke} -constrai } -setup { deleteWindows catch {interp delete slave} - interp create slave + ::_test_tmp::testInterp slave load {} Tktest slave } -body { deleteWindows @@ -1034,7 +1065,7 @@ test unixEmbed-7.2a {TkpRedirectKeyEvent procedure, don't forward keystroke widt } -setup { deleteWindows catch {interp delete slave} - interp create slave + ::_test_tmp::testInterp slave load {} Tktest slave } -body { frame .f1 -container 1 -width 200 -height 50 @@ -1093,7 +1124,7 @@ test unixEmbed-8.1 {TkpClaimFocus procedure} -constraints { test unixEmbed-8.1a {TkpClaimFocus procedure} -constraints unix -setup { deleteWindows catch {interp delete slave} - interp create slave + ::_test_tmp::testInterp slave load {} Tktest slave } -body { frame .f1 -container 1 -width 200 -height 50 @@ -1191,7 +1222,7 @@ test unixEmbed-9.2a {EmbedWindowDeleted procedure, check embeddedPtr} -constrain } -setup { deleteWindows catch {interp delete slave} - interp create slave + ::_test_tmp::testInterp slave load {} Tktest slave } -body { frame .f1 -container 1 -width 200 -height 50 -- cgit v0.12 From f5aac2cbc6abf0f40ed14db7acc4a5bcfd96bce8 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sat, 26 Jan 2019 16:58:17 +0000 Subject: Load the Tk package, not Tktest --- tests/unixEmbed.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unixEmbed.test b/tests/unixEmbed.test index dabf0a0..4058058 100644 --- a/tests/unixEmbed.test +++ b/tests/unixEmbed.test @@ -29,7 +29,7 @@ namespace eval ::_test_tmp { } foreach pkg [info loaded] { - if {[lindex $pkg 1] eq "Tktest"} { + if {[lindex $pkg 1] eq "Tk"} { set ::_test_tmp::TkLoadCmd [list load {*}$pkg] break } -- cgit v0.12 From 02aabb7cd260aa61803ba37759a38f1213adda53 Mon Sep 17 00:00:00 2001 From: culler Date: Sun, 27 Jan 2019 00:25:43 +0000 Subject: Fix bug [688cd9c9de]: many wm-transient tests fail on macOS --- macosx/tkMacOSXWm.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++++--- macosx/tkMacOSXWm.h | 14 ++++++ 2 files changed, 148 insertions(+), 7 deletions(-) diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index a5e1564..0418632 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -681,6 +681,7 @@ TkWmNewWindow( wmPtr->masterWindowName = NULL; wmPtr->icon = NULL; wmPtr->iconFor = NULL; + wmPtr->transientPtr = NULL; wmPtr->sizeHintsFlags = 0; wmPtr->minWidth = wmPtr->minHeight = 1; wmPtr->maxWidth = 0; @@ -882,6 +883,7 @@ TkWmDeadWindow( TkWindow *winPtr) /* Top-level window that's being deleted. */ { WmInfo *wmPtr = winPtr->wmInfoPtr, *wmPtr2; + TkDisplay *dispPtr = TkGetDisplayList(); if (wmPtr == NULL) { return; @@ -915,7 +917,6 @@ TkWmDeadWindow( } while (wmPtr->protPtr != NULL) { ProtocolHandler *protPtr = wmPtr->protPtr; - wmPtr->protPtr = protPtr->nextPtr; Tcl_EventuallyFree(protPtr, TCL_DYNAMIC); } @@ -930,6 +931,30 @@ TkWmDeadWindow( } /* + * If the dead window has a transient, remove references to it from + * the transient. + */ + + for (Transient *transientPtr = wmPtr->transientPtr; + transientPtr != NULL; transientPtr = transientPtr->nextPtr) { + TkWindow *winPtr2 = transientPtr->winPtr; + Window master = TkGetTransientMaster(winPtr2); + TkWindow *masterPtr = (TkWindow *)Tk_IdToWindow(dispPtr->display, master); + if (masterPtr == winPtr) { + wmPtr2 = winPtr2->wmInfoPtr; + wmPtr2->master = None; + ckfree(wmPtr2->masterWindowName); + wmPtr2->masterWindowName = NULL; + } + } + + while (wmPtr->transientPtr != NULL) { + Transient *transientPtr = wmPtr->transientPtr; + wmPtr->transientPtr = transientPtr->nextPtr; + ckfree(transientPtr); + } + + /* * Delete the Mac window and remove it from the windowTable. The window * could be nil if the window was never mapped. However, we don't do this * for embedded windows, they don't go in the window list, and they do not @@ -1758,6 +1783,7 @@ WmDeiconifyCmd( { register WmInfo *wmPtr = winPtr->wmInfoPtr; NSWindow *win = TkMacOSXDrawableWindow(winPtr->window); + TkDisplay *dispPtr = TkGetDisplayList(); if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "window"); @@ -1786,6 +1812,27 @@ WmDeiconifyCmd( if (wmPtr->icon) { Tk_UnmapWindow((Tk_Window)wmPtr->icon); } + + /* + * If this window has a transient, the transient must also be deiconified if + * it was withdrawn by the master. + */ + + for (Transient *transientPtr = wmPtr->transientPtr; + transientPtr != NULL; transientPtr = transientPtr->nextPtr) { + TkWindow *winPtr2 = transientPtr->winPtr; + WmInfo *wmPtr2 = winPtr2->wmInfoPtr; + Window master = TkGetTransientMaster(winPtr2); + TkWindow *masterPtr = (TkWindow *)Tk_IdToWindow(dispPtr->display, master); + if (masterPtr == winPtr) { + if (!(wmPtr2->hints.initial_state == WithdrawnState && + (transientPtr->flags & WITHDRAWN_BY_MASTER) == 0)) { + TkpWmSetState(winPtr2, NormalState); + transientPtr->flags &= ~WITHDRAWN_BY_MASTER; + } + } + } + return TCL_OK; } @@ -2272,6 +2319,7 @@ WmIconifyCmd( int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { + TkDisplay *dispPtr = TkGetDisplayList(); register WmInfo *wmPtr = winPtr->wmInfoPtr; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "window"); @@ -2308,6 +2356,24 @@ WmIconifyCmd( if (wmPtr->icon) { Tk_MapWindow((Tk_Window)wmPtr->icon); } + + /* + * If this window has a transient the transient must be withdrawn when + * the master is iconified. + */ + + for (Transient *transientPtr = wmPtr->transientPtr; + transientPtr != NULL; transientPtr = transientPtr->nextPtr) { + TkWindow *winPtr2 = transientPtr->winPtr; + Window master = TkGetTransientMaster(winPtr2); + TkWindow *masterPtr = (TkWindow *)Tk_IdToWindow(dispPtr->display, master); + if (masterPtr == winPtr && + winPtr2->wmInfoPtr->hints.initial_state != WithdrawnState) { + TkpWmSetState(winPtr2, WithdrawnState); + transientPtr->flags |= WITHDRAWN_BY_MASTER; + } + } + return TCL_OK; } @@ -3508,6 +3574,7 @@ WmTransientCmd( register WmInfo *wmPtr = winPtr->wmInfoPtr; Tk_Window master; WmInfo *wmPtr2; + TkDisplay *dispPtr = TkGetDisplayList(); char *masterWindowName; int length; @@ -3523,16 +3590,39 @@ WmTransientCmd( return TCL_OK; } if (Tcl_GetString(objv[3])[0] == '\0') { - wmPtr->master = None; - if (wmPtr->masterWindowName != NULL) { - ckfree(wmPtr->masterWindowName); + + /* + * Remove the transient from its master's list. + */ + + if (wmPtr->master != None) { + TkWindow *masterPtr = (TkWindow*)Tk_IdToWindow(dispPtr->display, + wmPtr->master); + wmPtr2 = masterPtr->wmInfoPtr; + Transient *transientPtr = wmPtr2->transientPtr; + if (transientPtr->winPtr == winPtr) { + wmPtr2->transientPtr = transientPtr->nextPtr; + } else while (transientPtr->nextPtr != NULL) { + if (transientPtr->nextPtr->winPtr == winPtr) { + transientPtr->nextPtr = transientPtr->nextPtr->nextPtr; + break; + } + transientPtr = transientPtr->nextPtr; + } + if (transientPtr!= NULL) { + ckfree(transientPtr); + } + wmPtr->master = None; + if (wmPtr->masterWindowName != NULL) { + ckfree(wmPtr->masterWindowName); + } + wmPtr->masterWindowName = NULL; } - wmPtr->masterWindowName = NULL; } else { if (TkGetWindowFromObj(interp, tkwin, objv[3], &master) != TCL_OK) { return TCL_ERROR; } - TkWindow* masterPtr = (TkWindow*) master; + TkWindow *masterPtr = (TkWindow*) master; while (!Tk_TopWinHierarchy(masterPtr)) { /* @@ -3568,6 +3658,26 @@ WmTransientCmd( return TCL_ERROR; } + /* + * Add the transient to the master's list. + */ + + Transient *transient = ckalloc(sizeof(Transient)); + transient->winPtr = winPtr; + transient->flags = 0; + transient->nextPtr = wmPtr->transientPtr; + wmPtr2->transientPtr = transient; + + /* + * If the master is withdrawn or iconic then withdraw the transient. + */ + if ((wmPtr2->hints.initial_state == WithdrawnState || + wmPtr2->hints.initial_state == IconicState) && + wmPtr->hints.initial_state != WithdrawnState){ + TkpWmSetState(winPtr, WithdrawnState); + transient->flags |= WITHDRAWN_BY_MASTER; + } + wmPtr->master = Tk_WindowId(masterPtr); masterWindowName = masterPtr->pathName; length = strlen(masterWindowName); @@ -3620,11 +3730,29 @@ WmWithdrawCmd( Tcl_SetErrorCode(interp, "TK", "WM", "WITHDRAW", "ICON", NULL); return TCL_ERROR; } + TkpWmSetState(winPtr, WithdrawnState); + NSWindow *win = TkMacOSXDrawableWindow(winPtr->window); + TkDisplay *dispPtr = TkGetDisplayList(); [win orderOut:nil]; [win setExcludedFromWindowsMenu:YES]; + /* + * If this window has a transient, the transient must also be withdrawn. + */ + for (Transient *transientPtr = wmPtr->transientPtr; + transientPtr != NULL; transientPtr = transientPtr->nextPtr) { + TkWindow *winPtr2 = transientPtr->winPtr; + Window master = TkGetTransientMaster(winPtr2); + TkWindow *masterPtr = (TkWindow *)Tk_IdToWindow(dispPtr->display, master); + if (masterPtr == winPtr && + winPtr2->wmInfoPtr->hints.initial_state != WithdrawnState) { + TkpWmSetState(winPtr2, WithdrawnState); + transientPtr->flags |= WITHDRAWN_BY_MASTER; + } + } + return TCL_OK; } @@ -4734,7 +4862,6 @@ Tk_MoveToplevelWindow( wmPtr->x = x; wmPtr->y = y; wmPtr->flags |= WM_MOVE_PENDING; - // wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y); if (!(wmPtr->sizeHintsFlags & (USPosition|PPosition))) { wmPtr->sizeHintsFlags |= USPosition; wmPtr->flags |= WM_UPDATE_SIZE_HINTS; diff --git a/macosx/tkMacOSXWm.h b/macosx/tkMacOSXWm.h index 43f1a7a..a7ea92c 100644 --- a/macosx/tkMacOSXWm.h +++ b/macosx/tkMacOSXWm.h @@ -36,6 +36,17 @@ typedef struct ProtocolHandler { * THE LAST FIELD OF THE STRUCTURE. */ } ProtocolHandler; +/* The following data structure is used in the TkWmInfo to maintain a list of all of the + * transient windows belonging to a given master. + */ + +typedef struct Transient { + TkWindow *winPtr; + int flags; + struct Transient *nextPtr; +} Transient; + +#define WITHDRAWN_BY_MASTER 0x1 /* * A data structure of the following type holds window-manager-related @@ -70,6 +81,9 @@ typedef struct TkWmInfo { * NULL. */ Tk_Window iconFor; /* Window for which this window is icon, or * NULL if this isn't an icon for anyone. */ + Transient *transientPtr; /* First item in a list of all transient windows + * belonging to this window, or NULL if there + * are no transients. */ /* * Information used to construct an XSizeHints structure for the window -- cgit v0.12 From 9aa9f3289047d44aeb99520da7b94bb2cdd5d118 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sun, 27 Jan 2019 09:11:52 +0000 Subject: Make unixEmbed-3.2 pass (revert previous change that introduced a loop on [winfo exists .t2] since this prevents the necessary update to be executed) --- tests/unixEmbed.test | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/unixEmbed.test b/tests/unixEmbed.test index 4058058..0ab275d 100644 --- a/tests/unixEmbed.test +++ b/tests/unixEmbed.test @@ -390,9 +390,7 @@ test unixEmbed-3.2 {ContainerEventProc procedure, set size on creation} -constra toplevel .t1 -container 1 wm geometry .t1 +0+0 toplevel .t2 -use [winfo id .t1] -bg red - while {[winfo exists .t2] == 0} { - update - } + update wm geometry .t2 } -cleanup { deleteWindows -- cgit v0.12 From 9747a9414bed5cfde9117d6af3dd076cdd21e15a Mon Sep 17 00:00:00 2001 From: fvogel Date: Sun, 27 Jan 2019 13:38:05 +0000 Subject: Make unixEmbed-3.2 pass on macOS even with the deployment target when unixEmbed-1.5a was run before. --- tests/unixEmbed.test | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unixEmbed.test b/tests/unixEmbed.test index 0ab275d..ecdab0d 100644 --- a/tests/unixEmbed.test +++ b/tests/unixEmbed.test @@ -386,6 +386,7 @@ test unixEmbed-3.2 {ContainerEventProc procedure, set size on creation} -constra unix } -setup { deleteWindows + update } -body { toplevel .t1 -container 1 wm geometry .t1 +0+0 -- cgit v0.12 From 7444c05633a6dd6546d4046e238bec448eb42c9d Mon Sep 17 00:00:00 2001 From: fvogel Date: Sun, 27 Jan 2019 13:46:01 +0000 Subject: Fix indentation in the -setup and -cleanup sections of the new *a tests --- tests/unixEmbed.test | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/tests/unixEmbed.test b/tests/unixEmbed.test index ecdab0d..349449a 100644 --- a/tests/unixEmbed.test +++ b/tests/unixEmbed.test @@ -145,7 +145,7 @@ test unixEmbed-1.5 {TkpUseWindow procedure, creating Container records} -constra deleteWindows } -result {{{XXX {} {} .t}} 0} test unixEmbed-1.5a {TkpUseWindow procedure, creating Container records} -constraints { - unix testembed + unix testembed } -setup { deleteWindows catch {interp delete slave} @@ -162,8 +162,8 @@ test unixEmbed-1.5a {TkpUseWindow procedure, creating Container records} -constr list [testembed] [expr {[lindex [lindex [testembed all] 0] 0] - [w]}] } } -cleanup { - interp delete slave - deleteWindows + interp delete slave + deleteWindows } -result {{{XXX {} {} .t}} 0} test unixEmbed-1.6 {TkpUseWindow procedure, creating Container records} -constraints { unix testembed notAqua @@ -185,7 +185,7 @@ test unixEmbed-1.6 {TkpUseWindow procedure, creating Container records} -constra deleteWindows } -result {{XXX {} {} .t2} {XXX {} {} .t1}} test unixEmbed-1.6a {TkpUseWindow procedure, creating Container records} -constraints { - unix testembed + unix testembed } -setup { deleteWindows catch {interp delete slave} @@ -204,8 +204,8 @@ test unixEmbed-1.6a {TkpUseWindow procedure, creating Container records} -constr testembed } } -cleanup { - interp delete slave - deleteWindows + interp delete slave + deleteWindows } -result {{XXX {} {} .t2} {XXX {} {} .t1}} test unixEmbed-1.7 {TkpUseWindow procedure, container and embedded in same app} -constraints { unix testembed @@ -248,7 +248,7 @@ test unixEmbed-2.1 {EmbeddedEventProc procedure} -constraints { deleteWindows } -result {} test unixEmbed-2.1a {EmbeddedEventProc procedure} -constraints { - unix testembed + unix testembed } -setup { deleteWindows catch {interp delete slave} @@ -269,7 +269,7 @@ test unixEmbed-2.1a {EmbeddedEventProc procedure} -constraints { testembed } } -cleanup { - deleteWindows + deleteWindows } -result {} test unixEmbed-2.2 {EmbeddedEventProc procedure} -constraints { unix testembed notAqua @@ -290,7 +290,7 @@ test unixEmbed-2.2 {EmbeddedEventProc procedure} -constraints { deleteWindows } -result {} test unixEmbed-2.2a {EmbeddedEventProc procedure} -constraints { - unix testembed + unix testembed } -setup { deleteWindows catch {interp delete slave} @@ -418,7 +418,7 @@ test unixEmbed-3.3 {ContainerEventProc procedure, disallow position changes} -co deleteWindows } -result {200x200+0+0} test unixEmbed-3.3a {ContainerEventProc procedure, disallow position changes} -constraints { - unix + unix } -setup { deleteWindows catch {interp delete slave} @@ -506,7 +506,7 @@ test unixEmbed-3.5 {ContainerEventProc procedure, geometry requests} -constraint deleteWindows } -result {300 80 300x80+0+0} test unixEmbed-3.5a {ContainerEventProc procedure, geometry requests} -constraints { - unix + unix } -setup { deleteWindows catch {interp delete slave} @@ -551,7 +551,7 @@ test unixEmbed-3.6 {ContainerEventProc procedure, map requests} -constraints { deleteWindows } -result {mapped} test unixEmbed-3.6a {ContainerEventProc procedure, map requests} -constraints { - unix + unix } -setup { deleteWindows catch {interp delete slave} @@ -599,7 +599,7 @@ test unixEmbed-3.7 {ContainerEventProc procedure, destroy events} -constraints { deleteWindows } -result {dead 0} test unixEmbed-3.7a {ContainerEventProc procedure, destroy events} -constraints { - unix + unix } -setup { deleteWindows catch {interp delete slave} @@ -648,7 +648,7 @@ test unixEmbed-4.1 {EmbedStructureProc procedure, configure events} -constraints deleteWindows } -result {180x100+0+0} test unixEmbed-4.1a {EmbedStructureProc procedure, configure events} -constraints { - unix + unix } -setup { deleteWindows catch {interp delete slave} @@ -691,7 +691,7 @@ test unixEmbed-4.2 {EmbedStructureProc procedure, destroy events} -constraints { deleteWindows } -result {{{XXX .f1 XXX {}}} {}} test unixEmbed-4.2a {EmbedStructureProc procedure, destroy events} -constraints { - unix testembed + unix testembed } -setup { deleteWindows catch {interp delete slave} @@ -737,7 +737,7 @@ test unixEmbed-5.1 {EmbedFocusProc procedure, FocusIn events} -constraints { deleteWindows } -result {{focus in .t1}} test unixEmbed-5.1a {EmbedFocusProc procedure, FocusIn events} -constraints { - unix + unix } -setup { deleteWindows catch {interp delete slave} @@ -784,7 +784,7 @@ test unixEmbed-5.2 {EmbedFocusProc procedure, focusing on dead window} -constrai deleteWindows } -result {} test unixEmbed-5.2a {EmbedFocusProc procedure, focusing on dead window} -constraints { - unix + unix } -setup { deleteWindows catch {interp delete slave} @@ -832,7 +832,7 @@ test unixEmbed-5.3 {EmbedFocusProc procedure, FocusOut events} -constraints { deleteWindows } -result {{{focus in .t1}} {{focus in .t1} {focus out .t1}}} test unixEmbed-5.3a {EmbedFocusProc procedure, FocusOut events} -constraints { - unix + unix } -setup { deleteWindows catch {interp delete slave} @@ -886,7 +886,7 @@ test unixEmbed-6.1 {EmbedGeometryRequest procedure, window changes size} -constr deleteWindows } -result {{{configure .t1 300 120}} 300x120+0+0} test unixEmbed-6.1a {EmbedGeometryRequest procedure, window changes size} -constraints { - unix + unix } -setup { deleteWindows catch {interp delete slave} @@ -936,7 +936,7 @@ test unixEmbed-6.2 {EmbedGeometryRequest procedure, window changes size} -constr deleteWindows } -result {{{configure .t1 200 200}} 200x200+0+0} test unixEmbed-6.2a {EmbedGeometryRequest procedure, window changes size} -constraints { - unix + unix } -setup { deleteWindows catch {interp delete slave} @@ -997,7 +997,7 @@ test unixEmbed-7.1 {TkpRedirectKeyEvent procedure, forward keystroke} -constrain bind . {} } -result {{{key a 1}} {}} test unixEmbed-7.1a {TkpRedirectKeyEvent procedure, forward keystroke} -constraints { - unix + unix } -setup { deleteWindows catch {interp delete slave} @@ -1060,7 +1060,7 @@ test unixEmbed-7.2 {TkpRedirectKeyEvent procedure, don't forward keystroke width bind . {} } -result {{} {{key b}}} test unixEmbed-7.2a {TkpRedirectKeyEvent procedure, don't forward keystroke width} -constraints { - unix + unix } -setup { deleteWindows catch {interp delete slave} @@ -1217,7 +1217,7 @@ test unixEmbed-9.2 {EmbedWindowDeleted procedure, check embeddedPtr} -constraint deleteWindows } -result {{{XXX {} {} .t1}} {}} test unixEmbed-9.2a {EmbedWindowDeleted procedure, check embeddedPtr} -constraints { - unix testembed + unix testembed } -setup { deleteWindows catch {interp delete slave} -- cgit v0.12 From ff7c0d39fa897fd6a7fe27ed0cb6d424311d5d83 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sun, 27 Jan 2019 14:07:08 +0000 Subject: Reduce the number of unixEmbed test failures on Linux from 10 to 4 by propagating changes in TkpTestembedCmd from macosx/tkMacOSXEmbed.c to the unix version of it in unix/tkUnixEmbed.c --- unix/tkUnixEmbed.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/unix/tkUnixEmbed.c b/unix/tkUnixEmbed.c index b170ad0..539cb8a 100644 --- a/unix/tkUnixEmbed.c +++ b/unix/tkUnixEmbed.c @@ -873,6 +873,7 @@ TkpTestembedCmd( Container *containerPtr; Tcl_DString dString; char buffer[50]; + Tcl_Interp *embeddedInterp = NULL, *parentInterp = NULL; ThreadSpecificData *tsdPtr = Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); @@ -884,21 +885,34 @@ TkpTestembedCmd( Tcl_DStringInit(&dString); for (containerPtr = tsdPtr->firstContainerPtr; containerPtr != NULL; containerPtr = containerPtr->nextPtr) { + if (containerPtr->embeddedPtr != NULL) { + embeddedInterp = containerPtr->embeddedPtr->mainPtr->interp; + } + if (containerPtr->parentPtr != NULL) { + parentInterp = containerPtr->parentPtr->mainPtr->interp; + } + if (embeddedInterp != interp && parentInterp != interp) { + continue; + } Tcl_DStringStartSublist(&dString); + /* Parent id */ if (containerPtr->parent == None) { Tcl_DStringAppendElement(&dString, ""); } else if (all) { - sprintf(buffer, "0x%x", (int) containerPtr->parent); + sprintf(buffer, "0x%lx", (int) containerPtr->parent); Tcl_DStringAppendElement(&dString, buffer); } else { Tcl_DStringAppendElement(&dString, "XXX"); } - if (containerPtr->parentPtr == NULL) { + /* Parent pathName */ + if (containerPtr->parentPtr == NULL || + parentInterp != interp) { Tcl_DStringAppendElement(&dString, ""); } else { Tcl_DStringAppendElement(&dString, containerPtr->parentPtr->pathName); } + /* Wrapper */ if (containerPtr->wrapper == None) { Tcl_DStringAppendElement(&dString, ""); } else if (all) { @@ -907,7 +921,9 @@ TkpTestembedCmd( } else { Tcl_DStringAppendElement(&dString, "XXX"); } - if (containerPtr->embeddedPtr == NULL) { + /* Embedded window pathName */ + if (containerPtr->embeddedPtr == NULL || + embeddedInterp != interp) { Tcl_DStringAppendElement(&dString, ""); } else { Tcl_DStringAppendElement(&dString, -- cgit v0.12 From b96636b76f92c8c6cf41a40633db08391560602f Mon Sep 17 00:00:00 2001 From: fvogel Date: Sun, 27 Jan 2019 16:04:23 +0000 Subject: More changes in the Unix version of TkpTestembedCmd --- unix/tkUnixEmbed.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unix/tkUnixEmbed.c b/unix/tkUnixEmbed.c index 539cb8a..e1c4394 100644 --- a/unix/tkUnixEmbed.c +++ b/unix/tkUnixEmbed.c @@ -899,7 +899,7 @@ TkpTestembedCmd( if (containerPtr->parent == None) { Tcl_DStringAppendElement(&dString, ""); } else if (all) { - sprintf(buffer, "0x%lx", (int) containerPtr->parent); + sprintf(buffer, "0x%lx", containerPtr->parent); Tcl_DStringAppendElement(&dString, buffer); } else { Tcl_DStringAppendElement(&dString, "XXX"); @@ -916,7 +916,7 @@ TkpTestembedCmd( if (containerPtr->wrapper == None) { Tcl_DStringAppendElement(&dString, ""); } else if (all) { - sprintf(buffer, "0x%x", (int) containerPtr->wrapper); + sprintf(buffer, "0x%lx", containerPtr->wrapper); Tcl_DStringAppendElement(&dString, buffer); } else { Tcl_DStringAppendElement(&dString, "XXX"); -- cgit v0.12 From 43b8641102c6727136926d0494328292a4c739aa Mon Sep 17 00:00:00 2001 From: culler Date: Sun, 27 Jan 2019 16:26:25 +0000 Subject: Fix bugs that could lead to segfaults when the test interpreter is destroyed. --- macosx/tkMacOSXWm.c | 109 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 73 insertions(+), 36 deletions(-) diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index 0418632..6a6c254 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -322,6 +322,7 @@ static void GetMaxSize(TkWindow *winPtr, int *maxWidthPtr, int *maxHeightPtr); static void RemapWindows(TkWindow *winPtr, MacDrawable *parentWin); +static void RemoveTransient(TkWindow *winPtr); #pragma mark NSWindow(TKWm) @@ -888,6 +889,13 @@ TkWmDeadWindow( if (wmPtr == NULL) { return; } + + /* + *If the dead window is a transient, remove it from the master's list. + */ + + RemoveTransient(winPtr); + Tk_ManageGeometry((Tk_Window) winPtr, NULL, NULL); Tk_DeleteEventHandler((Tk_Window) winPtr, StructureNotifyMask, TopLevelEventProc, winPtr); @@ -936,15 +944,15 @@ TkWmDeadWindow( */ for (Transient *transientPtr = wmPtr->transientPtr; - transientPtr != NULL; transientPtr = transientPtr->nextPtr) { - TkWindow *winPtr2 = transientPtr->winPtr; - Window master = TkGetTransientMaster(winPtr2); - TkWindow *masterPtr = (TkWindow *)Tk_IdToWindow(dispPtr->display, master); + transientPtr != NULL; transientPtr = transientPtr->nextPtr) { + TkWindow *winPtr2 = transientPtr->winPtr; + Window master = TkGetTransientMaster(winPtr2); + TkWindow *masterPtr = (TkWindow *)Tk_IdToWindow(dispPtr->display, master); if (masterPtr == winPtr) { - wmPtr2 = winPtr2->wmInfoPtr; - wmPtr2->master = None; - ckfree(wmPtr2->masterWindowName); - wmPtr2->masterWindowName = NULL; + wmPtr2 = winPtr2->wmInfoPtr; + wmPtr2->master = None; + ckfree(wmPtr2->masterWindowName); + wmPtr2->masterWindowName = NULL; } } @@ -3574,7 +3582,6 @@ WmTransientCmd( register WmInfo *wmPtr = winPtr->wmInfoPtr; Tk_Window master; WmInfo *wmPtr2; - TkDisplay *dispPtr = TkGetDisplayList(); char *masterWindowName; int length; @@ -3590,34 +3597,8 @@ WmTransientCmd( return TCL_OK; } if (Tcl_GetString(objv[3])[0] == '\0') { + RemoveTransient(winPtr); - /* - * Remove the transient from its master's list. - */ - - if (wmPtr->master != None) { - TkWindow *masterPtr = (TkWindow*)Tk_IdToWindow(dispPtr->display, - wmPtr->master); - wmPtr2 = masterPtr->wmInfoPtr; - Transient *transientPtr = wmPtr2->transientPtr; - if (transientPtr->winPtr == winPtr) { - wmPtr2->transientPtr = transientPtr->nextPtr; - } else while (transientPtr->nextPtr != NULL) { - if (transientPtr->nextPtr->winPtr == winPtr) { - transientPtr->nextPtr = transientPtr->nextPtr->nextPtr; - break; - } - transientPtr = transientPtr->nextPtr; - } - if (transientPtr!= NULL) { - ckfree(transientPtr); - } - wmPtr->master = None; - if (wmPtr->masterWindowName != NULL) { - ckfree(wmPtr->masterWindowName); - } - wmPtr->masterWindowName = NULL; - } } else { if (TkGetWindowFromObj(interp, tkwin, objv[3], &master) != TCL_OK) { return TCL_ERROR; @@ -3671,6 +3652,7 @@ WmTransientCmd( /* * If the master is withdrawn or iconic then withdraw the transient. */ + if ((wmPtr2->hints.initial_state == WithdrawnState || wmPtr2->hints.initial_state == IconicState) && wmPtr->hints.initial_state != WithdrawnState){ @@ -3690,6 +3672,61 @@ WmTransientCmd( ApplyMasterOverrideChanges(winPtr, NULL); return TCL_OK; } + +/* + *---------------------------------------------------------------------- + * + * RemoveTransient -- + * + * Clears the transient's master record and removes the transient + * from the master's list. + * + * Results: + * None + * + * Side effects: + * References to a master are removed from the transient's wmInfo + * structure and references to the transient are removed from its + * master's wmInfo. + * + *---------------------------------------------------------------------- + */ + +static void +RemoveTransient( + TkWindow *winPtr) +{ + WmInfo *wmPtr = winPtr->wmInfoPtr, *wmPtr2; + TkDisplay *dispPtr = TkGetDisplayList(); + TkWindow *masterPtr; + if (wmPtr == NULL || wmPtr->master == None) { + return; + } + masterPtr = (TkWindow*)Tk_IdToWindow(dispPtr->display, wmPtr->master); + wmPtr2 = masterPtr->wmInfoPtr; + if (wmPtr2 == NULL) { + return; + } + wmPtr->master = None; + if (wmPtr->masterWindowName != NULL) { + ckfree(wmPtr->masterWindowName); + } + wmPtr->masterWindowName = NULL; + Transient *temp, *cursor = wmPtr2->transientPtr; + if (cursor->winPtr == winPtr) { + temp = cursor->nextPtr; + ckfree(cursor); + cursor = temp; + masterPtr->wmInfoPtr->transientPtr = cursor; + } + while (cursor != NULL) { + if (cursor->winPtr == winPtr) { + temp = cursor->nextPtr; + ckfree(cursor); + cursor = temp; + } + } +} /* *---------------------------------------------------------------------- -- cgit v0.12 From ce11b1ea1514181f1c1c5e7d0b09fce77212dbe3 Mon Sep 17 00:00:00 2001 From: fvogel Date: Sun, 27 Jan 2019 16:56:40 +0000 Subject: Add an update making unixEmbed-5.1a pass on Linux --- tests/unixEmbed.test | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unixEmbed.test b/tests/unixEmbed.test index 349449a..1687a29 100644 --- a/tests/unixEmbed.test +++ b/tests/unixEmbed.test @@ -752,6 +752,7 @@ test unixEmbed-5.1a {EmbedFocusProc procedure, FocusIn events} -constraints { toplevel .t1 -use [w1] bind .t1 {lappend x "focus in %W"} bind .t1 {lappend x "focus out %W"} + update set x {} } focus -force .f1 -- cgit v0.12 From 2127d0a3c7f96a8769f3eced53bf5cd1008b768b Mon Sep 17 00:00:00 2001 From: culler Date: Sun, 27 Jan 2019 17:15:08 +0000 Subject: Fix over-correction in the last commit. We must allow item to be nil on macOS. --- macosx/tkMacOSXMenu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index ed8d0c3..0b84891 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -807,7 +807,7 @@ TkpPostMenu( if (itemIndex >= 0) { item = [menu itemAtIndex:itemIndex]; } - if (menu != nil && item != nil) { + if (menu != nil) { oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE); [menu popUpMenuPositioningItem:item atLocation:[win tkConvertPointFromScreen:location] -- cgit v0.12 From 8d1aa0f36abad1148d39757b1f9f23b6ea6a5ace Mon Sep 17 00:00:00 2001 From: culler Date: Mon, 28 Jan 2019 14:27:13 +0000 Subject: Use the MENU_DELETION_PENDING flag to guard against crashes when the postcommand deletes the menu. --- macosx/tkMacOSXMenu.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index 0b84891..ef32738 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -807,12 +807,10 @@ TkpPostMenu( if (itemIndex >= 0) { item = [menu itemAtIndex:itemIndex]; } - if (menu != nil) { - oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE); + if (menu != nil && !(menuPtr->menuFlags & MENU_DELETION_PENDING)) { [menu popUpMenuPositioningItem:item atLocation:[win tkConvertPointFromScreen:location] inView:view]; - Tcl_SetServiceMode(oldMode); } inPostMenu = 0; return TCL_OK; -- cgit v0.12 From e087bb7d89526c82c0c0fb1e1bf5a6f21cf6d2ab Mon Sep 17 00:00:00 2001 From: culler Date: Mon, 28 Jan 2019 16:39:02 +0000 Subject: Reverting TkpPostTearoffMenu to the unix function, which is equally useless but allows the tests to run without user intervention. --- macosx/tkMacOSXMenu.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 82 insertions(+), 9 deletions(-) diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index ef32738..d261add 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -779,7 +779,7 @@ TkpPostMenu( * entry, will be located. */ int index) { - int result, oldMode; + int result; Tk_Window root = Tk_MainWindow(interp); if (root == NULL) { @@ -807,11 +807,19 @@ TkpPostMenu( if (itemIndex >= 0) { item = [menu itemAtIndex:itemIndex]; } - if (menu != nil && !(menuPtr->menuFlags & MENU_DELETION_PENDING)) { - [menu popUpMenuPositioningItem:item - atLocation:[win tkConvertPointFromScreen:location] - inView:view]; + + /* + * The post commands could have deleted the menu, which means we are dead + * and should go away. + */ + + if (menuPtr->tkwin == NULL) { + return TCL_OK; } + + [menu popUpMenuPositioningItem:item + atLocation:[win tkConvertPointFromScreen:location] + inView:view]; inPostMenu = 0; return TCL_OK; } @@ -820,13 +828,78 @@ int TkpPostTearoffMenu( Tcl_Interp *interp, /* The interpreter this menu lives in */ TkMenu *menuPtr, /* The menu we are posting */ - int x, int y, /* The screen coordinates where the top left + int x, int y, int index) /* The screen coordinates where the top left * corner of the menu, or of the specified * entry, will be located. */ - int index) { - menuPtr->active = -1; - return TkpPostMenu(interp, menuPtr, x, y, index); + int vRootX, vRootY, vRootWidth, vRootHeight; + int result; + + if (index >= menuPtr->numEntries) { + index = menuPtr->numEntries - 1; + } + if (index >= 0) { + y -= menuPtr->entries[index]->y; + } + + TkActivateMenuEntry(menuPtr, -1); + TkRecomputeMenu(menuPtr); + result = TkPostCommand(menuPtr); + if (result != TCL_OK) { + return result; + } + + /* + * The post commands could have deleted the menu, which means we are dead + * and should go away. + */ + + if (menuPtr->tkwin == NULL) { + return TCL_OK; + } + + /* + * Adjust the position of the menu if necessary to keep it visible on the + * screen. There are two special tricks to make this work right: + * + * 1. If a virtual root window manager is being used then the coordinates + * are in the virtual root window of menuPtr's parent; since the menu + * uses override-redirect mode it will be in the *real* root window for + * the screen, so we have to map the coordinates from the virtual root + * (if any) to the real root. Can't get the virtual root from the menu + * itself (it will never be seen by the wm) so use its parent instead + * (it would be better to have an an option that names a window to use + * for this...). + * 2. The menu may not have been mapped yet, so its current size might be + * the default 1x1. To compute how much space it needs, use its + * requested size, not its actual size. + */ + + Tk_GetVRootGeometry(Tk_Parent(menuPtr->tkwin), &vRootX, &vRootY, + &vRootWidth, &vRootHeight); + vRootWidth -= Tk_ReqWidth(menuPtr->tkwin); + if (x > vRootX + vRootWidth) { + x = vRootX + vRootWidth; + } + if (x < vRootX) { + x = vRootX; + } + vRootHeight -= Tk_ReqHeight(menuPtr->tkwin); + if (y > vRootY + vRootHeight) { + y = vRootY + vRootHeight; + } + if (y < vRootY) { + y = vRootY; + } + Tk_MoveToplevelWindow(menuPtr->tkwin, x, y); + if (!Tk_IsMapped(menuPtr->tkwin)) { + Tk_MapWindow(menuPtr->tkwin); + } + TkWmRestackToplevel((TkWindow *) menuPtr->tkwin, Above, NULL); + return TCL_OK; + + // menuPtr->active = -1; + // return TkpPostMenu(interp, menuPtr, x, y, index); } /* -- cgit v0.12 From 41dd35f2c689c31dc23cde598c7828276b3186b7 Mon Sep 17 00:00:00 2001 From: culler Date: Mon, 28 Jan 2019 17:06:53 +0000 Subject: Edited comments. --- macosx/tkMacOSXMenu.c | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index d261add..bba2cfd 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -753,16 +753,15 @@ TkpDestroyMenuEntry( /* *---------------------------------------------------------------------- * - * TkpPostMenu, TkPostTearoffMenu -- + * TkpPostMenu -- * - * Posts a menu on the screen. (Tearoff menus are the same as - * ordinary menus on the mac.) If entry is < 0 then the menu is + * Posts a menu on the screen. If entry is < 0 then the menu is * drawn so its top left corner is located at the point with * screen coordinates (x, y). Otherwise the top left corner of * the specified entry is located at that point. * * Results: - * None. + * Returns a standard Tcl result. * * Side effects: * The menu is posted and handled. @@ -823,6 +822,34 @@ TkpPostMenu( inPostMenu = 0; return TCL_OK; } + +/* + *---------------------------------------------------------------------- + * + * TkpPostTearoffMenu -- + * + * Tearoff menus are not supported on the Mac. This placeholder + * function, which is simply a copy of the unix function, posts a + * completely useless window with a black background on the screen. If + * entry is < 0 then the window is positioned so that its top left corner + * is located at the point with screen coordinates (x, y). Otherwise the + * window position is offset so that top left corner of the specified + * entry would be located at that point, if there actually were a menu. + * + * Mac menus steal all mouse or keyboard input from the application until + * the menu is dismissed, with or without a selection, by a mouse or key + * event. Posting a Mac menu in a regression test will cause the test to + * halt waiting for user input. This is why the TkpPostMenu function is + * not being used as the placeholder. + * + * Results: + * None. + * + * Side effects: + * A useless window is posted. + * + *---------------------------------------------------------------------- + */ int TkpPostTearoffMenu( -- cgit v0.12 From a882b53474bbebcce65b5fcbd96dea64e652a44e Mon Sep 17 00:00:00 2001 From: culler Date: Mon, 28 Jan 2019 21:16:44 +0000 Subject: Remove lines that were commented out. --- macosx/tkMacOSXMenu.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index bba2cfd..6ed17d5 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -924,9 +924,6 @@ TkpPostTearoffMenu( } TkWmRestackToplevel((TkWindow *) menuPtr->tkwin, Above, NULL); return TCL_OK; - - // menuPtr->active = -1; - // return TkpPostMenu(interp, menuPtr, x, y, index); } /* -- cgit v0.12 From 97d125a390ac2ecb00955aa7bd992f425a7b3aba Mon Sep 17 00:00:00 2001 From: culler Date: Wed, 30 Jan 2019 16:27:08 +0000 Subject: A small change in how ActivateEvents are handled makes unixEmbed-5.3a pass on Aqua. --- macosx/tkMacOSXWindowEvent.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index ad6af30..bed4429 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -523,7 +523,9 @@ GenerateActivateEvents( int activeFlag) { TkGenerateActivateEvents(winPtr, activeFlag); - TkMacOSXGenerateFocusEvent(winPtr, activeFlag); + if (activeFlag) { + TkMacOSXGenerateFocusEvent(winPtr, activeFlag); + } return true; } -- cgit v0.12 From dcf8f65baa1a666ad952e8690b43af762eaaaef1 Mon Sep 17 00:00:00 2001 From: culler Date: Wed, 30 Jan 2019 17:04:23 +0000 Subject: Tweak the last commit: generate FocusOut events when the NSApp is deactivated. --- macosx/tkMacOSXWindowEvent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index bed4429..c39f62b 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -523,7 +523,7 @@ GenerateActivateEvents( int activeFlag) { TkGenerateActivateEvents(winPtr, activeFlag); - if (activeFlag) { + if (activeFlag || ![NSApp isActive]) { TkMacOSXGenerateFocusEvent(winPtr, activeFlag); } return true; -- cgit v0.12 From 25dfb62ab6c1f942344631c852e0dfce78f0a360 Mon Sep 17 00:00:00 2001 From: culler Date: Thu, 31 Jan 2019 22:00:31 +0000 Subject: Changes which make unixEmbed-8.1a pass on macOS. --- generic/tkFocus.c | 70 ++++++++++++++++++++++++++++++-------------------- macosx/tkMacOSXEmbed.c | 7 ++--- macosx/tkMacOSXWm.c | 6 +++-- tests/unixEmbed.test | 8 +++--- 4 files changed, 52 insertions(+), 39 deletions(-) diff --git a/generic/tkFocus.c b/generic/tkFocus.c index 60f631d..c621bf9 100644 --- a/generic/tkFocus.c +++ b/generic/tkFocus.c @@ -551,12 +551,17 @@ TkSetFocusWin( return; } + /* + * Get the current focus window with the same display and application + * as winPtr. + */ + displayFocusPtr = FindDisplayFocusInfo(winPtr->mainPtr, winPtr->dispPtr); /* - * If force is set, we should make sure we grab the focus regardless of - * the current focus window since under Windows, we may need to take - * control away from another application. + * Do nothing if the window already has focus and force is not set. If + * force is set, we need to grab the focus, since under Windows or macOS + * this may involve taking control away from another application. */ if (winPtr == displayFocusPtr->focusWinPtr && !force) { @@ -564,14 +569,15 @@ TkSetFocusWin( } /* - * Find the top-level window for winPtr, then find (or create) a record - * for the top-level. Also see whether winPtr and all its ancestors are + * Find the toplevel window for winPtr, then find (or create) a record + * for the toplevel. Also see whether winPtr and all its ancestors are * mapped. */ allMapped = 1; for (topLevelPtr = winPtr; ; topLevelPtr = topLevelPtr->parentPtr) { if (topLevelPtr == NULL) { + /* * The window is being deleted. No point in worrying about giving * it the focus. @@ -588,11 +594,11 @@ TkSetFocusWin( } /* - * If the new focus window isn't mapped, then we can't focus on it (X will - * generate an error, for example). Instead, create an event handler that - * will set the focus to this window once it gets mapped. At the same - * time, delete any old handler that might be around; it's no longer - * relevant. + * If any ancestor of the new focus window isn't mapped, then we can't set + * focus for it (X will generate an error, for example). Instead, create + * an event handler that will set the focus to this window once it gets + * mapped. At the same time, delete any old handler that might be around; + * it's no longer relevant. */ if (displayFocusPtr->focusOnMapPtr != NULL) { @@ -623,30 +629,38 @@ TkSetFocusWin( } tlFocusPtr->focusWinPtr = winPtr; - /* - * Reset the window system's focus window and generate focus events, with - * two special cases: - * - * 1. If the application is embedded and doesn't currently have the focus, - * don't set the focus directly. Instead, see if the embedding code can - * claim the focus from the enclosing container. - * 2. Otherwise, if the application doesn't currently have the focus, - * don't change the window system's focus unless it was already in this - * application or "force" was specified. - */ + if (topLevelPtr->flags & TK_EMBEDDED) { + + /* + * We are assigning focus to an embedded toplevel. The platform + * specific function TkpClaimFocus needs to handle the job of + * assigning focus to the container, since we have no way to find the + * contaiuner. + */ - if ((topLevelPtr->flags & TK_EMBEDDED) - && (displayFocusPtr->focusWinPtr == NULL)) { TkpClaimFocus(topLevelPtr, force); } else if ((displayFocusPtr->focusWinPtr != NULL) || force) { + /* - * Generate events to shift focus between Tk windows. We do this - * regardless of what TkpChangeFocus does with the real X focus so - * that Tk widgets track focus commands when there is no window - * manager. GenerateFocusEvents will set up a serial number marker so - * we discard focus events that are triggered by the ChangeFocus. + * If we are forcing removal of focus from a container hosting a + * toplevel from a different application, clear the focus in that + * application. */ + + if (force) { + TkWindow *focusPtr = winPtr->dispPtr->focusPtr; + if (focusPtr && focusPtr->mainPtr != winPtr->mainPtr) { + DisplayFocusInfo *displayFocusPtr2 = FindDisplayFocusInfo( + focusPtr->mainPtr, focusPtr->dispPtr); + displayFocusPtr2->focusWinPtr = NULL; + } + } + /* + * Call the platform specific function TkpChangeFocus to move the + * window manager's focus to a new toplevel. + */ + serial = TkpChangeFocus(TkpGetWrapperWindow(topLevelPtr), force); if (serial != 0) { displayFocusPtr->focusSerial = serial; diff --git a/macosx/tkMacOSXEmbed.c b/macosx/tkMacOSXEmbed.c index 8fcbb09..3108d4c 100644 --- a/macosx/tkMacOSXEmbed.c +++ b/macosx/tkMacOSXEmbed.c @@ -498,9 +498,7 @@ TkMacOSXGetHostToplevel( * TkpClaimFocus -- * * This procedure is invoked when someone asks for the input focus to be - * put on a window in an embedded application, but the application - * doesn't currently have the focus. It requests the input focus from the - * container application. + * put on a window in an embedded application. * * Results: * None. @@ -539,7 +537,7 @@ TkpClaimFocus( event.xfocus.window = containerPtr->parent; event.xfocus.mode = EMBEDDED_APP_WANTS_FOCUS; event.xfocus.detail = force; - Tk_QueueWindowEvent(&event,TCL_QUEUE_TAIL); + Tk_HandleEvent(&event); } /* @@ -914,7 +912,6 @@ EmbedActivateProc( XEvent *eventPtr) /* ResizeRequest event. */ { Container *containerPtr = clientData; - if (containerPtr->embeddedPtr != NULL) { if (eventPtr->type == ActivateNotify) { TkGenerateActivateEvents(containerPtr->embeddedPtr,1); diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index a5e1564..888705f 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -6221,8 +6221,10 @@ XSetInputFocus( * * TkpChangeFocus -- * - * This procedure is a stub on the Mac because we always own the focus if - * we are a front most application. + * This function is called when Tk moves focus from one window to another. + * It should be passed a non-embedded TopLevel. That toplevel gets raised + * to the top of the Tk stacking order and the associated NSWindow is + * ordered Front. * * Results: * The return value is the serial number of the command that changed the diff --git a/tests/unixEmbed.test b/tests/unixEmbed.test index 1687a29..a736e24 100644 --- a/tests/unixEmbed.test +++ b/tests/unixEmbed.test @@ -1130,19 +1130,19 @@ test unixEmbed-8.1a {TkpClaimFocus procedure} -constraints unix -setup { frame .f1 -container 1 -width 200 -height 50 frame .f2 -width 200 -height 50 pack .f1 .f2 + update slave alias w1 winfo id .f1 slave eval { destroy [winfo child .] toplevel .t1 -use [w1] -highlightthickness 2 -bd 2 -relief sunken } + # This should clear focus from the application embedded in .f1 focus -force .f2 update list [slave eval { - focus .t1 set x [list [focus]] - update - after 500 - update + focus .t1 + update lappend x [focus] }] [focus] } -cleanup { -- cgit v0.12 From 144943f2693109cf7edfca3d9eb1ee99a3aedef5 Mon Sep 17 00:00:00 2001 From: culler Date: Fri, 1 Feb 2019 23:38:29 +0000 Subject: Remove unnecessary sleep from unixEmbed-6.2a, which still fails however. --- tests/unixEmbed.test | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tests/unixEmbed.test b/tests/unixEmbed.test index a736e24..9f0ace5 100644 --- a/tests/unixEmbed.test +++ b/tests/unixEmbed.test @@ -946,17 +946,14 @@ test unixEmbed-6.2a {EmbedGeometryRequest procedure, window changes size} -const } -body { frame .f1 -container 1 -width 200 -height 50 place .f1 -width 200 -height 200 + update idletasks slave alias w1 winfo id .f1 slave eval { destroy [winfo child .] + set x {} toplevel .t1 -use [w1] - } - after 300 {set x done} - vwait x - slave eval { - bind .t1 {lappend x {configure .t1 %w %h}} update - set x {} + bind .t1 {lappend x {configure .t1 %w %h}} .t1 configure -width 300 -height 120 update list $x [winfo geom .t1] -- cgit v0.12 From 7ee00057db4a080edfaf39bc921f7eb58d64a459 Mon Sep 17 00:00:00 2001 From: oehhar Date: Sun, 3 Feb 2019 11:21:11 +0000 Subject: gif read not complete on overflow image - information missinterpreted if following subimage is querried [4da2191b] --- generic/tkImgGIF.c | 21 ++++++++++++++++++++- tests/imgPhoto.test | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/generic/tkImgGIF.c b/generic/tkImgGIF.c index 7c4872b..fa4b728 100644 --- a/generic/tkImgGIF.c +++ b/generic/tkImgGIF.c @@ -1034,7 +1034,7 @@ ReadImage( int transparent) { unsigned char initialCodeSize; - int xpos = 0, ypos = 0, pass = 0, i; + int xpos = 0, ypos = 0, pass = 0, i, count; register unsigned char *pixelPtr; static const int interlaceStep[] = { 8, 8, 4, 2 }; static const int interlaceStart[] = { 0, 4, 2, 1 }; @@ -1252,6 +1252,25 @@ ReadImage( } pixelPtr = imagePtr + (ypos) * len * ((transparent>=0)?4:3); } + + /* + * Now read until the final zero byte. + * It was observed that there might be 1 length blocks + * (test imgPhoto-14.1) which are not read. + * + * The field "stack" is abused for temporary buffer. it has 4096 bytes + * and we need 256. + * + * Loop until we hit a 0 length block which is the end sign. + */ + while ( 0 < (count = GetDataBlock(gifConfPtr, chan, stack))) + { + if (-1 == count ) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "error reading GIF image: %s", Tcl_PosixError(interp))); + return TCL_ERROR; + } + } return TCL_OK; } diff --git a/tests/imgPhoto.test b/tests/imgPhoto.test index 97fb7ae..c45c5fb 100644 --- a/tests/imgPhoto.test +++ b/tests/imgPhoto.test @@ -1212,6 +1212,39 @@ test imgPhoto-14.5 {Bug [fbaed1f66b] - GIF decoder with deferred clear code} -se image create photo -file $fileName -format "gif -index 2" } -returnCodes error -result {no image data for this index} +test imgPhoto-14.6 {Access Subimage after Subimage with buffer overflow. Ticket 4da2191b} -setup { + set data { + R0lGODlhYwA5APcAAAAAAIAAAACAAICAAAAAgIAAgACAgICAgAysnGy8hKzM + hASs3MTcjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAwP8AAAD/ + AP//AAAA//8A/wD//////ywAAAAAYwA5AAAI/wAZCBxIsKDBgwgTKlzIsKHD + hxAjSpxIsaLFixgzatzIsaPHjyBDihxJsqTJkyhTqlzJsqXLlzBjypxJs6bN + mzhz6tzJs6fPn0CDCh1KtKhRiwoSKEXAtGlTpUqPGkyagOmCq1edNsWalWkC + BUSXIuDqFepBqFWtZv3KU+zYrkrBSqT6dgECtjOTbu16NwFHvV3lshRLti/J + qlgRCE6ZuO9ik4Dt+k0ZVyZiyVIvXr77ODPEy5g9T4zMWfTEzXdNz1VbWvXn + uqldP1TAOrbshqBb314Y2W7n3Qdpv7UNPCHpycUVbv6dnODy5sqzQldIe8H0 + hciva9/Ovbv37+BzBgE7ACH5BAFkAAMALAAAAAAEAAQAAAMEKLrckgA7 + } +} -body { + image create photo photo1 -data $data -format "GIF -index 1" +} -cleanup { + catch {image delete photo1} +} -result photo1 + test imgPhoto-15.1 {photo images can fail to allocate memory gracefully} -constraints { nonPortable } -body { -- cgit v0.12 From e46d193fc6cc775196c64d70aaa67810c9882844 Mon Sep 17 00:00:00 2001 From: culler Date: Sun, 3 Feb 2019 16:39:31 +0000 Subject: Simplify and uniformize unixEmbed tests 6.1, 6.1a, 6.2, 6.2a. --- tests/unixEmbed.test | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/tests/unixEmbed.test b/tests/unixEmbed.test index 9f0ace5..0abccc8 100644 --- a/tests/unixEmbed.test +++ b/tests/unixEmbed.test @@ -874,9 +874,7 @@ test unixEmbed-6.1 {EmbedGeometryRequest procedure, window changes size} -constr dobg { eval destroy [winfo child .] toplevel .t1 -use $w1 - } - update - dobg { + update bind .t1 {lappend x {configure .t1 %w %h}} set x {} .t1 configure -width 300 -height 120 @@ -922,15 +920,11 @@ test unixEmbed-6.2 {EmbedGeometryRequest procedure, window changes size} -constr dobg { eval destroy [winfo child .] toplevel .t1 -use $w1 - } - after 300 {set x done} - vwait x - dobg { + update bind .t1 {lappend x {configure .t1 %w %h}} set x {} .t1 configure -width 300 -height 120 - after 300 {set y done} - vwait y + update list $x [winfo geom .t1] } } -cleanup { @@ -946,14 +940,14 @@ test unixEmbed-6.2a {EmbedGeometryRequest procedure, window changes size} -const } -body { frame .f1 -container 1 -width 200 -height 50 place .f1 -width 200 -height 200 - update idletasks + update slave alias w1 winfo id .f1 slave eval { destroy [winfo child .] - set x {} toplevel .t1 -use [w1] update bind .t1 {lappend x {configure .t1 %w %h}} + set x {} .t1 configure -width 300 -height 120 update list $x [winfo geom .t1] -- cgit v0.12 From b0ae93bd6283a82f95b52bea063cff0e9c4d16a3 Mon Sep 17 00:00:00 2001 From: culler Date: Mon, 4 Feb 2019 16:48:52 +0000 Subject: Make the place manager send ConfigureNotify events when size change requests are rejected. This makes unixEmbed-6.2a pass. --- generic/tkPlace.c | 6 ++++++ tests/unixEmbed.test | 15 +++++---------- unix/tkUnixEmbed.c | 8 ++++++++ 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/generic/tkPlace.c b/generic/tkPlace.c index 2c06977..8eee5a1 100644 --- a/generic/tkPlace.c +++ b/generic/tkPlace.c @@ -1185,6 +1185,12 @@ PlaceRequestProc( if ((slavePtr->flags & (CHILD_WIDTH|CHILD_REL_WIDTH)) && (slavePtr->flags & (CHILD_HEIGHT|CHILD_REL_HEIGHT))) { + /* + * Send a ConfigureNotify to indicate that the size change + * request was rejected. + */ + + TkDoConfigureNotify((TkWindow *)(slavePtr->tkwin)); return; } masterPtr = slavePtr->masterPtr; diff --git a/tests/unixEmbed.test b/tests/unixEmbed.test index 0abccc8..99f7265 100644 --- a/tests/unixEmbed.test +++ b/tests/unixEmbed.test @@ -323,11 +323,6 @@ test unixEmbed-2.3 {EmbeddedEventProc procedure} -constraints { destroy .f1 testembed } -result {} -if {[tk windowingsystem] eq "aqua"} { - set wrapperId {{}} -} else { - set wrapperId XXX -} test unixEmbed-2.4 {EmbeddedEventProc procedure} -constraints { unix testembed } -setup { @@ -342,7 +337,7 @@ test unixEmbed-2.4 {EmbeddedEventProc procedure} -constraints { list $x [winfo exists .t1] [winfo exists .f1] [testembed] } -cleanup { deleteWindows -} -result "{{XXX .f1 $wrapperId .t1}} 0 0 {}" +} -result "{{XXX .f1 {} .t1}} 0 0 {}" test unixEmbed-3.1 {ContainerEventProc procedure, detect creation} -constraints { @@ -899,7 +894,7 @@ test unixEmbed-6.1a {EmbedGeometryRequest procedure, window changes size} -const destroy [winfo child .] toplevel .t1 -use [w1] update - bind .t1 {lappend x {configure .t1 %w %h}} + bind .t1 {set x {configure .t1 %w %h}} set x {} .t1 configure -width 300 -height 120 update @@ -908,7 +903,7 @@ test unixEmbed-6.1a {EmbedGeometryRequest procedure, window changes size} -const } -cleanup { interp delete slave deleteWindows -} -result {{{configure .t1 300 120}} 300x120+0+0} +} -result {{configure .t1 300 120} 300x120+0+0} test unixEmbed-6.2 {EmbedGeometryRequest procedure, window changes size} -constraints { unix notAqua } -setup { @@ -946,7 +941,7 @@ test unixEmbed-6.2a {EmbedGeometryRequest procedure, window changes size} -const destroy [winfo child .] toplevel .t1 -use [w1] update - bind .t1 {lappend x {configure .t1 %w %h}} + bind .t1 {set x {configure .t1 %w %h}} set x {} .t1 configure -width 300 -height 120 update @@ -955,7 +950,7 @@ test unixEmbed-6.2a {EmbedGeometryRequest procedure, window changes size} -const } -cleanup { interp delete slave deleteWindows -} -result {{{configure .t1 200 200}} 200x200+0+0} +} -result {{configure .t1 200 200} 200x200+0+0} # Can't think up any tests for TkpGetOtherWindow procedure. diff --git a/unix/tkUnixEmbed.c b/unix/tkUnixEmbed.c index e1c4394..d9203ca 100644 --- a/unix/tkUnixEmbed.c +++ b/unix/tkUnixEmbed.c @@ -503,7 +503,15 @@ EmbedStructureProc( Tk_ErrorHandler errHandler; if (eventPtr->type == ConfigureNotify) { + /* + * Send a ConfigureNotify to the embedded application. + */ + + if (containerPtr->embeddedPtr != None) { + TkDoConfigureNotify(containerPtr->embeddedPtr); + } if (containerPtr->wrapper != None) { + /* * Ignore errors, since the embedded application could have * deleted its window. -- cgit v0.12 From 20fd9ad0dbfadae62d438616af4c461e39798fa9 Mon Sep 17 00:00:00 2001 From: culler Date: Mon, 4 Feb 2019 19:08:50 +0000 Subject: Change tkMacOSXEmbed.c to match the change in tkUnixEmbed.c even though this not needed to pass 6.2a. --- macosx/tkMacOSXEmbed.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/macosx/tkMacOSXEmbed.c b/macosx/tkMacOSXEmbed.c index 3108d4c..932d4cb 100644 --- a/macosx/tkMacOSXEmbed.c +++ b/macosx/tkMacOSXEmbed.c @@ -869,6 +869,14 @@ EmbedStructureProc( Tk_ErrorHandler errHandler; if (eventPtr->type == ConfigureNotify) { + + /* + * Send a ConfigureNotify to the embedded application. + */ + + if (containerPtr->embeddedPtr != None) { + TkDoConfigureNotify(containerPtr->embeddedPtr); + } if (containerPtr->embedded != None) { /* * Ignore errors, since the embedded application could have -- cgit v0.12 From 71775ff27a2673061e31435638f38fa3783868d0 Mon Sep 17 00:00:00 2001 From: culler Date: Thu, 7 Feb 2019 17:08:49 +0000 Subject: Also change tkWinEmbed.c to match the change in tkUnixEmbed.c, for consistency. --- win/tkWinEmbed.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/win/tkWinEmbed.c b/win/tkWinEmbed.c index 43c5e25..f28508d 100644 --- a/win/tkWinEmbed.c +++ b/win/tkWinEmbed.c @@ -856,6 +856,15 @@ ContainerEventProc( Tk_Window tkwin = (Tk_Window)containerPtr->parentPtr; if (eventPtr->type == ConfigureNotify) { + + /* + * Send a ConfigureNotify to the embedded application. + */ + + if (containerPtr->embeddedPtr != None) { + TkDoConfigureNotify(containerPtr->embeddedPtr); + } + /* * Resize the embedded window, if there is any. */ -- cgit v0.12 From e4d80b4d45925dc8efdb80b5c9bfa8f2e057d78a Mon Sep 17 00:00:00 2001 From: culler Date: Fri, 8 Feb 2019 16:44:25 +0000 Subject: Fix bug [1529659ff]: Embedded toplevel makes the outer toplevel menu inaccessible. --- macosx/tkMacOSXMenu.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index dfa3e53..316a8d7 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -985,26 +985,47 @@ TkpSetMainMenubar( { static Tcl_Interp *currentInterp = NULL; TKMenu *menu = nil; + TkWindow *winPtr = (TkWindow *) tkwin; + + /* + * We will be called when an embedded window receives an ActivationNotify + * event, but we should not change the menubar in that case. + */ + + if (Tk_IsEmbedded(winPtr)) { + return; + } if (menuName) { - TkWindow *winPtr = (TkWindow *) tkwin; + Tk_Window menubar = NULL; + if (winPtr->wmInfoPtr && + winPtr->wmInfoPtr->menuPtr && + winPtr->wmInfoPtr->menuPtr->masterMenuPtr) { + menubar = winPtr->wmInfoPtr->menuPtr->masterMenuPtr->tkwin; + } - if (winPtr->wmInfoPtr && winPtr->wmInfoPtr->menuPtr && - winPtr->wmInfoPtr->menuPtr->masterMenuPtr && - winPtr->wmInfoPtr->menuPtr->masterMenuPtr->tkwin && - !strcmp(menuName, Tk_PathName( - winPtr->wmInfoPtr->menuPtr->masterMenuPtr->tkwin))) { + /* + * Attempt to find the NSMenu directly. If that fails, ask Tk to find it. + */ + + if (menubar != NULL && strcmp(menuName, Tk_PathName(menubar)) == 0) { menu = (TKMenu *) winPtr->wmInfoPtr->menuPtr->platformData; } else { TkMenuReferences *menuRefPtr = TkFindMenuReferences(interp, menuName); - if (menuRefPtr && menuRefPtr->menuPtr && menuRefPtr->menuPtr->platformData) { menu = (TKMenu *) menuRefPtr->menuPtr->platformData; } } } + + /* + * If we couldn't find a menu, do nothing unless the window belongs + * to a different application. In that case, install the default + * menubar. + */ + if (menu || interp != currentInterp) { [NSApp tkSetMainMenu:menu]; } -- cgit v0.12 From 57942e0fd075aa6e841279d4e098b6296d97fecd Mon Sep 17 00:00:00 2001 From: fvogel Date: Fri, 8 Feb 2019 17:10:18 +0000 Subject: Fix the build for MSVC --- win/tkWinEmbed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win/tkWinEmbed.c b/win/tkWinEmbed.c index f28508d..6c80964 100644 --- a/win/tkWinEmbed.c +++ b/win/tkWinEmbed.c @@ -861,7 +861,7 @@ ContainerEventProc( * Send a ConfigureNotify to the embedded application. */ - if (containerPtr->embeddedPtr != None) { + if (containerPtr->embeddedPtr != NULL) { TkDoConfigureNotify(containerPtr->embeddedPtr); } -- cgit v0.12 From 014209356fa48fa5d181e87c4ebba55dd7ea9a4a Mon Sep 17 00:00:00 2001 From: culler Date: Sat, 9 Feb 2019 18:56:40 +0000 Subject: Fix bug [8814bddf5d]: segfault in [NSMenu size] --- macosx/tkMacOSXMenu.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index 316a8d7..227c379 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -1038,8 +1038,8 @@ TkpSetMainMenubar( * CheckForSpecialMenu -- * * Given a menu, check to see whether or not it is a cascade in a menubar - * with one of the special names .apple, .help or .window If it is, the - * entry that points to this menu will be marked. + * with one of the special names ".apple", ".help" or ".window". If it + * is, the entry that points to this menu will be marked. * * Results: * None. @@ -1216,7 +1216,7 @@ void TkpComputeStandardMenuGeometry( TkMenu *menuPtr) /* Structure describing menu. */ { - NSSize menuSize = [(NSMenu *)menuPtr->platformData size]; + NSSize menuSize; Tk_Font tkfont, menuFont; Tk_FontMetrics menuMetrics, entryMetrics, *fmPtr; int modifierCharWidth, menuModifierCharWidth; @@ -1227,10 +1227,14 @@ TkpComputeStandardMenuGeometry( TkMenuEntry *mePtr; int haveAccel = 0; - if (menuPtr->tkwin == NULL) { + /* + * Do nothing if this menu is a clone. + */ + if (menuPtr->tkwin == NULL || menuPtr->masterMenuPtr != menuPtr) { return; } - + + menuSize = [(NSMenu *)menuPtr->platformData size]; Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr, &borderWidth); Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->activeBorderWidthPtr, -- cgit v0.12 From d7ace80f3a43a83a2ebc55b16ff631aba32a4665 Mon Sep 17 00:00:00 2001 From: culler Date: Wed, 13 Feb 2019 03:34:15 +0000 Subject: Fix bug [b389dfcd8f]: Aqua miscalculates window position on secondary display --- macosx/tkMacOSXWindowEvent.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index c39f62b..42979db 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -75,12 +75,11 @@ extern NSString *NSWindowDidOrderOffScreenNotification; if (winPtr) { WmInfo *wmPtr = winPtr->wmInfoPtr; NSRect bounds = [w frame]; - NSRect screenRect = [[w screen] frame]; int x, y, width = -1, height = -1, flags = 0; int minY = 1 + [[NSApp mainMenu] menuBarHeight]; x = bounds.origin.x; - y = screenRect.size.height - (bounds.origin.y + bounds.size.height); + y = tkMacOSXZeroScreenHeight - (bounds.origin.y + bounds.size.height); if (winPtr->changes.x != x || winPtr->changes.y != y) { flags |= TK_LOCATION_CHANGED; } else { @@ -102,7 +101,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification; } /* - * Mac windows cannot go higher than the bottom of the menu bar. The + * Mac windows are not allowed to overlap the menu bar. The * Tk window manager can request that a window be drawn so that it * overlaps the menu bar, but it will actually be drawn immediately * below the menu bar. In such a case it saves a lot of trouble and @@ -682,7 +681,6 @@ TkGenWMConfigureEvent( if (flags & TK_LOCATION_CHANGED) { wmPtr->x = x; wmPtr->y = y; - //wmPtr->flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y); } if ((flags & TK_SIZE_CHANGED) && !(wmPtr->flags & WM_SYNC_PENDING) && ((width != Tk_Width(tkwin)) || (height != Tk_Height(tkwin)))) { -- cgit v0.12 From f0b015abf1cd2457689595d92c44b8993297d19b Mon Sep 17 00:00:00 2001 From: culler Date: Wed, 13 Feb 2019 15:49:19 +0000 Subject: Fix bug [2249e64bdc]: Some unixWm tests expect the impossible on Aqua --- macosx/tkMacOSXWindowEvent.c | 14 -------------- tests/unixWm.test | 39 +++++++++++++++++++++++++++------------ 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 42979db..7752780 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -100,20 +100,6 @@ extern NSString *NSWindowDidOrderOffScreenNotification; flags |= TK_MACOSX_HANDLE_EVENT_IMMEDIATELY; } - /* - * Mac windows are not allowed to overlap the menu bar. The - * Tk window manager can request that a window be drawn so that it - * overlaps the menu bar, but it will actually be drawn immediately - * below the menu bar. In such a case it saves a lot of trouble and - * causes no harm if we let Tk think that the window is located at the - * requested point. (Many of the the tests assume that this is the - * case, especially for windows with upper left corner at (0,0).) So - * we just tell a harmless white lie here. - */ - - if (y == minY && wmPtr->y < minY) { - y = wmPtr->y; - } TkGenWMConfigureEvent((Tk_Window) winPtr, x, y, width, height, flags); } diff --git a/tests/unixWm.test b/tests/unixWm.test index 12a2142..c147bbf 100644 --- a/tests/unixWm.test +++ b/tests/unixWm.test @@ -40,8 +40,23 @@ proc makeToplevels {} { } } +# On macOS windows are not allowed to overlap the menubar at the top +# of the screen. So tests which move a window and then check whether +# it got moved to the requested location should use a y coordinate +# larger than the height of the menubar (normally 23 pixels). + +if {[tk windowingsystem] eq "aqua"} { + set Y0 23 + set Y2 25 + set Y5 28 +} else { + set Y0 0 + set Y2 2 + set Y5 5 +} + set i 1 -foreach geom {+20+80 +80+20 +0+0} { +foreach geom "+23+80 +80+23 +0+$Y0" { destroy .t test unixWm-1.$i {initial window position} unix { toplevel .t -width 200 -height 150 @@ -67,7 +82,7 @@ update scan [wm geom .t] %dx%d+%d+%d width height x y set xerr [expr 150-$x] set yerr [expr 150-$y] -foreach geom {+20+80 +80+20 +0+0 -0-0 +0-0 -0+0 -10-5 -10+5 +10-5} { +foreach geom "+20+80 +80+23 +0+$Y0 -0-0 +0-0 -0+$Y0 -10-5 -10+$Y5 +10-5" { test unixWm-2.$i {moving window while mapped} unix { wm geom .t $geom update @@ -79,7 +94,7 @@ foreach geom {+20+80 +80+20 +0+0 -0-0 +0-0 -0+0 -10-5 -10+5 +10-5} { } set i 1 -foreach geom {+20+80 +80+20 +0+0 -0-0 +0-0 -0+0 -10-5 -10+5 +10-5} { +foreach geom "+20+80 +80+23 +0+$Y0 -0-0 +0-0 -0+$Y0 -10-5 -10+$Y5 +10-5" { test unixWm-3.$i {moving window while iconified} unix { wm iconify .t sleep 200 @@ -95,7 +110,7 @@ foreach geom {+20+80 +80+20 +0+0 -0-0 +0-0 -0+0 -10-5 -10+5 +10-5} { } set i 1 -foreach geom {+20+80 +100+40 +0+0} { +foreach geom "+20+80 +100+40 +0+$Y0" { test unixWm-4.$i {moving window while withdrawn} unix { wm withdraw .t sleep 200 @@ -179,27 +194,27 @@ test unixWm-5.7 {compounded state changes} {unix nonPortable} { destroy .t toplevel .t -width 200 -height 100 -wm geom .t +10+10 +wm geom .t +10+23 wm minsize .t 1 1 update test unixWm-6.1 {size changes} unix { .t config -width 180 -height 150 update wm geom .t -} 180x150+10+10 +} 180x150+10+23 test unixWm-6.2 {size changes} unix { wm geom .t 250x60 .t config -width 170 -height 140 update wm geom .t -} 250x60+10+10 +} 250x60+10+23 test unixWm-6.3 {size changes} unix { wm geom .t 250x60 .t config -width 170 -height 140 wm geom .t {} update wm geom .t -} 170x140+10+10 +} 170x140+10+23 test unixWm-6.4 {size changes} {unix nonPortable userInteraction} { wm minsize .t 1 1 update @@ -1357,14 +1372,14 @@ test unixWm-40.1 {Tk_SetGrid procedure, set grid dimensions before turning on gr test unixWm-40.2 {Tk_SetGrid procedure, turning on grid when dimensions already set} unix { destroy .t toplevel .t - wm geometry .t 200x100+0+0 + wm geometry .t 200x100+0+$Y0 listbox .t.l -height 20 -width 20 pack .t.l -fill both -expand 1 update .t.l configure -setgrid 1 update wm geometry .t -} {20x20+0+0} +} "20x20+0+$Y0" test unixWm-41.1 {ConfigureEvent procedure, internally generated size changes} unix { destroy .t @@ -1559,10 +1574,10 @@ test unixWm-44.8 {UpdateGeometryInfo procedure, computing position} unix { tkwait visibility .t wm overrideredirect .t 1 update - wm geometry .t -30+2 + wm geometry .t -30+$Y2 update list [winfo x .t] [winfo y .t] -} [list [expr [winfo screenwidth .t] - 110] 2] +} [list [expr [winfo screenwidth .t] - 110] $Y2] destroy .t test unixWm-44.9 {UpdateGeometryInfo procedure, updating fixed dimensions} {unix testwrapper} { -- cgit v0.12 From 4266bcfcf2a8caf18483c350a3139a69ac753402 Mon Sep 17 00:00:00 2001 From: culler Date: Wed, 13 Feb 2019 16:12:16 +0000 Subject: Two text tests also try to position a window with y = 0. Tweak these for Aqua. --- tests/text.test | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tests/text.test b/tests/text.test index aaddc2c..be25ca6 100644 --- a/tests/text.test +++ b/tests/text.test @@ -3474,6 +3474,12 @@ test text-14.18 {ConfigureText procedure} -constraints fonts -setup { # minimum size and it was interfering with the size requested by the -setgrid. # The "overrideredirect" gets rid of the titlebar so the toplevel can shrink # to the appropriate size. +# On macOS, however, there is no way to make the window overlap the menubar. +if {[tk windowingsystem] == "aqua"} { + set minY 23 +} else { + set minY 0 +} test text-14.19 {ConfigureText procedure} -setup { toplevel .top text .top.t -font {Courier -12} -borderwidth 2 -highlightthickness 2 @@ -3481,16 +3487,17 @@ test text-14.19 {ConfigureText procedure} -setup { .top.t configure -width 20 -height 10 -setgrid 1 wm overrideredirect .top 1 pack .top.t - wm geometry .top +0+0 + wm geometry .top +0+$minY update wm geometry .top } -cleanup { destroy .top -} -result {20x10+0+0} +} -result "20x10+0+$minY" # This test was failing on Windows because the title bar on .t was a certain # minimum size and it was interfering with the size requested by the -setgrid. # The "overrideredirect" gets rid of the titlebar so the toplevel can shrink # to the appropriate size. +# On macOS we again use minY as a workaround. test text-14.20 {ConfigureText procedure} -setup { toplevel .top text .top.t -font {Courier -12} -borderwidth 2 -highlightthickness 2 @@ -3498,7 +3505,7 @@ test text-14.20 {ConfigureText procedure} -setup { .top.t configure -width 20 -height 10 -setgrid 1 wm overrideredirect .top 1 pack .top.t - wm geometry .top +0+0 + wm geometry .top +0+$minY update set result [wm geometry .top] wm geometry .top 15x8 @@ -3509,7 +3516,7 @@ test text-14.20 {ConfigureText procedure} -setup { lappend result [wm geometry .top] } -cleanup { destroy .top -} -result {20x10+0+0 15x8+0+0 15x8+0+0} +} -result "20x10+0+$minY 15x8+0+$minY 15x8+0+$minY" test text-15.1 {TextWorldChanged procedure, spacing options} -constraints { -- cgit v0.12 From 467268bf38ec0cab6e8c5cc66e44f6953f13b684 Mon Sep 17 00:00:00 2001 From: culler Date: Wed, 13 Feb 2019 21:32:46 +0000 Subject: Remove a missed unused variable. --- macosx/tkMacOSXWindowEvent.c | 1 - 1 file changed, 1 deletion(-) diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 7752780..212381e 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -76,7 +76,6 @@ extern NSString *NSWindowDidOrderOffScreenNotification; WmInfo *wmPtr = winPtr->wmInfoPtr; NSRect bounds = [w frame]; int x, y, width = -1, height = -1, flags = 0; - int minY = 1 + [[NSApp mainMenu] menuBarHeight]; x = bounds.origin.x; y = tkMacOSXZeroScreenHeight - (bounds.origin.y + bounds.size.height); -- cgit v0.12 From 26f086b4be1a8a8a559d080ece2f257b19763c17 Mon Sep 17 00:00:00 2001 From: culler Date: Mon, 18 Feb 2019 18:48:45 +0000 Subject: Fix bug [56a1823c73]: Aqua toplevels can fail to appear on screen. --- macosx/tkMacOSXInit.c | 10 ++++++++++ macosx/tkMacOSXSubwindows.c | 24 +++++++++++++++++------- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c index 9d4d487..e1d56fa 100644 --- a/macosx/tkMacOSXInit.c +++ b/macosx/tkMacOSXInit.c @@ -122,7 +122,17 @@ static char scriptPath[PATH_MAX + 1] = ""; * method is called. Activating too early can cause the menu * bar to be unresponsive. */ + [NSApp activateIgnoringOtherApps: YES]; + + /* + * Process events to ensure that the root window is fully + * initialized. See ticket 56a1823c73. + */ + + [NSApp _lockAutoreleasePool]; + while (Tcl_DoOneEvent(TCL_WINDOW_EVENTS| TCL_DONT_WAIT)) {} + [NSApp _unlockAutoreleasePool]; } - (void) _setup: (Tcl_Interp *) interp diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c index 7bc807a..c3df4d4 100644 --- a/macosx/tkMacOSXSubwindows.c +++ b/macosx/tkMacOSXSubwindows.c @@ -149,6 +149,7 @@ XMapWindow( if (Tk_IsTopLevel(macWin->winPtr)) { if (!Tk_IsEmbedded(macWin->winPtr)) { NSWindow *win = TkMacOSXDrawableWindow(window); + /* * We want to activate Tk when a toplevel is mapped * but we must not supply YES here. This is because @@ -157,6 +158,7 @@ XMapWindow( * the app to activate too early can make the menu bar * unresponsive. */ + TkMacOSXApplyWindowAttributes(macWin->winPtr, win); [win setExcludedFromWindowsMenu:NO]; [NSApp activateIgnoringOtherApps:NO]; @@ -166,11 +168,22 @@ XMapWindow( } else { [win orderFrontRegardless]; } + + /* + * In some cases the toplevel will not be drawn unless we process + * all pending events now. See ticket 56a1823c73. + */ + + [NSApp _lockAutoreleasePool]; + while (Tcl_DoOneEvent(TCL_WINDOW_EVENTS| TCL_DONT_WAIT)) {} + [NSApp _unlockAutoreleasePool]; } else { + /* * Rebuild the container's clipping region and display * the window. */ + TkWindow *contWinPtr = TkpGetOtherWindow(macWin->winPtr); TkMacOSXInvalClipRgns((Tk_Window)contWinPtr); TkMacOSXInvalidateWindow(macWin, TK_PARENT_WINDOW); @@ -190,7 +203,9 @@ XMapWindow( event.xmap.event = window; event.xmap.override_redirect = macWin->winPtr->atts.override_redirect; Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + } else { + /* * Rebuild the parent's clipping region and display the window. * @@ -211,11 +226,10 @@ XMapWindow( NotifyVisibility(macWin->winPtr, &event); /* - * Make sure that subwindows get displayed. + * This seems to be needed to ensure that all subwindows get displayed. */ GenerateConfigureNotify(macWin->winPtr, 1); - } /* @@ -284,11 +298,7 @@ XUnmapWindow( if (!Tk_IsEmbedded(winPtr) && winPtr->wmInfoPtr->hints.initial_state!=IconicState) { NSWindow *win = TkMacOSXDrawableWindow(window); - - if ([win isVisible]) { - [[win parentWindow] removeChildWindow:win]; - [win orderOut:NSApp]; - } + [win orderOut:nil]; } TkMacOSXInvalClipRgns((Tk_Window) winPtr); -- cgit v0.12 From 1cef9274b60a299bef15c8ddc054701387f9d560 Mon Sep 17 00:00:00 2001 From: fvogel Date: Fri, 22 Feb 2019 18:50:23 +0000 Subject: Fix [30a0fc767a]: spelling error in a comment --- macosx/tkMacOSXSubwindows.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c index 7bc807a..35002a9 100644 --- a/macosx/tkMacOSXSubwindows.c +++ b/macosx/tkMacOSXSubwindows.c @@ -1314,7 +1314,7 @@ TkMacOSXWinCGBounds( * UpdateOffsets -- * * Updates the X & Y offsets of the given TkWindow from the TopLevel it is - * a decendant of. + * a descendant of. * * Results: * None. -- cgit v0.12 From 3d2e242f10eb499e845c3b3227040514748cc0de Mon Sep 17 00:00:00 2001 From: culler Date: Sat, 23 Feb 2019 05:44:41 +0000 Subject: Fix bug [9771ae0f0b]: In Aqua, deiconifying a transient of a withdrawn window can create a zombie --- macosx/tkMacOSXWm.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index ab5cd8d..67d6ecb 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -6871,7 +6871,6 @@ ApplyMasterOverrideChanges( TkDisplay *dispPtr = TkGetDisplayList(); TkWindow *masterWinPtr = (TkWindow *) Tk_IdToWindow(dispPtr->display, wmPtr->master); - if (masterWinPtr && masterWinPtr->window != None && TkMacOSXHostToplevelExists(masterWinPtr)) { NSWindow *masterMacWin = @@ -6882,8 +6881,20 @@ ApplyMasterOverrideChanges( if (parentWindow) { [parentWindow removeChildWindow:macWindow]; } - [masterMacWin addChildWindow:macWindow - ordered:NSWindowAbove]; + + /* + * A child NSWindow retains its relative position with + * respect to the parent when the parent is moved. This is + * pointless if the parent is offscreen, and adding a child + * to an offscreen window causes the parent to be displayed + * as a zombie. So we should only do this if the parent is + * visible. + */ + + if ([masterMacWin isVisible]) { + [masterMacWin addChildWindow:macWindow + ordered:NSWindowAbove]; + } if (wmPtr->flags & WM_TOPMOST) { [macWindow setLevel:kCGUtilityWindowLevel]; } -- cgit v0.12 From 8f55c5985d13b4b7857066df9cd2ac55f9dc14ef Mon Sep 17 00:00:00 2001 From: culler Date: Wed, 27 Feb 2019 23:22:36 +0000 Subject: Adding 1 character fixes two of the three crashes reported in ticket [1951abf33d] --- macosx/tkMacOSXWm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index 67d6ecb..31f745a 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -3646,7 +3646,7 @@ WmTransientCmd( Transient *transient = ckalloc(sizeof(Transient)); transient->winPtr = winPtr; transient->flags = 0; - transient->nextPtr = wmPtr->transientPtr; + transient->nextPtr = wmPtr2->transientPtr; wmPtr2->transientPtr = transient; /* -- cgit v0.12 From 33c0644d0f0db1639b351981459ed7a9e4d4270d Mon Sep 17 00:00:00 2001 From: culler Date: Thu, 28 Feb 2019 05:02:10 +0000 Subject: Make sure that we don't create cycles in the parent->child digraph even if there are cycles in the master->transient digraph. --- macosx/tkMacOSXWm.c | 62 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index 31f745a..c8e0445 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -6793,6 +6793,7 @@ ApplyMasterOverrideChanges( int oldFlags = wmPtr->flags; unsigned long styleMask; NSRect structureRect; + NSWindow *parentWindow; if (!macWindow && winPtr->window != None && TkMacOSXHostToplevelExists(winPtr)) { @@ -6833,7 +6834,6 @@ ApplyMasterOverrideChanges( } } if (macWindow) { - NSWindow *parentWindow = [macWindow parentWindow]; structureRect = [NSWindow frameRectForContentRect:NSZeroRect styleMask:styleMask]; @@ -6873,35 +6873,51 @@ ApplyMasterOverrideChanges( Tk_IdToWindow(dispPtr->display, wmPtr->master); if (masterWinPtr && masterWinPtr->window != None && TkMacOSXHostToplevelExists(masterWinPtr)) { - NSWindow *masterMacWin = - TkMacOSXDrawableWindow(masterWinPtr->window); + NSWindow *masterMacWin = TkMacOSXDrawableWindow(masterWinPtr->window); + + /* + * Try to add the transient window as a child window of the + * master. A child NSWindow retains its relative position with + * respect to the parent when the parent is moved. This is + * pointless if the parent is offscreen, and adding a child to + * an offscreen window causes the parent to be displayed as a + * zombie. So we only do this if the parent is visible. + */ + + if (masterMacWin && + [masterMacWin isVisible] && + (winPtr->flags & TK_MAPPED)) { - if (masterMacWin && masterMacWin != parentWindow && - (winPtr->flags & TK_MAPPED)) { - if (parentWindow) { - [parentWindow removeChildWindow:macWindow]; - } - /* - * A child NSWindow retains its relative position with - * respect to the parent when the parent is moved. This is - * pointless if the parent is offscreen, and adding a child - * to an offscreen window causes the parent to be displayed - * as a zombie. So we should only do this if the parent is - * visible. + * If the transient is already a child of some other window, + * remove it. */ + + parentWindow = [macWindow parentWindow]; + if (parentWindow && parentWindow != masterMacWin) { + [parentWindow removeChildWindow:macWindow]; + } - if ([masterMacWin isVisible]) { - [masterMacWin addChildWindow:macWindow - ordered:NSWindowAbove]; + /* + * To avoid cycles, if the master is a child of some + other window, remove it. + */ + parentWindow = [masterMacWin parentWindow]; + if (parentWindow) { + [parentWindow removeChildWindow:masterMacWin]; } - if (wmPtr->flags & WM_TOPMOST) { - [macWindow setLevel:kCGUtilityWindowLevel]; + [masterMacWin addChildWindow:macWindow + ordered:NSWindowAbove]; } - } } - } else if (parentWindow) { - [parentWindow removeChildWindow:macWindow]; + } else { + parentWindow = [macWindow parentWindow]; + if (parentWindow) { + [parentWindow removeChildWindow:macWindow]; + } + } + if (wmPtr->flags & WM_TOPMOST) { + [macWindow setLevel:kCGUtilityWindowLevel]; } ApplyWindowAttributeFlagChanges(winPtr, macWindow, oldAttributes, oldFlags, 0, 0); -- cgit v0.12 From 25cab35e68932b15367a751414207d51a502e687 Mon Sep 17 00:00:00 2001 From: culler Date: Thu, 28 Feb 2019 06:18:53 +0000 Subject: Remove some bloat from tkMacOSXWm.c. --- generic/tkInt.decls | 2 +- generic/tkIntPlatDecls.h | 4 +- macosx/tkMacOSXWm.c | 98 +++++++++++++++++------------------------------- macosx/tkMacOSXWm.h | 6 +-- 4 files changed, 38 insertions(+), 72 deletions(-) diff --git a/generic/tkInt.decls b/generic/tkInt.decls index d0b7678..a3e1f98 100644 --- a/generic/tkInt.decls +++ b/generic/tkInt.decls @@ -1009,7 +1009,7 @@ declare 47 aqua { Tk_Window TkMacOSXGetCapture(void) } declare 49 aqua { - Window TkGetTransientMaster(TkWindow *winPtr) + Tk_Window TkGetTransientMaster(TkWindow *winPtr) } declare 50 aqua { int TkGenerateButtonEvent(int x, int y, Window window, unsigned int state) diff --git a/generic/tkIntPlatDecls.h b/generic/tkIntPlatDecls.h index ded5ac5..26a5f46 100644 --- a/generic/tkIntPlatDecls.h +++ b/generic/tkIntPlatDecls.h @@ -243,7 +243,7 @@ EXTERN int TkpIsWindowFloating(void *window); EXTERN Tk_Window TkMacOSXGetCapture(void); /* Slot 48 is reserved */ /* 49 */ -EXTERN Window TkGetTransientMaster(TkWindow *winPtr); +EXTERN Tk_Window TkGetTransientMaster(TkWindow *winPtr); /* 50 */ EXTERN int TkGenerateButtonEvent(int x, int y, Window window, unsigned int state); @@ -392,7 +392,7 @@ typedef struct TkIntPlatStubs { int (*tkpIsWindowFloating) (void *window); /* 46 */ Tk_Window (*tkMacOSXGetCapture) (void); /* 47 */ void (*reserved48)(void); - Window (*tkGetTransientMaster) (TkWindow *winPtr); /* 49 */ + Tk_Window (*tkGetTransientMaster) (TkWindow *winPtr); /* 49 */ int (*tkGenerateButtonEvent) (int x, int y, Window window, unsigned int state); /* 50 */ void (*tkGenWMDestroyEvent) (Tk_Window tkwin); /* 51 */ void (*tkMacOSXSetDrawingEnabled) (TkWindow *winPtr, int flag); /* 52 */ diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index c8e0445..ecb4456 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -669,7 +669,7 @@ TkWmNewWindow( wmPtr->reparent = None; wmPtr->titleUid = NULL; wmPtr->iconName = NULL; - wmPtr->master = None; + wmPtr->master = NULL; wmPtr->hints.flags = InputHint | StateHint; wmPtr->hints.input = True; wmPtr->hints.initial_state = NormalState; @@ -679,7 +679,6 @@ TkWmNewWindow( wmPtr->hints.icon_mask = None; wmPtr->hints.window_group = None; wmPtr->leaderName = NULL; - wmPtr->masterWindowName = NULL; wmPtr->icon = NULL; wmPtr->iconFor = NULL; wmPtr->transientPtr = NULL; @@ -884,18 +883,16 @@ TkWmDeadWindow( TkWindow *winPtr) /* Top-level window that's being deleted. */ { WmInfo *wmPtr = winPtr->wmInfoPtr, *wmPtr2; - TkDisplay *dispPtr = TkGetDisplayList(); if (wmPtr == NULL) { return; } - - /* + + /* *If the dead window is a transient, remove it from the master's list. */ RemoveTransient(winPtr); - Tk_ManageGeometry((Tk_Window) winPtr, NULL, NULL); Tk_DeleteEventHandler((Tk_Window) winPtr, StructureNotifyMask, TopLevelEventProc, winPtr); @@ -911,9 +908,6 @@ TkWmDeadWindow( if (wmPtr->leaderName != NULL) { ckfree(wmPtr->leaderName); } - if (wmPtr->masterWindowName != NULL) { - ckfree(wmPtr->masterWindowName); - } if (wmPtr->icon != NULL) { wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr; wmPtr2->iconFor = NULL; @@ -942,17 +936,14 @@ TkWmDeadWindow( * If the dead window has a transient, remove references to it from * the transient. */ - + for (Transient *transientPtr = wmPtr->transientPtr; transientPtr != NULL; transientPtr = transientPtr->nextPtr) { TkWindow *winPtr2 = transientPtr->winPtr; - Window master = TkGetTransientMaster(winPtr2); - TkWindow *masterPtr = (TkWindow *)Tk_IdToWindow(dispPtr->display, master); + TkWindow *masterPtr = (TkWindow *)TkGetTransientMaster(winPtr2); if (masterPtr == winPtr) { wmPtr2 = winPtr2->wmInfoPtr; - wmPtr2->master = None; - ckfree(wmPtr2->masterWindowName); - wmPtr2->masterWindowName = NULL; + wmPtr2->master = NULL; } } @@ -1791,7 +1782,6 @@ WmDeiconifyCmd( { register WmInfo *wmPtr = winPtr->wmInfoPtr; NSWindow *win = TkMacOSXDrawableWindow(winPtr->window); - TkDisplay *dispPtr = TkGetDisplayList(); if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "window"); @@ -1830,17 +1820,16 @@ WmDeiconifyCmd( transientPtr != NULL; transientPtr = transientPtr->nextPtr) { TkWindow *winPtr2 = transientPtr->winPtr; WmInfo *wmPtr2 = winPtr2->wmInfoPtr; - Window master = TkGetTransientMaster(winPtr2); - TkWindow *masterPtr = (TkWindow *)Tk_IdToWindow(dispPtr->display, master); + TkWindow *masterPtr = (TkWindow *)TkGetTransientMaster(winPtr2); if (masterPtr == winPtr) { - if (!(wmPtr2->hints.initial_state == WithdrawnState && - (transientPtr->flags & WITHDRAWN_BY_MASTER) == 0)) { + if ((wmPtr2->hints.initial_state == WithdrawnState && + (transientPtr->flags & WITHDRAWN_BY_MASTER) != 0)) { TkpWmSetState(winPtr2, NormalState); transientPtr->flags &= ~WITHDRAWN_BY_MASTER; } } } - + return TCL_OK; } @@ -2327,7 +2316,6 @@ WmIconifyCmd( int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { - TkDisplay *dispPtr = TkGetDisplayList(); register WmInfo *wmPtr = winPtr->wmInfoPtr; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "window"); @@ -2341,7 +2329,7 @@ WmIconifyCmd( Tcl_SetErrorCode(interp, "TK", "WM", "ICONIFY", "OVERRIDE_REDIRECT", NULL); return TCL_ERROR; - } else if (wmPtr->master != None) { + } else if (wmPtr->master != NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "can't iconify \"%s\": it is a transient", winPtr->pathName)); Tcl_SetErrorCode(interp, "TK", "WM", "ICONIFY", "TRANSIENT", NULL); @@ -2373,8 +2361,7 @@ WmIconifyCmd( for (Transient *transientPtr = wmPtr->transientPtr; transientPtr != NULL; transientPtr = transientPtr->nextPtr) { TkWindow *winPtr2 = transientPtr->winPtr; - Window master = TkGetTransientMaster(winPtr2); - TkWindow *masterPtr = (TkWindow *)Tk_IdToWindow(dispPtr->display, master); + TkWindow *masterPtr = (TkWindow *)TkGetTransientMaster(winPtr2); if (masterPtr == winPtr && winPtr2->wmInfoPtr->hints.initial_state != WithdrawnState) { TkpWmSetState(winPtr2, WithdrawnState); @@ -3466,7 +3453,7 @@ WmStateCmd( "OVERRIDE_REDIRECT", NULL); return TCL_ERROR; } - if (wmPtr->master != None) { + if (wmPtr->master != NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "can't iconify \"%s\": it is a transient", winPtr->pathName)); @@ -3582,17 +3569,15 @@ WmTransientCmd( register WmInfo *wmPtr = winPtr->wmInfoPtr; Tk_Window master; WmInfo *wmPtr2; - char *masterWindowName; - int length; if ((objc != 3) && (objc != 4)) { Tcl_WrongNumArgs(interp, 2, objv, "window ?master?"); return TCL_ERROR; } if (objc == 3) { - if (wmPtr->master != None) { + if (wmPtr->master != NULL) { Tcl_SetObjResult(interp, - Tcl_NewStringObj(wmPtr->masterWindowName, -1)); + Tcl_NewStringObj(Tk_PathName(wmPtr->master), -1)); } return TCL_OK; } @@ -3648,7 +3633,7 @@ WmTransientCmd( transient->flags = 0; transient->nextPtr = wmPtr2->transientPtr; wmPtr2->transientPtr = transient; - + /* * If the master is withdrawn or iconic then withdraw the transient. */ @@ -3660,14 +3645,7 @@ WmTransientCmd( transient->flags |= WITHDRAWN_BY_MASTER; } - wmPtr->master = Tk_WindowId(masterPtr); - masterWindowName = masterPtr->pathName; - length = strlen(masterWindowName); - if (wmPtr->masterWindowName != NULL) { - ckfree(wmPtr->masterWindowName); - } - wmPtr->masterWindowName = ckalloc(length+1); - strcpy(wmPtr->masterWindowName, masterWindowName); + wmPtr->master = (Tk_Window)masterPtr; } ApplyMasterOverrideChanges(winPtr, NULL); return TCL_OK; @@ -3697,21 +3675,16 @@ RemoveTransient( TkWindow *winPtr) { WmInfo *wmPtr = winPtr->wmInfoPtr, *wmPtr2; - TkDisplay *dispPtr = TkGetDisplayList(); TkWindow *masterPtr; - if (wmPtr == NULL || wmPtr->master == None) { + if (wmPtr == NULL || wmPtr->master == NULL) { return; } - masterPtr = (TkWindow*)Tk_IdToWindow(dispPtr->display, wmPtr->master); + masterPtr = (TkWindow*)wmPtr->master; wmPtr2 = masterPtr->wmInfoPtr; if (wmPtr2 == NULL) { return; } - wmPtr->master = None; - if (wmPtr->masterWindowName != NULL) { - ckfree(wmPtr->masterWindowName); - } - wmPtr->masterWindowName = NULL; + wmPtr->master = NULL; Transient *temp, *cursor = wmPtr2->transientPtr; if (cursor->winPtr == winPtr) { temp = cursor->nextPtr; @@ -3769,9 +3742,8 @@ WmWithdrawCmd( } TkpWmSetState(winPtr, WithdrawnState); - + NSWindow *win = TkMacOSXDrawableWindow(winPtr->window); - TkDisplay *dispPtr = TkGetDisplayList(); [win orderOut:nil]; [win setExcludedFromWindowsMenu:YES]; @@ -3781,8 +3753,7 @@ WmWithdrawCmd( for (Transient *transientPtr = wmPtr->transientPtr; transientPtr != NULL; transientPtr = transientPtr->nextPtr) { TkWindow *winPtr2 = transientPtr->winPtr; - Window master = TkGetTransientMaster(winPtr2); - TkWindow *masterPtr = (TkWindow *)Tk_IdToWindow(dispPtr->display, master); + TkWindow *masterPtr = (TkWindow *)TkGetTransientMaster(winPtr2); if (masterPtr == winPtr && winPtr2->wmInfoPtr->hints.initial_state != WithdrawnState) { TkpWmSetState(winPtr2, WithdrawnState); @@ -5335,14 +5306,14 @@ TkSetWMName( *---------------------------------------------------------------------- */ -Window +Tk_Window TkGetTransientMaster( TkWindow *winPtr) { if (winPtr->wmInfoPtr != NULL) { - return winPtr->wmInfoPtr->master; + return (Tk_Window)winPtr->wmInfoPtr->master; } - return None; + return NULL; } /* @@ -6579,7 +6550,7 @@ TkMacOSXApplyWindowAttributes( { WmInfo *wmPtr = winPtr->wmInfoPtr; ApplyWindowAttributeFlagChanges(winPtr, macWindow, 0, 0, 0, 1); - if (wmPtr->master != None || winPtr->atts.override_redirect) { + if (wmPtr->master != NULL || winPtr->atts.override_redirect) { ApplyMasterOverrideChanges(winPtr, macWindow); } } @@ -6716,7 +6687,7 @@ ApplyWindowAttributeFlagChanges( */ if ((winPtr->atts.override_redirect) || - (wmPtr->master != None) || + (wmPtr->master != NULL) || (winPtr->wmInfoPtr->macClass == kHelpWindowClass)) { b |= (NSWindowCollectionBehaviorCanJoinAllSpaces | NSWindowCollectionBehaviorFullScreenAuxiliary); @@ -6852,7 +6823,7 @@ ApplyMasterOverrideChanges( if (wmPtr->hints.initial_state == NormalState) { [macWindow orderFront:nil]; } - if (wmPtr->master != None) { + if (wmPtr->master != NULL) { wmPtr->flags |= WM_TOPMOST; } else { wmPtr->flags &= ~WM_TOPMOST; @@ -6868,13 +6839,12 @@ ApplyMasterOverrideChanges( wmPtr->flags &= ~WM_TOPMOST; } if (wmPtr->master != None) { - TkDisplay *dispPtr = TkGetDisplayList(); - TkWindow *masterWinPtr = (TkWindow *) - Tk_IdToWindow(dispPtr->display, wmPtr->master); + TkWindow *masterWinPtr = (TkWindow *)wmPtr->master; if (masterWinPtr && masterWinPtr->window != None && TkMacOSXHostToplevelExists(masterWinPtr)) { - NSWindow *masterMacWin = TkMacOSXDrawableWindow(masterWinPtr->window); - + NSWindow *masterMacWin = TkMacOSXDrawableWindow( + masterWinPtr->window); + /* * Try to add the transient window as a child window of the * master. A child NSWindow retains its relative position with @@ -6892,13 +6862,13 @@ ApplyMasterOverrideChanges( * If the transient is already a child of some other window, * remove it. */ - + parentWindow = [macWindow parentWindow]; if (parentWindow && parentWindow != masterMacWin) { [parentWindow removeChildWindow:macWindow]; } - /* + /* * To avoid cycles, if the master is a child of some other window, remove it. */ diff --git a/macosx/tkMacOSXWm.h b/macosx/tkMacOSXWm.h index a7ea92c..5f07fe6 100644 --- a/macosx/tkMacOSXWm.h +++ b/macosx/tkMacOSXWm.h @@ -65,7 +65,7 @@ typedef struct TkWmInfo { Tk_Uid titleUid; /* Title to display in window caption. If NULL, * use name of widget. */ char *iconName; /* Name to display in icon. */ - Window master; /* Master window for TRANSIENT_FOR property, or + Tk_Window master; /* Master window for TRANSIENT_FOR property, or * None. */ XWMHints hints; /* Various pieces of information for window * manager. */ @@ -73,10 +73,6 @@ typedef struct TkWmInfo { * (corresponds to hints.window_group). * Malloc-ed. Note: this field doesn't get * updated if leader is destroyed. */ - char *masterWindowName; /* Path name of window specified as master in - * "wm transient" command, or NULL. Malloc-ed. - * Note: this field doesn't get updated if - * masterWindowName is destroyed. */ Tk_Window icon; /* Window to use as icon for this window, or * NULL. */ Tk_Window iconFor; /* Window for which this window is icon, or -- cgit v0.12 From 827393fdd0d40c400d800dbf3b042b48c8f3a692 Mon Sep 17 00:00:00 2001 From: culler Date: Thu, 28 Feb 2019 15:29:23 +0000 Subject: Fix bugs in the list management code for the record of transient windows. --- macosx/tkMacOSXWm.c | 51 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index ecb4456..599455d 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -3569,6 +3569,7 @@ WmTransientCmd( register WmInfo *wmPtr = winPtr->wmInfoPtr; Tk_Window master; WmInfo *wmPtr2; + Transient *transient; if ((objc != 3) && (objc != 4)) { Tcl_WrongNumArgs(interp, 2, objv, "window ?master?"); @@ -3625,14 +3626,19 @@ WmTransientCmd( } /* - * Add the transient to the master's list. + * Add the transient to the master's list, if it not already there. */ - - Transient *transient = ckalloc(sizeof(Transient)); - transient->winPtr = winPtr; - transient->flags = 0; - transient->nextPtr = wmPtr2->transientPtr; - wmPtr2->transientPtr = transient; + + for (transient = wmPtr2->transientPtr; + transient != NULL && transient->winPtr != winPtr; + transient = transient->nextPtr) {} + if (transient == NULL) { + transient = ckalloc(sizeof(Transient)); + transient->winPtr = winPtr; + transient->flags = 0; + transient->nextPtr = wmPtr2->transientPtr; + wmPtr2->transientPtr = transient; + } /* * If the master is withdrawn or iconic then withdraw the transient. @@ -3676,6 +3682,8 @@ RemoveTransient( { WmInfo *wmPtr = winPtr->wmInfoPtr, *wmPtr2; TkWindow *masterPtr; + Transient *T, *temp; + if (wmPtr == NULL || wmPtr->master == NULL) { return; } @@ -3685,18 +3693,23 @@ RemoveTransient( return; } wmPtr->master = NULL; - Transient *temp, *cursor = wmPtr2->transientPtr; - if (cursor->winPtr == winPtr) { - temp = cursor->nextPtr; - ckfree(cursor); - cursor = temp; - masterPtr->wmInfoPtr->transientPtr = cursor; - } - while (cursor != NULL) { - if (cursor->winPtr == winPtr) { - temp = cursor->nextPtr; - ckfree(cursor); - cursor = temp; + T = wmPtr2->transientPtr; + while (T != NULL) { + if (T->winPtr != winPtr) { + break; + } + temp = T->nextPtr; + ckfree(T); + T = temp; + } + wmPtr2->transientPtr = T; + while (T != NULL) { + if (T->nextPtr && T->nextPtr->winPtr == winPtr) { + temp = T->nextPtr; + T->nextPtr = temp->nextPtr; + ckfree(temp); + } else { + T = T->nextPtr; } } } -- cgit v0.12 From 403f01fa032b477c866cb88915f0604d9d9d0dac Mon Sep 17 00:00:00 2001 From: culler Date: Fri, 1 Mar 2019 15:28:48 +0000 Subject: Make it be an error to create a transient/master cycle on Aqua. Other platforms will be handled in separate check-ins. --- doc/wm.n | 29 +++++++++++++++-------------- macosx/tkMacOSXWm.c | 25 +++++++++++-------------- tests/wm.test | 14 ++++++++++++-- 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/doc/wm.n b/doc/wm.n index e7aedf7..a137d06 100644 --- a/doc/wm.n +++ b/doc/wm.n @@ -710,20 +710,21 @@ specified then the command returns the current title for the .TP \fBwm transient \fIwindow\fR ?\fImaster\fR? . -If \fImaster\fR is specified, then the window manager is informed -that \fIwindow\fR is a transient window (e.g. pull-down menu) working -on behalf of \fImaster\fR (where \fImaster\fR is the -path name for a top-level window). If \fImaster\fR -is specified as an empty string then \fIwindow\fR is marked as not -being a transient window any more. Otherwise the command -returns the path name of \fIwindow\fR's current master, or an -empty string if \fIwindow\fR is not currently a transient window. -A transient window will mirror state changes in the master and -inherit the state of the master when initially mapped. It is an -error to attempt to make a window a transient of itself. -The window manager may also decorate a transient window differently, removing -some features normally present (e.g., minimize and maximize buttons) though -this is entirely at the discretion of the window manager. +If \fImaster\fR is specified, then the window manager is informed that +\fIwindow\fR is a transient window (e.g. pull-down menu) working on +behalf of \fImaster\fR (where \fImaster\fR is the path name for a +top-level window). If \fImaster\fR is specified as an empty string +then \fIwindow\fR is marked as not being a transient window any more. +Otherwise the command returns the path name of \fIwindow\fR's current +master, or an empty string if \fIwindow\fR is not currently a +transient window. A transient window will mirror state changes in the +master and inherit the state of the master when initially mapped. The +directed graph with an edge from each transient to its master must be +acyclic. In particular, it is an error to attempt to make a window a +transient of itself. The window manager may also decorate a transient +window differently, removing some features normally present (e.g., +minimize and maximize buttons) though this is entirely at the +discretion of the window manager. .TP \fBwm withdraw \fIwindow\fR . diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c index 599455d..a1fbbde 100644 --- a/macosx/tkMacOSXWm.c +++ b/macosx/tkMacOSXWm.c @@ -3568,6 +3568,7 @@ WmTransientCmd( { register WmInfo *wmPtr = winPtr->wmInfoPtr; Tk_Window master; + TkWindow *masterPtr, *w; WmInfo *wmPtr2; Transient *transient; @@ -3589,7 +3590,7 @@ WmTransientCmd( if (TkGetWindowFromObj(interp, tkwin, objv[3], &master) != TCL_OK) { return TCL_ERROR; } - TkWindow *masterPtr = (TkWindow*) master; + masterPtr = (TkWindow*) master; while (!Tk_TopWinHierarchy(masterPtr)) { /* @@ -3618,11 +3619,15 @@ WmTransientCmd( return TCL_ERROR; } - if (masterPtr == winPtr) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "can't make \"%s\" its own master", Tk_PathName(winPtr))); - Tcl_SetErrorCode(interp, "TK", "WM", "TRANSIENT", "SELF", NULL); - return TCL_ERROR; + for (w = masterPtr; w != NULL && w->wmInfoPtr != NULL; + w = (TkWindow *)w->wmInfoPtr->master) { + if (w == winPtr) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "setting \"%s\" as master creates a transient/master cycle", + Tk_PathName(masterPtr))); + Tcl_SetErrorCode(interp, "TK", "WM", "TRANSIENT", "SELF", NULL); + return TCL_ERROR; + } } /* @@ -6881,14 +6886,6 @@ ApplyMasterOverrideChanges( [parentWindow removeChildWindow:macWindow]; } - /* - * To avoid cycles, if the master is a child of some - other window, remove it. - */ - parentWindow = [masterMacWin parentWindow]; - if (parentWindow) { - [parentWindow removeChildWindow:masterMacWin]; - } [masterMacWin addChildWindow:macWindow ordered:NSWindowAbove]; } diff --git a/tests/wm.test b/tests/wm.test index 7b81985..c2bc385 100644 --- a/tests/wm.test +++ b/tests/wm.test @@ -1640,14 +1640,24 @@ test wm-transient-1.7 {usage} -returnCodes error -body { wm transient .master .master } -cleanup { deleteWindows -} -result {can't make ".master" its own master} +} -result {setting ".master" as master creates a transient/master cycle} test wm-transient-1.8 {usage} -returnCodes error -body { + toplevel .t1 + toplevel .t2 + toplevel .t3 + wm transient .t2 .t1 + wm transient .t3 .t2 + wm transient .t1 .t3 +} -cleanup { + deleteWindows +} -result {setting ".t3" as master creates a transient/master cycle} +test wm-transient-1.9 {usage} -returnCodes error -body { toplevel .master frame .master.f wm transient .master .master.f } -cleanup { deleteWindows -} -result {can't make ".master" its own master} +} -result {setting ".master" as master creates a transient/master cycle} test wm-transient-2.1 {basic get/set of master} -setup { set results [list] -- cgit v0.12 From ec1cf983bd80cc43701c88134d9bd94131e6100f Mon Sep 17 00:00:00 2001 From: culler Date: Fri, 1 Mar 2019 15:46:38 +0000 Subject: Make it be an error to create a transient/master cycle on unix. --- unix/tkUnixWm.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/unix/tkUnixWm.c b/unix/tkUnixWm.c index 8944ecc..9ed9082 100644 --- a/unix/tkUnixWm.c +++ b/unix/tkUnixWm.c @@ -3524,7 +3524,7 @@ WmTransientCmd( Tcl_Obj *const objv[]) /* Argument objects. */ { register WmInfo *wmPtr = winPtr->wmInfoPtr; - TkWindow *masterPtr = wmPtr->masterPtr; + TkWindow *masterPtr = wmPtr->masterPtr, *w; WmInfo *wmPtr2; if ((objc != 3) && (objc != 4)) { @@ -3593,12 +3593,18 @@ WmTransientCmd( return TCL_ERROR; } - if (masterPtr == winPtr) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "can't make \"%s\" its own master", Tk_PathName(winPtr))); - Tcl_SetErrorCode(interp, "TK", "WM", "TRANSIENT", "SELF", NULL); - return TCL_ERROR; - } else if (masterPtr != wmPtr->masterPtr) { + for (w = masterPtr; w != NULL && w->wmInfoPtr != NULL; + w = (TkWindow *)w->wmInfoPtr->masterPtr) { + if (w == winPtr) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "setting \"%s\" as master creates a transient/master cycle", + Tk_PathName(masterPtr))); + Tcl_SetErrorCode(interp, "TK", "WM", "TRANSIENT", "SELF", NULL); + return TCL_ERROR; + } + } + + if (masterPtr != wmPtr->masterPtr) { /* * Remove old master map/unmap binding before setting the new * master. The event handler will ensure that transient states -- cgit v0.12 From 4acf3a1da92f5ef0bc2dbe3ac5fa457ae0ae2836 Mon Sep 17 00:00:00 2001 From: culler Date: Fri, 1 Mar 2019 16:04:19 +0000 Subject: Make it be an error to create a transient/master cycle on Windows. --- win/tkWinWm.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/win/tkWinWm.c b/win/tkWinWm.c index 97cf255..5bb23d1 100644 --- a/win/tkWinWm.c +++ b/win/tkWinWm.c @@ -5526,7 +5526,7 @@ WmTransientCmd( Tcl_Obj *const objv[]) /* Argument objects. */ { register WmInfo *wmPtr = winPtr->wmInfoPtr; - TkWindow *masterPtr = wmPtr->masterPtr, **masterPtrPtr = &masterPtr; + TkWindow *masterPtr = wmPtr->masterPtr, **masterPtrPtr = &masterPtr, *w; WmInfo *wmPtr2; if ((objc != 3) && (objc != 4)) { @@ -5584,13 +5584,17 @@ WmTransientCmd( Tcl_SetErrorCode(interp, "TK", "WM", "TRANSIENT", "ICON", NULL); return TCL_ERROR; } - - if (masterPtr == winPtr) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "can't make \"%s\" its own master", Tk_PathName(winPtr))); - Tcl_SetErrorCode(interp, "TK", "WM", "TRANSIENT", "SELF", NULL); - return TCL_ERROR; - } else if (masterPtr != wmPtr->masterPtr) { + for (w = masterPtr; w != NULL && w->wmInfoPtr != NULL; + w = (TkWindow *)w->wmInfoPtr->masterPtr) { + if (w == winPtr) { + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "setting \"%s\" as master creates a transient/master cycle", + Tk_PathName(masterPtr))); + Tcl_SetErrorCode(interp, "TK", "WM", "TRANSIENT", "SELF", NULL); + return TCL_ERROR; + } + } + if (masterPtr != wmPtr->masterPtr) { /* * Remove old master map/unmap binding before setting the new * master. The event handler will ensure that transient states -- cgit v0.12 From ffc8760419eff5493bbd2be5f8d8e585c1e8d95c Mon Sep 17 00:00:00 2001 From: culler Date: Sun, 3 Mar 2019 17:04:13 +0000 Subject: Increase the size of the ring buffer for Aqua, and modify bgerror so it doesn't try (and fail) to post a dialog inside [NSView drawRect]. --- generic/tkBind.c | 2 +- library/bgerror.tcl | 17 +++++++++----- macosx/tkMacOSXKeyEvent.c | 56 +++------------------------------------------ macosx/tkMacOSXMouseEvent.c | 51 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 60 deletions(-) diff --git a/generic/tkBind.c b/generic/tkBind.c index 70f10aa..e0971ba 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -84,7 +84,7 @@ typedef union { */ #ifndef TK_MAC_OSX - #define EVENT_BUFFER_SIZE 45 + #define EVENT_BUFFER_SIZE 90 #else #define EVENT_BUFFER_SIZE 30 #endif diff --git a/library/bgerror.tcl b/library/bgerror.tcl index b15387e..574ad8b 100644 --- a/library/bgerror.tcl +++ b/library/bgerror.tcl @@ -97,7 +97,7 @@ proc ::tk::dialog::error::ReturnInDetails w { # Arguments: # err - The error message. # -proc ::tk::dialog::error::bgerror err { +proc ::tk::dialog::error::bgerror {err {flag 1}} { global errorInfo variable button @@ -106,15 +106,20 @@ proc ::tk::dialog::error::bgerror err { set ret [catch {::tkerror $err} msg]; if {$ret != 1} {return -code $ret $msg} - # Ok the application's tkerror either failed or was not found - # we use the default dialog then : + # The application's tkerror either failed or was not found + # so we use the default dialog. But on Aqua we cannot display + # the dialog if the background error occurs in an idle task + # being processed inside of [NSView drawRect]. In that case + # we post the dialog as an after task instead. set windowingsystem [tk windowingsystem] if {$windowingsystem eq "aqua"} { - set ok [mc Ok] - } else { - set ok [mc OK] + if $flag { + after 500 [list bgerror "$err" 0] + return + } } + set ok [mc OK] # Truncate the message if it is too wide (>maxLine characters) or # too tall (>4 lines). Truncation occurs at the first point at # which one of those conditions is met. diff --git a/macosx/tkMacOSXKeyEvent.c b/macosx/tkMacOSXKeyEvent.c index 3327f0a..543e7ab 100644 --- a/macosx/tkMacOSXKeyEvent.c +++ b/macosx/tkMacOSXKeyEvent.c @@ -24,9 +24,6 @@ */ #define NS_KEYLOG 0 - -static Tk_Window grabWinPtr = NULL; - /* Current grab window, NULL if no grab. */ static Tk_Window keyboardGrabWinPtr = NULL; /* Current keyboard grab window. */ static NSWindow *keyboardGrabNSWindow = nil; @@ -500,11 +497,12 @@ XGrabKeyboard( Time time) { keyboardGrabWinPtr = Tk_IdToWindow(display, grab_window); - if (keyboardGrabWinPtr && grabWinPtr) { + TkWindow *captureWinPtr = (TkWindow *)TkMacOSXGetCapture(); + if (keyboardGrabWinPtr && captureWinPtr) { NSWindow *w = TkMacOSXDrawableWindow(grab_window); MacDrawable *macWin = (MacDrawable *) grab_window; - if (w && macWin->toplevel->winPtr == (TkWindow*) grabWinPtr) { + if (w && macWin->toplevel->winPtr == (TkWindow*) captureWinPtr) { if (modalSession) { Tcl_Panic("XGrabKeyboard: already grabbed"); } @@ -551,26 +549,6 @@ XUngrabKeyboard( /* *---------------------------------------------------------------------- * - * TkMacOSXGetCapture -- - * - * Results: - * Returns the current grab window - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Tk_Window -TkMacOSXGetCapture(void) -{ - return grabWinPtr; -} - -/* - *---------------------------------------------------------------------- - * * TkMacOSXGetModalSession -- * * Results: @@ -591,34 +569,6 @@ TkMacOSXGetModalSession(void) /* *---------------------------------------------------------------------- * - * TkpSetCapture -- - * - * This function captures the mouse so that all future events will be - * reported to this window, even if the mouse is outside the window. If - * the specified window is NULL, then the mouse is released. - * - * Results: - * None. - * - * Side effects: - * Sets the capture flag and captures the mouse. - * - *---------------------------------------------------------------------- - */ - -void -TkpSetCapture( - TkWindow *winPtr) /* Capture window, or NULL. */ -{ - while (winPtr && !Tk_IsTopLevel(winPtr)) { - winPtr = winPtr->parentPtr; - } - grabWinPtr = (Tk_Window) winPtr; -} - -/* - *---------------------------------------------------------------------- - * * Tk_SetCaretPos -- * * This enables correct placement of the XIM caret. This is called by diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c index 7b83679..2d5d152 100644 --- a/macosx/tkMacOSXMouseEvent.c +++ b/macosx/tkMacOSXMouseEvent.c @@ -24,6 +24,7 @@ typedef struct { Point global; Point local; } MouseEventData; +static Tk_Window captureWinPtr = NULL; /* Current capture window; may be NULL. */ static int GenerateButtonEvent(MouseEventData *medPtr); static unsigned int ButtonModifiers2State(UInt32 buttonState, @@ -581,6 +582,56 @@ TkpWarpPointer( } /* + *---------------------------------------------------------------------- + * + * TkpSetCapture -- + * + * This function captures the mouse so that all future events will be + * reported to this window, even if the mouse is outside the window. If + * the specified window is NULL, then the mouse is released. + * + * Results: + * None. + * + * Side effects: + * Sets the capture flag and captures the mouse. + * + *---------------------------------------------------------------------- + */ + +void +TkpSetCapture( + TkWindow *winPtr) /* Capture window, or NULL. */ +{ + while (winPtr && !Tk_IsTopLevel(winPtr)) { + winPtr = winPtr->parentPtr; + } + captureWinPtr = (Tk_Window) winPtr; +} + +/* + *---------------------------------------------------------------------- + * + * TkMacOSXGetCapture -- + * + * Results: + * Returns the current grab window + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Tk_Window +TkMacOSXGetCapture(void) +{ + return captureWinPtr; +} + + + +/* * Local Variables: * mode: objc * c-basic-offset: 4 -- cgit v0.12 From 4e356bee29f77e86babcc504bb647ff078d55c3e Mon Sep 17 00:00:00 2001 From: culler Date: Mon, 4 Mar 2019 23:30:15 +0000 Subject: Fix bug [609e0045f5]: Aqua scrollwheel events have incorrect mouse coordinates. --- macosx/tkMacOSXMouseEvent.c | 115 ++++++++++++++++++++++++++++++++------------ 1 file changed, 85 insertions(+), 30 deletions(-) diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c index 2d5d152..38adc8c 100644 --- a/macosx/tkMacOSXMouseEvent.c +++ b/macosx/tkMacOSXMouseEvent.c @@ -48,15 +48,17 @@ enum { @implementation TKApplication(TKMouseEvent) - (NSEvent *) tkProcessMouseEvent: (NSEvent *) theEvent { -#ifdef TK_MAC_DEBUG_EVENTS - TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, theEvent); -#endif NSWindow* eventWindow = [theEvent window]; NSEventType eventType = [theEvent type]; + TkWindow *winPtr, *grabWinPtr; + Tk_Window tkwin; #if 0 NSTrackingArea *trackingArea = nil; NSInteger eventNumber, clickCount, buttonNumber; #endif +#ifdef TK_MAC_DEBUG_EVENTS + TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, theEvent); +#endif switch (eventType) { case NSMouseEntered: case NSMouseExited: @@ -88,52 +90,95 @@ enum { [_windowWithMouse retain]; } - /* Create an Xevent to add to the Tk queue. */ + /* + * Compute the mouse position in Tk screen coordinates (global) and in + * the Tk coordinates of its containing Tk Window. + */ + NSPoint global, local = [theEvent locationInWindow]; - if (eventWindow) { /* local will be in window coordinates. */ + + /* + * If the event has no NSWindow, try using the cached NSWindow from the + * last mouse event. + */ + + if (eventWindow == NULL) { + eventWindow == _windowWithMouse; + } + if (eventWindow) { + + /* + * Set the local mouse position to its NSWindow flipped coordinates, + * with the origin at top left, and the global mouse position to the + * flipped screen coordinates. + */ + global = [eventWindow tkConvertPointToScreen: local]; local.y = [eventWindow frame].size.height - local.y; global.y = tkMacOSXZeroScreenHeight - global.y; - } else { /* local will be in screen coordinates. */ - if (_windowWithMouse ) { - eventWindow = _windowWithMouse; - global = local; - local = [eventWindow tkConvertPointFromScreen: local]; - local.y = [eventWindow frame].size.height - local.y; - global.y = tkMacOSXZeroScreenHeight - global.y; - } else { /* We have no window. Use the screen???*/ - local.y = tkMacOSXZeroScreenHeight - local.y; - global = local; - } + + } else { + + /* + * As a last resort, with no NSWindow to work witn, set both local and + * global to the screen coordinates. + */ + + local.y = tkMacOSXZeroScreenHeight - local.y; + global = local; } - TkWindow *winPtr = TkMacOSXGetTkWindow(eventWindow); - Tk_Window tkwin = (Tk_Window) winPtr; + /* + * Find the toplevel which corresponds to the event NSWindow. + */ - 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; - } - } else { + winPtr = TkMacOSXGetTkWindow(eventWindow); + if (winPtr == NULL) { tkwin = TkMacOSXGetCapture(); + winPtr = (TkWindow *)tkwin; + } else { + tkwin = (Tk_Window) winPtr; } if (!tkwin) { TkMacOSXDbgMsg("tkwin == NULL"); return theEvent; /* Give up. No window for this event. */ - } else { - winPtr = (TkWindow *)tkwin; } + /* + * If another toplevel has a grab, we ignore the event. + */ + + grabWinPtr = winPtr->dispPtr->grabWinPtr; + if (grabWinPtr && + grabWinPtr != winPtr && + !winPtr->dispPtr->grabFlags && /* this means the grab is local. */ + grabWinPtr->mainPtr == winPtr->mainPtr) { + return theEvent; + } + + /* + * Convert local from NSWindow flipped coordinates to the toplevel's + * coordinates. + */ + 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.) + */ + int win_x, win_y; tkwin = Tk_TopCoordsToWindow(tkwin, local.x, local.y, &win_x, &win_y); + local.x = win_x; + local.y = win_y; + /* + * Generate an XEvent for this mouse event. + */ + unsigned int state = 0; NSInteger button = [theEvent buttonNumber]; EventRef eventRef = (EventRef)[theEvent eventRef]; @@ -182,11 +227,21 @@ enum { } if (eventType != NSScrollWheel) { + + /* + * For normal mouse events, Tk_UpdatePointer will send the XEvent. + */ + #ifdef TK_MAC_DEBUG_EVENTS TKLog(@"UpdatePointer %p x %f.0 y %f.0 %d", tkwin, global.x, global.y, state); #endif Tk_UpdatePointer(tkwin, global.x, global.y, state); - } else { /* handle scroll wheel event */ + } else { + + /* + * For scroll wheel events we need to send the XEvent here. + */ + CGFloat delta; int coarseDelta; XEvent xEvent; -- cgit v0.12 From 63f73c5f9542e461a6daa5e95cb7fd16e161f3b6 Mon Sep 17 00:00:00 2001 From: apnadkarni Date: Wed, 6 Mar 2019 04:54:35 +0000 Subject: Copy PDBs to installation if option PDBS is given during install --- win/makefile.vc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/win/makefile.vc b/win/makefile.vc index 947e167..1e44bff 100644 --- a/win/makefile.vc +++ b/win/makefile.vc @@ -336,6 +336,9 @@ all: release $(CAT32) core: setup $(TKSTUBLIB) $(TKLIB) cwish: $(WISHC) install: install-binaries install-libraries install-docs +!if $(SYMBOLS) +install: install-pdbs +!endif tktest: setup $(TKTEST) $(CAT32) setup: default-setup @@ -516,6 +519,11 @@ install-docs: !endif # "emacs font-lock highlighting fix +install-pdbs: + @echo Installing debug symbols + @$(CPY) "$(OUT_DIR)\*.pdb" "$(BIN_INSTALL_DIR)\" +# "emacs font-lock highlighting fix + #--------------------------------------------------------------------- # Special case object file targets #--------------------------------------------------------------------- -- cgit v0.12 From 804f3a603296dff36b4c678e180edb2ca69f6eb3 Mon Sep 17 00:00:00 2001 From: fvogel Date: Thu, 14 Mar 2019 20:59:55 +0000 Subject: Fix typo --- macosx/tkMacOSXMouseEvent.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c index 38adc8c..9a1988d 100644 --- a/macosx/tkMacOSXMouseEvent.c +++ b/macosx/tkMacOSXMouseEvent.c @@ -94,7 +94,7 @@ enum { * Compute the mouse position in Tk screen coordinates (global) and in * the Tk coordinates of its containing Tk Window. */ - + NSPoint global, local = [theEvent locationInWindow]; /* @@ -106,7 +106,7 @@ enum { eventWindow == _windowWithMouse; } if (eventWindow) { - + /* * Set the local mouse position to its NSWindow flipped coordinates, * with the origin at top left, and the global mouse position to the @@ -120,7 +120,7 @@ enum { } else { /* - * As a last resort, with no NSWindow to work witn, set both local and + * As a last resort, with no NSWindow to work with, set both local and * global to the screen coordinates. */ @@ -160,7 +160,7 @@ enum { * Convert local from NSWindow flipped coordinates to the toplevel's * coordinates. */ - + local.x -= winPtr->wmInfoPtr->xInParent; local.y -= winPtr->wmInfoPtr->yInParent; @@ -178,7 +178,7 @@ enum { /* * Generate an XEvent for this mouse event. */ - + unsigned int state = 0; NSInteger button = [theEvent buttonNumber]; EventRef eventRef = (EventRef)[theEvent eventRef]; -- cgit v0.12 From 5d3696a737a0d6cbfc1c3eda16547cff2f9078d7 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 15 Mar 2019 20:24:47 +0000 Subject: Make Tk run on win32/win64 using -DTCL_UTF_MAX=6. Adapted from androwish. --- generic/tkFocus.c | 6 +++--- generic/tkImgGIF.c | 2 +- generic/tkMain.c | 39 ++++++++++++++++++++++++++------------- unix/tkUnixMenu.c | 6 +----- win/tkWinDialog.c | 7 ++----- win/tkWinMenu.c | 16 +++++++++++----- win/ttkWinXPTheme.c | 53 +++++++++++++++++++++++++++++++++++++---------------- 7 files changed, 81 insertions(+), 48 deletions(-) diff --git a/generic/tkFocus.c b/generic/tkFocus.c index c621bf9..eae981e 100644 --- a/generic/tkFocus.c +++ b/generic/tkFocus.c @@ -630,7 +630,7 @@ TkSetFocusWin( tlFocusPtr->focusWinPtr = winPtr; if (topLevelPtr->flags & TK_EMBEDDED) { - + /* * We are assigning focus to an embedded toplevel. The platform * specific function TkpClaimFocus needs to handle the job of @@ -646,7 +646,7 @@ TkSetFocusWin( * toplevel from a different application, clear the focus in that * application. */ - + if (force) { TkWindow *focusPtr = winPtr->dispPtr->focusPtr; if (focusPtr && focusPtr->mainPtr != winPtr->mainPtr) { @@ -660,7 +660,7 @@ TkSetFocusWin( * Call the platform specific function TkpChangeFocus to move the * window manager's focus to a new toplevel. */ - + serial = TkpChangeFocus(TkpGetWrapperWindow(topLevelPtr), force); if (serial != 0) { displayFocusPtr->focusSerial = serial; diff --git a/generic/tkImgGIF.c b/generic/tkImgGIF.c index fa4b728..0c32047 100644 --- a/generic/tkImgGIF.c +++ b/generic/tkImgGIF.c @@ -1260,7 +1260,7 @@ ReadImage( * * The field "stack" is abused for temporary buffer. it has 4096 bytes * and we need 256. - * + * * Loop until we hit a 0 length block which is the end sign. */ while ( 0 < (count = GetDataBlock(gifConfPtr, chan, stack))) diff --git a/generic/tkMain.c b/generic/tkMain.c index a7d4ca1..3600142 100644 --- a/generic/tkMain.c +++ b/generic/tkMain.c @@ -79,22 +79,35 @@ extern const TclIntPlatStubs *tclIntPlatStubsPtr; #endif /* - * Further on, in UNICODE mode, we need to use Tcl_NewUnicodeObj, - * while otherwise NewNativeObj is needed (which provides proper - * conversion from native encoding to UTF-8). + * Further on, in UNICODE mode we just use Tcl_NewUnicodeObj, otherwise + * NewNativeObj is needed (which provides proper conversion from native + * encoding to UTF-8). */ -#ifdef UNICODE + +#if defined(UNICODE) && (TCL_UTF_MAX <= 4) # define NewNativeObj Tcl_NewUnicodeObj -#else /* !UNICODE */ - static Tcl_Obj *NewNativeObj(char *string, int length) { - Tcl_Obj *obj; - Tcl_DString ds; - Tcl_ExternalToUtfDString(NULL, string, length, &ds); - obj = Tcl_NewStringObj(Tcl_DStringValue(&ds), Tcl_DStringLength(&ds)); - Tcl_DStringFree(&ds); - return obj; +#else /* !UNICODE || (TCL_UTF_MAX > 4) */ +static inline Tcl_Obj * +NewNativeObj( + TCHAR *string, + int length) +{ + Tcl_Obj *obj; + Tcl_DString ds; + +#ifdef UNICODE + if (length > 0) { + length *= sizeof(WCHAR); + } + Tcl_WinTCharToUtf(string, length, &ds); +#else + Tcl_ExternalToUtfDString(NULL, (char *) string, length, &ds); +#endif + obj = Tcl_NewStringObj(Tcl_DStringValue(&ds), Tcl_DStringLength(&ds)); + Tcl_DStringFree(&ds); + return obj; } -#endif /* !UNICODE */ +#endif /* !UNICODE || (TCL_UTF_MAX > 4) */ /* * Declarations for various library functions and variables (don't want to diff --git a/unix/tkUnixMenu.c b/unix/tkUnixMenu.c index d7ed873..909276a 100644 --- a/unix/tkUnixMenu.c +++ b/unix/tkUnixMenu.c @@ -857,11 +857,7 @@ DrawMenuUnderline( if ((mePtr->underline >= 0) && (mePtr->labelPtr != NULL)) { int len; - /* - * Do the unicode call just to prevent overruns. - */ - - Tcl_GetUnicodeFromObj(mePtr->labelPtr, &len); + len = Tcl_GetCharLength(mePtr->labelPtr); if (mePtr->underline < len) { int activeBorderWidth, leftEdge; const char *label, *start, *end; diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c index 366485b..4ad3b9e 100644 --- a/win/tkWinDialog.c +++ b/win/tkWinDialog.c @@ -2911,13 +2911,10 @@ Tk_MessageBoxObjCmd( flags |= icon | type | MB_TASKMODAL | MB_SETFOREGROUND; - tmpObj = messageObj ? Tcl_DuplicateObj(messageObj) - : Tcl_NewUnicodeObj(NULL, 0); + tmpObj = messageObj ? Tcl_DuplicateObj(messageObj) : Tcl_NewObj(); Tcl_IncrRefCount(tmpObj); if (detailObj) { - const Tcl_UniChar twoNL[] = { '\n', '\n' }; - - Tcl_AppendUnicodeToObj(tmpObj, twoNL, 2); + Tcl_AppendStringsToObj(tmpObj, "\n\n", NULL); Tcl_AppendObjToObj(tmpObj, detailObj); } diff --git a/win/tkWinMenu.c b/win/tkWinMenu.c index 8dc0e24..7a2924d 100644 --- a/win/tkWinMenu.c +++ b/win/tkWinMenu.c @@ -1249,7 +1249,9 @@ TkWinHandleMenuEvent( if (hashEntryPtr != NULL) { int i, len, underline; Tcl_Obj *labelPtr; - Tcl_UniChar *wlabel, menuChar; + WCHAR *wlabel; + Tcl_UniChar menuChar; + Tcl_DString ds; *plResult = 0; menuPtr = Tcl_GetHashValue(hashEntryPtr); @@ -1259,6 +1261,7 @@ TkWinHandleMenuEvent( */ menuChar = Tcl_UniCharToUpper((Tcl_UniChar) LOWORD(*pwParam)); + Tcl_DStringInit(&ds); for (i = 0; i < menuPtr->numEntries; i++) { underline = menuPtr->entries[i]->underline; labelPtr = menuPtr->entries[i]->labelPtr; @@ -1266,7 +1269,10 @@ TkWinHandleMenuEvent( /* * Ensure we don't exceed the label length, then check */ - wlabel = Tcl_GetUnicodeFromObj(labelPtr, &len); + const char *src = Tcl_GetStringFromObj(labelPtr, &len); + + Tcl_DStringFree(&ds); + wlabel = (WCHAR *) Tcl_WinUtfToTChar(src, len, &ds); if ((underline < len) && (menuChar == Tcl_UniCharToUpper(wlabel[underline]))) { *plResult = (2 << 16) | i; @@ -1275,6 +1281,7 @@ TkWinHandleMenuEvent( } } } + Tcl_DStringFree(&ds); } break; } @@ -2070,8 +2077,7 @@ DrawMenuUnderline( if ((mePtr->underline >= 0) && (mePtr->labelPtr != NULL)) { int len; - /* do the unicode call just to prevent overruns */ - Tcl_GetUnicodeFromObj(mePtr->labelPtr, &len); + len = Tcl_GetCharLength(mePtr->labelPtr); if (mePtr->underline < len) { const char *label, *start, *end; @@ -2467,7 +2473,7 @@ DrawMenuEntryLabel( XFillRectangle(menuPtr->display, d, menuPtr->disabledGC, x, y, (unsigned) width, (unsigned) height); } else if ((mePtr->image != NULL) - && (menuPtr->disabledImageGC != NULL)) { + && menuPtr->disabledImageGC) { XFillRectangle(menuPtr->display, d, menuPtr->disabledImageGC, leftEdge + imageXOffset, (int) (y + (mePtr->height - imageHeight)/2 + imageYOffset), diff --git a/win/ttkWinXPTheme.c b/win/ttkWinXPTheme.c index 3de1504..b828221 100644 --- a/win/ttkWinXPTheme.c +++ b/win/ttkWinXPTheme.c @@ -455,7 +455,7 @@ InitElementData(ElementData *elementData, Tk_Window tkwin, Drawable d) { Window win = Tk_WindowId(tkwin); - if (win != None) { + if (win) { elementData->hwnd = Tk_GetHWND(win); } else { elementData->hwnd = elementData->procs->stubWindow; @@ -829,16 +829,21 @@ static void TextElementSize( ElementData *elementData = clientData; RECT rc = {0, 0}; HRESULT hr = S_OK; + const char *src; + int len; + Tcl_DString ds; if (!InitElementData(elementData, tkwin, 0)) return; + src = Tcl_GetStringFromObj(element->textObj, &len); + Tcl_WinUtfToTChar(src, len, &ds); hr = elementData->procs->GetThemeTextExtent( elementData->hTheme, elementData->hDC, elementData->info->partId, Ttk_StateTableLookup(elementData->info->statemap, 0), - Tcl_GetUnicode(element->textObj), + (WCHAR *) Tcl_DStringValue(&ds), -1, DT_LEFT,// | DT_BOTTOM | DT_NOPREFIX, NULL, @@ -851,6 +856,7 @@ static void TextElementSize( if (*widthPtr < 80) *widthPtr = 80; if (*heightPtr < 20) *heightPtr = 20; + Tcl_DStringFree(&ds); FreeElementData(elementData); } @@ -862,20 +868,27 @@ static void TextElementDraw( ElementData *elementData = clientData; RECT rc = BoxToRect(b); HRESULT hr = S_OK; + const char *src; + int len; + Tcl_DString ds; if (!InitElementData(elementData, tkwin, d)) return; + src = Tcl_GetStringFromObj(element->textObj, &len); + Tcl_WinUtfToTChar(src, len, &ds); hr = elementData->procs->DrawThemeText( elementData->hTheme, elementData->hDC, elementData->info->partId, Ttk_StateTableLookup(elementData->info->statemap, state), - Tcl_GetUnicode(element->textObj), + (WCHAR *) Tcl_DStringValue(&ds), -1, DT_LEFT,// | DT_BOTTOM | DT_NOPREFIX, (state & TTK_STATE_DISABLED) ? DTT_GRAYED : 0, &rc); + + Tcl_DStringFree(&ds); FreeElementData(elementData); } @@ -1102,7 +1115,7 @@ Ttk_CreateVsapiElement( XPThemeData *themeData = clientData; ElementInfo *elementPtr = NULL; ClientData elementData; - Tcl_UniChar *className; + WCHAR *className; int partId = 0; Ttk_StateTable *stateTable; Ttk_Padding pad = {0, 0, 0, 0}; @@ -1111,6 +1124,7 @@ Ttk_CreateVsapiElement( char *name; LPWSTR wname; Ttk_ElementSpec *elementSpec = &GenericElementSpec; + Tcl_DString classBuf; static const char *optionStrings[] = { "-padding","-width","-height","-margins", "-syssize", @@ -1128,7 +1142,8 @@ Ttk_CreateVsapiElement( if (Tcl_GetIntFromObj(interp, objv[1], &partId) != TCL_OK) { return TCL_ERROR; } - className = Tcl_GetUnicodeFromObj(objv[0], &length); + name = Tcl_GetStringFromObj(objv[0], &length); + className = (WCHAR *) Tcl_WinUtfToTChar(name, length, &classBuf); /* flags or padding */ if (objc > 3) { @@ -1140,54 +1155,54 @@ Ttk_CreateVsapiElement( "Missing value for \"%s\".", Tcl_GetString(objv[i]))); Tcl_SetErrorCode(interp, "TTK", "VSAPI", "MISSING", NULL); - return TCL_ERROR; + goto retErr; } if (Tcl_GetIndexFromObjStruct(interp, objv[i], optionStrings, sizeof(char *), "option", 0, &option) != TCL_OK) - return TCL_ERROR; + goto retErr; switch (option) { case O_PADDING: if (Ttk_GetBorderFromObj(interp, objv[i+1], &pad) != TCL_OK) { - return TCL_ERROR; + goto retErr; } break; case O_MARGINS: if (Ttk_GetBorderFromObj(interp, objv[i+1], &pad) != TCL_OK) { - return TCL_ERROR; + goto retErr; } flags |= PAD_MARGINS; break; case O_WIDTH: if (Tcl_GetIntFromObj(interp, objv[i+1], &tmp) != TCL_OK) { - return TCL_ERROR; + goto retErr; } pad.left = pad.right = tmp; flags |= IGNORE_THEMESIZE; break; case O_HEIGHT: if (Tcl_GetIntFromObj(interp, objv[i+1], &tmp) != TCL_OK) { - return TCL_ERROR; + goto retErr; } pad.top = pad.bottom = tmp; flags |= IGNORE_THEMESIZE; break; case O_SYSSIZE: if (GetSysFlagFromObj(interp, objv[i+1], &tmp) != TCL_OK) { - return TCL_ERROR; + goto retErr; } elementSpec = &GenericSizedElementSpec; flags |= (tmp & 0xFFFF); break; case O_HALFHEIGHT: if (Tcl_GetBooleanFromObj(interp, objv[i+1], &tmp) != TCL_OK) { - return TCL_ERROR; + goto retErr; } if (tmp) flags |= HALF_HEIGHT; break; case O_HALFWIDTH: if (Tcl_GetBooleanFromObj(interp, objv[i+1], &tmp) != TCL_OK) { - return TCL_ERROR; + goto retErr; } if (tmp) flags |= HALF_WIDTH; @@ -1201,7 +1216,7 @@ Ttk_CreateVsapiElement( Tcl_Obj **specs; int n,j,count, status = TCL_OK; if (Tcl_ListObjGetElements(interp, objv[2], &count, &specs) != TCL_OK) - return TCL_ERROR; + goto retErr; /* we over-allocate to ensure there is a terminating entry */ stateTable = ckalloc(sizeof(Ttk_StateTable) * (count + 1)); memset(stateTable, 0, sizeof(Ttk_StateTable) * (count + 1)); @@ -1217,6 +1232,7 @@ Ttk_CreateVsapiElement( } if (status != TCL_OK) { ckfree(stateTable); + Tcl_DStringFree(&classBuf); return status; } } else { @@ -1237,7 +1253,7 @@ Ttk_CreateVsapiElement( elementPtr->elementName = name; /* set the class name to an allocated copy */ - wname = ckalloc(sizeof(WCHAR) * (length + 1)); + wname = ckalloc(Tcl_DStringLength(&classBuf) + sizeof(WCHAR)); wcscpy(wname, className); elementPtr->className = wname; @@ -1247,7 +1263,12 @@ Ttk_CreateVsapiElement( Ttk_RegisterCleanup(interp, elementData, DestroyElementData); Tcl_SetObjResult(interp, Tcl_NewStringObj(elementName, -1)); + Tcl_DStringFree(&classBuf); return TCL_OK; + +retErr: + Tcl_DStringFree(&classBuf); + return TCL_ERROR; } /*---------------------------------------------------------------------- -- cgit v0.12 From 7ee3cf1eefe8f83ea1e5a48fd3b8c0d01803f3b9 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 19 Mar 2019 16:31:21 +0000 Subject: More use of Tcl_WinTCharToUtf() in stead of Tcl_UniCharToUtfDString(), making Tk less sensitive to the value of TCL_UTF_MAX (either 3, 4, or 6) --- generic/tkMain.c | 4 ---- generic/tkSelect.c | 2 +- win/tkWinClipboard.c | 8 ++------ win/tkWinKey.c | 2 +- win/tkWinMenu.c | 4 ++-- 5 files changed, 6 insertions(+), 14 deletions(-) diff --git a/generic/tkMain.c b/generic/tkMain.c index 3600142..b80ce4d 100644 --- a/generic/tkMain.c +++ b/generic/tkMain.c @@ -84,9 +84,6 @@ extern const TclIntPlatStubs *tclIntPlatStubsPtr; * encoding to UTF-8). */ -#if defined(UNICODE) && (TCL_UTF_MAX <= 4) -# define NewNativeObj Tcl_NewUnicodeObj -#else /* !UNICODE || (TCL_UTF_MAX > 4) */ static inline Tcl_Obj * NewNativeObj( TCHAR *string, @@ -107,7 +104,6 @@ NewNativeObj( Tcl_DStringFree(&ds); return obj; } -#endif /* !UNICODE || (TCL_UTF_MAX > 4) */ /* * Declarations for various library functions and variables (don't want to diff --git a/generic/tkSelect.c b/generic/tkSelect.c index fcfd323..8ba0c5f 100644 --- a/generic/tkSelect.c +++ b/generic/tkSelect.c @@ -26,7 +26,7 @@ typedef struct { int charOffset; /* The offset of the next char to retrieve. */ int byteOffset; /* The expected byte offset of the next * chunk. */ - char buffer[TCL_UTF_MAX]; /* A buffer to hold part of a UTF character + char buffer[4]; /* A buffer to hold part of a UTF character * that is split across chunks. */ char command[1]; /* Command to invoke. Actual space is * allocated as large as necessary. This must diff --git a/win/tkWinClipboard.c b/win/tkWinClipboard.c index 877eed4..93c5d42 100644 --- a/win/tkWinClipboard.c +++ b/win/tkWinClipboard.c @@ -79,9 +79,7 @@ TkSelGetSelection( goto error; } data = GlobalLock(handle); - Tcl_DStringInit(&ds); - Tcl_UniCharToUtfDString((Tcl_UniChar *)data, - Tcl_UniCharLen((Tcl_UniChar *)data), &ds); + Tcl_WinTCharToUtf((TCHAR *)data, -1, &ds); GlobalUnlock(handle); } else if (IsClipboardFormatAvailable(CF_TEXT)) { /* @@ -157,9 +155,7 @@ TkSelGetSelection( if (count) { Tcl_DStringAppend(&ds, "\n", 1); } - len = Tcl_UniCharLen((Tcl_UniChar *) fname); - Tcl_DStringInit(&dsTmp); - Tcl_UniCharToUtfDString((Tcl_UniChar *) fname, len, &dsTmp); + Tcl_WinTCharToUtf(fname, -1, &dsTmp); Tcl_DStringAppend(&ds, Tcl_DStringValue(&dsTmp), Tcl_DStringLength(&dsTmp)); Tcl_DStringFree(&dsTmp); diff --git a/win/tkWinKey.c b/win/tkWinKey.c index 357a804..8db34af 100644 --- a/win/tkWinKey.c +++ b/win/tkWinKey.c @@ -122,7 +122,7 @@ TkpGetString( if (((keysym != NoSymbol) && (keysym > 0) && (keysym < 256)) || (keysym == XK_Return) || (keysym == XK_Tab)) { - len = Tcl_UniCharToUtf((Tcl_UniChar) (keysym & 255), buf); + len = Tcl_UniCharToUtf(keysym & 255, buf); Tcl_DStringAppend(dsPtr, buf, len); } } diff --git a/win/tkWinMenu.c b/win/tkWinMenu.c index 7a2924d..3223759 100644 --- a/win/tkWinMenu.c +++ b/win/tkWinMenu.c @@ -1250,7 +1250,7 @@ TkWinHandleMenuEvent( int i, len, underline; Tcl_Obj *labelPtr; WCHAR *wlabel; - Tcl_UniChar menuChar; + int menuChar; Tcl_DString ds; *plResult = 0; @@ -1259,7 +1259,7 @@ TkWinHandleMenuEvent( * Assume we have something directly convertable to Tcl_UniChar. * True at least for wide systems. */ - menuChar = Tcl_UniCharToUpper((Tcl_UniChar) LOWORD(*pwParam)); + menuChar = Tcl_UniCharToUpper(LOWORD(*pwParam)); Tcl_DStringInit(&ds); for (i = 0; i < menuPtr->numEntries; i++) { -- cgit v0.12 From 63f067286fc348190bd0e780deec6c9566b2409b Mon Sep 17 00:00:00 2001 From: culler Date: Tue, 19 Mar 2019 22:25:22 +0000 Subject: Fixed a typo that was causing extraneous "tkwin == NULL" debug messages in the mac regression tests. --- macosx/tkMacOSXMouseEvent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c index 9a1988d..ec713d4 100644 --- a/macosx/tkMacOSXMouseEvent.c +++ b/macosx/tkMacOSXMouseEvent.c @@ -103,7 +103,7 @@ enum { */ if (eventWindow == NULL) { - eventWindow == _windowWithMouse; + eventWindow = _windowWithMouse; } if (eventWindow) { -- cgit v0.12 From 4494f123bac86f61b2f1c3c8b56949c9e0aa2e92 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 22 Mar 2019 14:13:15 +0000 Subject: Bugfix in tkWinClipboard: Failed to determine fname length in loop. --- win/tkWinClipboard.c | 3 ++- win/tkWinInit.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/win/tkWinClipboard.c b/win/tkWinClipboard.c index 93c5d42..a00909c 100644 --- a/win/tkWinClipboard.c +++ b/win/tkWinClipboard.c @@ -155,7 +155,8 @@ TkSelGetSelection( if (count) { Tcl_DStringAppend(&ds, "\n", 1); } - Tcl_WinTCharToUtf(fname, -1, &dsTmp); + len = Tcl_UniCharLen((Tcl_UniChar *) fname); + Tcl_WinTCharToUtf(fname, len * sizeof(WCHAR), &dsTmp); Tcl_DStringAppend(&ds, Tcl_DStringValue(&dsTmp), Tcl_DStringLength(&dsTmp)); Tcl_DStringFree(&dsTmp); diff --git a/win/tkWinInit.c b/win/tkWinInit.c index 4c18399..780888a 100644 --- a/win/tkWinInit.c +++ b/win/tkWinInit.c @@ -199,7 +199,7 @@ TkWin32ErrorObj( } #ifdef _UNICODE - Tcl_WinTCharToUtf(lpBuffer, (int)wcslen(lpBuffer) * sizeof (WCHAR), &ds); + Tcl_WinTCharToUtf(lpBuffer, wcslen(lpBuffer) * sizeof (WCHAR), &ds); errPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), Tcl_DStringLength(&ds)); Tcl_DStringFree(&ds); #else -- cgit v0.12 From 53623d974a56e46a09078d5c6d72a792f9018829 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 22 Mar 2019 14:15:37 +0000 Subject: Slightly better: Don't use Tcl_UniCharLen() but wcslen(). --- win/tkWinClipboard.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/win/tkWinClipboard.c b/win/tkWinClipboard.c index a00909c..8c6a4a4 100644 --- a/win/tkWinClipboard.c +++ b/win/tkWinClipboard.c @@ -149,13 +149,14 @@ TkSelGetSelection( if (drop->fWide) { WCHAR *fname = (WCHAR *) ((char *) drop + drop->pFiles); Tcl_DString dsTmp; - int count = 0, len; + int count = 0; + size_t len; while (*fname != 0) { if (count) { Tcl_DStringAppend(&ds, "\n", 1); } - len = Tcl_UniCharLen((Tcl_UniChar *) fname); + len = wcslen(fname); Tcl_WinTCharToUtf(fname, len * sizeof(WCHAR), &dsTmp); Tcl_DStringAppend(&ds, Tcl_DStringValue(&dsTmp), Tcl_DStringLength(&dsTmp)); -- cgit v0.12 From 2cf5a82a75201dd866c90d3add0462c19854d88f Mon Sep 17 00:00:00 2001 From: culler Date: Mon, 25 Mar 2019 15:50:47 +0000 Subject: Fix bug [48c39440af]: On macOS, Buttons and Labels do not recompute their textLayout when the text option is set to an empty string. --- macosx/tkMacOSXButton.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index c0b83f2..484dcf2 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -295,11 +295,11 @@ TkpComputeButtonGeometry( haveImage = 1; } - if (strlen(text) > 0) { + if (haveImage == 0 || butPtr->compound != COMPOUND_NONE) { Tk_FreeTextLayout(butPtr->textLayout); butPtr->textLayout = Tk_ComputeTextLayout(butPtr->tkfont, - Tcl_GetString(butPtr->textPtr), -1, butPtr->wrapLength, - butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight); + text, -1, butPtr->wrapLength, butPtr->justify, 0, + &butPtr->textWidth, &butPtr->textHeight); txtWidth = butPtr->textWidth + 2*butPtr->padX; txtHeight = butPtr->textHeight + 2*butPtr->padY; -- cgit v0.12