Multiple Browser Issue[SOLVED]

Having problems with building or using the JCEF Java binding? Ask your questions here.

Multiple Browser Issue[SOLVED]

Postby micrikit » Tue Jun 14, 2022 2:46 am

Hi,
I create a program with JCEF that displays multiple browser but it's not working fine.
For example, launch the program and displays two separate Google pages,
CPU usage gets 100% (program 50% and CTF loader 50%) and if I focus Google's search field caret rapidly flickering.
It doesn't happen with single browser.

here is the code below.

Code: Select all
public class MainFrame extends JFrame {
   private static final long serialVersionUID = -5570653778104813836L;
   private final JTextField address_;
   private final CefApp cefApp_;
   private final CefClient client_;
   private final CefBrowser browser_;
   private final Component browerUI_;
   private final CefBrowser browser_2;
   private final Component browerUI_2;
   private boolean browserFocus_ = true;

   public static void main(String[] args) {
      // Perform startup initialization on platforms that require it.
      if (!CefApp.startup(args)) {
          System.out.println("Startup initialization failed!");
          return;
      }

      // The simple example application is created as anonymous class and points
      // to Google as the very first loaded page. Windowed rendering mode is used by
      // default. If you want to test OSR mode set |useOsr| to true and recompile.
      boolean useOsr = false;
      new MainFrame("http://www.google.com", useOsr, false);
  }

   /**
    * To display a simple browser window, it suffices completely to create an
    * instance of the class CefBrowser and to assign its UI component to your
    * application (e.g. to your content pane).
    * But to be more verbose, this CTOR keeps an instance of each object on the
    * way to the browser UI.
    */
   private MainFrame(String startURL, boolean useOSR, boolean isTransparent) {
      CefApp.addAppHandler(new CefAppHandlerAdapter(null) {
         @Override
         public void stateHasChanged(org.cef.CefApp.CefAppState state) {
            // Shutdown the app if the native CEF part is terminated
            if (state == CefAppState.TERMINATED)
               System.exit(0);
         }
      });
      CefSettings settings = new CefSettings();
      settings.windowless_rendering_enabled = useOSR;
      cefApp_ = CefApp.getInstance(settings);

      client_ = cefApp_.createClient();

      browser_ = client_.createBrowser(startURL, useOSR, isTransparent);
      browerUI_ = browser_.getUIComponent();

      //second browser
      browser_2 = client_.createBrowser(startURL, useOSR, isTransparent);
      browerUI_2 = browser_2.getUIComponent();

      address_ = new JTextField(startURL, 100);
      address_.addActionListener(new ActionListener() {
         @Override
         public void actionPerformed(ActionEvent e) {
            browser_.loadURL(address_.getText());
         }
      });

      // Update the address field when the browser URL changes.
      client_.addDisplayHandler(new CefDisplayHandlerAdapter() {
         @Override
         public void onAddressChange(CefBrowser browser, CefFrame frame, String url) {
            address_.setText(url);
         }
      });

      // Clear focus from the browser when the address field gains focus.
      address_.addFocusListener(new FocusAdapter() {
         @Override
         public void focusGained(FocusEvent e) {
            if (!browserFocus_)
               return;
            browserFocus_ = false;
            KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
            address_.requestFocus();
         }
      });

      // Clear focus from the address field when the browser gains focus.
      client_.addFocusHandler(new CefFocusHandlerAdapter() {
         @Override
         public void onGotFocus(CefBrowser browser) {
            if (browserFocus_)
               return;
            browserFocus_ = true;
            KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
            browser.setFocus(true);
         }

         @Override
         public void onTakeFocus(CefBrowser browser, boolean next) {
            browserFocus_ = false;
         }
      });

      getContentPane().add(address_, BorderLayout.NORTH);

      JPanel jpanel1 = new JPanel();
      JPanel jpanel2 = new JPanel();

      jpanel1.setLayout(new BorderLayout());
      jpanel2.setLayout(new BorderLayout());
      jpanel1.setBounds(0, address_.getHeight(), 400, 600-address_.getHeight());
      jpanel2.setBounds(400, address_.getHeight(), 400, 600-address_.getHeight());

      jpanel1.add(browerUI_);
      jpanel2.add(browerUI_2);

      pack();
      setSize(800, 600);

      getContentPane().add(jpanel1);
      getContentPane().add(jpanel2);
      setVisible(true);

      addWindowListener(new WindowAdapter() {
         @Override
         public void windowClosing(WindowEvent e) {
            CefApp.getInstance().dispose();
            dispose();
         }
      });
   }
}


