Disclosure Statement: This site contains affiliate links, which means that I may receive a commission if you make a purchase using these links. As an eBay Partner, I earn from qualifying purchases.

Cef4D on Mac with Fpc - Help needed

martin_fr
Posts: 30
Joined: Wed Jan 27, 2021 5:56 pm

Re: Cef4D on Mac with Fpc - Help needed

Post by martin_fr »

salvadordf wrote: Wed Feb 17, 2021 10:25 am I see that you've moved the MacOS demo to a new directory and you added support for other OSs.

CEF and Chromium have very different ways of doing things depending on the OS and widgetset used.
A few examples would be :
  • Unique app bundles for Mac.
  • Different ways to resize, show and hide the internal browser view in Windows, Linux and probably MacOS.
  • Different destruction steps.
  • Different ways to handle the web page image in OSR mode.
  • etc.
Having all that in one demo is possible but I would recommend that we focus on a demo only for MacOS because adding support for other OSs only takes time away from having a full MacOS demo.
In principal a demo just for Mac would be fine. However the differences are very small.
The combined demo has, but a very few IFDEF. So with the existing of that combined demo, I am not sure if there really still is the need for the Mac only demo.

And about the combined demo: Many Lazarus users write their apps, and cross compile them. Mac may not be the most frequented target, but Linux+Win is probably common.
Those users need a demo, how to write code that compiles for all required targets. So IMHO a good idea.

I am even working on a subclassed component, that will handle most of the stuff that is currently in the user code (size events, close events, start in timer, ....). I got it working on my machines already. But more on that later.
salvadordf wrote: Wed Feb 17, 2021 10:25 am In general, CEF is more complicated to use than TWebBrowser and I decided to create more demos that were easier to understand and maintain.

Most of the current demos (not all) show how to do a reduced set of things and this should make it easier for the developers to take the code they need from the demos to their own applications. Small changes in the CEF API, which are not infrequent, are also easier to detect and fix this way.
The demo only shows the TCefLinkedParentWindow.
And it only shows ExternalPump.

So on Linux and Win it can be run with the threaded message-loop too.

The only in consequent bit is that it mixes External/Separate Subprocess and build in.
- That is, on Mac the SubProcess must be a different exe (actually 4 copies of one different exe)
- But on Windows and Linux the demo uses the main-project as subprocess. Which indeed adds a few lines of code.

For Win/Linux the demo includes (commented) the code for using a separate exe. That is one single line to uncomment. (And a few lines that could get commented instead, but are kept)
This is the one thing, that could have been put into a separate demo.

On the other hand for me the amount of demos is rather confusing (to some part still is). There is no (or I have not found) detail on where the demos differ.
Even demos with the same name, do not do the same thing. ExternalPump for Linux uses TCefLinkedWindowParent but for Windos it uses TCefWindowParent. That is despite the former works on windows too. The latter exists on Windows only.

So as a user I can not even compare the examples for target-diffs. Let alone that even equal examples, over time got more and more different. Just code moved to diff locations. Or changes that could work on all targets applied to only one (IIRC, need doublecheck).



salvadordf wrote: Wed Feb 17, 2021 10:25 am About the shutdown issues, there are a couple of suggestions :
  • Windows and Linux have slightly different destruction steps that need to be implemented in order to avoid shutdown issues. As you can see in the "ExternalMessageBrowser" demos, the TChromium.OnClose event sets a different value for the aAction parameter because the Windows demo needs to destroy CEFWindowParent1. That is necessary to receive the TChromium.OnBeforeClose event and then close the main form. The Linux demo in the other hand doesn't need all that and you can set aAction to cbaClose to continue closing the browser. I would have to learn a lot more about MacOS and check the CEF sources to know what MacOS needs for that event in a Lazarus demo.
salvadordf wrote: Wed Feb 17, 2021 10:25 am [*]The other "ExternalMessageBrowser" demos have some extra code in the LPR file to free the main application form and call GlobalCEFWorkScheduler.StopScheduler before the DestroyGlobalCEFApp and DestroyGlobalCEFWorkScheduler calls. This is also necessary to avoid shutdown issues. https://github.com/salvadordf/CEF4Delphi/blob/master/demos/Lazarus_Linux/ExternalPumpBrowser/ExternalPumpBrowser.lpr
[/list]
I missed the GlobalCEFWorkScheduler.StopScheduler
I will take a look.

