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;
NotifyUserInput := False;
// WriteLn('Msg: ', WM_To_String(Msg));
WindowInfo := GetWin32WindowInfo(Window);
if WindowInfo^.isChildEdit then
begin
@ -2207,15 +2209,15 @@ begin
begin
//WriteLn('Restore');
RestoreStayOnTopFlags(Window);
if assigned(Application) then
Application.IntfAppActivate;
if Assigned(Application) then
Application.IntfAppActivate;
end
else
begin // deactivated
//WriteLn('Remove');
RemoveStayOnTopFlags(Window);
if assigned(Application) then
Application.IntfAppDeactivate;
if Assigned(Application) then
Application.IntfAppDeactivate;
end;
end;
end;

View File

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

View File

@ -493,14 +493,15 @@ begin
if (lWindowInfo <> nil) then
begin
lWinControl := lWindowInfo^.WinControl;
if (lWinControl <> nil) and (lWinControl is TCustomForm)
and (TCustomForm(lWinControl).FormStyle in fsAllStayOnTop)
and not (csDesigning in TCustomForm(lWinControl).ComponentState) then
if Assigned(lWinControl) and
(lWinControl is TCustomForm) and
(TCustomForm(lWinControl).FormStyle in fsAllStayOnTop) and
not (csDesigning in lWinControl.ComponentState) then
list.Add(Pointer(Handle));
end;
end;
procedure EnumStayOnTop(window: THandle; dstlist: TList);
procedure EnumStayOnTop(Window: THandle; dstlist: TList);
begin
EnumThreadWindows(GetWindowThreadProcessId(Window, nil),
@EnumStayOnTopProc, LPARAM(dstlist));
@ -508,9 +509,11 @@ end;
class procedure TWin32WSCustomForm.SetFormStyle(const AForm: TCustomform;
const AFormStyle, AOldFormStyle: TFormStyle);
const
WindowPosFlags = SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOOWNERZORDER;
var
toplist : TList;
i : Integer;
toplist: TList;
i: Integer;
begin
// Some changes don't require RecreateWnd
@ -518,7 +521,7 @@ begin
if (AOldFormStyle = fsNormal) and (AFormStyle in fsAllStayOnTop) then
begin
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
end
else
@ -546,12 +549,10 @@ begin
toplist := TList.Create;
try
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
begin
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);
end;
SetWindowPos(HWND(toplist[i]), HWND_TOPMOST, 0, 0, 0, 0, WindowPosFlags);
finally
toplist.Free;
end;