Title bar buttons flicker in Windows 10
I am seeing this on Windows 10 64bit using HeidiSQL 9.3
I have the same problem but its not only heidi sql, all file browser windows and most of the application windows except chrome. Chrome windows and tabs are stand still and almost all other windows title bars flickering.
I realize something, i'm using slideshow desktop background and it does everything when background switch to another.
Probably its related about graphic adapter or windows itself.
here is it video i captured when it happens to show what its look like (skip to 25. sec)
https://www.youtube.com/watch?v=r9XoV0p69WE
Your video shows the issue quite well. Every window flickers when HeidiSQL window is visible. If Heidi is not visible, nothing flickers.
This post says I shall ensure the FullRepaint property of all TPanel instances are set. That is the case, I just checked that.
I could not find any other threads related to flickering Delphi XE5 applications yet.
HeidiSQL has some code in a so called TApplicationEvents.Idle event. That is, when the application does nothing, then do something. You can imagine that there is a chance that HeidiSQL does something weird here which could cause flicker, but the code in that event is written very carefully and lightweight.
It is more likely that the action list and imagelist which HeidiSQL has, is updated automatically by the underlying VCL library. For example, updating the enabled/disabled properties of all contained TActions could cause flicker. Indeed, in Delphi, when I add an image to Heidi's main TImageList, I can see a flicker issue for 1 or 2 seconds. Probably this has the same cause as the flicker in Win10.
What I already checked: FullRepaint property on all TPanel's: (was already the case)
There is more to check: DoubleBuffered property on all TMemo's:
I get this too - it's driving me mad - please please fix if at all possible as Heidi is otherwise an excellent tool! Is anyone actively working on this? I do have one 4k monitor and two smaller 1280 x 1024 monitors plugged in so I too have a mix of DPI but turning it off for Heidi is really undesirable!
Keep up the good work guys - it's a really really good product :-)
Bug triggers for me:
- group policy update at regular intervals, can be run manually:
gpupdate.exe /target:computer
. - change any checkbox and press Apply in Advanced System Settings - Visual Effects: see screenshot by
joaojacome
above.
Environment: Windows 10 Pro version 1607 (build 14393.187), HeidiSQL 9.3.0.5118.
I have no screen saver, animation settings made no difference.
Other related threads:
- Windows 10 - UI elements periodically flickering - Super User - superuser.com/questions/1011142/ui-elements-periodically-flickering
- The system slows down and the gui flickers while it repaints itself - Microsoft Community - answers.microsoft.com/en-us/insider/forum/insider_wintp-insider_perf/the-system-slows-down-and-the-gui-flickers-while/556f860f-0057-4d67-bfcc-2de06527b801
- Bug: HeidiSQL causes slowdowns on Windows 10 - www.heidisql.com/forum.php?t=18120
- Menu and bars are flickering under Windows 10 Insider Preview 14342 - www.heidisql.com/forum.php?t=21342
(I'm sorry, forum doesn't allow me to post links).
No problem - my fault for not posting a gif originally (I don't think the technology existed back then :P).
Yes, my problem is the hover state isn't kept - it just flickers on and off when the mouse moves. I can fix it by disabling DPI scaling on the .exe and it works fine (but obviously the window is not scaled).
Glad the other issue is fixed now tho.
Setting up Sticky Keys will cause this:
Control Panel\All Control Panel Items\Ease of Access Centre\Make the keyboard easier to use
- Click on: Set up Stick Keys
- Click on: first checkbox (toggle on or off)
- Click on: OK and screen elements like title bars and task bar and some windows will flicker.
Go back in and toggle it again and it will flicker again - very reliable. Exit HeidiSQL and there is no flicker.
This always happens on our site, when heidisql is open and group-policies get aplied (about every 15 minutes). Especially group-policies dealing with registry-entries or drive-mappings seem to cause the flickering. When no heidisql-instance is running, nothing flickers.
Each additional instance of heidisql causes the flicker to appear with a lower frequency, but making the whole system less responsive.
I assume that heidisql performs as some kind of "event-multiplier". It fires broadcast-events to all other processes, when some kind of external system-event arrives.
It´s really a pain in the ass.
Is someone still working on that issue?
That someone could only be me, but I don't currently. I was watching out for different suspicious automatic things which HeidiSQL does in the background. But without luck. Probably now that I am soon on Windows 10 finally, I will get some more background on what could cause the flickering.
Problem is easily reproduced by changing mouse speed in Windows mouse settings and hitting "apply". With HeidiSQL open, everything flickers for a few seconds like crazy until the settings are actually applied. Without HeidiSQL open, the settings are being applies instantly, no flickering.
Set DoubleBuffered property on main form, an attempt to reduce flickering on Windows 10. See https://www.heidisql.com/forum.php?t=19141
In the just added r5161, I am activating a "DoubleBuffered" property on the dialogs, which can probably help a bit against that flickering.
Btw, the Delphi IDE is even more flickering than HeidiSQL.
Will check further things.
I just reverted that change in r5162. Please update.
Reduce flicker on Windows 10. See https://www.heidisql.com/forum.php?t=19141
I am also facing the same issue from a long time. It's really frustrating. Let's see what happens after I update to r5165. I will keep you guys updated. I am sure we all can put our efforts and make sure this is fixed forever. And Thanks @ansgar
This might be related as if effects Delphi (All version / Windows 10)
In my case every 15 min the "Accent color" of my personalization settings was changing to match the current background picture.
In windows, Settings -> Colors -> Choose a Color -> switch off "Automatically pick an accent color from my background".
When activated, every 15 minutes windows 10 automagically pick an accent color from your background and fires 4x WM_DWMCOLORIZATIONCOLORCHANGED. That makes the IDE repaint itself like crazy.
The problem is the broadcast of WM_SETTINGCHANGE and how it is handled in the Delphi VCL. So not only HeidiSQL is causing this, also other Delphi based software (like our product, my little demo tool and the RAD Studio itself).
Description:
TApplication.WndProc calles a function named Default for each WM_SETTINGCHANGED and somewhere in the call chain the fonts and screen metrics are updated, regardless of what the Flag (lParam) of WM_SETTINGCHANGED implies.
The VCL calls a TCustomForm.CMFontChanged on that message and this then triggers TToolBar.CreateWnd and/or TCoolBar.CreatWnd which inturn destroys the Windows component underlying those Delphi components.
This causes a mass of WM_CREATE, WM_REPAINT, WM_ERASEBKGND, WM_DESTROY, CMFontChanged calls and so on: the flickering we see. And one can see that also on older Win-Boxes - confirmed Win7 x64.
The uggly part here is that thos calls happen before the programmer has a chance to influence the window message handling of the VCL. The only possibility I found is to utilize TApplication.HookMainWindow:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.ToolWin, AJ.Vcl.ComCtrls, Vcl.ImgList;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private-Deklarationen }
function HookMainWindow(var Message: TMessage): Boolean;
public
{ Public-Deklarationen }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
const
WM_MSG_OFFSET = WM_USER * 8;
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
begin
Application.HookMainWindow(HookMainWindow);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
Application.UnhookMainWindow(HookMainWindow);
end;
function TForm1.HookMainWindow(var Message: TMessage): Boolean;
const
WM_SETTINGCHANGE_OFFSET = 8 * WM_USER;
begin
Result := False;
if WM_SETTINGCHANGE = Message.Msg then
begin
case Message.WParam of
// Add the setting flag here that triggered the flickering.
0, 1, SPI_SETMOUSETRAILS, SPI_SETMOUSE, SPI_SETMOUSESPEED:
begin
// Do not eat the message, instead hide it from the normal handling by adding
// an offset. That way it remains possible to catch those messages by the
// normal message handler methods.
Inc(Message.Msg, WM_SETTINGCHANGE_OFFSET);
end;
end;
end;
end;
end.
TApplication.WndProc calles a function named Default for each WM_SETTINGCHANGED and somewhere in the call chain the fonts and screen metrics are updated, regardless of what the Flag (lParam) of WM_SETTINGCHANGED implies.
I apologize, the method in question is TApplication.CheckIniChange, not Default.
Thanks to that post we were able to fix a flickering issue by applying following patch (on forms.pas, Delphi2010 version).
Essense of the patch is to modify the TScreen.GetMetricSettings method so, that the Handle of diverse Fonts has only to be changed if there are significant changes of the fonts, not every time the method is called:
procedure SafeChangeFont(aFontToChange: TFont; aLogFont: tagLOGFONTW);
var
LTmpFont: TFont;
begin
LTmpFont := TFont.Create;
try
LTmpFont.Assign(aFontToChange);
LTmpFont.Handle := CreateFontIndirect(aLogFont);
if (LTmpFont.Size <> aFontToChange.Size)
or (LTmpFont.Name <> aFontToChange.Name)
or (LTmpFont.Style <> aFontToChange.Style) then
begin
aFontToChange.Handle := CreateFontIndirect(aLogFont);
end;
finally
FreeAndNil(LTmpFont);
end;
end;
// ... and then instead of
// FIconFont.Handle := CreateFontIndirect(LogFont);
// use
SafeChangeFont(FIconFont, LogFont);
Excellent - how will that solve the Heidi-Issue?
As uso perfectly described, the event WM_SETTINGCHANGE comes much more frequently in windows10 as in windows7. This change calls TScreen.GetMetricSettings which itself triggers change of five different system fonts (FIconFont, FHintFont, FMenuFont, FMessageFont and FCaptionFont) via assignment of their Handles to the newly created ones. Those TFont-instances are changed no matter whether the underlying fonts are really changed or not. Each of those Font-Instance changes triggers RecreateWnd of the ToolBars/CoolBars. So each CoolBar recreates itself 5 time. So multiply the number of CoolBars/ToolBars of all open windows in the delphi application with 5 and you will get the number of CoolBars/ToolBars recreations for each WM_SETTINGCHANGE event.
Our patch modifies the GetMetricSettings that way, that we are trying to recognize whether there are significant changes on system fonts before changing them. Most of the time the system fonts are not changed, so there is no need to trigger font instance changes and CoolBar/ToolBar recreations at all.
In our tests we've got no font changes at all. Possibly you'd like to extend the Modification-Check of the SafeChangeFont-procedure to consider font colour as well.
I was able to apply the "SafeChangeFont" patch to Vcl.Forms.pas in Delphi XE5, create a new Vcl.Forms.dcu and finally compile HeidiSQL. The result is a drastically reduced flicker in HeidiSQL for TPanel and TToolbutton but stay reduced at TPagecontrol. Tpagecontrol flickers the same way as the window size is changed.
I was able to apply the "SafeChangeFont" patch to Vcl.Forms.pas in Delphi XE5, create a new Vcl.Forms.dcu and finally compile HeidiSQL. The result is a drastically reduced flicker in HeidiSQL for TPanel and TToolbutton but stay reduced at TPagecontrol. Tpagecontrol flickers the same way as the window size is changed.
with latest svn version 5174 the flickering of TPanel and TToolbutton also disappeared.
Thanks to kostgr we nailed down a long standing Vcl bug.
Finally I used Delphi-Detours-Library
https COLON SLASH SLASH github DOT com/MahdiSafsafi/delphi-detours-library
(sorry I'm not allowed to post http links, yet) to inject a runtime patch (I do not like patching the RTL/VCL) of TScreen.GetScreenMetrics and created a TFontHelper.Equals function to simplify the comparison.
unit OScreenIntercept;
interface
type
TScreenIntercept = packed record
strict private type
TGetMetricSettings = procedure(const Self);
strict private class var
GetMetricSettings: TGetMetricSettings;
strict private
class constructor Create();
class destructor Destroy();
class procedure HookedGetMetricSettings(const Self); static;
public
class procedure ForceClassConstructorExec; static;
end;
implementation
uses
System.SysUtils, Winapi.Windows, Vcl.Forms, Vcl.Graphics
//
, DDetours
//
;
{ TFontHelper }
type
TFontHelper = class helper for TFont
public
function Equals(const AOther: TFont): Boolean;
end;
function TFontHelper.Equals(const AOther: TFont): Boolean;
begin
Result := (AOther.PixelsPerInch = self.PixelsPerInch)
and (AOther.Charset = self.Charset)
and (AOther.Color = self.Color)
and (AOther.Height = self.Height)
and (AOther.Name = self.Name)
and (AOther.Orientation = self.Orientation)
and (AOther.Pitch = self.Pitch)
and (AOther.Size = self.Size)
and (AOther.Style = self.Style)
and (AOther.Quality = self.Quality);
end;
{ TScreenIntercept }
class constructor TScreenIntercept.Create;
var
pGetMetricSettings: Pointer;
begin
asm
mov pGetMetricSettings, offset TScreen@GetMetricSettings
end;
TScreenIntercept.GetMetricSettings := InterceptCreate(pGetMetricSettings, @TScreenIntercept.HookedGetMetricSettings);
end;
class destructor TScreenIntercept.Destroy;
begin
if Assigned(TScreenIntercept.GetMetricSettings) then
begin
InterceptRemove(@TScreenIntercept.GetMetricSettings);
end;
end;
class procedure TScreenIntercept.ForceClassConstructorExec;
begin
// Call this function to force to compiler to execute the class constructor.
end;
class procedure TScreenIntercept.HookedGetMetricSettings(const Self);
procedure CheckedFontChange(const ACurrFont: TFont; const ANewFont: tagLOGFONTW);
var
TmpFont: TFont;
begin
TmpFont := TFont.Create;
try
TmpFont.Assign(ACurrFont);
TmpFont.Handle := CreateFontIndirect(ANewFont);
if not TmpFont.Equals(ACurrFont) then
begin
ACurrFont.Handle := CreateFontIndirect(ANewFont);
end;
finally
FreeAndNil(TmpFont);
end;
end;
var
LSize: Cardinal;
LogFont: TLogFont;
NonClientMetrics: TNonClientMetrics;
SaveShowHint: Boolean;
begin
// Patched copy of TScreen.GetScreenMetrics as suggested by kostgr.
end;
end.
Unfortunatly this code will not compile w/ DelphiXE5 and Win64 output. Error E1025 will raise. ASM and delphi code mixing isn't allowed for 64 bit compiler. Also using of a simple copy of the patched TScreen.GetScreenMetrics will not work, because of private variables of TScreen not visible outside.
FHintFont: TFont; FIconFont: TFont; FMenuFont: TFont; FMessageFont: TFont; FCaptionFont: TFont;
Unfortunatly this code will not compile w/ DelphiXE5 and Win64 output. Error E1025 will raise. ASM and delphi code mixing isn't allowed for 64 bit compiler. Also using of a simple copy of the patched TScreen.GetScreenMetrics will not work, because of private variables of TScreen not visible outside.
FHintFont: TFont; FIconFont: TFont; FMenuFont: TFont; FMessageFont: TFont; FCaptionFont: TFont;
I do not use the x64 compiler with XE7.
Concerning the private fields, I replaced them in my code with the corresponding public properties of TScreen and it works.
If your compiler does not allow mixing asm and Delphi functions, make a pure asm function and return the pointer to TScreen.GetScreenMetrics from there. See Stackoverflow (https COLON SLASH SLASH stackoverflow DOT com/a/36765512) to get an idea how.
Additionally, if you are using XE5 and do not have to be compatible with newer versions of Delphi (>= Berlin) you can also use class helpers to squeeze the GetScreenMetrics address out of TScreen and you can implement your own getters and setters for the mentioned private variables, too (in case side evects caused by the standard (g|s)etters arise).
Many thanks for your hints.
See below a working fix for heidiSQL 5174 combining work of kostgr and uso. The fix is tested w/ DelphiXE5 32- and 64-bit output.
unit Vcl.FormsFix;
interface
implementation
uses
System.SysUtils, Winapi.Windows, Vcl.Forms, Vcl.Graphics, System.UITypes
//
, DDetours
//
;
var
trampoline_GetMetricSettings: Procedure = nil;
type
TFontHelper = class helper for TFont
public
function Equals(const AOther: TFont): Boolean;
end;
function TFontHelper.Equals(const AOther: TFont): Boolean;
begin
Result := (AOther.PixelsPerInch = self.PixelsPerInch)
and (AOther.Charset = self.Charset)
and (AOther.Color = self.Color)
and (AOther.Height = self.Height)
and (AOther.Name = self.Name)
and (AOther.Orientation = self.Orientation)
and (AOther.Pitch = self.Pitch)
and (AOther.Size = self.Size)
and (AOther.Style = self.Style)
and (AOther.Quality = self.Quality);
end;
type
TScreenHelper = class Helper for TScreen
public
function getPtr_GetMetricSettings:Pointer;
end;
function TScreenHelper.getPtr_GetMetricSettings:Pointer;
begin
result:=@TScreen.GetMetricSettings;
end;
procedure HookedGetMetricSettings(const Self);
procedure CheckedFontChange(const ACurrFont: TFont; const ANewFont: tagLOGFONTW);
var
TmpFont: TFont;
begin
TmpFont := TFont.Create;
try
TmpFont.Assign(ACurrFont);
TmpFont.Handle := CreateFontIndirect(ANewFont);
if not TmpFont.Equals(ACurrFont) then
begin
ACurrFont.Handle := CreateFontIndirect(ANewFont);
end;
finally
FreeAndNil(TmpFont);
end;
end;
var
LSize: Cardinal;
LogFont: TLogFont;
NonClientMetrics: TNonClientMetrics;
SaveShowHint: Boolean;
begin
SaveShowHint := False;
if Assigned(Application) then SaveShowHint := Application.ShowHint;
try
if Assigned(Application) then Application.ShowHint := False;
{$IF DEFINED(CLR)}
LSize := Marshal.SizeOf(TypeOf(TLogFont));
{$ELSE}
LSize := SizeOf(TLogFont);
{$ENDIF}
if SystemParametersInfo(SPI_GETICONTITLELOGFONT, LSize, {$IFNDEF CLR}@{$ENDIF}LogFont, 0) then
begin
CheckedFontChange(Screen.IconFont, LogFont);
end
else
Screen.IconFont.Handle := GetStockObject(SYSTEM_FONT);
{$IF DEFINED(CLR)}
LSize := Marshal.SizeOf(TypeOf(TNonClientMetrics));
{$ELSE}
LSize := TNonClientMetrics.SizeOf;
{$ENDIF}
NonClientMetrics.cbSize := LSize;
if SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, {$IFNDEF CLR}@{$ENDIF}NonClientMetrics, 0) then
begin
CheckedFontChange(Screen.HintFont, NonClientMetrics.lfStatusFont);
CheckedFontChange(Screen.MenuFont, NonClientMetrics.lfMenuFont);
CheckedFontChange(Screen.MessageFont, NonClientMetrics.lfMessageFont);
CheckedFontChange(Screen.CaptionFont, NonClientMetrics.lfCaptionFont);
end else
begin
Screen.HintFont.Size := 8;
Screen.MenuFont.Handle := GetStockObject(SYSTEM_FONT);
Screen.MessageFont.Handle := GetStockObject(SYSTEM_FONT);
Screen.CaptionFont.Handle := GetStockObject(SYSTEM_FONT);
end;
Screen.HintFont.Color := clInfoText;
Screen.MenuFont.Color := clMenuText;
Screen.MessageFont.Color := clWindowText;
finally
if Assigned(Application) then Application.ShowHint := SaveShowHint;
end;
end;
initialization
@trampoline_GetMetricSettings := InterceptCreate(Screen.getPtr_GetMetricSettings, @HookedGetMetricSettings);
finalization
InterceptRemove(@trampoline_GetMetricSettings);
end.
I think I have that fix working here, including the Delphi Detours library. Only one harmless compiler warning remains.
However, I need to update HeidiSQL's AuthentiCode certificate, which has expired some weeks ago. Without a new one, the heidisql.exe updates don't get any certificate, which will bring up the dreaded security dialog on Win10 after downloading. Well, I got it from Certum previously, but that doesn't seem to work any longer, and their page is horrribly translated from Polish and non-working in many places. I managed to buy a certificate there, but I cannot activate it, for some reason. Waiting for response from Certum now, otherwise my 35€ will be gone.
New attempt to fix menu and buttons flicker on Win10, this time by with the help of Delphi Detours library. See https://www.heidisql.com/forum.php?t=19141
Here we go: r5175 has the patch with the Detours library. Seems to work here now, with the nice help from Thomas.
What I could not manage is to get a new AuthentiCode certificate, for signing heidisql.exe so Win10 does not complain after downloading. So, if you decide to update HeidiSQL, you need to ignore the Windows Defender SmartScreen warning message. Certum.pl requires some Crypt card hardware, Comodo requires a validation via notary or attorney, as my business is not registered on dnb.com . Although I'm registered at the German Finanzamt, grrr...
Here we go: r5175 has the patch with the Detours library. Seems to work here now, with the nice help from Thomas.
Comodo requires a validation via notary or attorney, as my business is not registered on dnb.com . Although I'm registered at the German Finanzamt, grrr...
If you register as an individual (just with your personal name) and not as a company (or any generic description like "Open Source Developer...", you won't need to be registered at dnb. They will ask you for three different documents proving you are you and you live where you claim you do (e.g. phone bill, electricity bill, etc.) and they will call you to verify your phone number. The process is quite ennoying in my experience, but at least it always worked out so far in the end.
Clean up:
* remove Detours package, move code to /source/detours/
* remove Detours code from /source/vcl-styles-utils/delphi-detours-library/, so we have only one version
* remove Vcl.FormsFix.pas, as the bugs I fixed with that are most likely fixed with the move to Delphi 10. See https://www.heidisql.com/forum.php?t=19141 for the original bug report.
* only vcl-styles-utils uses the Detours lib from now on
Back to the topic of this thread: I have upgraded to Delphi 10.2 recently, and removed the above mentioned workaround with the Detours library, for avoiding flicker on Windows 10. For me the newer builds work without flicker even without that workaround. Would be nice to get some feedback from users which saw this flicker when changing the mouse speed for example, after updating the newest HeidiSQL build.
Please login to leave a reply, or register at first.