1
0
mirror of https://github.com/salvadordf/CEF4Delphi.git synced 2025-05-23 21:50:21 +02:00

Update to CEF 91.1.21

The TabbedBrowser2 demo for Windows can now open new tabs without losing the POST data.
This commit is contained in:
Salvador Díaz Fau 2021-06-20 13:08:37 +02:00
parent 371c056192
commit b0259524c5
23 changed files with 1796 additions and 1331 deletions

View File

@ -3,15 +3,15 @@ CEF4Delphi is an open source project created by Salvador Díaz Fau to embed Chro
CEF4Delphi is based on DCEF3 and fpCEF3. The original license of those projects still applies to CEF4Delphi. Read the license terms in the first lines of any *.pas file.
CEF4Delphi uses CEF 91.1.20 which includes Chromium 91.0.4472.101.
CEF4Delphi uses CEF 91.1.21 which includes Chromium 91.0.4472.114.
The CEF binaries used by CEF4Delphi are available for download at spotify :
* [Windows 32 bits](https://cef-builds.spotifycdn.com/cef_binary_91.1.20%2Bg5800665%2Bchromium-91.0.4472.101_windows32.tar.bz2)
* [Windows 64 bits](https://cef-builds.spotifycdn.com/cef_binary_91.1.20%2Bg5800665%2Bchromium-91.0.4472.101_windows64.tar.bz2)
* [Linux x86 32 bits](https://cef-builds.spotifycdn.com/cef_binary_91.1.20%2Bg5800665%2Bchromium-91.0.4472.101_linux32.tar.bz2)
* [Linux x86 64 bits](https://cef-builds.spotifycdn.com/cef_binary_91.1.20%2Bg5800665%2Bchromium-91.0.4472.101_linux64.tar.bz2)
* [Linux ARM 32 bits](https://cef-builds.spotifycdn.com/cef_binary_91.1.20%2Bg5800665%2Bchromium-91.0.4472.101_linuxarm.tar.bz2)
* [Linux ARM 64 bits](https://cef-builds.spotifycdn.com/cef_binary_91.1.20%2Bg5800665%2Bchromium-91.0.4472.101_linuxarm64.tar.bz2)
* [MacOS x86 64 bits](https://cef-builds.spotifycdn.com/cef_binary_91.1.20%2Bg5800665%2Bchromium-91.0.4472.101_macosx64.tar.bz2)
* [Windows 32 bits](https://cef-builds.spotifycdn.com/cef_binary_91.1.21%2Bg9dd45fe%2Bchromium-91.0.4472.114_windows32.tar.bz2)
* [Windows 64 bits](https://cef-builds.spotifycdn.com/cef_binary_91.1.21%2Bg9dd45fe%2Bchromium-91.0.4472.114_windows64.tar.bz2)
* [Linux x86 32 bits](https://cef-builds.spotifycdn.com/cef_binary_91.1.21%2Bg9dd45fe%2Bchromium-91.0.4472.114_linux32.tar.bz2)
* [Linux x86 64 bits](https://cef-builds.spotifycdn.com/cef_binary_91.1.21%2Bg9dd45fe%2Bchromium-91.0.4472.114_linux64.tar.bz2)
* [Linux ARM 32 bits](https://cef-builds.spotifycdn.com/cef_binary_91.1.21%2Bg9dd45fe%2Bchromium-91.0.4472.114_linuxarm.tar.bz2)
* [Linux ARM 64 bits](https://cef-builds.spotifycdn.com/cef_binary_91.1.21%2Bg9dd45fe%2Bchromium-91.0.4472.114_linuxarm64.tar.bz2)
* [MacOS x86 64 bits](https://cef-builds.spotifycdn.com/cef_binary_91.1.21%2Bg9dd45fe%2Bchromium-91.0.4472.114_macosx64.tar.bz2)
CEF4Delphi was developed and tested on Delphi 10.4.2 and it has been tested in Delphi 7, Delphi XE, Delphi 10, Delphi 10.2, Delphi 10.3 and Lazarus 2.0.12/FPC 3.2.0. CEF4Delphi includes VCL, FireMonkey (FMX) and Lazarus components.

View File

@ -55,9 +55,11 @@ uses
{$R *.res}
// CEF needs to set the LARGEADDRESSAWARE flag which allows 32-bit processes to use up to 3GB of RAM.
// If you don't add this flag the rederer process will crash when you try to load large images.
{$SetPEFlags IMAGE_FILE_LARGE_ADDRESS_AWARE}
{$IFDEF WIN32}
// CEF needs to set the LARGEADDRESSAWARE flag which allows 32-bit processes to use up to 3GB of RAM.
// If you don't add this flag the rederer process will crash when you try to load large images.
{$SetPEFlags IMAGE_FILE_LARGE_ADDRESS_AWARE}
{$ENDIF}
begin
CreateGlobalCEFApp;

View File

@ -6,7 +6,7 @@
<MainSource>TabbedBrowser2.dpr</MainSource>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Debug</Config>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<Platform Condition="'$(Platform)'==''">Win64</Platform>
<TargetedPlatforms>3</TargetedPlatforms>
<AppType>Application</AppType>
</PropertyGroup>

View File

@ -30,7 +30,6 @@ object BrowserFrame: TBrowserFrame
Top = 5
Width = 25
Height = 25
Align = alLeft
Caption = '3'
Font.Charset = SYMBOL_CHARSET
Font.Color = clWindowText
@ -76,7 +75,6 @@ object BrowserFrame: TBrowserFrame
Top = 5
Width = 25
Height = 25
Align = alRight
Caption = '='
Font.Charset = SYMBOL_CHARSET
Font.Color = clWindowText
@ -95,15 +93,16 @@ object BrowserFrame: TBrowserFrame
Height = 35
Align = alClient
BevelOuter = bvNone
Padding.Top = 7
Padding.Bottom = 10
TabOrder = 1
DesignSize = (
774
35)
object URLCbx: TComboBox
Left = 0
Left = 2
Top = 7
Width = 774
Width = 770
Height = 21
Align = alClient
Anchors = [akLeft, akTop, akRight]
ItemIndex = 0
TabOrder = 0
Text = 'https://www.google.com'
@ -173,17 +172,12 @@ object BrowserFrame: TBrowserFrame
Height = 35
Align = alRight
BevelOuter = bvNone
Padding.Left = 5
Padding.Top = 5
Padding.Right = 5
Padding.Bottom = 5
TabOrder = 2
object GoBtn: TButton
Left = 5
Top = 5
Width = 25
Height = 25
Align = alClient
Caption = #9658
Font.Charset = ANSI_CHARSET
Font.Color = clWindowText

View File

@ -45,15 +45,22 @@ uses
{$IFDEF DELPHI16_UP}
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
Vcl.ExtCtrls, Vcl.ComCtrls, Vcl.StdCtrls,
Vcl.ExtCtrls, Vcl.ComCtrls, Vcl.StdCtrls, System.SyncObjs,
{$ELSE}
Windows, Messages, SysUtils, Variants,
Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, ComCtrls, StdCtrls,
ExtCtrls, ComCtrls, StdCtrls, SyncObjs,
{$ENDIF}
uCEFWinControl, uCEFWindowParent, uCEFChromiumCore, uCEFChromium,
uCEFInterfaces, uCEFTypes, uCEFConstants;
const
CEF_UPDATECAPTION = WM_APP + $A55;
CEF_UPDATEADDRESS = WM_APP + $A56;
CEF_UPDATESTATE = WM_APP + $A57;
CEF_UPDATESTATUSTEXT = WM_APP + $A58;
type
TBrowserTitleEvent = procedure(Sender: TObject; const aTitle : string) of object;
@ -90,24 +97,59 @@ type
procedure GoBtnClick(Sender: TObject);
protected
FCriticalSection : TCriticalSection;
FClosing : boolean; // Indicates that this frame is destroying the browser
FHomepage : string;
FPendingAddress : string;
FPendingTitle : string;
FPendingStatus : string;
FPendingIsLoading : boolean;
FPendingCanGoBack : boolean;
FPendingCanGoForward : boolean;
FOnBrowserDestroyed : TNotifyEvent;
FOnBrowserTitleChange : TBrowserTitleEvent;
function CreateClientHandler(var windowInfo : TCefWindowInfo; var client : ICefClient; const targetFrameName : string; const popupFeatures : TCefPopupFeatures) : boolean;
function GetInitialized : boolean;
function GetPendingAddress : string;
function GetPendingTitle : string;
function GetPendingStatus : string;
function GetPendingIsLoading : boolean;
function GetPendingCanGoBack : boolean;
function GetPendingCanGoForward : boolean;
procedure SetPendingAddress(const aValue : string);
procedure SetPendingTitle(const aValue : string);
procedure SetPendingStatus(const aValue : string);
procedure SetPendingIsLoading(aValue : boolean);
procedure SetPendingCanGoBack(aValue : boolean);
procedure SetPendingCanGoForward(aValue : boolean);
procedure BrowserCreatedMsg(var aMessage : TMessage); message CEF_AFTERCREATED;
procedure BrowserDestroyMsg(var aMessage : TMessage); message CEF_DESTROY;
procedure BrowserUpdateCaptionMsg(var aMessage : TMessage); message CEF_UPDATECAPTION;
procedure BrowserUpdateAddressMsg(var aMessage : TMessage); message CEF_UPDATEADDRESS;
procedure BrowserUpdateStateMsg(var aMessage : TMessage); message CEF_UPDATESTATE;
procedure BrowserUpdateStatusTextMsg(var aMessage : TMessage); message CEF_UPDATESTATUSTEXT;
property PendingAddress : string read GetPendingAddress write SetPendingAddress;
property PendingTitle : string read GetPendingTitle write SetPendingTitle;
property PendingStatus : string read GetPendingStatus write SetPendingStatus;
property PendingIsLoading : boolean read GetPendingIsLoading write SetPendingIsLoading;
property PendingCanGoBack : boolean read GetPendingCanGoBack write SetPendingCanGoBack;
property PendingCanGoForward : boolean read GetPendingCanGoForward write SetPendingCanGoForward;
public
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
procedure NotifyMoveOrResizeStarted;
procedure CreateAllHandles;
procedure CreateBrowser;
procedure CloseBrowser;
procedure ShowBrowser;
procedure HideBrowser;
function CreateClientHandler(var windowInfo : TCefWindowInfo; var client : ICefClient; const targetFrameName : string; const popupFeatures : TCefPopupFeatures) : boolean;
property Initialized : boolean read GetInitialized;
property Closing : boolean read FClosing;
property Homepage : string read FHomepage write FHomepage;
property OnBrowserDestroyed : TNotifyEvent read FOnBrowserDestroyed write FOnBrowserDestroyed;
@ -119,18 +161,137 @@ implementation
{$R *.dfm}
uses
uBrowserTab;
uCEFMiscFunctions, uBrowserTab;
// The TChromium events are executed in a CEF thread and we should only update the
// GUI controls in the main application thread.
// This demo saves all the information in those events using a synchronization
// object and sends a custom message to update the GUI in the main application thread.
// Destruction steps
// =================
// 1. TBrowserFrame.CloseBrowser sets CanClose to FALSE calls TChromium.CloseBrowser
// which triggers the TChromium.OnClose event.
// 2. TChromium.OnClose sends a CEFBROWSER_DESTROY message to destroy CEFWindowParent1
// in the main thread, which triggers the TChromium.OnBeforeClose event.
// 3. TChromium.OnBeforeClose triggers the TBrowserFrame.OnBrowserDestroyed event
// which sends a CEF_DESTROYTAB message with the TabID to the main form.
constructor TBrowserFrame.Create(AOwner : TComponent);
begin
inherited Create(AOwner);
FCriticalSection := TCriticalSection.Create;
FClosing := False;
FHomepage := '';
FOnBrowserDestroyed := nil;
FOnBrowserTitleChange := nil;
end;
destructor TBrowserFrame.Destroy;
begin
FreeAndNil(FCriticalSection);
inherited Destroy;
end;
procedure TBrowserFrame.CreateAllHandles;
begin
CreateHandle;
CEFWindowParent1.CreateHandle;
end;
function TBrowserFrame.GetInitialized : boolean;
begin
Result := Chromium1.Initialized;
end;
function TBrowserFrame.GetPendingAddress : string;
begin
FCriticalSection.Acquire;
Result := FPendingAddress;
FCriticalSection.Release;
end;
function TBrowserFrame.GetPendingTitle : string;
begin
FCriticalSection.Acquire;
Result := FPendingTitle;
FCriticalSection.Release;
end;
function TBrowserFrame.GetPendingStatus : string;
begin
FCriticalSection.Acquire;
Result := FPendingStatus;
FCriticalSection.Release;
end;
function TBrowserFrame.GetPendingIsLoading : boolean;
begin
FCriticalSection.Acquire;
Result := FPendingIsLoading;
FCriticalSection.Release;
end;
function TBrowserFrame.GetPendingCanGoBack : boolean;
begin
FCriticalSection.Acquire;
Result := FPendingCanGoBack;
FCriticalSection.Release;
end;
function TBrowserFrame.GetPendingCanGoForward : boolean;
begin
FCriticalSection.Acquire;
Result := FPendingCanGoForward;
FCriticalSection.Release;
end;
procedure TBrowserFrame.SetPendingAddress(const aValue : string);
begin
FCriticalSection.Acquire;
FPendingAddress := aValue;
FCriticalSection.Release;
end;
procedure TBrowserFrame.SetPendingTitle(const aValue : string);
begin
FCriticalSection.Acquire;
FPendingTitle := aValue;
FCriticalSection.Release;
end;
procedure TBrowserFrame.SetPendingStatus(const aValue : string);
begin
FCriticalSection.Acquire;
FPendingStatus := aValue;
FCriticalSection.Release;
end;
procedure TBrowserFrame.SetPendingIsLoading(aValue : boolean);
begin
FCriticalSection.Acquire;
FPendingIsLoading := aValue;
FCriticalSection.Release;
end;
procedure TBrowserFrame.SetPendingCanGoBack(aValue : boolean);
begin
FCriticalSection.Acquire;
FPendingCanGoBack := aValue;
FCriticalSection.Release;
end;
procedure TBrowserFrame.SetPendingCanGoForward(aValue : boolean);
begin
FCriticalSection.Acquire;
FPendingCanGoForward := aValue;
FCriticalSection.Release;
end;
procedure TBrowserFrame.NotifyMoveOrResizeStarted;
begin
Chromium1.NotifyMoveOrResizeStarted;
@ -201,9 +362,8 @@ procedure TBrowserFrame.Chromium1AddressChange( Sender : TObject;
const frame : ICefFrame;
const url : ustring);
begin
if (URLCbx.Items.IndexOf(url) < 0) then URLCbx.Items.Add(url);
URLCbx.Text := url;
PendingAddress := url;
PostMessage(Handle, CEF_UPDATEADDRESS, 0, 0);
end;
procedure TBrowserFrame.Chromium1BeforeClose(Sender: TObject; const browser: ICefBrowser);
@ -226,15 +386,9 @@ procedure TBrowserFrame.Chromium1BeforePopup( Sender : TObject;
var noJavascriptAccess : Boolean;
var Result : Boolean);
begin
case targetDisposition of
WOD_NEW_FOREGROUND_TAB,
WOD_NEW_BACKGROUND_TAB,
WOD_NEW_WINDOW : Result := True; // For simplicity, this demo blocks new tabs and new windows.
WOD_NEW_POPUP : Result := not(CreateClientHandler(windowInfo, client, targetFrameName, popupFeatures));
else Result := False;
end;
Result := not(assigned(Parent) and
(Parent is TBrowserTab) and
TBrowserTab(Parent).DoOnBeforePopup(windowInfo, client, targetFrameName, popupFeatures, targetDisposition));
end;
procedure TBrowserFrame.Chromium1OpenUrlFromTab( Sender : TObject;
@ -245,7 +399,9 @@ procedure TBrowserFrame.Chromium1OpenUrlFromTab( Sender : TObjec
userGesture : Boolean;
out Result : Boolean);
begin
Result := (targetDisposition in [WOD_NEW_FOREGROUND_TAB, WOD_NEW_BACKGROUND_TAB, WOD_NEW_POPUP, WOD_NEW_WINDOW]);
Result := assigned(Parent) and
(Parent is TBrowserTab) and
TBrowserTab(Parent).DoOpenUrlFromTab(targetUrl, targetDisposition);
end;
procedure TBrowserFrame.Chromium1Close( Sender : TObject;
@ -281,38 +437,32 @@ procedure TBrowserFrame.Chromium1LoadingStateChange( Sender : TObject
canGoBack : Boolean;
canGoForward : Boolean);
begin
BackBtn.Enabled := canGoBack;
ForwardBtn.Enabled := canGoForward;
PendingIsLoading := isLoading;
PendingCanGoBack := canGoBack;
PendingCanGoForward := canGoForward;
if isLoading then
begin
ReloadBtn.Enabled := False;
StopBtn.Enabled := True;
end
else
begin
ReloadBtn.Enabled := True;
StopBtn.Enabled := False;
end;
PostMessage(Handle, CEF_UPDATESTATE, 0, 0);
end;
procedure TBrowserFrame.Chromium1StatusMessage( Sender : TObject;
const browser : ICefBrowser;
const value : ustring);
begin
StatusBar1.Panels[0].Text := value;
PendingStatus := value;
PostMessage(Handle, CEF_UPDATESTATUSTEXT, 0, 0);
end;
procedure TBrowserFrame.Chromium1TitleChange( Sender : TObject;
const browser : ICefBrowser;
const title : ustring);
begin
if not(assigned(FOnBrowserTitleChange)) then exit;
if (length(title) > 0) then
FOnBrowserTitleChange(self, title)
PendingTitle := title
else
FOnBrowserTitleChange(self, Chromium1.DocumentURL);
PendingTitle := Chromium1.DocumentURL;
PostMessage(Handle, CEF_UPDATECAPTION, 0, 0);
end;
procedure TBrowserFrame.BrowserCreatedMsg(var aMessage : TMessage);
@ -326,14 +476,63 @@ begin
CEFWindowParent1.Free;
end;
function TBrowserFrame.CreateClientHandler(var windowInfo : TCefWindowInfo;
var client : ICefClient;
const targetFrameName : string;
const popupFeatures : TCefPopupFeatures) : boolean;
procedure TBrowserFrame.BrowserUpdateCaptionMsg(var aMessage : TMessage);
begin
Result := assigned(Parent) and
(Parent is TBrowserTab) and
TBrowserTab(Parent).CreateClientHandler(windowInfo, client, targetFrameName, popupFeatures);
if assigned(FOnBrowserTitleChange) then
FOnBrowserTitleChange(self, PendingTitle);
end;
procedure TBrowserFrame.BrowserUpdateAddressMsg(var aMessage : TMessage);
var
TempAddress : string;
begin
TempAddress := PendingAddress;
if (URLCbx.Items.IndexOf(TempAddress) < 0) then
URLCbx.Items.Add(TempAddress);
URLCbx.Text := TempAddress;
end;
procedure TBrowserFrame.BrowserUpdateStateMsg(var aMessage : TMessage);
begin
BackBtn.Enabled := PendingCanGoBack;
ForwardBtn.Enabled := PendingCanGoForward;
if PendingIsLoading then
begin
ReloadBtn.Enabled := False;
StopBtn.Enabled := True;
end
else
begin
ReloadBtn.Enabled := True;
StopBtn.Enabled := False;
end;
end;
procedure TBrowserFrame.BrowserUpdateStatusTextMsg(var aMessage : TMessage);
begin
StatusBar1.Panels[0].Text := PendingStatus;
end;
function TBrowserFrame.CreateClientHandler(var windowInfo : TCefWindowInfo;
var client : ICefClient;
const targetFrameName : string;
const popupFeatures : TCefPopupFeatures) : boolean;
var
TempRect : TRect;
begin
if CEFWindowParent1.HandleAllocated and
Chromium1.CreateClientHandler(client, False) then
begin
Result := True;
TempRect := CEFWindowParent1.ClientRect;
WindowInfoAsChild(windowInfo, CEFWindowParent1.Handle, TempRect, '');
end
else
Result := False;
end;
end.

View File

@ -44,10 +44,10 @@ interface
uses
{$IFDEF DELPHI16_UP}
Winapi.Windows, System.Classes, Winapi.Messages, Vcl.ComCtrls, Vcl.Controls,
Vcl.Forms,
Vcl.Forms, System.SysUtils,
{$ELSE}
Windows, Classes, Messages, ComCtrls, Controls,
Forms,
Forms, SysUtils,
{$ENDIF}
uCEFInterfaces, uCEFTypes, uBrowserFrame;
@ -58,6 +58,8 @@ type
FTabID : cardinal;
function GetParentForm : TCustomForm;
function GetInitialized : boolean;
function GetClosing : boolean;
function PostFormMessage(aMsg : cardinal; aWParam : WPARAM = 0; aLParam : LPARAM = 0) : boolean;
@ -69,13 +71,18 @@ type
public
constructor Create(AOwner: TComponent; aTabID : cardinal; const aCaption : string); reintroduce;
procedure NotifyMoveOrResizeStarted;
procedure CreateFrame(const aHomepage : string = '');
procedure CreateBrowser(const aHomepage : string);
procedure CloseBrowser;
procedure ShowBrowser;
procedure HideBrowser;
function CreateClientHandler(var windowInfo : TCefWindowInfo; var client : ICefClient; const targetFrameName : string; const popupFeatures : TCefPopupFeatures) : boolean;
function DoOnBeforePopup(var windowInfo : TCefWindowInfo; var client : ICefClient; const targetFrameName : string; const popupFeatures : TCefPopupFeatures; targetDisposition : TCefWindowOpenDisposition) : boolean;
function DoOpenUrlFromTab(const targetUrl : string; targetDisposition : TCefWindowOpenDisposition) : boolean;
property TabID : cardinal read FTabID;
property TabID : cardinal read FTabID;
property Closing : boolean read GetClosing;
property Initialized : boolean read GetInitialized;
end;
implementation
@ -107,6 +114,18 @@ begin
Result := nil;
end;
function TBrowserTab.GetInitialized : boolean;
begin
Result := (FBrowserFrame <> nil) and
FBrowserFrame.Initialized;
end;
function TBrowserTab.GetClosing : boolean;
begin
Result := (FBrowserFrame <> nil) and
FBrowserFrame.Closing;
end;
function TBrowserTab.PostFormMessage(aMsg : cardinal; aWParam : WPARAM; aLParam : LPARAM) : boolean;
var
TempForm : TCustomForm;
@ -122,17 +141,28 @@ begin
FBrowserFrame.NotifyMoveOrResizeStarted;
end;
procedure TBrowserTab.CreateFrame(const aHomepage : string);
begin
if (FBrowserFrame = nil) then
begin
FBrowserFrame := TBrowserFrame.Create(self);
FBrowserFrame.Name := 'BrowserFrame' + IntToStr(TabID);
FBrowserFrame.Parent := self;
FBrowserFrame.Align := alClient;
FBrowserFrame.Visible := True;
FBrowserFrame.OnBrowserDestroyed := BrowserFrame_OnBrowserDestroyed;
FBrowserFrame.OnBrowserTitleChange := BrowserFrame_OnBrowserTitleChange;
FBrowserFrame.CreateAllHandles;
end;
FBrowserFrame.Homepage := aHomepage;
end;
procedure TBrowserTab.CreateBrowser(const aHomepage : string);
begin
FBrowserFrame := TBrowserFrame.Create(self);
FBrowserFrame.Parent := self;
FBrowserFrame.Align := alClient;
FBrowserFrame.Visible := True;
FBrowserFrame.Homepage := aHomepage;
FBrowserFrame.OnBrowserDestroyed := BrowserFrame_OnBrowserDestroyed;
FBrowserFrame.OnBrowserTitleChange := BrowserFrame_OnBrowserTitleChange;
CreateFrame(aHomepage);
FBrowserFrame.CreateBrowser;
if (FBrowserFrame <> nil) then FBrowserFrame.CreateBrowser;
end;
procedure TBrowserTab.CloseBrowser;
@ -162,17 +192,38 @@ begin
Caption := aTitle;
end;
function TBrowserTab.CreateClientHandler(var windowInfo : TCefWindowInfo;
var client : ICefClient;
const targetFrameName : string;
const popupFeatures : TCefPopupFeatures) : boolean;
function TBrowserTab.CreateClientHandler(var windowInfo : TCefWindowInfo;
var client : ICefClient;
const targetFrameName : string;
const popupFeatures : TCefPopupFeatures) : boolean;
begin
Result := (FBrowserFrame <> nil) and
FBrowserFrame.CreateClientHandler(windowInfo, client, targetFrameName, popupFeatures);
end;
function TBrowserTab.DoOnBeforePopup(var windowInfo : TCefWindowInfo;
var client : ICefClient;
const targetFrameName : string;
const popupFeatures : TCefPopupFeatures;
targetDisposition : TCefWindowOpenDisposition) : boolean;
var
TempForm : TCustomForm;
begin
TempForm := ParentForm;
Result := (TempForm <> nil) and
(TempForm is TMainForm) and
TMainForm(TempForm).CreateClientHandler(windowInfo, client, targetFrameName, popupFeatures);
TMainForm(TempForm).DoOnBeforePopup(windowInfo, client, targetFrameName, popupFeatures, targetDisposition);
end;
function TBrowserTab.DoOpenUrlFromTab(const targetUrl : string;
targetDisposition : TCefWindowOpenDisposition) : boolean;
var
TempForm : TCustomForm;
begin
TempForm := ParentForm;
Result := (TempForm <> nil) and
(TempForm is TMainForm) and
TMainForm(TempForm).DoOpenUrlFromTab(targetUrl, targetDisposition);
end;
end.

View File

@ -29,8 +29,10 @@ object ChildForm: TChildForm
object Chromium1: TChromium
OnTitleChange = Chromium1TitleChange
OnBeforePopup = Chromium1BeforePopup
OnAfterCreated = Chromium1AfterCreated
OnBeforeClose = Chromium1BeforeClose
OnClose = Chromium1Close
OnOpenUrlFromTab = Chromium1OpenUrlFromTab
Left = 24
Top = 56
end

View File

@ -53,6 +53,9 @@ uses
uCEFChromium, uCEFTypes, uCEFInterfaces, uCEFConstants, uCEFWindowParent, uCEFWinControl,
uCEFChromiumCore;
const
CEF_UPDATECAPTION = WM_APP + $A55;
type
TChildForm = class(TForm)
Chromium1: TChromium;
@ -63,30 +66,38 @@ type
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure Chromium1AfterCreated(Sender: TObject; const browser: ICefBrowser);
procedure Chromium1BeforePopup(Sender: TObject; const browser: ICefBrowser; const frame: ICefFrame; 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: Boolean; var Result: Boolean);
procedure Chromium1TitleChange(Sender: TObject; const browser: ICefBrowser; const title: ustring);
procedure Chromium1Close(Sender: TObject; const browser: ICefBrowser; var aAction : TCefCloseBrowserAction);
procedure Chromium1BeforeClose(Sender: TObject; const browser: ICefBrowser);
procedure Chromium1OpenUrlFromTab(Sender: TObject; const browser: ICefBrowser; const frame: ICefFrame; const targetUrl: ustring; targetDisposition: TCefWindowOpenDisposition; userGesture: Boolean; out Result: Boolean);
protected
FCriticalSection : TCriticalSection;
FCanClose : boolean;
FClosing : boolean;
FClientInitialized : boolean;
FBrowserWasCreated : boolean;
FTitle : string;
FPopupFeatures : TCefPopupFeatures;
function GetInitialized : boolean;
procedure WMMove(var aMessage : TWMMove); message WM_MOVE;
procedure WMMoving(var aMessage : TMessage); message WM_MOVING;
procedure WMEnterMenuLoop(var aMessage: TMessage); message WM_ENTERMENULOOP;
procedure WMExitMenuLoop(var aMessage: TMessage); message WM_EXITMENULOOP;
procedure BrowserDestroyMsg(var aMessage : TMessage); message CEF_DESTROY;
procedure BrowserUpdateCaptionMsg(var aMessage : TMessage); message CEF_UPDATECAPTION;
public
procedure AfterConstruction; override;
function CreateBrowser(const aHomepage : string) : boolean;
function CreateClientHandler(var windowInfo : TCefWindowInfo; var client : ICefClient; const targetFrameName : string; const popupFeatures : TCefPopupFeatures) : boolean;
procedure ApplyPopupFeatures;
property ClientInitialized : boolean read FClientInitialized;
property Closing : boolean read FClosing;
property Initialized : boolean read GetInitialized;
property Closing : boolean read FClosing;
end;
implementation
@ -103,8 +114,10 @@ uses
// Destruction steps
// =================
// 1. FormCloseQuery sets CanClose to FALSE calls TChromium.CloseBrowser which triggers the TChromium.OnClose event.
// 2. TChromium.OnClose sends a CEFBROWSER_DESTROY message to destroy CEFWindowParent1 in the main thread, which triggers the TChromium.OnBeforeClose event.
// 1. FormCloseQuery sets CanClose to FALSE calls TChromium.CloseBrowser which
// triggers the TChromium.OnClose event.
// 2. TChromium.OnClose sends a CEFBROWSER_DESTROY message to destroy CEFWindowParent1
// in the main thread, which triggers the TChromium.OnBeforeClose event.
// 3. TChromium.OnBeforeClose sets FCanClose := True and sends WM_CLOSE to the form.
procedure TChildForm.AfterConstruction;
@ -126,10 +139,9 @@ begin
if CEFWindowParent1.HandleAllocated and
Chromium1.CreateClientHandler(client, False) then
begin
Result := True;
FClientInitialized := True;
FPopupFeatures := popupFeatures;
TempRect := CEFWindowParent1.ClientRect;
Result := True;
FPopupFeatures := popupFeatures;
TempRect := CEFWindowParent1.ClientRect;
if (FPopupFeatures.widthset <> 0) then TempRect.Right := max(FPopupFeatures.width, 100);
if (FPopupFeatures.heightset <> 0) then TempRect.Bottom := max(FPopupFeatures.height, 100);
@ -140,6 +152,12 @@ begin
Result := False;
end;
function TChildForm.CreateBrowser(const aHomepage : string) : boolean;
begin
Chromium1.DefaultURL := aHomepage;
Result := Chromium1.CreateBrowser(CEFWindowParent1);
end;
procedure TChildForm.ApplyPopupFeatures;
begin
if (FPopupFeatures.xset <> 0) then Chromium1.SetFormLeftTo(FPopupFeatures.x);
@ -148,13 +166,18 @@ begin
if (FPopupFeatures.heightset <> 0) then Chromium1.ResizeFormHeightTo(FPopupFeatures.height);
end;
procedure TChildForm.Chromium1AfterCreated(Sender: TObject; const browser: ICefBrowser);
begin
FBrowserWasCreated := True;
end;
procedure TChildForm.Chromium1BeforeClose(Sender: TObject; const browser: ICefBrowser);
begin
FCanClose := True;
PostMessage(Handle, WM_CLOSE, 0, 0);
end;
procedure TChildForm.Chromium1BeforePopup(Sender : TObject;
procedure TChildForm.Chromium1BeforePopup( Sender : TObject;
const browser : ICefBrowser;
const frame : ICefFrame;
const targetUrl : ustring;
@ -169,15 +192,18 @@ procedure TChildForm.Chromium1BeforePopup(Sender : TObject;
var noJavascriptAccess : Boolean;
var Result : Boolean);
begin
case targetDisposition of
WOD_NEW_FOREGROUND_TAB,
WOD_NEW_BACKGROUND_TAB,
WOD_NEW_WINDOW : Result := True; // For simplicity, this demo blocks new tabs and new windows.
Result := not(TMainForm(Owner).DoOnBeforePopup(windowInfo, client, targetFrameName, popupFeatures, targetDisposition));
end;
WOD_NEW_POPUP : Result := not(TMainForm(Owner).CreateClientHandler(windowInfo, client, targetFrameName, popupFeatures));
else Result := False;
end;
procedure TChildForm.Chromium1OpenUrlFromTab( Sender : TObject;
const browser : ICefBrowser;
const frame : ICefFrame;
const targetUrl : ustring;
targetDisposition : TCefWindowOpenDisposition;
userGesture : Boolean;
out Result : Boolean);
begin
Result := not(TMainForm(Owner).DoOpenUrlFromTab(targetUrl, targetDisposition));
end;
procedure TChildForm.Chromium1Close(Sender: TObject; const browser: ICefBrowser; var aAction : TCefCloseBrowserAction);
@ -188,7 +214,18 @@ end;
procedure TChildForm.Chromium1TitleChange(Sender: TObject; const browser: ICefBrowser; const title: ustring);
begin
Caption := title;
try
FCriticalSection.Acquire;
FTitle := title;
finally
FCriticalSection.Release;
PostMessage(Handle, CEF_UPDATECAPTION, 0, 0);
end;
end;
function TChildForm.GetInitialized : boolean;
begin
Result := Chromium1.Initialized;
end;
procedure TChildForm.WMMove(var aMessage : TWMMove);
@ -226,26 +263,34 @@ end;
procedure TChildForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
CanClose := FCanClose;
if not(FClosing) then
if FBrowserWasCreated then
begin
FClosing := True;
Visible := False;
Chromium1.CloseBrowser(True);
end;
CanClose := FCanClose;
if not(FClosing) then
begin
FClosing := True;
Visible := False;
Chromium1.CloseBrowser(True);
end;
end
else
CanClose := True;
end;
procedure TChildForm.FormCreate(Sender: TObject);
begin
FCriticalSection := TCriticalSection.Create;
FBrowserWasCreated := False;
FCanClose := False;
FClosing := False;
FClientInitialized := False;
end;
procedure TChildForm.FormDestroy(Sender: TObject);
begin
if FClientInitialized and TMainForm(Owner).HandleAllocated then
FCriticalSection.Free;
if FBrowserWasCreated and TMainForm(Owner).HandleAllocated then
PostMessage(TMainForm(Owner).Handle, CEF_CHILDDESTROYED, 0, 0);
end;
@ -254,4 +299,14 @@ begin
CEFWindowParent1.Free;
end;
procedure TChildForm.BrowserUpdateCaptionMsg(var aMessage : TMessage);
begin
try
FCriticalSection.Acquire;
Caption := FTitle;
finally
FCriticalSection.Release;
end;
end;
end.

View File

@ -25,6 +25,7 @@ object MainForm: TMainForm
Height = 703
Align = alClient
TabOrder = 0
TabWidth = 150
end
object ButtonPnl: TPanel
Left = 0
@ -39,15 +40,11 @@ object MainForm: TMainForm
Padding.Right = 3
Padding.Bottom = 3
TabOrder = 1
DesignSize = (
32
703)
object AddTabBtn: TSpeedButton
Left = 3
Top = 3
Width = 26
Height = 26
Align = alTop
Caption = '+'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
@ -56,14 +53,12 @@ object MainForm: TMainForm
Font.Style = []
ParentFont = False
OnClick = AddTabBtnClick
ExplicitWidth = 27
end
object RemoveTabBtn: TSpeedButton
Left = 3
Top = 32
Width = 26
Height = 26
Anchors = [akLeft, akTop, akRight]
Caption = #8722
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText

View File

@ -49,13 +49,14 @@ uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, SyncObjs,
Controls, Forms, Dialogs, ComCtrls, ToolWin, Buttons, ExtCtrls,
{$ENDIF}
uCEFApplication, uCEFInterfaces, uCEFTypes, uCEFConstants, uChildForm;
uCEFApplication, uCEFInterfaces, uCEFTypes, uCEFConstants, uChildForm, uBrowserTab;
const
CEF_INITIALIZED = WM_APP + $A50;
CEF_DESTROYTAB = WM_APP + $A51;
CEF_CREATENEXTCHILD = WM_APP + $A52;
CEF_CHILDDESTROYED = WM_APP + $A53;
CEF_INITIALIZED = WM_APP + $A50;
CEF_DESTROYTAB = WM_APP + $A51;
CEF_CREATENEXTCHILD = WM_APP + $A52;
CEF_CREATENEXTTAB = WM_APP + $A53;
CEF_CHILDDESTROYED = WM_APP + $A54;
HOMEPAGE_URL = 'https://www.google.com';
DEFAULT_TAB_CAPTION = 'New tab';
@ -76,33 +77,41 @@ type
procedure FormDestroy(Sender: TObject);
protected
FHiddenTab : TBrowserTab;
FChildForm : TChildForm;
FCriticalSection : TCriticalSection;
FCanClose : boolean;
FClosing : boolean; // Set to True in the CloseQuery event.
FLastTabID : cardinal; // Used by NextTabID to generate unique tab IDs
FPendingURL : string;
function GetNextTabID : cardinal;
function GetPopupChildCount : integer;
function GetBrowserTabCount : integer;
procedure EnableButtonPnl;
function CloseAllBrowsers : boolean;
procedure CloseTab(aIndex : integer);
procedure CreateHiddenBrowsers;
procedure CEFInitializedMsg(var aMessage : TMessage); message CEF_INITIALIZED;
procedure DestroyTabMsg(var aMessage : TMessage); message CEF_DESTROYTAB;
procedure CreateNextChildMsg(var aMessage : TMessage); message CEF_CREATENEXTCHILD;
procedure CreateNextTabMsg(var aMessage : TMessage); message CEF_CREATENEXTTAB;
procedure ChildDestroyedMsg(var aMessage : TMessage); message CEF_CHILDDESTROYED;
procedure WMMove(var aMessage : TWMMove); message WM_MOVE;
procedure WMMoving(var aMessage : TMessage); message WM_MOVING;
procedure WMEnterMenuLoop(var aMessage: TMessage); message WM_ENTERMENULOOP;
procedure WMExitMenuLoop(var aMessage: TMessage); message WM_EXITMENULOOP;
procedure WMQueryEndSession(var aMessage: TWMQueryEndSession); message WM_QUERYENDSESSION;
property NextTabID : cardinal read GetNextTabID;
property PopupChildCount : integer read GetPopupChildCount;
property BrowserTabCount : integer read GetBrowserTabCount;
public
function CreateClientHandler(var windowInfo : TCefWindowInfo; var client : ICefClient; const targetFrameName : string; const popupFeatures : TCefPopupFeatures) : boolean;
function DoOnBeforePopup(var windowInfo : TCefWindowInfo; var client : ICefClient; const targetFrameName : string; const popupFeatures : TCefPopupFeatures; targetDisposition : TCefWindowOpenDisposition) : boolean;
function DoOpenUrlFromTab(const targetUrl : string; targetDisposition : TCefWindowOpenDisposition) : boolean;
end;
var
@ -114,8 +123,6 @@ implementation
{$R *.dfm}
uses
uBrowserTab;
// This demo shows how to use a TPageControl with TFrames that include
// CEF4Delphi browsers.
@ -146,6 +153,24 @@ uses
// the PopupBrowser2 demo. Please, read the code comments in that demo for all
// details about handling the custom child forms.
// Additionally, this demo also creates new tabs when a browser triggers the
// TChromium.OnBeforePopup event.
// VCL components *MUST* be created and destroyed in the main thread but CEF
// executes the TChromium.OnBeforePopup in a different thread.
// For this reason this demo creates a hidden popup form (TChildForm) and a
// hidden TBrowserTab in case CEF needs to show a popup window.
// TChromium.OnBeforePopup calls TMainForm.DoOnBeforePopup to handle all the
// events in the same place.
// TMainForm.DoOnBeforePopup will call CreateClientHandler to initialize some
// parameters and create the new ICefClient using the hidden form or tab.
// After that, it sends a custom message to show the popup form or tab and create
// a new one.
// To close safely this demo you must close all the browser tabs first following
// this steps :
//
@ -167,7 +192,12 @@ procedure CreateGlobalCEFApp;
begin
GlobalCEFApp := TCefApplication.Create;
GlobalCEFApp.cache := 'cache';
GlobalCEFApp.EnablePrintPreview := True;
GlobalCEFApp.OnContextInitialized := GlobalCEFApp_OnContextInitialized;
// This is a workaround for the CEF4Delphi issue #324 :
// https://github.com/salvadordf/CEF4Delphi/issues/324
GlobalCEFApp.DisableFeatures := 'WinUseBrowserSpellChecker';
end;
procedure TMainForm.EnableButtonPnl;
@ -177,7 +207,7 @@ begin
ButtonPnl.Enabled := True;
Caption := 'Tabbed Browser 2';
cursor := crDefault;
if (BrowserPageCtrl.PageCount = 0) then AddTabBtn.Click;
if (BrowserTabCount = 0) then AddTabBtn.Click;
end;
end;
@ -197,12 +227,28 @@ begin
while (i >= 0) do
begin
TempForm := screen.CustomForms[i];
// Only count the fully initialized child forms and not the one waiting to be used.
TempForm := screen.CustomForms[i];
if (TempForm is TChildForm) and
TChildForm(TempForm).ClientInitialized then
TChildForm(TempForm).Initialized then
inc(Result);
dec(i);
end;
end;
function TMainForm.GetBrowserTabCount : integer;
var
i : integer;
begin
Result := 0;
i := pred(BrowserPageCtrl.PageCount);
while (i >= 0) do
begin
// Only count the fully initialized browser tabs and not the one waiting to be used.
if TBrowserTab(BrowserPageCtrl.Pages[i]).Initialized then
inc(Result);
dec(i);
@ -224,9 +270,7 @@ end;
procedure TMainForm.CEFInitializedMsg(var aMessage : TMessage);
begin
EnableButtonPnl;
if (FChildForm = nil) then
TChildForm.Create(self);
CreateHiddenBrowsers;
end;
procedure TMainForm.DestroyTabMsg(var aMessage : TMessage);
@ -234,6 +278,8 @@ var
i : integer;
TempTab : TBrowserTab;
begin
// Every tab sends a CEF_DESTROYTAB message when its browser has been destroyed
// and then we can destroy the TBrowserTab control.
i := 0;
while (i < BrowserPageCtrl.PageCount) do
begin
@ -248,7 +294,9 @@ begin
inc(i);
end;
if FClosing and (PopupChildCount = 0) and (BrowserPageCtrl.PageCount = 0) then
// Here we check if this was the last initialized browser to close the
// application safely.
if FClosing and (PopupChildCount = 0) and (BrowserTabCount = 0) then
begin
FCanClose := True;
PostMessage(Handle, WM_CLOSE, 0, 0);
@ -257,7 +305,10 @@ end;
procedure TMainForm.ChildDestroyedMsg(var aMessage : TMessage);
begin
if FClosing and (PopupChildCount = 0) and (BrowserPageCtrl.PageCount = 0) then
// Every destroyed child form sends a CEF_CHILDDESTROYED message
// Here we check if this was the last initialized browser to close the
// application safely.
if FClosing and (PopupChildCount = 0) and (BrowserTabCount = 0) then
begin
FCanClose := True;
PostMessage(Handle, WM_CLOSE, 0, 0);
@ -271,7 +322,12 @@ begin
if (FChildForm <> nil) then
begin
FChildForm.ApplyPopupFeatures;
if (aMessage.lParam <> 0) then
FChildForm.CreateBrowser(FPendingURL)
else
FChildForm.ApplyPopupFeatures;
FChildForm.Show;
end;
@ -281,6 +337,31 @@ begin
end;
end;
procedure TMainForm.CreateNextTabMsg(var aMessage : TMessage);
begin
try
FCriticalSection.Acquire;
if (FHiddenTab <> nil) then
begin
FHiddenTab.TabVisible := True;
FHiddenTab.PageIndex := pred(BrowserPageCtrl.PageCount);
if (aMessage.lParam <> 0) then
FHiddenTab.CreateBrowser(FPendingURL);
BrowserPageCtrl.ActivePageIndex := FHiddenTab.PageIndex;
end;
FHiddenTab := TBrowserTab.Create(self, NextTabID, DEFAULT_TAB_CAPTION);
FHiddenTab.PageControl := BrowserPageCtrl;
FHiddenTab.TabVisible := False;
FHiddenTab.CreateFrame;
finally
FCriticalSection.Release;
end;
end;
procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
CanClose := FCanClose;
@ -304,6 +385,7 @@ begin
FClosing := False;
FLastTabID := 0;
FChildForm := nil;
FHiddenTab := nil;
FCriticalSection := TCriticalSection.Create;
end;
@ -317,14 +399,13 @@ begin
if (GlobalCEFApp <> nil) and GlobalCEFApp.GlobalContextInitialized then
begin
EnableButtonPnl;
if (FChildForm = nil) then
FChildForm := TChildForm.Create(self);
CreateHiddenBrowsers;
end;
end;
procedure TMainForm.RemoveTabBtnClick(Sender: TObject);
begin
// Call TBrowserTab.CloseBrowser in the active tab
CloseTab(BrowserPageCtrl.ActivePageIndex);
end;
@ -332,16 +413,16 @@ function TMainForm.CloseAllBrowsers : boolean;
var
i : integer;
TempForm : TCustomForm;
TempTab : TBrowserTab;
begin
Result := False;
i := pred(screen.CustomFormCount);
while (i >= 0) do
begin
TempForm := screen.CustomForms[i];
if (TempForm is TChildForm) and
TChildForm(TempForm).ClientInitialized and
TChildForm(TempForm).Initialized and
not(TChildForm(TempForm).Closing) then
begin
PostMessage(TempForm.Handle, WM_CLOSE, 0, 0);
@ -352,11 +433,16 @@ begin
end;
i := pred(BrowserPageCtrl.PageCount);
while (i >= 0) do
begin
TBrowserTab(BrowserPageCtrl.Pages[i]).CloseBrowser;
Result := True;
TempTab := TBrowserTab(BrowserPageCtrl.Pages[i]);
if TempTab.Initialized and not(TempTab.Closing) then
begin
TempTab.CloseBrowser;
Result := True;
end;
dec(i);
end;
end;
@ -367,6 +453,26 @@ begin
TBrowserTab(BrowserPageCtrl.Pages[aIndex]).CloseBrowser;
end;
procedure TMainForm.CreateHiddenBrowsers;
begin
try
FCriticalSection.Acquire;
if (FChildForm = nil) then
FChildForm := TChildForm.Create(self);
if (FHiddenTab = nil) then
begin
FHiddenTab := TBrowserTab.Create(self, NextTabID, DEFAULT_TAB_CAPTION);
FHiddenTab.PageControl := BrowserPageCtrl;
FHiddenTab.TabVisible := False;
FHiddenTab.CreateFrame;
end;
finally
FCriticalSection.Release;
end;
end;
procedure TMainForm.WMMove(var aMessage : TWMMove);
var
i : integer;
@ -411,17 +517,70 @@ begin
GlobalCEFApp.OsmodalLoop := False;
end;
function TMainForm.CreateClientHandler(var windowInfo : TCefWindowInfo;
var client : ICefClient;
const targetFrameName : string;
const popupFeatures : TCefPopupFeatures) : boolean;
procedure TMainForm.WMQueryEndSession(var aMessage: TWMQueryEndSession);
begin
// We return False (0) to close the browser correctly while we can.
// This is not what Microsoft recommends doing when an application receives
// WM_QUERYENDSESSION but at least we avoid TApplication calling HALT when
// it receives WM_ENDSESSION.
// The CEF subprocesses may receive WM_QUERYENDSESSION and WM_ENDSESSION
// before the main process and they may crash before closing the main form.
aMessage.Result := 0;
PostMessage(Handle, WM_CLOSE, 0, 0);
end;
function TMainForm.DoOnBeforePopup(var windowInfo : TCefWindowInfo;
var client : ICefClient;
const targetFrameName : string;
const popupFeatures : TCefPopupFeatures;
targetDisposition : TCefWindowOpenDisposition) : boolean;
begin
try
FCriticalSection.Acquire;
Result := (FChildForm <> nil) and
FChildForm.CreateClientHandler(windowInfo, client, targetFrameName, popupFeatures) and
PostMessage(Handle, CEF_CREATENEXTCHILD, 0, 0);
case targetDisposition of
WOD_NEW_FOREGROUND_TAB,
WOD_NEW_BACKGROUND_TAB :
Result := (FHiddenTab <> nil) and
FHiddenTab.CreateClientHandler(windowInfo, client, targetFrameName, popupFeatures) and
PostMessage(Handle, CEF_CREATENEXTTAB, 0, ord(False));
WOD_NEW_WINDOW,
WOD_NEW_POPUP :
Result := (FChildForm <> nil) and
FChildForm.CreateClientHandler(windowInfo, client, targetFrameName, popupFeatures) and
PostMessage(Handle, CEF_CREATENEXTCHILD, 0, ord(False));
else Result := False;
end;
finally
FCriticalSection.Release;
end;
end;
function TMainForm.DoOpenUrlFromTab(const targetUrl : string;
targetDisposition : TCefWindowOpenDisposition) : boolean;
begin
try
FCriticalSection.Acquire;
case targetDisposition of
WOD_NEW_FOREGROUND_TAB,
WOD_NEW_BACKGROUND_TAB :
begin
FPendingURL := targetUrl;
Result := PostMessage(Handle, CEF_CREATENEXTTAB, 0, ord(True));
end;
WOD_NEW_WINDOW,
WOD_NEW_POPUP :
begin
FPendingURL := targetUrl;
Result := PostMessage(Handle, CEF_CREATENEXTCHILD, 0, ord(True));
end
else Result := False;
end;
finally
FCriticalSection.Release;
end;

View File

@ -1,983 +0,0 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{2A491C1D-D0F3-4D4B-9606-F7FC09C7713E}</ProjectGuid>
<ProjectVersion>18.8</ProjectVersion>
<FrameworkType>VCL</FrameworkType>
<MainSource>TabbedBrowser2.dpr</MainSource>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Debug</Config>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>1</TargetedPlatforms>
<AppType>Application</AppType>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
<Base_Win32>true</Base_Win32>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
<Base_Win64>true</Base_Win64>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
<Cfg_1>true</Cfg_1>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
<Cfg_1_Win32>true</Cfg_1_Win32>
<CfgParent>Cfg_1</CfgParent>
<Cfg_1>true</Cfg_1>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
<Cfg_2>true</Cfg_2>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
<Cfg_2_Win32>true</Cfg_2_Win32>
<CfgParent>Cfg_2</CfgParent>
<Cfg_2>true</Cfg_2>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Base)'!=''">
<DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
<DCC_ExeOutput>..\..\..\bin</DCC_ExeOutput>
<DCC_E>false</DCC_E>
<DCC_N>false</DCC_N>
<DCC_S>false</DCC_S>
<DCC_F>false</DCC_F>
<DCC_K>false</DCC_K>
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)</DCC_Namespace>
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
<UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44>
<UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150>
<SanitizedProjectName>TabbedBrowser2</SanitizedProjectName>
<VerInfo_Locale>3082</VerInfo_Locale>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win32)'!=''">
<DCC_UsePackage>DBXSqliteDriver;bindcompdbx;fmxase;DBXDb2Driver;DBXInterBaseDriver;vcl;DBXSybaseASEDriver;vclactnband;RESTComponents;vclFireDAC;IndyProtocols250;FireDACDb2Driver;IndyCore250;DataSnapFireDAC;svnui;tethering;dsnapcon;FireDACADSDriver;FireDACMSAccDriver;fmxFireDAC;DBXMSSQLDriver;vclimg;FireDACInfxDriver;DatasnapConnectorsFreePascal;FireDAC;FireDACMSSQLDriver;vcltouch;Componentes_UI;vcldb;bindcompfmx;svn;Detours;FireDACSqliteDriver;FireDACPgDriver;DBXOracleDriver;inetdb;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;SVGPackage;soaprtl;DbxCommonDriver;FireDACIBDriver;fmx;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;fmxdae;vclwinx;rtl;FireDACDSDriver;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;vcldsnap;dbexpress;FireDACDBXDriver;vclx;bindcomp;appanalytics;dsnap;DataSnapCommon;DBXInformixDriver;FireDACCommon;bindcompvcl;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;vclie;CEF4Delphi_FMX;bindengine;DBXMySQLDriver;FireDACOracleDriver;dsnapxml;FireDACMySQLDriver;dbrtl;inetdbxpress;DBXFirebirdDriver;DataSnapProviderClient;FireDACMongoDBDriver;FireDACCommonODBC;FireDACCommonDriver;CloudService;DataSnapClient;VisualStyles;IndySystem250;inet;DataSnapServerMidas;$(DCC_UsePackage)</DCC_UsePackage>
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
<BT_BuildType>Debug</BT_BuildType>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<VerInfo_Locale>1033</VerInfo_Locale>
<Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win64)'!=''">
<DCC_UsePackage>DBXSqliteDriver;bindcompdbx;fmxase;DBXDb2Driver;DBXInterBaseDriver;vcl;DBXSybaseASEDriver;vclactnband;RESTComponents;vclFireDAC;IndyProtocols250;FireDACDb2Driver;IndyCore250;DataSnapFireDAC;tethering;dsnapcon;FireDACADSDriver;FireDACMSAccDriver;fmxFireDAC;DBXMSSQLDriver;vclimg;FireDACInfxDriver;DatasnapConnectorsFreePascal;FireDAC;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;FireDACSqliteDriver;FireDACPgDriver;DBXOracleDriver;inetdb;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;soaprtl;DbxCommonDriver;FireDACIBDriver;fmx;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;fmxdae;vclwinx;rtl;FireDACDSDriver;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;vcldsnap;dbexpress;FireDACDBXDriver;vclx;bindcomp;appanalytics;dsnap;DataSnapCommon;DBXInformixDriver;FireDACCommon;bindcompvcl;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;vclie;CEF4Delphi_FMX;bindengine;DBXMySQLDriver;FireDACOracleDriver;dsnapxml;FireDACMySQLDriver;dbrtl;inetdbxpress;DBXFirebirdDriver;DataSnapProviderClient;FireDACMongoDBDriver;FireDACCommonODBC;FireDACCommonDriver;CloudService;DataSnapClient;IndySystem250;inet;DataSnapServerMidas;$(DCC_UsePackage)</DCC_UsePackage>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
<DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
<DCC_DebugDCUs>true</DCC_DebugDCUs>
<DCC_Optimize>false</DCC_Optimize>
<DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
<DCC_RemoteDebug>true</DCC_RemoteDebug>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
<DCC_RemoteDebug>false</DCC_RemoteDebug>
<AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Locale>1033</VerInfo_Locale>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
<DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
<DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
<DCC_DebugInformation>0</DCC_DebugInformation>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
<AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
</PropertyGroup>
<ItemGroup>
<DelphiCompile Include="$(MainSource)">
<MainSource>MainSource</MainSource>
</DelphiCompile>
<DCCReference Include="uMainForm.pas">
<Form>MainForm</Form>
</DCCReference>
<DCCReference Include="uBrowserFrame.pas">
<Form>BrowserFrame</Form>
<DesignClass>TFrame</DesignClass>
</DCCReference>
<DCCReference Include="uBrowserTab.pas"/>
<BuildConfiguration Include="Release">
<Key>Cfg_2</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>
<BuildConfiguration Include="Debug">
<Key>Cfg_1</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
</ItemGroup>
<ProjectExtensions>
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
<Borland.ProjectType>Application</Borland.ProjectType>
<BorlandProject>
<Delphi.Personality>
<Source>
<Source Name="MainSource">TabbedBrowser2.dpr</Source>
</Source>
<Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dclIPIndyImpl260.bpl">IP Abstraction Indy Implementation Design Time</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k260.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
<Excluded_Packages Name="$(BDSBIN)\dclofficexp260.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
</Excluded_Packages>
</Delphi.Personality>
<Deployment Version="3">
<DeployFile LocalName="..\..\..\bin\TabbedBrowser2.exe" Configuration="Debug" Class="ProjectOutput">
<Platform Name="Win32">
<RemoteName>TabbedBrowser2.exe</RemoteName>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployClass Name="AdditionalDebugSymbols">
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidClassesDexFile">
<Platform Name="Android">
<RemoteDir>classes</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>classes</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidFileProvider">
<Platform Name="Android">
<RemoteDir>res\xml</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\xml</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidGDBServer">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidLibnativeArmeabiFile">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidLibnativeArmeabiv7aFile">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidLibnativeMipsFile">
<Platform Name="Android">
<RemoteDir>library\lib\mips</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\mips</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidServiceOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\arm64-v8a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidServiceOutput_Android32">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashImageDef">
<Platform Name="Android">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashStyles">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashStylesV21">
<Platform Name="Android">
<RemoteDir>res\values-v21</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values-v21</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_Colors">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_DefaultAppIcon">
<Platform Name="Android">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon144">
<Platform Name="Android">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon36">
<Platform Name="Android">
<RemoteDir>res\drawable-ldpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-ldpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon48">
<Platform Name="Android">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon72">
<Platform Name="Android">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon96">
<Platform Name="Android">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon24">
<Platform Name="Android">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon36">
<Platform Name="Android">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon48">
<Platform Name="Android">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon72">
<Platform Name="Android">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_NotificationIcon96">
<Platform Name="Android">
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xxxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage426">
<Platform Name="Android">
<RemoteDir>res\drawable-small</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-small</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage470">
<Platform Name="Android">
<RemoteDir>res\drawable-normal</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-normal</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage640">
<Platform Name="Android">
<RemoteDir>res\drawable-large</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-large</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage960">
<Platform Name="Android">
<RemoteDir>res\drawable-xlarge</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\drawable-xlarge</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_Strings">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DebugSymbols">
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DependencyFramework">
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.framework</Extensions>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.framework</Extensions>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DependencyModule">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.dll;.bpl</Extensions>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="DependencyPackage">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.bpl</Extensions>
</Platform>
</DeployClass>
<DeployClass Name="File">
<Platform Name="Android">
<Operation>0</Operation>
</Platform>
<Platform Name="Android64">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>0</Operation>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\Resources\StartUp\</RemoteDir>
<Operation>0</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\Resources\StartUp\</RemoteDir>
<Operation>0</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1024x768">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1536x2048">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1668">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1668x2388">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2048x1536">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2048x2732">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2224">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2388x1668">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2732x2048">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch768x1024">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1125">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1136x640">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1242">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1242x2688">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1334">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch1792">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2208">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2436">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch2688x1242">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch320">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch640">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch640x1136">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch750">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch828">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectAndroidManifest">
<Platform Name="Android">
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceDebug">
<Platform Name="iOSDevice32">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceResourceRules">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSEntitlements">
<Platform Name="iOSDevice32">
<RemoteDir>..\</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<RemoteDir>..\</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSInfoPList">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSResource">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXDebug">
<Platform Name="OSX64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXEntitlements">
<Platform Name="OSX32">
<RemoteDir>..\</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>..\</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXInfoPList">
<Platform Name="OSX32">
<RemoteDir>Contents</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXResource">
<Platform Name="OSX32">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="ProjectOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Android64">
<RemoteDir>library\lib\arm64-v8a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="Linux64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="OSX64">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOutput_Android32">
<Platform Name="Android64">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectUWPManifest">
<Platform Name="Win32">
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo150">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo44">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/>
</Deployment>
<Platforms>
<Platform value="Win32">True</Platform>
<Platform value="Win64">False</Platform>
</Platforms>
</BorlandProject>
<ProjectFileVersion>12</ProjectFileVersion>
</ProjectExtensions>
<Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
<Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
<Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
</Project>

View File

@ -35,7 +35,7 @@
<PackageName Value="LCL"/>
</Item2>
</RequiredPackages>
<Units Count="4">
<Units Count="5">
<Unit0>
<Filename Value="TabbedBrowser2.lpr"/>
<IsPartOfProject Value="True"/>
@ -50,14 +50,17 @@
<Unit2>
<Filename Value="uBrowserFrame.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="BrowserFrame"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Frame"/>
</Unit2>
<Unit3>
<Filename Value="uBrowserTab.pas"/>
<IsPartOfProject Value="True"/>
</Unit3>
<Unit4>
<Filename Value="uChildForm.pas"/>
<IsPartOfProject Value="True"/>
<HasResources Value="True"/>
</Unit4>
</Units>
</ProjectOptions>
<CompilerOptions>

View File

@ -42,18 +42,26 @@ program TabbedBrowser2;
{$I cef.inc}
uses
{$IFDEF DELPHI16_UP}
Vcl.Forms,
WinApi.Windows,
{$ELSE}
Forms,
LCLIntf, LCLType, LMessages, Interfaces,
{$ENDIF }
uCEFApplication,
uMainForm in 'uMainForm.pas' {MainForm},
uBrowserFrame in 'uBrowserFrame.pas' {BrowserFrame: TFrame},
uBrowserTab in 'uBrowserTab.pas';
uBrowserTab in 'uBrowserTab.pas',
uChildForm in 'uChildForm.pas' {ChildForm};
{.$R *.res}
// CEF needs to set the LARGEADDRESSAWARE flag which allows 32-bit processes to use up to 3GB of RAM.
// If you don't add this flag the rederer process will crash when you try to load large images.
{$SetPEFlags $20}
{$IFDEF WIN32}
// CEF needs to set the LARGEADDRESSAWARE flag which allows 32-bit processes to use up to 3GB of RAM.
// If you don't add this flag the rederer process will crash when you try to load large images.
{$SetPEFlags IMAGE_FILE_LARGE_ADDRESS_AWARE}
{$ENDIF}
begin
CreateGlobalCEFApp;
@ -61,6 +69,9 @@ begin
if GlobalCEFApp.StartMainProcess then
begin
Application.Initialize;
{$IFDEF DELPHI11_UP}
Application.MainFormOnTaskbar := True;
{$ENDIF}
Application.CreateForm(TMainForm, MainForm);
Application.Run;
end;

View File

@ -1,116 +1,115 @@
object BrowserFrame: TBrowserFrame
Left = 0
Height = 670
Top = 0
Width = 932
ClientHeight = 670
ClientWidth = 932
Height = 670
TabOrder = 0
DesignLeft = 269
DesignTop = 169
object NavControlPnl: TPanel
Left = 0
Height = 28
Top = 0
Width = 932
Height = 35
Align = alTop
BevelOuter = bvNone
ClientHeight = 28
ClientWidth = 932
Enabled = False
TabOrder = 0
object NavButtonPnl: TPanel
Left = 0
Height = 28
Top = 0
Width = 123
Height = 35
Align = alLeft
BevelOuter = bvNone
ClientHeight = 28
ClientWidth = 123
TabOrder = 0
object BackBtn: TButton
Left = 0
Height = 25
Top = 0
Left = 3
Top = 3
Width = 25
Height = 25
Caption = '3'
Font.CharSet = SYMBOL_CHARSET
Font.Charset = SYMBOL_CHARSET
Font.Color = clWindowText
Font.Height = -19
Font.Name = 'Webdings'
OnClick = BackBtnClick
Font.Style = []
ParentFont = False
TabOrder = 0
OnClick = BackBtnClick
end
object ForwardBtn: TButton
Left = 30
Height = 25
Top = 0
Left = 33
Top = 3
Width = 25
Height = 25
Caption = '4'
Font.CharSet = SYMBOL_CHARSET
Font.Charset = SYMBOL_CHARSET
Font.Color = clWindowText
Font.Height = -19
Font.Name = 'Webdings'
OnClick = ForwardBtnClick
Font.Style = []
ParentFont = False
TabOrder = 1
OnClick = ForwardBtnClick
end
object ReloadBtn: TButton
Left = 59
Height = 25
Top = 0
Left = 62
Top = 3
Width = 25
Height = 25
Caption = 'q'
Font.CharSet = SYMBOL_CHARSET
Font.Charset = SYMBOL_CHARSET
Font.Color = clWindowText
Font.Height = -19
Font.Name = 'Webdings'
OnClick = ReloadBtnClick
Font.Style = []
ParentFont = False
TabOrder = 2
OnClick = ReloadBtnClick
end
object StopBtn: TButton
Left = 88
Height = 25
Top = 0
Left = 91
Top = 3
Width = 25
Height = 25
Caption = '='
Font.CharSet = SYMBOL_CHARSET
Font.Charset = SYMBOL_CHARSET
Font.Color = clWindowText
Font.Height = -19
Font.Name = 'Webdings'
OnClick = StopBtnClick
Font.Style = []
ParentFont = False
TabOrder = 3
OnClick = StopBtnClick
end
end
object URLEditPnl: TPanel
Left = 123
Height = 28
Left = 121
Top = 0
Width = 774
Height = 35
Align = alClient
BevelOuter = bvNone
ClientHeight = 28
ClientWidth = 774
TabOrder = 1
object URLCbx: TComboBox
Left = 0
Height = 23
Top = 1
Width = 774
Anchors = [akTop, akLeft, akRight]
ItemHeight = 15
Top = 5
Width = 770
Height = 21
Anchors = [akLeft, akTop, akRight]
ItemIndex = 0
TabOrder = 0
Text = 'https://www.google.com'
Items.Strings = (
'https://www.google.com'
'https://www.whatismybrowser.com/detect/what-http-headers-is-my-browser-sending'
'https://www.whatismybrowser.com/detect/what-http-headers-is-my-b' +
'rowser-sending'
'https://www.w3schools.com/js/tryit.asp?filename=tryjs_win_close'
'https://www.w3schools.com/js/tryit.asp?filename=tryjs_alert'
'https://www.w3schools.com/js/tryit.asp?filename=tryjs_loc_assign'
'https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_style_backgroundcolor'
'https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_styl' +
'e_backgroundcolor'
'https://www.w3schools.com/html/html5_video.asp'
'http://www.adobe.com/software/flash/about/'
'http://isflashinstalled.com/'
@ -118,7 +117,9 @@ object BrowserFrame: TBrowserFrame
'https://www.ultrasounds.com/'
'https://www.whatismybrowser.com/detect/is-flash-installed'
'http://html5test.com/'
'https://webrtc.github.io/samples/src/content/devices/input-output/'
'https://webrtc.github.io/samples/src/content/devices/input-outpu' +
't/'
'https://test.webrtc.org/'
'https://www.w3schools.com/'
'http://webglsamples.org/'
@ -126,9 +127,15 @@ object BrowserFrame: TBrowserFrame
'https://www.briskbard.com'
'https://www.youtube.com'
'https://html5demos.com/drag/'
'https://developers.google.com/maps/documentation/javascript/examples/streetview-embed?hl=fr'
'https://www.w3schools.com/Tags/tryit.asp?filename=tryhtml_iframe_name'
'http://www-db.deis.unibo.it/courses/TW/DOCS/w3schools/html/tryit.asp-filename=tryhtml5_html_manifest.html'
'https://developers.google.com/maps/documentation/javascript/exam' +
'ples/streetview-embed?hl=fr'
'https://www.w3schools.com/Tags/tryit.asp?filename=tryhtml_iframe' +
'_name'
'http://www-db.deis.unibo.it/courses/TW/DOCS/w3schools/html/tryit' +
'.asp-filename=tryhtml5_html_manifest.html'
'https://www.browserleaks.com/webrtc'
'https://frames-per-second.appspot.com/'
'chrome://version/'
@ -148,45 +155,40 @@ object BrowserFrame: TBrowserFrame
'chrome://gpucrash'
'chrome://gpuhang'
'chrome://extensions-support'
'chrome://process-internals'
)
TabOrder = 0
Text = 'https://www.google.com'
'chrome://process-internals')
end
end
object ConfigPnl: TPanel
Left = 897
Height = 28
Left = 895
Top = 0
Width = 35
Height = 35
Align = alRight
BevelOuter = bvNone
ClientHeight = 28
ClientWidth = 35
TabOrder = 2
object GoBtn: TButton
Left = 5
Height = 25
Top = 0
Left = 3
Top = 3
Width = 25
Height = 25
Caption = '►'
Font.CharSet = ANSI_CHARSET
Font.Charset = ANSI_CHARSET
Font.Color = clWindowText
Font.Height = -17
Font.Name = 'Arial'
Font.Style = [fsBold]
OnClick = GoBtnClick
ParentFont = False
TabOrder = 0
OnClick = GoBtnClick
end
end
end
object StatusBar1: TStatusBar
Left = 0
Height = 23
Top = 647
Top = 651
Width = 932
Panels = <
Height = 19
Panels = <
item
Width = 500
end>
@ -194,9 +196,9 @@ object BrowserFrame: TBrowserFrame
end
object CEFWindowParent1: TCEFWindowParent
Left = 0
Height = 619
Top = 28
Top = 35
Width = 932
Height = 616
Align = alClient
TabOrder = 2
end
@ -211,7 +213,7 @@ object BrowserFrame: TBrowserFrame
OnBeforeClose = Chromium1BeforeClose
OnClose = Chromium1Close
OnOpenUrlFromTab = Chromium1OpenUrlFromTab
left = 40
top = 72
Left = 40
Top = 72
end
end

View File

@ -44,12 +44,25 @@ unit uBrowserFrame;
interface
uses
{$IFDEF DELPHI16_UP}
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
Vcl.ExtCtrls, Vcl.ComCtrls, Vcl.StdCtrls, System.SyncObjs,
{$ELSE}
LCLIntf, LCLType, LMessages, Messages, SysUtils, Variants,
Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, ComCtrls, StdCtrls,
ExtCtrls, ComCtrls, StdCtrls, SyncObjs,
{$ENDIF}
uCEFWinControl, uCEFWindowParent, uCEFChromiumCore, uCEFChromium,
uCEFInterfaces, uCEFTypes, uCEFConstants;
const
CEF_UPDATECAPTION = WM_APP + $A55;
CEF_UPDATEADDRESS = WM_APP + $A56;
CEF_UPDATESTATE = WM_APP + $A57;
CEF_UPDATESTATUSTEXT = WM_APP + $A58;
type
TBrowserTitleEvent = procedure(Sender: TObject; const aTitle : string) of object;
@ -86,20 +99,59 @@ type
procedure GoBtnClick(Sender: TObject);
protected
FCriticalSection : TCriticalSection;
FClosing : boolean; // Indicates that this frame is destroying the browser
FHomepage : string;
FPendingAddress : string;
FPendingTitle : string;
FPendingStatus : string;
FPendingIsLoading : boolean;
FPendingCanGoBack : boolean;
FPendingCanGoForward : boolean;
FOnBrowserDestroyed : TNotifyEvent;
FOnBrowserTitleChange : TBrowserTitleEvent;
function GetInitialized : boolean;
function GetPendingAddress : string;
function GetPendingTitle : string;
function GetPendingStatus : string;
function GetPendingIsLoading : boolean;
function GetPendingCanGoBack : boolean;
function GetPendingCanGoForward : boolean;
procedure SetPendingAddress(const aValue : string);
procedure SetPendingTitle(const aValue : string);
procedure SetPendingStatus(const aValue : string);
procedure SetPendingIsLoading(aValue : boolean);
procedure SetPendingCanGoBack(aValue : boolean);
procedure SetPendingCanGoForward(aValue : boolean);
procedure BrowserCreatedMsg(var aMessage : TMessage); message CEF_AFTERCREATED;
procedure BrowserDestroyMsg(var aMessage : TMessage); message CEF_DESTROY;
procedure BrowserUpdateCaptionMsg(var aMessage : TMessage); message CEF_UPDATECAPTION;
procedure BrowserUpdateAddressMsg(var aMessage : TMessage); message CEF_UPDATEADDRESS;
procedure BrowserUpdateStateMsg(var aMessage : TMessage); message CEF_UPDATESTATE;
procedure BrowserUpdateStatusTextMsg(var aMessage : TMessage); message CEF_UPDATESTATUSTEXT;
property PendingAddress : string read GetPendingAddress write SetPendingAddress;
property PendingTitle : string read GetPendingTitle write SetPendingTitle;
property PendingStatus : string read GetPendingStatus write SetPendingStatus;
property PendingIsLoading : boolean read GetPendingIsLoading write SetPendingIsLoading;
property PendingCanGoBack : boolean read GetPendingCanGoBack write SetPendingCanGoBack;
property PendingCanGoForward : boolean read GetPendingCanGoForward write SetPendingCanGoForward;
public
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
procedure NotifyMoveOrResizeStarted;
procedure CreateAllHandles;
procedure CreateBrowser;
procedure CloseBrowser;
procedure ShowBrowser;
procedure HideBrowser;
function CreateClientHandler(var windowInfo : TCefWindowInfo; var client : ICefClient; const targetFrameName : string; const popupFeatures : TCefPopupFeatures) : boolean;
property Initialized : boolean read GetInitialized;
property Closing : boolean read FClosing;
property Homepage : string read FHomepage write FHomepage;
property OnBrowserDestroyed : TNotifyEvent read FOnBrowserDestroyed write FOnBrowserDestroyed;
@ -110,16 +162,138 @@ implementation
{$R *.lfm}
uses
uCEFMiscFunctions, uBrowserTab;
// The TChromium events are executed in a CEF thread and we should only update the
// GUI controls in the main application thread.
// This demo saves all the information in those events using a synchronization
// object and sends a custom message to update the GUI in the main application thread.
// Destruction steps
// =================
// 1. TBrowserFrame.CloseBrowser sets CanClose to FALSE calls TChromium.CloseBrowser
// which triggers the TChromium.OnClose event.
// 2. TChromium.OnClose sends a CEFBROWSER_DESTROY message to destroy CEFWindowParent1
// in the main thread, which triggers the TChromium.OnBeforeClose event.
// 3. TChromium.OnBeforeClose triggers the TBrowserFrame.OnBrowserDestroyed event
// which sends a CEF_DESTROYTAB message with the TabID to the main form.
constructor TBrowserFrame.Create(AOwner : TComponent);
begin
inherited Create(AOwner);
FCriticalSection := TCriticalSection.Create;
FClosing := False;
FHomepage := '';
FOnBrowserDestroyed := nil;
FOnBrowserTitleChange := nil;
end;
destructor TBrowserFrame.Destroy;
begin
FreeAndNil(FCriticalSection);
inherited Destroy;
end;
procedure TBrowserFrame.CreateAllHandles;
begin
CreateHandle;
CEFWindowParent1.CreateHandle;
end;
function TBrowserFrame.GetInitialized : boolean;
begin
Result := Chromium1.Initialized;
end;
function TBrowserFrame.GetPendingAddress : string;
begin
FCriticalSection.Acquire;
Result := FPendingAddress;
FCriticalSection.Release;
end;
function TBrowserFrame.GetPendingTitle : string;
begin
FCriticalSection.Acquire;
Result := FPendingTitle;
FCriticalSection.Release;
end;
function TBrowserFrame.GetPendingStatus : string;
begin
FCriticalSection.Acquire;
Result := FPendingStatus;
FCriticalSection.Release;
end;
function TBrowserFrame.GetPendingIsLoading : boolean;
begin
FCriticalSection.Acquire;
Result := FPendingIsLoading;
FCriticalSection.Release;
end;
function TBrowserFrame.GetPendingCanGoBack : boolean;
begin
FCriticalSection.Acquire;
Result := FPendingCanGoBack;
FCriticalSection.Release;
end;
function TBrowserFrame.GetPendingCanGoForward : boolean;
begin
FCriticalSection.Acquire;
Result := FPendingCanGoForward;
FCriticalSection.Release;
end;
procedure TBrowserFrame.SetPendingAddress(const aValue : string);
begin
FCriticalSection.Acquire;
FPendingAddress := aValue;
FCriticalSection.Release;
end;
procedure TBrowserFrame.SetPendingTitle(const aValue : string);
begin
FCriticalSection.Acquire;
FPendingTitle := aValue;
FCriticalSection.Release;
end;
procedure TBrowserFrame.SetPendingStatus(const aValue : string);
begin
FCriticalSection.Acquire;
FPendingStatus := aValue;
FCriticalSection.Release;
end;
procedure TBrowserFrame.SetPendingIsLoading(aValue : boolean);
begin
FCriticalSection.Acquire;
FPendingIsLoading := aValue;
FCriticalSection.Release;
end;
procedure TBrowserFrame.SetPendingCanGoBack(aValue : boolean);
begin
FCriticalSection.Acquire;
FPendingCanGoBack := aValue;
FCriticalSection.Release;
end;
procedure TBrowserFrame.SetPendingCanGoForward(aValue : boolean);
begin
FCriticalSection.Acquire;
FPendingCanGoForward := aValue;
FCriticalSection.Release;
end;
procedure TBrowserFrame.NotifyMoveOrResizeStarted;
begin
Chromium1.NotifyMoveOrResizeStarted;
@ -151,6 +325,20 @@ begin
end;
end;
procedure TBrowserFrame.ShowBrowser;
begin
Chromium1.WasHidden(False);
Chromium1.SendFocusEvent(True);
Chromium1.AudioMuted := False;
end;
procedure TBrowserFrame.HideBrowser;
begin
Chromium1.SendFocusEvent(False);
Chromium1.WasHidden(True);
Chromium1.AudioMuted := True;
end;
procedure TBrowserFrame.ForwardBtnClick(Sender: TObject);
begin
Chromium1.GoForward;
@ -161,8 +349,7 @@ begin
Chromium1.LoadURL(URLCbx.Text);
end;
procedure TBrowserFrame.Chromium1AfterCreated(Sender: TObject;
const browser: ICefBrowser);
procedure TBrowserFrame.Chromium1AfterCreated(Sender: TObject; const browser: ICefBrowser);
begin
PostMessage(Handle, CEF_AFTERCREATED, 0, 0);
end;
@ -172,42 +359,67 @@ begin
Chromium1.GoBack;
end;
procedure TBrowserFrame.Chromium1AddressChange(Sender: TObject;
const browser: ICefBrowser; const frame: ICefFrame; const url: ustring);
procedure TBrowserFrame.Chromium1AddressChange( Sender : TObject;
const browser : ICefBrowser;
const frame : ICefFrame;
const url : ustring);
begin
if (URLCbx.Items.IndexOf(url) < 0) then URLCbx.Items.Add(url);
URLCbx.Text := url;
PendingAddress := url;
PostMessage(Handle, CEF_UPDATEADDRESS, 0, 0);
end;
procedure TBrowserFrame.Chromium1BeforeClose(Sender: TObject;
const browser: ICefBrowser);
procedure TBrowserFrame.Chromium1BeforeClose(Sender: TObject; const browser: ICefBrowser);
begin
if assigned(FOnBrowserDestroyed) then FOnBrowserDestroyed(self);
end;
procedure TBrowserFrame.Chromium1BeforePopup(Sender: TObject;
const browser: ICefBrowser; const frame: ICefFrame; 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 TBrowserFrame.Chromium1BeforePopup( Sender : TObject;
const browser : ICefBrowser;
const frame : ICefFrame;
const targetUrl : ustring;
const targetFrameName : ustring;
targetDisposition : TCefWindowOpenDisposition;
userGesture : Boolean;
const popupFeatures : TCefPopupFeatures;
var windowInfo : TCefWindowInfo;
var client : ICefClient;
var settings : TCefBrowserSettings;
var extra_info : ICefDictionaryValue;
var noJavascriptAccess : Boolean;
var Result : Boolean);
begin
// For simplicity, this demo blocks all popup windows and new tabs
Result := (targetDisposition in [WOD_NEW_FOREGROUND_TAB, WOD_NEW_BACKGROUND_TAB, WOD_NEW_POPUP, WOD_NEW_WINDOW]);
Result := not(assigned(Parent) and
(Parent is TBrowserTab) and
TBrowserTab(Parent).DoOnBeforePopup(windowInfo, client, targetFrameName, popupFeatures, targetDisposition));
end;
procedure TBrowserFrame.Chromium1Close(Sender: TObject;
const browser: ICefBrowser; var aAction: TCefCloseBrowserAction);
procedure TBrowserFrame.Chromium1OpenUrlFromTab( Sender : TObject;
const browser : ICefBrowser;
const frame : ICefFrame;
const targetUrl : ustring;
targetDisposition : TCefWindowOpenDisposition;
userGesture : Boolean;
out Result : Boolean);
begin
Result := assigned(Parent) and
(Parent is TBrowserTab) and
TBrowserTab(Parent).DoOpenUrlFromTab(targetUrl, targetDisposition);
end;
procedure TBrowserFrame.Chromium1Close( Sender : TObject;
const browser : ICefBrowser;
var aAction : TCefCloseBrowserAction);
begin
PostMessage(Handle, CEF_DESTROY, 0, 0);
aAction := cbaDelay;
end;
procedure TBrowserFrame.Chromium1LoadError(Sender: TObject;
const browser: ICefBrowser; const frame: ICefFrame; errorCode: Integer;
const errorText, failedUrl: ustring);
procedure TBrowserFrame.Chromium1LoadError( Sender : TObject;
const browser : ICefBrowser;
const frame : ICefFrame;
errorCode : Integer;
const errorText : ustring;
const failedUrl : ustring);
var
TempString : string;
begin
@ -221,48 +433,38 @@ begin
Chromium1.LoadString(TempString, frame);
end;
procedure TBrowserFrame.Chromium1LoadingStateChange(Sender: TObject;
const browser: ICefBrowser; isLoading, canGoBack, canGoForward: Boolean);
procedure TBrowserFrame.Chromium1LoadingStateChange( Sender : TObject;
const browser : ICefBrowser;
isLoading : Boolean;
canGoBack : Boolean;
canGoForward : Boolean);
begin
BackBtn.Enabled := canGoBack;
ForwardBtn.Enabled := canGoForward;
PendingIsLoading := isLoading;
PendingCanGoBack := canGoBack;
PendingCanGoForward := canGoForward;
if isLoading then
begin
ReloadBtn.Enabled := False;
StopBtn.Enabled := True;
end
else
begin
ReloadBtn.Enabled := True;
StopBtn.Enabled := False;
end;
PostMessage(Handle, CEF_UPDATESTATE, 0, 0);
end;
procedure TBrowserFrame.Chromium1OpenUrlFromTab(Sender: TObject;
const browser: ICefBrowser; const frame: ICefFrame; const targetUrl: ustring;
targetDisposition: TCefWindowOpenDisposition; userGesture: Boolean;
out Result: Boolean);
procedure TBrowserFrame.Chromium1StatusMessage( Sender : TObject;
const browser : ICefBrowser;
const value : ustring);
begin
// For simplicity, this demo blocks all popup windows and new tabs
Result := (targetDisposition in [WOD_NEW_FOREGROUND_TAB, WOD_NEW_BACKGROUND_TAB, WOD_NEW_POPUP, WOD_NEW_WINDOW]);
PendingStatus := value;
PostMessage(Handle, CEF_UPDATESTATUSTEXT, 0, 0);
end;
procedure TBrowserFrame.Chromium1StatusMessage(Sender: TObject;
const browser: ICefBrowser; const value: ustring);
procedure TBrowserFrame.Chromium1TitleChange( Sender : TObject;
const browser : ICefBrowser;
const title : ustring);
begin
StatusBar1.Panels[0].Text := value;
end;
procedure TBrowserFrame.Chromium1TitleChange(Sender: TObject;
const browser: ICefBrowser; const title: ustring);
begin
if not(assigned(FOnBrowserTitleChange)) then exit;
if (length(title) > 0) then
FOnBrowserTitleChange(self, title)
PendingTitle := title
else
FOnBrowserTitleChange(self, Chromium1.DocumentURL);
PendingTitle := Chromium1.DocumentURL;
PostMessage(Handle, CEF_UPDATECAPTION, 0, 0);
end;
procedure TBrowserFrame.BrowserCreatedMsg(var aMessage : TMessage);
@ -276,6 +478,65 @@ begin
CEFWindowParent1.Free;
end;
procedure TBrowserFrame.BrowserUpdateCaptionMsg(var aMessage : TMessage);
begin
if assigned(FOnBrowserTitleChange) then
FOnBrowserTitleChange(self, PendingTitle);
end;
procedure TBrowserFrame.BrowserUpdateAddressMsg(var aMessage : TMessage);
var
TempAddress : string;
begin
TempAddress := PendingAddress;
if (URLCbx.Items.IndexOf(TempAddress) < 0) then
URLCbx.Items.Add(TempAddress);
URLCbx.Text := TempAddress;
end;
procedure TBrowserFrame.BrowserUpdateStateMsg(var aMessage : TMessage);
begin
BackBtn.Enabled := PendingCanGoBack;
ForwardBtn.Enabled := PendingCanGoForward;
if PendingIsLoading then
begin
ReloadBtn.Enabled := False;
StopBtn.Enabled := True;
end
else
begin
ReloadBtn.Enabled := True;
StopBtn.Enabled := False;
end;
end;
procedure TBrowserFrame.BrowserUpdateStatusTextMsg(var aMessage : TMessage);
begin
StatusBar1.Panels[0].Text := PendingStatus;
end;
function TBrowserFrame.CreateClientHandler(var windowInfo : TCefWindowInfo;
var client : ICefClient;
const targetFrameName : string;
const popupFeatures : TCefPopupFeatures) : boolean;
var
TempRect : TRect;
begin
if CEFWindowParent1.HandleAllocated and
Chromium1.CreateClientHandler(client, False) then
begin
Result := True;
TempRect := CEFWindowParent1.ClientRect;
WindowInfoAsChild(windowInfo, CEFWindowParent1.Handle, TempRect, '');
end
else
Result := False;
end;
end.

View File

@ -1,4 +1,4 @@
// ************************************************************************
// ************************************************************************
// ***************************** CEF4Delphi *******************************
// ************************************************************************
//
@ -44,9 +44,14 @@ unit uBrowserTab;
interface
uses
{$IFDEF DELPHI16_UP}
Winapi.Windows, System.Classes, Winapi.Messages, Vcl.ComCtrls, Vcl.Controls,
Vcl.Forms, System.SysUtils,
{$ELSE}
LCLIntf, LCLType, LMessages, Classes, Messages, ComCtrls, Controls,
Forms,
uBrowserFrame;
Forms, SysUtils,
{$ENDIF}
uCEFInterfaces, uCEFTypes, uBrowserFrame;
type
TBrowserTab = class(TTabSheet)
@ -55,6 +60,8 @@ type
FTabID : cardinal;
function GetParentForm : TCustomForm;
function GetInitialized : boolean;
function GetClosing : boolean;
function PostFormMessage(aMsg : cardinal; aWParam : WPARAM = 0; aLParam : LPARAM = 0) : boolean;
@ -66,10 +73,18 @@ type
public
constructor Create(AOwner: TComponent; aTabID : cardinal; const aCaption : string); reintroduce;
procedure NotifyMoveOrResizeStarted;
procedure CreateFrame(const aHomepage : string = '');
procedure CreateBrowser(const aHomepage : string);
procedure CloseBrowser;
procedure ShowBrowser;
procedure HideBrowser;
function CreateClientHandler(var windowInfo : TCefWindowInfo; var client : ICefClient; const targetFrameName : string; const popupFeatures : TCefPopupFeatures) : boolean;
function DoOnBeforePopup(var windowInfo : TCefWindowInfo; var client : ICefClient; const targetFrameName : string; const popupFeatures : TCefPopupFeatures; targetDisposition : TCefWindowOpenDisposition) : boolean;
function DoOpenUrlFromTab(const targetUrl : string; targetDisposition : TCefWindowOpenDisposition) : boolean;
property TabID : cardinal read FTabID;
property TabID : cardinal read FTabID;
property Closing : boolean read GetClosing;
property Initialized : boolean read GetInitialized;
end;
implementation
@ -101,6 +116,18 @@ begin
Result := nil;
end;
function TBrowserTab.GetInitialized : boolean;
begin
Result := (FBrowserFrame <> nil) and
FBrowserFrame.Initialized;
end;
function TBrowserTab.GetClosing : boolean;
begin
Result := (FBrowserFrame <> nil) and
FBrowserFrame.Closing;
end;
function TBrowserTab.PostFormMessage(aMsg : cardinal; aWParam : WPARAM; aLParam : LPARAM) : boolean;
var
TempForm : TCustomForm;
@ -116,17 +143,28 @@ begin
FBrowserFrame.NotifyMoveOrResizeStarted;
end;
procedure TBrowserTab.CreateFrame(const aHomepage : string);
begin
if (FBrowserFrame = nil) then
begin
FBrowserFrame := TBrowserFrame.Create(self);
FBrowserFrame.Name := 'BrowserFrame' + IntToStr(TabID);
FBrowserFrame.Parent := self;
FBrowserFrame.Align := alClient;
FBrowserFrame.Visible := True;
FBrowserFrame.OnBrowserDestroyed := BrowserFrame_OnBrowserDestroyed;
FBrowserFrame.OnBrowserTitleChange := BrowserFrame_OnBrowserTitleChange;
FBrowserFrame.CreateAllHandles;
end;
FBrowserFrame.Homepage := aHomepage;
end;
procedure TBrowserTab.CreateBrowser(const aHomepage : string);
begin
FBrowserFrame := TBrowserFrame.Create(self);
FBrowserFrame.Parent := self;
FBrowserFrame.Align := alClient;
FBrowserFrame.Visible := True;
FBrowserFrame.Homepage := aHomepage;
FBrowserFrame.OnBrowserDestroyed := BrowserFrame_OnBrowserDestroyed;
FBrowserFrame.OnBrowserTitleChange := BrowserFrame_OnBrowserTitleChange;
CreateFrame(aHomepage);
FBrowserFrame.CreateBrowser;
if (FBrowserFrame <> nil) then FBrowserFrame.CreateBrowser;
end;
procedure TBrowserTab.CloseBrowser;
@ -134,8 +172,18 @@ begin
if (FBrowserFrame <> nil) then FBrowserFrame.CloseBrowser;
end;
procedure TBrowserTab.ShowBrowser;
begin
if (FBrowserFrame <> nil) then FBrowserFrame.ShowBrowser;
end;
procedure TBrowserTab.HideBrowser;
begin
if (FBrowserFrame <> nil) then FBrowserFrame.HideBrowser;
end;
procedure TBrowserTab.BrowserFrame_OnBrowserDestroyed(Sender: TObject);
begin
begin
// This event is executed in a CEF thread so we have to send a message to
// destroy the tab in the main application thread.
PostFormMessage(CEF_DESTROYTAB, TabID);
@ -146,4 +194,38 @@ begin
Caption := aTitle;
end;
function TBrowserTab.CreateClientHandler(var windowInfo : TCefWindowInfo;
var client : ICefClient;
const targetFrameName : string;
const popupFeatures : TCefPopupFeatures) : boolean;
begin
Result := (FBrowserFrame <> nil) and
FBrowserFrame.CreateClientHandler(windowInfo, client, targetFrameName, popupFeatures);
end;
function TBrowserTab.DoOnBeforePopup(var windowInfo : TCefWindowInfo;
var client : ICefClient;
const targetFrameName : string;
const popupFeatures : TCefPopupFeatures;
targetDisposition : TCefWindowOpenDisposition) : boolean;
var
TempForm : TCustomForm;
begin
TempForm := ParentForm;
Result := (TempForm <> nil) and
(TempForm is TMainForm) and
TMainForm(TempForm).DoOnBeforePopup(windowInfo, client, targetFrameName, popupFeatures, targetDisposition);
end;
function TBrowserTab.DoOpenUrlFromTab(const targetUrl : string;
targetDisposition : TCefWindowOpenDisposition) : boolean;
var
TempForm : TCustomForm;
begin
TempForm := ParentForm;
Result := (TempForm <> nil) and
(TempForm is TMainForm) and
TMainForm(TempForm).DoOpenUrlFromTab(targetUrl, targetDisposition);
end;
end.

View File

@ -0,0 +1,37 @@
object ChildForm: TChildForm
Left = 0
Top = 0
Caption = 'Popup'
ClientHeight = 256
ClientWidth = 352
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
Position = poScreenCenter
OnClose = FormClose
OnCloseQuery = FormCloseQuery
OnCreate = FormCreate
OnDestroy = FormDestroy
PixelsPerInch = 96
object CEFWindowParent1: TCEFWindowParent
Left = 0
Top = 0
Width = 352
Height = 256
Align = alClient
TabOrder = 0
end
object Chromium1: TChromium
OnTitleChange = Chromium1TitleChange
OnBeforePopup = Chromium1BeforePopup
OnAfterCreated = Chromium1AfterCreated
OnBeforeClose = Chromium1BeforeClose
OnClose = Chromium1Close
OnOpenUrlFromTab = Chromium1OpenUrlFromTab
Left = 24
Top = 56
end
end

View File

@ -0,0 +1,314 @@
// ************************************************************************
// ***************************** CEF4Delphi *******************************
// ************************************************************************
//
// CEF4Delphi is based on DCEF3 which uses CEF to embed a chromium-based
// browser in Delphi applications.
//
// The original license of DCEF3 still applies to CEF4Delphi.
//
// For more information about CEF4Delphi visit :
// https://www.briskbard.com/index.php?lang=en&pageid=cef
//
// Copyright © 2021 Salvador Diaz Fau. All rights reserved.
//
// ************************************************************************
// ************ vvvv Original license and comments below vvvv *************
// ************************************************************************
(*
* Delphi Chromium Embedded 3
*
* Usage allowed under the restrictions of the Lesser GNU General Public License
* or alternatively the restrictions of the Mozilla Public License 1.1
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
*
* Unit owner : Henri Gourvest <hgourvest@gmail.com>
* Web site : http://www.progdigy.com
* Repository : http://code.google.com/p/delphichromiumembedded/
* Group : http://groups.google.com/group/delphichromiumembedded
*
* Embarcadero Technologies, Inc is not permitted to use or redistribute
* this source code without explicit permission.
*
*)
unit uChildForm;
{$MODE Delphi}
{$I cef.inc}
interface
uses
{$IFDEF DELPHI16_UP}
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
System.SyncObjs, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
Vcl.ExtCtrls,
{$ELSE}
LCLIntf, LCLType, LMessages, Messages, SysUtils, Variants, Classes, SyncObjs,
Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls,
{$ENDIF}
uCEFChromium, uCEFTypes, uCEFInterfaces, uCEFConstants, uCEFWindowParent, uCEFWinControl,
uCEFChromiumCore;
const
CEF_UPDATECAPTION = WM_APP + $A55;
type
TChildForm = class(TForm)
Chromium1: TChromium;
CEFWindowParent1: TCEFWindowParent;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure Chromium1AfterCreated(Sender: TObject; const browser: ICefBrowser);
procedure Chromium1BeforePopup(Sender: TObject; const browser: ICefBrowser; const frame: ICefFrame; 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: Boolean; var Result: Boolean);
procedure Chromium1TitleChange(Sender: TObject; const browser: ICefBrowser; const title: ustring);
procedure Chromium1Close(Sender: TObject; const browser: ICefBrowser; var aAction : TCefCloseBrowserAction);
procedure Chromium1BeforeClose(Sender: TObject; const browser: ICefBrowser);
procedure Chromium1OpenUrlFromTab(Sender: TObject; const browser: ICefBrowser; const frame: ICefFrame; const targetUrl: ustring; targetDisposition: TCefWindowOpenDisposition; userGesture: Boolean; out Result: Boolean);
protected
FCriticalSection : TCriticalSection;
FCanClose : boolean;
FClosing : boolean;
FBrowserWasCreated : boolean;
FTitle : string;
FPopupFeatures : TCefPopupFeatures;
function GetInitialized : boolean;
procedure WMMove(var aMessage : TWMMove); message WM_MOVE;
procedure WMMoving(var aMessage : TMessage); message WM_MOVING;
procedure WMEnterMenuLoop(var aMessage: TMessage); message WM_ENTERMENULOOP;
procedure WMExitMenuLoop(var aMessage: TMessage); message WM_EXITMENULOOP;
procedure BrowserDestroyMsg(var aMessage : TMessage); message CEF_DESTROY;
procedure BrowserUpdateCaptionMsg(var aMessage : TMessage); message CEF_UPDATECAPTION;
public
procedure AfterConstruction; override;
function CreateBrowser(const aHomepage : string) : boolean;
function CreateClientHandler(var windowInfo : TCefWindowInfo; var client : ICefClient; const targetFrameName : string; const popupFeatures : TCefPopupFeatures) : boolean;
procedure ApplyPopupFeatures;
property Initialized : boolean read GetInitialized;
property Closing : boolean read FClosing;
end;
implementation
{$R *.lfm}
uses
{$IFDEF DELPHI16_UP}
System.Math,
{$ELSE}
Math,
{$ENDIF}
uCEFMiscFunctions, uCEFApplication, uMainForm;
// Destruction steps
// =================
// 1. FormCloseQuery sets CanClose to FALSE calls TChromium.CloseBrowser which
// triggers the TChromium.OnClose event.
// 2. TChromium.OnClose sends a CEFBROWSER_DESTROY message to destroy CEFWindowParent1
// in the main thread, which triggers the TChromium.OnBeforeClose event.
// 3. TChromium.OnBeforeClose sets FCanClose := True and sends WM_CLOSE to the form.
procedure TChildForm.AfterConstruction;
begin
inherited AfterConstruction;
CreateHandle;
CEFWindowParent1.CreateHandle;
end;
function TChildForm.CreateClientHandler(var windowInfo : TCefWindowInfo;
var client : ICefClient;
const targetFrameName : string;
const popupFeatures : TCefPopupFeatures) : boolean;
var
TempRect : TRect;
begin
if CEFWindowParent1.HandleAllocated and
Chromium1.CreateClientHandler(client, False) then
begin
Result := True;
FPopupFeatures := popupFeatures;
TempRect := CEFWindowParent1.ClientRect;
if (FPopupFeatures.widthset <> 0) then TempRect.Right := max(FPopupFeatures.width, 100);
if (FPopupFeatures.heightset <> 0) then TempRect.Bottom := max(FPopupFeatures.height, 100);
WindowInfoAsChild(windowInfo, CEFWindowParent1.Handle, TempRect, '');
end
else
Result := False;
end;
function TChildForm.CreateBrowser(const aHomepage : string) : boolean;
begin
Chromium1.DefaultURL := aHomepage;
Result := Chromium1.CreateBrowser(CEFWindowParent1);
end;
procedure TChildForm.ApplyPopupFeatures;
begin
if (FPopupFeatures.xset <> 0) then Chromium1.SetFormLeftTo(FPopupFeatures.x);
if (FPopupFeatures.yset <> 0) then Chromium1.SetFormTopTo(FPopupFeatures.y);
if (FPopupFeatures.widthset <> 0) then Chromium1.ResizeFormWidthTo(FPopupFeatures.width);
if (FPopupFeatures.heightset <> 0) then Chromium1.ResizeFormHeightTo(FPopupFeatures.height);
end;
procedure TChildForm.Chromium1AfterCreated(Sender: TObject; const browser: ICefBrowser);
begin
FBrowserWasCreated := True;
end;
procedure TChildForm.Chromium1BeforeClose(Sender: TObject; const browser: ICefBrowser);
begin
FCanClose := True;
PostMessage(Handle, WM_CLOSE, 0, 0);
end;
procedure TChildForm.Chromium1BeforePopup( Sender : TObject;
const browser : ICefBrowser;
const frame : ICefFrame;
const targetUrl : ustring;
const targetFrameName : ustring;
targetDisposition : TCefWindowOpenDisposition;
userGesture : Boolean;
const popupFeatures : TCefPopupFeatures;
var windowInfo : TCefWindowInfo;
var client : ICefClient;
var settings : TCefBrowserSettings;
var extra_info : ICefDictionaryValue;
var noJavascriptAccess : Boolean;
var Result : Boolean);
begin
Result := not(TMainForm(Owner).DoOnBeforePopup(windowInfo, client, targetFrameName, popupFeatures, targetDisposition));
end;
procedure TChildForm.Chromium1OpenUrlFromTab( Sender : TObject;
const browser : ICefBrowser;
const frame : ICefFrame;
const targetUrl : ustring;
targetDisposition : TCefWindowOpenDisposition;
userGesture : Boolean;
out Result : Boolean);
begin
Result := not(TMainForm(Owner).DoOpenUrlFromTab(targetUrl, targetDisposition));
end;
procedure TChildForm.Chromium1Close(Sender: TObject; const browser: ICefBrowser; var aAction : TCefCloseBrowserAction);
begin
PostMessage(Handle, CEF_DESTROY, 0, 0);
aAction := cbaDelay;
end;
procedure TChildForm.Chromium1TitleChange(Sender: TObject; const browser: ICefBrowser; const title: ustring);
begin
try
FCriticalSection.Acquire;
FTitle := title;
finally
FCriticalSection.Release;
PostMessage(Handle, CEF_UPDATECAPTION, 0, 0);
end;
end;
function TChildForm.GetInitialized : boolean;
begin
Result := Chromium1.Initialized;
end;
procedure TChildForm.WMMove(var aMessage : TWMMove);
begin
inherited;
if (Chromium1 <> nil) then Chromium1.NotifyMoveOrResizeStarted;
end;
procedure TChildForm.WMMoving(var aMessage : TMessage);
begin
inherited;
if (Chromium1 <> nil) then Chromium1.NotifyMoveOrResizeStarted;
end;
procedure TChildForm.WMEnterMenuLoop(var aMessage: TMessage);
begin
inherited;
if (aMessage.wParam = 0) and (GlobalCEFApp <> nil) then GlobalCEFApp.OsmodalLoop := True;
end;
procedure TChildForm.WMExitMenuLoop(var aMessage: TMessage);
begin
inherited;
if (aMessage.wParam = 0) and (GlobalCEFApp <> nil) then GlobalCEFApp.OsmodalLoop := False;
end;
procedure TChildForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;
procedure TChildForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if FBrowserWasCreated then
begin
CanClose := FCanClose;
if not(FClosing) then
begin
FClosing := True;
Visible := False;
Chromium1.CloseBrowser(True);
end;
end
else
CanClose := True;
end;
procedure TChildForm.FormCreate(Sender: TObject);
begin
FCriticalSection := TCriticalSection.Create;
FBrowserWasCreated := False;
FCanClose := False;
FClosing := False;
end;
procedure TChildForm.FormDestroy(Sender: TObject);
begin
FCriticalSection.Free;
if FBrowserWasCreated and TMainForm(Owner).HandleAllocated then
PostMessage(TMainForm(Owner).Handle, CEF_CHILDDESTROYED, 0, 0);
end;
procedure TChildForm.BrowserDestroyMsg(var aMessage : TMessage);
begin
CEFWindowParent1.Free;
end;
procedure TChildForm.BrowserUpdateCaptionMsg(var aMessage : TMessage);
begin
try
FCriticalSection.Acquire;
Caption := FTitle;
finally
FCriticalSection.Release;
end;
end;
end.

View File

@ -1,62 +1,66 @@
object MainForm: TMainForm
Left = 357
Height = 704
Top = 89
Width = 991
Left = 0
Top = 0
Caption = 'Initializing. Please, wait...'
ClientHeight = 704
ClientHeight = 703
ClientWidth = 991
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
Position = poScreenCenter
OnCloseQuery = FormCloseQuery
OnCreate = FormCreate
OnDestroy = FormDestroy
OnShow = FormShow
Position = poScreenCenter
LCLVersion = '2.0.6.0'
PixelsPerInch = 96
object BrowserPageCtrl: TPageControl
Left = 34
Height = 704
Left = 32
Top = 0
Width = 957
Width = 959
Height = 703
Align = alClient
TabOrder = 0
TabWidth = 150
end
object ButtonPnl: TPanel
Left = 0
Height = 704
Top = 0
Width = 34
Width = 32
Height = 703
Align = alLeft
BevelOuter = bvNone
ClientHeight = 704
ClientWidth = 34
Enabled = False
TabOrder = 1
object AddTabBtn: TSpeedButton
Left = 4
Height = 26
Top = 4
Left = 1
Top = 1
Width = 26
Height = 26
Caption = '+'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -24
Font.Name = 'Arial Black'
OnClick = AddTabBtnClick
Font.Style = []
ParentFont = False
OnClick = AddTabBtnClick
end
object RemoveTabBtn: TSpeedButton
Left = 4
Height = 26
Top = 33
Left = 1
Top = 30
Width = 26
Height = 26
Caption = '−'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -24
Font.Name = 'Arial Black'
OnClick = RemoveTabBtnClick
Font.Style = []
ParentFont = False
OnClick = RemoveTabBtnClick
end
end
end

View File

@ -44,13 +44,21 @@ unit uMainForm;
interface
uses
LCLIntf, LCLType, LMessages, Messages, SysUtils, Variants, Classes, Graphics,
{$IFDEF DELPHI16_UP}
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, System.SyncObjs,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.ToolWin, Vcl.Buttons, Vcl.ExtCtrls,
{$ELSE}
LCLIntf, LCLType, LMessages, Messages, SysUtils, Variants, Classes, Graphics, SyncObjs,
Controls, Forms, Dialogs, ComCtrls, ToolWin, Buttons, ExtCtrls,
uCEFApplication, uCEFTypes, uCEFConstants;
{$ENDIF}
uCEFApplication, uCEFInterfaces, uCEFTypes, uCEFConstants, uChildForm, uBrowserTab;
const
CEF_INITIALIZED = WM_APP + $100;
CEF_DESTROYTAB = WM_APP + $101;
CEF_INITIALIZED = WM_APP + $A50;
CEF_DESTROYTAB = WM_APP + $A51;
CEF_CREATENEXTCHILD = WM_APP + $A52;
CEF_CREATENEXTTAB = WM_APP + $A53;
CEF_CHILDDESTROYED = WM_APP + $A54;
HOMEPAGE_URL = 'https://www.google.com';
DEFAULT_TAB_CAPTION = 'New tab';
@ -68,28 +76,44 @@ type
procedure FormShow(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure FormDestroy(Sender: TObject);
protected
// Variables to control when can we destroy the form safely
FCanClose : boolean;
FClosing : boolean;
FLastTabID : cardinal; // Used by NextTabID to generate unique tab IDs
FHiddenTab : TBrowserTab;
FChildForm : TChildForm;
FCriticalSection : TCriticalSection;
FCanClose : boolean;
FClosing : boolean; // Set to True in the CloseQuery event.
FLastTabID : cardinal; // Used by NextTabID to generate unique tab IDs
FPendingURL : string;
function GetNextTabID : cardinal;
function GetPopupChildCount : integer;
function GetBrowserTabCount : integer;
procedure EnableButtonPnl;
function CloseAllTabs : boolean;
function CloseAllBrowsers : boolean;
procedure CloseTab(aIndex : integer);
procedure CreateHiddenBrowsers;
procedure CEFInitializedMsg(var aMessage : TMessage); message CEF_INITIALIZED;
procedure DestroyTabMsg(var aMessage : TMessage); message CEF_DESTROYTAB;
procedure CreateNextChildMsg(var aMessage : TMessage); message CEF_CREATENEXTCHILD;
procedure CreateNextTabMsg(var aMessage : TMessage); message CEF_CREATENEXTTAB;
procedure ChildDestroyedMsg(var aMessage : TMessage); message CEF_CHILDDESTROYED;
procedure WMMove(var aMessage : TWMMove); message WM_MOVE;
procedure WMMoving(var aMessage : TMessage); message WM_MOVING;
procedure WMEnterMenuLoop(var aMessage: TMessage); message WM_ENTERMENULOOP;
procedure WMExitMenuLoop(var aMessage: TMessage); message WM_EXITMENULOOP;
procedure WMQueryEndSession(var aMessage: TWMQueryEndSession); message WM_QUERYENDSESSION;
property NextTabID : cardinal read GetNextTabID;
property NextTabID : cardinal read GetNextTabID;
property PopupChildCount : integer read GetPopupChildCount;
property BrowserTabCount : integer read GetBrowserTabCount;
public
function DoOnBeforePopup(var windowInfo : TCefWindowInfo; var client : ICefClient; const targetFrameName : string; const popupFeatures : TCefPopupFeatures; targetDisposition : TCefWindowOpenDisposition) : boolean;
function DoOpenUrlFromTab(const targetUrl : string; targetDisposition : TCefWindowOpenDisposition) : boolean;
end;
var
@ -101,8 +125,6 @@ implementation
{$R *.lfm}
uses
uBrowserTab;
// This demo shows how to use a TPageControl with TFrames that include
// CEF4Delphi browsers.
@ -129,14 +151,38 @@ uses
// event which will be used in TBrowserTab to send a CEF_DESTROYTAB message
// to the main form to free the tab.
// This demo also uses custom forms to open popup browsers in the same way as
// the PopupBrowser2 demo. Please, read the code comments in that demo for all
// details about handling the custom child forms.
// Additionally, this demo also creates new tabs when a browser triggers the
// TChromium.OnBeforePopup event.
// VCL components *MUST* be created and destroyed in the main thread but CEF
// executes the TChromium.OnBeforePopup in a different thread.
// For this reason this demo creates a hidden popup form (TChildForm) and a
// hidden TBrowserTab in case CEF needs to show a popup window.
// TChromium.OnBeforePopup calls TMainForm.DoOnBeforePopup to handle all the
// events in the same place.
// TMainForm.DoOnBeforePopup will call CreateClientHandler to initialize some
// parameters and create the new ICefClient using the hidden form or tab.
// After that, it sends a custom message to show the popup form or tab and create
// a new one.
// To close safely this demo you must close all the browser tabs first following
// this steps :
//
// 1. FormCloseQuery sets CanClose to FALSE and calls CloseAllTabs and FClosing
// 1. FormCloseQuery sets CanClose to FALSE and calls CloseAllBrowsers and FClosing
// is set to TRUE.
// 2. Each tab will send a CEF_DESTROYTAB message to free that tab.
// 3. When TPageControl has no tabs then we can set FCanClose to TRUE and send a
// WM_CLOSE to the main form to close the application.
// 2. Each tab will send a CEF_DESTROYTAB message to the main form to free that tab.
// 3. Each child form will send a CEF_CHILDDESTROYED message to the main form.
// 3. When TPageControl has no tabs and all the child forms are also closed then we
// can set FCanClose to TRUE and send a WM_CLOSE message to the main form to
// close the application.
procedure GlobalCEFApp_OnContextInitialized;
begin
@ -148,7 +194,12 @@ procedure CreateGlobalCEFApp;
begin
GlobalCEFApp := TCefApplication.Create;
GlobalCEFApp.cache := 'cache';
GlobalCEFApp.EnablePrintPreview := True;
GlobalCEFApp.OnContextInitialized := GlobalCEFApp_OnContextInitialized;
// This is a workaround for the CEF4Delphi issue #324 :
// https://github.com/salvadordf/CEF4Delphi/issues/324
GlobalCEFApp.DisableFeatures := 'WinUseBrowserSpellChecker';
end;
procedure TMainForm.EnableButtonPnl;
@ -158,7 +209,7 @@ begin
ButtonPnl.Enabled := True;
Caption := 'Tabbed Browser 2';
cursor := crDefault;
if (BrowserPageCtrl.PageCount = 0) then AddTabBtn.Click;
if (BrowserTabCount = 0) then AddTabBtn.Click;
end;
end;
@ -168,6 +219,44 @@ begin
Result := FLastTabID;
end;
function TMainForm.GetPopupChildCount : integer;
var
i : integer;
TempForm : TCustomForm;
begin
Result := 0;
i := pred(screen.CustomFormCount);
while (i >= 0) do
begin
// Only count the fully initialized child forms and not the one waiting to be used.
TempForm := screen.CustomForms[i];
if (TempForm is TChildForm) and
TChildForm(TempForm).Initialized then
inc(Result);
dec(i);
end;
end;
function TMainForm.GetBrowserTabCount : integer;
var
i : integer;
begin
Result := 0;
i := pred(BrowserPageCtrl.PageCount);
while (i >= 0) do
begin
// Only count the fully initialized browser tabs and not the one waiting to be used.
if TBrowserTab(BrowserPageCtrl.Pages[i]).Initialized then
inc(Result);
dec(i);
end;
end;
procedure TMainForm.AddTabBtnClick(Sender: TObject);
var
TempNewTab : TBrowserTab;
@ -183,6 +272,7 @@ end;
procedure TMainForm.CEFInitializedMsg(var aMessage : TMessage);
begin
EnableButtonPnl;
CreateHiddenBrowsers;
end;
procedure TMainForm.DestroyTabMsg(var aMessage : TMessage);
@ -190,6 +280,8 @@ var
i : integer;
TempTab : TBrowserTab;
begin
// Every tab sends a CEF_DESTROYTAB message when its browser has been destroyed
// and then we can destroy the TBrowserTab control.
i := 0;
while (i < BrowserPageCtrl.PageCount) do
begin
@ -204,13 +296,74 @@ begin
inc(i);
end;
if FClosing and (BrowserPageCtrl.PageCount = 0) then
// Here we check if this was the last initialized browser to close the
// application safely.
if FClosing and (PopupChildCount = 0) and (BrowserTabCount = 0) then
begin
FCanClose := True;
PostMessage(Handle, WM_CLOSE, 0, 0);
end;
end;
procedure TMainForm.ChildDestroyedMsg(var aMessage : TMessage);
begin
// Every destroyed child form sends a CEF_CHILDDESTROYED message
// Here we check if this was the last initialized browser to close the
// application safely.
if FClosing and (PopupChildCount = 0) and (BrowserTabCount = 0) then
begin
FCanClose := True;
PostMessage(Handle, WM_CLOSE, 0, 0);
end;
end;
procedure TMainForm.CreateNextChildMsg(var aMessage : TMessage);
begin
try
FCriticalSection.Acquire;
if (FChildForm <> nil) then
begin
if (aMessage.lParam <> 0) then
FChildForm.CreateBrowser(FPendingURL)
else
FChildForm.ApplyPopupFeatures;
FChildForm.Show;
end;
FChildForm := TChildForm.Create(self);
finally
FCriticalSection.Release;
end;
end;
procedure TMainForm.CreateNextTabMsg(var aMessage : TMessage);
begin
try
FCriticalSection.Acquire;
if (FHiddenTab <> nil) then
begin
FHiddenTab.TabVisible := True;
FHiddenTab.PageIndex := pred(BrowserPageCtrl.PageCount);
if (aMessage.lParam <> 0) then
FHiddenTab.CreateBrowser(FPendingURL);
BrowserPageCtrl.ActivePageIndex := FHiddenTab.PageIndex;
end;
FHiddenTab := TBrowserTab.Create(self, NextTabID, DEFAULT_TAB_CAPTION);
FHiddenTab.PageControl := BrowserPageCtrl;
FHiddenTab.TabVisible := False;
FHiddenTab.CreateFrame;
finally
FCriticalSection.Release;
end;
end;
procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
CanClose := FCanClose;
@ -220,7 +373,7 @@ begin
FClosing := True;
ButtonPnl.Enabled := False;
if not(CloseAllTabs) then
if not(CloseAllBrowsers) then
begin
FCanClose := True;
PostMessage(Handle, WM_CLOSE, 0, 0);
@ -230,33 +383,68 @@ end;
procedure TMainForm.FormCreate(Sender: TObject);
begin
FCanClose := False;
FClosing := False;
FLastTabID := 0;
FCanClose := False;
FClosing := False;
FLastTabID := 0;
FChildForm := nil;
FHiddenTab := nil;
FCriticalSection := TCriticalSection.Create;
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
FreeAndNil(FCriticalSection);
end;
procedure TMainForm.FormShow(Sender: TObject);
begin
if (GlobalCEFApp <> nil) and GlobalCEFApp.GlobalContextInitialized then
EnableButtonPnl;
begin
EnableButtonPnl;
CreateHiddenBrowsers;
end;
end;
procedure TMainForm.RemoveTabBtnClick(Sender: TObject);
begin
// Call TBrowserTab.CloseBrowser in the active tab
CloseTab(BrowserPageCtrl.ActivePageIndex);
end;
function TMainForm.CloseAllTabs : boolean;
function TMainForm.CloseAllBrowsers : boolean;
var
i : integer;
i : integer;
TempForm : TCustomForm;
TempTab : TBrowserTab;
begin
Result := False;
i := pred(BrowserPageCtrl.PageCount);
i := pred(screen.CustomFormCount);
while (i >= 0) do
begin
TBrowserTab(BrowserPageCtrl.Pages[i]).CloseBrowser;
Result := True;
TempForm := screen.CustomForms[i];
if (TempForm is TChildForm) and
TChildForm(TempForm).Initialized and
not(TChildForm(TempForm).Closing) then
begin
PostMessage(TempForm.Handle, WM_CLOSE, 0, 0);
Result := True;
end;
dec(i);
end;
i := pred(BrowserPageCtrl.PageCount);
while (i >= 0) do
begin
TempTab := TBrowserTab(BrowserPageCtrl.Pages[i]);
if TempTab.Initialized and not(TempTab.Closing) then
begin
TempTab.CloseBrowser;
Result := True;
end;
dec(i);
end;
end;
@ -267,6 +455,26 @@ begin
TBrowserTab(BrowserPageCtrl.Pages[aIndex]).CloseBrowser;
end;
procedure TMainForm.CreateHiddenBrowsers;
begin
try
FCriticalSection.Acquire;
if (FChildForm = nil) then
FChildForm := TChildForm.Create(self);
if (FHiddenTab = nil) then
begin
FHiddenTab := TBrowserTab.Create(self, NextTabID, DEFAULT_TAB_CAPTION);
FHiddenTab.PageControl := BrowserPageCtrl;
FHiddenTab.TabVisible := False;
FHiddenTab.CreateFrame;
end;
finally
FCriticalSection.Release;
end;
end;
procedure TMainForm.WMMove(var aMessage : TWMMove);
var
i : integer;
@ -311,4 +519,73 @@ begin
GlobalCEFApp.OsmodalLoop := False;
end;
procedure TMainForm.WMQueryEndSession(var aMessage: TWMQueryEndSession);
begin
// We return False (0) to close the browser correctly while we can.
// This is not what Microsoft recommends doing when an application receives
// WM_QUERYENDSESSION but at least we avoid TApplication calling HALT when
// it receives WM_ENDSESSION.
// The CEF subprocesses may receive WM_QUERYENDSESSION and WM_ENDSESSION
// before the main process and they may crash before closing the main form.
aMessage.Result := 0;
PostMessage(Handle, WM_CLOSE, 0, 0);
end;
function TMainForm.DoOnBeforePopup(var windowInfo : TCefWindowInfo;
var client : ICefClient;
const targetFrameName : string;
const popupFeatures : TCefPopupFeatures;
targetDisposition : TCefWindowOpenDisposition) : boolean;
begin
try
FCriticalSection.Acquire;
case targetDisposition of
WOD_NEW_FOREGROUND_TAB,
WOD_NEW_BACKGROUND_TAB :
Result := (FHiddenTab <> nil) and
FHiddenTab.CreateClientHandler(windowInfo, client, targetFrameName, popupFeatures) and
PostMessage(Handle, CEF_CREATENEXTTAB, 0, ord(False));
WOD_NEW_WINDOW,
WOD_NEW_POPUP :
Result := (FChildForm <> nil) and
FChildForm.CreateClientHandler(windowInfo, client, targetFrameName, popupFeatures) and
PostMessage(Handle, CEF_CREATENEXTCHILD, 0, ord(False));
else Result := False;
end;
finally
FCriticalSection.Release;
end;
end;
function TMainForm.DoOpenUrlFromTab(const targetUrl : string;
targetDisposition : TCefWindowOpenDisposition) : boolean;
begin
try
FCriticalSection.Acquire;
case targetDisposition of
WOD_NEW_FOREGROUND_TAB,
WOD_NEW_BACKGROUND_TAB :
begin
FPendingURL := targetUrl;
Result := PostMessage(Handle, CEF_CREATENEXTTAB, 0, ord(True));
end;
WOD_NEW_WINDOW,
WOD_NEW_POPUP :
begin
FPendingURL := targetUrl;
Result := PostMessage(Handle, CEF_CREATENEXTCHILD, 0, ord(True));
end
else Result := False;
end;
finally
FCriticalSection.Release;
end;
end;
end.

View File

@ -21,7 +21,7 @@
</CompilerOptions>
<Description Value="CEF4Delphi is an open source project created by Salvador Díaz Fau to embed Chromium-based browsers in applications made with Delphi or Lazarus/FPC."/>
<License Value="MPL 1.1"/>
<Version Major="91" Minor="1" Release="20"/>
<Version Major="91" Minor="1" Release="21"/>
<Files Count="202">
<Item1>
<Filename Value="..\source\uCEFAccessibilityHandler.pas"/>

View File

@ -66,13 +66,13 @@ uses
const
CEF_SUPPORTED_VERSION_MAJOR = 91;
CEF_SUPPORTED_VERSION_MINOR = 1;
CEF_SUPPORTED_VERSION_RELEASE = 20;
CEF_SUPPORTED_VERSION_RELEASE = 21;
CEF_SUPPORTED_VERSION_BUILD = 0;
CEF_CHROMEELF_VERSION_MAJOR = 91;
CEF_CHROMEELF_VERSION_MINOR = 0;
CEF_CHROMEELF_VERSION_RELEASE = 4472;
CEF_CHROMEELF_VERSION_BUILD = 101;
CEF_CHROMEELF_VERSION_BUILD = 114;
{$IFDEF MSWINDOWS}
LIBCEF_DLL = 'libcef.dll';

View File

@ -2,9 +2,9 @@
"UpdateLazPackages" : [
{
"ForceNotify" : true,
"InternalVersion" : 305,
"InternalVersion" : 306,
"Name" : "cef4delphi_lazarus.lpk",
"Version" : "91.1.20.0"
"Version" : "91.1.21.0"
}
],
"UpdatePackageData" : {