mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-16 12:02:38 +02:00
Qt: added caching of TQtWidgetSet.WindowFromPoint() to avoid unnecesarry calls of very slow QApplication_widgetAt() function. Now TQtWidgetSet.WindowFromPoint() returns same as Win32 WindowFromPoint(), especially in case if mouse isn't moved but widget under it has been disabled or hidden, or new widget is shown above it.
git-svn-id: trunk@27309 -
This commit is contained in:
parent
1fc4c3a359
commit
00d38fd701
@ -57,6 +57,11 @@ type
|
||||
TQtWidgetSet = Class(TWidgetSet)
|
||||
private
|
||||
App: QApplicationH;
|
||||
|
||||
// cache for WindowFromPoint
|
||||
FLastWFPMousePos: TPoint;
|
||||
FLastWFPResult: HWND;
|
||||
|
||||
FEatNextDeactivate: Boolean;
|
||||
FOverrideCursor: TObject;
|
||||
SavedDCList: TFPList;
|
||||
@ -135,6 +140,11 @@ type
|
||||
procedure RemoveHandle(AHandle: TObject);
|
||||
function IsValidHandle(AHandle: HWND): Boolean;
|
||||
|
||||
// cache for WindowFromPoint to reduce very expensive calls
|
||||
// of QApplication_widgetAt() inside WindowFromPoint().
|
||||
function IsWidgetAtCache(AHandle: HWND): Boolean;
|
||||
procedure InvalidateWidgetAtCache;
|
||||
|
||||
// drag image list
|
||||
function DragImageList_BeginDrag(AImage: QImageH; AHotSpot: TPoint): Boolean;
|
||||
procedure DragImageList_EndDrag;
|
||||
|
@ -52,6 +52,9 @@ end;
|
||||
------------------------------------------------------------------------------}
|
||||
constructor TQtWidgetSet.Create;
|
||||
begin
|
||||
FLastWFPMousePos := Point(MaxInt, MaxInt);
|
||||
FLastWFPResult := 0;
|
||||
|
||||
inherited Create;
|
||||
|
||||
App := QApplication_Create(@argc, argv);
|
||||
@ -455,6 +458,9 @@ function TQtWidgetSet.EventFilter(Sender: QObjectH; Event: QEventH): Boolean; cd
|
||||
var
|
||||
AObject: TQtObject;
|
||||
W: TQtMainWindow;
|
||||
R: TRect;
|
||||
P: TPoint;
|
||||
Pt: TQtPoint;
|
||||
begin
|
||||
Result := False;
|
||||
case QEvent_type(Event) of
|
||||
@ -491,6 +497,21 @@ begin
|
||||
FreeSysColorBrushes(True);
|
||||
end;
|
||||
end;
|
||||
QEventShow,
|
||||
QEventHide:
|
||||
begin
|
||||
// invalidate widgetAt cache if needed
|
||||
if QObject_isWidgetType(Sender) and IsValidHandle(FLastWFPResult) then
|
||||
begin
|
||||
QWidget_geometry(QWidgetH(Sender), @R);
|
||||
Pt.x := 0;
|
||||
Pt.y := 0;
|
||||
QWidget_mapToGlobal(QWidgetH(Sender), @Pt, @Pt);
|
||||
R := Rect(Pt.X, Pt.Y, Pt.X + (R.Right - R.Left), Pt.Y + (R.Bottom - R.Top));
|
||||
if PtInRect(R, FLastWFPMousePos) then
|
||||
InvalidateWidgetAtCache;
|
||||
end;
|
||||
end;
|
||||
LCLQt_Destroy:
|
||||
begin
|
||||
AObject := TQtObject(Pointer(QLCLMessageEvent_getWParam(QLCLMessageEventH(Event))));
|
||||
@ -701,6 +722,24 @@ begin
|
||||
System.LeaveCriticalsection(CriticalSection);
|
||||
end;
|
||||
|
||||
{Params: HWND
|
||||
This function is needed by cache used in TQtWidgetSet.WindowFromPoint().
|
||||
Returns: True if we are cached (FLastWFPResult).
|
||||
}
|
||||
function TQtWidgetSet.IsWidgetAtCache(AHandle: HWND): Boolean;
|
||||
begin
|
||||
Result := AHandle = FLastWFPResult;
|
||||
end;
|
||||
|
||||
{Params: none
|
||||
Invalidates TQtWidgetSet.WindowFromPoint() cache (FLastWFPResult).
|
||||
Returns: nothing
|
||||
}
|
||||
procedure TQtWidgetSet.InvalidateWidgetAtCache;
|
||||
begin
|
||||
FLastWFPResult := 0;
|
||||
end;
|
||||
|
||||
function TQtWidgetSet.DragImageList_BeginDrag(AImage: QImageH;
|
||||
AHotSpot: TPoint): Boolean;
|
||||
var
|
||||
|
@ -209,6 +209,7 @@ type
|
||||
function getLayoutDirection: QtLayoutDirection;
|
||||
function getVisible: Boolean; virtual;
|
||||
function getVisibleTo(AWidget: QWidgetH): Boolean; virtual;
|
||||
function getOwner: TQtWidget;
|
||||
function getParent: QWidgetH;
|
||||
function getPos: TQtPoint;
|
||||
function getFrameSize: TSize;
|
||||
@ -2046,6 +2047,11 @@ begin
|
||||
if LCLObject <> nil then
|
||||
begin
|
||||
case QEvent_type(Event) of
|
||||
QEventEnabledChange:
|
||||
begin
|
||||
if QtWidgetSet.IsWidgetAtCache(HWND(Self)) then
|
||||
QtWidgetSet.InvalidateWidgetAtCache;
|
||||
end;
|
||||
QEventShow: SlotShow(True);
|
||||
QEventHide: SlotShow(False);
|
||||
QEventClose:
|
||||
@ -2950,6 +2956,8 @@ begin
|
||||
WriteLn('TQtWidget.SlotMove');
|
||||
{$endif}
|
||||
|
||||
if QtWidgetSet.IsWidgetAtCache(HWND(Self)) then
|
||||
QtWidgetSet.InvalidateWidgetAtCache;
|
||||
// do not loop with LCL
|
||||
if InUpdate then
|
||||
exit;
|
||||
@ -3094,7 +3102,10 @@ begin
|
||||
{$ifdef VerboseQt}
|
||||
WriteLn('TQtWidget.SlotResize');
|
||||
{$endif}
|
||||
|
||||
|
||||
if QtWidgetSet.IsWidgetAtCache(HWND(Self)) then
|
||||
QtWidgetSet.InvalidateWidgetAtCache;
|
||||
|
||||
// return size w/o frame
|
||||
NewSize := QResizeEvent_size(QResizeEventH(Event))^;
|
||||
{
|
||||
@ -3379,6 +3390,8 @@ end;
|
||||
|
||||
function TQtWidget.getEnabled: Boolean;
|
||||
begin
|
||||
if Widget = nil then
|
||||
exit(False);
|
||||
Result := QWidget_isEnabled(Widget);
|
||||
end;
|
||||
|
||||
@ -3409,14 +3422,23 @@ end;
|
||||
|
||||
function TQtWidget.getVisible: boolean;
|
||||
begin
|
||||
if Widget = nil then
|
||||
exit(False);
|
||||
Result := QWidget_isVisible(Widget);
|
||||
end;
|
||||
|
||||
function TQtWidget.getVisibleTo(AWidget: QWidgetH): Boolean;
|
||||
begin
|
||||
if Widget = nil then
|
||||
exit(False);
|
||||
Result := QWidget_isVisibleTo(Widget, AWidget);
|
||||
end;
|
||||
|
||||
function TQtWidget.getOwner: TQtWidget;
|
||||
begin
|
||||
Result := FOwner;
|
||||
end;
|
||||
|
||||
function TQtWidget.getParent: QWidgetH;
|
||||
begin
|
||||
Result := QWidget_parentWidget(Widget);
|
||||
@ -10539,6 +10561,8 @@ end;
|
||||
|
||||
function TQtMenu.getVisible: Boolean;
|
||||
begin
|
||||
if ActionHandle = nil then
|
||||
exit(False);
|
||||
Result := QAction_isVisible(ActionHandle);
|
||||
end;
|
||||
|
||||
|
@ -5677,21 +5677,53 @@ end;
|
||||
If the point is over a static text control,
|
||||
the return value is a handle to the window under the static text control.
|
||||
------------------------------------------------------------------------------}
|
||||
function TQtWidgetSet.WindowFromPoint(Point: TPoint): HWND;
|
||||
function TQtWidgetSet.WindowFromPoint(APoint: TPoint): HWND;
|
||||
var
|
||||
Widget: QWidgetH;
|
||||
AForm: TCustomForm;
|
||||
begin
|
||||
{$note QApplication_widgetAt() is very expensive operation,
|
||||
we must do some kind of caching here like gtk2 does.}
|
||||
// we use cachedresults instead of calling very expensive widgetAt
|
||||
if (FLastWFPResult <> 0) then
|
||||
begin
|
||||
if not IsValidHandle(FLastWFPResult) then
|
||||
FLastWFPResult := 0
|
||||
else
|
||||
if (APoint.X = FLastWFPMousePos.X) and (APoint.Y = FLastWFPMousePos.Y) and
|
||||
TQtWidget(FLastWFPResult).getVisible and
|
||||
TQtWidget(FLastWFPResult).getEnabled then
|
||||
begin
|
||||
// return from cache
|
||||
exit(FLastWFPResult);
|
||||
end;
|
||||
end;
|
||||
|
||||
Result := 0;
|
||||
Widget := QApplication_widgetAt(Point.x, Point.y);
|
||||
Widget := QApplication_widgetAt(APoint.x, APoint.y);
|
||||
|
||||
if (Widget = nil) then
|
||||
begin
|
||||
if (APoint.X = FLastWFPMousePos.X) and (APoint.Y = FLastWFPMousePos.Y) then
|
||||
begin
|
||||
FLastWFPMousePos := Point(MaxInt, MaxInt);
|
||||
FLastWFPResult := 0;
|
||||
end;
|
||||
exit;
|
||||
end;
|
||||
|
||||
// according to MSDN disabled widget shouldn't be in result
|
||||
// but win32 returns first enabled and visible parent !
|
||||
if not QWidget_isEnabled(Widget) or not QWidget_isVisible(Widget) then
|
||||
exit;
|
||||
begin
|
||||
while Widget <> nil do
|
||||
begin
|
||||
Widget := QWidget_parentWidget(Widget);
|
||||
if (Widget <> nil) and QWidget_IsVisible(Widget) and
|
||||
QWidget_isEnabled(Widget) then
|
||||
break;
|
||||
end;
|
||||
if Widget = nil then
|
||||
exit;
|
||||
end;
|
||||
|
||||
Result := HWND(QtObjectFromWidgetH(Widget));
|
||||
|
||||
@ -5700,44 +5732,34 @@ begin
|
||||
begin
|
||||
if QWidget_parentWidget(Widget) <> nil then
|
||||
begin
|
||||
Widget := QWidget_parentWidget(Widget);
|
||||
Result := HWND(QtObjectFromWidgetH(Widget));
|
||||
while (Widget <> nil) do
|
||||
begin
|
||||
Widget := QWidget_parentWidget(Widget);
|
||||
if Widget <> nil then
|
||||
Result := HWND(QtObjectFromWidgetH(Widget));
|
||||
if Result <> 0 then
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
if (Result <> 0) and
|
||||
not (TQtWidget(Result) is TQtMainWindow) then
|
||||
begin
|
||||
// just in case we are an orphan
|
||||
if TQtWidget(Result).LCLObject = nil then
|
||||
begin
|
||||
while Widget <> nil do
|
||||
begin
|
||||
Widget := QWidget_parentWidget(Widget);
|
||||
if Widget <> nil then
|
||||
begin
|
||||
Result := HWND(QtObjectFromWidgetH(Widget));
|
||||
if (Result <> 0) and (TQtWidget(Result).LCLObject <> nil) then
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
//if we are TQtViewPort -> return correct handle -> TQtCustomControl !
|
||||
if (Result <> 0) and (TQtWidget(Result) is TQtViewPort) then
|
||||
begin
|
||||
Widget := QWidget_parentWidget(TQtWidget(Result).Widget);
|
||||
Result := HWND(QtObjectFromWidgetH(Widget));
|
||||
end;
|
||||
|
||||
if TQtWidget(Result).getOwner <> nil then
|
||||
Result := HWND(TQtWidget(Result).getOwner);
|
||||
end else
|
||||
begin
|
||||
Widget := QApplication_topLevelAt(Point.x, Point.y);
|
||||
Widget := QApplication_topLevelAt(APoint.x, APoint.y);
|
||||
if (Widget <> nil) and QWidget_isEnabled(Widget) then
|
||||
Result := HWND(QtObjectFromWidgetH(Widget))
|
||||
else
|
||||
Result := 0;
|
||||
end;
|
||||
|
||||
// add to cache
|
||||
FLastWFPResult := Result;
|
||||
FLastWFPMousePos := APoint;
|
||||
end;
|
||||
|
||||
//##apiwiz##eps## // Do not remove, no wizard declaration after this line
|
||||
|
@ -215,7 +215,7 @@ function SystemParametersInfo(uiAction: DWord; uiParam: DWord; pvParam: Pointer;
|
||||
|
||||
function TextOut(DC: HDC; X,Y : Integer; Str : Pchar; Count: Integer) : Boolean; override;
|
||||
function UpdateWindow(Handle: HWND): Boolean; override;
|
||||
function WindowFromPoint(Point: TPoint): HWND; override;
|
||||
function WindowFromPoint(APoint: TPoint): HWND; override;
|
||||
|
||||
//##apiwiz##eps## // Do not remove, no wizard declaration after this line
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user