Multi platform HiDPI

320 views
Skip to first unread message

Teodor Petrov

unread,
Mar 18, 2019, 7:58:57 PM3/18/19
to wx-...@googlegroups.com
Hello,

I'm trying to make Code::Blocks look good on the three OSes (4 different ports).
My main struggle is that I don't know what is really the correct approach.
Is there some guide about this? It would be rather helpful.

So what I'm currently doing:
I'm working on the toolbars, because they are the most affected by HiDPI.
Our toolbars are wxToolbars created from xrc files using custom XRC handler.
We use wxAUI and the toolbars could be re-arranged by the user.
The images and xrc files for the toolbars are stored in a zip file.
We don't use the Apple's suffixes in filenames.

I'm currently testing on a macbook pro 13 and linux/window 7 4k 27inch monitor.
The plan is to have as many icon sizes as possible and allow the user to choose the
size and probably use the scale factor to adjust it. Not really sure what to do.

Currently I do something like:

wxToolBar* Manager::CreateEmptyToolbar()
{
    const wxSize size(m_ToolbarImageSize, m_ToolbarImageSize);
    wxWindow *appFrame = GetAppFrame();
#if wxCHECK_VERSION(3, 0, 0)
    const double scaleFactor = appFrame->GetContentScaleFactor();
    const wxSize scaledSize(size.x/scaleFactor, size.y/scaleFactor);
#else
    const wxSize scaledSize = size;
#endif // wxCHECK_VERSION(3, 0, 0)

    wxToolBar* toolbar = new wxToolBar(appFrame, -1, wxDefaultPosition, scaledSize, wxTB_FLAT | wxTB_NODIVIDER);
    toolbar->SetToolBitmapSize(scaledSize);

    return toolbar;
}

So I create a toolbar based on the scaling factor.
This is the only way I've found to get a good looking toolbar on macOS. I also have to
use the special wxBitmap constructor to set proper scaling to the images, because they
aren't marked with a suffix.

On linux this works fine, too, but I'm not able to get any scaling different from 1.0 on
both gtk2 and gtk3 :(

On windows this also works, but the the result of wxToolbar::GetToolBitmapSize changes
after a call to realize and I'm a bit confused and worried that I don't do the correct thing.
Should I create the toolbar to match the size of my images on windows and gtk2/3 and do
the scaling corrections only on macOS?

Another problem I have is that on windows 7 wxComboBox and wxComboCtrl have different
heights. This makes all toolbars on a given row look a bit off and ugly. Is this expected?
Can I do something about this?

Best regards,
Teodor

Vadim Zeitlin

unread,
Mar 19, 2019, 8:21:08 PM3/19/19
to wx-...@googlegroups.com
On Tue, 19 Mar 2019 01:58:45 +0200 Teodor Petrov wrote:

TP> I'm trying to make Code::Blocks look good on the three OSes (4 different
TP> ports).

Excellent, we really need to have a concrete example of problems
encountered (and solved) when adding high DPI support to a non-trivial
application using wx and, ideally, an open-source one, so that we could
point people directly to the relevant commits/parts of its source. And as
C::B satisfies both the "non-trivial" and "open-source", you're very
welcome to be our guinea pig^W^W valuable contributor helping us to improve
our high DPI support!

TP> My main struggle is that I don't know what is really the correct approach.
TP> Is there some guide about this? It would be rather helpful.

I promise to write it once I know what to put into it :-)

TP> So what I'm currently doing:
TP> I'm working on the toolbars, because they are the most affected by HiDPI.
TP> Our toolbars are wxToolbars created from xrc files using custom XRC handler.
TP> We use wxAUI and the toolbars could be re-arranged by the user.
TP> The images and xrc files for the toolbars are stored in a zip file.
TP> We don't use the Apple's suffixes in filenames.

In (non open-source) applications I worked on so far, I've always used the
@2x suffix because, as much as I dislike Apple in general, this just seems
to be the most reasonable way to do it.

TP> The plan is to have as many icon sizes as possible and allow the user to
TP> choose the size and probably use the scale factor to adjust it.

Why should users be bothered with this? IMO it would be a pretty poor user
experience. Perhaps you want to provide a choice between small, medium and
large toolbar icons in the options, but surely the icons should appear in
the correct size, appropriate for the current resolution, by default?

Of course, this does require some way of finding the right bitmap for the
given logical size and the current DPI. If you don't use the suffixes (and
wx doesn't support them out of the box in non-Mac ports anyhow currently),
there must be some other mechanism for doing it. Ideal would be to have
such mechanism inside wxWidgets, while making it sufficiently flexible, so
that it could be customized by the different applications to their needs.

TP> Currently I do something like:
TP>
TP> wxToolBar* Manager::CreateEmptyToolbar()
TP> {
TP> const wxSize size(m_ToolbarImageSize, m_ToolbarImageSize);
TP> wxWindow *appFrame = GetAppFrame();
TP> #if wxCHECK_VERSION(3, 0, 0)
TP> const double scaleFactor = appFrame->GetContentScaleFactor();
TP> const wxSize scaledSize(size.x/scaleFactor, size.y/scaleFactor);
TP> #else
TP> const wxSize scaledSize = size;
TP> #endif // wxCHECK_VERSION(3, 0, 0)
TP>
TP> wxToolBar* toolbar = new wxToolBar(appFrame, -1, wxDefaultPosition,
TP> scaledSize, wxTB_FLAT | wxTB_NODIVIDER);
TP> toolbar->SetToolBitmapSize(scaledSize);
TP>
TP> return toolbar;
TP> }

