Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 567629

Summary: Chromium browser doesn't tell the system that it did get focus.
Product: [Eclipse Project] Platform Reporter: Johan Compagner <jcompagner>
Component: SWTAssignee: Platform-SWT-Inbox <platform-swt-inbox>
Status: CLOSED WONTFIX QA Contact:
Severity: normal    
Priority: P3 CC: akurtakov, guillez, jfaltermeier, Lars.Vogel, niraj.modi
Version: 4.17   
Target Milestone: ---   
Hardware: PC   
OS: Windows 10   
Whiteboard:
Bug Depends on:    
Bug Blocks: 566608, 569095    

Description Johan Compagner CLA 2020-10-06 06:48:19 EDT
We use in our product the chromium browser editor (also from before the  integration, i created there already also a bug some time ago: https://github.com/maketechnology/chromium.swt/issues/86)

But now i am debugging it a bit more, the problem is that eclipse doesn't see that the browser gets activated (gets focus)
so "part activated" doesn't happen. So it looks like for eclipse that you just focused an external window. 
As an example the stack that does not happen is:

Thread [main] (Suspended (breakpoint at line 383 in CTabFolder))	
	CTabFolder.onActivate(Event) line: 383	
	CTabFolder.lambda$0(Event) line: 340	
	0000000000000000.handleEvent(Event) line: not available	
	EventTable.sendEvent(Event) line: 89	
	Display.sendEvent(EventTable, Event) line: 4195	
	CTabFolder(Widget).sendEvent(Event) line: 1037	
	CTabFolder(Widget).sendEvent(int, Event, boolean) line: 1061	
	CTabFolder(Widget).sendEvent(int, Event) line: 1046	
	Shell.setActiveControl(Control, int) line: 1469	
	Shell.WM_MOUSEACTIVATE(long, long) line: 2315	
	Shell(Control).windowProc(long, int, long, long) line: 4803	
	Shell(Canvas).windowProc(long, int, long, long) line: 340	
	Shell(Decorations).windowProc(long, int, long, long) line: 1480	
	Shell.windowProc(long, int, long, long) line: 2142	
	Display.windowProc(long, long, long, long) line: 4921	
	OS.DefWindowProc(long, int, long, long) line: not available [native method]	
	Scrollable.callWindowProc(long, int, long, long) line: 91	
	Composite(Control).windowProc(long, int, long, long) line: 4860	
	Display.windowProc(long, long, long, long) line: 4921	
	OS.DefWindowProc(long, int, long, long) line: not available [native method]	
	Scrollable.callWindowProc(long, int, long, long) line: 91	
	Composite(Control).windowProc(long, int, long, long) line: 4860	
	Display.windowProc(long, long, long, long) line: 4921	
	OS.DefWindowProc(long, int, long, long) line: not available [native method]	
	Scrollable.callWindowProc(long, int, long, long) line: 91	
	Composite(Control).windowProc(long, int, long, long) line: 4860	
	Display.windowProc(long, long, long, long) line: 4921	
	OS.DefWindowProc(long, int, long, long) line: not available [native method]	
	Scrollable.callWindowProc(long, int, long, long) line: 91	
	Composite(Control).windowProc(long, int, long, long) line: 4860	
	Display.windowProc(long, long, long, long) line: 4921	
	OS.DefWindowProc(long, int, long, long) line: not available [native method]	
	Scrollable.callWindowProc(long, int, long, long) line: 91	
	Composite(Control).windowProc(long, int, long, long) line: 4860	
	Display.windowProc(long, long, long, long) line: 4921	
	OS.DefWindowProc(long, int, long, long) line: not available [native method]	
	Scrollable.callWindowProc(long, int, long, long) line: 91	
	Composite(Control).windowProc(long, int, long, long) line: 4860	
	Display.windowProc(long, long, long, long) line: 4921	
	OS.DefWindowProc(long, int, long, long) line: not available [native method]	
	Scrollable.callWindowProc(long, int, long, long) line: 91	
	CTabFolder(Control).windowProc(long, int, long, long) line: 4860	
	Display.windowProc(long, long, long, long) line: 4921	
	OS.DefWindowProc(long, int, long, long) line: not available [native method]	
	Scrollable.callWindowProc(long, int, long, long) line: 91	
	Composite(Control).windowProc(long, int, long, long) line: 4860	
	Display.windowProc(long, long, long, long) line: 4921	
	OS.DefWindowProc(long, int, long, long) line: not available [native method]	
	Scrollable.callWindowProc(long, int, long, long) line: 91	
	Composite(Control).windowProc(long, int, long, long) line: 4860	
	Display.windowProc(long, long, long, long) line: 4921	
	OS.DefWindowProc(long, int, long, long) line: not available [native method]	
	Scrollable.callWindowProc(long, int, long, long) line: 91	
	CTabFolder(Control).windowProc(long, int, long, long) line: 4860	
	Display.windowProc(long, long, long, long) line: 4921	
	OS.DefWindowProc(long, int, long, long) line: not available [native method]	
	Scrollable.callWindowProc(long, int, long, long) line: 91	
	ContributedPartRenderer$1(Control).windowProc(long, int, long, long) line: 4860	
	Display.windowProc(long, long, long, long) line: 4921	
	OS.DefWindowProc(long, int, long, long) line: not available [native method]	
	Scrollable.callWindowProc(long, int, long, long) line: 91	
	Composite(Control).windowProc(long, int, long, long) line: 4860	
	Display.windowProc(long, long, long, long) line: 4921	
	OS.DefWindowProc(long, int, long, long) line: not available [native method]	
	Scrollable.callWindowProc(long, int, long, long) line: 91	
	CTabFolder(Control).windowProc(long, int, long, long) line: 4860	
	Display.windowProc(long, long, long, long) line: 4921	
	OS.DefWindowProc(long, int, long, long) line: not available [native method]	
	Scrollable.callWindowProc(long, int, long, long) line: 91	
	Composite(Control).windowProc(long, int, long, long) line: 4860	
	Display.windowProc(long, long, long, long) line: 4921	
	OS.DefWindowProc(long, int, long, long) line: not available [native method]	
	Scrollable.callWindowProc(long, int, long, long) line: 91	
	Browser(Control).windowProc(long, int, long, long) line: 4860	
	Display.windowProc(long, long, long, long) line: 4921	
	OS.DefWindowProc(long, int, long, long) line: not available [native method]	
	Scrollable.callWindowProc(long, int, long, long) line: 91	
	OleFrame(Control).windowProc(long, int, long, long) line: 4860	
	Display.windowProc(long, long, long, long) line: 4921	
	OS.DefWindowProc(long, int, long, long) line: not available [native method]	
	Scrollable.callWindowProc(long, int, long, long) line: 91	
	WebSite(Control).windowProc(long, int, long, long) line: 4860	
	Display.windowProc(long, long, long, long) line: 4921	
	OS.PeekMessage(MSG, long, int, int, int) line: not available [native method]	
	Display.readAndDispatch() line: 3607	
	PartRenderingEngine$5.run() line: 1157	
	Realm.runWithDefault(Realm, Runnable) line: 338	
	PartRenderingEngine.run(MApplicationElement, IEclipseContext) line: 1046	
	E4Workbench.createAndRunUI(MApplicationElement) line: 155	
	Workbench.lambda$3(Display, WorkbenchAdvisor, int[]) line: 644	
	0000000000000000.run() line: not available	
	Realm.runWithDefault(Realm, Runnable) line: 338	
	Workbench.createAndRunWorkbench(Display, WorkbenchAdvisor) line: 551	
	PlatformUI.createAndRunWorkbench(Display, WorkbenchAdvisor) line: 153	
	IDEApplication.start(IApplicationContext) line: 150	
	EclipseAppHandle.run(Object) line: 203	
	EclipseAppLauncher.runApplication(Object) line: 134	
	EclipseAppLauncher.start(Object) line: 104	
	EclipseStarter.run(Object) line: 401	
	EclipseStarter.run(String[], Runnable) line: 255	
	NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]	
	NativeMethodAccessorImpl.invoke(Object, Object[]) line: 62	
	DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43	
	Method.invoke(Object, Object...) line: 564	
	Main.invokeFramework(String[], URL[]) line: 657	
	Main.basicRun(String[]) line: 594	
	Main.run(String[]) line: 1465	
	Main.main(String[]) line: 1438	



