FromDIP, wxHAVE_DPI_INDEPENDENT_PIXELS and Fractional Scaling

339 views
Skip to first unread message

Iwbnwif Yiw

unread,
Oct 29, 2019, 7:40:38 PM10/29/19
to wx-dev
window.h  defines "wxHAVE_DPI_INDEPENDENT_PIXELS" if __WXGTK3__ is defined.

The note says // FromDIP() and ToDIP() become trivial in this case, so make them inline to avoid any overhead.

Therefore, FromDIP(100) simply returns 100.

I think the intention is that GTK+3 has display scaling built in and so a 100,100 rectangle will be scaled by the appropriate amount and converted to (for example) 200,200 physical pixels if the display scaling is 2.

However, this toolkit conversion does not seem to work for fractional scales. 

KDE (and to a lesser extent Gnome) has some fractional scaling support. For example, on my 4k displays, I can set a display scale of 1.3. This is good, because it means everything appears a sensible size (1.0 is too small and 2.0 is huge). 

There appears to be two aspects to display scaling on KDE, font scaling and general display scaling.

Font scaling allows the user to define a Fonts DPI, and scales text correspondingly. This value can be adjusted independently, but is also set automatically when adjusting the general display scaling value.  In my case, setting display scaling to 1.3 automatically adjusts the font DPI to 125 (e.g. 96 * 1.3).

Therefore, I propose to use a different method for wxWindow::GetContentScalingFactor and wxWindow::FromDIP etc.

I think that gdk_screen_get_resolution returns the user set font DPI (in my case 125). This can be used to determine the scaling factor (125 / 96 = 1.3) which can be compared to gtk_widget_get_scale_factor if necessary. 

This may not handle situations where the user has overridden the font DPI compared to the screen DPI, I still think it provides a reasonable compromise.

It may also be useful to provide a global method of setting the scaling factor for situations where the built-in automatic ones fail, or no longer work due to a library (e.g. gdk) change or some weird user / display configuration.












Vadim Zeitlin

unread,
Oct 29, 2019, 8:50:44 PM10/29/19
to wx-...@googlegroups.com
On Tue, 29 Oct 2019 16:40:38 -0700 (PDT) Iwbnwif Yiw wrote:

IY> window.h defines "wxHAVE_DPI_INDEPENDENT_PIXELS" if __WXGTK3__ is defined.
IY>
IY> The note says // FromDIP() and ToDIP() become trivial in this case, so make
IY> them inline to avoid any overhead.
IY>
IY> Therefore, FromDIP(100) simply returns 100.
IY>
IY> I think the intention is that GTK+3 has display scaling built in and so a
IY> 100,100 rectangle will be scaled by the appropriate amount and converted to
IY> (for example) 200,200 physical pixels if the display scaling is 2.

Yes, indeed.

IY> However, this toolkit conversion does not seem to work for fractional
IY> scales.

One big problem is that even if it worked, we'd still suffer from rounding
problems as all our coordinates are integers. But unfortunately I don't
think we can realistically do anything about this.

IY> KDE (and to a lesser extent Gnome) has some fractional scaling support. For
IY> example, on my 4k displays, I can set a display scale of 1.3. This is good,
IY> because it means everything appears a sensible size (1.0 is too small and
IY> 2.0 is huge).
IY>
IY> There appears to be two aspects to display scaling on KDE, font scaling and
IY> general display scaling.
IY>
IY> Font scaling allows the user to define a Fonts DPI, and scales text
IY> correspondingly.

I wonder how is this different from just changing the size of the default
system font?

IY> This value can be adjusted independently, but is also set
IY> automatically when adjusting the general display scaling value.

This is also a mystery to me: why would fonts need to be adjusted at all
if the DPI is already appropriate? I've never used GTK with fractional
scaling, but with 2x scaling the fonts are twice as big, yet they don't use
any special scaling, they just get adjusted along with everything else.

IY> In my case, setting display scaling to 1.3 automatically adjusts the
IY> font DPI to 125 (e.g. 96 * 1.3).
IY>
IY> Therefore, I propose to use a different method for
IY> wxWindow::GetContentScalingFactor and wxWindow::FromDIP etc.
IY>
IY> I think that gdk_screen_get_resolution returns the user set font DPI (in my
IY> case 125).

It doesn't make any sense to use font DPI for screen resolution, but this
doesn't necessarily prevent GTK from doing this, of course...

IY> This can be used to determine the scaling factor (125 / 96 =
IY> 1.3) which can be compared to gtk_widget_get_scale_factor if necessary.

So what does gtk_widget_get_scale_factor() return in this case? Still 1?

IY> This may not handle situations where the user has overridden the font DPI
IY> compared to the screen DPI, I still think it provides a reasonable
IY> compromise.

It could conceivably also make things worse if we choose between them
wrongly.

IY> It may also be useful to provide a global method of setting the scaling
IY> factor for situations where the built-in automatic ones fail, or no longer
IY> work due to a library (e.g. gdk) change or some weird user / display
IY> configuration.

So we would probably indeed need something like WX_SCALE...

Would anyone know about any source of information about fractional scaling
support in GTK anywhere? All I could find with a (admittedly very quick)
search was stuff about Gnome, but nothing about GTK API for this itself.

Thanks,
VZ

Iwbnwif Yiw

unread,
Oct 30, 2019, 7:22:27 AM10/30/19
to wx-dev
On Wednesday, October 30, 2019 at 12:50:44 AM UTC, VZ wrote:

Firstly, thank you for the fast reply again. OT, but one day you should write a self-help book on how to consistently stay with a project through thick and thin!!

IY> I think the intention is that GTK+3 has display scaling built in and so a
IY> 100,100 rectangle will be scaled by the appropriate amount and converted to
IY> (for example) 200,200 physical pixels if the display scaling is 2.

 Yes, indeed.

Thank you for this confirmation. It was my fundamental misunderstanding that Windows doesn't do this (I assumed it did). Finally, this summary helped - https://doc.qt.io/qt-5/highdpi.html in particular the section:

"The user can choose a scaling factor from the control panel or via context menu. This works by making the functions for querying the system metrics return different values for standard font sizes, sizes of window borders, and so on. It does not perform any actual scaling."

