Skip to content

Updates for Tcl 8.6 and 9.0 support #20

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open

Conversation

mark987
Copy link
Contributor

@mark987 mark987 commented May 27, 2025

I've been working on tcl 8.6 / 9.0 updates for a while, have read the proposed patches from @qykth-git and I believe these miss some important things, it is easier for me to just show my work including explanations in the commit messages. Key differences:

There are a number of updates to mouse scroll handling we should make for Tcl/Tk 8.6, these depend upon TIP 171, and this precedes anything for TIP 474 / Tcl 9. We should update gitk requirements to be 8.6 before doing this as 8.4/8.5 don't support TIP 171, 8.6 will likely continue in use for a decade as 9.0 just hit. My 9.0 mouse version uses the Option- modifier to select large motion (like on x11 previously) vs fine motion (line on aqua previously), similar to how Tk changes this by default on other widgets.

Tcl 9 includes TIP 699 because of much confusion about binary channels. Following that document and looking carefully at gikt, I reach a different result than 042ede8, reasoning is in the 0f4b70c commit message.

There are additional changes using -profile needed to operate on Tcl 9 to cover some encoding issues, 5d5d337 and 036fc90.

I'm successfully using gitk (and git-gui) on Tcl8.6 and on Tcl9.0.1 with this set (no longer have 8.7, but did some of the earlier work with that).

@j6t
Copy link
Owner

j6t commented May 29, 2025

Thank you! The extensive explanations in the commit messages are very much appreciated. This looks already very good.

I am concerned that the horizontal scrolling of the commit graph is a regression on MacOS: before, it was active when the mouse was on any of the three panels, now the mouse must be over the commit graph panel.

I am not happy with the simple tilde substitution with $env(HOME). I do not have Git for Windows installed and have set HOME manually because I know that it is needed. How does file tildeexpand work on Windows when HOME is not set, as is common outside of Git for Windows? Does it use the HOMEDRIVE\HOMEDIR combo?

#11 changes fconfigure to chan configure. Is this not needed for Tcl 9?