If i have 2 editors open where one is the browser and 1 is a text editor besides each other (so i split the editor area). Then when clicking in the browser you see that its tab doesn't get highlighted and the text editor tab stays highlighted.

We already noticed that almost all commands that the IE browser did still do (like CTRL-S or any of those key bindings) where not coming through. So what we did was catch those in the browser send them over a websocket to the eclipse environment and then find the command there for that key combo and execute it.
I think this has the same original problem.

We already patched it a bit also by that websocket to do this

	configuredHandlers.put("activated", new IServerService()
		{
			@Override
			public Object executeMethod(String methodName, JSONObject args) throws Exception
			{
				if (editorPart != PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActivePart())
				{
					PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().activate(editorPart);
				}

				return null;
			}
		});

so activated is a command that happens in the browser (mouse click) and that then tells eclipse its activated and that does that activate(editorPart) what normally eclipse would do..

Problem is this doesn't fully help. That is because the focus event doesn't fully work in the activate part (that does by default also "requestFocus")

This is because when we call activate the browser already says "isFocusControl()" true

And then control.forceFocus() doesn't do anything and just returns true.

it gets there because our EditorPage has:

	public void setFocus()
	{
		browser.setFocus();
	}

and that setFocus ends up in Control.forceFocus but that then doesn't do anything
and i think it should do:

	OS.SetFocus (handle);
	if (isDisposed ()) return false;
	shell.setSavedFocus (this);