Unfortunately, linux, KDE or GTK are not covered in the article.
 
IY> However, this toolkit conversion does not seem to work for fractional
IY> scales.

 One big problem is that even if it worked, we'd still suffer from rounding
problems as all our coordinates are integers. But unfortunately I don't
think we can realistically do anything about this.

It might be the lesser of two evils. We should at least be able to scale fonts and anything drawn with a wxGraphicsContext / wxGCDC properly?
 
IY> There appears to be two aspects to display scaling on KDE, font scaling and
IY> general display scaling.
IY>
IY> Font scaling allows the user to define a Fonts DPI, and scales text
IY> correspondingly.

 I wonder how is this different from just changing the size of the default
system font?

I think this depends very much on how the individual application has been written, what toolkit has been used etc. 

I bought my two 4k displays just under a year ago thinking it would be utopia for long hours of typing, unfortunately it has been nothing but a world of pain :(. I regularly use software such as KiCAD, FreeCAD, LibreOffice, Kdenlive, etc. and it has taken ages to find a combination where they display more or less okay. Still, there are the odd dialog where the fonts / icons are uncomfortably small or ridiculously huge. This isn't limited to Linux, but also on Windows and not just free software either.

I am guessing, but I suspect some apps try to work around software limitations by using font metrics, whilst others use more recent toolkit / OS calls. It all depends on which one as to how the final results work on a specific system setup.
 
IY> This value can be adjusted independently, but is also set
IY> automatically when adjusting the general display scaling value.

 This is also a mystery to me: why would fonts need to be adjusted at all
if the DPI is already appropriate? I've never used GTK with fractional
scaling, but with 2x scaling the fonts are twice as big, yet they don't use
any special scaling, they just get adjusted along with everything else.

I cannot understand this either, unless it has been put in place as a brute force method to compensate for earlier application shortcomings. For example, if toolbar icons are selected / scaled based on some get_font_metrics call against a reference font size. Alternatively, I think the font DPI / scaling is a much older API function related to accessibility and / or themes.

Also there is a discussion here that kind of implies that fonts are scaled automatically, but other things aren't:


I have tried (and so far failed) to work out how wxDataViewCtrl appears about right, but wxTreeCtrl, wxSTC and wxPropertyGrid all get it wrong. I will send some screenshots later today of the unmodified examples to show this.
 
IY> I think that gdk_screen_get_resolution returns the user set font DPI (in my
IY> case 125).

 It doesn't make any sense to use font DPI for screen resolution, but this
doesn't necessarily prevent GTK from doing this, of course...

I think this is just badly named. The description in the GDK manual says it "Sets the resolution for font handling on the screen." here:


There is also some useful information in this thread:


IY> This can be used to determine the scaling factor (125 / 96 =
IY> 1.3) which can be compared to gtk_widget_get_scale_factor if necessary.

 So what does gtk_widget_get_scale_factor() return in this case? Still 1?

Yes, but it more depends on the value set for the general display scaling (e.g. GDK_SCALE) rather than the font scale (e.g. GDK_DPI_SCALE). It can only return an integer and appears to be rounded down (not exhaustively tested by me but see this table https://bugs.eclipse.org/bugs/show_bug.cgi?id=489771#c40).
 
IY> This may not handle situations where the user has overridden the font DPI
IY> compared to the screen DPI, I still think it provides a reasonable
IY> compromise.

 It could conceivably also make things worse if we choose between them
wrongly.

Absolutely! That is a good point, particularly when a large font has been set perhaps for accessibility reasons. 
 
IY> It may also be useful to provide a global method of setting the scaling
IY> factor for situations where the built-in automatic ones fail, or no longer
IY> work due to a library (e.g. gdk) change or some weird user / display
IY> configuration.

 So we would probably indeed need something like WX_SCALE...

Yes, and also some API functions such as wxDisplay::SetScreenScale (bitmaps, DC etc.) and wxDisplay::SetFontScale (text). I would then provide a dialog option to override the default values.

Of course, I could do that now but it would mean sub-classing all the built in widgets.
 
 Would anyone know about any source of information about fractional scaling
support in GTK anywhere? All I could find with a (admittedly very quick)
search was stuff about Gnome, but nothing about GTK API for this itself.

This is really the nub of the problem, the documentation is pretty sketchy and the terminology is so ambiguous - not to mention the extreme platform differences! It may be worse on Linux because X11 and Wayland could be different also. 

I've spent hours on and off trawling for information on this and only so far found a few useful threads on the subject.

Eran of Codelite fame has a pretty good understanding and Codelite is starting it handle it quite well - at least on the two platforms I use (Windows and Ubuntu). Also, I will try to be more organised in building a repository of useful information links and continue with the testing.

Vadim Zeitlin

unread,
Oct 30, 2019, 9:48:31 AM10/30/19
to wx-...@googlegroups.com
On Wed, 30 Oct 2019 04:22:27 -0700 (PDT) Iwbnwif Yiw wrote:

IY> Firstly, thank you for the fast reply again. OT, but one day you should
IY> write a self-help book on how to consistently stay with a project through
IY> thick and thin!!

I've made a special effort for 3.1.3 release and I'm still continuing by
inertia for now but, to be honest, I really ought to stop spending so much
time on wx stuff and concentrate more on my work instead. I.e. objectively
speaking I'm pretty sure the most *self*-helping answer would be to not do
this at all. Luckily, I was never one for following anybody's advice,
including my own.

IY> > IY> I think the intention is that GTK+3 has display scaling built in
IY> > IY> and so a 100,100 rectangle will be scaled by the appropriate
IY> > IY> amount and converted to (for example) 200,200 physical pixels if
IY> > IY> the display scaling is 2.
IY> >
IY> > Yes, indeed.
IY> >
IY>
IY> Thank you for this confirmation. It was my fundamental misunderstanding
IY> that Windows doesn't do this (I assumed it did).

I'm not sure how to interpret this but, to be clear, MSW doesn't do any
scaling at all for us automatically, which is why we need to do it
ourselves. Both Cocoa and GTK perform the scaling internally, i.e. they
work with logical pixels, but MSW always works with physical pixels.

IY> Also there is a discussion here that kind of implies that fonts are scaled
IY> automatically, but other things aren't:
IY>
IY> https://wiki.archlinux.org/index.php/HiDPI#GDK_3_(GTK_3)

OTOH https://developer.gnome.org/gtk3/stable/gtk-x11.html seems to imply
that GDK_DPI_SCALE is useful for "scale-unaware applications", which would
make sense.

IY> I have tried (and so far failed) to work out how wxDataViewCtrl appears
IY> about right, but wxTreeCtrl, wxSTC and wxPropertyGrid all get it wrong.

The difference is, of course, that wxDataViewCtrl is native, i.e. uses GTK
mechanisms for scaling, while the rest of these classes are not. So it's
not surprising per se, it just means that we have to fix wxTreeCtrl &c to
do the right thing under GTK.

IY> > IY> I think that gdk_screen_get_resolution returns the user set font DPI
IY> > IY> (in my case 125).
IY> >
IY> > It doesn't make any sense to use font DPI for screen resolution, but
IY> > this doesn't necessarily prevent GTK from doing this, of course...
IY>
IY> I think this is just badly named. The description in the GDK manual
IY> says it *"Sets the resolution for font handling on the screen."* here:
IY>
IY> https://developer.gnome.org/gdk3/stable/GdkScreen.html#gdk-screen-get-resolution

Ah, I see, thanks. Somehow I've missed this, even though I must have read
these docs a dozen of times. So this does look like the function to use, as
it should take into account all kinds of scaling and can deal with
fractional scaling. Unfortunately it's also the only DPI-related GTK
functions our code does _not_ use right now :-(

IY> There is also some useful information in this thread:
IY>
IY> https://bugs.eclipse.org/bugs/show_bug.cgi?id=489771

I got a bit lost here...

IY> > So what does gtk_widget_get_scale_factor() return in this case? Still 1?
IY> >
IY>
IY> Yes, but it more depends on the value set for the general display scaling
IY> (e.g. GDK_SCALE) rather than the font scale (e.g. GDK_DPI_SCALE). It can
IY> only return an integer and appears to be rounded down (not exhaustively
IY> tested by me but see this table
IY> https://bugs.eclipse.org/bugs/show_bug.cgi?id=489771#c40).

... but this table seems to confirm that gdk_screen_get_resolution() is the
function to use.

Unfortunately there is one big problem here: I don't see any equivalent
for this function in GdkMonitor, so it simply can't be used with multiple
monitors. So finally I still have no idea about what to do.

IY> Eran of Codelite fame has a pretty good understanding and Codelite is
IY> starting it handle it quite well - at least on the two platforms I use
IY> (Windows and Ubuntu). Also, I will try to be more organised in building a
IY> repository of useful information links and continue with the testing.

We basically need a way to get the DPI/scaling values compatible with what
everybody else uses. I.e. it's less important for them to be "right" (which
they should currently be in wxGTK, as we really compute DPI by dividing the
number of dots by the number of inches), than to be the same as in all the
other applications on the system. Unfortunately I still have no idea about
how to do it with GTK API.

The good thing is that if native GTK apps work correctly for you even with
fractional scaling, this ought to be possible. We "just" need to find out
how.

Regards,
VZ

Iwbnwif Yiw

unread,
Oct 30, 2019, 7:34:23 PM10/30/19
to wx-dev
On Wednesday, October 30, 2019 at 1:48:31 PM UTC, VZ wrote:

Sorry, I have gone down several rabbit holes trying to work this out today! Unfortunately, without much progress...
 
... but this table seems to confirm that gdk_screen_get_resolution() is the
function to use.

 Unfortunately there is one big problem here: I don't see any equivalent
for this function in GdkMonitor, so it simply can't be used with multiple
monitors. So finally I still have no idea about what to do.
 
 We basically need a way to get the DPI/scaling values compatible with what
everybody else uses. I.e. it's less important for them to be "right" (which
they should currently be in wxGTK, as we really compute DPI by dividing the
number of dots by the number of inches), than to be the same as in all the
other applications on the system. Unfortunately I still have no idea about
how to do it with GTK API.

 The good thing is that if native GTK apps work correctly for you even with
fractional scaling, this ought to be possible. We "just" need to find out
how.

I will keep searching and post back when I have found something that may be useful. 

Iwbnwif Yiw

unread,
Nov 2, 2019, 4:30:10 AM11/2/19
to wx-dev
On Wednesday, October 30, 2019 at 1:48:31 PM UTC, VZ wrote:

So, after quite a lot of searching, I am still not much further forwards! But anyway, there are a few notes / points that may be of interest. If nothing else, for me to come back to later and hopefully not repeat myself.

 I'm not sure how to interpret this but, to be clear, MSW doesn't do any
scaling at all for us automatically, which is why we need to do it
ourselves. Both Cocoa and GTK perform the scaling internally, i.e. they
work with logical pixels, but MSW always works with physical pixels.

Yes, this was my understanding too and what I was trying to say (badly). 

However, it looks to me that GTK doesn't actually perform any scaling, that is done by Mutter. 

There is quite a good description here: https://mail.gnome.org/archives/gnome-shell-list/2017-June/msg00000.html although no actual details on the API. This is linked from https://wiki.gnome.org/Hackfests/FractionalScaling2017 which also has links to a blog post and Github changes - but I think this does not represent the final version. 

The closest thing that I have found so far to an 'API' is here: https://github.com/GNOME/mutter/blob/master/src/backends/meta-monitor-config-manager.c and here: https://github.com/GNOME/mutter/blob/master/src/backends/meta-settings.c but this may be a red herring. 

But from what I can tell, these functions are not accessed directly, but through an interface - (D-BUS?) maybe this one: https://github.com/GNOME/mutter/blob/master/src/org.gnome.Mutter.DisplayConfig.xml

Note: Sometimes scale is a float/double and sometimes an int. Just because it is an int doesn't mean it isn't fractional because the int can have values up to 8 representing 50% - 400% respectively.

Testing both X11 and (finally) Wayland seems to imply that this type of scaling affects everything and is sort of at a bitmap (framebuffer?) level. IMO that isn't particularly interesting for us because we just draw as normal and Mutter takes care of it.

KDE takes a different approach, more like windows. The 'display scaling' factor is not per monitor (although the UI makes it look like it) and seems to only affect things like title bar size and maybe some layout spacing.

In short, I am not sure how to interpret these fractional 'display' scales at all even if we had the API!
 
 OTOH https://developer.gnome.org/gtk3/stable/gtk-x11.html seems to imply
that GDK_DPI_SCALE is useful for "scale-unaware applications", which would
make sense.

Yes, this may be a useful value to access. If the Mutter framebuffer scaling is in operation (or GDK_SCALE?), we may want to use this to stop things getting too big. But this may have its own problems, because Wayland is handled differently (whole screen vs actor) from X11!!
 
The difference is, of course, that wxDataViewCtrl is native, i.e. uses GTK
mechanisms for scaling, while the rest of these classes are not. So it's
not surprising per se, it just means that we have to fix wxTreeCtrl &c to
do the right thing under GTK.

Yes, I think this is the most important thing right now. 

 Ah, I see, thanks. Somehow I've missed this, even though I must have read
these docs a dozen of times. So this does look like the function to use, as
it should take into account all kinds of scaling and can deal with
fractional scaling. Unfortunately it's also the only DPI-related GTK
functions our code does _not_ use right now :-( 
 
... but this table seems to confirm that gdk_screen_get_resolution() is the
function to use.

Yes, I agree that is the first one to implement because it can help sort out wxTreeCtrl etc. I have made a quick hack (see attached) to wxCairoContext to adjust font sizes on the fly (just before rendering). This works with all the samples that I was having problems with before.
 
 Unfortunately there is one big problem here: I don't see any equivalent
for this function in GdkMonitor, so it simply can't be used with multiple
monitors. So finally I still have no idea about what to do.

I haven't found any per monitor font scaling and I don't think there is anything that can be done here.
 
We basically need a way to get the DPI/scaling values compatible with what
everybody else uses. I.e. it's less important for them to be "right" (which
they should currently be in wxGTK, as we really compute DPI by dividing the
number of dots by the number of inches), than to be the same as in all the
other applications on the system. Unfortunately I still have no idea about
how to do it with GTK API.

My suggestion is to focus on font scaling and other things that are related to text size initially. As discussed above,  gdk_screen_get_resolution() is our friend for that and works on both Gnome and KDE - it is just a matter of deciding where to put it. If we include a wxDisplay::GetFontScalingFactor() (for example) then people can scale bitmaps / drawings etc. if they want to.
 
scale_test.diff
widgets.png
widgets2.png

Iwbnwif Yiw

unread,
Nov 2, 2019, 4:34:51 AM11/2/19
to wx-dev
I should have said that widgets.png in my previous email is without my patch applied and widgets2.png is with it applied.

Vadim Zeitlin

unread,
Nov 2, 2019, 11:14:52 AM11/2/19
to wx-...@googlegroups.com
On Sat, 2 Nov 2019 01:30:10 -0700 (PDT) Iwbnwif Yiw wrote:

IY> > I'm not sure how to interpret this but, to be clear, MSW doesn't do any
IY> > scaling at all for us automatically, which is why we need to do it
IY> > ourselves. Both Cocoa and GTK perform the scaling internally, i.e. they
IY> > work with logical pixels, but MSW always works with physical pixels.
IY>
IY> Yes, this was my understanding too and what I was trying to say (badly).
IY>
IY> However, it looks to me that GTK doesn't actually perform any scaling,

It definitely does with GDK_SCALE. And when using 2x scaling on my high
DPI display the GTK "application pixels" are twice bigger (i.e. the
coordinates expressed in them are twice smaller) than the physical pixels.

IY> > ... but this table seems to confirm that gdk_screen_get_resolution() is
IY> > the function to use.
IY>
IY> Yes, I agree that is the first one to implement because it can help sort
IY> out wxTreeCtrl etc. I have made a quick hack (see attached) to
IY> wxCairoContext to adjust font sizes on the fly (just before rendering).
IY> This works with all the samples that I was having problems with before.

So we need to do something like this because it helps with people using
fractional scaling on a single monitor and probably (but this would need to
be tested) doesn't really harm people using multiple monitors with
different DPIs.

Could you please check if scaling by this factor (which probably should be
cached) in the Pango version of wxNativeFontInfo::SetFractionalPointSize()
in src/unix/fontutil.cpp works for you as well? If so, please don't
hesitate to make a PR with this change.

TIA,
VZ

Iwbnwif Yiw

unread,
Nov 3, 2019, 6:07:03 AM11/3/19
to wx-dev
On Saturday, November 2, 2019 at 3:14:52 PM UTC, VZ wrote:

 It definitely does with GDK_SCALE. And when using 2x scaling on my high
DPI display the GTK "application pixels" are twice bigger (i.e. the
coordinates expressed in them are twice smaller) than the physical pixels.

You are absolutely right of course - I hadn't appreciated this.
 
 Could you please check if scaling by this factor (which probably should be 
cached) in the Pango version of wxNativeFontInfo::SetFractionalPointSize()
in src/unix/fontutil.cpp works for you as well? If so, please don't
hesitate to make a PR with this change.

I was thinking that the value should be cached, but I haven't come up with a good place to cache it. 

wxNativeFontInfo::SetFractionalPointSize() works perfectly - thanks for that tip! This means we don't need to change graphicc.cpp at all.

I would still like to include a manual override, because there are so many combinations (Gnome vs KDE, X11 vs Wayland, LXDE etc.) that could end up with something going wrong. 

My inclination is to put it in wxDisplay (see attached patch), because it feels like a natural home (even though at the moment it is system wide rather than display specific). My reluctance with my current patch is that it calls the top level wxDisplay rather than the GTK implementation which is a little wasteful, but maybe not an issue. Also, it is not really caching - but AFAICT there is no static wxDisplay-type object available under GTK builds.

Anyway, if there is basic agreement for this change, I will create a more complete PR this evening and we can discuss it further there.

scale_font.diff

Vadim Zeitlin

unread,
Nov 3, 2019, 10:40:32 AM11/3/19
to wx-...@googlegroups.com
On Sun, 3 Nov 2019 03:07:02 -0800 (PST) Iwbnwif Yiw wrote:

IY> > Could you please check if scaling by this factor (which probably should
IY> > be cached) in the Pango version of wxNativeFontInfo::SetFractionalPointSize()
IY> > in src/unix/fontutil.cpp works for you as well? If so, please don't
IY> > hesitate to make a PR with this change.
IY>
IY> I was thinking that the value should be cached, but I haven't come up with
IY> a good place to cache it.

To begin with, we may not cache it at all, the overhead of calling a
couple of almost trivial GDK functions shouldn't be too big. Later/ideally
we should do it somewhere where we can subscribe to the changes to
PROP_RESOLUTION property of GdkScreen by connecting to its "notify" signal.

IY> wxNativeFontInfo::SetFractionalPointSize() works perfectly - thanks for
IY> that tip! This means we don't need to change graphicc.cpp at all.
IY>
IY> I would still like to include a manual override, because there are so many
IY> combinations (Gnome vs KDE, X11 vs Wayland, LXDE etc.) that could end up
IY> with something going wrong.

I think GDK_DPI_SCALE *is* the manual override, so I don't think we need
another one.

IY> My inclination is to put it in wxDisplay (see attached patch), because it
IY> feels like a natural home (even though at the moment it is system wide
IY> rather than display specific).

I agree that it makes sense to have it in wxDisplay conceptually, but I
don't like fixing the API for this before we really know what are we doing.
I.e. things may (and hopefully will) change in the future, so for now I'd
avoid any changes to the public API and just fix this inside wxGTK.

Also, even though this ought to be display-dependent, not only currently
it isn't, but the way we use it, inside wxNativeFontInfo, where no display
is or can ever be available, actually makes this potential dependence on
the display useless, as we're always going to use the primary display here,
just because there is nothing else we can do.

So I'd really prefer to keep things simple and just use the font scaling
factor directly in SetFractionalPointSize() for now. We can always expose
it in some nice API later. The only thing to watch for is that this code is
also compiled as part of wxX11, so it should be enclosed in __WXGTK__
preprocessor checks.

Thanks,
VZ

Iwbnwif Yiw

unread,
Nov 3, 2019, 11:35:13 AM11/3/19
to wx-dev


On Sunday, November 3, 2019 at 3:40:32 PM UTC, VZ wrote:

IY> I would still like to include a manual override, because there are so many
IY> combinations (Gnome vs KDE, X11 vs Wayland, LXDE etc.) that could end up
IY> with something going wrong.

 I think GDK_DPI_SCALE *is* the manual override, so I don't think we need
another one.

Okay, fair enough.
 
IY> My inclination is to put it in wxDisplay (see attached patch), because it
IY> feels like a natural home (even though at the moment it is system wide
IY> rather than display specific).

 I agree that it makes sense to have it in wxDisplay conceptually, but I
don't like fixing the API for this before we really know what are we doing.
I.e. things may (and hopefully will) change in the future, so for now I'd
avoid any changes to the public API and just fix this inside wxGTK.

 Also, even though this ought to be display-dependent, not only currently
it isn't, but the way we use it, inside wxNativeFontInfo, where no display
is or can ever be available, actually makes this potential dependence on
the display useless, as we're always going to use the primary display here,
just because there is nothing else we can do.

 So I'd really prefer to keep things simple and just use the font scaling
factor directly in SetFractionalPointSize() for now. We can always expose
it in some nice API later. The only thing to watch for is that this code is
also compiled as part of wxX11, so it should be enclosed in __WXGTK__
preprocessor checks.

Okay, I understand your reasoning for not wanting to change the API at this stage. It also makes it a much simpler PR :).

How do you feel about including it as an undocumented / experimental feature in wxDisplay? 

The reason for asking is that my next challenge will be to make wxRibbonBar look nice with fractional scaling!! To do this, I need to pick or scale bitmaps appropriately and scale other elements such as the gallery.

Furthermore, anything drawn using a wxGraphicsContext or wxGCDC can be very easily scaled with the fractional value if it is exposed (I am already doing this using gdk_screen_get_resolution).


Vadim Zeitlin

unread,
Nov 3, 2019, 1:22:08 PM11/3/19
to wx-...@googlegroups.com
On Sun, 3 Nov 2019 08:35:13 -0800 (PST) Iwbnwif Yiw wrote:

IY> Okay, I understand your reasoning for not wanting to change the API at this
IY> stage. It also makes it a much simpler PR :).