BTW, the horizontal scrolling on X11 now works secretly with the mouse wheel (Shift+Alt+wheel), but it uses a very small increment here. It takes a lot of wheel turns to scroll even half the window width. Is that intended? (I haven't tested elsewhere, yet.)

gitk runs under wish, so naturally has Tcl and Tk available, and of the
same version. gitk sets a requirement on Tk version >= 8.4, but this is
very outdated, and not shipping on any current OS.  As 8.7 is in alpha
test, and is generally compatible with 8.x, we should allow that, but
9.0 has planned compatibility breaking changes so is not yet supported.

Also, as git-gui requires at least 8.5, and gitk and git-gui can launch
each other, the minimum requirement should be at least 8.5.  But, no
currently supported OS is shipping 8.5, much less 8.4, and 9.0 is
already released.  So, even 8.5 is essentially an untestable
requirement: 8.6 is a more reasonable minimum requirement.

So, we should allow 8.6-8.7 but not 9.0. As we are using wish, we only
need to check the version of Tcl or of Tk as these must be the same.
Let's put this at the top of file so the requirements are obvious.

Signed-off-by: Mark Levedahl <[email protected]>
@mark987
Copy link
Contributor Author

mark987 commented May 30, 2025

I've updated the branch to:

  • correct spelling errors and generally improve wording in commit messages
  • moved settting and use of colspc variable into 432717b from its successor (now 61da1f5)
  • increased the value of colspc from 5 to 25, horizontal scrolling of the commit graph is now 5x larger than before.

To @j6t on your previous questions:
horizontal scrolling of the commit graph is a regression on MacOS

  • I updated comments in 432717b about this: basically, normal GUI design has the mouse pointer indicate the window to be scrolled. While vertical scolling in any of the top 3 panes makes sense, as all scroll, horizontal scrolling of the commit graph from any pane does not as ONLY the commit graph will scroll.

I am not happy with the simple tilde substitution with $env(HOME)

  • What I wrote works on all the platforms I know how to test and can explain. I know the configuration of git on Windows using either Cygwin or MSYS (the latter underlies g4w). MSYS defines HOME, g4w assures this is propagated, but not of other approaches.
  • Tilde expansion on Tcl 9 uses $HOME if it is defined. Tcl sets up the environment when starting, and tries to assure $HOME is defined, using $HOMEDRIVE and $HOMEDIR if $HOME is not there. But, those variables are wrong on Cygwin, might not point to what g4w thinks is $HOME, so I'm not at all sure what they mean.
  • So, as long as $HOME is honored and not touched, this doesn't matter to me. I just don't understand a supportable configuration where $HOME is not defined.

#11 changes fconfigure to chan configure. Is this not needed for Tcl 9?

  • The "chan" command was introduced in Tcl 8.5 per TIP 208 to consolidate many (by no means all) channel related commands into one group. A few commands, including fconfigure, were recommended to be deprecated in TIP 208, but this did not happen in 8.5 or 8.6. In 9.0, fconfigure and chan configure are the same thing, though the Tcl 9 documentation for fconfigure shows this is now deprecated. Nothing in the documentation on migrating to Tcl 9 mentions this, and fconfigure shows up in the migration instructions.
  • My take is this is optional, not required. We could do a global search/replace, it makes no difference. So, I didn't do it.

horizontal scrolling on X11 now works secretly with the mouse wheel (Shift+Alt+wheel), but it uses a very small increment here.

  • The colspc variable mentioned above can be increased to make this scroll more quickly, I changed it from 5 to 25, giving a 5x increase.
  • We might also use $linespc instead of $colspc to set horizontal scolling increments : linespc is computed as the vertical font size, so is roughly the size of a line, this could be a reasonable value to use for horizontal scrolling as well.
  • You have to use Tcl9 to see any difference when the Alt key is pressed: Tcl8 does not generate the Option- modifier.

@qykth-git
Copy link
Contributor

@j6t
$env(HOME) was defined like this on Windows Tcl.
https://github.com/tcltk/tcl/blob/9f8cc0d427b6fea52116a71060c9a37a757efea4/win/tclWinInit.c#L558

Windows Tcl build own $env(HOME) with these order.

  1. Use supplied $HOME
  2. Build $HOME from $HOMEDRIVE and $HOMEPATH
  3. Build $HOME from $USERPROFILE
  4. Just use C:\\ as $HOME

@j6t
Copy link
Owner

j6t commented May 30, 2025

Windows Tcl build own $env(HOME) with these order.

  1. Use supplied $HOME
  2. Build $HOME from $HOMEDRIVE and $HOMEPATH
  3. Build $HOME from $USERPROFILE
  4. Just use C:\\ as $HOME

Thank you, this matches the results of my experiments today. Hence, using $env(HOME) instead of the tilde is fine.

@j6t
Copy link
Owner

j6t commented May 30, 2025

@mark987 Thank you for the update and the explanations. Using $env(HOME) for the tilde is alright. The horizontal scrolling speed is now a lot better.

The need for -profile tcl8 is scary stuff. (Who the hell writes software that expects a perfect environment, and crashes at the first imperfection, I have to ask the Tcl people?) Do we need a plan to do something similar for the exec calls that capture output from the commands?

@mark987
Copy link
Contributor Author

mark987 commented May 30, 2025

@j6t - I will amend 432717b to use $linespc for vertical and horizontal increments so that this is modified by font metrics.

gitk uses exec as a pipe_open and read stdout (maybe stderr?) function, and exec has no -profile setting. git-gui's git_read is a good substitute that calls open, and we can modify open to use -profile tcl8. gitk has at least one exec call that does not invoke git, this will require similar treatment but git_read itself won't do it. My git-gui tree already has modifications to handle Tcl 9 including -profile tcl8 on all opened channels, will push that out later.

@mark987
Copy link
Contributor Author

mark987 commented May 30, 2025

The use of -profile strict in Tcl is really driven by the internationalization standards (not sure exactly what spec): the tcl8 behavior is apparently non-compliant, this raises security / vulnerability issues. I won't be surprised to find this is just the start of a new campaign that will force git's permissive approach to change, possibly forcing tools to rewrite history with full encoding headers validated to be correct.

@mark987
Copy link
Contributor Author

mark987 commented May 31, 2025

By experiment, it seems that [exec ...] uses the "replace" strategy. Using a simple test prog:

#include <stdio.h>
int main (int argc, char *argv[])
{
        int c = 0x70;
        while (c < 0x90) {
                for (int col = 0 ; col < 10; col++) {
                        printf("%4x %c  ", c, c);
                        ++c;
                }
                printf("\n");
        }
        return(0);
}

Compiled, ./a.out gives

  70 p    71 q    72 r    73 s    74 t    75 u    76 v    77 w    78 x    79 y  
  7a z    7b {    7c |    7d }    7e ~    7f     80 �    81 �    82 �    83 �  
  84 �    85 �    86 �    87 �    88 �    89 �    8a �    8b �    8c �    8d �  
  8e �    8f �    90 �    91 �    92 �    93 �    94 �    95 �    96 �    97 �  

My system is configured for utf-8, does not recognize bytes >= 0x80 as valid, so displays those with the defined "replacement" character �.

Running this in tclsh 9 using a pipe, thus has -profile strict, gives the expected tantrum

tclsh [~/] set fd [open [list | ./a.out] r]
file5
tclsh [~/] gets $fd
  70 p    71 q    72 r    73 s    74 t    75 u    76 v    77 w    78 x    79 y  
tclsh [~/] gets $fd
error reading "file5": invalid or incomplete multibyte or wide character

But, using exec is ok:

tclsh [~/maint/src/git-gui] set s [exec ./a.out]
  70 p    71 q    72 r    73 s    74 t    75 u    76 v    77 w    78 x    79 y  
  7a z    7b {    7c |    7d }    7e ~    7f     80 �    81 �    82 �    83 �  
  84 �    85 �    86 �    87 �    88 �    89 �    8a �    8b �    8c �    8d �  
  8e �    8f �    90 �    91 �    92 �    93 �    94 �    95 �    96 �    97 �  

Under 8.6, I get somewhat different results - no errors, but no glyph for anything >= 0x7f:

set fd [open [list | ./a.out] r]
file5
> gets $fd
  70 p    71 q    72 r    73 s    74 t    75 u    76 v    77 w    78 x    79 y  
> gets $fd
  7a z    7b {    7c |    7d }    7e ~    7f     80     81     82     83   
> gets $fd
  84     85     86     87     88     89     8a     8b     8c     8d   
> gets $fd
  8e     8f     90     92     93     94     95     96     97   
> gets $fd

> 
set s [exec ./a.out]
  70 p    71 q    72 r    73 s    74 t    75 u    76 v    77 w    78 x    79 y  
  7a z    7b {    7c |    7d }    7e ~    7f     80     81     82     83   
  84     85     86     87     88     89     8a     8b     8c     8d   
  8e     8f     90     92     93     94     95     96     97

exec on Tclsh8.6 stops after reading character 0x97, but setting the range starting at 0xa0 gives:

set s [exec ./a.out]
  a8 ¨    a9 ©    aa ª    ab «    ac ¬    ad ­    ae ®    af ¯    b0 °    b1 ±  
  b2 ²    b3 ³    b4 ´    b5 µ    b6 ¶    b7 ·    b8 ¸    b9 ¹    ba º    bb »  
  bc ¼    bd ½    be ¾    bf ¿    c0 À    c1 Á    c2 Â    c3 Ã    c4 Ä    c5 Å  
  c6 Æ    c7 Ç    c8 È    c9 É    ca Ê    cb Ë    cc Ì    cd Í    ce Î    cf Ï  
  d0 Ð    d1 Ñ    d2 Ò    d3 Ó    d4 Ô    d5 Õ    d6 Ö    d7 ×    d8 Ø    d9 Ù  
  da Ú    db Û    dc Ü    dd Ý    de Þ    df ß    e0 à    e1 á    e2 â    e3 ã  
  e4 ä    e5 å    e6 æ    e7 ç    e8 è    e9 é    ea ê    eb ë    ec ì    ed í  
  ee î    ef ï    f0 ð    f1 ñ    f2 ò    f3 ó    f4 ô    f5 õ    f6 ö    f7 ÷  
  f8 ø    f9 ù    fa ú    fb û    fc ü    fd ý    fe þ    ff ÿ 

My inference:

tcl8.6 operates as expected, transcoding (some) valid extended ascii characters via the ISO-8899-1 code page. Tcl 9.0 uses the 'replace' profile, so does not throw an exception but also gives different results than 8.6.
So, we probably should use a variant of git_read to replace set x [exec ...]

BTW, git-filter-repo, written in python, throws errors on repos with extended ascii characters as well. This is not just a tcl thing.

@mark987
Copy link
Contributor Author

mark987 commented May 31, 2025

The solution actually removes lines of code, as we no longer need the Windows exec override :^) Instead, just use a pipeline from [open | ..], and take advantage that we already overwrote open to add -profile tcl8.

