diff --git a/demos/Lazarus_Linux_GTK3/GTKBrowser/00-Delete.bat b/demos/Lazarus_Linux_GTK3/GTKBrowser/00-Delete.bat new file mode 100644 index 00000000..0b5ba5c8 --- /dev/null +++ b/demos/Lazarus_Linux_GTK3/GTKBrowser/00-Delete.bat @@ -0,0 +1,2 @@ +rmdir /S /Q lib +rmdir /S /Q backup diff --git a/demos/Lazarus_Linux_GTK3/GTKBrowser/GTKBrowser.lpi b/demos/Lazarus_Linux_GTK3/GTKBrowser/GTKBrowser.lpi new file mode 100644 index 00000000..dc797ae7 --- /dev/null +++ b/demos/Lazarus_Linux_GTK3/GTKBrowser/GTKBrowser.lpi @@ -0,0 +1,82 @@ + + + + + + + + + + + + + <UseAppBundle Value="False"/> + <ResourceType Value="res"/> + </General> + <MacroValues Count="1"> + <Macro1 Name="LCLWidgetType" Value="gtk3"/> + </MacroValues> + <BuildModes> + <Item Name="Default" Default="True"/> + <SharedMatrixOptions Count="1"> + <Item1 ID="267891709676" Modes="Default" Type="IDEMacro" MacroName="LCLWidgetType" Value="gtk3"/> + </SharedMatrixOptions> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + <UseFileFilters Value="True"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + </RunParams> + <RequiredPackages> + <Item> + <PackageName Value="CEF4Delphi_Lazarus"/> + </Item> + <Item> + <PackageName Value="LCL"/> + </Item> + </RequiredPackages> + <Units> + <Unit> + <Filename Value="GTKBrowser.lpr"/> + <IsPartOfProject Value="True"/> + </Unit> + <Unit> + <Filename Value="umainwindow.pas"/> + <IsPartOfProject Value="True"/> + </Unit> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <Target> + <Filename Value="../../../bin/GTKBrowser"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Linking> + <Debugging> + <DebugInfoType Value="dsDwarf3"/> + </Debugging> + </Linking> + <Other> + <CustomOptions Value="-dUseCthreads"/> + </Other> + </CompilerOptions> + <Debugging> + <Exceptions> + <Item> + <Name Value="EAbort"/> + </Item> + <Item> + <Name Value="ECodetoolError"/> + </Item> + <Item> + <Name Value="EFOpenError"/> + </Item> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/demos/Lazarus_Linux_GTK3/GTKBrowser/GTKBrowser.lpr b/demos/Lazarus_Linux_GTK3/GTKBrowser/GTKBrowser.lpr new file mode 100644 index 00000000..99842777 --- /dev/null +++ b/demos/Lazarus_Linux_GTK3/GTKBrowser/GTKBrowser.lpr @@ -0,0 +1,24 @@ +program GTKBrowser; + +{$mode objfpc}{$H+} + +uses + {$IFDEF UseCThreads} + cthreads, + {$ENDIF} + uCEFApplication, umainwindow; + +begin + CreateGlobalCEFApp; + + if StartMainProcess then + begin + MainWindow := TMainWindow.Create; + MainWindow.Show; + MainWindow.Run; + MainWindow.Free; + end; + + DestroyGlobalCEFApp; +end. + diff --git a/demos/Lazarus_Linux_GTK3/GTKBrowser/umainwindow.pas b/demos/Lazarus_Linux_GTK3/GTKBrowser/umainwindow.pas new file mode 100644 index 00000000..4754d147 --- /dev/null +++ b/demos/Lazarus_Linux_GTK3/GTKBrowser/umainwindow.pas @@ -0,0 +1,355 @@ +unit umainwindow; + +{$mode ObjFPC}{$H+} + +interface + +uses + Classes, SysUtils, SyncObjs, + LazGtk3, LazGdk3, LazGObject2, LazGLib2, xlib, + uCEFApplication, uCEFConstants, uCEFTypes, uCEFChromium, + uCEFMiscFunctions, uCEFLinuxFunctions, uCEFInterfaces; + +type + TMainWindow = class + private + FCanClose : boolean; + FClosing : boolean; + FInitializing : boolean; + FLoading : boolean; + FWindow : PGtkWidget; + FChromium : TChromium; + + function GetTitle : string; + function GetWidth : integer; + function GetHeight : integer; + + procedure SetTitle(const aValue : string); + + procedure DoAfterCreated; + procedure DoBeforeClose; + procedure DoCloseQuery(var aCanClose: Boolean); + procedure DoResize; + + procedure UpdateBrowserSize(aLeft, aTop, aWidth, aHeight : integer); + procedure UpdateXWindowVisibility(aVisible : boolean); + procedure NotifyMoveOrResizeStarted; + procedure CloseBrowser(aForceClose : boolean); + procedure CreateBrowser; + procedure CreateWidgets; + + procedure OnAfterCreated(Sender: TObject; const browser: ICefBrowser); + procedure OnBeforeClose(Sender: TObject; const browser: ICefBrowser); + procedure OnBeforePopup(Sender: TObject; const browser: ICefBrowser; const frame: ICefFrame; popup_id: Integer; const targetUrl, targetFrameName: ustring; targetDisposition: TCefWindowOpenDisposition; userGesture: Boolean; const popupFeatures: TCefPopupFeatures; var windowInfo: TCefWindowInfo; var client: ICefClient; var settings: TCefBrowserSettings; var extra_info: ICefDictionaryValue; var noJavascriptAccess, Result: Boolean); + procedure OnOpenUrlFromTab(Sender: TObject; const browser: ICefBrowser; const frame: ICefFrame; const targetUrl: ustring; targetDisposition: TCefWindowOpenDisposition; userGesture: Boolean; out Result: Boolean); + + public + constructor Create; + destructor Destroy; override; + procedure AfterConstruction; override; + procedure Show; + procedure Run; + + property Width : integer read GetWidth; + property Height : integer read GetHeight; + property Title : string read GetTitle write SetTitle; + end; + +var + MainWindow : TMainWindow = nil; + +procedure CreateGlobalCEFApp; +function StartMainProcess: boolean; + +implementation + +var + MainAppEvent : TEventObject = nil; + +{GlobalCEFApp functions} +{%Region} +procedure GlobalCEFApp_OnContextInitialized(); +begin + MainAppEvent.SetEvent; +end; + +procedure CreateGlobalCEFApp; +begin + GlobalCEFApp := TCefApplication.Create; + GlobalCEFApp.LogFile := 'debug.log'; + GlobalCEFApp.LogSeverity := LOGSEVERITY_INFO; + GlobalCEFApp.RootCache := 'RootCache'; + GlobalCEFApp.DisableZygote := True; + GlobalCEFApp.SetCurrentDir := True; + GlobalCEFApp.MultiThreadedMessageLoop := False; + GlobalCEFApp.ExternalMessagePump := False; + GlobalCEFApp.GTKVersion := gtkVersion3; + GlobalCEFApp.OzonePlatform := ozpX11; + GlobalCEFApp.OnContextInitialized := @GlobalCEFApp_OnContextInitialized; +end; + +function StartMainProcess: boolean; +begin + Result := False; + + if GlobalCEFApp.StartMainProcess then + begin + // Wait until the context is initialized before initializing GTK. + if (MainAppEvent.WaitFor(10000) = wrTimeout) then + CefDebugLog('CEF initialization failure!') + else + Result := True; + end; +end; +{%Endregion} + +{Message handlers} +{%Region} +function DeleteEventHandler(widget: PGtkWidget; event: PGdkEventAny): gboolean; cdecl; +var + TempCanClose : boolean; +begin + MainWindow.DoCloseQuery(TempCanClose); + Result := not(TempCanClose); +end; + +function DestroyEventHandler(widget: PGtkWidget; event: PGdkEventAny): gboolean; cdecl; +begin + Result := False; + GlobalCEFApp.QuitMessageLoop; +end; + +function ShowEventHandler(Widget: PGtkWidget; Data: gPointer): gboolean; cdecl; +begin + Result := False; + MainWindow.CreateBrowser; +end; + +function ConfigureEvent(widget: PGtkWidget; event: PGdkEventConfigure): gboolean; cdecl; +begin + Result := False; + MainWindow.DoResize; + MainWindow.NotifyMoveOrResizeStarted; +end; + +function CustomX11ErrorHandler(Display: PDisplay; ErrorEv: PXErrorEvent) : longint; cdecl; +begin + Result := 0; +end; + +function CustomXIOErrorHandler(Display: PDisplay) : longint; cdecl; +begin + Result := 0; +end; +{%Endregion} + +{Public methods} +{%Region} +constructor TMainWindow.Create; +begin + inherited Create; + + FCanClose := False; + FClosing := False; + FInitializing := True; + FLoading := False; + FWindow := nil; + FChromium := nil; +end; + +destructor TMainWindow.Destroy; +begin + if (FChromium <> nil) then + FreeAndNil(FChromium); + + inherited Destroy; +end; + +procedure TMainWindow.AfterConstruction; +begin + inherited AfterConstruction; + + // Force Gtk to use Xwayland (in case a Wayland compositor is being used). + gdk_set_allowed_backends('x11'); + + // The Chromium sandbox requires that there only be a single thread during + // initialization. Therefore initialize GTK after CEF. + gtk_init(@argc, @argv); + + // Install xlib error handlers so that the application won't be terminated + // on non-fatal errors. Must be done after initializing GTK. + XSetErrorHandler(@CustomX11ErrorHandler); + XSetIOErrorHandler(@CustomXIOErrorHandler); + + FChromium := TChromium.Create(nil); + FChromium.DefaultURL := 'https://www.google.com'; + FChromium.OnAfterCreated := @OnAfterCreated; + FChromium.OnBeforeClose := @OnBeforeClose; + FChromium.OnBeforePopup := @OnBeforePopup; + FChromium.OnOpenUrlFromTab := @OnOpenUrlFromTab; + + CreateWidgets; +end; + +procedure TMainWindow.Show; +begin + // Show the GTK window. + UseDefaultX11VisualForGtk(FWindow); + gtk_widget_show_all(FWindow); + + // Flush the display to make sure the underlying X11 window gets created + // immediately. + FlushDisplay(FWindow); +end; + +procedure TMainWindow.Run; +begin + GlobalCEFApp.RunMessageLoop; +end; +{%Endregion} + +{Property setters and getters} +{%Region} +function TMainWindow.GetTitle: string; +begin + Result := gtk_window_get_title(PGtkWindow(FWindow)); +end; + +function TMainWindow.GetWidth : integer; +begin + Result := gtk_widget_get_allocated_width(FWindow); +end; + +function TMainWindow.GetHeight : integer; +begin + Result := gtk_widget_get_allocated_height(FWindow); +end; + +procedure TMainWindow.SetTitle(const aValue : string); +begin + gtk_window_set_title(PGtkWindow(FWindow), PGChar(aValue)); +end; +{%Endregion} + +{Chromium events} +{%Region} +procedure TMainWindow.OnAfterCreated(Sender: TObject; const browser: ICefBrowser); +begin + TThread.Synchronize(nil, @DoAfterCreated); +end; + +procedure TMainWindow.OnBeforeClose(Sender: TObject; const browser: ICefBrowser); +begin + FCanClose := True; + TThread.Synchronize(nil, @DoBeforeClose); +end; + +procedure TMainWindow.OnBeforePopup(Sender: TObject; + const browser: ICefBrowser; const frame: ICefFrame; popup_id: Integer; + const targetUrl, targetFrameName: ustring; targetDisposition: TCefWindowOpenDisposition; + userGesture: Boolean; const popupFeatures: TCefPopupFeatures; + var windowInfo: TCefWindowInfo; var client: ICefClient; + var settings: TCefBrowserSettings; var extra_info: ICefDictionaryValue; + var noJavascriptAccess, Result: Boolean); +begin + // For simplicity, this demo blocks all popup windows and new tabs + Result := (targetDisposition in [CEF_WOD_NEW_FOREGROUND_TAB, CEF_WOD_NEW_BACKGROUND_TAB, CEF_WOD_NEW_POPUP, CEF_WOD_NEW_WINDOW]); +end; + +procedure TMainWindow.OnOpenUrlFromTab(Sender: TObject; + const browser: ICefBrowser; const frame: ICefFrame; + const targetUrl: ustring; targetDisposition: TCefWindowOpenDisposition; + userGesture: Boolean; out Result: Boolean); +begin + // For simplicity, this demo blocks all popup windows and new tabs + Result := (targetDisposition in [CEF_WOD_NEW_FOREGROUND_TAB, CEF_WOD_NEW_BACKGROUND_TAB, CEF_WOD_NEW_POPUP, CEF_WOD_NEW_WINDOW]); +end; +{%Endregion} + +{Private methods} +{%Region} +procedure TMainWindow.UpdateBrowserSize(aLeft, aTop, aWidth, aHeight : integer); +begin + if (FChromium <> nil) and FChromium.Initialized then + FChromium.UpdateBrowserSize(aLeft, aTop, aWidth, aHeight); +end; + +procedure TMainWindow.UpdateXWindowVisibility(aVisible : boolean); +begin + if (FChromium <> nil) and FChromium.Initialized then + FChromium.UpdateXWindowVisibility(aVisible); +end; + +procedure TMainWindow.DoAfterCreated; +begin + UpdateXWindowVisibility(True); + UpdateBrowserSize(0, 0, Width, Height); +end; + +procedure TMainWindow.DoBeforeClose; +begin + gtk_window_close(PGtkWindow(FWindow)); +end; + +procedure TMainWindow.DoResize; +begin + UpdateBrowserSize(0, 0, Width, Height); +end; + +procedure TMainWindow.DoCloseQuery(var aCanClose: Boolean); +begin + aCanClose := FCanClose; + + if not(FClosing) then + begin + FClosing := True; + FChromium.CloseBrowser(True); + end; +end; + +procedure TMainWindow.CreateBrowser; +begin + if (FChromium <> nil) and not(FChromium.Initialized) then + begin + if not(FChromium.CreateBrowser(TCefWindowHandle(FWindow), Rect(0, 0, Width, Height))) then + CefDebugLog('CreateBrowser failed'); + end; +end; + +procedure TMainWindow.CreateWidgets; +begin + FWindow := gtk_window_new(GTK_WINDOW_TOPLEVEL); + + gtk_window_set_default_size(PGtkWindow(FWindow), 1024, 768); + gtk_window_move(PGtkWindow(FWindow), 300, 200); + + g_signal_connect_data(FWindow, 'delete_event', TGCallback(@DeleteEventHandler), nil, nil, G_CONNECT_DEFAULT); + g_signal_connect_data(FWindow, 'destroy', TGCallback(@DestroyEventHandler), nil, nil, G_CONNECT_DEFAULT); + g_signal_connect_data(FWindow, 'show', TGCallback(@ShowEventHandler), nil, nil, G_CONNECT_DEFAULT); + g_signal_connect_data(FWindow, 'configure-event', TGCallback(@ConfigureEvent), nil, nil, G_CONNECT_DEFAULT); + + Title := 'GTKBrowser'; +end; + +procedure TMainWindow.NotifyMoveOrResizeStarted; +begin + if (FChromium <> nil) then + FChromium.NotifyMoveOrResizeStarted; +end; + +procedure TMainWindow.CloseBrowser(aForceClose : boolean); +begin + if (FChromium <> nil) then + FChromium.CloseBrowser(aForceClose); +end; +{%Endregion} + +initialization + MainAppEvent := TEventObject.Create(nil, True, False, 'MainAppEvent'); + +finalization + if assigned(MainAppEvent) then + FreeAndNil(MainAppEvent); + +end. + diff --git a/source/uCEFApplicationCore.pas b/source/uCEFApplicationCore.pas index f8dd300c..e9ad510d 100644 --- a/source/uCEFApplicationCore.pas +++ b/source/uCEFApplicationCore.pas @@ -167,6 +167,7 @@ type {$IFDEF LINUX} FPasswordStorage : TCefPasswordStorage; FGTKVersion : TCefGTKVersion; + FOzonePlatform : TCefOzonePlatform; {$ENDIF} @@ -1351,6 +1352,13 @@ type /// <para><see href="https://github.com/chromium/chromium/blob/main/ui/gtk/gtk_compat.cc">See the LoadGtkImpl function in ui/gtk/gtk_compat.cc</see></para> /// </remarks> property GTKVersion : TCefGTKVersion read FGTKVersion write FGTKVersion; + /// <summary> + /// Preferred GTK version loaded by Chromium. + /// </summary> + /// <remarks> + /// <para><see href="https://peter.sh/experiments/chromium-command-line-switches/#ozone-platform">Uses the following command line switch: --ozone-platform</see></para> + /// </remarks> + property OzonePlatform : TCefOzonePlatform read FOzonePlatform write FOzonePlatform; {$ENDIF} /// <summary> /// Ignores certificate-related errors. @@ -2063,6 +2071,7 @@ begin {$IFDEF LINUX} FPasswordStorage := psDefault; FGTKVersion := gtkVersionDefault; + FOzonePlatform := ozpDefault; {$ENDIF} // Fields used during the CEF initialization @@ -3754,6 +3763,12 @@ begin gtkVersion3 : ReplaceSwitch(aKeys, aValues, '--gtk-version', '3'); gtkVersion4 : ReplaceSwitch(aKeys, aValues, '--gtk-version', '4'); end; + + case FOzonePlatform of + ozpWayland : ReplaceSwitch(aKeys, aValues, '--ozone-platform', 'wayland'); + ozpX11 : ReplaceSwitch(aKeys, aValues, '--ozone-platform', 'x11'); + ozpHeadless : ReplaceSwitch(aKeys, aValues, '--ozone-platform', 'headless'); + end; {$ENDIF} // The list of features you can enable is here : diff --git a/source/uCEFLinuxFunctions.pas b/source/uCEFLinuxFunctions.pas index 07caeecd..3373ca05 100644 --- a/source/uCEFLinuxFunctions.pas +++ b/source/uCEFLinuxFunctions.pas @@ -62,6 +62,13 @@ function gdk_screen_get_resolution(screen:PGdkScreen):gdouble; cdecl; external ' function gdk_x11_window_get_xid(window: PGdkWindow): TXID; cdecl; external 'libgdk-3.so.0'; function gdk_x11_get_default_xdisplay: PDisplay; cdecl; external 'libgdk-3.so.0'; procedure gdk_set_allowed_backends(const backends: PGchar); cdecl; external 'libgdk-3.so.0'; +function gdk_x11_display_get_xdisplay(display: PGdkDisplay): PDisplay; cdecl; external 'libgdk-3.so.0'; +function gdk_x11_screen_get_screen_number(screen: PGdkScreen): longint; cdecl; external 'libgdk-3.so.0'; +function gdk_x11_visual_get_xvisual(visual: PGdkVisual): PVisual; cdecl; external 'libgdk-3.so.0'; +procedure UseDefaultX11VisualForGtk(widget : PGtkWidget); overload; +procedure UseDefaultX11VisualForGtk(aHandle : TCefWindowHandle); overload; +procedure FlushDisplay(widget : PGtkWidget); overload; +procedure FlushDisplay(aHandle : TCefWindowHandle); overload; {$ENDIF} procedure ShowX11Message(const aMessage : string); {$ENDIF}{$ENDIF} @@ -74,6 +81,7 @@ uses {$ELSE} SysUtils, {$ENDIF} + {$IFDEF LCLGTK3}gtk3widgets,{$ENDIF} uCEFLinuxConstants, uCEFConstants; {$IFDEF LINUX} @@ -657,6 +665,96 @@ begin XCloseDisplay(TempDisplay); end; -{$ENDIF}{$ENDIF} +{$ENDIF} + +{$IFDEF LCLGTK3} +procedure UseDefaultX11VisualForGtk(widget : PGtkWidget); +type + PGdkX11Screen = type PGdkScreen; +var + screen : PGdkScreen; + visuals, cursor : PGList; + x11_screen : PGdkX11Screen; + default_xvisual : PVisual; + visual : PGdkVisual; + + function GDK_X11_VISUAL(obj : pointer) : PGdkVisual; + begin + Result := PGdkVisual(obj); + end; + + function GDK_SCREEN_X11(obj : pointer) : PGdkX11Screen; + begin + GDK_SCREEN_X11 := PGdkX11Screen(obj); + end; + + function GDK_SCREEN_XDISPLAY(screen : PGdkScreen) : PDisplay; + begin + GDK_SCREEN_XDISPLAY := gdk_x11_display_get_xdisplay(gdk_screen_get_display(screen)); + end; + + function GDK_SCREEN_XNUMBER(screen : PGdkScreen) : longint; + begin + GDK_SCREEN_XNUMBER := gdk_x11_screen_get_screen_number(screen); + end; + +begin + // GTK+ > 3.15.1 uses an X11 visual optimized for GTK+'s OpenGL stuff + // since revid dae447728d: https://github.com/GNOME/gtk/commit/dae447728d + // However, it breaks CEF: https://github.com/cztomczak/cefcapi/issues/9 + // Let's use the default X11 visual instead of the GTK's blessed one. + // Copied from: https://github.com/cztomczak/cefcapi. + screen := gdk_screen_get_default(); + visuals := gdk_screen_list_visuals(screen); + x11_screen := GDK_SCREEN_X11(screen); + + if (x11_screen <> nil) then + begin + default_xvisual := DefaultVisual(GDK_SCREEN_XDISPLAY(x11_screen), + GDK_SCREEN_XNUMBER(x11_screen)); + + if (default_xvisual <> nil) then + begin + cursor := visuals; + + while (cursor <> nil) do + begin + visual := GDK_X11_VISUAL(cursor^.data); + + if (default_xvisual^.visualid = gdk_x11_visual_get_xvisual(visual)^.visualid) then + begin + gtk_widget_set_visual(widget, visual); + break; + end; + + cursor := cursor^.next; + end; + end; + end; + + g_list_free(visuals); +end; + +procedure UseDefaultX11VisualForGtk(aHandle : TCefWindowHandle); +begin + UseDefaultX11VisualForGtk(TGtk3Widget(aHandle).Widget); +end; + +procedure FlushDisplay(widget : PGtkWidget); +var + gdk_window : PGdkWindow; + display : PGdkDisplay; +begin + gdk_window := gtk_widget_get_window(widget); + display := gdk_window_get_display(gdk_window); + gdk_display_flush(display); +end; + +procedure FlushDisplay(aHandle : TCefWindowHandle); +begin + FlushDisplay(TGtk3Widget(aHandle).Widget); +end; +{$ENDIF} +{$ENDIF} end. diff --git a/source/uCEFTypes.pas b/source/uCEFTypes.pas index 3bb979fb..0cac6fee 100644 --- a/source/uCEFTypes.pas +++ b/source/uCEFTypes.pas @@ -478,6 +478,31 @@ type /// </summary> gtkVersion4 ); + + /// <summary> + /// Ozone platform implementation type. + /// </summary> + /// <remarks> + /// <para><see href="https://peter.sh/experiments/chromium-command-line-switches/#ozone-platform">Used by the --ozone-platform switch</see></para> + /// </remarks> + TCefOzonePlatform = ( + /// <summary> + /// Default platform. + /// </summary> + ozpDefault, + /// <summary> + /// Wayland platform. + /// </summary> + ozpWayland, + /// <summary> + /// X11 platform. + /// </summary> + ozpX11, + /// <summary> + /// Headless platform. Not supported by CEF. + /// </summary> + ozpHeadless + ); {$ENDIF} /// <summary> diff --git a/source/uCEFWindowInfoWrapper.pas b/source/uCEFWindowInfoWrapper.pas index bdbe8d3a..22afbf26 100644 --- a/source/uCEFWindowInfoWrapper.pas +++ b/source/uCEFWindowInfoWrapper.pas @@ -13,9 +13,9 @@ interface uses {$IFDEF DELPHI16_UP} - {$IFDEF MSWINDOWS}WinApi.Windows,{$ENDIF}System.Classes, System.Types, + {$IFDEF MSWINDOWS}WinApi.Windows,{$ENDIF}System.Classes, System.Types, System.SysUtils, {$ELSE} - {$IFDEF MSWINDOWS}Windows,{$ENDIF}Classes, Types, + {$IFDEF MSWINDOWS}Windows,{$ENDIF}Classes, Types, SysUtils, {$ENDIF} uCEFTypes; @@ -236,7 +236,7 @@ uses {$IFDEF LINUX}{$IFDEF FPC} ctypes, keysym, xf86keysym, x, xlib, {$IFDEF LCLGTK2}gtk2, glib2, gdk2, gtk2proc, gtk2int, Gtk2Def, gdk2x, Gtk2Extra,{$ENDIF} - {$IFDEF LCLGTK3}LazGdk3, LazGtk3, LazGLib2, gtk3widgets,{$ENDIF} + {$IFDEF LCLGTK3}LazGdk3, LazGtk3, LazGLib2, Gtk3Widgets, Gtk3Procs, LazGObject2,{$ENDIF} uCEFLinuxFunctions, {$ENDIF}{$ENDIF} uCEFMiscFunctions; @@ -475,6 +475,9 @@ class procedure TCEFWindowInfoWrapper.AsChild(var aWindowInfo: TCEFWindowInfo; a {$IFDEF LINUX} var TempParent : TCefWindowHandle; + {$IFDEF LCLGTK3} + TempWidget : PGtkWidget; + {$ENDIF} {$ENDIF} begin aWindowInfo.size := SizeOf(TCEFWindowInfo); @@ -499,24 +502,34 @@ begin {$IFDEF FPC} {$IFDEF LCLGTK2} - if ValidCefWindowHandle(aParent) and (PGtkWidget(aParent)^.window <> nil) then - TempParent := gdk_window_xwindow(PGtkWidget(aParent)^.window); + if ValidCefWindowHandle(aParent) then + begin + // This is a translation of the GetXWindowForWidget function found in + // tests/cefclient/browser/browser_window_std_gtk.cc + // That function calls GDK_WINDOW_XID(gtk_widget_get_window(widget)) to get the TempParent value. + + // /usr/include/gtk-2.0/gdk/gdkx.h defines GDK_WINDOW_XID as gdk_x11_drawable_get_xid + // /usr/share/lazarus/4.2.0/lcl/interfaces/gtk2/gtk2extrah.inc renames gdk_x11_drawable_get_xid as gdk_window_xwindow + + // aParent is an LCL Handle which can be casted as a PGtkWidget in GTK2. + TempParent := gdk_window_xwindow(PGtkWidget(aParent)^.window); + end; {$ENDIF} {$IFDEF LCLGTK3} - if ValidCefWindowHandle(aParent) and (TGtk3Widget(aParent).Widget <> nil) then + if ValidCefWindowHandle(aParent) then begin - // cefclient creates the main window with this code in root_window_gtk.cc - // window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL); - // Then if populates window_info with : - // window_info.SetAsChild(GetXWindowForWidget(parent_handle), rect); - // GetXWindowForWidget returns this : - // GDK_WINDOW_XID(gtk_widget_get_window(widget)); - // GDK_WINDOW_XID is a macro equivalent to gdk_x11_drawable_get_xid in gtk2 but - // in gtk3 we use gdk_x11_window_get_xid instead. - // LCL sets TGtk3Widget.Widget to gtk_window_new(GTK_WINDOW_TOPLEVEL) for the main form. - // When we call TChromium.CreateBrowser with the main form as parent we get this error in the console (not in the log) : - // [19140:19166:0604/174851.690766:ERROR:x11_software_bitmap_presenter.cc(144)] XGetWindowAttributes failed for window XXXXXXX - TempParent := gdk_x11_window_get_xid(gtk_widget_get_window(TGtk3Widget(aParent).Widget)); + // This is a translation of the GetXWindowForWidget function found in + // tests/cefclient/browser/browser_window_std_gtk.cc + // That function calls GDK_WINDOW_XID(gtk_widget_get_window(widget)) to get the TempParent value. + + // /usr/include/gtk-3.0/gdk/x11/gdkx11window.h defines GDK_WINDOW_XID as gdk_x11_window_get_xid + + if Gtk3IsWidget(PGObject(aParent)) then + TempWidget := PGtkWidget(aParent) + else + TempWidget := TGtk3Widget(aParent).Widget; // aParent is an LCL Handle which can be casted as a TGtk3Widget in GTK3. + + TempParent := gdk_x11_window_get_xid(gtk_widget_get_window(TempWidget)); end; {$ENDIF} {$ENDIF}