This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

Bug 90371

Summary: Editor cursor visible even though the focus not in editor
Product: editor Reporter: Jaromir Uhrik <juhrik>
Component: -- Other --Assignee: _ tboudreau <tboudreau>
Status: RESOLVED FIXED    
Severity: blocker CC: dsimonek, mkleint, tboudreau
Priority: P3 Keywords: FOCUS
Version: 6.x   
Hardware: Macintosh   
OS: Mac OS X   
Issue Type: DEFECT Exception Reporter:
Attachments: Messages.log with debug messages...
Dirty hack to set null caret on focus loss using only focusGained events
Patch which works
Final patch

Description Jaromir Uhrik 2006-11-30 16:43:41 UTC
NetBeans IDE Dev (Build 200611300230)
1.5.0_06; Java HotSpot(TM) Client VM 1.5.0_06-64
Mac OS X version 10.4.8 running on ppc
en_US (nb); MacRoman
(I am not able to reproduce on Ubuntu nor Win XP!)

Write in editor and switch to some other window like Project View. The focus moves to Project View but the 
cursor in editor is still visible(blinking). It is confusing behaviour because user doesn't know where is 
currently focus.
Comment 1 Vitezslav Stejskal 2007-03-20 01:08:12 UTC
Could you please try this on JDK1.6.0?
Comment 2 Miloslav Metelka 2007-03-20 14:29:01 UTC
Please run the IDE with
-J-Dnetbeans.debug.editor.caret.focus=true
and attach the output. It should give some additional focus debugging. THanks.
Comment 3 Jaromir Uhrik 2007-03-22 14:17:58 UTC
Created attachment 39815 [details]
Messages.log with debug messages...
Comment 4 Jaromir Uhrik 2007-03-22 16:52:58 UTC
Vito, sorry I don't have 1.6.0 on my Mac so that I am not able to try on
JDK1.6.0 - I use the last released Java 1.5.0_06; Java HotSpot(TM) Client VM
1.5.0_06-64.
Comment 5 Vitezslav Stejskal 2007-03-23 06:21:44 UTC
Ok, the log shows that the focus was moved from the editor tab, but the
component that should recieve it was null and then (perhaps because of that) the
focus was moved back to the editor. Strange. What happens when you type or use
arrows? Are the key strokes captured by Project View or editor?
Comment 6 Miloslav Metelka 2008-02-08 16:42:30 UTC
*** Issue 77348 has been marked as a duplicate of this issue. ***
Comment 7 Miloslav Metelka 2008-02-08 16:44:22 UTC
BTW is this still reproducible on the Mac?
Comment 8 _ tboudreau 2008-02-09 04:44:48 UTC
Still occurs with nightly build of Apple JDK 6.  I suspect Apple's UI delegates are depending on some event which our "QuietEditorPane" is being too quiet 
about.  I do not see the same problem with IntellIiJ, which is also using Swing;  in NetBeans, the editor cursor is always blinking, no matter where focus is, and 
it is clear that something is wrong in hiding inplace editors and quick-search boxes based on focus events as well, as you can send focus back to the editor 
and they aren't hidden.

Probably it is a Mac OS bug of some sort, but since it does not occur in other Swing apps on mac, and does occur on both JDK 5 and JDK 6 (in which the Aqua 
L&F was completely rewritten), probably there is something we are doing with suppressing events that both iterations of their L&F depend on.
Comment 9 _ tboudreau 2008-02-09 06:56:44 UTC
So the characteristic that triggers the problem is a null opposite component from the FocusEvent?