I moved as much of the lpr code as possible into other units. This is to avoid the user having to edit the lpr file to much.

The only thing still needed in the lpr is one unit in the uses clause, that has to be before "Interfaces" so it can intercept the start up, before the LCL widgetset starts. And create the CEF app.

I do not know for sure, but does that order (cef vs widgetset) affect the subprocess only, or also the main app?
Because if it is subprocess only, and the user uses AppHelper, then they would need no change to the lpr at all.
martin_fr
Posts: 30
Joined: Wed Jan 27, 2021 5:56 pm

Re: Cef4D on Mac with Fpc - Help needed

Post by martin_fr »

Thanks for the idea with the cbaDelay vs cbaClose. But it does not seem to help (Yet I can not be sure my way of "closing the handle" was correct).

Looking at the error I get (and having talked to some folks) it seems the Lazarus Widgetset needs to implement the "AppProtocol", and then a handler needs to be added. Someone I know will try and see what can be done.

---------------------
In the meantime some more questions.

TCEFWinControl
implements UpdateSize but only for windows.

TCEFLinkedWindowParent
adds implementation of UpdateSize for Linux
adds implementation of SetVisible for Linux
That can only be added here, because TChromium is needed.

TChromiumWindow
has only what TCEFWinControl has

===> Should TChromiumWindow not have both the methods that TCEFLinkedWindowParent has?

TChromiumWindow and TCEFLinkedWindowParent also have nearly identical WndProc
The only diff is in

Code: Select all

    WM_SETFOCUS:
      begin
        if FUseSetFocus and (FChromium <> nil) then
          FChromium.SetFocus(True)
TCEFLinkedWindowParent does not have the test for FUseSetFocus
(that could be solved with a virtual method returning the value (defaults to true))

===> It does occur do me that the 2 classes, might benefit from a shared base class
TChromiumWindow => TCEFChromiumWinControl =>TCEFWinControl
TCEFLinkedWindowParent => TCEFChromiumWinControl =>TCEFWinControl

just my 2 cents.

---------------------
TChromiumWindow also has NotifyMoveOrResizeStarted
This appears for all Wigdetsets?

If this is used is UpdateSize still needed?
martin_fr
Posts: 30
Joined: Wed Jan 27, 2021 5:56 pm

Re: Cef4D on Mac with Fpc - Help needed

Post by martin_fr »

Sorry lots of questions today....

As indicated I moved a lot of the control code into a new component. (No need to pull it yet, lets first answer a few question)
https://github.com/salvadordf/CEF4Delphi/compare/master...User4martin:fpc-work-3

All except the menu-modal stuff is gone from user code.

It works on Win/Linux/Mac same as the other demo app.
I do not have Delphi, but maybe you want to see how much of it can be done in Delphi? (Most should work, but I do not know about RealizeBounds)

----------
Also I would like to look at getting rid of the "reintroduce" bits.

If it is ok for you, I would make some changes to TChromiumWindow. Probably make some of the methods virtual.
Or extract a base class, without them. Not sure yet.
User avatar
salvadordf
Posts: 4016
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: Cef4D on Mac with Fpc - Help needed

Post by salvadordf »

martin_fr wrote: Wed Feb 17, 2021 10:20 pm In principal a demo just for Mac would be fine. However the differences are very small.
The combined demo has, but a very few IFDEF. So with the existing of that combined demo, I am not sure if there really still is the need for the Mac only demo.
It's not only a question of need. It's also a question of stamina.
The path you've chosen with a combined demo is harder and it will take longer.
I will only be able to help you explaining concepts but not with code and my greatest fear is that you get tired before having a complete MacOS demo.
martin_fr wrote: Wed Feb 17, 2021 10:20 pm Even demos with the same name, do not do the same thing. ExternalPump for Linux uses TCefLinkedWindowParent but for Windos it uses TCefWindowParent. That is despite the former works on windows too. The latter exists on Windows only.
So as a user I can not even compare the examples for target-diffs. Let alone that even equal examples, over time got more and more different. Just code moved to diff locations. Or changes that could work on all targets applied to only one (IIRC, need doublecheck).
This is mostly a consequence of the diferences between Widgetsets and OSs that I mentioned previously.
Besides, Linux support is relatively new in CEF4Delphi and some features are not implemented yet.

