win32: a trial to correct application focus lose when local stay on top windows are involved (issue #0018494)

git-svn-id: trunk@30228 -
This commit is contained in:
paul 2011-04-07 02:30:35 +00:00
parent 6c7c35c17b
commit f37b868f3a
3 changed files with 40 additions and 36 deletions

View File

@ -1006,6 +1006,8 @@ begin
WinProcess := True; WinProcess := True;
NotifyUserInput := False; NotifyUserInput := False;
// WriteLn('Msg: ', WM_To_String(Msg));
WindowInfo := GetWin32WindowInfo(Window); WindowInfo := GetWin32WindowInfo(Window);
if WindowInfo^.isChildEdit then if WindowInfo^.isChildEdit then
begin begin
@ -2207,14 +2209,14 @@ begin
begin begin
//WriteLn('Restore'); //WriteLn('Restore');
RestoreStayOnTopFlags(Window); RestoreStayOnTopFlags(Window);
if assigned(Application) then if Assigned(Application) then
Application.IntfAppActivate; Application.IntfAppActivate;
end end
else else
begin // deactivated begin // deactivated
//WriteLn('Remove'); //WriteLn('Remove');
RemoveStayOnTopFlags(Window); RemoveStayOnTopFlags(Window);
if assigned(Application) then if Assigned(Application) then
Application.IntfAppDeactivate; Application.IntfAppDeactivate;
end; end;
end; end;

View File

@ -99,8 +99,8 @@ function AllocWindowInfo(Window: HWND): PWin32WindowInfo;
function DisposeWindowInfo(Window: HWND): boolean; function DisposeWindowInfo(Window: HWND): boolean;
function GetWin32WindowInfo(Window: HWND): PWin32WindowInfo; function GetWin32WindowInfo(Window: HWND): PWin32WindowInfo;
procedure RemoveStayOnTopFlags(Window: HWND; ASystemTopAlso: Boolean = False); procedure RemoveStayOnTopFlags(AppHandle: HWND; ASystemTopAlso: Boolean = False);
procedure RestoreStayOnTopFlags(Window: HWND); procedure RestoreStayOnTopFlags(AppHandle: HWND);
procedure HidePopups(AppHandle: HWND); procedure HidePopups(AppHandle: HWND);
procedure RestorePopups; procedure RestorePopups;
@ -132,6 +132,7 @@ procedure UpdateWindowsVersion;
type type
PStayOnTopWindowsInfo = ^TStayOnTopWindowsInfo; PStayOnTopWindowsInfo = ^TStayOnTopWindowsInfo;
TStayOnTopWindowsInfo = record TStayOnTopWindowsInfo = record
AppHandle: HWND;
SystemTopAlso: Boolean; SystemTopAlso: Boolean;
StayOnTopList: TList; StayOnTopList: TList;
end; end;
@ -920,76 +921,76 @@ end;
function EnumStayOnTopRemove(Handle: HWND; Param: LPARAM): WINBOOL; stdcall; function EnumStayOnTopRemove(Handle: HWND; Param: LPARAM): WINBOOL; stdcall;
var var
AStyle: DWord;
StayOnTopWindowsInfo: PStayOnTopWindowsInfo absolute Param; StayOnTopWindowsInfo: PStayOnTopWindowsInfo absolute Param;
lWindowInfo: PWin32WindowInfo; lWindowInfo: PWin32WindowInfo;
lWinControl: TWinControl; lWinControl: TWinControl;
begin begin
Result := True; Result := True;
AStyle := GetWindowLong(Handle, GWL_EXSTYLE); if ((GetWindowLong(Handle, GWL_EXSTYLE) and WS_EX_TOPMOST) <> 0) then
if (AStyle and WS_EX_TOPMOST) <> 0 then // if stay on top then
begin begin
// Don't remove system-wide stay on top, unless desired // Don't remove system-wide stay on top, unless desired
if not StayOnTopWindowsInfo^.SystemTopAlso then if not StayOnTopWindowsInfo^.SystemTopAlso then
begin begin
lWindowInfo := GetWin32WindowInfo(Handle); lWindowInfo := GetWin32WindowInfo(Handle);
if (lWindowInfo <> nil) then if Assigned(lWindowInfo) then
begin begin
lWinControl := lWindowInfo^.WinControl; lWinControl := lWindowInfo^.WinControl;
if (lWinControl <> nil) and (lWinControl is TCustomForm) if Assigned(lWinControl) and
and (TCustomForm(lWinControl).FormStyle = fsSystemStayOnTop) then (lWinControl is TCustomForm) and
(TCustomForm(lWinControl).FormStyle = fsSystemStayOnTop) then
Exit; Exit;
end; end;
end; end;
StayOnTopWindowsInfo^.StayOnTopList.Add(Pointer(Handle)); StayOnTopWindowsInfo^.StayOnTopList.Add(Pointer(Handle));
SetWindowPos(Handle, HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOOWNERZORDER or SWP_NOSENDCHANGING);
end; end;
end; end;
procedure RemoveStayOnTopFlags(Window: HWND; ASystemTopAlso: Boolean = False); procedure RemoveStayOnTopFlags(AppHandle: HWND; ASystemTopAlso: Boolean = False);
var var
StayOnTopWindowsInfo: PStayOnTopWindowsInfo; StayOnTopWindowsInfo: PStayOnTopWindowsInfo;
WindowInfo: PWin32WindowInfo; WindowInfo: PWin32WindowInfo;
I: Integer;
begin begin
// WriteLn('RemoveStayOnTopFlags 1'); //WriteLn('RemoveStayOnTopFlags ', InRemoveStayOnTopFlags);
if InRemoveStayOnTopFlags = 0 then if InRemoveStayOnTopFlags = 0 then
begin begin
New(StayOnTopWindowsInfo); New(StayOnTopWindowsInfo);
StayOnTopWindowsInfo^.AppHandle := AppHandle;
StayOnTopWindowsInfo^.SystemTopAlso := ASystemTopAlso; StayOnTopWindowsInfo^.SystemTopAlso := ASystemTopAlso;
StayOnTopWindowsInfo^.StayOnTopList := TList.Create; StayOnTopWindowsInfo^.StayOnTopList := TList.Create;
WindowInfo := GetWin32WindowInfo(Window); WindowInfo := GetWin32WindowInfo(AppHandle);
WindowInfo^.StayOnTopList := StayOnTopWindowsInfo^.StayOnTopList; WindowInfo^.StayOnTopList := StayOnTopWindowsInfo^.StayOnTopList;
EnumThreadWindows(GetWindowThreadProcessId(Window, nil), EnumThreadWindows(GetWindowThreadProcessId(AppHandle, nil),
@EnumStayOnTopRemove, LPARAM(StayOnTopWindowsInfo)); @EnumStayOnTopRemove, LPARAM(StayOnTopWindowsInfo));
for I := 0 to WindowInfo^.StayOnTopList.Count - 1 do
SetWindowPos(HWND(WindowInfo^.StayOnTopList[I]), HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOOWNERZORDER or SWP_DRAWFRAME);
Dispose(StayOnTopWindowsInfo); Dispose(StayOnTopWindowsInfo);
end; end;
inc(InRemoveStayOnTopFlags); inc(InRemoveStayOnTopFlags);
// WriteLn('RemoveStayOnTopFlags 2');
end; end;
procedure RestoreStayOnTopFlags(Window: HWND); procedure RestoreStayOnTopFlags(AppHandle: HWND);
var var
WindowInfo: PWin32WindowInfo; WindowInfo: PWin32WindowInfo;
I: integer; I: integer;
begin begin
// WriteLn('RestoreStayOnTopFlags 1'); //WriteLn('RestoreStayOnTopFlags ', InRemoveStayOnTopFlags);
if InRemoveStayOnTopFlags = 1 then if InRemoveStayOnTopFlags = 1 then
begin begin
WindowInfo := GetWin32WindowInfo(Window); WindowInfo := GetWin32WindowInfo(AppHandle);
if WindowInfo^.StayOnTopList <> nil then if WindowInfo^.StayOnTopList <> nil then
begin begin
for I := 0 to WindowInfo^.StayOnTopList.Count - 1 do for I := 0 to WindowInfo^.StayOnTopList.Count - 1 do
SetWindowPos(HWND(WindowInfo^.StayOnTopList.Items[I]), SetWindowPos(HWND(WindowInfo^.StayOnTopList.Items[I]),
HWND_TOPMOST, 0, 0, 0, 0, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOOWNERZORDER or SWP_NOSENDCHANGING); SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOOWNERZORDER or SWP_DRAWFRAME);
FreeAndNil(WindowInfo^.StayOnTopList); FreeAndNil(WindowInfo^.StayOnTopList);
end; end;
end; end;
if InRemoveStayOnTopFlags > 0 then if InRemoveStayOnTopFlags > 0 then
dec(InRemoveStayOnTopFlags); dec(InRemoveStayOnTopFlags);
// WriteLn('RestoreStayOnTopFlags 2');
end; end;
function EnumHidePopups(Handle: HWND; Param: LPARAM): WINBOOL; stdcall; function EnumHidePopups(Handle: HWND; Param: LPARAM): WINBOOL; stdcall;

View File

@ -493,14 +493,15 @@ begin
if (lWindowInfo <> nil) then if (lWindowInfo <> nil) then
begin begin
lWinControl := lWindowInfo^.WinControl; lWinControl := lWindowInfo^.WinControl;
if (lWinControl <> nil) and (lWinControl is TCustomForm) if Assigned(lWinControl) and
and (TCustomForm(lWinControl).FormStyle in fsAllStayOnTop) (lWinControl is TCustomForm) and
and not (csDesigning in TCustomForm(lWinControl).ComponentState) then (TCustomForm(lWinControl).FormStyle in fsAllStayOnTop) and
not (csDesigning in lWinControl.ComponentState) then
list.Add(Pointer(Handle)); list.Add(Pointer(Handle));
end; end;
end; end;
procedure EnumStayOnTop(window: THandle; dstlist: TList); procedure EnumStayOnTop(Window: THandle; dstlist: TList);
begin begin
EnumThreadWindows(GetWindowThreadProcessId(Window, nil), EnumThreadWindows(GetWindowThreadProcessId(Window, nil),
@EnumStayOnTopProc, LPARAM(dstlist)); @EnumStayOnTopProc, LPARAM(dstlist));
@ -508,6 +509,8 @@ end;
class procedure TWin32WSCustomForm.SetFormStyle(const AForm: TCustomform; class procedure TWin32WSCustomForm.SetFormStyle(const AForm: TCustomform;
const AFormStyle, AOldFormStyle: TFormStyle); const AFormStyle, AOldFormStyle: TFormStyle);
const
WindowPosFlags = SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOOWNERZORDER;
var var
toplist: TList; toplist: TList;
i: Integer; i: Integer;
@ -518,7 +521,7 @@ begin
if (AOldFormStyle = fsNormal) and (AFormStyle in fsAllStayOnTop) then if (AOldFormStyle = fsNormal) and (AFormStyle in fsAllStayOnTop) then
begin begin
if not (csDesigning in AForm.ComponentState) then if not (csDesigning in AForm.ComponentState) then
SetWindowPos(AForm.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE) SetWindowPos(AForm.Handle, HWND_TOPMOST, 0, 0, 0, 0, WindowPosFlags)
// From StayOnTop to normal // From StayOnTop to normal
end end
else else
@ -546,12 +549,10 @@ begin
toplist := TList.Create; toplist := TList.Create;
try try
EnumStayOnTop(AForm.Handle, toplist); EnumStayOnTop(AForm.Handle, toplist);
SetWindowPos(AForm.Handle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE); SetWindowPos(AForm.Handle, HWND_NOTOPMOST, 0, 0, 0, 0, WindowPosFlags);
for i := 0 to toplist.Count - 1 do for i := 0 to toplist.Count - 1 do
begin
if HWND(toplist[i]) <> AForm.Handle then if HWND(toplist[i]) <> AForm.Handle then
SetWindowPos(HWND(toplist[i]), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE); SetWindowPos(HWND(toplist[i]), HWND_TOPMOST, 0, 0, 0, 0, WindowPosFlags);
end;
finally finally
toplist.Free; toplist.Free;
end; end;