EtheaDev/IconFontsImageList

Issues when font is installed runtime

aehimself opened this issue · 8 comments

Describe the bug
This is a crosspost from https://en.delphipraxis.net/topic/3377-looking-for-icon-fonts-support-in-delphi-for-high-dpi-and-themed-app

If the font is not installed on the developer machine, launching the VCL demo (from within the IDE or starting the compiled .EXE) for the first time icons do not show up:

image

The demo does not unregister the font upon closing, so at the second launch everything behaves normally.

I can confirm that AddFontResource works, as calling Screen.ResetFonts and re-evaluating them by calling Screen.Fonts before and after the WinApi call the font shows up in the list.

To Reproduce

  1. Make sure font is not installed on the machine
  2. Start the VCL demo from the IDE or by launching the compiled .EXE file

Desktop (please complete the following information):

  • OS: Win10 21H1 x64
  • Delphi 10.4.2
  • Latest source downloaded from this Git repository

using:
Sleep(1000);
PostMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
instead of SendMessage it seems to works.
I suppose there is a problem of "timing" from sending messagge and receiving...
Can you make some tests?

We got to the same conclusion, I was about to comment my findings. Using SendMessage and a sleep between 100 and 250 seems to make it to work.
It does not make sense, though. If the VCL thread is sleeping, it's not processing messages and SendMessage must wait until all top-level windows processed the message... what is happening here?

A solution can be to send a message only to the application itself:
PostMessage(GetCurrentProcess, WM_FONTCHANGE, 0, 0);
ops... doesn't works without sleep...

I did some testing. The message broadcast is for all other applications, the current one is unaffected (especially since it doesn't even have a topmost form in the moment the message is sent). If you replace PostMessage / SendMessage with a Sleep(xxx) it will still update the pictures in the imagelist.
Is threading used somewhere inside the component? I suspect some work is not yet done when the FontMissing event handler returns, causing the images to be corrupted / incomplete.

The images are not corrupted, simply when TIconFontItem.PaintTo is called, it performs a GDI+ drawing of the character of the font that is not yet available as a resource and it draws some "squares"...
this could be the problem:
https://www.vbforums.com/showthread.php?883637-GDI-problems-with-GdipCreateFontFamilyFromName

It is indeed going to be a drawing issue in the component. If you drop a label on the form, set the font name and copy-paste some characters, those will show up correctly on the label but not in the ImageList.

Because the label uses a "non GDI+" method to draw the font...
If you disable from IconFontsImageList.inc file the section:
{$IFDEF DXE4+}
{$Define GDI+}
{$ENDIF}
you can notice that the icons are painted correctly without the need to add a Sleep command...
there was some problem of alignment of font collection available into GDI+ context