if you have any ideas, please share.
thanks.
Last edited by micrikit on Thu Jun 16, 2022 9:47 pm, edited 1 time in total.
micrikit
Techie
 
Posts: 14
Joined: Tue Jun 14, 2022 2:10 am

Re: Multiple Browser Issue

Postby Phylanx » Tue Jun 14, 2022 4:41 am

Try using two CefClients instead of one.
Maybe the FocusHandler that is active for both browser instances causes the problem...

We always use one CefBrowser with one CefClient.
Phylanx
Expert
 
Posts: 201
Joined: Thu Aug 11, 2016 8:17 am

Re: Multiple Browser Issue

Postby micrikit » Tue Jun 14, 2022 5:11 am

Thank you for your reply.
I edited the code as you mentioned and comment out all listner/handler like below,
but still same situation happen...
Maybe I failed to configure build pass?

Code: Select all
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

import org.cef.CefApp;
import org.cef.CefClient;
import org.cef.CefSettings;
import org.cef.browser.CefBrowser;

public class MainFrame extends JFrame {
   private static final long serialVersionUID = -5570653778104813836L;
   private final JTextField address_;
   private final CefApp cefApp_;
   private final CefClient client_;
   private final CefClient client_2;
   private final CefBrowser browser_;
   private final Component browerUI_;
   private final CefBrowser browser_2;
   private final Component browerUI_2;
   private boolean browserFocus_ = true;

   public static void main(String[] args) {
      // Perform startup initialization on platforms that require it.
      if (!CefApp.startup(args)) {
          System.out.println("Startup initialization failed!");
          return;
      }

      // The simple example application is created as anonymous class and points
      // to Google as the very first loaded page. Windowed rendering mode is used by
      // default. If you want to test OSR mode set |useOsr| to true and recompile.
      boolean useOsr = false;
      new MainFrame("http://www.google.com", useOsr, false);
  }

   /**
    * To display a simple browser window, it suffices completely to create an
    * instance of the class CefBrowser and to assign its UI component to your
    * application (e.g. to your content pane).
    * But to be more verbose, this CTOR keeps an instance of each object on the
    * way to the browser UI.
    */
   private MainFrame(String startURL, boolean useOSR, boolean isTransparent) {
//      CefApp.addAppHandler(new CefAppHandlerAdapter(null) {
//         @Override
//         public void stateHasChanged(org.cef.CefApp.CefAppState state) {
//            // Shutdown the app if the native CEF part is terminated
//            if (state == CefAppState.TERMINATED)
//               System.exit(0);
//         }
//      });
      CefSettings settings = new CefSettings();
      settings.windowless_rendering_enabled = useOSR;
      cefApp_ = CefApp.getInstance(settings);

      client_ = cefApp_.createClient();
      client_2 = cefApp_.createClient();

      browser_ = client_.createBrowser(startURL, useOSR, isTransparent);
      browerUI_ = browser_.getUIComponent();

      //second browser
      browser_2 = client_2.createBrowser(startURL, useOSR, isTransparent);
      browerUI_2 = browser_2.getUIComponent();

      address_ = new JTextField(startURL, 100);
//      address_.addActionListener(new ActionListener() {
//         @Override
//         public void actionPerformed(ActionEvent e) {
//            browser_.loadURL(address_.getText());
//         }
//      });
//
//      // Update the address field when the browser URL changes.
//      client_.addDisplayHandler(new CefDisplayHandlerAdapter() {
//         @Override
//         public void onAddressChange(CefBrowser browser, CefFrame frame, String url) {
//            address_.setText(url);
//         }
//      });
//
//      // Clear focus from the browser when the address field gains focus.
//      address_.addFocusListener(new FocusAdapter() {
//         @Override
//         public void focusGained(FocusEvent e) {
//            if (!browserFocus_)
//               return;
//            browserFocus_ = false;
//            KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
//            address_.requestFocus();
//         }
//      });
//
//      // Clear focus from the address field when the browser gains focus.
//      client_.addFocusHandler(new CefFocusHandlerAdapter() {
//         @Override
//         public void onGotFocus(CefBrowser browser) {
//            if (browserFocus_)
//               return;
//            browserFocus_ = true;
//            KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
//            browser.setFocus(true);
//         }
//
//         @Override
//         public void onTakeFocus(CefBrowser browser, boolean next) {
//            browserFocus_ = false;
//         }
//      });

      getContentPane().add(address_, BorderLayout.NORTH);

      JPanel jpanel1 = new JPanel();
      JPanel jpanel2 = new JPanel();

      jpanel1.setLayout(new BorderLayout());
      jpanel2.setLayout(new BorderLayout());
      jpanel1.setBounds(0, address_.getHeight(), 400, 600-address_.getHeight());
      jpanel2.setBounds(400, address_.getHeight(), 400, 600-address_.getHeight());

      jpanel1.add(browerUI_);
      jpanel2.add(browerUI_2);

      pack();
      setSize(800, 600);

      getContentPane().add(jpanel1);
      getContentPane().add(jpanel2);

      setVisible(true);

      addWindowListener(new WindowAdapter() {
         @Override
         public void windowClosing(WindowEvent e) {
            CefApp.getInstance().dispose();
            dispose();
         }
      });
   }
}
Attachments
untitled.png
build pass
untitled.png (43.75 KiB) Viewed 16015 times
micrikit
Techie
 