Yes, this is another important advantage.

IY> How do you feel about including it as an undocumented / experimental
IY> feature in wxDisplay?

Undocumented/experimental features are even worse than other ones, because
they still end up being used by the code outside of the library...

IY> The reason for asking is that my next challenge will be to make wxRibbonBar
IY> look nice with fractional scaling!! To do this, I need to pick or scale
IY> bitmaps appropriately and scale other elements such as the gallery.

But shouldn't wxWindow::GetContentScaleFactor() be used for this? I.e.
shouldn't we just take this factor into account in wxGTK implementation?
My reasoning is that this function still needs to be used under MSW and
Mac, so why not GTK too?

Regards,
VZ

Iwbnwif Yiw

unread,
Nov 3, 2019, 3:31:04 PM11/3/19
to wx-dev
I have created the following PR https://github.com/wxWidgets/wxWidgets/pull/1635 to address this issue.

Iwbnwif Yiw

unread,
Nov 3, 2019, 3:37:28 PM11/3/19
to wx-dev
On Sunday, November 3, 2019 at 6:22:08 PM UTC, VZ wrote:
 
IY> The reason for asking is that my next challenge will be to make wxRibbonBar 
IY> look nice with fractional scaling!! To do this, I need to pick or scale
IY> bitmaps appropriately and scale other elements such as the gallery.

 But shouldn't wxWindow::GetContentScaleFactor() be used for this? I.e.