Because something did get focus inside eclipse that eclipse has no idea that it did that..
And that thing (the browser) does tell already to eclipse that it has the focus..

if we hack around that:

			browser = new Browser(parent, SWT.CHROMIUM)
			{
				@Override
				public boolean isFocusControl()
				{
					return false;
				}

				@Override
				protected void checkSubclass()
				{
				}
			};

then it starts working, the right tab gets active all the time and no funny things anymore like pressing the backspace in an text editor deletes a thing in our Visual editor based on chromium (because that is attached to a delete action)


But having to call activate our self and then make sure that the full focus is done by just always saying that it is not the focus control (i have no idea when i just could return true...) sounds really hackish to me.
And i have a feeling a lot more people will be gettin weird behavior because of this.

The problem is a bit that debugging and patching Chromium class is hard, how do you guys do that? if i checkout and import it as a project it is not really usable..
Comment 1 Johan Compagner CLA 2020-10-06 06:55:00 EDT
i have a feeling that this in Chromium class:

protected void browserFocus(boolean set) {
		//debugPrint("cef focus: " + set);
		if (!isDisposed() && browser != 0) {
			long parent = (Display.getDefault().getActiveShell() == null) ? 0 : getHandle(chromium.getParent());
			if (chromium.getDisplay().getActiveShell() != chromium.getShell()) {
//			System.err.println("Ignore do_message_loop_work due inactive shell");
				return;
			}
			ChromiumLib.cefswt_set_focus(browser, set, parent);
		}
	}

should do something more..
Should tell the eclipse system that this happend (when "set" == true)
Comment 2 Johan Compagner CLA 2020-10-14 10:01:26 EDT
i needed to do a bit better patch so that the isFocusControl doesnt always return false but only 
when i noticed the browser didn't get focus yet.

The difference between IE and CHROMIUM is really that in chromium the Browser control gets the focus
and in IE its a control WebSite (that is a child of the browser, chromium impl doesn't have children)

The thing is and maybe that is the cause of all this, is that toe "hasFocus" boolean of the Chromium class
is set to true once:

Thread [main] (Suspended (breakpoint at line 1351 in Chromium))	
	ChromiumImpl(Chromium).on_got_focus(long) line: 1351	
	Chromium.on_got_focus(long, long) line: 1346	
	OS.DispatchMessage(MSG) line: not available [native method]	
	Display.readAndDispatch() line: 3610	
	PartRenderingEngine$5.run() line: 1157	
	Realm.runWithDefault(Realm, Runnable) line: 338	
	PartRenderingEngine.run(MApplicationElement, IEclipseContext) line: 1046	
	E4Workbench.createAndRunUI(MApplicationElement) line: 155	
	Workbench.lambda$3(Display, WorkbenchAdvisor, int[]) line: 644	
	0000000000000000.run() line: not available	
	Realm.runWithDefault(Realm, Runnable) line: 338	
	Workbench.createAndRunWorkbench(Display, WorkbenchAdvisor) line: 551	
	PlatformUI.createAndRunWorkbench(Display, WorkbenchAdvisor) line: 153	
	IDEApplication.start(IApplicationContext) line: 150	
	EclipseAppHandle.run(Object) line: 203	
	EclipseAppLauncher.runApplication(Object) line: 134	
	EclipseAppLauncher.start(Object) line: 104	
	EclipseStarter.run(Object) line: 401	
	EclipseStarter.run(String[], Runnable) line: 255	
	NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]	
	NativeMethodAccessorImpl.invoke(Object, Object[]) line: 62	
	DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43	
	Method.invoke(Object, Object...) line: 564	
	Main.invokeFramework(String[], URL[]) line: 657	
	Main.basicRun(String[]) line: 594	
	Main.run(String[]) line: 1465	
	Main.main(String[]) line: 1438	

and then the chromiumn never thinks it will loose focus.. even if i click somewhere else in Eclipse.
and the Browser relays isFocusControl() to Chromium impl and that returns true based on that boolean
So it never thinks it did loose focus.