The question for me is whether we should apply the scaling inside
SetToolBitmapSize() itself. On one hand, this would be more convenient,
IMO. OTOH it would break your existing code and any other code doing its
own scale adjustment. We could add a new SetToolBitmapLogicalSize(), which
would be 100% backwards compatible, but I don't know if it's a good idea to
add new variants of all the existing functions dealing with sizes... For
once, I think we should break compatibility here and decide, once and for
all, that all wxWindow-level functions work with logical pixels.

TP> So I create a toolbar based on the scaling factor.
TP> This is the only way I've found to get a good looking toolbar on macOS. I
TP> also have to use the special wxBitmap constructor to set proper scaling
TP> to the images, because they aren't marked with a suffix.

In the absence of some general mechanism allowing to do it, all
applications providing high DPI bitmaps would have to do something like
this which is, of course, quite suboptimal...

TP> On linux this works fine, too, but I'm not able to get any scaling
TP> different from 1.0 on both gtk2 and gtk3 :(

For GTK+ 2 it's not a surprise, it just doesn't support high DPI and
trying to do anything with it is hopeless. For GTK+ 3 it should really
work, I tested this relatively recently and there is even a small patch to
the toolbar sample at https://trac.wxwidgets.org/ticket/18225 which
definitely worked for me. Could you please check if it works for you?

TP> On windows this also works, but the the result of
TP> wxToolbar::GetToolBitmapSize changes after a call to realize and I'm a
TP> bit confused and worried that I don't do the correct thing.

What does GetToolBitmapSize() return?

TP> Should I create the toolbar to match the size of my images on windows and
TP> gtk2/3 and do the scaling corrections only on macOS?

Of course we want the same code to work under all platforms.

TP> Another problem I have is that on windows 7 wxComboBox and wxComboCtrl
TP> have different heights. This makes all toolbars on a given row look a
TP> bit off and ugly. Is this expected? Can I do something about this?

Not sure, but please wait until https://trac.wxwidgets.org/ticket/18294
is finally resolved, as this might change things. If it doesn't, please
open a separate ticket for this with, as usual, a minimal patch allowing me
to see/debug the problem if possible.

TIA,
VZ

David Connet

unread,
Mar 20, 2019, 9:43:58 AM3/20/19
to wx-...@googlegroups.com
On 3/19/2019 5:21 PM, Vadim Zeitlin wrote:
> I've always used the
> @2x suffix because, as much as I dislike Apple in general, this just seems
> to be the most reasonable way to do it.

This is what I've been doing also - on Windows too. I created a
wxArtProvider derived class and handle the image scaling in that.

If you want to see, it's https://github.com/dconnet/AgilityBook
Specifically the ImageManager files (src/LibArbWin/ and
Include/LibArbWin/), ImageHelperBase (same directories), and ImageHelper
files (src/Win/). (oh, and AgilityBook.cpp)

Dave

Teodor Petrov

unread,
Mar 20, 2019, 4:03:19 PM3/20/19
to wx-...@googlegroups.com
Thanks for answering.

Unfortunately I cannot answer on specific points, so I'll post a big lump.

1. About the docs it would be good to have some documentation which
sizes/positions
   are logical and which aren't. I'm fine doing the adjustments, but
currently I have to find
   out this information by testing each port to see what happens for
each size/position.
   I'm not in a delusion that I'll write it once and it will be the
same everywhere, but a bit
   of consistency won't hurt.
2. Current plan is to be able to change resolutions and make every
resolution look crisp,
    then I'll find a way to make a pleasant UI for users. As a start I
want to be able to select
    16x16, 22x22 and 32x32 image sizes for toolbars and they should
work as expected.
    After that I can probably detect the scaling and provide "small",
"normal", "large", "larger"
    options to users.
3. I don't like the current behaviour of @2x, because it does something
only on macOS
   and currently I have to use a special constructor to undo the damage
of the special
   handling or introduce the special handling for the other ports.
4. Unfortunately the non macOS world would have to handle non 2x scales,
so I want/need
    to support 1.25, 1.50, 1.75, 2.0, 2.5, 3.0, 4.0 scales, etc.
5. gtk3 seems to be bigger trouble than gtk2. Currently my 4k 27inch
monitor is detected as
    1.0 scale, but the fonts are probably adjusted for dpi using the
X-values and C::B looks
   worse with gtk3 than with gtk2. Because this font adjustment is done
for part of the fonts
   and not for others. For example starting the stc sample leads to
really small font selected
   by default. But I'll report this later.
5.1. My current code doesn't work for gtk3 and displays detected to be
2x scale.
6. I'll post a ticket about wxComboCtrl, when I get everything else working.

/Teodor

Vadim Zeitlin

unread,
Mar 20, 2019, 9:56:45 PM3/20/19
to wx-...@googlegroups.com
On Wed, 20 Mar 2019 22:03:11 +0200 Teodor Petrov wrote:

TP> Unfortunately I cannot answer on specific points, so I'll post a big lump.
TP>
TP> 1. About the docs it would be good to have some documentation which
TP> sizes/positions are logical and which aren't.

In general, everything wxWindow-related is logical and only wxDC/wxBitmap
stuff should be physical.

TP> 2. Current plan is to be able to change resolutions and make every
TP> resolution look crisp,     then I'll find a way to make a pleasant UI
TP> for users. As a start I want to be able to select     16x16, 22x22 and
TP> 32x32 image sizes for toolbars and they should work as expected.

OK, so what prevents it from working currently?

TP> 3. I don't like the current behaviour of @2x, because it does something
TP> only on macOS    and currently I have to use a special constructor to
TP> undo the damage of the special    handling or introduce the special
TP> handling for the other ports.

I don't insist on using this everywhere, but I currently don't have any
other reasonable idea about how to do it. I.e. how are you going to ensure
that you select the correct bitmaps for, say, 32*32 size for the current
resolution, i.e. either 32*32 or 64*64 ones?

TP> 4. Unfortunately the non macOS world would have to handle non 2x scales,

This is a generalization of 2x case, I'd like to start by handling this
one correctly.

TP> 5. gtk3 seems to be bigger trouble than gtk2. Currently my 4k 27inch
TP> monitor is detected as     1.0 scale, but the fonts are probably
TP> adjusted for dpi using the X-values and C::B looks    worse with gtk3
TP> than with gtk2. Because this font adjustment is done for part of the
TP> fonts    and not for others. For example starting the stc sample leads
TP> to really small font selected    by default. But I'll report this
TP> later.

wxSTC is a bit of a special case, I'm afraid...

Regards,
VZ

Teodor Petrov

unread,
Apr 14, 2019, 11:05:06 AM4/14/19
to wx-...@googlegroups.com
Hello again,

I think, I've made it working on all 4 ports I care about at the moment.

So to summarize:
There seem to be two kinds of platforms in the wild: platforms which do
internal scaling and others that don't.
Cocoa and Gtk3 do it and Gtk2 and win32 don't.

So to get crisp results on the former (gtk3/cocoa) group I have to do
two steps:
1. Use the special c-tor of wxBitmap which will tell the system that the
bitmap has the correct scaling
    and doesn't need to do anything with it.
2. Create a toolbar that is smaller by the scaling factor

To get crisp results on the latter(gtk2/win32) I do nothing special:
1. Load the image it has no scaling in it
2. Create a toolbar in the final size

So the final code looks like this:

wxBitmap cbLoadBitmapScaled(const wxString& filename, wxBitmapType
bitmapType, double scaleFactor, wxFileSystem *fs)
{
    wxImage im;
    <load the image somehow to wxImage object>
#if defined(__WXOSX__) || (defined(__WXGTK3__) && wxCHECK_VERSION(3,
1, 2))
    return wxBitmap(im, -1, scaleFactor);