@j6t
Copy link
Owner

j6t commented Jun 1, 2025

Thank you for the extensive tests.

The exec replacement that you suggest isn't something I would take. It's too scary. There could be library calls outside of Gitk that expect a certain API, but the suggested replacement isn't fully compatible.

At any rate, the important finding is that exec of neither Tcl 8.6 nor Tcl 9 fails on invalid UTF-8 input. That the two versions don't give the same result (or an "unexpected" result), is of no concern for Gitk. (After all, its a form of garbage-in-garbage-out.) Therefore, I wouldn't do anything about it at this time.

@mark987
Copy link
Contributor Author

mark987 commented Jun 1, 2025

I agree - the patch was really a throw-away test to see if it made any difference, I didn't find one, even running with profile -strict. But, if this is needed in future, a careful analysis of any call-site and how it parses data is needed to do this correctly - I punted on that.

A more interesting question is whether -profile replace should be used rather than -profile tcl8. This would change output, but would better reflect that we don't know the correct character to show anyway.

The big danger under all of this is that some repo has a tree with extended ascii on filenames. I don't know how git handles encoding trees now, whether that has changed, etc. Certainly utf-8 was less universal when git started. Regardless, if this problem exists, it is one for git to solve, not gitk/git-gui.

@j6t
Copy link
Owner

j6t commented Jun 2, 2025

I have now used this series in production on Windows for a day. It works as expected.

But... I notice that the mouse wheel scrolls the patch text and the file list a lot slower than before, to the point that it becomes hard work (and dangerous for the finger that operates the wheel). The reason is that we no longer override wheel scrolling for those two windows and use Tk's default binding. Whatever they recommend to use as scrolling unit, it is far too less and our values were a lot better. In my case, the old version scrolled 5 lines at a minimum (don't know exactly), while the new version scrolls only 2 lines. Opinions? Should we increase -yscrollincr for these two windows?

