United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6242833 Mouse cursor doesn't behave correctly after maximizing on Linux/JDS 3
JDK-6242833 : Mouse cursor doesn't behave correctly after maximizing on Linux/JDS 3

Details
Type:
Bug
Submit Date:
2005-03-18
Status:
Resolved
Updated Date:
2011-01-19
Project Name:
JDK
Resolved Date:
2006-03-20
Component:
client-libs
OS:
linux,linux_2.6
Sub-Component:
java.awt
CPU:
x86,other
Priority:
P2
Resolution:
Fixed
Affected Versions:
5.0,5.0u5
Fixed Versions:

Related Reports
Duplicate:
Relates:
Relates:
Relates:

Sub Tasks

Description
When you launch swing application and maximize it on Linux/JDS 3, the mouse cursor starts to change on wrong positions. The incorrect behaviour can is visible on SwingSet2 Demo in JDK. Steps to reproduce:

1. Launch the demo and choose JSplitPane (the one with astronaut). 
2. Maximize the window. 
3. Try to hover over the splitting line between the two images. The cursor doesn't change from arrow to the sliding cursor.

This bug seems to influence all swing applications. I report it due to problematic behaviour in NetBeans, there are many mouse cursor changes which stop to work correctly when the window is maximized.
###@###.### 2005-03-18 15:52:47 GMT

                                    

Comments
EVALUATION

Cursor change is the result of Enter|LeaveNotify event. We set  XAwtState.setComponentMouseEntered() before changing cursor (XWindow.handleXCrossingEvent()). But seems there is no any EnterNotify events (as well as LeaveNotify) while maximizing window even mouse pointer is actually still inside toplevel.
Similar effect seen if we restore down ("normalize") that window.
I noticed that if I restore window and move mouse back into inner space of that window there is no EnterNotify event again. (But it will happen if you move mouse slowly into that window.) Believe the last one is a timing issue and shouldn't be considered like a bug.

To fix decribed problem we would make a detection of changing state of the window and initialize WeakRef on component under mouse. I tried to implement it in XFramePeer and it does work for SwingSet.
To be honest, it's unsufficient just to set that component to "this" in the cases of Maximization/Restoring. We should invent how to find that correct component.
                                     
2005-12-08
SUGGESTED FIX

At first we considered the most safe fix that affected xcrossing event handling within XWindow: now we won't spik it if it has NotifyGrab or NotifyUngrab modes.
--- /net/karanar/export/dav/mustang67//webrev/src/solaris/classes/sun/awt/X11/XWindow.java        ???? ?????? 20 16:42:37 2005

*** 749,760 ****
          super.handleXCrossingEvent(ptr);
          XCrossingEvent xce = new XCrossingEvent(ptr);
  
          if (eventLog.isLoggable(Level.FINEST)) eventLog.finest(xce.toString());        
  
          // Skip event If it was caused by a grab
!         if (xce.get_mode() != NotifyNormal) {
              return;
          }
  
          // X sends XCrossing to all hierarchy so if the edge of child equals to
          // ancestor and mouse enters child, the ancestor will get an event too.
--- 749,776 ----
          super.handleXCrossingEvent(ptr);
          XCrossingEvent xce = new XCrossingEvent(ptr);
  
          if (eventLog.isLoggable(Level.FINEST)) eventLog.finest(xce.toString());        
  
+         // 6242833 : Mouse cursor doesn't behave correctly after maximizing on Linux/JDS 3
+         // On Maximize with double click on titlebar
+         // or _releasing_ ALT+TAB on other window so java window becomes active
+         boolean shouldHandle = false;
+         if (xce.get_mode() == NotifyUngrab && 
+             (xce.get_detail() == NotifyVirtual ||
+              xce.get_detail() == NotifyAncestor)) {
+             shouldHandle = true;
+         }
+         //On pressing ALT+TAB on java window
+         if (xce.get_mode() == NotifyGrab && 
+             (xce.get_detail() == NotifyVirtual ||
+              xce.get_detail() == NotifyAncestor)) {
+             shouldHandle = true;
+         }
+         
          // Skip event If it was caused by a grab
!         if (xce.get_mode() != NotifyNormal && !shouldHandle) {
              return;
          }
  
          // X sends XCrossing to all hierarchy so if the edge of child equals to
          // ancestor and mouse enters child, the ancestor will get an event too.
                                     