#else
    (void)scaleFactor;
     return wxBitmap(im);
#endif // defined(__WXOSX__) || (defined(__WXGTK3__) &&
wxCHECK_VERSION(3, 1, 2))
}

wxToolBar* Manager::CreateEmptyToolbar()
{
    const wxSize size(m_ToolbarImageSize, m_ToolbarImageSize);
    wxWindow *appFrame = GetAppFrame();

#ifdef __WXMSW__
    const double scaleFactor = 1.0;
#else
    const double scaleFactor = cbGetContentScaleFactor(*appFrame);
// this is just a wrapper to make wx2.8 work
#endif // __WXMSW__
    const wxSize scaledSize(size.x/scaleFactor, size.y/scaleFactor);

    wxToolBar* toolbar = new wxToolBar(appFrame, -1,
wxDefaultPosition, scaledSize, wxTB_FLAT | wxTB_NODIVIDER);
    toolbar->SetToolBitmapSize(scaledSize);

    return toolbar;
}

The GTK3 seems to be the worst of the platforms, because it tries to
emulate macOS, but the gtk3 devs haven't realized that people
would use non integer scaling factors more often, because these are the
kind of monitors they have. This means that the 2x scaling
thing doesn't work...

Can someone share a function which can be used to detect the scaling
based on font sizes? I'll need this for both gtk2 and 3.

Next I'll try to see if using an artprovider would make things easier.
After that I'll try to tackle the menu icons.

Best regards,
Teodor Petrov

Vadim Zeitlin

unread,
Apr 15, 2019, 6:15:50 AM4/15/19
to wx-...@googlegroups.com
On Sun, 14 Apr 2019 18:05:09 +0300 Teodor Petrov wrote:

TP> So to summarize:
TP> There seem to be two kinds of platforms in the wild: platforms which do
TP> internal scaling and others that don't.

Yes, absolutely. And the goal is to make it possible to handle both of
them in the same code, i.e. without preprocessor condition checks, as much
as possible.

TP> Cocoa and Gtk3 do it and Gtk2 and win32 don't.

The trouble with GTK+ 2 is that it doesn't support high DPI at all, so I
really don't think it's reasonable to use it. Do you actually scale all the
fonts yourself when using it?

TP> So to get crisp results on the former (gtk3/cocoa) group I have to do
TP> two steps:
TP> 1. Use the special c-tor of wxBitmap which will tell the system that the
TP> bitmap has the correct scaling     and doesn't need to do anything with
TP> it.
TP> 2. Create a toolbar that is smaller by the scaling factor
TP>
TP> To get crisp results on the latter(gtk2/win32) I do nothing special:
TP> 1. Load the image it has no scaling in it
TP> 2. Create a toolbar in the final size

(1) must really be addressed together with loading the bitmap because in
the case of Mac/GTK3 you also need to use different bitmap files for high
DPI screens and normal ones.