@mark987
Copy link
Contributor Author

mark987 commented Jun 3, 2025

The existing mouse scrolling code is a mess: three different codes for three different platforms, each giving different scrolling behavior. To wit:

  • aqua has the hidden horizontal commt graph scrolling, scrolls by one line for each event, and default Tk bindings do the same.
  • win32 has mouse_wheel_redirector that gives default 5 lines vertical scrolling for each event, and does this for every widget in the main window. Horizontal scrolling is handled by any default bindings that might exist.
  • x11 binds mouse buttons to get default 5 units vertical scrolling on the top 3 panes, 5 units horizontal scrolling on the text window (lower left), defaults on all else.

The "correct" scrolling value is obviously non-obvious: @j6t complains of < 5 lines per event, but aqua has 1. I suspect we need a config item scroll_lines_per_mouse_event or some such, expecting values in the range 1-10.

My patches for 8.6 do not achieve harmony as I hadn't noticed all I wrote above, and they cannot do what Tcl 9 does.

For Tcl 9, my patches try to unify everything around the new model given by Tk 9. Nominal scrolling is 1 line per event, with the Option- modifier (Alt key on PC, Option on Mac), we get about 5 lines per event, which is also the Tk default. All good.

I'm pushing a modified branch that gets win32 and x11 close at default 5 lines per event scrolling for the top 3 panes and bottom 2. I didn't touch aqua, but it should get modified to do the common thing. I'll take a stab once we agree on what we are trying to achieve for 8.6.

Tk through 8.6 has different approaches for handling mouse wheel /
touchpad scrolling events on the different platforms, and gitk has
separate code for these. But, some x11 bindings are applied on aqua as
we do not have these in a clean if / then / else tree based upon
platform.  Let's split these bindings apart.

Signed-off-by: Mark Levedahl <[email protected]>
@mark987
Copy link
Contributor Author

mark987 commented Jun 4, 2025

I've reworked the 8.6 scrolling, with the goal of making all platforms do the same thing (they did not come even close, it turns out, and for no good reason). I also wanted to make 8.6 and 9.0 do the same thing but failed. The problem is that 9.0 adds the Option- modifier using the Alt key on PC, and Option key on Mac, to get ~5x (or more) motion than the nominal. This key cannot be changed. But, in 8.6 and earlier, the Alt- key on PC/Windows activates the menu-bar, this cannot be changed, and makes the Alt- key as a modifier for mouse scrolling essentially unusable.

I added a mouse motion multiplier (kscroll) in the preferences dialog, default value = 1, allowed [1..20]. 1 gives essentially the old aqua motion, 5 the win32 motion, and the x11 had a mixture of those two. A value < 1 is not useful, though you can type in whatever fractional value you wish even though the spinbox only does integers.

So, in 8.6, on all platforms, the 5 main windows (3 top panes, two text widgets below) are scrolled vertically by kscroll lines (the text widgets are weird, move 2-3 lines when asked to move 1, can do nothing about that). Horizontal scrolling is available on the two left panes.

9.0 does the same, but adds the Option- modifier to get more motion. With this I set the kscroll preference to 1, use Alt- to move far. But, as I said, cannot get this for 8.6.

More lines of bindings than I wished, but this is the only way to get the uniform scrolling I had put into win32 15 years ago, and forgot all about if I even noticed it then :^).

@j6t
Copy link
Owner

j6t commented Jun 5, 2025

Thank you for this update! The new setting makes it very easy to apply the personal preference.

BTW, should we call it "Wheel scrolling multiplier" to emphasize that it is specific to the mouse wheel?

The commit message of abb97b6 says "increase scrolling motion by a factor of 5". Is this "5" outdated and the new setting should be mentioned, or is it something else?

@mark987
Copy link
Contributor Author

mark987 commented Jun 6, 2025

@j6t - I've incorporated your suggestion on the preference name, and clarified that the Option- modifier gets 5x the defined scrolling value having nothing to do with prior defaults.

But, i've also refactored the scrolling code. I was bothered about the number of mouse binding lines added, their replication, as well as missing details in the scrolling calculations. My new branch adds some features using a common [scroll_val ...] function

  • the scroll val is integer, required on Tk 8.6, regardless of the user setting a floating point scrolling multiplier
  • the scroll value adjusts to accommodate the nominal minimum 3 line scrolling of text widgets.
  • the default preference is now 3, a compromise of the former behaviors on the different platforms, and also the minimum value at which the canvas and text widgets scroll by the same amount.
    Overall, fewer lines added, more understandable to me.

I don't have anymore nagging problems with this code, so won't change anything more except to address feedback. Tested on Linux/X11 with Tcl 8.6.15 and Tcl 9.0.1, Cygwin/X11 with Tcl 8.6.12, G4W/win32 with Tcl 8.6.13. I don't have Tcl 9 except on Linux, no access to aqua anywhere, so those are the big holes in testing.