shouldn't we just take this factor into account in wxGTK implementation?
My reasoning is that this function still needs to be used under MSW and
Mac, so why not GTK too?

Hmm, wxWindow::GetContentScaleFactor uses gtk_widget_get_scale_factor internally which can only ever return an integer (usually 1 or 2) as I am sure you are aware.

The problem is that I need the fractional scaling factor. Are you suggesting that we use gdk_screen_get_resolution instead in wxWindow::GetContentScaleFactor?

Eran Ifrah

unread,
Nov 3, 2019, 5:32:11 PM11/3/19
to wx-dev
I am not sure my email was received by the mailing list, so I am reposting.
sorry if it did :)

This is how I get my ratio (for fonts, but it should be the same for bitmaps):

wxFont clScrolledPanel::GetDefaultFont()
{
    wxFont f = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
#ifdef __WXGTK__
    static double ratio = 1.0;
    static bool once = false;
    if(!once) {
        GdkScreen* screen = gdk_screen_get_default();
        if(screen) {
            double res = gdk_screen_get_resolution(screen);
            ratio = (res / 96.);
        }
        once = true;
    }
#if wxCHECK_VERSION(3, 1, 2)
    float pointSize = f.GetFractionalPointSize() * ratio;
    f.SetFractionalPointSize(pointSize);
#else
    int pointSize = f.GetPointSize() * ratio;
    f.SetPointSize(pointSize);
#endif
#endif
    return f;
}