For (2) I am still not sure whether we should just change
wxToolBar::SetToolBitmapSize() to take logical pixels (and so do the right
thing automatically under Mac/GTK3) or add a new function doing this.
Adding a new function is really not appealing because it's not the only
place where it would be needed, but changing SetToolBitmapSize() would
(silently!) break your code and any other similar code that already does
its own conversions and we usually try very hard not to do this. Perhaps we
could avoid this problem by just ignoring SetToolBitmapSize() and using the
size of the actual bitmaps being added to the toolbar. Right now it seems
like the best solution to me, but it's also the one requiring the most
work, of course.

TP> The GTK3 seems to be the worst of the platforms, because it tries to
TP> emulate macOS, but the gtk3 devs haven't realized that people
TP> would use non integer scaling factors more often, because these are the
TP> kind of monitors they have. This means that the 2x scaling
TP> thing doesn't work...

You just have to choose the lesser evil and use either 1x or 2x.

TP> Can someone share a function which can be used to detect the scaling
TP> based on font sizes?

Sorry, what do you mean?

Thanks again for sharing your experience,
VZ

Teodor Petrov

unread,
Apr 15, 2019, 1:36:11 PM4/15/19
to wx-...@googlegroups.com
On 4/15/19 1:15 PM, Vadim Zeitlin wrote:

> The trouble with GTK+ 2 is that it doesn't support high DPI at all, so I
> really don't think it's reasonable to use it. Do you actually scale all the
> fonts yourself when using it?

In fact wxGTK + gtk2 works way better than wxGTK + gtk3. I'm not really
sure how I've set my
system (HiDPI is so confusing on linux, no doubt people are using macOS
or windows). But I
guess X knows the scaling and scales fonts automatically, so most
layouts look good. Some
windows are really small by default. And of course images are small.

On gtk3 many controls are using small fonts (wxTreeCtrl, stc, propgrid,
wxlistbook). I'll post tickets
about them when I have more details.