Posts: 14
Joined: Tue Jun 14, 2022 2:10 am

Re: Multiple Browser Issue

Postby ndesktop » Tue Jun 14, 2022 5:18 am

onGotFocus is calling browser.setFocus(true);
I suppose this will trigger another onGotFocus and this will enter in some loop.
ndesktop
Master
 
Posts: 750
Joined: Thu Dec 03, 2015 10:10 am

Re: Multiple Browser Issue

Postby micrikit » Tue Jun 14, 2022 5:58 am

ndesktop wrote:onGotFocus is calling browser.setFocus(true);
I suppose this will trigger another onGotFocus and this will enter in some loop.


THIS is the cause of issue!
I put log in onGotFocus() and log loopin!
But I don't know how to solve it...
browser_.setFocus(false) doesn't work.

PS:
https://bitbucket.org/chromiumembedded/ ... eeps-focus
I though this might be related , but comment out "Java_org_cef_browser_CefBrowser_1N_N_1SetFocus " don't solve anything...
micrikit
Techie
 
Posts: 14
Joined: Tue Jun 14, 2022 2:10 am

Re: Multiple Browser Issue

Postby ndesktop » Tue Jun 14, 2022 3:24 pm

I don't know JCEF, but maybe one can check if the browser does not has the focus already (1). And second, maybe there can be some form of guard to be used, such as in the following hypotetical pseudocode
Code: Select all
onSetFocus() {
    if ( ! in_set_focus ) {
      in_set_focus = true;

      if ( ! browser has already focus ) {
        browser.setFocus(true);
      }

      in_set_focus = false;
    }
}

Of course, if there are multiple threads involved that won't work, but I think all the action is on TID_UI.
There is also the case of multiple browsers, where the focus can belong to one browser etc.
ndesktop
Master
 
Posts: 750
Joined: Thu Dec 03, 2015 10:10 am

Re: Multiple Browser Issue

Postby micrikit » Tue Jun 14, 2022 9:09 pm

ndesktop wrote:I don't know JCEF, but maybe one can check if the browser does not has the focus already (1). And second, maybe there can be some form of guard to be used, such as in the following hypotetical pseudocode
Code: Select all
onSetFocus() {
    if ( ! in_set_focus ) {
      in_set_focus = true;

      if ( ! browser has already focus ) {
        browser.setFocus(true);
      }

      in_set_focus = false;
    }
}

Of course, if there are multiple threads involved that won't work, but I think all the action is on TID_UI.
There is also the case of multiple browsers, where the focus can belong to one browser etc.


Thank you for your advice , finally I solve this issue!
Here is the code :
Code: Select all
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

import org.cef.CefApp;
import org.cef.CefApp.CefAppState;
import org.cef.CefClient;
import org.cef.CefSettings;
import org.cef.browser.CefBrowser;
import org.cef.browser.CefFrame;
import org.cef.handler.CefAppHandlerAdapter;
import org.cef.handler.CefDisplayHandlerAdapter;
import org.cef.handler.CefFocusHandlerAdapter;

public class MainFrame extends JFrame {
   private static final long serialVersionUID = -5570653778104813836L;
   private final JTextField address_;
   private final CefApp cefApp_;
   private final CefClient client_;
   private final CefBrowser browser_;
   private final Component browserUI_;
   private final CefBrowser browser_2;
   private final Component browserUI_2;

   private final ArrayList<CefBrowser> bindBrowsers = new ArrayList<CefBrowser>();
   private boolean browserFocus_ = true;

