Hello Mattias
Can you explain, what you are trying to do? How do you want to solve the bug?
I think I just solved that bug. It was quite easy, once I understand what to do and especially where to apply the change. I've included the complete patch (including the show modal patch posted earlier) in the attachment.

What I did is simple. I saved the (topmost) state of the windows to a list (which is part of the TWin32WidgetSet) and changed their behavior to fix the bug. After the modal window is closed, I recall the state of the windows according to the list.

This is very similar to what the VCL does and I tried to use the same conventions if possible. Looking at the VCL source code it might be useful to have those new public functions: NormalizeAllTopMosts; NormalizeTopMosts; RestoreTopMosts; for other things (like minimize etc.)

The patch needs to be verified, but here everything works as expected.

   Christian

P.S.: Any ideas what to do with this patch now?
Index: win32callback.inc
===================================================================
--- win32callback.inc   (revision 9708)
+++ win32callback.inc   (working copy)
@@ -657,26 +657,37 @@
     lControl: TControl;
     BoundsOffset: TRect;
   begin
-    if (lWinControl <> nil) and not (csDesigning in lWinControl.ComponentState)
-      and (Lo(LParam) = HTCLIENT) then
-    begin
-      Windows.GetCursorPos(Windows.POINT(P));
-      Windows.ScreenToClient(Window, Windows.POINT(P));
-      if GetLCLClientBoundsOffset(lWinControl.Parent, BoundsOffset) then
-      begin
-        Dec(P.X, BoundsOffset.Left);
-        Dec(P.Y, BoundsOffset.Top);
+    if (lWinControl <> nil) and not (csDesigning in 
lWinControl.ComponentState) then
+      case Lo(LParam) of
+        HTCLIENT:
+          begin
+            Windows.GetCursorPos(Windows.POINT(P));
+            Windows.ScreenToClient(Window, Windows.POINT(P));
+            if GetLCLClientBoundsOffset(lWinControl.Parent, BoundsOffset) then
+            begin
+              Dec(P.X, BoundsOffset.Left);
+              Dec(P.Y, BoundsOffset.Top);
+            end;
+            // statictext controls do not get WM_SETCURSOR messages...
+            lControl := lWinControl.ControlAtPos(P, false, true);
+            if lControl = nil then
+              lControl := lWinControl;
+            if lControl.Cursor <> crDefault then
+            begin
+              Windows.SetCursor(Windows.LoadCursor(0, 
LclCursorToWin32CursorMap[lControl.Cursor]));
+              LMessage.Result := 1;
+            end;
+          end;
+        HTERROR:
+          begin
+            if (Hi(LParam) = WM_LBUTTONDOWN) and 
(TWin32WidgetSet(WidgetSet).AppHandle <> 0) and
+              (GetForegroundWindow <> 
GetLastActivePopup(TWin32WidgetSet(WidgetSet).AppHandle)) then
+            begin
+              Application.BringToFront;
+              Exit;
+            end;
+          end;
       end;
-      // statictext controls do not get WM_SETCURSOR messages...
-      lControl := lWinControl.ControlAtPos(P, false, true);
-      if lControl = nil then
-        lControl := lWinControl;
-      if lControl.Cursor <> crDefault then
-      begin
-        Windows.SetCursor(Windows.LoadCursor(0, 
LclCursorToWin32CursorMap[lControl.Cursor]));
-        LMessage.Result := 1;
-      end;
-    end;
     if LMessage.Result = 0 then
     begin
       LMessage.Msg := LM_SETCURSOR;
@@ -1144,9 +1155,14 @@
         LMessage.Msg := LM_SETEDITABLE;
       If Window=TWin32WidgetSet(WidgetSet).FAppHandle then
         if WParam=0 then
-          DisableApplicationWindows(Window)
-        else
+        begin
+          DisableApplicationWindows(Window);
+          TWin32WidgetSet(WidgetSet).NormalizeAllTopMosts;
+        end else
+        begin
+          TWin32WidgetSet(WidgetSet).RestoreTopMosts;
           EnableApplicationWindows(Window);
+        end;
 
       If (lWinControl is TCustomFloatSpinEdit) then
         EnableFloatSpinEditBuddy(Window, WParam<>0);
Index: win32int.pp
===================================================================
--- win32int.pp (revision 9708)
+++ win32int.pp (working copy)
@@ -146,6 +146,9 @@
     FWaitHandlers: array of TWaitHandler;
     FWaitPipeHandlers: PPipeEventInfo;
 
+    FTopMostList: TList;
+    FTopMostLevel: Integer;
+
     FThemesActive: boolean;
     FThemeLibrary: HMODULE;
     IsThemeActive: function: LongBool; stdcall;
@@ -167,6 +170,7 @@
     Function WinRegister: Boolean;
     Procedure NormalizeIconName(Var IconName: String);
     Procedure NormalizeIconName(Var IconName: PChar);
+    procedure DoNormalizeTopMosts(IncludeMain: Boolean);
 
   Public
     { Creates a callback of Lazarus message Msg for Sender }
@@ -198,6 +202,10 @@
     procedure UpdateThemesActive;
     procedure ShowHide(Sender: TObject);
 