If we can nail down exactly the source of the problem, we can file a bug for Apple's JDK team, though probably we will need to do some local workaround 
anyway.  I do know Apple's toolkit screws around weirdly with events and their sources - I was once advised never to trust EventQueue.getCurrentEvent() 
because events from various get replanned wildly and that call cannot be relied on to tell the truth;  if the opposite component of a FocusEvent is not set 
when the FocusEvent is created, that would cause similar unpredictability.
Comment 10 Vitezslav Stejskal 2008-03-06 08:02:25 UTC
This is probably related - issue #119617. The focus transitions are definitely broken, even though I'm not sure if
Netbeans or JDK is at fault. The weird thing in #119617 is that there is a guy reporting the same problem on Ubuntu with
Sun's JDK6.
Comment 11 Jiri Prox 2008-04-11 00:43:14 UTC
moving opened issues from TM <= 6.1 to TM=Dev
Comment 12 Vitezslav Stejskal 2008-08-01 08:35:22 UTC
*** Issue 138105 has been marked as a duplicate of this issue. ***
Comment 13 Vitezslav Stejskal 2008-08-11 11:04:18 UTC
*** Issue 143413 has been marked as a duplicate of this issue. ***
Comment 14 Max Sauer 2008-11-13 10:26:59 UTC
Lets focus next release..
Comment 15 Jaromir Uhrik 2009-05-11 10:43:29 UTC
Although this is not nice the behavior is not destructive. The focus indication is only visible in 2 places at once. But the focus is properly at the place where the 
user expects it to be. 
Comment 16 Jaromir Uhrik 2009-05-11 10:49:33 UTC
*** Issue 142775 has been marked as a duplicate of this issue. ***
Comment 17 Vitezslav Stejskal 2009-05-20 15:33:05 UTC
*** Issue 165613 has been marked as a duplicate of this issue. ***
Comment 18 tomwheeler 2009-07-23 20:20:18 UTC
I just observed what I believe is this bug on a colleague's machine (using 6.7 on a MacBook Pro running Java 6 under Mac
OS X 10.5.7).  He had split the editor window for a file so he could look at two sections simultaneously.  Both editor
windows had flashing cursors, though obviously only one of them had focus.  

Additionally, there was no obvious way to tell by looking which of these two windows had focus.  Both had active
scrollbars and flashing cursors, and the title tab for both editor windows seemed to look exactly alike.
Comment 19 _ tboudreau 2009-07-23 22:48:31 UTC
I set up a small test app on my mac with an AWTEventListener to log focus events.  It also contains a TopComponent that
contains a plain JEditorPane and a JTextField.

The problem is reproducible with the JEditorPane - give it focus, then give the explorer tree focus, and the cursor
keeps blinking.

Send focus from the JEditorPane to the JTextField, and *sometimes* the caret in the JEditorPane disappears.

But at any rate, the logging nails down the root of the problem:
The receiving component receives a FocusGained event.  But the JEditorPane never receives the FocusLost event.  That's
the root of the problem.

I have tried this in a standalone Swing app, and focus behavior is correct.  So either something in NetBeans is either
consuming FocusLost events before they reach the JEditorPane, or the events are never sent to begin with.

