United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6539458 JPopupMenu does not display if invoker is instance of JWindow
JDK-6539458 : JPopupMenu does not display if invoker is instance of JWindow

Details
Type:
Bug
Submit Date:
2007-03-27
Status:
Closed
Updated Date:
2011-05-18
Project Name:
JDK
Resolved Date:
2011-05-18
Component:
client-libs
OS:
windows_xp
Sub-Component:
java.awt
CPU:
x86
Priority:
P3
Resolution:
Fixed
Affected Versions:
6
Fixed Versions:

Related Reports
Backport:
Duplicate:
Relates:
Relates:

Sub Tasks

Description
FULL PRODUCT VERSION :
java version "1.6.0"
Java(TM) SE Runtime Environment (build 1.6.0-b105)
Java HotSpot(TM) Client VM (build 1.6.0-b105, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

A DESCRIPTION OF THE PROBLEM :
A call to JPopupMenu.show(Component invoker, int x, int y) will fail to show the JPopupMenu if the invoker passed in is a JWindow.  A call to the JPopupMenu "isVisible()" method will return true, but the popup menu will not actually be displayed.

This problem does not occur with JDK 1.5.0_11.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
The source code provided in "Source code for an executable test case" will reproduce the problem.  Compile and run, then right click in the gray window which appears in the upper left hand corner of the screen.


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The test program program should display a popup menu with a single menu option called "quit".  The following message (or similar) should be displayed on stdout:

Showing menu at java.awt.Point[x=71,y=76] isVisible: true isValid: true

ACTUAL -
No popup is displayed.  The message printed out on stdout shows that the "isVisible" method on the popup menu is returning true, and that the location of the menu is right in the middle of the box, where it should be:

Showing menu at java.awt.Point[x=74,y=86] isVisible: true isValid: true


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JWindow;

public class Main {
  
  /** Creates a new instance of Main */
  public Main() {
  }
  
  /**
   * Mouse adapter which listens for mouse events and shows a popup menu as
   * required.
   */
  static public class PopupListener extends MouseAdapter {
    JPopupMenu menu;

    public PopupListener(
      JPopupMenu menu
    ) {
      this.menu = menu;
    }
    
    public void mousePressed(MouseEvent e) {showPopup(e);}
    public void mouseReleased(MouseEvent e) {showPopup(e);}
    private void showPopup(MouseEvent e) {
      if(e.isPopupTrigger()) {
        // This doesnt' work if e.getComponent() is a JWindow
        menu.show(e.getComponent(), e.getX(), e.getY());
        
        System.out.println(
          "Showing menu at " + menu.getLocationOnScreen() +
          " isVisible: " + menu.isVisible() +
          " isValid: " + menu.isValid());
      }
    }
  }

  
  /**
   * @param args the command line arguments
   */
  public static void main(String[] args) {
    JWindow window = new JWindow();
    window.setBounds(10, 10, 100, 100);
    
    JPopupMenu popupMenu = new JPopupMenu();
    JMenuItem quit = new JMenuItem("Quit");
    quit.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        System.exit(0);
      }
    });
    popupMenu.add(quit);
    
    window.addMouseListener(new PopupListener(popupMenu));
    
    window.setFocusable(true);
    
    window.validate();
    window.setVisible(true);
  }
  
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Instead of calling JPopupMenu.show() and passing the JWindow:

private void showPopup(MouseEvent e) {
  Point componentLocation = e.getComponent().getLocationOnScreen();
  menu.show(null, componentLocation.x + e.getX(), componentLocation.y + e.getY());
}

Release Regression From : 5.0u9
The above release value was the last known release where this 
bug was not reproducible. Since then there has been a regression.

                                    

Comments
EVALUATION

For some reason after the popup is shown we get UngrabEvent which closes the popup
Note that UngrabEvent doesn't get generated for JDialog

reassigned to AWT team

Here my test case which shows the problem more clearly:

import sun.awt.UngrabEvent;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class bug6539458 {
    private static void createGui() {
        final Window w = new JWindow();
        
        // For JDialog it works fine
//        final Window w = new JDialog();

        Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
            public void eventDispatched(AWTEvent event) {
                if (event instanceof UngrabEvent) {
                    System.out.println("UngrabEvent !!!");
                }
            }
        }, 0xFFFFFFFF);


        final JPopupMenu menu = new JPopupMenu();
        JMenuItem item = new JMenuItem("Quit");
        item.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });
        menu.add(item);
        w.addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                if (e.isPopupTrigger()) {
                    menu.show(w, 30, 30);
                }
            }

            public void mouseReleased(MouseEvent e) {
                if (e.isPopupTrigger()) {
                    menu.show(w, 30, 30);
                }
            }
        });
        w.setSize(200, 200);
        w.setLocationRelativeTo(null);
        w.setVisible(true);
    }

    public static void main(String[] args) throws Exception {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                bug6539458.createGui();
            }
        });
    }
}
                                     
2007-04-06
EVALUATION

it looks like it is a regression of fix for 4841881.  We do not perform grab on unfocused window, but the window in the test is unfocusable, and so it is not focused :(
                                     
2007-04-17
EVALUATION

Well, I have removed fix for 4841881 and the test works fine, but the test fo 4841881 doesn't :(  Sometime frame (from which I'm alt-tabbing) goes back to front and returns foxus to itself.  This is because of antoher code in the AwtWindow::Grab():

if (GetHWnd() != sm_focusedWindow) {
    _ToFront(env->NewGlobalRef(GetPeer(env)));
    // Global ref was deleted in _ToFront
}

After I removed these lines both tests work fine.  Unfortunately these lines were in the
code from the initial implementation of netive grab, so it is not clear why their were
added :(  Need to discuss this with Swing team.
                                     
2007-05-31
EVALUATION

tested more and found that after my changes 6458497 (which is almost the same as 4841881) is reproducible :(  it looks like I have a nice choice :-/
                                     
2007-06-05
EVALUATION

After discussion with swing I've decided that it will be enough for now to just allow grab
for unfocusable toplevels.  It will fix this particular problem and wil not affect
6458497.
                                     
2007-08-07
SUGGESTED FIX

webrev for the fix can be found at http://sa.sfbay.sun.com/projects/awt_data/7/6539458.0

--- /export/work/son/tests/java/awt/6539458/v0/webrev/src/windows/native/sun/windows/awt_Window.cpp-        2007-08-02 12:03:34.000000000 +0400
+++ awt_Window.cpp        2007-07-24 12:23:56.000000000 +0400
@@ -201,12 +201,12 @@
     if (m_grabbedWindow != NULL) {
         m_grabbedWindow->Ungrab();
     }
     m_grabbed = TRUE;
     m_grabbedWindow = this;
-    if (sm_focusedWindow == NULL) {
-        // we shouldn't perform grab in this case (see 4841881)
+    if (sm_focusedWindow == NULL && IsFocusableWindow()) {
+        // we shouldn't perform grab in this case (see 4841881 & 6539458) 
         Ungrab();
     } else if (GetHWnd() != sm_focusedWindow) {
         _ToFront(env->NewGlobalRef(GetPeer(env)));
         // Global ref was deleted in _ToFront
     }
                                     
2007-08-07



Hardware and Software, Engineered to Work Together