Something similar happened when I added Firemonkey support to CEF4Delphi. VCL and FMX are very different, the demos have big differences and they use different components in order to get a working browser with similar settings.

Anyway, if you prefer to do a combined demo that's fine with me. Undertand that I was just trying to make it easier for you. ;)
martin_fr wrote: Wed Feb 17, 2021 10:20 pm I do not know for sure, but does that order (cef vs widgetset) affect the subprocess only, or also the main app?
Because if it is subprocess only, and the user uses AppHelper, then they would need no change to the lpr at all.
The problem with the widgetset initialization affected Linux and not Windows.
Even when you don't use a "sandbox", Chromium will execute a function related to that feature that will cause problems when it detects more than one thread. That's why we have to call gtk_init after the CEF initialization for the main browser process only :
https://bitbucket.org/chromiumembedded/cef/src/8f5fdc1f9adb0aa81f9db4c3f0d74d08d554ccc5/tests/cefclient/cefclient_gtk.cc#lines-113

Initializing the widgetset is not necessary in the subprocesses because they don't have any GUI. In fact, it caused problems in the past :
https://github.com/salvadordf/CEF4Delphi/issues/139
martin_fr wrote: Thu Feb 18, 2021 12:24 am TCEFWinControl
implements UpdateSize but only for windows.

TCEFLinkedWindowParent
adds implementation of UpdateSize for Linux
adds implementation of SetVisible for Linux
That can only be added here, because TChromium is needed.

TChromiumWindow
has only what TCEFWinControl has

===> Should TChromiumWindow not have both the methods that TCEFLinkedWindowParent has?
I created TCEFLinkedWindowParent because its way to handle the focus is equivalent to what the official CEF sample application does.
TCEFWindowParent uses a simple WM_SETFOCUS message. This solution works fine and you can use it too with the same results.

However, Linux used a much different way to resize and set the browser visibility. In the previous Chromium version I had to use a CEF API function that only worked in the CEF UI thread to get a XDisplay pointer to be able to resize or set the visibility, and it was much easier to use a custom CEF task inside TChromium. That's why I used a TCEFLinkedWindowParent in Linux. In the current Chromium version things have changed a bit but replacing TCEFLinkedWindowParent would require adding extra code in each application so I decided to keep it.

Apparently, MacOS doesn't need any of this. Read the cefclient code comments in the CEF project :
https://bitbucket.org/chromiumembedded/cef/src/master/tests/cefclient/browser/browser_window_std_mac.mm
martin_fr wrote: Thu Feb 18, 2021 12:24 am TChromiumWindow also has NotifyMoveOrResizeStarted
This appears for all Wigdetsets?
Searching in the official CEF source code I only see NotifyMoveOrResizeStarted calls in Windows and GTK units.
martin_fr wrote: Thu Feb 18, 2021 12:33 am Sorry lots of questions today....
Don't worry. Ask anything you want.
martin_fr wrote: Thu Feb 18, 2021 12:33 am Also I would like to look at getting rid of the "reintroduce" bits.
I'm not aware of any issue related to "reintroduce" in FPC or Delphi.
Is there some performance penalty or incompatibility?
martin_fr wrote: Thu Feb 18, 2021 12:33 am If it is ok for you, I would make some changes to TChromiumWindow. Probably make some of the methods virtual.
Or extract a base class, without them. Not sure yet.
Please, remember that many users added modified versions of CEF4Delphi components into their applications.
That's why there're many virtual methods in TChromiumCore and all the fields are just "protected" and not "private".
User avatar
salvadordf
Posts: 4016
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: Cef4D on Mac with Fpc - Help needed

Post by salvadordf »

This is the main unit for mac in cefclient. The code comments explain a few things about initializing CEF and the widgetset :
https://bitbucket.org/chromiumembedded/cef/src/master/tests/cefclient/cefclient_mac.mm
martin_fr
Posts: 30
Joined: Wed Jan 27, 2021 5:56 pm

Re: Cef4D on Mac with Fpc - Help needed

Post by martin_fr »

salvadordf wrote: Thu Feb 18, 2021 5:53 pm I will only be able to help you explaining concepts but not with code and my greatest fear is that you get tired before having a complete MacOS demo.
Well, we will see. As I said currently I am having a college take a look at the crash. This is unfortunately in an area outside my experience (LCL cocoa widgetset).
I did find the cef_simple_mac.mm file. And it has some code that - for all any knows right now - needs to be translated.
So that is being looked at.

