Search code examples
c++delphichromiumchromium-embedded

chromium embedded framework


How to make real open new tabs in the same form, using tabs or simply the same cef component or create new one, not that is the important part. The important thing is what the usage of

procedure OnBeforePopup ...
  ...
  begin
  Return:= true;
  TChromium1.LoadURL(target_url);
end; 

not work in some cases like in real browser (and I think this is not real dispatch to the new tab).

In TWebBrowser I don't have such problem, that code work well:

  procedure TForm1.WebBrowser1NewWindow2(Sender: TObject;
  var ppDisp: IDispatch; var Cancel: WordBool);
  var NewWindow: TForm1;
  begin
    NewWindow := TForm1.Create(self);
    NewWindow.Show;
   ppDisp := NewWindow.Webbrowser1.DefaultDispatch;
  end;

How to make real dispatch?

In OnBeforePopup exists const target_disposition . How to change it(target_disposition) to current tab?


Solution

  • The price you pay for a better browser is more time trying to embed it in your app. In general, the TWebBrowser component is much easier to use from the developer point of view but your users will have a much worse experience.

    Opening new tabs or forms the right way using CEF is one of those features that are much more complicated.

    This is why I added the PopupBrowser2 demo in CEF4Delphi and OldCEF4Delphi.

    You can't change a CONST parameter. I would recommend you to follow what CEF3 says about this event to create a new child browser.

    The CEF3 code comments for the OnBeforePopup event are these :

    ///
    // Called on the UI thread before a new popup browser is created. The
    // |browser| and |frame| values represent the source of the popup request. The
    // |target_url| and |target_frame_name| values indicate where the popup
    // browser should navigate and may be NULL if not specified with the request.
    // The |target_disposition| value indicates where the user intended to open
    // the popup (e.g. current tab, new tab, etc). The |user_gesture| value will
    // be true (1) if the popup was opened via explicit user gesture (e.g.
    // clicking a link) or false (0) if the popup opened automatically (e.g. via
    // the DomContentLoaded event). The |popupFeatures| structure contains
    // additional information about the requested popup window. To allow creation
    // of the popup browser optionally modify |windowInfo|, |client|, |settings|
    // and |no_javascript_access| and return false (0). To cancel creation of the
    // popup browser return true (1). The |client| and |settings| values will
    // default to the source browser's values. If the |no_javascript_access| value
    // is set to false (0) the new browser will not be scriptable and may not be
    // hosted in the same renderer process as the source browser. Any
    // modifications to |windowInfo| will be ignored if the parent browser is
    // wrapped in a cef_browser_view_t. Popup browser creation will be canceled if
    // the parent browser is destroyed before the popup browser creation completes
    // (indicated by a call to OnAfterCreated for the popup browser).
    ///
    

    The challenge here is that CEF3 may use a different thread than the main thread to execute all the events and you would like to create VCL components when this event is triggered.

    DCEF3 uses a different thread if you set CEF_MULTI_THREADED_MESSAGE_LOOP in cef.inc. CEF4Delphi uses a different thread if GlobalCEFApp.MultiThreadedMessageLoop is True, which is the default value because it's the recommended setting by CEF3 for Windows apps.

    As you know, if you create and destroy VCL components in different threads you will have problems.

    This forces you to create a hidden popup form just in case this event is triggered. As you can see in PopupBrowser2, there's a hidden FChildForm that is created in the main thread and outside this event.

    Later, when the OnBeforePopup is executed, the demo calls CreateClientHandler to set the "windowInfo" and "client" event parameters with the windowInfo and client used by FChildForm.

    If you want to use tabs, you would also need to create a hidden tab.

    You could also try to unset CEF_MULTI_THREADED_MESSAGE_LOOP in DCEF3 or set GlobalCEFApp.MultiThreadedMessageLoop to False in CEF4Delphi but then you would need to use an "external pump". See the SimpleExternalPumpBrowser demo for more details.