Probably the best next step is to patch FocusEvent.consume() to print a stack trace;  that should tell where it's coming
from.  Would do so myself but at the moment my macbook is out of power and the power adapter is MIA :-(

At worst, if it cannot be fixed, it could be worked around by an AWTEventListener which listens for focus gained events,
and if the opposite component is a JEditorPane, do something like
pane.putClientProperty ("cachedCaret", pane.getCaret());
pane.setCaret(null);
and the inverse when focus is gained.
Comment 20 _ tboudreau 2009-07-23 23:36:08 UTC
I can confirm that focus lost events are received by JEditorPanes in NetBeans on Windows;  the logging is definitely
different on mac.

One complete shot-in-the-dark:  See if the problem goes away if you call Beans.setDesignTime(false).  I remember some
other workarounds we had to do for Macs where we had to change that temporarily, cache the value, then set it back, for
things to work correctly.
Comment 21 medmunds 2009-07-30 00:54:53 UTC
I would respectfully disagree with juhrik's conclusion that "the behavior is not destructive. ... the focus is properly 
at the place where the user expects it to be." I've found the behavior to be destructive, precisely because focus is not 
where I expect it to be (or where it appears to be).

A specific example: switching back and forth between NetBeans and a browser window while debugging a Ruby app, on return 
to NetBeans the focus indication is blinking in both the editor window and the Ruby interactive (output) window. Seeing 
the cursor in the interactive window, I paste some debugging code. Unfortunately, the cursor is actually in the editor 
window, and I've now inserted unwanted code into my source.

True, the recovery from this is to hit "undo", but this requires a mental context switch away from the debugging task I 
was focused on and into noticing and repairing the unwanted edits to my source code. I'd argue that forcing that kind of 
context switch on a developer is "destructive" behavior for an IDE. (And if I'm not careful with the undos, literally 
destructive to my source code.)
Comment 22 _ tboudreau 2009-07-30 23:01:39 UTC
I got the following from an Apple JDK engineer - don't know if it is of use or not;  the problem seems to be the
focusLost being consumed or not fired, not the caret not paying attention to events.  Frame.active might be useful
somehow to make behavior of text controls more mac-like, however.
----------
Well, from reading the source of the com.apple.laf.AquaCaret class, we do install a FocusListener on the component and
also check if the component has a "Frame.active" client property present, which we key off of to determine if the
components in the window should be painted "active" or "inactive", depending on whether the window is in the foreground
or background.

We only set the caret visible if there is the dot and the mark are the same (no selection), the component has focus, and
the "Frame.active" property is Boolean.TRUE.
Comment 23 _ tboudreau 2009-07-31 03:51:44 UTC
Created attachment 85584 [details]
Dirty hack to set null caret on focus loss using only focusGained events
Comment 24 _ tboudreau 2009-07-31 03:58:00 UTC
I've attached an (untested) dirty hack to add to the other dirty hacks in the applemenu module, which may work to solve
the caret problem.  It does pretty much what I described below.  Since we only get focus gained events, never focus lost
events, it uses the existing AWT Event listener that makes ctrl-click work for popup menus to 
 - check if the component focus was lost from is a JTextComponent
 - if yes, store the result of getCaret() using putClientProperty() on the component
 - check if the component focus was gained by is a JTextComponent
 - if yes, find the stored Caret, and if non-null, call setCaret() on the focus recipient with it

I'll test it on my mac in the next few days, but if someone wants to beat me to it, feel free.  The patch could have
side effects - for example, going into overstrike mode with the keyboard and then setting focus might result in the
wrong caret being shown - or any case where the caret is changed programmatically.  It also probably depends on listener
order.  

However, we can see how severe the side effects are, if there are any at all.  Still would like to diagnose where the
FocusLost events are being consumed, or if they are simply not there at all.
Comment 25 _ tboudreau 2009-08-04 03:18:33 UTC
Using a patched version of FocusEvent, I can confirm that FocusLost events are indeed created for JTextComponents.  I can also confirm they are not being 
consumed.  However, they are not being delivered to the component, or even to an AWTEventListener listening globally for focus events.

I'd suspect some sort of bug in Apple's implementation of JTextComponent or KeyboardFocusManager.  Construction stack traces below for switching 
between editor and explorer, and explorer quick search and editor, and editor and external application.

Created a focus lost event
java.lang.Exception: Stack trace
	at java.lang.Thread.dumpStack(Thread.java:1176)
	at java.awt.event.FocusEvent.<init>(FocusEvent.java:155)
	at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:604)
	at java.awt.Component.dispatchEventImpl(Component.java:3941)
	at java.awt.Container.dispatchEventImpl(Container.java:2068)
	at java.awt.Window.dispatchEventImpl(Window.java:1801)
	at java.awt.Component.dispatchEvent(Component.java:3903)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:463)
	at org.netbeans.core.TimableEventQueue.dispatchEvent(TimableEventQueue.java:104)
	at java.awt.SequencedEvent.dispatch(SequencedEvent.java:93)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:461)
	at org.netbeans.core.TimableEventQueue.dispatchEvent(TimableEventQueue.java:104)
	at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:269)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:184)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:176)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:110)
