lazarus/lcl/interfaces/qt/qtobject.inc

1625 lines
48 KiB
PHP

{%MainUnit qtint.pp}
{
*****************************************************************************
This file is part of the Lazarus Component Library (LCL)
See the file COPYING.modifiedLGPL.txt, included in this distribution,
for details about the license.
*****************************************************************************
}
//---------------------------------------------------------------
{$IFDEF HASX11}
// palette initialisation for X11, fixed delayed initialization of palettes
// with various styles under X11.
procedure QtX11InitializePalettes;
var
Palette: QPaletteH;
LineEditPalette: QPaletteH;
ComboBoxPalette: QPaletteH;
TextEditPalette: QPaletteH;
Brush: QBrushH;
begin
//palette for disabled viewports and edit controls
Palette := QPalette_create();
QApplication_palette(Palette);
Brush := QPalette_window(Palette);
QPalette_setBrush(Palette, QPaletteDisabled, QPaletteBase, Brush);
QApplication_setPalette(Palette);
QPalette_destroy(Palette);
LineEditPalette := QPalette_create();
ComboBoxPalette := QPalette_create();
TextEditPalette := QPalette_create();
//palette for inactive titlebars
Palette := QPalette_create();
QApplication_palette(Palette);
// save original palette for QLineEdit, QComboBox, QTextEdit
QApplication_palette(LineEditPalette, 'QLineEdit');
QApplication_palette(ComboBoxPalette, 'QComboBox');
QApplication_palette(TextEditPalette, 'QTextEdit');
Brush := QPalette_dark(Palette);
QPalette_setBrush(Palette, QPaletteInactive, QPaletteHighlight, Brush);
QApplication_setPalette(Palette);
QPalette_destroy(Palette);
// restore original palettes for QLineEdit, QComboBox, QTextEdit
// otherwise we can have inactive selection color when setting
// selection on invisible widgets
QApplication_setPalette(LineEditPalette,'QLineEdit');
QApplication_setPalette(ComboBoxPalette,'QComboBox');
QApplication_setPalette(TextEditPalette,'QTextEdit');
QPalette_destroy(LineEditPalette);
QPalette_destroy(ComboBoxPalette);
QPalette_destroy(TextEditPalette);
end;
{$ENDIF}
{------------------------------------------------------------------------------
Method: TQtWidgetSet.Create
Params: None
Returns: Nothing
Constructor for the class.
------------------------------------------------------------------------------}
constructor TQtWidgetSet.Create;
begin
FLastWFPMousePos := Point(MaxInt, MaxInt);
FLastWFPResult := 0;
inherited Create;
FIsLibraryInstance := QCoreApplication_instance() <> nil;
if FIsLibraryInstance then
App := QApplicationH(QCoreApplication_instance())
else
App := QApplication_Create(@argc, argv);
{$J+}
QtVersionInt(QtVersionMajor, QtVersionMinor, QtVersionMicro);
{$J-}
FCachedMenuBarHeight := -1;
FAppEvenFilterHook := nil;
FAppFocusChangedHook := nil;
QtGDIObjects := TQtGDIObjects.Create;
InitStockItems;
QtWidgetSet := Self;
ClearCachedColors;
FDockImage := nil;
FDragImageLock := False;
System.InitCriticalSection(CriticalSection);
SavedHandlesList := TMap.Create(TMapIdType(ituPtrSize), SizeOf(TObject));
FSocketEventMap := TMap.Create(TMapIdType(its4), SizeOf(Pointer));
StayOnTopList := nil;
FAppActive := False;
{$IFDEF HASX11}
SavedHintHandlesList := TFPList.Create;
FMinimizedByPager := False;
FLastMinimizeEvent := 0;
if not FIsLibraryInstance and
((QtVersionMajor = 4) and (QtVersionMinor < 6)) or IsOldKDEInstallation then
QtX11InitializePalettes;
FWindowManagerName := LowerCase(GetWindowManager);
// metacity wm forks. marco = mint mate wm, gnome shell = gnome 3 wm
if (FWindowManagerName = 'marco') or (FWindowManagerName = 'gnome shell') then
FWindowManagerName := 'metacity';
{$ENDIF}
{$IFDEF DARWIN}
// do not swap meta and ctrl keys, issue #20897
if not FIsLibraryInstance and (QtVersionMajor = 4) and (QtVersionMinor > 5) then
QCoreApplication_setAttribute(QtAA_MacDontSwapCtrlAndMeta, True);
{$ENDIF}
FGlobalActions := TFPList.Create;
end;
{------------------------------------------------------------------------------
Method: TQtWidgetSet.Destroy
Params: None
Returns: Nothing
Destructor for the class.
------------------------------------------------------------------------------}
destructor TQtWidgetSet.Destroy;
begin
if FDockImage <> nil then
QRubberBand_destroy(FDockImage);
DestroyGlobalCaret;
Clipboard.Free;
FreeStockItems;
FreeSysColorBrushes;
QtDefaultPrinter.Free;
QtWidgetSet := nil;
if SavedDCList<>nil then
SavedDCList.Free;
QtDefaultContext.Free;
QtScreenContext.Free;
ClearCachedColors;
if StayOnTopList <> nil then
begin
StayOnTopList.Free;
StayOnTopList := nil;
end;
if SavedHandlesList <> nil then
begin
SavedHandlesList.Free;
SavedHandlesList := nil;
end;
{$IFDEF HASX11}
if SavedHintHandlesList <> nil then
begin
SavedHintHandlesList.Free;
SavedHintHandlesList := nil;
end;
{$ENDIF}
FSocketEventMap.Free;
FGlobalActions.Free;
System.DoneCriticalsection(CriticalSection);
if Assigned(QtGDIObjects) then
FreeThenNil(QtGDIObjects);
inherited Destroy;
end;
{------------------------------------------------------------------------------
Method: TQtWidgetSet.Destroy
Params: None
Returns: Nothing
Creates a new timer and sets the callback event.
------------------------------------------------------------------------------}
function TQtWidgetSet.CreateTimer(Interval: integer; TimerFunc: TWSTimerProc): THandle;
var
QtTimer: TQtTimer;
begin
QtTimer := TQtTimer.CreateTimer(Interval, TimerFunc, App);
Result := THandle(QtTimer);
end;
{------------------------------------------------------------------------------
Method: TQtWidgetSet.Destroy
Params: None
Returns: Nothing
Destroys a timer.
------------------------------------------------------------------------------}
function TQtWidgetSet.DestroyTimer(TimerHandle: THandle): boolean;
begin
TQtTimer(TimerHandle).Free;
Result := True;
end;
{------------------------------------------------------------------------------
Method: TQtWidgetSet.AppInit
Params: None
Returns: Nothing
Initializes the application
------------------------------------------------------------------------------}
procedure TQtWidgetSet.AppInit(var ScreenInfo: TScreenInfo);
var
ScreenDC: HDC;
begin
WakeMainThread := @OnWakeMainThread;
{
check whether this hook crashes on linux & darwin and why it is so
we need this hook to catch release messages
}
// install global event filter
FAppEvenFilterHook := QObject_hook_create(App);
QObject_hook_hook_events(FAppEvenFilterHook, @EventFilter);
// install focus change slot
FAppFocusChangedHook := QApplication_hook_create(App);
QApplication_hook_hook_focusChanged(FAppFocusChangedHook, @FocusChanged);
if not FIsLibraryInstance then
begin
FAppSessionQuit := QApplication_hook_create(App);
QApplication_hook_hook_commitDataRequest(FAppSessionQuit, @SlotCommitDataRequest);
FAppSaveSessionRequest := QApplication_hook_create(App);
QApplication_hook_hook_saveStateRequest(FAppSaveSessionRequest, @SlotSaveDataRequest);
end else
begin
FAppSessionQuit := nil;
FAppSaveSessionRequest := nil;
end;
ScreenDC := GetDC(0);
try
ScreenInfo.PixelsPerInchX := GetDeviceCaps(ScreenDC, LOGPIXELSX);
ScreenInfo.PixelsPerInchY := GetDeviceCaps(ScreenDC, LOGPIXELSY);
ScreenInfo.ColorDepth := GetDeviceCaps(ScreenDC, BITSPIXEL);
finally
ReleaseDC(0, ScreenDC);
end;
QtDefaultPrinter;
{$IFNDEF MSWINDOWS}
// initialize clipboard
ClipBoard;
{$ENDIF}
// initialize default app font name
SetDefaultAppFontName;
end;
{------------------------------------------------------------------------------
Method: TQtWidgetSet.AppRun
Params: None
Returns: Nothing
Enter the main message loop
------------------------------------------------------------------------------}
procedure TQtWidgetSet.AppRun(const ALoop: TApplicationMainLoop);
begin
// use LCL loop
if Assigned(ALoop) then
ALoop;
end;
{------------------------------------------------------------------------------
Method: TQtWidgetSet.AppWaitMessage
Params: None
Returns: Nothing
Waits until a message arrives, processes that and returns control out of the function
Utilized on Modal dialogs
------------------------------------------------------------------------------}
procedure TQtWidgetSet.AppWaitMessage;
begin
{we cannot call directly processEvents() with this flag
since it produces AV's sometimes, so better check is there
any pending event.}
QCoreApplication_processEvents(QEventLoopWaitForMoreEvents);
end;
{------------------------------------------------------------------------------
Method: TQtWidgetSet.AppProcessMessages
Params: None
Returns: Nothing
Processes all messages on the quoue
------------------------------------------------------------------------------}
procedure TQtWidgetSet.AppProcessMessages;
begin
QCoreApplication_processEvents(QEventLoopAllEvents);
end;
{------------------------------------------------------------------------------
Method: TQtWidgetSet.AppTerminate
Params: None
Returns: Nothing
Implements Application.Terminate and MainForm.Close.
------------------------------------------------------------------------------}
procedure TQtWidgetSet.AppTerminate;
begin
// free hooks
QObject_hook_destroy(FAppEvenFilterHook);
QApplication_hook_destroy(FAppFocusChangedHook);
// do not quit application if we are library
if not FIsLibraryInstance then
begin
if Assigned(FAppSessionQuit) then
begin
QApplication_hook_destroy(FAppSessionQuit);
FAppSessionQuit := nil;
end;
if Assigned(FAppSaveSessionRequest) then
begin
QApplication_hook_destroy(FAppSaveSessionRequest);
FAppSaveSessionRequest := nil;
end;
QCoreApplication_quit;
end;
end;
procedure TQtWidgetSet.AppMinimize;
{$IFDEF HASX11}
var
i: Integer;
AForm: TCustomForm;
States: QtWindowStates;
{$ENDIF}
begin
if (Application.MainForm <> nil) and (Application.MainForm.HandleAllocated) then
begin
{$IFDEF HASX11}
HideAllHints;
for i := 0 to Screen.CustomFormZOrderCount-1 do
begin
AForm := Screen.CustomFormsZOrdered[i];
if (AForm.Parent=nil) and AForm.HandleAllocated and
TQtWidget(AForm.Handle).getVisible and
not (AForm.FormStyle in [fsMDIChild, fsSplash]) and
not (AForm.BorderStyle in [bsNone]) then
begin
States := TQtMainWindow(AForm.Handle).getWindowState;
if not TQtMainWindow(AForm.Handle).isMinimized then
TQtMainWindow(AForm.Handle).setWindowState(States or QtWindowMinimized);
end;
end;
{$ELSE}
TQtMainWindow(Application.MainForm.Handle).ShowMinimized;
{$ENDIF}
end;
end;
procedure TQtWidgetSet.AppRestore;
{$IFDEF HASX11}
var
i: Integer;
AForm: TCustomForm;
States: QtWindowStates;
{$ENDIF}
begin
if (Application.MainForm <> nil) and (Application.MainForm.HandleAllocated) then
begin
{$IFDEF HASX11}
if Screen = nil then exit;
for i := Screen.CustomFormZOrderCount-1 downto 0 do
begin
AForm := Screen.CustomFormsZOrdered[i];
if (AForm.Parent=nil) and AForm.HandleAllocated and
TQtWidget(AForm.Handle).getVisible and
not (AForm.FormStyle in [fsMDIChild, fsSplash]) and
not (AForm.BorderStyle in [bsNone]) then
begin
States := TQtMainWindow(AForm.Handle).getWindowState;
if TQtMainWindow(AForm.Handle).isMinimized then
TQtMainWindow(AForm.Handle).setWindowState(States and not QtWindowMinimized);
end;
end;
RestoreAllHints;
{$ELSE}
TQtMainWindow(Application.MainForm.Handle).ShowNormal;
{$ENDIF}
end;
end;
procedure TQtWidgetSet.AppBringToFront;
begin
if (Application.MainForm <> nil) and
(Application.MainForm.HandleAllocated) and
(TQtMainWindow(Application.MainForm.Handle).getVisible) then
TQtMainWindow(Application.MainForm.Handle).BringToFront;
end;
procedure TQtWidgetSet.AppSetIcon(const Small, Big: HICON);
var
DoDestroyIcon: Boolean;
Icon: QIconH;
begin
DoDestroyIcon := Big = 0;
if DoDestroyIcon then
Icon := QIcon_create()
else
Icon := TQtIcon(Big).Handle;
QApplication_setWindowIcon(Icon);
if DoDestroyIcon then
QIcon_destroy(Icon);
end;
procedure TQtWidgetSet.AppSetTitle(const ATitle: string);
var
W: WideString;
begin
W := GetUtf8String(ATitle);
QCoreApplication_setApplicationName(@W);
end;
function TQtWidgetSet.AppRemoveStayOnTopFlags(const ASystemTopAlso: Boolean = False): Boolean;
begin
Result := True;
QtRemoveStayOnTop(ASystemTopAlso);
end;
function TQtWidgetSet.AppRestoreStayOnTopFlags(const ASystemTopAlso: Boolean = False): Boolean;
begin
Result := True;
QtRestoreStayOnTop(ASystemTopAlso);
end;
procedure TQtWidgetSet.SetOverrideCursor(const AValue: TObject);
begin
if AValue = nil then
QApplication_restoreOverrideCursor()
else
if FOverrideCursor = nil then
QApplication_setOverrideCursor(TQtCursor(AValue).Handle)
else
QApplication_changeOverrideCursor(TQtCursor(AValue).Handle);
FOverrideCursor := AValue;
end;
type
TQtTempFormStyleSet = Set of TFormStyle;
const
TQtTopForms: Array[Boolean] of TQtTempFormStyleSet = (fsAllNonSystemStayOnTop,
fsAllStayOnTop);
procedure TQtWidgetSet.QtRemoveStayOnTop(const ASystemTopAlso: Boolean = False);
var
i: Integer;
AForm: TCustomForm;
W: TQtMainWindow;
Flags: QtWindowFlags;
begin
if StayOnTopList = nil then
StayOnTopList := TMap.Create(TMapIdType(ituPtrSize), SizeOf(TObject));
for i := 0 to Screen.CustomFormZOrderCount - 1 do
begin
AForm := Screen.CustomFormsZOrdered[i];
if AForm.HandleAllocated then
begin
W := TQtMainWindow(AForm.Handle);
if (AForm.Parent = nil) and
(AForm.FormStyle in TQtTopForms[ASystemTopAlso]) and W.GetVisible and
not W.IsMdiChild and not W.IsModal and not w.isMinimized then
begin
Flags := W.windowFlags;
if (Flags and QtWindowStaysOnTopHint) <> 0 then
begin
W.BeginUpdate;
W.setAttribute(QtWA_ShowWithoutActivating, True);
W.setWindowFlags(Flags and not QtWindowStaysOnTopHint);
W.Show;
W.EndUpdate;
if not StayOnTopList.HasId(W) then
StayOnTopList.Add(W, W);
end;
end;
end;
end;
end;
procedure TQtWidgetSet.QtRestoreStayOnTop(const ASystemTopAlso: Boolean = False);
var
i: Integer;
AForm: TCustomForm;
W: TQtMainWindow;
Flags: QtWindowFlags;
begin
if StayOnTopList = nil then
exit;
for i := Screen.CustomFormZOrderCount - 1 downto 0 do
begin
AForm := Screen.CustomFormsZOrdered[i];
if AForm.HandleAllocated then
begin
W := TQtMainWindow(AForm.Handle);
if (AForm.Parent = nil) and
(AForm.FormStyle in TQtTopForms[ASystemTopAlso]) and W.GetVisible and
not W.IsMdiChild and not W.IsModal and not W.isMinimized then
begin
if StayOnTopList.HasId(W) then
begin
W.BeginUpdate;
Flags := W.windowFlags;
W.setWindowFlags(Flags or QtWindowStaysOnTopHint);
W.Show;
W.setAttribute(QtWA_ShowWithoutActivating, False);
W.EndUpdate;
end;
end;
end;
end;
StayOnTopList.Free;
StayOnTopList := nil;
end;
procedure TQtWidgetSet.SetDefaultAppFontName;
var
AppFont: QFontH;
begin
FCachedMenuBarHeight := -1;
AppFont := QFont_create();
QApplication_font(AppFont);
QFont_family(AppFont, @FDefaultAppFontName);
QFont_destroy(AppFont);
end;
function TQtWidgetSet.CreateThemeServices: TThemeServices;
begin
Result := TQtThemeServices.Create;
end;
function TQtWidgetSet.EventFilter(Sender: QObjectH; Event: QEventH): Boolean; cdecl;
var
AObject: TQtObject;
W: TQtMainWindow;
LCLEvent: QLCLMessageEventH;
ASequence: QKeySequenceH;
AKey: WideString;
AParent: QWidgetH;
function IsAnyWindowActive: Boolean;
begin
Result := (QApplication_activeWindow() <> nil) or
(QApplication_activeModalWidget() <> nil) or
(QApplication_activePopupWidget() <> nil);
end;
begin
Result := False;
case QEvent_type(Event) of
QEventShortcutOverride: // issue #22827
begin
QKeyEvent_text(QKeyEventH(Event), @AKey);
if (QKeyEvent_modifiers(QKeyEventH(Event)) = QtAltModifier) and
(AKey <> '') then
begin
ASequence := QKeySequence_create(QKeyEvent_modifiers(QKeyEventH(Event))
or QKeyEvent_Key(QKeyEventH(Event)));
try
AParent := QWidget_parentWidget(QWidgetH(Sender));
if AParent <> nil then
Result := QApplication_notify(App, AParent, Event);
finally
QKeySequence_destroy(ASequence);
end;
end;
end;
QEventApplicationFontChange: SetDefaultAppFontName;
QEventStyleChange:
begin
if (Sender = QCoreApplication_instance()) then
begin
FCachedMenuBarHeight := -1;
ThemeServices.IntfDoOnThemeChange;
end;
end;
QEventApplicationActivate:
begin
LCLEvent := QLCLMessageEvent_create(LCLQt_ApplicationActivate);
// activate it imediatelly (high priority)
QCoreApplication_postEvent(Sender, LCLEvent, 1 {high priority});
end;
LCLQt_ApplicationActivate:
if Assigned(Application) and not FAppActive then
begin
FAppActive := True;
{$IF DEFINED(QTDEBUGAPPACTIVATE) OR DEFINED(VerboseQtEvents)}
DebugLn('TQtWidgetSet.EventFilter: Application is activated - time ',dbgs(GetTickCount));
{$ENDIF}
// check if activated form is StayOnTop, if it's so, we must
// eat next appdeactivate & appactivate since we are changing form
// flags !
if (StayOnTopList <> nil) then
W := TQtMainWindow(HWNDFromWidgetH(QApplication_activeWindow()))
else
W := nil;
Application.IntfAppActivate;
QtRestoreStayOnTop;
if (W <> nil) and Assigned(StayOnTopList) and StayOnTopList.HasId(W) then
W.Activate;
Result := True;
end;
QEventApplicationDeactivate:
begin
// we must check if we are ready for deactivation (low priority)
// this is 2way check. LCLQt_ApplicationDeActivate sends
// LCLQt_ApplicationDeActivate_Check to be 100% sure if needed.
LCLEvent := QLCLMessageEvent_create(LCLQt_ApplicationDeActivate);
QCoreApplication_postEvent(Sender, LCLEvent, -$FF);
end;
LCLQt_ApplicationDeactivate:
begin
if Assigned(Application) and FAppActive then
begin
if not IsAnyWindowActive then
begin
QCoreApplication_sendPostedEvents(nil, QEventWindowActivate);
QCoreApplication_processEvents(QEventLoopAllEvents, 10 {msec});
end;
// if there's active window after posting from queue, just exit ...
// app is not deactivated.
if IsAnyWindowActive then
exit(True);
// to be 100% sure that we are really deactivated, send check
// event with pretty low priority. We need
// LCLQt_ApplicationDeActivate_Check to avoid infinite loop inside
// this event with same code.
LCLEvent := QLCLMessageEvent_create(LCLQt_ApplicationDeActivate_Check);
QCoreApplication_postEvent(Sender, LCLEvent, -$FFFF);
Result := True;
end;
end;
LCLQt_ApplicationDeactivate_Check:
if Assigned(Application) and FAppActive then
begin
// 1st send posted events, and process few events from queue
if not IsAnyWindowActive then
begin
QCoreApplication_sendPostedEvents(nil, QEventWindowActivate);
QCoreApplication_processEvents(QEventLoopAllEvents, 10 {msec});
end;
// if there's active window after posting from queue, just exit ...
// app is not deactivated.
if IsAnyWindowActive then
begin
{$IF DEFINED(QTDEBUGAPPACTIVATE) OR DEFINED(VerboseQtEvents)}
DebugLn('NOTICE: TQtWidgetSet.EventFilter: App deactivation called with active windows ... ignoring.');
{$ENDIF}
QEvent_ignore(Event);
exit(True);
end;
{$IF DEFINED(QTDEBUGAPPACTIVATE) OR DEFINED(VerboseQtEvents)}
DebugLn('TQtWidgetSet.EventFilter: Application is deactivated - time ',dbgs(GetTickCount));
{$ENDIF}
FAppActive := False;
Application.IntfAppDeactivate;
QtRemoveStayOnTop;
Result := True;
end;
QEventApplicationPaletteChange:
begin
if Sender = App then
begin
ClearCachedColors;
FreeSysColorBrushes(True);
end;
end;
QEventShow,
QEventHide:
begin
// invalidate widgetAt cache.
if QObject_isWidgetType(Sender) and IsValidWidgetAtCachePointer then
InvalidateWidgetAtCache;
end;
LCLQt_Destroy:
begin
AObject := TQtObject(Pointer(QLCLMessageEvent_getWParam(QLCLMessageEventH(Event))));
//WriteLn('Catched free for: ', PtrUInt(AObject), ' : ', AObject.ClassName);
AObject.Free;
Result := True;
QEvent_Accept(Event);
end;
LCLQt_CheckSynchronize:
begin
// a thread is waiting -> synchronize
CheckSynchronize;
end;
end;
end;
procedure TQtWidgetSet.FocusChanged(aold: QWidgetH; anew: QWidgetH); cdecl;
var
OldWidget, NewWidget: TQtWidget;
Msg: TLMessage;
FocusedQtWidget: QWidgetH;
FocusedTQtWidget: TQtWidget;
{qt is tricky about focus, we don't want to inform LCL when qt internally
kills focus on an inactive form. eg. TTreeView->Editor enabled}
function CheckIfActiveForm(AWidget: TQtWidget): Boolean;
var
AForm: TCustomForm;
AMainWin: TQtMainWindow;
QtEdit: IQtEdit;
begin
Result := True;
if Assigned(AWidget) and Assigned(AWidget.LCLObject) then
begin
AMainWin := nil;
if (csDesigning in AWidget.LCLObject.ComponentState) then
exit;
if TQtWidget(AWidget.LCLObject.Handle) is TQtMainWindow then
AMainWin := TQtMainWindow(AWidget);
if AMainWin = nil then
begin
AForm := GetParentForm(AWidget.LCLObject);
if Assigned(AForm) and (AForm.HandleAllocated) then
AMainWin := TQtMainWindow(AForm.Handle);
end;
Result := AMainWin <> nil;
if not Result then
begin
{$IF DEFINED(VerboseFocus) OR DEFINED(DebugQtFocus)}
WriteLn('TQtWidgetSet.FocusChanged: CheckIfActiveForm *** NO FORM ?!? ***');
{$ENDIF}
exit;
end;
if AMainWin.IsMdiChild then
begin
Result :=
QMdiArea_activeSubWindow(QMdiSubWindow_mdiArea(QMdiSubWindowH(AMainWin.Widget))) =
QMdiSubWindowH(AMainWin.Widget);
end else
begin
Result := QWidget_isActiveWindow(AMainWin.Widget);
end;
if (AMainWin <> AWidget) and not Supports(AWidget, IQtEdit, QtEdit) then
Result := True;
end;
end;
{checks when qtmdi is doing weird thing (trying to loop itself)}
function MDIFocusFixNeeded: Boolean;
var
OldWin, NewWin: TCustomForm;
// H: HWND;
begin
Result := False;
if Assigned(OldWidget.LCLObject) then
OldWin := GetParentForm(OldWidget.LCLObject)
else
OldWin := nil;
if (NewWidget <> nil) and Assigned(NewWidget.LCLObject) then
NewWin := GetParentForm(NewWidget.LCLObject)
else
NewWin := nil;
Result := (OldWin <> nil) and OldWin.HandleAllocated and
((OldWin = NewWin) or (NewWin = nil));
if not Result then
exit;
// that's real window of our => form
Result := TQtMainWindow(OldWin.Handle).MDIChildArea <> nil;
// Result := Result and ((NewWin = nil) or (TQtMainWindow(NewWin.Handle).MDIChildArea <> nil));
if Result then
Result := (OldWin = OldWidget.LCLObject) or
((NewWin = nil) or (NewWin = NewWidget.LCLObject));
end;
begin
{$IF DEFINED(VerboseFocus) OR DEFINED(DebugQtFocus)}
WriteLn('TQtWidgetSet.FocusChanged: old: ', dbgHex(PtrUInt(aold)), ' new: ', dbgHex(PtrUInt(anew)));
{$ENDIF}
OldWidget := GetFirstQtObjectFromWidgetH(aold);
NewWidget := GetFirstQtObjectFromWidgetH(anew);
if OldWidget = NewWidget then
begin
{$IF DEFINED(VerboseFocus) OR DEFINED(DebugQtFocus)}
WriteLn('TQtWidgetSet.FocusChanged: OldWidget = NewWidget ... exiting ...');
{$ENDIF}
Exit;
end;
{Applies to all TQtWidgets which have "subwidgets" created
by CreateFrom() eg. comboBox.}
if (OldWidget <> nil) and
(NewWidget <> nil) and
(OldWidget.LCLObject = NewWidget.LCLObject) then
begin
{$IF DEFINED(VerboseFocus) OR DEFINED(DebugQtFocus)}
WriteLn('TQtWidgetSet.FocusChanged: exiting ... '+
'OldWidget.LCLObject=NewWidget.LCLObject OBJ=',dbgsName(OldWidget.LCLObject));
{$ENDIF}
exit;
end;
Msg.Msg := 0; // shutup compiler
FillChar(Msg, SizeOf(Msg), 0);
if IsValidHandle(HWND(NewWidget)) then
begin
{$IF DEFINED(VerboseFocus) OR DEFINED(DebugQtFocus)}
WriteLn('TQtWidgetSet.FocusChanged: SET ', dbgsName(NewWidget.LCLObject));
{$ENDIF}
Msg.msg := LM_SETFOCUS;
Msg.wParam := PtrInt(OldWidget);
if (NewWidget is TQtMainWindow) and (TQtMainWindow(NewWidget).IsMdiChild) and
Assigned(TQtMainWindow(NewWidget).LCLObject) and
not (csDesigning in TQtMainWindow(NewWidget).LCLObject.ComponentState) then
begin
// DO NOT TRIGGER ANYTHING, THIS IS SPURIOUS EVENT FROM MDIAREA
FocusedQtWidget := QWidget_focusWidget(NewWidget.Widget);
{$IF DEFINED(VerboseFocus) OR DEFINED(DebugQtFocus)}
Writeln('TQtWidgetSet.FocusChanged: *** DO NOT SET FOCUS ***',dbgHex(PtrUInt(FocusedQtWidget)));
{$ENDIF}
if FocusedQtWidget <> nil then
begin
FocusedTQtWidget := TQtWidget(HwndFromWidgetH(FocusedQtWidget));
if FocusedTQtWidget <> nil then
begin
if FocusedTQtWidget = NewWidget then
begin
{$IF DEFINED(VerboseFocus) OR DEFINED(DebugQtFocus)}
writeln('TQtWidgetSet.FocusChanged: WE CANNOT FOCUS (segfault) ',dbgsName(FocusedTQtWidget.LCLObject),
' Active ? ',TCustomForm(NewWidget.LCLObject).Active);
{$ENDIF}
if Assigned(TCustomForm(NewWidget.LCLObject).ActiveControl) then
begin
{$IF DEFINED(VerboseFocus) OR DEFINED(DebugQtFocus)}
writeln('TQtWidgetSet.FocusChanged: THIS ONE SHOULD BE FOCUSED (1) : ',dbgsName(TCustomForm(NewWidget.LCLObject).ActiveControl));
{$ENDIF}
if TCustomForm(NewWidget.LCLObject).ActiveControl.HandleAllocated then
begin
// setFocus(TCustomForm(NewWidget.LCLObject).ActiveControl.Handle);
FocusedTQtWidget := TQtWidget(TCustomForm(NewWidget.LCLObject).ActiveControl.Handle);
if FocusedTQtWidget <> nil then
begin
// first check if we are active subwin, if not then we'll trigger qt do
// do correct thing
if TQtMainWindow(NewWidget).MDIChildArea.ActiveSubWindow <> NewWidget.Widget then
TQtMainWindow(NewWidget).MDIChildArea.ActivateSubWindow(QMDISubWindowH(NewWidget.Widget))
else
begin
// if we are already active then just inform lcl
Msg.msg := LM_SETFOCUS;
if OldWidget = FocusedTQtWidget then
OldWidget := nil;
Msg.wParam := PtrInt(OldWidget);
FocusedTQtWidget.DeliverMessage(Msg);
end;
end;
end else
{$IF DEFINED(VerboseFocus) OR DEFINED(DebugQtFocus)}
writeln('TQtWidgetSet.FocusChanged: BUT NO HANDLE ... CRAP: ',dbgsName(TCustomForm(NewWidget.LCLObject).ActiveControl))
{$ENDIF}
;
end else
// if this happens then qt's mdi focus is real crap
{$IF DEFINED(VerboseFocus) OR DEFINED(DebugQtFocus)}
writeln('TQtWidgetSet.FocusChanged: WE ARE COMPLETELY OUT OF MIND WHAT TO DO (1) .....')
{$ENDIF}
;
end else
begin
// should never happen
{$IF DEFINED(VerboseFocus) OR DEFINED(DebugQtFocus)}
if Assigned(TCustomForm(NewWidget.LCLObject).ActiveControl) then
writeln('TQtWidgetSet.FocusChanged: THIS ONE SHOULD BE FOCUSED (2) : ',dbgsName(TCustomForm(NewWidget.LCLObject).ActiveControl))
else
writeln('TQtWidgetSet.FocusChanged: WE ARE COMPLETELY OUT OF MIND WHAT TO DO (2) .....');
{$ENDIF}
end;
end;
end;
end else
NewWidget.DeliverMessage(Msg);
end;
FillChar(Msg, SizeOf(Msg), 0);
if IsValidHandle(HWND(OldWidget)) then
begin
{$IF DEFINED(VerboseFocus) OR DEFINED(DebugQtFocus)}
WriteLn('TQtWidgetSet.FocusChanged: KILL ', dbgsName(OldWidget.LCLObject),' W.Visible ',OldWidget.getVisible,
' destroying ? ',csDestroying in OldWidget.LCLObject.ComponentState,
' handle ?!? ',OldWidget.LCLObject.HandleAllocated);
{$ENDIF}
Msg.msg := LM_KILLFOCUS;
Msg.wParam := PtrInt(NewWidget);
if ((OldWidget is TQtMainWindow) and (TQtMainWindow(OldWidget).IsMdiChild) and
Assigned(TQtMainWindow(OldWidget).LCLObject) and
not (csDesigning in TQtMainWindow(OldWidget).LCLObject.ComponentState))
or MDIFocusFixNeeded then
// DO NOT TRIGGER ANYTHING, THIS IS SPURIOUS EVENT FROM MDIAREA
{$IF DEFINED(VerboseFocus) OR DEFINED(DebugQtFocus)}
Writeln('TQtWidgetSet.FocusChanged: *** DO NOT KILL FOCUS ***')
{$ENDIF}
else
if CheckIfActiveForm(OldWidget) then
OldWidget.DeliverMessage(Msg)
{$IF DEFINED(VerboseFocus) OR DEFINED(DebugQtFocus)}
else
Writeln('TQtWidgetSet.FocusChanged: Cannot kill focus of ',dbgsName(OldWidget.LCLObject))
{$ENDIF}
;
end;
end;
procedure TQtWidgetSet.OnWakeMainThread(Sender: TObject);
var
Event: QEventH;
begin
Event := QEvent_create(LCLQt_CheckSynchronize);
QCoreApplication_postEvent(QCoreApplication_instance(), Event, 1 {high priority});
end;
procedure TQtWidgetSet.SlotCommitDataRequest(sessionManager: QSessionManagerH);
cdecl;
var
ACancel: Boolean;
begin
ACancel := False;
{$IFDEF QTDEBUGSESSIONMANAGER}
DebugLn('TQtWidgetSet.SlotCommitDataRequest allowInteraction ? ',dbgs(QSessionManager_allowsInteraction(sessionManager)),
' errorInteraction ',dbgs(QSessionManager_allowsErrorInteraction(sessionManager)),
' phase2 ',dbgs(QSessionManager_isPhase2(sessionManager)));
{$ENDIF}
// if session manager does not allow interaction, then we close app without any intf calls
if QSessionManager_allowsInteraction(sessionManager) then
begin
Application.IntfQueryEndSession(ACancel);
if ACancel then
begin
{$IFDEF QTDEBUGSESSIONMANAGER}
DebugLn('*** App shutdown cancelled ...***');
{$ENDIF}
QSessionManager_cancel(sessionManager);
end else
begin
Application.IntfEndSession;
QApplication_hook_destroy(FAppSessionQuit);
FAppSessionQuit := nil;
{$IFDEF QTDEBUGSESSIONMANAGER}
DebugLn('*** App shutdown releasing sessionManager ...***');
{$ENDIF}
QSessionManager_release(sessionManager);
end;
end;
end;
procedure TQtWidgetSet.SlotSaveDataRequest(sessionManager: QSessionManagerH);
cdecl;
begin
{$IFDEF QTDEBUGSESSIONMANAGER}
DebugLn('TQtWidgetSet.SlotSaveDataRequest ');
{$ENDIF}
end;
function TQtWidgetSet.LCLPlatform: TLCLPlatform;
begin
Result:= lpQT;
end;
function TQtWidgetSet.GetLCLCapability(ACapability: TLCLCapability): PtrUInt;
begin
case ACapability of
lcEmulatedMDI,
lcCanDrawOutsideOnPaint: Result := LCL_CAPABILITY_NO;
lcDragDockStartOnTitleClick: Result :=
{$ifdef MSWINDOWS} LCL_CAPABILITY_YES {$else} LCL_CAPABILITY_NO {$endif};
lcNeedMininimizeAppWithMainForm: Result :=
{$ifdef HASX11} LCL_CAPABILITY_YES {$else} LCL_CAPABILITY_NO {$endif};
{when issue #20475 is fixed, then set this to LCL_CAPABILITY_YES}
lcReceivesLMClearCutCopyPasteReliably: Result := LCL_CAPABILITY_NO;
else
Result := inherited GetLCLCapability(ACapability);
end;
end;
function TQtWidgetSet.DCGetPixel(CanvasHandle: HDC; X, Y: integer): TGraphicsColor;
var
Color: QColorH;
begin
Result := clNone;
if not IsValidDC(CanvasHandle) then Exit;
if (TQtDeviceContext(CanvasHandle).vImage <> nil) then
begin
Color := QColor_create(QImage_pixel(TQtDeviceContext(CanvasHandle).vImage.Handle, X, Y));
Result := RGBToColor(QColor_red(Color), QColor_green(Color), QColor_blue(Color));
QColor_destroy(Color);
end;
end;
procedure dbgcolor(msg: string; C:TQColor);
begin
debugLn(msg+' spec=%x alpha=%x r=%x g=%x b=%x pad=%x',[c.ColorSpec,c.Alpha,c.r,c.g,c.b,c.pad]);
end;
procedure TQtWidgetSet.DCSetPixel(CanvasHandle: HDC; X, Y: integer; AColor: TGraphicsColor);
var
ASavedColor: TQColor;
Color: TQColor;
ColorRef: TColorRef;
Pen: QPenH;
Painter: QPainterH;
begin
if IsValidDC(CanvasHandle) then
begin
// WriteLn('TQtWidgetSet.DCSetPixel X=',X,' Y=',Y, ' AColor=',dbghex(AColor),' rgb ? ',dbgHex(ColorToRGB(AColor)));
Painter := TQtDeviceContext(CanvasHandle).Widget;
Pen := QPainter_pen(Painter);
QPen_color(Pen, @ASavedColor);
ColorRef := TColorRef(ColorToRGB(AColor));
QColor_fromRgb(@Color, Red(ColorRef), Green(ColorRef), Blue(ColorRef));
QPainter_setPen(Painter, @Color);
QPainter_drawPoint(Painter, X,Y);
QPainter_setPen(Painter, @ASavedColor);
end;
end;
procedure TQtWidgetSet.DCRedraw(CanvasHandle: HDC);
begin
// TODO: implement me
end;
procedure TQtWidgetSet.DCSetAntialiasing(CanvasHandle: HDC; AEnabled: Boolean);
var
DC: TQtDeviceContext;
begin
if IsValidDC(CanvasHandle) then
begin
if CanvasHandle = 1 then
DC := QtDefaultContext
else
DC := TQtDeviceContext(CanvasHandle);
DC.setRenderHint(QPainterAntialiasing, AEnabled);
end;
end;
procedure TQtWidgetSet.SetDesigning(AComponent: TComponent);
begin
end;
{------------------------------------------------------------------------------
Function: TQtWidgetSet.IsValidDC
Params: DC - handle to a device context (TQtDeviceContext)
Returns: True - if the DC is valid
------------------------------------------------------------------------------}
function TQtWidgetSet.IsValidDC(const DC: HDC): Boolean;
begin
Result := (DC <> 0);
end;
{------------------------------------------------------------------------------
Function: TQtWidgetSet.IsValidGDIObject
Params: GDIObject - handle to a GDI Object (TQtFont, TQtBrush, etc)
Returns: True - if the DC is valid
Remark: All handles for GDI objects must be pascal objects so we can
distinguish between them
------------------------------------------------------------------------------}
function TQtWidgetSet.IsValidGDIObject(const GDIObject: HGDIOBJ): Boolean;
var
aObject: TObject;
begin
Result := False;
if not QtGDIObjects.IsValidGDIObject(GDIObject) then
exit;
aObject := TObject(GDIObject);
try
if aObject is TObject then
begin
Result :=
(aObject is TQtFont) or
(aObject is TQtBrush) or
(aObject is TQtImage) or
(aObject is TQtPen) or
(aObject is TQtRegion);
end;
except
// DebugLn(['TQtWidgetSet.IsValidGDIObject: Gdi object ', GDIObject, ' is not an object!']);
raise Exception.CreateFmt('TQtWidgetSet.IsValidGDIObject: %u is not an object ',[PtrUInt(GDIObject)]);
end;
end;
procedure TQtWidgetSet.AddHandle(AHandle: TObject);
begin
System.EnterCriticalsection(CriticalSection);
if not SavedHandlesList.HasId(AHandle) then
SavedHandlesList.Add(AHandle, AHandle);
System.LeaveCriticalsection(CriticalSection);
end;
procedure TQtWidgetSet.RemoveHandle(AHandle: TObject);
begin
System.EnterCriticalsection(CriticalSection);
if SavedHandlesList.HasId(AHandle) then
SavedHandlesList.Delete(AHandle);
System.LeaveCriticalsection(CriticalSection);
end;
function TQtWidgetSet.IsValidHandle(AHandle: HWND): Boolean;
begin
if (AHandle = 0) then
Exit(False);
System.EnterCriticalsection(CriticalSection);
Result := SavedHandlesList.HasId(TObject(AHandle));
System.LeaveCriticalsection(CriticalSection);
end;
{$IFDEF HASX11}
procedure TQtWidgetSet.AddHintHandle(AHandle: TObject);
begin
System.EnterCriticalsection(CriticalSection);
if SavedHintHandlesList.IndexOf(AHandle) < 0 then
SavedHintHandlesList.Add(AHandle);
System.LeaveCriticalsection(CriticalSection);
end;
procedure TQtWidgetSet.RemoveHintHandle(AHandle: TObject);
var
AIndex: Integer;
begin
System.EnterCriticalsection(CriticalSection);
AIndex := SavedHintHandlesList.IndexOf(AHandle);
if AIndex >= 0 then
SavedHintHandlesList.Delete(AIndex);
System.LeaveCriticalsection(CriticalSection);
end;
function TQtWidgetSet.IsValidHintHandle(AHandle: TObject): Boolean;
begin
if (AHandle = nil) then
Exit(False);
System.EnterCriticalsection(CriticalSection);
Result := SavedHintHandlesList.IndexOf(AHandle) >= 0;
System.LeaveCriticalsection(CriticalSection);
end;
procedure TQtWidgetSet.HideAllHints;
var
i: Integer;
AWidget: TQtHintWindow;
begin
System.EnterCriticalsection(CriticalSection);
try
Application.CancelHint;
if not Assigned(SavedHintHandlesList) then
exit;
for i := SavedHintHandlesList.Count - 1 downto 0 do
begin
if IsValidHintHandle(TObject(SavedHintHandlesList.Items[i])) then
begin
AWidget := TQtHintWindow(SavedHintHandlesList.Items[i]);
AWidget.NeedRestoreVisible := AWidget.getVisible;
AWidget.Hide;
end;
end;
finally
System.LeaveCriticalsection(CriticalSection);
end;
end;
procedure TQtWidgetSet.RestoreAllHints;
var
i: Integer;
AWidget: TQtHintWindow;
begin
System.EnterCriticalsection(CriticalSection);
try
if not Assigned(SavedHintHandlesList) then
exit;
for i := SavedHintHandlesList.Count - 1 downto 0 do
begin
if IsValidHintHandle(TObject(SavedHintHandlesList.Items[i])) then
begin
AWidget := TQtHintWindow(SavedHintHandlesList.Items[i]);
if AWidget.NeedRestoreVisible then
begin
AWidget.NeedRestoreVisible := False;
AWidget.Show;
end;
end;
end;
finally
System.LeaveCriticalsection(CriticalSection);
end;
end;
{$ENDIF}
procedure TQtWidgetSet.ClearGlobalActions;
begin
{$IFDEF QT_DEBUG_GLOBALACTIONS}
writeln('TQtWidgetSet.ClearGlobalActions');
{$ENDIF}
FGlobalActions.Clear;
end;
procedure TQtWidgetSet.AddGlobalAction(AnAction: QActionH);
begin
{$IFDEF QT_DEBUG_GLOBALACTIONS}
writeln('TQtWidgetSet.AddGlobalAction() AnAction ',dbgHex(PtrUInt(AnAction)));
{$ENDIF}
FGlobalActions.Add(AnAction);
end;
function TQtWidgetSet.ShortcutInGlobalActions(const AMnemonicText: WideString;
out AGlobalActionIndex: Integer): Boolean;
var
NewKey: QKeySequenceH;
NewStr: WideString;
CurrentKey: QKeySequenceH;
CurrentStr: WideString;
Action: QActionH;
i: Integer;
begin
{$IFDEF QT_DEBUG_GLOBALACTIONS}
writeln('TQtWidgetSet.ShortcutInGlobalActions ',AMnemonicText);
{$ENDIF}
Result := False;
AGlobalActionIndex := -1;
NewKey := QKeySequence_create();
try
QKeySequence_fromString(NewKey, @AMnemonicText);
NewStr := '';
QKeySequence_toString(NewKey, @NewStr);
{$IFDEF QT_DEBUG_GLOBALACTIONS}
writeln('TQtWidgetSet.ShortcutInGlobalActions new seq=',NewStr);
{$ENDIF}
for i := 0 to FGlobalActions.Count - 1 do
begin
Action := QActionH(FGlobalActions.Items[i]);
CurrentStr := '';
QAction_text(Action, @CurrentStr);
CurrentKey := QKeySequence_create();
try
QKeySequence_mnemonic(CurrentKey, @CurrentStr);
if not QKeySequence_isEmpty(CurrentKey) then
begin
QKeySequence_toString(CurrentKey, @CurrentStr);
{$IFDEF QT_DEBUG_GLOBALACTIONS}
writeln('TQtWidgetSet.ShortcutInGlobalActions CurrentKey ',
CurrentStr,' NewKey ',NewStr,' Result ? ',CurrentStr = NewStr);
{$ENDIF}
Result := CurrentStr = NewStr;
AGlobalActionIndex := i;
if Result then
break;
end;
finally
QKeySequence_destroy(CurrentKey);
end;
end;
finally
QKeySequence_destroy(NewKey);
end;
end;
procedure TQtWidgetSet.TriggerGlobalAction(const ActionIndex: Integer);
var
Action: QActionH;
MainWin: TQtMainWindow;
begin
Action := QActionH(FGlobalActions[ActionIndex]);
if (Action <> nil) and Assigned(Application.MainForm) and
(Application.MainForm.HandleAllocated) then
begin
MainWin := TQtMainWindow(Application.MainForm.Handle);
MainWin.Activate;
QMenuBar_setActiveAction(QMenuBarH(MainWin.MenuBar.Widget), Action);
end;
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;
{Params: none
Returns: True if last cached FLastWFPResult is valid otherwise False.
}
function TQtWidgetSet.IsValidWidgetAtCachePointer: Boolean;
begin
if FLastWFPResult = 0 then
exit(False);
Result := IsValidHandle(FLastWFPResult);
end;
{Params: none
Returns last cached FLastWFPMousePos
Returns: TPoint
}
function TQtWidgetSet.GetWidgetAtCachePoint: TPoint;
begin
Result := FLastWFPMousePos;
end;
function TQtWidgetSet.DragImageList_BeginDrag(AImage: QImageH;
AHotSpot: TPoint): Boolean;
var
ASize: TSize;
APixmap: QPixmapH;
AMask: QBitmapH;
ABrush: QBrushH;
APalette: QPaletteH;
begin
if FDragImageList = nil then
begin
FDragImageList := QWidget_create(nil,
QtSubWindow or QtFramelessWindowHint or
QtWindowStaysOnTopHint {$IFDEF HASX11}or QtX11BypassWindowManagerHint{$ENDIF});
// do not set focus and do not activate this widget
QWidget_setFocusPolicy(FDragImageList, QtNoFocus);
QWidget_setAttribute(FDragImageList, QtWA_ShowWithoutActivating, True);
QImage_size(AImage, @ASize);
QWidget_setFixedSize(FDragImageList, @ASize);
APixmap := QPixmap_create();
QPixmap_fromImage(APixmap, AImage);
AMask := QBitmap_create();
QPixmap_mask(APixmap, AMask);
QWidget_setMask(FDragImageList, AMask);
ABrush := QBrush_create(AImage);
APalette := QWidget_palette(FDragImageList);
QPalette_setBrush(APalette, QPaletteWindow, ABrush);
QBrush_destroy(ABrush);
QBitmap_destroy(AMask);
QPixmap_destroy(APixmap);
QWidget_setAutoFillBackground(FDragImageList, True);
FDragHotSpot := AHotSpot;
end;
Result := FDragImageList <> nil;
end;
procedure TQtWidgetSet.DragImageList_EndDrag;
begin
if FDragImageList <> nil then
begin
QObject_deleteLater(FDragImageList);
FDragImageList := nil;
end;
end;
function TQtWidgetSet.DragImageList_DragMove(X, Y: Integer): Boolean;
begin
Result := FDragImageList <> nil;
if Result then
begin
QWidget_raise(FDragImageList);
QWidget_move(FDragImageList, X - FDragHotSpot.X, Y - FDragHotSpot.Y);
end;
end;
function TQtWidgetSet.DragImageList_SetVisible(NewVisible: Boolean): Boolean;
begin
Result := FDragImageList <> nil;
if Result then
QWidget_setVisible(FDragImageList, NewVisible);
end;
{$IFDEF MSWINDOWS}
function TQtWidgetSet.GetWinKeyState(AKeyState: LongInt): SHORT;
begin
Result := Windows.GetKeyState(AKeyState);
end;
{$ENDIF}
{------------------------------------------------------------------------------
Function: CreateDefaultFont
Params: none
Returns: a TQtFont object
Creates an default font, used for initial values
------------------------------------------------------------------------------}
function TQtWidgetSet.CreateDefaultFont: HFONT;
var
QtFont: TQtFont;
begin
QtFont := TQtFont.Create(True);
QtFont.FShared := True;
QApplication_font(QtFont.FHandle);
Result := HFONT(QtFont);
end;
function TQtWidgetSet.GetDefaultAppFontName: WideString;
begin
Result := FDefaultAppFontName;
end;
procedure TQtWidgetSet.DeleteDefaultDC;
begin
if FStockDefaultDC <> 0 then
TQtDeviceContext(FStockDefaultDC).Free;
FStockDefaultDC := 0;
end;
procedure TQtWidgetSet.FreeStockItems;
procedure DeleteAndNilObject(var h: HGDIOBJ);
begin
if h <> 0 then
TQtResource(h).FShared := False;
DeleteObject(h);
h := 0;
end;
begin
DeleteAndNilObject(FStockNullBrush);
DeleteAndNilObject(FStockBlackBrush);
DeleteAndNilObject(FStockLtGrayBrush);
DeleteAndNilObject(FStockGrayBrush);
DeleteAndNilObject(FStockDkGrayBrush);
DeleteAndNilObject(FStockWhiteBrush);
DeleteAndNilObject(FStockNullPen);
DeleteAndNilObject(FStockBlackPen);
DeleteAndNilObject(FStockWhitePen);
DeleteAndNilObject(FStockSystemFont);
end;
procedure TQtWidgetSet.FreeSysColorBrushes(const AInvalidateHandlesOnly: Boolean = False);
procedure DeleteAndNilObject(var h: HGDIOBJ);
begin
if h <> 0 then
begin
TQtResource(h).FShared := False;
DeleteObject(h);
h := 0;
end;
end;
procedure InvalidateHandleOnly(AIndex: Integer; h: HGDIOBJ);
begin
if (h <> 0) and (TQtBrush(h).FHandle <> nil) then
begin
QBrush_destroy(TQtBrush(h).FHandle);
TQtBrush(h).FHandle := nil;
getSysColorBrush(AIndex);
end;
end;
var
i: integer;
begin
for i := Low(FSysColorBrushes) to High(FSysColorBrushes) do
if AInvalidateHandlesOnly then
InvalidateHandleOnly(i, FSysColorBrushes[i])
else
DeleteAndNilObject(FSysColorBrushes[i]);
end;
function TQtWidgetSet.GetQtDefaultDC: HDC;
begin
Result := FStockDefaultDC;
end;
procedure TQtWidgetSet.SetQtDefaultDC(Handle: HDC);
begin
FStockDefaultDC := Handle;
end;
procedure TQtWidgetSet.InitStockItems;
var
LogBrush: TLogBrush;
logPen : TLogPen;
begin
FillChar(LogBrush,SizeOf(TLogBrush),0);
LogBrush.lbStyle := BS_NULL;
FStockNullBrush := CreateBrushIndirect(LogBrush);
TQtBrush(FStockNullBrush).FShared := True;
LogBrush.lbStyle := BS_SOLID;
LogBrush.lbColor := $000000;
FStockBlackBrush := CreateBrushIndirect(LogBrush);
TQtBrush(FStockBlackBrush).FShared := True;
LogBrush.lbColor := $C0C0C0;
FStockLtGrayBrush := CreateBrushIndirect(LogBrush);
TQtBrush(FStockLtGrayBrush).FShared := True;
LogBrush.lbColor := $808080;
FStockGrayBrush := CreateBrushIndirect(LogBrush);
TQtBrush(FStockGrayBrush).FShared := True;
LogBrush.lbColor := $404040;
FStockDkGrayBrush := CreateBrushIndirect(LogBrush);
TQtBrush(FStockDkGrayBrush).FShared := True;
LogBrush.lbColor := $FFFFFF;
FStockWhiteBrush := CreateBrushIndirect(LogBrush);
TQtBrush(FStockWhiteBrush).FShared := True;
LogPen.lopnStyle := PS_NULL;
LogPen.lopnWidth := Point(0, 0); // create cosmetic pens
LogPen.lopnColor := $FFFFFF;
FStockNullPen := CreatePenIndirect(LogPen);
TQtPen(FStockNullPen).FShared := True;
LogPen.lopnStyle := PS_SOLID;
FStockWhitePen := CreatePenIndirect(LogPen);
TQtPen(FStockWhitePen).FShared := True;
LogPen.lopnColor := $000000;
FStockBlackPen := CreatePenIndirect(LogPen);
TQtPen(FStockBlackPen).FShared := True;
FStockSystemFont := 0; // styles aren't initialized yet
FStockDefaultDC := 0; // app must be initialized
end;
function TQtWidgetSet.GetMenuHeight: Integer;
var
AMenuBar: QMenuBarH;
DummyWindow: QMainWindowH;
DummyStr: WideString;
Size: TSize;
begin
{$IFDEF DARWIN}
FCachedMenuBarHeight := 1;
{$ENDIF}
if FCachedMenuBarHeight = -1 then
begin
DummyWindow := QMainWindow_create(QApplication_desktop());
QWidget_setVisible(DummyWindow, False);
AMenuBar := QMenuBar_create();
DummyStr := 'DUMMY BAR';
QMenuBar_addMenu(AMenuBar, @DummyStr);
QMainWindow_setMenuBar(DummyWindow, AMenuBar);
QMenuBar_sizeHint(AMenuBar, @Size);
QMainWindow_destroy(DummyWindow);
FCachedMenuBarHeight := Size.cy;
if QStyle_styleHint(QApplication_style(),
QStyleSH_MainWindow_SpaceBelowMenuBar) > 0 then
inc(FCachedMenuBarHeight, 4);
if QStyle_styleHint(QApplication_style(),
QStyleSH_ScrollView_FrameOnlyAroundContents) > 0 then
inc(FCachedMenuBarHeight, 4);
end;
if (FCachedMenuBarHeight <= 0) then
begin
FCachedMenuBarHeight := 22;
if QStyle_styleHint(QApplication_style(), QStyleSH_MainWindow_SpaceBelowMenuBar) > 0 then
inc(FCachedMenuBarHeight, 4);
end;
Result := FCachedMenuBarHeight;
end;
procedure TQtWidgetSet.ClearCachedColors;
var
i: Integer;
begin
for i := 0 to High(FCachedColors) do
begin
if FCachedColors[i] <> nil then
FreeMem(FCachedColors[i]);
FCachedColors[i] := nil;
end;
end;
function TQtWidgetSet.GetStyleName: String;
var
WStr: WideString;
begin
QObject_objectName(QApplication_style, @WStr);
Result := UTF8ToUTF16(WStr);
end;
//------------------------------------------------------------------------