52
52
PWinControl: TWinControl; // control to paint for
53
53
AWinControl: TWinControl; // control associated with (for buddy controls)
55
StayOnTopList: TList; // a list of windows that were normalized when showing modal
55
StayOnTopList: TFPList; // a list of windows that were normalized when showing modal
57
MouseX, MouseY: smallint; // noticing spurious WM_MOUSEMOVE messages
58
DispInfoTextA: array [0..LV_DISP_INFO_COUNT-1] of AnsiString; // buffer for ListView LVN_GETDISPINFO notification
59
DispInfoTextW: array [0..LV_DISP_INFO_COUNT-1] of WideString; // it's recommended to keep buffer unchanged
60
DispInfoIndex: Integer; // between 2 calls of LVN_GETDISPINFO
61
DrawItemIndex: integer; // in case of listbox, when handling WM_DRAWITEM
62
DrawItemSelected: boolean;// whether this item is selected LB_GETSEL not uptodate yet
56
63
needParentPaint: boolean; // has a tabpage as parent, and is winxp themed
57
64
isTabPage: boolean; // is window of tabpage
58
65
isComboEdit: boolean; // is buddy of combobox, the edit control
59
66
isChildEdit: boolean; // is buddy edit of a control
60
67
ThemedCustomDraw: boolean;// controls needs themed drawing in wm_notify/nm_customdraw
62
DrawItemIndex: integer; // in case of listbox, when handling WM_DRAWITEM
63
DrawItemSelected: boolean;// whether this item is selected LB_GETSEL not uptodate yet
64
MouseX, MouseY: smallint; // noticing spurious WM_MOUSEMOVE messages
65
DispInfoTextA: array [0..LV_DISP_INFO_COUNT-1] of AnsiString; // buffer for ListView LVN_GETDISPINFO notification
66
DispInfoTextW: array [0..LV_DISP_INFO_COUNT-1] of WideString; // it's recommended to keep buffer unchanged
67
DispInfoIndex: Integer; // between 2 calls of LVN_GETDISPINFO
68
68
IMEComposed: Boolean;
70
70
0: (spinValue: Double);
77
77
function WM_To_String(WM_Message: Integer): string;
78
78
function WindowPosFlagsToString(Flags: UINT): string;
79
procedure EventTrace(Message: String; Data: TObject);
80
procedure AssertEx(const Message: String; const PassErr: Boolean;
81
const Severity: Byte);
82
procedure AssertEx(const PassErr: Boolean; const Message: String);
83
procedure AssertEx(const Message: String);
84
function GetShiftState: TShiftState;
85
procedure CallEvent(const Target: TObject; Event: TNotifyEvent;
86
const Data: Pointer; const EventType: TEventType);
87
79
function ObjectToHWND(const AObject: TObject): HWND;
88
function LCLControlSizeNeedsUpdate(Sender: TWinControl;
89
SendSizeMsgOnDiff: boolean): boolean;
90
function GetLCLClientBoundsOffset(Sender: TObject; var ORect: TRect): boolean;
91
function GetLCLClientBoundsOffset(Handle: HWnd; var Rect: TRect): boolean;
92
procedure LCLBoundsToWin32Bounds(Sender: TObject;
93
var Left, Top, Width, Height: Integer);
80
function LCLControlSizeNeedsUpdate(Sender: TWinControl; SendSizeMsgOnDiff: boolean): boolean;
81
function GetLCLClientBoundsOffset(Sender: TObject; out ORect: TRect): boolean;
82
function GetLCLClientBoundsOffset(Handle: HWnd; out Rect: TRect): boolean;
83
procedure LCLBoundsToWin32Bounds(Sender: TObject; var Left, Top, Width, Height: Integer);
94
84
procedure Win32PosToLCLPos(Sender: TObject; var Left, Top: SmallInt);
95
85
procedure GetWin32ControlPos(Window, Parent: HWND; var Left, Top: integer);
97
87
procedure UpdateWindowStyle(Handle: HWnd; Style: integer; StyleMask: integer);
98
function BorderStyleToWin32Flags(Style: TFormBorderStyle): DWORD;
99
function BorderStyleToWin32FlagsEx(Style: TFormBorderStyle): DWORD;
100
function GetDesigningBorderStyle(const AForm: TCustomForm): TFormBorderStyle;
102
89
function AllocWindowInfo(Window: HWND): PWin32WindowInfo;
103
90
function DisposeWindowInfo(Window: HWND): boolean;
104
91
function GetWin32WindowInfo(Window: HWND): PWin32WindowInfo;
106
procedure RemoveStayOnTopFlags(Window: HWND; ASystemTopAlso: Boolean = False);
107
procedure RestoreStayOnTopFlags(Window: HWND);
93
procedure RemoveStayOnTopFlags(AppHandle: HWND; ASystemTopAlso: Boolean = False);
94
procedure RestoreStayOnTopFlags(AppHandle: HWND);
95
procedure HidePopups(AppHandle: HWND);
96
procedure RestorePopups;
97
function LookupTopWindow(AppHandle: HWND): HWND;
109
99
procedure AddToChangedMenus(Window: HWnd);
110
100
procedure RedrawMenus;
280
283
// edit control messages start (todo: add more if needed)
281
284
$00B0: Result := 'EM_GETSEL';
282
285
$00B1: Result := 'EM_SETSEL';
286
$00B2: Result := 'EM_GETRECT';
287
$00B3: Result := 'EM_SETRECT';
288
$00B4: Result := 'EM_SETRECTNP';
289
$00B5: Result := 'EM_SCROLL';
290
$00B6: Result := 'EM_LINESCROLL';
283
291
$00B7: Result := 'EM_SCROLLCARET';
292
$00B8: Result := 'EM_GETMODIFY';
293
$00B9: Result := 'EM_SETMODIFY';
294
$00BA: Result := 'EM_GETLINECOUNT';
295
$00BB: Result := 'EM_LINEINDEX';
296
$00BC: Result := 'EM_SETHANDLE';
297
$00BD: Result := 'EM_GETHANDLE';
298
$00BE: Result := 'EM_GETTHUMB';
299
$00C1: Result := 'EM_LINELENGTH';
300
$00C2: Result := 'EM_REPLACESEL';
301
$00C4: Result := 'EM_GETLINE';
284
302
$00C5: Result := 'EM_LIMITTEXT';
303
$00C6: Result := 'EM_CANUNDO';
304
$00C7: Result := 'EM_UNDO';
305
$00C8: Result := 'EM_FMTLINES';
306
$00C9: Result := 'EM_LINEFROMCHAR';
307
$00CB: Result := 'EM_SETTABSTOPS';
285
308
$00CC: Result := 'EM_SETPASSWORDCHAR';
309
$00CD: Result := 'EM_EMPTYUNDOBUFFER';
310
$00CE: Result := 'EM_GETFIRSTVISIBLELINE';
286
311
$00CF: Result := 'EM_SETREADONLY';
312
$00D0: Result := 'EM_SETWORDBREAKPROC';
313
$00D1: Result := 'EM_GETWORDBREAKPROC';
314
$00D2: Result := 'EM_GETPASSWORDCHAR';
315
$00D3: Result := 'EM_SETMARGINS';
316
$00D4: Result := 'EM_GETMARGINS';
317
$00D5: Result := 'EM_GETLIMITTEXT';
318
$00D6: Result := 'EM_POSFROMCHAR';
319
$00D7: Result := 'EM_CHARFROMPOS';
287
320
// edit control messages end
288
321
// scrollbar control messages start
289
322
$00E0: Result := 'SBM_SETPOS';
524
557
Result := FlagsStr;
528
{------------------------------------------------------------------------------
529
procedure: EventTrace
530
Params: Message - Event name
531
Data - Object which fired this event
534
Displays a trace about an event
535
------------------------------------------------------------------------------}
536
procedure EventTrace(Message: String; Data: TObject);
539
Assert(False, Format('Trace:Event [%S] fired', [Message]))
541
Assert(False, Format('Trace:Event [%S] fired for %S',[Message, Data.Classname]));
544
{------------------------------------------------------------------------------
546
Params: Message - Message sent
547
PassErr - Pass error to a catching procedure (default: False)
548
Severity - How severe is the error on a scale from 0 to 3
552
An expanded, better version of Assert
553
------------------------------------------------------------------------------}
554
procedure AssertEx(const Message: String; const PassErr: Boolean; const Severity: Byte);
559
Assert(PassErr, Message);
563
Assert(PassErr, Format('Trace:%S', [Message]));
570
WriteLn(rsWin32Warning, Message);
574
MessageBox(0, PChar(Message), PChar(rsWin32Warning), MB_OK);
583
WriteLn(rsWin32Error, Message);
587
MessageBox(0, PChar(Message), nil, MB_OK);
594
procedure AssertEx(const PassErr: Boolean; const Message: String);
596
AssertEx(Message, PassErr, 0);
599
procedure AssertEx(const Message: String);
601
AssertEx(Message, False, 0);
604
{------------------------------------------------------------------------------
605
function: GetShiftState
607
Returns: A shift state
609
Creates a TShiftState set based on the status when the function was called.
610
------------------------------------------------------------------------------}
611
function GetShiftState: TShiftState;
614
// NOTE: it may be better to use GetAsyncKeyState
615
// if GetKeyState AND $8000 <> 0 then down (e.g. shift)
616
// if GetKeyState AND 1 <> 0, then toggled on (e.g. num lock)
617
if (GetKeyState(VK_SHIFT) and $8000) <> 0 then
618
Result := Result + [ssShift];
619
if (GetKeyState(VK_CAPITAL) and 1) <> 0 then
620
Result := Result + [ssCaps];
621
if (GetKeyState(VK_CONTROL) and $8000) <> 0 then
622
Result := Result + [ssCtrl];
623
if (GetKeyState(VK_MENU) and $8000) <> 0 then
624
Result := Result + [ssAlt];
625
if (GetKeyState(VK_NUMLOCK) and 1) <> 0 then
626
Result := Result + [ssNum];
628
if (GetKeyState(VK_SCROLL) and 1) <> 0 then
629
Result := Result + [ssScroll];
630
// GetKeyState takes mouse button swap into account (GetAsyncKeyState doesn't),
631
// so no need to test GetSystemMetrics(SM_SWAPBUTTON)
632
if (GetKeyState(VK_LBUTTON) and $8000) <> 0 then
633
Result := Result + [ssLeft];
634
if (GetKeyState(VK_MBUTTON) and $8000) <> 0 then
635
Result := Result + [ssMiddle];
636
if (GetKeyState(VK_RBUTTON) and $8000) <> 0 then
637
Result := Result + [ssRight];
641
560
{------------------------------------------------------------------------------
642
561
procedure: GetWin32KeyInfo
643
562
Params: Event - Requested info
695
590
Returns the Window handle of the given object, 0 if no object available
696
591
------------------------------------------------------------------------------}
697
592
function ObjectToHWND(const AObject: TObject): HWND;
702
595
if not assigned(AObject) then
703
596
Assert (False, 'TRACE:[ObjectToHWND] Object not assigned')
705
598
if (AObject is TWinControl) then
707
600
if TWinControl(AObject).HandleAllocated then
708
Handle := TWinControl(AObject).Handle
601
Result := TWinControl(AObject).Handle
711
604
if (AObject is TMenuItem) then
713
606
if TMenuItem(AObject).HandleAllocated then
714
Handle := TMenuItem(AObject).Handle
607
Result := TMenuItem(AObject).Handle
717
610
if (AObject is TMenu) then
719
612
if TMenu(AObject).HandleAllocated then
720
Handle := TMenu(AObject).Items.Handle
613
Result := TMenu(AObject).Items.Handle
723
616
if (AObject is TCommonDialog) then
725
618
{if TCommonDialog(AObject).HandleAllocated then }
726
Handle := TCommonDialog(AObject).Handle
729
Assert(False, Format('Trace:[ObjectToHWND] Message received With unhandled class-type <%s>', [AObject.ClassName]));
733
Assert(False, 'Trace:[ObjectToHWND]****** Warning: handle = 0 *******');
619
Result := TCommonDialog(AObject).Handle
736
623
(***********************************************************************
784
670
It is used in GetClientBounds to define LCL bounds from win32 bounds.
785
671
-------------------------------------------------------------------------------}
786
function GetLCLClientBoundsOffset(Sender: TObject; var ORect: TRect): boolean;
672
function GetLCLClientBoundsOffset(Sender: TObject; out ORect: TRect): boolean;
674
TM: Windows.TextMetric;
791
TheWinControl: TWinControl;
677
TheWinControl: TWinControl absolute Sender;
795
if (Sender = nil) or (not (Sender is TWinControl)) then exit;
796
TheWinControl := TWinControl(Sender);
681
if not (Sender is TWinControl) then exit;
797
682
if not TheWinControl.HandleAllocated then exit;
798
683
Handle := TheWinControl.Handle;
799
684
FillChar(ORect, SizeOf(ORect), 0);
800
685
if TheWinControl is TScrollingWinControl then
687
{$ifdef RedirectDestroyMessages}
688
with TScrollingWinControl(TheWinControl) do
690
OffsetRect(ORect, -HorzScrollBar.Position, -VertScrollBar.Position);
801
693
with TScrollingWinControl(TheWinControl) do
803
695
if HorzScrollBar <> nil then
904
798
SetWindowLong(Handle, GWL_STYLE, NewStyle);
907
function BorderStyleToWin32Flags(Style: TFormBorderStyle): DWORD;
909
Result := WS_CLIPCHILDREN or WS_CLIPSIBLINGS;
911
bsSizeable, bsSizeToolWin:
912
Result := Result or (WS_OVERLAPPED or WS_THICKFRAME or WS_CAPTION);
913
bsSingle, bsToolWindow:
914
Result := Result or (WS_OVERLAPPED or WS_BORDER or WS_CAPTION);
916
Result := Result or (WS_POPUP or WS_BORDER or WS_CAPTION);
918
Result := Result or WS_POPUP;
922
function BorderStyleToWin32FlagsEx(Style: TFormBorderStyle): DWORD;
927
Result := WS_EX_DLGMODALFRAME or WS_EX_WINDOWEDGE;
928
bsToolWindow, bsSizeToolWin:
929
Result := WS_EX_TOOLWINDOW;
933
function GetDesigningBorderStyle(const AForm: TCustomForm): TFormBorderStyle;
934
{$NOTE Belongs in Win32WSForms, but is needed in windowproc}
936
if csDesigning in AForm.ComponentState then
939
Result := AForm.BorderStyle;
942
801
function AllocWindowInfo(Window: HWND): PWin32WindowInfo;
944
803
WindowInfo: PWin32WindowInfo;
973
832
function EnumStayOnTopRemove(Handle: HWND; Param: LPARAM): WINBOOL; stdcall;
976
834
StayOnTopWindowsInfo: PStayOnTopWindowsInfo absolute Param;
977
835
lWindowInfo: PWin32WindowInfo;
978
836
lWinControl: TWinControl;
981
AStyle := GetWindowLong(Handle, GWL_EXSTYLE);
982
if (AStyle and WS_EX_TOPMOST) <> 0 then // if stay on top then
839
if ((GetWindowLong(Handle, GWL_EXSTYLE) and WS_EX_TOPMOST) <> 0) then
984
841
// Don't remove system-wide stay on top, unless desired
985
842
if not StayOnTopWindowsInfo^.SystemTopAlso then
987
844
lWindowInfo := GetWin32WindowInfo(Handle);
988
if (lWindowInfo <> nil) then
845
if Assigned(lWindowInfo) then
990
847
lWinControl := lWindowInfo^.WinControl;
991
if (lWinControl <> nil) and (lWinControl is TCustomForm)
992
and (TCustomForm(lWinControl).FormStyle = fsSystemStayOnTop) then
848
if (lWinControl is TCustomForm) and
849
(TCustomForm(lWinControl).FormStyle = fsSystemStayOnTop) then
997
854
StayOnTopWindowsInfo^.StayOnTopList.Add(Pointer(Handle));
998
SetWindowPos(Handle, HWND_NOTOPMOST, 0, 0, 0, 0,
999
SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOOWNERZORDER or SWP_NOSENDCHANGING);
1003
procedure RemoveStayOnTopFlags(Window: HWND; ASystemTopAlso: Boolean = False);
858
procedure RemoveStayOnTopFlags(AppHandle: HWND; ASystemTopAlso: Boolean = False);
1005
860
StayOnTopWindowsInfo: PStayOnTopWindowsInfo;
1006
861
WindowInfo: PWin32WindowInfo;
1008
// WriteLn('RemoveStayOnTopFlags 1');
864
//WriteLn('RemoveStayOnTopFlags ', InRemoveStayOnTopFlags);
1009
865
if InRemoveStayOnTopFlags = 0 then
1011
867
New(StayOnTopWindowsInfo);
1012
StayOnTopWindowsInfo^.AppWindow := Window;
868
StayOnTopWindowsInfo^.AppHandle := AppHandle;
1013
869
StayOnTopWindowsInfo^.SystemTopAlso := ASystemTopAlso;
1014
StayOnTopWindowsInfo^.StayOnTopList := TList.Create;
1015
WindowInfo := GetWin32WindowInfo(Window);
870
StayOnTopWindowsInfo^.StayOnTopList := TFPList.Create;
871
WindowInfo := GetWin32WindowInfo(AppHandle);
1016
872
WindowInfo^.StayOnTopList := StayOnTopWindowsInfo^.StayOnTopList;
1017
EnumThreadWindows(GetWindowThreadProcessId(Window, nil),
873
EnumThreadWindows(GetWindowThreadProcessId(AppHandle, nil),
1018
874
@EnumStayOnTopRemove, LPARAM(StayOnTopWindowsInfo));
875
for I := 0 to WindowInfo^.StayOnTopList.Count - 1 do
876
SetWindowPos(HWND(WindowInfo^.StayOnTopList[I]), HWND_NOTOPMOST, 0, 0, 0, 0,
877
SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOOWNERZORDER or SWP_DRAWFRAME);
1019
878
Dispose(StayOnTopWindowsInfo);
1021
880
inc(InRemoveStayOnTopFlags);
1022
// WriteLn('RemoveStayOnTopFlags 2');
1025
procedure RestoreStayOnTopFlags(Window: HWND);
883
procedure RestoreStayOnTopFlags(AppHandle: HWND);
1027
885
WindowInfo: PWin32WindowInfo;
1030
// WriteLn('RestoreStayOnTopFlags 1');
888
//WriteLn('RestoreStayOnTopFlags ', InRemoveStayOnTopFlags);
1031
889
if InRemoveStayOnTopFlags = 1 then
1033
WindowInfo := GetWin32WindowInfo(Window);
891
WindowInfo := GetWin32WindowInfo(AppHandle);
1034
892
if WindowInfo^.StayOnTopList <> nil then
1036
894
for I := 0 to WindowInfo^.StayOnTopList.Count - 1 do
1037
895
SetWindowPos(HWND(WindowInfo^.StayOnTopList.Items[I]),
1038
896
HWND_TOPMOST, 0, 0, 0, 0,
1039
SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOOWNERZORDER or SWP_NOSENDCHANGING);
897
SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOOWNERZORDER or SWP_DRAWFRAME);
1040
898
FreeAndNil(WindowInfo^.StayOnTopList);
1043
901
if InRemoveStayOnTopFlags > 0 then
1044
902
dec(InRemoveStayOnTopFlags);
1045
// WriteLn('RestoreStayOnTopFlags 2');
905
function EnumHidePopups(Handle: HWND; Param: LPARAM): WINBOOL; stdcall;
909
Owner := GetWindow(Handle, GW_OWNER);
910
if (Owner <> 0) and (Owner <> PPopupOwnersWindowInfo(Param)^.AppHandle) then
911
PPopupOwnersWindowInfo(Param)^.OwnersList.Add(Pointer(Owner));
915
procedure HidePopups(AppHandle: HWND);
918
Info: PPopupOwnersWindowInfo;
920
if not Assigned(PopupOwnersList) then
922
PopupOwnersList := TFPList.Create;
925
Info^.AppHandle := AppHandle;
926
Info^.OwnersList := PopupOwnersList;
927
EnumThreadWindows(GetWindowThreadProcessId(Application.MainFormHandle, nil),
928
@EnumHidePopups, LPARAM(Info));
929
for i := 0 to PopupOwnersList.Count - 1 do
930
ShowOwnedPopups(HWND(PopupOwnersList[i]), False);
937
procedure RestorePopups;
941
if Assigned(PopupOwnersList) then
943
for i := 0 to PopupOwnersList.Count - 1 do
944
ShowOwnedPopups(HWND(PopupOwnersList[i]), True);
945
FreeAndNil(PopupOwnersList);
949
function EnumLookupTopWindow(Handle: HWND; Param: LPARAM): WINBOOL; stdcall;
952
if IsWindowVisible(Handle) and IsWindowEnabled(Handle) then
954
with PLookupTopWindowInfo(Param)^ do
956
if (Handle = AppHandle) or (Handle = TopWindow) then
958
if GetWindowLong(Handle, GWL_EXSTYLE) and WS_EX_TOPMOST <> 0 then
960
// we've found the top most window => stop
965
if TopWindow = 0 then
971
function LookupTopWindow(AppHandle: HWND): HWND;
973
Info: PLookupTopWindowInfo;
976
Info^.AppHandle := AppHandle;
977
Info^.TopWindow := 0;
978
EnumThreadWindows(GetWindowThreadProcessId(AppHandle, nil),
979
@EnumLookupTopWindow, LPARAM(Info));
980
Result := Info^.TopWindow;
1049
986
{-------------------------------------------------------------------------------
1050
987
procedure AddToChangedMenus(Window: HWnd);