Created a focus lost event
java.lang.Exception: Stack trace
	at java.lang.Thread.dumpStack(Thread.java:1176)
	at java.awt.event.FocusEvent.<init>(FocusEvent.java:155)
	at java.awt.KeyboardFocusManager.retargetFocusLost(KeyboardFocusManager.java:2785)
	at java.awt.KeyboardFocusManager.retargetFocusEvent(KeyboardFocusManager.java:2882)
	at java.awt.Component.dispatchEventImpl(Component.java:3934)
	at java.awt.Container.dispatchEventImpl(Container.java:2068)
	at java.awt.Component.dispatchEvent(Component.java:3903)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:463)
	at org.netbeans.core.TimableEventQueue.dispatchEvent(TimableEventQueue.java:104)
	at java.awt.SentEvent.dispatch(SentEvent.java:50)
	at java.awt.DefaultKeyboardFocusManager$DefaultKeyboardFocusManagerSentEvent.dispatch(DefaultKeyboardFocusManager.java:161)
	at java.awt.DefaultKeyboardFocusManager.sendMessage(DefaultKeyboardFocusManager.java:188)
	at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:604)
	at java.awt.Component.dispatchEventImpl(Component.java:3941)
	at java.awt.Container.dispatchEventImpl(Container.java:2068)
	at java.awt.Window.dispatchEventImpl(Window.java:1801)
	at java.awt.Component.dispatchEvent(Component.java:3903)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:463)
	at org.netbeans.core.TimableEventQueue.dispatchEvent(TimableEventQueue.java:104)
	at java.awt.SequencedEvent.dispatch(SequencedEvent.java:93)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:461)
	at org.netbeans.core.TimableEventQueue.dispatchEvent(TimableEventQueue.java:104)
	at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:269)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:184)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:176)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:110)
WARNING: A nonexistent Java extension /Library/Java/Extensions/libsvnjavahl.jnilib on /Library/Java/Extensions
Created a focus lost event
java.lang.Exception: Stack trace
	at java.lang.Thread.dumpStack(Thread.java:1176)
	at java.awt.event.FocusEvent.<init>(FocusEvent.java:155)
	at java.awt.KeyboardFocusManager.shouldNativelyFocusHeavyweight(KeyboardFocusManager.java:2320)
Created a focus lost event
java.lang.Exception: Stack trace
	at java.lang.Thread.dumpStack(Thread.java:1176)
	at java.awt.event.FocusEvent.<init>(FocusEvent.java:155)
	at java.awt.KeyboardFocusManager.processCurrentLightweightRequests(KeyboardFocusManager.java:2603)
	at java.awt.KeyboardFocusManager.retargetFocusEvent(KeyboardFocusManager.java:2874)
	at java.awt.Component.dispatchEventImpl(Component.java:3934)
	at java.awt.Container.dispatchEventImpl(Container.java:2068)
	at java.awt.Component.dispatchEvent(Component.java:3903)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:463)
	at org.netbeans.core.TimableEventQueue.dispatchEvent(TimableEventQueue.java:104)
	at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:269)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:184)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:176)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:110)
Created a focus lost event
java.lang.Exception: Stack trace
	at java.lang.Thread.dumpStack(Thread.java:1176)
	at java.awt.event.FocusEvent.<init>(FocusEvent.java:155)
	at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:604)
	at java.awt.Component.dispatchEventImpl(Component.java:3941)
	at java.awt.Container.dispatchEventImpl(Container.java:2068)
	at java.awt.Window.dispatchEventImpl(Window.java:1801)
	at java.awt.Component.dispatchEvent(Component.java:3903)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:463)
	at org.netbeans.core.TimableEventQueue.dispatchEvent(TimableEventQueue.java:104)
	at java.awt.SequencedEvent.dispatch(SequencedEvent.java:93)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:461)
	at org.netbeans.core.TimableEventQueue.dispatchEvent(TimableEventQueue.java:104)
	at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:269)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:184)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:176)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:110)