Note that this method uses gdk_screen_get_default(), which returns the main screen. If you have multiple screens, you will need to decide which screen to use.
96 is the standard DPI. This will give you the ratio needed for the bitmaps (you can then decide if to load @2 or @1.5 bitmaps)

Eran
 

Vadim Zeitlin

unread,
Nov 3, 2019, 5:56:12 PM11/3/19
to wx-...@googlegroups.com
On Sun, 3 Nov 2019 13:36:19 -0800 (PST) Eran Ifrah wrote:

EI> On Sunday, November 3, 2019 at 10:37:28 PM UTC+2, Iwbnwif Yiw wrote:
EI> >
EI> > On Sunday, November 3, 2019 at 6:22:08 PM UTC, VZ wrote:
...
EI> >> But shouldn't wxWindow::GetContentScaleFactor() be used for this? I.e.
EI> >> shouldn't we just take this factor into account in wxGTK implementation?
EI> >> My reasoning is that this function still needs to be used under MSW and
EI> >> Mac, so why not GTK too?
EI> >
EI> > Hmm, wxWindow::GetContentScaleFactor uses gtk_widget_get_scale_factor
EI> > internally which can only ever return an integer (usually 1 or 2) as I am
EI> > sure you are aware.
EI> >
EI> > The problem is that I need the fractional scaling factor. Are you
EI> > suggesting that we use gdk_screen_get_resolution instead in
EI> > wxWindow::GetContentScaleFactor?

