I'm trying to create an IntelliJ plugin using JCEF (version: 73.1.11.215) to display the UI. I'm able to get JCEF working on Windows and Linux when I run them as standalone applications.
It also works when being run in an IntelliJ plugin on Windows. The issue I'm having occurs when I try running JCEF as an IntelliJ plugin on my Ubuntu 18.04 OS.
This is the code I'm using to render the JFrame:
- Code: Select all
CefSettings DEFAULT_SETTINGS = new CefSettings();
DEFAULT_SETTINGS.windowless_rendering_enabled = false;
CefApp cefApp = CefApp.getInstance(DEFAULT_SETTINGS);
CefClient client = cefApp.createClient();
CefBrowser browser = client.createBrowser("https://google.com", false, false);
Component browserUI = browser.getUIComponent();
JFrame mainFrame = new JFrame();
mainFrame.getContentPane().add(browserUI, BorderLayout.CENTER);
mainFrame.setSize(1000, 600);
mainFrame.setVisible(true);
browser.setFocus(true);
mainFrame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent windowEvent) {
mainFrame.dispose();
cefApp.dispose();
}
});
Running this code standalone shows:
Running the same code as an IntelliJ plugin (by extending StartupActivity.runActivity) show this:
I was able to track a discrepancy of their execution down to CefBrowserWr.createBrowserIfRequired. That method calls getNativeRef("CefBrowser") to determine if it should create a new browser or not and when running JCEF under IntelliJ it will always result in 0 which causes an infinite loop of it trying to create a browser.
Since the issue appeared to be in the native code, I downloaded and built the debug versions of CEF and JCEF and tracked another discrepancy between the successful and unsuccessful execution down to the unsuccessful one never calling CefBrowserHostImpl::CreateInternal (browser_host_impl.cc). It appears this method needs to execute for LifeSpanHandler::OnAfterCreated (life_span_handler.cpp) to be called which will set the necessary value for getNativeRef("CefBrowser") to return a valid reference and the infinite loop fixed.
This is where I have been stuck for a while. I'm able to see that CefBrowserHostImpl::CreateInternal is triggered by CefBrowserHost::CreateBrowser (browser_host_impl.cc) and I'm able to confirm that code gets executed during the unsuccessful run and even returns true, however the required function never executes. This should be getting executed because CefBrowserHost::CreateBrowser contains the following code which should trigger it:
- Code: Select all
// Create the browser on the UI thread.
CreateBrowserHelper* helper = new CreateBrowserHelper(
windowInfo, client, url, settings, request_context);
CEF_POST_TASK(CEF_UIT, base::BindOnce(CreateBrowserWithHelper, helper));
Because of this code, I started to think I was dealing with a threading issue. This was further strengthened by the fact that modifying Context::PreInitialize (context.cpp) and setting settings.multi_threaded_message_loop to false causes even the standalone JCEF application to exhibit the IntelliJ infinite create browser loop. This code also has a rather large comment mentioning "XInitThreads" but unfortunately, that wasn't a fix for me. I compiled the .so mentioned in the StackOverflow link and I called that during a breakpoint on Thread.run when IntelliJ itself is loading; the same issue.
Keeping a close eye on the threads which are used to trigger things I'm able to notice that on the standalone application CefMainDelegate::RunProcess is called by a thread called "CefUIThread" (stack trace), whereas when it's run under an IntelliJ plugin the thread is simply called "java" (stack trace).
It's because of all of these reasons that I believe I'm dealing with some kind of threading issue but it's not obvious to me what kind. Is anyone able to recommend better ways to debug this issue? I know CEF can work with IntelliJ because JxBrowser uses it and I was able to successfully evaluate it an IntelliJ plugin on Ubuntu. Using JCEF I almost have a functional open-source JxBrowser alternative (called Journey), at least for my needs. I just need to figure out what's going on here. I would really appreciate any pushes in the right direction, thanks.