2005-12-08
EVALUATION

After previous evaluation one place need to be clarified much: sun.awt.GlobalCursorManager uses  findHeavyweightUnderCursor() that actually returns cached XAwtState.componentMouseEnteredRef component. If some of EnterNotify event has missed then we probably get wrong componentUnder mouse variable.
There is another approach in MToolkit : we handle reference to current component under mouse on native level.
                                     
2005-12-12
EVALUATION

This bug happens often (on awt-linux-01, linux machines) because (as
described in my previous email) we skip crossingEvent and doesn't
initialize XAwtState's componentEntered variable. That variable is then
used in GlobalCursorManager to change cursor shape.
Initially I though it's WM error and it just misses one
Enter/LeaveNotify event but further testing uncovered a bug in awt :
XWindow.java : handleXCrossingEvent() skip events if they are not in
NotifyNormal mode.
I found that only some actions may lead to skipping that event.
(There are two instances will be considered in following: XContentWindow
and XFramePeer.)
In particular:
1) double clicking on titlebar of the window (it if leads to maximization)
  In this case we obtain
1) missed xEvent == XCrossingEvent = type = EnterNotify,
sun.awt.X11.XFramePeer@1c5f743(2c00007), mode = 2, detail = 1
2) missed xEvent == XCrossingEvent = type = EnterNotify,
sun.awt.X11.XContentWindow@2803d5(2c0000e), mode = 2, detail = 0
Mode 2 means NotifyUngrab (it happens on second mouse release)
Detail 0 means NotifyAncestor
Detail 1 - NotifyVirtual
How does it work. When there are three windows: A(this is a root
window), B(XFramePeer), C(XContentWindow) and A is a parent of B and B
is a parent of C and crossing happens from A to C then B will receive
NotifyVirtual and C - NotifyAncestor.
You would imagine that similar things happen on crossing in other direction.

2) On pressing Alt-Tab:
Now lets consider pressing ALT+TAB (although there are no complains on
it in CR)
Java window initially activated and pointer over it and over other
window so when you release kbd pointer will come to different window:
(events will arrive on PRESS - this is significant)
1) missed xEvent == XCrossingEvent = type = LeaveNotify,
sun.awt.X11.XContentWindow@2803d5(2c0000e), mode = 1, detail = 0
2) missed xEvent == XCrossingEvent = type = LeaveNotify,
sun.awt.X11.XFramePeer@1c5f743(2c00007), mode = 1, detail = 1
Similar situation - crossing happens affecting same windows like before:
Mode 1 == NotifyGrab
XContentWindow recieves NotifyAncestor and XFramePeer - NotifyVirtual
as a middle-point in this chain.

3) On pressin ALT+TAB
Other (read "native") window initially activated and pointer over it and
over Java window:
(events arrives on RELEASE - significant)
1) missed xEvent == XCrossingEvent = type = EnterNotify,
sun.awt.X11.XFramePeer@1c5f743(2c00007), mode = 2, detail = 1
2) missed xEvent == XCrossingEvent = type = EnterNotify,
sun.awt.X11.XContentWindow@2803d5(2c0000e), mode = 2, detail = 0
You would notice exactly the same situation as in case 1).

We should correctly handle these events. I'm not sure about reasons of
filtering them for now and I'd filter them more precisely respecting
cases described above.
                                     
2005-12-19
EVALUATION

Seems there is no reasons to filter these XCrossing events based on their mode. So we should just handle all events. Suggested fix section contain two variants of the fix and the last one (simple one) should go into workspace.
                                     
2006-02-06
SUGGESTED FIX

But after some more investigation we found that there is nothing could break if we just handle all of xcrossing events.
So another fix look less safe but simple:
--- XWindow.java	2006-02-06 12:55:06.000000000 +0300
***************
*** 751,761 ****
  
          if (eventLog.isLoggable(Level.FINEST)) eventLog.finest(xce.toString());        
  
-         // Skip event If it was caused by a grab
-         if (xce.get_mode() != NotifyNormal) {
-             return;
-         }
- 
          // X sends XCrossing to all hierarchy so if the edge of child equals to
          // ancestor and mouse enters child, the ancestor will get an event too.
          // From java point the event is bogus as ancestor is obscured, so if
--- 751,756 ----
                                     
2006-02-06



Hardware and Software, Engineered to Work Together