But yes, generally gtk2 is not a problem because the scaling is 1 and
things are not proportional,
but at least text size is good. And gtk2 is almost dead anyway.
Unfortunately we'll have to tackle
gtk3 and 4. :(

> TP> So to get crisp results on the former (gtk3/cocoa) group I have to do
> TP> two steps:
> TP> 1. Use the special c-tor of wxBitmap which will tell the system that the
> TP> bitmap has the correct scaling     and doesn't need to do anything with
> TP> it.
> TP> 2. Create a toolbar that is smaller by the scaling factor
> TP>
> TP> To get crisp results on the latter(gtk2/win32) I do nothing special:
> TP> 1. Load the image it has no scaling in it
> TP> 2. Create a toolbar in the final size
>
> (1) must really be addressed together with loading the bitmap because in
> the case of Mac/GTK3 you also need to use different bitmap files for high
> DPI screens and normal ones.

I think the @2 handling in the loading code for wxBitmap on macOS is a
mistake and must be removed.
If it is left there it should be implemented for other OSes. Because you
now have some magic which is
working on a single OS and if you want to use it on the others you have
to do it yourself, so what is the
benefit? I see only downsides, because I have to use a special wxBitmap
constructor and introduce a
wrapper function and other complexities. Currently I'd have to change
every place which loads bitmaps
using wxBitmap directly.

Also I don't think people doing cross platform apps which has to support
non-2x scaling would provide
different images for 32x32@2 and 64x64 as Apple is advising. We you have
only two scales then this
suggestion makes sense, but when you have 4-5 it doesn't. for sure we
won't do it, we'll just reuse
images.

> For (2) I am still not sure whether we should just change
> wxToolBar::SetToolBitmapSize() to take logical pixels (and so do the right
> thing automatically under Mac/GTK3) or add a new function doing this.
> Adding a new function is really not appealing because it's not the only
> place where it would be needed, but changing SetToolBitmapSize() would
> (silently!) break your code and any other similar code that already does
> its own conversions and we usually try very hard not to do this. Perhaps we
> could avoid this problem by just ignoring SetToolBitmapSize() and using the
> size of the actual bitmaps being added to the toolbar. Right now it seems
> like the best solution to me, but it's also the one requiring the most
> work, of course.

I have no opinion here. Silent breakages are really bad, so I guess you
don't have many realistic options
left.

> TP> The GTK3 seems to be the worst of the platforms, because it tries to
> TP> emulate macOS, but the gtk3 devs haven't realized that people
> TP> would use non integer scaling factors more often, because these are the
> TP> kind of monitors they have. This means that the 2x scaling
> TP> thing doesn't work...
>
> You just have to choose the lesser evil and use either 1x or 2x.
You can do it when you're apple and control the whole stack, but you
cannot do it when you're lib vendor
for very broad spectrum of use cases. (I'm talking about the automatic
switch to 2x done by gtk3).

> TP> Can someone share a function which can be used to detect the scaling
> TP> based on font sizes?
>
> Sorry, what do you mean?
In another discussion about hidpi another wx-dev mentioned that he/she
is using such a function. But I cannot find the discussion :(

I'll post if using an approvider is any better or has similar/other
problems.

/Teodor

Igor Korot

unread,
Apr 15, 2019, 4:46:47 PM4/15/19
to wx-dev
Hi, Teodor,
Did you mean this:
https://stackoverflow.com/questions/55605441/how-to-calculate-the-scale-factor-for-current-window-in-wxwidgets

?

Thank you.

>
> I'll post if using an approvider is any better or has similar/other
> problems.
>
> /Teodor
>
> --
> To unsubscribe, send email to wx-dev+un...@googlegroups.com
> or visit http://groups.google.com/group/wx-dev
>

Teodor Petrov

unread,
May 18, 2019, 2:36:17 PM5/18/19
to wx-...@googlegroups.com
Hello again,

Is there any reliable way to get the height of items in a wxListCtrl
during creation? I need to create
the image list which would be used to the icons and thus I need to find
out the size in a reliable
manner. The list is in report mode.

I'm using list->GetTextExtent("some text"), but it returns a size which
is obviously too big.

Best regards,
Teodor

Vadim Zeitlin

unread,
May 20, 2019, 1:07:49 PM5/20/19
to wx-...@googlegroups.com
On Sat, 18 May 2019 21:35:52 +0300 Teodor Petrov wrote:

TP> Is there any reliable way to get the height of items in a wxListCtrl
TP> during creation? I need to create the image list which would be used to
TP> the icons and thus I need to find out the size in a reliable manner.
TP> The list is in report mode.

I'm not sure why do you want to do it like this. Before any high DPI
changes your code presumably didn't work like this and just used the icons
in whichever sizes you had them (typically 16*16 for small wxListCtrl
icons). So why not just continue doing the same thing but scale up the size
of your icons by the DPI ratio to the standard one (i.e. use 32*32 for 192
DPI)? Of course, you need to find the closest actually available icon size,
but this would be the same even if you could do what you're asking for.

TP> I'm using list->GetTextExtent("some text"), but it returns a size which
TP> is obviously too big.

The height returned by GetTextExtent() or, alternatively, GetCharHeight()
should be close/scale proportionally to the size of the icons, but it's not
really equal to it. The height returned by wxListCtrl::GetItemRect() should
be pretty close to it however. But even if it works for you, I still would
rather do this as described above instead.

Regards,
VZ

Teodor Petrov

unread,
May 21, 2019, 7:20:31 PM5/21/19
to wx-...@googlegroups.com
Hello,

On 5/20/19 8:07 PM, Vadim Zeitlin wrote:
> I'm not sure why do you want to do it like this. Before any high DPI
> changes your code presumably didn't work like this and just used the icons
> in whichever sizes you had them (typically 16*16 for small wxListCtrl
> icons). So why not just continue doing the same thing but scale up the size
> of your icons by the DPI ratio to the standard one (i.e. use 32*32 for 192
> DPI)? Of course, you need to find the closest actually available icon size,
> but this would be the same even if you could do what you're asking for.

The problem is that I don't know the DPI. If I can find the DPI or the
real scaling
I can use it, but I can't on gtk2 and on gtk3. The other problem is that
someone
could have changed the font used for UI in gtk2 or gtk3 and then my
icons wouldn't
work.

> The height returned by GetTextExtent() or, alternatively, GetCharHeight()
> should be close/scale proportionally to the size of the icons, but it's not
> really equal to it. The height returned by wxListCtrl::GetItemRect() should
> be pretty close to it however. But even if it works for you, I still would
> rather do this as described above instead.

This would work only after I've added some items, isn't it?

/Teodor

Vadim Zeitlin

unread,
May 21, 2019, 7:32:27 PM5/21/19
to wx-...@googlegroups.com
On Wed, 22 May 2019 02:20:15 +0300 Teodor Petrov wrote:

TP> The problem is that I don't know the DPI.

This is definitely supposed to work in master and, I think (but I'm not
100% sure about it), in 3.1.2.

TP> The other problem is that someone could have changed the font used for
TP> UI in gtk2 or gtk3 and then my icons wouldn't work.

Well, this could happen for icons of any size. Unless you use vector icons
(which, admittedly, could be the best solution in the long term) you can't
do anything about this.

TP> > The height returned by GetTextExtent() or, alternatively, GetCharHeight()
TP> > should be close/scale proportionally to the size of the icons, but it's not
TP> > really equal to it. The height returned by wxListCtrl::GetItemRect() should
TP> > be pretty close to it however. But even if it works for you, I still would
TP> > rather do this as described above instead.
TP>
TP> This would work only after I've added some items, isn't it?

Yes, but nothing prevents you from adding a dummy item and then removing
it.

Regards,
VZ

Teodor Petrov

unread,
May 21, 2019, 7:36:48 PM5/21/19
to wx-...@googlegroups.com
On 5/22/19 2:32 AM, Vadim Zeitlin wrote:
> On Wed, 22 May 2019 02:20:15 +0300 Teodor Petrov wrote:
>
> TP> The problem is that I don't know the DPI.
>
> This is definitely supposed to work in master and, I think (but I'm not
> 100% sure about it), in 3.1.2.
What API should I use for this? GetScalingFactor isn't one that works.

> Well, this could happen for icons of any size. Unless you use vector icons
> (which, admittedly, could be the best solution in the long term) you can't
> do anything about this.

I have plenty of icon sizes, so this is not a problem.

/Teodor

Vadim Zeitlin

unread,
May 21, 2019, 7:45:25 PM5/21/19
to wx-...@googlegroups.com
On Wed, 22 May 2019 02:36:40 +0300 Teodor Petrov wrote:

TP> On 5/22/19 2:32 AM, Vadim Zeitlin wrote:
TP> > On Wed, 22 May 2019 02:20:15 +0300 Teodor Petrov wrote:
TP> >
TP> > TP> The problem is that I don't know the DPI.
TP> >
TP> > This is definitely supposed to work in master and, I think (but I'm not
TP> > 100% sure about it), in 3.1.2.
TP> What API should I use for this? GetScalingFactor isn't one that works.

wxDisplay::GetDPI().
VZ

Teodor Petrov

unread,
Jun 26, 2019, 3:32:43 PM6/26/19
to wx-...@googlegroups.com
Hello again,

I've implemented a function which uses a window to find the display and
then to query the PPI,
but now I'm hitting the log message below:
    wxLogDebug("ClientToScreen cannot work when toplevel window is not
shown");

This happens because I want to find out the scaling factor during
initialization of the application.
So most windows haven't been shown yet. I've tried to detect this case,
but calling window.IsShown()
returns true. Is there some way to detect that the window is not shown
on GTK2/3? I want to make
sure that wxDisplay::GetFromWindow(&window)) would not produce this warning?

Best regards,
Teodor

p.s. I can replace the code with a call to wxGetDisplayPPI, but I prefer
to have a way to use the display.

Vadim Zeitlin

unread,
Jun 26, 2019, 6:53:58 PM6/26/19
to wx-...@googlegroups.com
On Wed, 26 Jun 2019 22:32:17 +0300 Teodor Petrov wrote:

TP> I've implemented a function which uses a window to find the display and
TP> then to query the PPI,
TP> but now I'm hitting the log message below:
TP>     wxLogDebug("ClientToScreen cannot work when toplevel window is not
TP> shown");

Do you know why is ClientToScreen() being called? This isn't immediately
clear to me...

Also, for which window exactly is the debug message above given?

TP> Is there some way to detect that the window is not shown on GTK2/3?

Well, the check in DoClientToScreen() verifies if gtk_widget_get_window()
returns a non-null GdkWindow, so I guess you could do this, but ideally it
shouldn't be necessary, of course.

TP> I want to make sure that wxDisplay::GetFromWindow(&window)) would not
TP> produce this warning?

I don't know what is wxDisplay::GetFromWindow() supposed to return for a
window before it's shown on screen -- how do we even know on which display
will it be shown? If you know the position at which you're going to put it,
you could use wxDisplay::GetFromPoint(), but if you're using the default
position, you probably can't do better than just using the primary display.

Regards,
VZ

Teodor Petrov

unread,
Jul 16, 2019, 1:00:35 PM7/16/19
to wx-...@googlegroups.com
Hello again,

I've hit the next problem in my quest to make Code::Blocks HiDPI aware -
wxHtmlWindow :(
This thing again has the special handling for macOS, but this time the
GTK3 port is ignored
and I don't see a way to tell the whole thing that all images I give it
must be drawn as is
without any scaling.

What I'm doing:
1. I detect the real scale (or use getContentScaleFactor for ports which
are known to work
    correctly)
2. Then I use the wxHtmlWindow::OnOpeningURL method to redirect image
URLs to the
    image with the correct size for the current scale factor.

The problem is that on GTK3 and GDK_SCALE=2 images look blurry, because
they aren't
created with the special c-tor and their scale is 1.

I'm looking at the code and I've tried to adjust the scaleHDPI in
TAG_HANDLER_BEGIN(IMG, "IMG,MAP,AREA"),
but this broke some things related to the layout. The images which
showed looked sharp, but
I guess more changes are needed. I see there is some pixelScale in
various places, but I'm
not sure what is doing.

Any help or guidance would be really helpful. I'm wondering if providing
a style for
wxHtmlWindow which disables this magic bmp handling would be an
acceptable solution?

Best regards,
Teodor

Vadim Zeitlin

unread,
Jul 24, 2019, 8:46:30 PM7/24/19
to wx-...@googlegroups.com
On Tue, 16 Jul 2019 20:00:15 +0300 Teodor Petrov wrote:

TP> I've hit the next problem in my quest to make Code::Blocks HiDPI aware -
TP> wxHtmlWindow :(

Yes, it's in my (big) list of things to fix for proper high DPI support...
I hoped to at least get started with it by now, hence the delay with reply,
but it is becoming clearer with each passing day that I won't be able to do
it any time soon, so let me at least reply to this message.

TP> This thing again has the special handling for macOS, but this time the
TP> GTK3 port is ignored and I don't see a way to tell the whole thing that
TP> all images I give it must be drawn as is without any scaling.

I'm afraid I don't fully understand the problem. For me the missing part
is that it doesn't check for @2x images on platforms other than Mac, but
you seem to be actually complaining about this being done for Mac instead?
I.e. my goal would be for wxHtmlWindow to automatically use the high DPI
version of the image specified in <img> tag "src" attribute everywhere, but
it looks like yours is something different, could you please explain what
is it?

TP> What I'm doing:
TP> 1. I detect the real scale (or use getContentScaleFactor for ports which
TP> are known to work     correctly)
TP> 2. Then I use the wxHtmlWindow::OnOpeningURL method to redirect image
TP> URLs to the     image with the correct size for the current scale
TP> factor.
TP>
TP> The problem is that on GTK3 and GDK_SCALE=2 images look blurry, because
TP> they aren't
TP> created with the special c-tor and their scale is 1.
TP>
TP> I'm looking at the code and I've tried to adjust the scaleHDPI in
TP> TAG_HANDLER_BEGIN(IMG, "IMG,MAP,AREA"),
TP> but this broke some things related to the layout. The images which
TP> showed looked sharp, but I guess more changes are needed. I see there
TP> is some pixelScale in various places, but I'm not sure what is doing.
TP>
TP> Any help or guidance would be really helpful.

We definitely need to modify wxHtmlWindow itself, we can't make it
high-DPI-aware from the outside. And we do need to use the appropriate
scaleHDPI in this code for this. The current Mac-specific code determines
it itself because it knows that @2x file is, well, twice larger. If you'd
like to set the scale factor from your overridden OnOpeningURL(), we need
to extend the API to allow returning it, I don't see any possible way
around this.

TP> I'm wondering if providing a style for wxHtmlWindow which disables this
TP> magic bmp handling would be an acceptable solution?

Sorry, what do you mean by "magic bmp handling"? The only thing that I can
think of is Mac-specific code, but it's not really very magic, and it's not
relevant under GTK anyhow, so why would you want to disable it?

I think the problem is due to lack/insufficiency of magic, not there being
too much of it...

Regards,
VZ

Teodor Petrov

unread,
Jul 25, 2019, 2:48:31 AM7/25/19
to wx-...@googlegroups.com
Hello,

By magic I mean the automatic code which tries to load scaled images by
appending @2x to
file names. I don't want that. I just want wxHtmlWindow to draw sharp
images (calling the
wxBitmap(filename, type, currentScaleFactor)). I can select the correct
images using other
means from the outside. Also I don't want to store all my images in a
single folder. At the
moment I'd prefer if the folder structure looks like:

./x1.25/new.png
./x1.25/open.png
./x1.25/reopen.png
./x1.25/tip.png
./x1.25/www.png
./x1.5/new.png
./x1.5/open.png
./x1.5/reopen.png
./x1.5/tip.png
./x1.5/www.png
./x1.75/new.png
./x1.75/open.png
./x1.75/reopen.png
./x1.75/tip.png
./x1.75/www.png
./x1/new.png
./x1/open.png
./x1/reopen.png
./x1/tip.png
./x1/www.png
./x2.5/new.png
./x2.5/open.png
./x2.5/reopen.png
./x2.5/tip.png
./x2.5/www.png
./x2/new.png
./x2/open.png
./x2/reopen.png
./x2/tip.png
./x2/www.png
./x3/new.png
./x3/open.png
./x3/reopen.png
./x3/tip.png
./x3/www.png

It won't be the end of the world if I have to put the images in a single
folder, but doing it like
I want is nicer and tidier.
You can see that I want to support multiple scale factors, not just 2x.
This means that either
the magic code should become smarter or would become slower (it will
have to try to load
all kinds of images one by one).

I hope this makes it clear. I don't know if my use case falls in the 95%
range or in the 5%
range.

Best regards,
Teodor

Vadim Zeitlin

unread,
Jul 27, 2019, 8:03:39 PM7/27/19
to wx-...@googlegroups.com
On Thu, 25 Jul 2019 09:48:15 +0300 Teodor Petrov wrote:

TP> By magic I mean the automatic code which tries to load scaled images by
TP> appending @2x to file names. I don't want that.

Yes, this should be the default, but it should be overridable in some way.

TP> I just want wxHtmlWindow to draw sharp images (calling the
TP> wxBitmap(filename, type, currentScaleFactor)). I can select the correct
TP> images using other means from the outside. Also I don't want to store
TP> all my images in a single folder. At the moment I'd prefer if the
TP> folder structure looks like:
TP>
TP> ./x1.25/new.png
[...]

This is fine, you should be able to do this if we provide you with some
way of overriding a function that will be called to get a bitmap with the
given name at the specified scale. We just need to define the API for this,
finally, and also decide how (and if?) it's going to affect wxArtProvider.

Unfortunately, the object doing this (name, scale) mapping probably needs
to be global, as although we could associate a specific object with
wxHtmlWindow (and any other class that needs to load bitmaps by name), I
don't see how could we pass it to wxBitmap, which also needs to use it in
its LoadFile() method. So it will either have to be wxApp or, better from
the separation of concerns perspective, but even more painful to override,
some object created by wxApp, or wxAppTraits, method.

I just don't have time to write this right now, but it really shouldn't be
very difficult and it absolutely needs to get done before 3.1.3.

Regards,
VZ

Teodor Petrov

unread,
Jul 28, 2019, 5:51:36 AM7/28/19
to wx-...@googlegroups.com
Hello,

On 7/28/19 3:03 AM, Vadim Zeitlin wrote:
> This is fine, you should be able to do this if we provide you with some
> way of overriding a function that will be called to get a bitmap with the
> given name at the specified scale. We just need to define the API for this,
> finally, and also decide how (and if?) it's going to affect wxArtProvider.

The API is already there. I can rewrite URL, so I can change filenames
whatever I like.
I just need wxHtmlWindow to use the wxBitmap(path, type, scaleFactor)
constructor when
loading bitmaps. Unfortunately this is not enough, because the scaling
factor is used in
multiple places, so very strange things happens when I change just the
loading code. If
you guide me where I need to touch I can do the work. I can also show an
example what
I am trying to do. If you think it might be helpful.


> Unfortunately, the object doing this (name, scale) mapping probably needs
> to be global, as although we could associate a specific object with
> wxHtmlWindow (and any other class that needs to load bitmaps by name), I
> don't see how could we pass it to wxBitmap, which also needs to use it in
> its LoadFile() method. So it will either have to be wxApp or, better from
> the separation of concerns perspective, but even more painful to override,
> some object created by wxApp, or wxAppTraits, method.

This sounds too complex. The only addition to the ArtProvider I would do
is to pass the
scale factor to the various functions. But I don't know if this is OK,
because this breaks
the API quite badly. Also for good scaling behaviour buttons, toolbars
and all other controls
should have a mode where they use the art provider for their images and
give exact sizes
to wxArtProvider::GetBitmap. At the moment it is not really useful that
there is an
artprovider, because the user should create the images (using calls to
the art provider)
during control creation. It would be better if I do something like:

m_toolbar.AddButton(..., wxArtId("toolbar action 1")...);
...
m_button->SetBitmap(wxArtId("button bmp 2"));
...


This means that the control could request the image with correct size
during drawing. At
the moment it is impossible to make good looking toolbars, when there
are controls in
them, because the size of the control is dependent on the font and other
stuff and you
don't know it at toolbar/toolbar item creation time.

Also this API would work really well with changing DPI when moving from
one monitor to
the next. It would be pretty automatic compared to know where we'll have
to handle an
event and do all the UI recreation manually (I've not tried the special
branch, yet, but I
imagine this is how it will work).

Best regards,
Teodor

Vadim Zeitlin

unread,
Jul 28, 2019, 2:25:26 PM7/28/19
to wx-...@googlegroups.com
On Sun, 28 Jul 2019 12:51:40 +0300 Teodor Petrov wrote:

TP> On 7/28/19 3:03 AM, Vadim Zeitlin wrote:
TP> > This is fine, you should be able to do this if we provide you with some
TP> > way of overriding a function that will be called to get a bitmap with the
TP> > given name at the specified scale. We just need to define the API for this,
TP> > finally, and also decide how (and if?) it's going to affect wxArtProvider.
TP>
TP> The API is already there.

I don't think so. You can try to use wxHtmlWindow-specific redirection
mechanism for this, but it's not general enough, doesn't allow you to
replace the built-in logic (but only to override it later) and, well, just
doesn't work.

TP> > Unfortunately, the object doing this (name, scale) mapping probably needs
TP> > to be global, as although we could associate a specific object with
TP> > wxHtmlWindow (and any other class that needs to load bitmaps by name), I
TP> > don't see how could we pass it to wxBitmap, which also needs to use it in
TP> > its LoadFile() method. So it will either have to be wxApp or, better from
TP> > the separation of concerns perspective, but even more painful to override,
TP> > some object created by wxApp, or wxAppTraits, method.
TP>
TP> This sounds too complex.

I'm itching to show that it isn't by just doing it myself, but
unfortunately I just can't afford to work on this right now instead of
finishing more urgent tasks elsewhere. So all I can say is that I don't
believe it's too complex, it's just an extra interface with a single
function and a way to get an object implementing it.

And in any case, it's unavoidable to have something like this when writing
applications working in any DPI: you simply must have some way of loading
the right "physical" version of the given "logical" image. And instead of
duplicating this way in each and every application, it makes much more
sense to do it once in wxWidgets and then allow the applications to tweak
it if necessary.

Regards,
VZ

Teodor Petrov

unread,
Jul 29, 2019, 2:35:52 AM7/29/19
to wx-...@googlegroups.com
On 7/28/19 9:25 PM, Vadim Zeitlin wrote:
> TP> This sounds too complex.
>
> I'm itching to show that it isn't by just doing it myself, but
> unfortunately I just can't afford to work on this right now instead of
> finishing more urgent tasks elsewhere. So all I can say is that I don't
> believe it's too complex, it's just an extra interface with a single
> function and a way to get an object implementing it.
>
> And in any case, it's unavoidable to have something like this when writing
> applications working in any DPI: you simply must have some way of loading
> the right "physical" version of the given "logical" image. And instead of
> duplicating this way in each and every application, it makes much more
> sense to do it once in wxWidgets and then allow the applications to tweak
> it if necessary.

OK, but what about wxHtmlWindow, even if you have this API the code
needs to know
that it is dealing with images created with wxBitmap(path, type,
scaleFactor). There are
different scale values scattered around the code and I'm not sure what
they do, but they
do something and affect the result.

Also keep in mind the odd behaviour of GTK2 and GTK3 (this one
especially). Currently I
load images for scale 1.5x and render them on GTKx which thinks
everything is 1x.
This is a real use-case and one very common on PC!

/Teodor

Vadim Zeitlin

unread,
Jul 29, 2019, 11:57:50 AM7/29/19
to wx-...@googlegroups.com
On Mon, 29 Jul 2019 09:35:58 +0300 Teodor Petrov wrote:

TP> OK, but what about wxHtmlWindow, even if you have this API the code
TP> needs to know that it is dealing with images created with
TP> wxBitmap(path, type, scaleFactor). There are different scale values
TP> scattered around the code and I'm not sure what they do, but they do
TP> something and affect the result.

Sorry, I don't really understand what do you mean. wxHtmlWindow has the
name of the file (path) and the size of the image in logical pixels (not
affected by scaling). It will use the new API to get the bitmap of this
logical size, with the API picking the most appropriate physical size.
Logically, wxHTML doesn't need anything else than this bitmap.

TP> Also keep in mind the odd behaviour of GTK2 and GTK3 (this one
TP> especially). Currently I load images for scale 1.5x and render them on
TP> GTKx which thinks everything is 1x. This is a real use-case and one
TP> very common on PC!

Again, I'm afraid I just don't understand what is the problem. Of course,
I assume that bitmaps render correctly, i.e. using the right size and
without scaling. Do you mean that this isn't the case? It definitely worked
for me the last time I tested (a few months ago) with GTK 3. If it doesn't
work for you, it would, as usual, be extremely useful to have a minimal
test case reproducing the problem.

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