+    procedure NormalizeAllTopMosts;
+    procedure NormalizeTopMosts;
+    procedure RestoreTopMosts;
+
     // create and destroy
     function CreateComponent(Sender : TObject): THandle; override;
     function CreateTimer(Interval: integer; TimerFunc: TFNTimerProc) : 
integer; override;
@@ -316,4 +324,4 @@
 
   Assert(False, 'Trace:win32int.pp - Finalization');
 
-end.
\ No newline at end of file
+end.
Index: win32object.inc
===================================================================
--- win32object.inc     (revision 9708)
+++ win32object.inc     (working copy)
@@ -32,6 +32,7 @@
 Begin
   Inherited Create;
   FTimerData  := TList.Create;
+  FTopMostList := TList.Create;
   FMetrics.cbSize := SizeOf(FMetrics);
   FMetricsFailed := not Windows.SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
     SizeOf(FMetrics), @FMetrics, 0);
@@ -105,7 +106,9 @@
   end;
 
   FTimerData.Free;
+  FTopMostList.Free;
 
+
   if FAppHandle <> 0 then
     DestroyWindow(FAppHandle);
 
@@ -224,8 +227,16 @@
   Brings the entire application on top of all other non-topmost programs
  
------------------------------------------------------------------------------}
 procedure TWin32WidgetSet.AppBringToFront;
+var
+  TopWindow: HWnd;
 begin
-  Windows.SetForegroundWindow(FAppHandle);
+  if FAppHandle <> 0 then
+  begin
+    TopWindow := GetLastActivePopup(FAppHandle);
+    if (TopWindow <> 0) and (TopWindow <> FAppHandle) and
+      IsWindowVisible(TopWindow) and IsWindowEnabled(TopWindow) then
+      Windows.SetForegroundWindow(TopWindow);
+  end;
 end;
 
 procedure TWin32WidgetSet.SetDesigning(AComponent: TComponent);
@@ -564,6 +575,56 @@
   IconName := StrToPChar(Str);
 End;
 
+type
+  PTopMostEnumInfo = ^TTopMostEnumInfo;
+  TTopMostEnumInfo = record
+    TopWindow: HWND;
+    IncludeMain: Boolean;
+    W32Widget: TWin32WidgetSet;
+  end;
+
+function GetTopMostWindows(Handle: HWND; Info: LongInt): BOOL; stdcall;
+begin
+  Result := True;
+  if GetWindow(Handle, GW_OWNER) = PTopMostEnumInfo(Info)^.W32Widget.AppHandle 
then
+    if (GetWindowLong(Handle, GWL_EXSTYLE) and WS_EX_TOPMOST <> 0) and
+      (PTopMostEnumInfo(Info)^.IncludeMain {or (Application.MainForm = nil) or
+      (Handle <> Application.MainForm.Handle)}) then
+      PTopMostEnumInfo(Info)^.W32Widget.FTopMostList.Add(Pointer(Handle))
+    else
+    begin
+      PTopMostEnumInfo(Info)^.TopWindow := Handle;
+      Result := False;
+    end;
+end;
+
+procedure TWin32WidgetSet.DoNormalizeTopMosts(IncludeMain: Boolean);
+var
+  I: Integer;
+  Info: TTopMostEnumInfo;
+begin
+  if FAppHandle <> 0 then
+  begin
+    if FTopMostLevel = 0 then
+    begin
+      Info.TopWindow := FAppHandle;
+      Info.IncludeMain := IncludeMain;
+      Info.W32Widget := self;
+      EnumWindows(@GetTopMostWindows, Longint(@Info));
+      if FTopMostList.Count <> 0 then
+      begin
+        Info.TopWindow := GetWindow(Info.TopWindow, GW_HWNDPREV);
+        if GetWindowLong(Info.TopWindow, GWL_EXSTYLE) and WS_EX_TOPMOST <> 0 
then
+          Info.TopWindow := HWND_NOTOPMOST;
+        for I := FTopMostList.Count - 1 downto 0 do
+          SetWindowPos(HWND(FTopMostList[I]), Info.TopWindow, 0, 0, 0, 0,
+            SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOOWNERZORDER);
+      end;
+    end;
+    Inc(FTopMostLevel);
+  end;
+end;
+
  
{------------------------------------------------------------------------------
   Function: TWin32WidgetSet.CreateComponent
   Params:   Sender - object for which to create visual representation
@@ -637,6 +698,33 @@
   End;
 End;
 
+procedure TWin32WidgetSet.NormalizeAllTopMosts;
+begin
+  DoNormalizeTopMosts(True);
+end;
+
+procedure TWin32WidgetSet.NormalizeTopMosts;
+begin
+  DoNormalizeTopMosts(False);
+end;
+
+procedure TWin32WidgetSet.RestoreTopMosts;
+var
+  I: Integer;
+begin
+  if (AppHandle <> 0) and (FTopMostLevel > 0) then
+  begin
+    Dec(FTopMostLevel);
+    if FTopMostLevel = 0 then
+    begin
+      for I := FTopMostList.Count - 1 downto 0 do
+        SetWindowPos(HWND(FTopMostList[I]), HWND_TOPMOST, 0, 0, 0, 0,
+          SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOOWNERZORDER);
+      FTopMostList.Clear;
+    end;
+  end;
+end;
+
 {------------------------------------------------------------------------------
   Method: TWin32WidgetSet.DCReDraw
   Params: CanvasHandle - HDC to redraw

Reply via email to