   public static void main(String[] args) {
      // Perform startup initialization on platforms that require it.
      if (!CefApp.startup(args)) {
         System.out.println("Startup initialization failed!");
         return;
      }

      // The simple example application is created as anonymous class and points
      // to Google as the very first loaded page. Windowed rendering mode is used by
      // default. If you want to test OSR mode set |useOsr| to true and recompile.
      boolean useOsr = false;
      new MainFrame("http://www.google.com", useOsr, false);
   }

   /**
    * To display a simple browser window, it suffices completely to create an
    * instance of the class CefBrowser and to assign its UI component to your
    * application (e.g. to your content pane).
    * But to be more verbose, this CTOR keeps an instance of each object on the
    * way to the browser UI.
    */
   private MainFrame(String startURL, boolean useOSR, boolean isTransparent) {
      CefApp.addAppHandler(new CefAppHandlerAdapter(null) {
         @Override
         public void stateHasChanged(org.cef.CefApp.CefAppState state) {
            // Shutdown the app if the native CEF part is terminated
            if (state == CefAppState.TERMINATED)
               System.exit(0);
         }
      });
      CefSettings settings = new CefSettings();
      settings.windowless_rendering_enabled = useOSR;
      cefApp_ = CefApp.getInstance(null, settings);

      client_ = cefApp_.createClient();

      browser_ = client_.createBrowser(startURL, useOSR, isTransparent);
      browserUI_ = browser_.getUIComponent();

      //second browser
      browser_2 = client_.createBrowser(startURL, useOSR, isTransparent);
      browserUI_2 = browser_2.getUIComponent();

      bindBrowsers.add(browser_);
      bindBrowsers.add(browser_2);

      address_ = new JTextField(startURL, 100);
      address_.addActionListener(new ActionListener() {
         @Override
         public void actionPerformed(ActionEvent e) {
            browser_.loadURL(address_.getText());
         }
      });
      client_.addDisplayHandler(new CefDisplayHandlerAdapter() {
         @Override
         public void onAddressChange(CefBrowser browser, CefFrame frame, String url) {
            address_.setText(url);
         }
      });
      address_.addFocusListener(new FocusAdapter() {
         @Override
         public void focusGained(FocusEvent e) {
            if (!browserFocus_)
               return;
            browserFocus_ = false;
            KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
            address_.requestFocus();
         }
      });


      // ↓ Prevent focus loop ↓
      client_.addFocusHandler(new CefFocusHandlerAdapter() {
         @Override
         public void onGotFocus(CefBrowser browser) {
            System.out.println("onGotFocus");
         }
         @Override
         public boolean onSetFocus(final CefBrowser browser, FocusSource focusSource) {
            if(browser == null)return false;
            for(CefBrowser bindBrowser : bindBrowsers) {
               if(bindBrowser.getUIComponent().hasFocus()) {
                  return false;
               }
            }
            return true;
         }
      });
      // ↑ Prevent focus loop ↑


      getContentPane().add(address_, BorderLayout.NORTH);

      JPanel jpanel0 = new JPanel();
      JPanel jpanel1 = new JPanel();
      JPanel jpanel2 = new JPanel();
      jpanel0.setLayout(new BorderLayout());
      jpanel1.setLayout(new BorderLayout());
      jpanel2.setLayout(new BorderLayout());

      jpanel1.setBounds(0, address_.getHeight(), 400, 600 - address_.getHeight());
      jpanel2.setBounds(400, address_.getHeight(), 400, 600 - address_.getHeight());

      jpanel1.add(browserUI_, BorderLayout.CENTER);
      jpanel2.add(browserUI_2, BorderLayout.CENTER);

      pack();
      setSize(800, 600);

      jpanel0.setBounds(0, 0, getContentPane().getWidth(), getContentPane().getHeight());
      jpanel0.add(jpanel1);
      jpanel0.add(jpanel2);

      getContentPane().add(jpanel0);

      setVisible(true);

      addWindowListener(new WindowAdapter() {
         @Override
         public void windowClosing(WindowEvent e) {
            CefApp.getInstance().dispose();
            dispose();
         }
      });
   }
}


Thank you all.
Hope this helps someone.

*P.S
this causes setFocus() ignored...
micrikit
Techie
 
Posts: 14
Joined: Tue Jun 14, 2022 2:10 am


Return to JCEF Forum

Who is online

Users browsing this forum: No registered users and 19 guests