I think so, yes.

EI> I am not sure my email was received by the mailing list, so I am reposting.
EI> sorry if it did :)

The message got delayed by Google for some mysterious reason impenetrable
to mere mortals. I've accepted this one and removed the other one to avoid
duplicate posts, but unfortunately that's all I can do.

EI> This is how I get my ratio (for fonts, but it should be the same for
EI> bitmaps):
EI>
EI> wxFont clScrolledPanel::GetDefaultFont()
EI> {
EI> wxFont f = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
EI> #ifdef __WXGTK__
EI> static double ratio = 1.0;
EI> static bool once = false;
EI> if(!once) {
EI> GdkScreen* screen = gdk_screen_get_default();
EI> if(screen) {
EI> double res = gdk_screen_get_resolution(screen);
EI> ratio = (res / 96.);
EI> }
EI> once = true;
EI> }
EI> #if wxCHECK_VERSION(3, 1, 2)
EI> float pointSize = f.GetFractionalPointSize() * ratio;
EI> f.SetFractionalPointSize(pointSize);
EI> #else
EI> int pointSize = f.GetPointSize() * ratio;
EI> f.SetPointSize(pointSize);
EI> #endif
EI> #endif
EI> return f;
EI> }

This seems exactly what https://github.com/wxWidgets/wxWidgets/pull/1635
does. Note that you will need to change the code above to avoid doing any
scaling of your own with wx 3.1.4.

Do you have any experience with changing the resolution while the program
is running? As I wrote in my previous message in this thread, I think we
ought to monitor the resolution property for changes, but I haven't
actually tested this.

EI> Note that this method uses gdk_screen_get_default(), which returns the main
EI> screen. If you have multiple screens, you will need to decide which screen
EI> to use.

Yes, and this is just ridiculous because even though GDK does provide a
way to query the DPI of different monitors, it looks like we must actually
use this function, which doesn't allow to specify the monitor instead, in
order to actually do what the users expect.

Regards,
VZ

Teodor Petrov

unread,
Nov 4, 2019, 3:35:43 AM11/4/19
to wx-...@googlegroups.com
Hello,

This is what Code::Blocks is using at the moment:
https://github.com/obfuscated/codeblocks_sf/blob/master/src/sdk/globals.cpp#L1176
Also as previously mentioned I have to use the wxBitmap constructor
which allows me to undo the scaling of the OS.
C::B is not monitoring any resolution changes. It probably fails badly
on multi-monitor setups.
And there are chicken-egg problems related to this code: You need the
monitor in your window's constructor,
but you don't know what the window manager would do and where it will
place your window, so you have no
chance of getting the proper value.

