The first attached file contains the cocoa code snippets that
reproduce the problem.
- At first we create the Main window
- Clicking on the Main window creates the Second window
- The tracking rectangle is set for the Second window during the
window creation
(I also tried to set it in the -viewDidMoveToWindow method)
- When the second window appears under the mouse, the mouse enter
event is not received.
However the Second window tracks the mouse exited/entered events if
we manually move the mouse over the window
The second attached file is a test that shows the problem on the Java
side. It does the same and passes on the Windows and Ubuntu but fails on
the Mac OS X.
Thanks,
Alexandr.
On 4/18/2012 8:22 PM, Leonid Romanov wrote:
Hi,
A quick question to help me better understand what is going on in your webrev.
The common way to track mouse enter/exit events in OS X is to use NSView's
tracking rectangle or (newer than tracking rectangle) NSTrackingArea class. In
our port, we set a tracking rectangle in -viewDidMoveToWindow method of AWTView
class. So, my question is: have you investigated what is wrong with our current
approach? That is, why it doesn't work and for what cases?
Thanks,
Leonid.
On 18.04.2012, at 19:40, Alexander Scherbatiy wrote:
Please review a fix for CR 7154048.
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7154048
webrev: http://cr.openjdk.java.net/~alexsch/7154048/webrev.00/
Let's see the following test case:
- Frame contains two components JLabel and JButton
- The JLabel component has a mouse listener
mousePressed: create a Window under the mouse click
mouseDragged: drag the created window
mouseReleased: close the Window
- A user clicks on the JLabel component, drags the mouse to the JButton
component and releases the mouse button
The current JDK 8 implementation shows the following events on Mac OS X:
--------------------------------------------------------
mouse pressed: javax.swing.JLabel
mouse exited: javax.swing.JLabel
mouse entered: javax.swing.JLabel
mouse dragged: javax.swing.JLabel
mouse exited: javax.swing.JLabel
mouse entered: javax.swing.JButton
mouse dragged: javax.swing.JLabel
mouse exited: javax.swing.JButton
mouse entered: Drag Window
mouse exited: Drag Window
mouse entered: javax.swing.JButton
mouse released: javax.swing.JButton
--------------------------------------------------------
There are several issues:
1) The window does not receive the mouse entered event when it is created under
the mouse
2) There are JLabel exited/JButton entered events during the window dragging
3) JLabel does not receive the mouse released event
The fix synthesizes the mouse entered/exited events manually if they are not
received.
The entered/exited events synthesizing is added to setFrame, toFront, toBack,
and zoom methods of the AWTWindow and CWrapper classes.
There is an option to add the events synthesizing to the windowDidResize
notification. However this notification is sent when a window size is changed
in both cases, programmatically and when user is resized the window. So in a
lot of case there is no need for the our use case events generation.
The LWWindowPeer class is updated to not generate extra mouse enter/exit events
during the mouse dragging.
Tho automated tests are added.
Thanks,
Alexandr.
// Create Main Window
NSRect rect = NSMakeRect (100, 100, 300, 300);
unsigned int styleMask = NSTitledWindowMask | NSClosableWindowMask;
NSWindow *win = [NSWindow alloc];
win = [win initWithContentRect: rect
styleMask: styleMask
backing: NSBackingStoreBuffered
defer: NO];
MainView *view = [[MainView alloc] initWithFrame:rect];
[view addTrackingRect:[view visibleRect]
owner:view
userData:NULL
assumeInside:NO];
[win setContentView: view];
[win setTitle: @"Main Window"];
[win makeKeyAndOrderFront: nil];
=========================================
// Main View creates the second window after clicking on it
@interface MainView : NSView
{
NSWindow *win;
}
@end
#import "MainView.h"
#import "SecondView.h"
@implementation MainView
- (void)mouseDown:(NSEvent *)theEvent {
NSLog(@"[main win] mouse down");
NSRect rect = NSMakeRect (200, 200, 100, 100);
unsigned int styleMask = NSTitledWindowMask | NSClosableWindowMask;
win = [NSWindow alloc];
win = [win initWithContentRect: rect
styleMask: styleMask
backing: NSBackingStoreBuffered
defer: NO];
SecondView *view = [[SecondView alloc] initWithFrame:rect];
[view addTrackingRect:[view visibleRect]
owner:view
userData:NULL
assumeInside:NO];
[win setContentView: view];
[win setTitle: @"Second Window"];
[win makeKeyAndOrderFront: nil];
}
@end
===================================
// Second View handles the mouse entered/exited events
@interface SecondView : NSView
@end
#import "SecondView.h"
@implementation SecondView
- (void)mouseEntered:(NSEvent *)theEvent{
NSLog(@"[second win] mouse entered");
}
- (void)mouseExited:(NSEvent *)theEvent{
NSLog(@"[second win] mouse exited");
}
@end
package toolbar.test;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import sun.awt.SunToolkit;
public class MouseEnterTest {
private static volatile int mouseEnteredCount = 0;
private static JFrame frame;
public static void main(String[] args) throws Exception {
Robot robot = new Robot();
robot.setAutoDelay(50);
robot.mouseMove(100, 100);
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
frame = new JFrame("Main Frame");
frame.setSize(300, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
mouseEnteredCount++;
}
});
frame.setVisible(true);
}
});
((SunToolkit) Toolkit.getDefaultToolkit()).realSync();
if (mouseEnteredCount != 1) {
throw new RuntimeException("No Mouse Entered event!");
}
System.out.println("PASSED!");
}
}