The final target, is to end up with some code that can be used for an app that will be compiled to Win,Linux and Mac (in that case, an add-on to the Lazarus IDE itself).
So therefore part of the goal is also to get code that runs on all 3 targets, with as little IFDEF (in user code) as possible.

Also if you have any request (like code formatting / naming convention) to keep the project unified, please say so, and I shall do my best.
salvadordf wrote: Thu Feb 18, 2021 5:53 pm
martin_fr wrote: Thu Feb 18, 2021 12:24 am So as a user I can not even compare the examples for target-diffs.
This is mostly a consequence of the diferences between Widgetsets and OSs that I mentioned previously.
Actually in one case, the problem was to a huge extend different order of the same methods. I had to re-order the methods, just to compare the files. Which then was possible.
salvadordf wrote: Thu Feb 18, 2021 5:53 pm Anyway, if you prefer to do a combined demo that's fine with me. Undertand that I was just trying to make it easier for you. ;)
I submitted a stripped down Mac-Only demo app.
I am not sure if it needs the WM_Move, etc. But they are called, and they do not seem to do harm. So I kept them. Removed the EnterMenuLoop stuff, and some Linux only code.

Still like to keep the "any_OS" demo. IMHO there are people (not just me) who could find it useful.
I will see, what other demos I might add in either category. Obviously Mac restricts to ExternalPump.

salvadordf wrote: Thu Feb 18, 2021 5:53 pm That's why we have to call gtk_init after the CEF initialization for the main browser process only :
https://bitbucket.org/chromiumembedded/cef/src/8f5fdc1f9adb0aa81f9db4c3f0d74d08d554ccc5/tests/cefclient/cefclient_gtk.cc#lines-113
Thanks, good to know the background.
The CEF documentation seems to have some gaps, to be filled by looking at the sources. Yet in the sources things can be a needle in the haystack. :)