@j6t
Copy link
Owner

j6t commented Jun 8, 2025

Thank you so much, this looks very good!

@j6t
Copy link
Owner

j6t commented Jun 21, 2025

Two small things I noticed while going over my patch list today:

  • The text "Wheel scrolling multiplier" is not prepared for translation. It should be.
  • We have two variables have_tk85 and have_tk86. They become obsolete with this series and all code using them can be simplified by assuming that the flags are true.

mark987 added 3 commits June 21, 2025 16:45
gitk provides scrolling of several windows, uses hard-coded values for
the amount of scrolling, and these values differ across platforms and
widgets. The nominal value used is either 1 text line per mouse /
touchpad / button event, or 5 lines. Furthermore, Tk does not scroll
text widgets by 1 line when told to, this usually gets 2-3 lines of
motion. The upper canvas objects holding the commit graph do scroll as
defined. But, clearly no value is universally preferred, so let's give
the user some control over this. Provide a single multiplier to be
applied for all scroll bindings, with a value of 3 to mean the default
nominal value of 3 line. This is selected both as a compromise between
the various defaults across platforms, and because it is the smallest
value honored by the two text widgets on the bottom of the screen.

Later commits will connect this variable for actual scrolling events.

Signed-off-by: Mark Levedahl <[email protected]>
gitk supports scrolling of 5 windows, but does this differently on the
aqua, x11, and win32 platforms as Tk provides different events on each.
TIP 171 removes some differences on win32 while altering the required
bindings on x11. TIP 474, which is in Tk 8.7 and later, finally unifies
all platforms on using common MouseWheel bindings. Importantly for now,
TIP 171 causes delivery of MouseWheel events to the widget under the
mouse cursor on win32, eliminating the need for completely different
bindings on win32.

Let's make some common functions to unify as much as we can in Tk 8.6.
Examining the platforms shows that the default platform scrolling is
overridden differently on the 3 platforms, and the nominal amount of
motion achieved per mouse wheel "click" is different. win32 nominally
makes everything move 5 lines per click, aqua 1 line per click, and x11
is a mixture. Part of this is due to win32 overriding all scroll events,
while x11 and aqua override smaller sets. Also, note that the text
widgets (the lower two panes) always scroll by 2-3 lines when given a
smaller scroll amount, while the upper three canvas objects follow the
requested scrolling value more accurately.

First, let's have a common routine to calculate the scroll value to give
to a widget in an event. This accounts for the user preference, the
scale of the %D (delta) value given by the event (120 on win32, 1 on
aqua, assumed 1 on x11), and must always be integer. Include negation as
by convention the screen moves opposite to the MouseWheel delta. Allow
setting an offset value to account for the larger minimum scrolling of
text widgets.

Second, let's have a common declaration of MouseWheel event bindings, as
those are shared by all in Tcl9, and by aqua/win32 earlier. Bind all
five display windows here. Note that the Patch/Tree widget (cflist)
cannot scroll horizontally.

Signed-off-by: Mark Levedahl <[email protected]>
gitk on win32 binds windows_mousewheel_redirector to all MouseWheel
events in the main window. This proc determines the widget under the
cursor, then determines what scroll command to give, possibly none, and
issues scroll commands to the widget. The top panes get only vertical
scroll events, as does the lower right Patch/Tree pane. All others get
both vertical and horizontal events. These are all hard coded at +/-
five lines.

We now have common MouseWheel event bindings that follow user
preferences for the scrolling amount, bind for only the five main
display widgets, and leave the other gui elements untouched. Let's use
this instead. With the scrolling preference set at 5, the users should
not notice much, if any, difference.

Signed-off-by: Mark Levedahl <[email protected]>
mark987 added 16 commits June 21, 2025 16:45
gitk has x11 mouse bindings that receive button presses, not MouseWheel
events, as this is the Tk implementation through Tk 8.6. On x11, gitk
translates each button event to a scrolling value of +/- 5 for the upper
three panes that scroll vertically as one unit. gitk applies similar
scaling for horizontal scaling of the lower-left commit details pane
(ctext), but not for vertical scrolling of either of the bottom panes.
Rather, the Tk default scrolling actions are used for vertical
scrolling.

Let's make X11 behave similarly to the just modified win32 platform. Do
so by connecting vertical and horizontal scrolling events for the same
items bound in 'proc bind_mousewheel' and using the same user preference
values.

Signed-off-by: Mark Levedahl <[email protected]>
Tk provides MouseWheel events to aqua, similar to win32. But, these
events on aqua have a nominal motion value (%D) of 1, not 120 as on
win32. gitk on aqua provides specific bindings only for the top 3 panes,
giving a nominal scrolling amount of +/- 1 for all events. gitk includes
a hidden feature providing horizontal scrolling of the commit graph,
added in 5fdcbb1 ("gitk: Fixes for Mac OS X TkAqua", 2009-03-23).
This horizontal scrolling is triggered by mouse events in any of the top
3 panes, and thus violates normal gui design where the object under the
mouse cursor scrolls.

