Skip to content

In linux, copying a tkinter font doubles its size when using Tk 8.6 and a hi-res screen. #128719

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
culler opened this issue Jan 10, 2025 · 7 comments
Labels
topic-tkinter type-bug An unexpected behavior, bug, or error

Comments

@culler
Copy link
Contributor

culler commented Jan 10, 2025

Bug report

Bug description:

>>> import tkinter
>>> from tkinter.font import Font
>>> root = tkinter.Tk()
>>> f1 = Font(name='TkDefaultFont', exists=True)
>>> f1.actual()
{'family': 'Noto Sans', 'size': 20, 'weight': 'normal', 'slant': 'roman', 'underline': 0, 'overstrike': 0}
>>> f2 = f1.copy()
>>> f2.actual()
{'family': 'Noto Sans', 'size': 40, 'weight': 'normal', 'slant': 'roman', 'underline': 0, 'overstrike': 0}
>>> f3 = f2.copy()
>>> f3.actual()
{'family': 'Noto Sans', 'size': 80, 'weight': 'normal', 'slant': 'roman', 'underline': 0, 'overstrike': 0}
>>> f4 = f3.copy()
>>> f4.actual()
{'family': 'Noto Sans', 'size': 160, 'weight': 'normal', 'slant': 'roman', 'underline': 0, 'overstrike': 0}

The example above is from Ubuntu 24.04 running on an Asus Zenbook with EVO screen. The display scaling from the system settings is the default, namely 200%. This does not happen when the display scaling is 100%.

Note that font f1 is already (more than) doubled in size, compared to what wish8.6 (built from 8.6.15 source) reports:

% info patchlevel
8.6.15
% font actual TkDefaultFont
-family {Noto Sans} -size 9 -weight normal -slant roman -underline 0 -overstrike 0
% font config TkDefaultFont
-family sans-serif -size -12 -weight normal -slant roman -underline 0 -overstrike 0

The negative value -12 means that the size is 12 pixels, as opposed to 12 points. I think the intitial expansion being slightly more than a factor of 2 may be caused by rounding when converting pixels to points.

Note that the behavior of Tk 9 is different. Using wish9.0 on the same system produces:

% info patchlevel
9.0.0
% font actual TkDefaultFont
-family {Noto Sans} -size 10 -weight normal -slant roman -underline 0 -overstrike 0
% font config TkDefaultFont
-family sans-serif -size 10 -weight normal -slant roman -underline 0 -overstrike 0

Also, the pending new version of tkinter from #124156 does not have this doubling behavior when used with Tk 9.0. (I have not tested the new tkinter with Tk 8.6, but I expect it to have the broken behavior since I don't think that the PR changes Font.copy.)

CPython versions tested on:

3.12

Operating systems tested on:

Linux

@culler culler added the type-bug An unexpected behavior, bug, or error label Jan 10, 2025
@NathanDunfield
Copy link

I think the doubling behavior is because tkinter's Font.copy relies on Font.actual:

def copy(self):
        "Return a distinct copy of the current font"
        return Font(self._tk, **self.actual())

On a high-res Linux screen with Ubuntu 24.04, the size and self.actual()['size'] differ, apparently by the scaling factor:

>>> import tkinter
>>> root = tkinter.Tk()
>>> f1 = Font(font='TkFixedFont')
>>> f1['size']
20
>>> f1.actual()['size']
40

This seems consistent with the Tk docs which say that font actual:

Returns information about the actual attributes that are obtained when font is used on window's display; the actual attributes obtained may differ from the attributes requested due to platform-dependant limitations, such as the availability of font families and pointsizes.

@NathanDunfield
Copy link

Also, on stock Ubuntu 24.04, I see a very different result from @culler's built-from-source Tk 8.6:

$ wish
% info patchlevel
8.6.14
% font actual TkDefaultFont
-family {Noto Sans} -size 20 -weight normal -slant roman -underline 0 -overstrike 0
% font config TkDefaultFont
-family sans-serif -size 10 -weight normal -slant roman -underline 0 -overstrike 0

Note everything here is in points, not a mix of points and pixels. The same difference between config and actual shows up in user-defined fonts:

% font create MyFont -family {Noto Sans} -size 8
MyFont
% font actual MyFont
-family {Noto Sans} -size 16 -weight normal -slant roman -underline 0 -overstrike 0
% font config MyFont
-family {Noto Sans} -size 8 -weight normal -slant roman -underline 0 -overstrike 0

@culler
Copy link
Contributor Author

culler commented Jan 11, 2025

This is probably a difference between 8.6.14 and 8.6.15. There is now a release of 8.6.16. I will report if it differs from 8.6.15.

@NathanDunfield
Copy link

@culler: I think this Tk ticket is related.

@culler
Copy link
Contributor Author

culler commented Jan 11, 2025

Indeed! It looks like they ended up fixing a related Tk bug but never got to the tkinter issue raised in the original report, which seems to be the same as this one..

@NathanDunfield
Copy link

I installed the proposed Ubuntu package libtk 8.6.16-1 by downloading the binary from launchpad. Now I get:

% font actual TkDefaultFont
-family {Noto Sans} -size 10 -weight normal -slant roman -underline 0 -overstrike 0
% font config TkDefaultFont
-family sans-serif -size 10 -weight normal -slant roman -underline 0 -overstrike 0
% font create MyFont -family {Noto Sans} -size 8
MyFont
% font actual MyFont
-family {Noto Sans} -size 8 -weight normal -slant roman -underline 0 -overstrike 0
% font config MyFont
-family {Noto Sans} -size 8 -weight normal -slant roman -underline 0 -overstrike 0

@NathanDunfield
Copy link

I'm thinking maybe there's nothing to do here for tkinter. I suspect it would have been a better design to have Font.copy() invoke config instead of actual as this seems like a poor copy:

>>> f1 = Font(family='sans-serif', size='10')
>>> f1['family']
'sans-serif'
>>> f1.copy()['family']
'Noto Sans '

However, if Tk itself is working right, they should always display the same. Moreover, Font.__init__ invokes actual which is why one sees:

>>> Font(font='TkDefaultFont').config()['family']
'Noto Sans`

whereas wish would say sans-serif. But presumably changing from actual to config would cause minor havoc and be more trouble than it's worth.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic-tkinter type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

3 participants