=================================================================================================
salvadordf wrote: Thu Feb 18, 2021 5:53 pm Initializing the widgetset is not necessary in the subprocesses because they don't have any GUI. In fact, it caused problems in the past :
https://github.com/salvadordf/CEF4Delphi/issues/139
Of course. Though I was not aware of the issue.
- On Linux that is taken care by my Demo code
- On Mac (also Win,Linux if using AppHelper) this is also ok. Because AppHelper is compiled with widgetset "NoGui" - a dummy WS.
- On Windows I will take care of that. (Actually just need to enable "uses InitSubprocess" which is currently in "$IFDEF Linux".

That brings me to another topic. Though not sure yet, if I will actually do anything about it.
Currently, using only the code for the sub-process, includes units that relay on widgetset code (for other code in the unit).
So currently the AppHelper can not be just a Pascal "program" with no reference to "Interfaces" at all.
However fixing this, might mean to massively refactor the code.

=================================================================================================
salvadordf wrote: Thu Feb 18, 2021 5:53 pm
martin_fr wrote: Thu Feb 18, 2021 12:24 am TCEFLinkedWindowParent
adds implementation of UpdateSize for Linux
adds implementation of SetVisible for Linux
TChromiumWindow
has only what TCEFWinControl has

===> Should TChromiumWindow not have both the methods that TCEFLinkedWindowParent has?
I created TCEFLinkedWindowParent because its way to handle the focus is equivalent to what the official CEF sample application does.
TCEFWindowParent uses a simple WM_SETFOCUS message.
The above question was not so much about TCEFWindowParent vs TCEFLinkedWindowParent.
It was about the absence of UpdateSize / SetVisible in TChromiumWindow.

Just tested again. They are needed, or TChromiumWindow will not work on Linux.

I can submit a patch for that, but need to know what you are willing to accept.
My plan would be to introduce a new base class

Code: Select all

   TCEFChromiumWindow = class(TCEFWinControl)
and move shared code into that (including WndProc).
=> Of course keeping it 100% compatible with the existing declaration. (You have the last word, once it is done)

But if you rather have copy and pasted code in TChromiumWindow => your choice.

=================================================================================================
salvadordf wrote: Thu Feb 18, 2021 5:53 pm Apparently, MacOS doesn't need any of this. Read the cefclient code comments in the CEF project :
https://bitbucket.org/chromiumembedded/cef/src/master/tests/cefclient/browser/browser_window_std_mac.mm

Searching in the official CEF source code I only see NotifyMoveOrResizeStarted calls in Windows and GTK units.
Ok, well Mac currently does not do the UpdateSize/SetVisible => good to know that is correct.
NotifyMoveOrResized is called on all OS, and does not seem to harm Mac.

=================================================================================================
salvadordf wrote: Thu Feb 18, 2021 5:53 pm
martin_fr wrote: Thu Feb 18, 2021 12:33 am Also I would like to look at getting rid of the "reintroduce" bits.
I'm not aware of any issue related to "reintroduce" in FPC or Delphi.
Is there some performance penalty or incompatibility?
That relates to
https://github.com/User4martin/CEF4Delphi/compare/fpc-work-2c...User4martin:fpc-work-3

A new component, that includes a lot of the stuff that was done in the user's app code.

- RealizeBounds replaces all WM_MOVE/SIZE code.
- The timer for "CreateBroser() and Initialized" is now in the component too.
- Waiting for Destruction is in the component.

I currently called it TLazarusBrowserWindow. Better names welcome.

I do not have Delphi, so no idea how much of it works in Delphi. If you want to check that, and IFDEF the FPC only parts, the the component might be usable for Delphi too?
Let me know
salvadordf wrote: Thu Feb 18, 2021 5:53 pm Please, remember that many users added modified versions of CEF4Delphi components into their applications.
That's why there're many virtual methods in TChromiumCore and all the fields are just "protected" and not "private".
I will.
Probably just slapping a few "virtual" modifiers on the procedures that I "reintroduce" currently.
martin_fr
Posts: 30
Joined: Wed Jan 27, 2021 5:56 pm

Re: Cef4D on Mac with Fpc - Help needed

Post by martin_fr »

salvadordf wrote: Thu Feb 18, 2021 5:53 pm Initializing the widgetset is not necessary in the subprocesses because they don't have any GUI. In fact, it caused problems in the past :
https://github.com/salvadordf/CEF4Delphi/issues/139
Well just tested. That is all fine if you have a separate exe for the subprocess (AppHelper). And of course you can have that on any of the OS.

But, if on Windows, you use the same exe as Main- and Sub-process, then that is not possible.

TCefApplication.Create calls TCefApplication.UpdateDeviceScaleFactor
And on Windows, that will crash if the Widgetset is not yet initialized.

However the test for subprocess
if GlobalCEFApp.StartMainProcess then
requires the above code to be executed.
User avatar
salvadordf
Posts: 4016
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: Cef4D on Mac with Fpc - Help needed

Post by salvadordf »

The latest CEF4Delphi update added Linux support to TChromiumWindow and it has a Linux version of the SimpleBrowser demo.
I also removed old unused code from the Windows version of the SimpleBrowser demo.
martin_fr
Posts: 30
Joined: Wed Jan 27, 2021 5:56 pm

Re: Cef4D on Mac with Fpc - Help needed

Post by martin_fr »

salvadordf wrote: Thu Feb 18, 2021 5:53 pm Even when you don't use a "sandbox", Chromium will execute a function related to that feature that will cause problems when it detects more than one thread. That's why we have to call gtk_init after the CEF initialization for the main browser process only :
https://bitbucket.org/chromiumembedded/cef/src/8f5fdc1f9adb0aa81f9db4c3f0d74d08d554ccc5/tests/cefclient/cefclient_gtk.cc#lines-113
But the current example in demos/Lazarus_Linux/TinyBrowser2 does not follow that example.

It uses the normal "Interfaces" unit.

CreateWidgetSet is called during initialization of that unit. And that is before the main body of the .lpr file gets executed. So before the CefApplication is created and run.
martin_fr
Posts: 30
Joined: Wed Jan 27, 2021 5:56 pm

Re: Cef4D on Mac with Fpc - Help needed

Post by martin_fr »

You did place
function TChromiumWindow.GetChildWindowHandle : THandle;

in an IFDEF WINDOWS

But that gets the handle from the TChronium, and works on all OS.
It is also all-OS on LinkedParentWindow

In the implementation (for fpc) it needs LclType.THandle as result type.
Because sysutils redefines THandle.

Or move "SysUtils" from the implementation to the interface, but put it *first* in the uses list.
Post Reply