Let's update this using the common bindings in 'proc bind_mousewheel',
allowing user preferences on motion scaling to apply to all windows.
The commit graph scrolling feature is removed by this, and will be added
back for all platforms in a later commit.

Signed-off-by: Mark Levedahl <[email protected]>
gitk commit 5fdcbb1 ("gitk: Fixes for Mac OS X TkAqua", 2009-03-23),
adds horizontal scrolling of the commit graph pane on aqua, but not on
x11 or win32. Also, the horizontal scrolling is triggered by MouseWheel
events attached to any of the three panes, not just the commit graph
that is the only one that scrolls. It is unusual to scroll a widget that
is not under the mouse, many would consider this a bug. No horizontal
scrollbar is provided for this, so there is no real cue for the user
that horizontal scrolling is available. We removed this aqua only
feature by transitioning aqua to use the common MouseWheel bindings set.

Let's add this as a feature on all platforms, and use the same approach
for scaling scroll motion as we do elsewhere.  For horizontal scrolling,
honor only events received by the commit graph in conformance with
normal GUI design.  Vertical scrolling is unchanged, and events received
by any of the 3 panes continue to scroll all 3 in unison.

Per the ancient and long ignored CUA standards, we should add a
horizontal scrollbar to the commit-graph, but gitk's interface is
already very cluttered: adding a scrollbar to only one of these three
panes is difficult while maintaining common pane vertical size,
especially so considering the movable sash separating panes 1 & 2, and
will consume yet more space. So, leave this as a hidden feature, now
available on all platforms.

Signed-off-by: Mark Levedahl <[email protected]>
TclTk 8.7 (still in alpha), and 9.0 (released), implement TIP 474 that
delivers uniform handling of mouse and touchpad scrolling events on all
platforms, and by default bound to most widgets. TIP 474 also implements
use of the Option- modifier key (Alt- key on PC, Option- key on Macs) to
indicate desire for more motion per scroll wheel event, the
amplification is not defined but seems to be 5x to 10x.

So, for TclTk >= 8.7 we can use identical MouseWheel bindings on all
platforms, and should enable use of the Option- modifier to enable
larger motion. Let's do all of this, and use a 5x multiplier for the
Option- modifier.

This largely follows the prior win32 model, except that Tk 8.6 does not
reliably use the Option- modifier because the Alt- key conflicts with
builtin behavior to activate the main menubar. Presumably this conflict
is addressed in the win32 Tcl9.x package.

Signed-off-by: Mark Levedahl <[email protected]>
gitk uses '-encoding binary' in several places to handle non-text data.
Per TIP 699, this is not recommended as there has been too much
confusion and misconfiguration of binary channels, and this option is
removed in Tcl 9.

Tcl defines a binary channel as one that reproduces the input data
exactly. As Tcl stores all data internally in unicode format, a binary
channel requires 3 things:
-  -encoding iso8859-1 : this causes each byte of input to be translated
   to its unicode equivalent (may be multi-byte).
-  -translation lf : this avoids any translation of line endings, which
   by default are translated to \n on input.
-  -eofchar {} : this avoids any use of an end of file character, which
   is ctrl-z by default on Windows.

The recommended '-translation binary' makes all three settings, but this
is not done in gitk now. Rather, gitk uses '-encoding binary', which is
an alias to '-encoding iso8859-1' removed by TIP 699, in multiple places,
and -eofchar {} in one place but not all. All other files, configured in
non-binary fashion, have -eofchar {}.

Unix and Windows differ on line ending conventions, Tcl by default
converts line endings to \n on input, and to those common on the
platform on output. git emits only \n on Unix or Windows. Also, Tcl's
proc gets recognizes and removes \n, \r, or \r\n as line endings, and
this is used by gitk except in procs selectline and parsecommit. But,
those two procs recognize any combination of \n and \r as terminating a
line. So, there is no need to translate line endings on input, and using
-translation binary avoids any such translation.

Tcl sets eofchar to ctrl-z (ascii \0x1a) only on Windows, otherwise
eofchar is {}. This provides compatibility to old DOS based codes and
files originating when file systems recorded only sectors allocated, and
not bytes used. git does not use ctrl-z to terminate data anywhere. Only
two channels in gitk leave eofchar at the default value, both use
-encoding binary now. A third one was converted in commit 681c329
("gitk: Handle blobs containing a DOS end-of-file marker", 2009-03-16),
fixing such a problem of early data termination. Using eofchar {} is
correct, even if not always necessary.

Tcl 9 forces change, using -translation binary per TIP 699 does what
gitk needs and is backwards compatible to Tcl 8.x. Do it.

Signed-off-by: Mark Levedahl <[email protected]>
gitk looks for configuration files under $(HOME)/.., and uses the
typical shortcut formats to find this, e.g., ~/.config/. This relies
upon Tcl expanding such constructs to replace ~ with $(HOME). But, Tcl 9
has stopped doing that for various reasons, and now supplies [file
tildeexpand ...] to perform this expansion.