I think we should make the controls work with ArtProviders and do the
sizing on the fly (call the art provider
at the time of drawing things) and specify the size they actually need.
I know this would create even more
problems in the layout code. :(

It is hard to make this work in a generic and non hacky way. And as
always the GTK people are making things
a lot more complicated with their inadequate decisions. (I cannot hold
myself ranting about this).

I'm fine if you break this and make it work more out of the box.

Best regards,
Teodor

Vadim Zeitlin

unread,
Nov 4, 2019, 11:37:48 AM11/4/19
to wx-...@googlegroups.com
On Mon, 4 Nov 2019 10:35:45 +0200 Teodor Petrov wrote:

TP> This is what Code::Blocks is using at the moment:
TP> https://github.com/obfuscated/codeblocks_sf/blob/master/src/sdk/globals.cpp#L1176

[it just uses wxGetDisplayPPI()]

But we know that this doesn't work well. If nothing else, this completely
ignores fractional scaling.

TP> And there are chicken-egg problems related to this code: You need the
TP> monitor in your window's constructor, but you don't know what the
TP> window manager would do and where it will place your window, so you
TP> have no chance of getting the proper value.

When restoring the windows using previously saved geometry, we could use
wxDisplay::GetFromPoint() for this, but I indeed have no idea about how to
determine on which display the window will show when showing it without any
fixed position.

I guess the only thing to do is to assume that it's shown on the primary
display and react to the DPI change event (which would need to be always
generated on showing the window on any display with DPI different from the
primary one) later.

TP> It is hard to make this work in a generic and non hacky way. And as
TP> always the GTK people are making things a lot more complicated with
TP> their inadequate decisions. (I cannot hold myself ranting about this).

Me neither.

TP> I'm fine if you break this and make it work more out of the box.

We're trying, but while using gdk_screen_get_resolution() will help with
fractional scaling, it will be a step back from per-monitor DPI support
point of view. Unfortunately I just don't think GTK has what it takes to
handle per-monitor DPI currently.

Regards,
VZ

Teodor Petrov

unread,
Nov 4, 2019, 2:01:46 PM11/4/19
to wx-...@googlegroups.com
On 11/4/19 6:37 PM, Vadim Zeitlin wrote:
> On Mon, 4 Nov 2019 10:35:45 +0200 Teodor Petrov wrote:
>
> TP> This is what Code::Blocks is using at the moment:
> TP> https://github.com/obfuscated/codeblocks_sf/blob/master/src/sdk/globals.cpp#L1176
>
> [it just uses wxGetDisplayPPI()]
>
> But we know that this doesn't work well. If nothing else, this completely
> ignores fractional scaling.

What do you mean by fractional scaling? Is this even a thing in the GTK3
world? From the past discussion
on the topic it is not clear if it is even possible to do it. If I
understand correctly Gnome applies some UI
scaling hacks on top of the inadequate GTK3 behaviour to scale its UI.

BTW: What we use works on my main test case - my 4k 27" monitor with 163
dpi. :) GTK3 reports this as
scaling factor 1 and I size images to be for scaling factor 163/96. We
have images sizes of 16, 20, 24, 28,
32, 48, 56, 64, so I'm selecting the closest match. I don't change
anything related to fonts. My goal is to
adjust images to match the size of the fonts next to them.