And i think that is the key to this problem. Because if i block once now when i see it shouldn't have focus yet:

                        boolean[] gained = new boolean[] { false };
			browser = new Browser(parent, SWT.CHROMIUM)
			{
				// hack for https://bugs.eclipse.org/bugs/show_bug.cgi?id=567629
				// because the internal browser does say "true" but the system didn't really know that that its own view had the focus now
				// so the activation of parts and focus is screwed up. if we return false here all the time then SWT will force a focus Control.forceFocus()
				@Override
				public boolean isFocusControl()
				{
					System.err.println("is focus control  " + gained[0] + "," + super.isFocusControl());
					if (!gained[0]) return false;
					return super.isFocusControl();
				}

				@Override
				protected void checkSubclass()
				{
				}
			};
			browser.addFocusListener(new FocusListener()
			{

				@Override
				public void focusLost(FocusEvent e)
				{
					gained[0] = false;

				}

				@Override
				public void focusGained(FocusEvent e)
				{
					gained[0] = true;
				}
			});

then it works better (without that on the mac it really didn't work, and also under windows that isFocusControl would be constantly called)

It starts working i think because now 1 time in Control.forceFocus() this is called: OS.SetFocus (handle);

But why does the browser implementation constantly think it has the focus, it doesn't looe it again at all?

because at first i thought that i at some point the chromiumn browser needs to call OS.SetFocus (handle); somewhere itself (or let the parent know) when it get focus.
But now i think its the other way around somehow, it never looses focus?
Comment 3 Guillermo Zunino CLA 2020-10-14 10:59:22 EDT
Hi, thanks for the analysis. As you said there is a bug on java code in the focus implementation, but there is also a problem in cef 59 which steals the focus.
We are working on contributing an update based on 69. Which as some of the issues fixed.
Comment 4 Niraj Modi CLA 2020-11-09 03:25:48 EST
(In reply to Guillermo Zunino from comment #3)
> Hi, thanks for the analysis. As you said there is a bug on java code in the
> focus implementation, but there is also a problem in cef 59 which steals the
> focus.
> We are working on contributing an update based on 69. Which as some of the
> issues fixed.

Hi Guillermo,
Let us know if the Chromium upgrade to version 69 or newer, is still planned for 4.18 ? Thanks!
Comment 5 Guillermo Zunino CLA 2020-11-10 20:03:17 EST
(In reply to Niraj Modi from comment #4)
> (In reply to Guillermo Zunino from comment #3)
> > Hi, thanks for the analysis. As you said there is a bug on java code in the
> > focus implementation, but there is also a problem in cef 59 which steals the
> > focus.
> > We are working on contributing an update based on 69. Which as some of the
> > issues fixed.
> 
> Hi Guillermo,
> Let us know if the Chromium upgrade to version 69 or newer, is still planned
> for 4.18 ? Thanks!

We will try to make it for 4.18, but timeline looks very difficult for us. It might have to go to 4.19. In that case we will try to make the small bug fixes at least for 4.18.
Comment 6 Johan Compagner CLA 2020-11-11 05:21:00 EST
where do the fixes need to go in?
For example a chromium upgrade is really just the CEF packages right (that is not part of eclipse itself)
or do we need a newer eclipse also for that?
(I guess if patches need to be done in the Chromium class..)
Comment 7 Niraj Modi CLA 2020-11-12 04:44:17 EST
(In reply to Guillermo Zunino from comment #5)
> (In reply to Niraj Modi from comment #4)
> > (In reply to Guillermo Zunino from comment #3)
> > > Hi, thanks for the analysis. As you said there is a bug on java code in the
> > > focus implementation, but there is also a problem in cef 59 which steals the
> > > focus.
> > > We are working on contributing an update based on 69. Which as some of the
> > > issues fixed.
> > 
> > Hi Guillermo,
> > Let us know if the Chromium upgrade to version 69 or newer, is still planned
> > for 4.18 ? Thanks!
> 
> We will try to make it for 4.18, but timeline looks very difficult for us.
> It might have to go to 4.19. In that case we will try to make the small bug
> fixes at least for 4.18.

Thanks for the update! sharing the 4.18 timelines for reference:
- M3 planned for 20, Nov
- RC1 planned for 27, Nov

(In reply to Johan Compagner from comment #6)
> where do the fixes need to go in?
> For example a chromium upgrade is really just the CEF packages right (that
> is not part of eclipse itself)
> or do we need a newer eclipse also for that?
> (I guess if patches need to be done in the Chromium class..)

Yes fixes will go in the Chromium classes in SWT 'master' branch(source/binaries). Thanks!
Comment 8 Lars Vogel CLA 2020-12-04 03:30:52 EST
(In reply to Guillermo Zunino from comment #5)

> We will try to make it for 4.18, but timeline looks very difficult for us.
> It might have to go to 4.19. In that case we will try to make the small bug
> fixes at least for 4.18.

Guillermo, can you share you plans for the update of Chromium?
Comment 9 Alexander Kurtakov CLA 2021-10-04 04:53:38 EDT
Chromium has been removed via bug 572010 .