Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make hovering over Minimize, Maximize, and Close buttons behave?

Tags:

In a Delphi application, when you hover over a border icon, e.g.:

  • Minimize
  • Maximize
  • Restore

it doesn't behave correctly:

enter image description here

Compare to an application that does behave correctly:

enter image description here

Step to Reproduce

  1. Click File, New, VCL Forms Application - Delphi
  2. Click Run (F9)
  3. Hover over the Minimize, Maximize, or Close buttons.

How to fix?

  • Windows 10, 64-bit (running natively on desktop PC)
  • Delphi XE6

Edit - It also fails with Delphi 7:

enter image description here

and in Delphi 5:

enter image description here

and in Delphi 4:

enter image description here

I assumed (i.e. was afraid) that it was caused by the ThemeServices engine; where they might have thought it was cool to not honor the user's preferences. But looks like it's something more fundamental.

Compatibility Modes

  • none: fails
  • Windows 8: fails
  • Windows 7: fails
  • Windows Vista (Service Pack 2): fails
  • Windows Vista (Service Pack 2): fails
  • Windows Vista: fails
  • Windows XP (Service Pack 3) (non-client area theming disabled): works
  • Windows XP (Service Pack 2) (non-client area theming disabled): works
  • Windows 98 / Windows Me (non-client area theming disabled): works
  • Windows 95 (non-client area theming disabled): works

Skype

Also fails in Skype; also written in Delphi:

enter image description here

High DPI is the trigger

I finally figured out why it fails on every Windows 10 machine i've used; but not for everyone. High dpi.

Set your dpi to 97 (101%) or higher.

Close Enough

Dalija's solutions works:

enter image description here

We'll ignore the problem with the tooltip and live to fight another day.

It should also be noted that Windows 10 will suggest that you might have to sign off and sign back on for some applications to work correctly after changing the DPI. This is definitely true of Delphi.

It should also be noted that Delphi doesn't tolerate the DPI changing behind its back like this. This includes adjusting the zoom slider. This would also include placing the app on any monitor besides the primary monitor.

And we never did figure out what the problem is; only kicked it down the road for users running multiple monitors.

QC Bug Report

Because Bor...Impr...CodeG...Embarca... Idera's QC site is behind a pay-wall, here's a copy of the bug report:

  • http://archive.is/v77rz

As you can see: nobody cares.

like image 767
Ian Boyd Avatar asked Jul 25 '15 19:07

Ian Boyd


People also ask

Which buttons are used to minimize maximize and close the program?

Minimizing, maximizing, and restoring windowsThe Minimize button is among the three buttons at the right end of the title bar. This button has a small dash (or minus sign). The Minimize button shrinks the window and places it on the taskbar while leaving the program running.

Where do you find maximize and minimize buttons?

Small buttons, usually located in the upper right corner of the window's title bar (optional feature). When activated, these buttons reduce the window to an icon or enlarge the window to its largest supported size, respectively.

Why Minimise Maximise close buttons missing?

If your computer supports the touchscreen feature, you might not see the title bar and the Minimize, Maximize, and Close buttons because Tablet mode is enabled. The easiest way to exit Tablet mode is to open Action Center and click on the Tablet tile to turn it off.


1 Answers

High DPI is the trigger and it leads to the solution.

Applications that exhibit the issue are not High DPI aware. Solution to hovering problem is to make them aware or turn on associated compatibility mode by using one of solutions under 1, 2 or 3.

Note: whether will rest of the application behave properly when High DPI awareness is turned on is another issue and will differ from application to application.

  1. Under compatibility mode check "Disable display scaling on high DPI settings"

  2. Call SetProcessDPIAware as first call in .dpr file - as noted by Ian Boyd, calling this function can leat to race condition and preferred way is using manifest. SetProcessDPIAware

  3. Use custom manifest with true or true/PM setting (default Delphi manifest included with "Enable runtime themes" is not high DPI aware)

Current versions of Delphi VCL and FMX frameworks lack support for per monitor DPI awareness, so use true/PM manifest only if you are handling per monitor DPI yourself. Reported to QP as VCL and FireMonkey lack Per-Monitor DPI support for Windows 8.1 (and Windows 10)


  <asmv3:application>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>true</dpiAware>
    </asmv3:windowsSettings>
  </asmv3:application>

or

  <asmv3:application>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>true/PM</dpiAware>
    </asmv3:windowsSettings>
  </asmv3:application>

Update:

Delphi VCL is source of buggy behavior, specifically issue is somewhere in TForm class or its ancestors. When direct Windows API is used resulting windows behave normally.

Windows API code that behaves properly:

  MessageBox(0, 'Correct', 'Caption', MB_OK); 

  ShowMessage('Correct'); // if themes are enabled -> Windows Task dialog is used

Full Delphi sample app that creates main window without using VCL - behaves properly

program win;

{$R *.res}

uses
  Windows,
  Messages,
  SysUtils;

var
  Msg: TMSG;
  LWndClass: TWndClass;
  hMainHandle: HWND;

function WindowProc(HWND, Msg: Longint; wParam: wParam; lParam: lParam): Longint; stdcall;
begin
  if Msg = WM_DESTROY then PostQuitMessage(0);
  Result := DefWindowProc(HWND, Msg, wParam, lParam);
end;

begin
  LWndClass.hInstance := hInstance;
  with LWndClass do
    begin
      lpszClassName := 'WinApiWnd';
      Style := CS_PARENTDC or CS_BYTEALIGNCLIENT;
      hIcon := LoadIcon(hInstance, 'MAINICON');
      lpfnWndProc := @WindowProc;
      hbrBackground := COLOR_BTNFACE + 1;
      hCursor := LoadCursor(0, IDC_ARROW);
    end;

  RegisterClass(LWndClass);
  hMainHandle := CreateWindow(LWndClass.lpszClassName, 'Window Title', WS_CAPTION or WS_MINIMIZEBOX or WS_SYSMENU or WS_VISIBLE, 0, 0, 360, 200, 0, 0, hInstance, nil);

  while GetMessage(Msg, 0, 0, 0) do
    begin
      TranslateMessage(Msg);
      DispatchMessage(Msg);
    end;
end.

Misbehaved VCL forms:

var
  f: TForm;

  f := CreateMessageDialog('Broken', mtWarning, mbOKCancel, mbOk);
  f.ShowModal;
  f.Free;

  f := TForm.Create(nil);
  f.ShowModal;
  f.Free;
like image 56
Dalija Prasnikar Avatar answered Oct 14 '22 22:10

Dalija Prasnikar