I was planning to do further testing on a proper HiDPI setup (at least
according to GTK3), but I got tired of
icons and postponed it for later. :(

GTK3 needs a lot of work to be usable on HiDPI setups unfortunately. :(

/Teodor

Iwbnwif Yiw

unread,
Nov 4, 2019, 4:17:52 PM11/4/19
to wx-dev
On Monday, November 4, 2019 at 7:01:46 PM UTC, Teodor Petrov wrote:

What do you mean by fractional scaling? Is this even a thing in the GTK3
world? From the past discussion
on the topic it is not clear if it is even possible to do it. If I
understand correctly Gnome applies some UI
scaling hacks on top of the inadequate GTK3 behaviour to scale its UI. 

My understanding is that GTK supports fractional scaling of text, for example using the GDK_DPI_SCALE parameter or making a Gnome setting change. Anything that uses a font metric (e.g. buttons, menus) for sizing is also scaled.

This isn't true fractional scaling of the whole display, however at least text in generic controls (such as in a wxTreeCtrl) doesn't appear tiny.

The problem with using the DPI / 96 (~170%) value is that in practice it looks oversized. So on your 4k 27" monitor your native text is probably scaled to something like 130% and we are trying to match that.

I don't change anything related to fonts.

Do you have any font scaling set up - e.g. in Gnome Settings?
 
My goal is to adjust images to match the size of the fonts next to them.

Yes, that is exactly my goal too. If you use DPI / 96 though the images will be oversized compared to any native text (depending on what has been set).
 

Iwbnwif Yiw

unread,
Nov 4, 2019, 4:32:59 PM11/4/19
to wx-dev
On Sunday, November 3, 2019 at 10:56:12 PM UTC, VZ wrote:

> Hmm, wxWindow::GetContentScaleFactor uses gtk_widget_get_scale_factor internally which can only ever return an integer (usually 1 or 2) as I am
> sure you are aware. The problem is that I need the fractional scaling factor. 
> Are you suggesting that we use gdk_screen_get_resolution instead in wxWindow::GetContentScaleFactor? 

 I think so, yes.

I am not sure that would be a good idea. For better or worse and for whatever reason there are two concepts at play :- text (a.k.a font / GDK_DPI_SCALE / font DPI) and everything else (a.k.a. title bars, GDK_SCALE, display scale etc.). wxWindow::GetContentScaleFactor covers the latter one okay for now, what we are missing is access to the former one.

If you really want to have per-monitor scaling of text, then that is possible using the ratio of gdk_screen_get_resolution and the DPI of the default monitor. If you apply the same ratio for the scaling of another monitor, the text should appear the same size on both. IDK if this will look right though, because I doubt if anything else matches on the two monitors!!

Vadim Zeitlin

unread,
Nov 4, 2019, 4:41:13 PM11/4/19
to wx-...@googlegroups.com
On Mon, 4 Nov 2019 21:01:47 +0200 Teodor Petrov wrote:

TP> On 11/4/19 6:37 PM, Vadim Zeitlin wrote:
TP> > On Mon, 4 Nov 2019 10:35:45 +0200 Teodor Petrov wrote:
TP> >
TP> > TP> This is what Code::Blocks is using at the moment:
TP> > TP> https://github.com/obfuscated/codeblocks_sf/blob/master/src/sdk/globals.cpp#L1176
TP> >
TP> > [it just uses wxGetDisplayPPI()]
TP> >
TP> > But we know that this doesn't work well. If nothing else, this completely
TP> > ignores fractional scaling.
TP>
TP> What do you mean by fractional scaling?

Err, the thing being discussed in this thread (have you noticed its
subject?).

TP> Is this even a thing in the GTK3 world? From the past discussion on the
TP> topic it is not clear if it is even possible to do it. If I understand
TP> correctly Gnome applies some UI scaling hacks on top of the inadequate
TP> GTK3 behaviour to scale its UI.

Yes, and we should apply the same inadequate hacks as the other Gnome
applications because it's better than nothing and because the goal of
wxWidgets is to behave as closely to the native applications as reasonably
possible.

Regards,
VZ

Vadim Zeitlin

unread,
Nov 4, 2019, 4:44:39 PM11/4/19
to wx-...@googlegroups.com
On Mon, 4 Nov 2019 13:32:59 -0800 (PST) Iwbnwif Yiw wrote:

IY> On Sunday, November 3, 2019 at 10:56:12 PM UTC, VZ wrote:
IY>
IY> > Hmm, wxWindow::GetContentScaleFactor uses
IY> > gtk_widget_get_scale_factor internally which can only ever return an
IY> > integer (usually 1 or 2) as I am
IY> > > sure you are aware. The problem is that I need the fractional scaling
IY> > factor.
IY>
IY> > Are you suggesting that we use gdk_screen_get_resolution instead in
IY> > wxWindow::GetContentScaleFactor?
IY>
IY> > I think so, yes.
IY>
IY> I am not sure that would be a good idea.

I'm not sure neither, but it seems better than not doing it. For example,
using an image nearby some text will work better if the image is scaled by
the same factor as the text is, and this is only possible if we take "text"
scaling into account in GetContentScaleFactor().

IY> For better or worse and for whatever reason there are two concepts at
IY> play :- text (a.k.a font / GDK_DPI_SCALE / font DPI) and everything
IY> else (a.k.a. title bars, GDK_SCALE, display scale etc.).
IY> wxWindow::GetContentScaleFactor covers the latter one okay for now,
IY> what we are missing is access to the former one.

So what problems will we have if we integrate it into the factor returned
by GetContentScaleFactor()?

IY> If you really want to have per-monitor scaling of text, then that is
IY> possible using the ratio of gdk_screen_get_resolution and the DPI of the
IY> default monitor. If you apply the same ratio for the scaling of another
IY> monitor, the text should appear the same size on both. IDK if this will
IY> look right though, because I doubt if anything else matches on the two
IY> monitors!!

I'm afraid it won't look right. The functions used for DPI determination
seem to return reasonable results, but they result in using different sizes
from what everybody else does, which is seen (and, admittedly, not fully
incorrectly) as wx bug.

Regards,
VZ

Teodor Petrov

unread,
Nov 7, 2019, 2:04:59 PM11/7/19
to wx-...@googlegroups.com
On 11/4/19 11:41 PM, Vadim Zeitlin wrote:
> On Mon, 4 Nov 2019 21:01:47 +0200 Teodor Petrov wrote:
>
> TP> On 11/4/19 6:37 PM, Vadim Zeitlin wrote:
> TP> > On Mon, 4 Nov 2019 10:35:45 +0200 Teodor Petrov wrote:
> TP> >
> TP> > TP> This is what Code::Blocks is using at the moment:
> TP> > TP> https://github.com/obfuscated/codeblocks_sf/blob/master/src/sdk/globals.cpp#L1176
> TP> >
> TP> > [it just uses wxGetDisplayPPI()]
> TP> >
> TP> > But we know that this doesn't work well. If nothing else, this completely
> TP> > ignores fractional scaling.
> TP>
> TP> What do you mean by fractional scaling?
>
> Err, the thing being discussed in this thread (have you noticed its
> subject?).

The function I've posted works just fine on my fractional scaling
monitor (4k, 27'', 16x ppi).
wxGetDisplayPPI returns the correct PPI and when divided by 96 it
returns scaling factor which seems to be correct.

This is the output when executing the function on the main frame during
its creation.

Initial scaling factor is 1.000
Actual scaling factor is 1.635

I really don't understand what you mean really by "completely ignores
fractional scaling".
It ignores multiple monitors with different scaling, but this is a
separate problem.

/Teodor

Vadim Zeitlin

unread,
Nov 7, 2019, 5:36:02 PM11/7/19
to wx-...@googlegroups.com
On Thu, 7 Nov 2019 21:04:57 +0200 Teodor Petrov wrote:

TP> On 11/4/19 11:41 PM, Vadim Zeitlin wrote:
TP> > On Mon, 4 Nov 2019 21:01:47 +0200 Teodor Petrov wrote:
TP> >
TP> > TP> On 11/4/19 6:37 PM, Vadim Zeitlin wrote:
TP> > TP> > On Mon, 4 Nov 2019 10:35:45 +0200 Teodor Petrov wrote:
TP> > TP> >
TP> > TP> > TP> This is what Code::Blocks is using at the moment:
TP> > TP> > TP> https://github.com/obfuscated/codeblocks_sf/blob/master/src/sdk/globals.cpp#L1176
TP> > TP> >
TP> > TP> > [it just uses wxGetDisplayPPI()]
TP> > TP> >
TP> > TP> > But we know that this doesn't work well. If nothing else, this completely
TP> > TP> > ignores fractional scaling.
TP> > TP>
TP> > TP> What do you mean by fractional scaling?
TP> >
TP> > Err, the thing being discussed in this thread (have you noticed its
TP> > subject?).
TP>
TP> The function I've posted works just fine on my fractional scaling
TP> monitor (4k, 27'', 16x ppi).

We need to define "fine".

TP> wxGetDisplayPPI returns the correct PPI and when divided by 96 it
TP> returns scaling factor which seems to be correct.

Maybe, for some meaning of "correct". But is it the same as is used in the
other applications, especially when you use scaling of 150% or 125%? I
don't think so.

TP> This is the output when executing the function on the main frame during
TP> its creation.
TP>
TP> Initial scaling factor is 1.000
TP> Actual scaling factor is 1.635

Even though 1.635 is indeed "correct" in the sense that it corresponds to
the real, physical number of pixels per inch on your monitor (and this is
why I implemented it like this), I'm almost sure native applications on
your system don't use 163.5% scaling, but either 150% or 200% (or maybe
175%). Which makes it correct but wrong.

TP> I really don't understand what you mean really by "completely ignores
TP> fractional scaling".

It doesn't take GDK_DPI_SCALE into account at all.

Regards,
VZ
Reply all
Reply to author
Forward
0 new messages