There are a very few places that need this expansion, and all must be
modified regardless of approach taken.

POSIX specifies that $HOME be defined at the time of login, and both
Cygwin and MSYS (underlying git for windows) set this variable. Tcl8
uses the POSIX defined pwnam to look up the underlying database record
on Unix, but will get the same result as using $HOME on any POSIX
compliant system. On Windows, Tcl just accesses $HOME, falling back to
other environment variables if $HOME is not set.  Git for Windows has
$HOME defined by MSYS, so this works just as on the others.

As $env(HOME) works in Tcl 8 and 9, while anything using [file
tildeexpand ... ] will not, let's use the simpler approach as doing so
adds no lines of code.

Signed-off-by: Mark Levedahl <[email protected]>
gitk invokes many git commands expecting output in utf-8 encoding, but
git accepts extended ascii (code page unknown) as utf-8 without
validating, so cannot guarantee valid utf-8 on output.  In particular,
using any extended ascii code page, of which there are many, has long
been acceptable given that everyone on a project is aware of and uses
that same code page to view all data. utf-8 accepts only 7-bit ascii
characters in single bytes, and any characters outside of that base set
require at least two bytes.

Tcl is a string based language, and transcodes all input data to an
internal unicode format, and to whatever format is requested on output:
"pure" binary is recoded using iso8859-1.  Tcl8.x silently recodes
invalid utf-8 as binary data, so extended ascii characters maintain
their binary value on output but may not display correctly.

Tcl 8.7 added three profiles to control this behaviour: strict (raises
exceptions), replace (replaces each invalid byte with ?), and the
default tcl8 maintaining the old behavior.  Tcl 9 changes the default
profile to strict, meaning any invalid utf-8 raises an exception that
gitk does not handle.

