lcl: introduce TScreen.DisableForms, TScreen.EnableForms,

lcl: Disabling/Enabling forms before/after showing of modal form
win32: remove win32 specific methods of disabling/enabling windows. Use new TScreen methods instead
win32: disable/enable forms before/after showing some system dialog (fixes bug #0012366, bug #0012382)

git-svn-id: trunk@18629 -
This commit is contained in:
paul 2009-02-10 14:38:01 +00:00
parent 26293e4375
commit 1d777bebeb
8 changed files with 71 additions and 95 deletions

View File

@ -851,6 +851,9 @@ type
procedure RemoveHandlerActiveFormChanged(
OnActiveFormChanged: TScreenActiveFormChangedEvent);
procedure RemoveAllHandlersOfObject(AnObject: TObject); override;
function DisableForms(SkipForm: TCustomForm; DisabledList: TList = nil): TList;
procedure EnableForms(var AFormList: TList);
public
property ActiveControl: TWinControl read FActiveControl;
property ActiveCustomForm: TCustomForm read FActiveCustomForm;

View File

@ -90,7 +90,8 @@ begin
end;
function TCommonDialog.DoExecute : boolean;
var CanClose: boolean;
var
CanClose: boolean;
begin
FCanCloseCalled := False;
if Assigned(FOnShow) then
@ -119,5 +120,5 @@ end;
function TCommonDialog.DefaultTitle: string;
begin
result := '';
Result := '';
end;

View File

@ -2050,7 +2050,7 @@ function TCustomForm.ShowModal: Integer;
end;
var
//WindowList: Pointer;
DisabledList: TList;
SavedFocusState: TFocusState;
//SaveCursor: TCursor;
//SaveCount: Integer;
@ -2079,6 +2079,7 @@ begin
Screen.FFocusedForm := Self;
Screen.MoveFormToFocusFront(Self);
Screen.MoveFormToZFront(Self);
DisabledList := Screen.DisableForms(Self);
ModalResult := 0;
try
@ -2120,6 +2121,7 @@ begin
DestroyHandle;
end;
finally
Screen.EnableForms(DisabledList);
if Screen.FSaveFocusedList.Count > 0 then
begin
Screen.FFocusedForm := TCustomForm(Screen.FSaveFocusedList.First);

View File

@ -72,8 +72,9 @@ end;
------------------------------------------------------------------------------}
function TScreen.CustomFormIndex(AForm: TCustomForm): integer;
begin
Result:=FCustomForms.Count-1;
while (Result>=0) and (CustomForms[Result]<>AForm) do dec(Result);
Result := FCustomForms.Count - 1;
while (Result >= 0) and (CustomForms[Result] <> AForm) do
Dec(Result);
end;
{------------------------------------------------------------------------------
@ -81,8 +82,9 @@ end;
------------------------------------------------------------------------------}
function TScreen.FormIndex(AForm: TForm): integer;
begin
Result:=FFormList.Count-1;
while (Result>=0) and (Forms[Result]<>AForm) do dec(Result);
Result := FFormList.Count - 1;
while (Result >= 0) and (Forms[Result] <> AForm) do
Dec(Result);
end;
{------------------------------------------------------------------------------
@ -248,6 +250,56 @@ begin
inherited RemoveAllHandlersOfObject(AnObject);
end;
{
Disable all forms except SkipForm. If DisabledList is available then add forms
to that list and return it, otherwise return new list. Used to show forms and
other dialogs modal
}
function TScreen.DisableForms(SkipForm: TCustomForm; DisabledList: TList = nil): TList;
var
i: integer;
AForm: TCustomForm;
begin
Result := DisabledList;
if Result = nil then
Result := TList.Create;
for i := 0 to CustomFormCount - 1 do
begin
AForm := CustomForms[i];
if (AForm <> SkipForm) and AForm.HandleAllocated then
begin
// we cannot use AForm.Enabled := False; since it checks csDesigning
// but we need this for IDE too. We also cannot check AForm.Visible -
// it returns wrong info for the forms opened in the designer
if IsWindowEnabled(AForm.Handle) and IsWindowVisible(AForm.Handle) then
begin
EnableWindow(AForm.Handle, False);
Result.Add(AForm);
end;
end;
end;
end;
{
Enable all forms from AFormList and destroy list. Used to restore state after
DisableForms
}
procedure TScreen.EnableForms(var AFormList: TList);
var
i: integer;
AForm: TCustomForm;
begin
if AFormList = nil then
Exit;
for i := AFormList.Count - 1 downto 0 do
begin
AForm := TCustomForm(AFormList[i]);
if (CustomFormIndex(AForm) <> -1) and AForm.HandleAllocated then
EnableWindow(AForm.Handle, True);
end;
FreeAndNil(AFormList);
end;
function EnumFontsNoDups(
var LogFont: TEnumLogFontEx;
var Metric: TNewTextMetricEx;

View File

@ -184,6 +184,7 @@ type
var
CurDoubleBuffer: TDoubleBuffer = (DC: 0; Bitmap: 0; BitmapWidth: 0; BitmapHeight: 0);
DisabledForms: TList = nil;
function CheckMouseMovement: boolean;
// returns true if mouse did not move between lmousebutton down
@ -1569,12 +1570,12 @@ begin
if WParam = 0 then
begin
RemoveStayOnTopFlags(Window);
DisableApplicationWindows(Window);
DisabledForms := Screen.DisableForms(nil, DisabledForms);
end
else
begin
RestoreStayOnTopFlags(Window);
EnableApplicationWindows(Window);
Screen.EnableForms(DisabledForms);
end;
// disable child windows of for example groupboxes, but not of forms

View File

@ -46,7 +46,6 @@ Type
PWinControl: TWinControl; // control to paint for
AWinControl: TWinControl; // control associated with (for buddy controls)
List: TStrings;
DisabledWindowList: TList;// a list of windows that were disabled when showing modal
StayOnTopList: TList; // a list of windows that were normalized when showing modal
needParentPaint: boolean; // has a tabpage as parent, and is winxp themed
isTabPage: boolean; // is window of tabpage
@ -102,10 +101,7 @@ function GetDesigningBorderStyle(const AForm: TCustomForm): TFormBorderStyle;
function AllocWindowInfo(Window: HWND): PWindowInfo;
function DisposeWindowInfo(Window: HWND): boolean;
function GetWindowInfo(Window: HWND): PWindowInfo;
function DisableWindowsProc(Window: HWND; Data: LParam): LongBool; stdcall;
procedure DisableApplicationWindows(Window: HWND);
procedure EnableApplicationWindows(Window: HWND);
procedure RemoveStayOnTopFlags(Window: HWND);
procedure RestoreStayOnTopFlags(Window: HWND);
@ -1082,7 +1078,6 @@ begin
Result := Windows.RemoveProp(Window, PChar(PtrUInt(WindowInfoAtom)))<>0;
if Result then
begin
WindowInfo^.DisabledWindowList.Free;
WindowInfo^.StayOnTopList.Free;
Dispose(WindowInfo);
end;
@ -1095,80 +1090,6 @@ begin
Result := @DefaultWindowInfo;
end;
{-----------------------------------------------------------------------------
function: DisableWindowsProc
Params: Window - handle of toplevel windows to be disabled
Data - handle of current window form
Returns: Whether the enumeration should continue
Used in LM_SHOWMODAL to disable the windows of application thread
except the current form.
-----------------------------------------------------------------------------}
function DisableWindowsProc(Window: HWND; Data: LParam): LongBool; stdcall;
var
Buffer: array[0..15] of Char;
begin
Result:=true;
// Don't disable the current window form
if Window = PDisableWindowsInfo(Data)^.NewModalWindow then exit;
// Don't disable any ComboBox listboxes
if (GetClassName(Window, @Buffer[0], sizeof(Buffer))<sizeof(Buffer))
and (StrIComp(Buffer, 'ComboLBox')=0) then exit;
if not IsWindowVisible(Window) or not IsWindowEnabled(Window) then exit;
PDisableWindowsInfo(Data)^.DisabledWindowList.Add(Pointer(Window));
EnableWindow(Window,False);
if (Application <> nil) and (Application.MainForm <> nil) and
Application.MainForm.HandleAllocated and (Window = Application.MainForm.Handle)
then
// In our windowproc we ignore WM_NCACTIVATE for the main form,
// if it is not disabled.
// Now we disable the mainform, so send WM_NCACTIVATE message;
// when we showed the modal form, the mainform was not yet disabled
Windows.SendMessage(Window, WM_NCACTIVATE, 0, 0)
end;
var
InDisableApplicationWindows: boolean = false;
procedure DisableApplicationWindows(Window: HWND);
var
DisableWindowsInfo: PDisableWindowsInfo;
WindowInfo: PWindowInfo;
begin
// prevent recursive calling when the AppHandle window is disabled
If InDisableApplicationWindows then
exit;
InDisableApplicationWindows:=true;
New(DisableWindowsInfo);
DisableWindowsInfo^.NewModalWindow := Window;
DisableWindowsInfo^.DisabledWindowList := TList.Create;
WindowInfo := GetWindowInfo(DisableWindowsInfo^.NewModalWindow);
WindowInfo^.DisabledWindowList := DisableWindowsInfo^.DisabledWindowList;
EnumThreadWindows(GetWindowThreadProcessId(DisableWindowsInfo^.NewModalWindow, nil),
@DisableWindowsProc, LPARAM(DisableWindowsInfo));
Dispose(DisableWindowsInfo);
InDisableApplicationWindows := false;
end;
procedure EnableApplicationWindows(Window: HWND);
var
WindowInfo: PWindowInfo;
I: integer;
begin
WindowInfo := GetWindowInfo(Window);
if WindowInfo^.DisabledWindowList <> nil then
begin
for I := 0 to WindowInfo^.DisabledWindowList.Count - 1 do
EnableWindow(HWND(WindowInfo^.DisabledWindowList.Items[I]), true);
FreeAndNil(WindowInfo^.DisabledWindowList);
end;
end;
function EnumStayOnTopRemove(Handle: HWND; Param: LPARAM): WINBOOL; stdcall;
var
AStyle: DWord;

View File

@ -58,6 +58,7 @@ uses
type
TApplicationState = record
FocusedWindow: HWND;
DisabledWindows: TList;
end;
TOpenFileDialogRec = record
@ -139,10 +140,12 @@ implementation
function SaveApplicationState: TApplicationState;
begin
Result.FocusedWindow := Windows.GetFocus;
Result.DisabledWindows := Screen.DisableForms(nil);
end;
procedure RestoreApplicationState(AState: TApplicationState);
begin
Screen.EnableForms(AState.DisabledWindows);
Windows.SetFocus(AState.FocusedWindow);
end;

View File

@ -72,7 +72,6 @@ type
TWin32WSCustomForm = class(TWSCustomForm)
published
class procedure CloseModal(const ACustomForm: TCustomForm); override;
class procedure SetAllowDropFiles(const AForm: TCustomForm; AValue: Boolean); override;
class procedure SetBorderIcons(const AForm: TCustomForm;
const ABorderIcons: TBorderIcons); override;
@ -321,11 +320,6 @@ begin
Result := Params.Window;
end;
class procedure TWin32WSCustomForm.CloseModal(const ACustomForm: TCustomForm);
begin
EnableApplicationWindows(ACustomForm.Handle);
end;
class procedure TWin32WSCustomForm.SetAllowDropFiles(const AForm: TCustomForm;
AValue: Boolean);
begin
@ -425,7 +419,6 @@ end;
class procedure TWin32WSCustomForm.ShowModal(const ACustomForm: TCustomForm);
begin
DisableApplicationWindows(ACustomForm.Handle);
ShowWindow(ACustomForm.Handle, SW_SHOW);
BringWindowToTop(ACustomForm.Handle);
end;