Created a focus lost event
java.lang.Exception: Stack trace
	at java.lang.Thread.dumpStack(Thread.java:1176)
	at java.awt.event.FocusEvent.<init>(FocusEvent.java:155)
	at java.awt.KeyboardFocusManager.retargetFocusLost(KeyboardFocusManager.java:2785)
	at java.awt.KeyboardFocusManager.retargetFocusEvent(KeyboardFocusManager.java:2882)
	at java.awt.Component.dispatchEventImpl(Component.java:3934)
	at java.awt.Container.dispatchEventImpl(Container.java:2068)
	at java.awt.Component.dispatchEvent(Component.java:3903)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:463)
	at org.netbeans.core.TimableEventQueue.dispatchEvent(TimableEventQueue.java:104)
	at java.awt.SentEvent.dispatch(SentEvent.java:50)
	at java.awt.DefaultKeyboardFocusManager$DefaultKeyboardFocusManagerSentEvent.dispatch(DefaultKeyboardFocusManager.java:161)
	at java.awt.DefaultKeyboardFocusManager.sendMessage(DefaultKeyboardFocusManager.java:188)
	at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:604)
	at java.awt.Component.dispatchEventImpl(Component.java:3941)
	at java.awt.Container.dispatchEventImpl(Container.java:2068)
	at java.awt.Window.dispatchEventImpl(Window.java:1801)
	at java.awt.Component.dispatchEvent(Component.java:3903)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:463)
	at org.netbeans.core.TimableEventQueue.dispatchEvent(TimableEventQueue.java:104)
	at java.awt.SequencedEvent.dispatch(SequencedEvent.java:93)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:461)
	at org.netbeans.core.TimableEventQueue.dispatchEvent(TimableEventQueue.java:104)
	at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:269)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:19
Comment 26 _ tboudreau 2009-08-04 04:19:30 UTC
A few more notes.  Tried a tweaked version of the attached patch;  however, frequently the opposite component on the FocusEvent is null, rather than the 
JTextComponent.  This is something I noticed when working on the window system years ago - that focus events are frequently component -> null -> 
component rather than component -> next component.  I still don't know what is the root of this behavior.

Also patched QuietEditorPane, the parent class for all standard NB text editors, and overrode
processEvent(AWTEvent) and processFocusEvent(FocusEvent).  These methods appear never to be called under any circumstances.

The fact that this behavior does happen in NetBeans, but not in standard Swing applications suggests there is *something* we are doing, either in core or the 
window system that is causing this problem.  Will continue digging.
Comment 27 _ tboudreau 2009-08-04 04:44:43 UTC
Created attachment 85734 [details]
Patch which works
Comment 28 _ tboudreau 2009-08-04 04:52:52 UTC
The latest attached patch fixes the problem, though not in the prettiest of ways:

The applemenu already installs an AWTEventListener to make ctrl-clicks properly invoke popup menus.  I added FOCUS_EVENT_MASK to the set of events it 
handles.  When focus is gained by a JTextComponent, that component is stored in a WeakReference.  When focus is gained by another component, the 
Reference<JTextComponent> is derefrenced, and if non-null, it calls caret.setVisible(false) on it.

Could be refined to check and store the current value of Caret.isVisible() as a client property of the component before changing it, to ensure we don't cause 
the caret to be shown on components that are programmatically set not to show one.  At the moment I know of no such cases, so probably this can be 
committed and if it causes such an issue that can be dealt with then.
Comment 29 _ tboudreau 2009-08-04 04:58:07 UTC
Created attachment 85736 [details]
Final patch
Comment 30 _ tboudreau 2009-08-04 05:12:12 UTC
Sorry, specification.diff attached to wrong issue.  Correct patch is the second applemenu.diff.
Comment 31 _ tboudreau 2009-08-04 05:58:25 UTC
Taking this issue.
Comment 32 _ tboudreau 2009-08-04 06:01:38 UTC
Fixed in changeset 990b9cc4f596
Comment 33 Miloslav Metelka 2009-09-29 15:28:38 UTC
*** Issue 173050 has been marked as a duplicate of this issue. ***