An example of this in the git repository is commit 7eb93c8965 ("[PATCH]
Simplify git script", 2005-09-07). This includes extended ascii
characters in the author name and commit message. As a result, gitk +
Tcl 9 cannot view the git repository at any point beyond that commit.
Note: Tcl 9.0 has a bug, to be fixed in 9.1, where this particular
condition results in a memory error causing Tcl to crash [1].

The tcl8 profile used so far has acceptable behavior given gitk's
acceptance: this allows gitk to accept extended ascii though it may
display incorrectly.  Let's continue that behavior by overriding open to
use the tcl8 profile on Tcl9 and later: Tcl 8.6 does not understand
fconfigure -profile, and Tcl 8.7 maintains the tcl8 profile.

[1] Per https://core.tcl-lang.org/tcl/tktview/73bb42fb3f35cd613af6fcea465e35bbfd352216

Signed-off-by: Mark Levedahl <[email protected]>
gitk in the prior commit learned to apply -profile tcl8 to all input
data streams, avoiding errors on non-binary data streams whose encoding
is not utf-8. But, gitk also consumes binary data streams (generally blobs
from commits), and internally decodes this to support various displays.

With Tcl9, errors occur in this decoding for the same reasons described
in the previous commit: basically, the underlying data was not validated
to conform to the given encoding, and this source encoding may not be
utf-8. gitk performs this decoding using Tcl's '[encoding convert from'
operator.

For example, the 7th commit in gitk's history has the extended ascii
value 0xA9, so

	gitk 9a40c50

in gitk's repository raises an exception. The error log has:

unexpected byte sequence starting at index 11: '\xA9'
    while executing
"encoding convertfrom $diffencoding $line"
    (procedure "parseblobdiffline" line 135)
    invoked from within
"parseblobdiffline $ids $line"
    (procedure "getblobdiffline" line 16)
    invoked from within
"getblobdiffline file6 9a40c50"
    ("eval" body line 1)
    invoked from within
"eval $script"
    (procedure "dorunq" line 11)
    invoked from within
"dorunq"
    ("after" script)

This problem has a similar fix to the prior issue: we must use the tlc8
profile when converting this data. Do so, again only on Tcl9 as Tcl8.6
does not recognize -profile, and only Tcl 9.0 makes strict the default.

Signed-off-by: Mark Levedahl <[email protected]>
Tcl/Tk 9.0 has been released, and has shipped in Fedora 42. Prior
patches in this sequence have addressed known incompatibilities, so gitk
is now operating with Tcl9. So, let's allow Tcl9.

Signed-off-by: Mark Levedahl <[email protected]>
gitk tests for having Tk being at least 8.5 or 8.6, using this
to enable code that will not work on earlier versions. But, gitk
now requires Tcl+Tk >= 8.6, so remove code for earlier versions.

Signed-off-by: Mark Levedahl <[email protected]>
gitk checks in a few places for very early git versions, such as 1.72,
but places no restriction on what version is used. gitk is distributed
as part of the full git tree, packagers do not mix parts from different
release versions, so it is unclear what backwards compatibility is
reasonably expected.  While tolerance for a non-current git version is
good for developers, we shouldn't expect the code to add features for
newer git but operate perpetually with git circa 2007.  Also, git-gui
and gitk can both launch each other, these two programs should have
compatible minimum requirements to avoid a confusing or broken
installation.

git-gui needs git-hook-run, added in git 2.36 while git 2.50 is now
current, so 2.36 is a reasonable minimum for now. Make it so.

Signed-off-by: Mark Levedahl <[email protected]>
gitk has a few code fragments that are used only for git versions <=
1.7.2 that do not support submodules or git-notes. git 1.7.2 was
released in 2010, is long out of support, and we just set the
requirement at git >= 2.36. Those code fragments are obsolete and can
never execute. Remove them.

Signed-off-by: Mark Levedahl <[email protected]>
gitk added the option to used themed Tk (ttk) in 0cc08ff ("gitk: Add
a user preference to enable/disable use of themed widgets", 2009-09-05),
and this had to be optional as ttk was a relatively new feature not
available in all Tk 8.4 then in common use. Even so, ttk has been the
default option when using Tk >= 8.5 since the above commit.

ttk was introduced in Tk 8.5, and all ttk features used by gitk have
always been available in Tk 8.6. As gitk now requires Tk >= 8.6, keeping
ttk optional just adds multiple code paths and maintenance burdens.
Let's move on and use ttk always so we can remove the alternate code
paths.

Signed-off-by: Mark Levedahl <[email protected]>
gitk uses ${NS} to select between unthemed and themed widgets, the
former are in the anonymous global namespace, while the themed ones are
in the ttk namespace.  However, gitk now always uses themed widgets, so
this indirection now serves no purpose. Let's switch to explicit use of
ttk:: via global search/replace, and make no other changes to keep this
commit more easily verifiable.

Signed-off-by: Mark Levedahl <[email protected]>
gitk offers many variables for configuration, and has all of these
listed in $config_variables. gitk allows modification of many of these
from a dialog box, and this dialog can be cancelled requiring that any
configuration variable modified is restored to its prior value. But,
gitk maintains lists of variables that can be used in the configuration
dialog separately from $config_variables, and these lists exist
independently in more than one place in the code.

This is confusing, error prone, and unnecessary. Let's just use
$config_variables as the authoritative list in all places: a new
configuration variable need only be added to this list to be saved,
restored, and returned to its prior value after the configuration dialog
is cancelled. This does mean that more unchanged global variables are
overwritten with their current values after cancelling the configuration
dialog, but this no-op takes trivial cpu time.

Signed-off-by: Mark Levedahl <[email protected]>
With the prior commits, gitk always uses themed wigets from namespace
ttk. The code paths to use the earlier non-themed alternates still
exist, so let's remove code paths that now cannot execute.

Signed-off-by: Mark Levedahl <[email protected]>
@mark987
Copy link
Contributor Author

mark987 commented Jun 22, 2025

I've updated my branch with:

  • scrubbed commit messages
  • added [mc "Wheel scrolling multiplier"]
  • changed mouse_wheel_scale to scroll_D0, as this is expected value of %D passed into the event
  • moved the commit allowing Tcl9 until after all Tcl9 compatibility is added.
  • added a number of additional commits removing compatibility with pre 8.6 Tcl/Tk and early git.

I was holding the latter patches back until the dust settles on the first, but, you asked :^) The first one, a3a7e5e, removes have_tk85 and have_tk86. I found much more to do, though. I've been running with all of these for a while.

@j6t
Copy link
Owner

j6t commented Jun 22, 2025

Thank you for the update.

Since I have a few topics in flight that change the user-interface, I would prefer to postpone the ttk changes until those topics are merged.

Regarding the requirement of a modern git, I of course agree that we remove compatibility for ancient versions. I would nevertheless target Debian Buster as the minimum, which has Git 2.20. Looking at 8c7307e, I don't think we must require 2.36.

@mark987
Copy link
Contributor Author

mark987 commented Jun 23, 2025

The issue on git version traces to git-gui, gitk launches git-gui, so gitk logically needs git supporting gitk AND git-gui.
git added core.hooksPath in v2.10, and this broke git-gui until I patched git-gui for Junio's git 2.43 release. This relies upon git-hook-run added in v2.36. So, git-gui post 2.43 is compatible with git v2.36 and later, earlier git-gui is compatible only up to git 2.09. git 2.10 --> 2.35 is not compatible as hooks do not run (or the wrong hooks run, this got reported to me by a former colleague causing me to pursue fixing the problem).

So, git 2.20 in Debian Buster is in "no-man's" land vis-a-vis git-gui. For reasons above, I have trouble saying gitk is ok.

@j6t
Copy link
Owner

j6t commented Jun 23, 2025

But as long as Git GUI isn't used, Gitk can work just fine with a Git version before 2.36. On top of that, if the Git GUI is a version before 2.43, then it still works (it just doesn't obey core.hooksPath). So, 2.36 isn't a hard requirement for Gitk.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants