United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6785058 Parent dn't get the focus after dialog is closed if security warning is applied
JDK-6785058 : Parent dn't get the focus after dialog is closed if security warning is applied

Details
Type:
Bug
Submit Date:
2008-12-15
Status:
Closed
Updated Date:
2011-01-19
Project Name:
JDK
Resolved Date:
2009-05-15
Component:
client-libs
OS:
solaris_10
Sub-Component:
java.awt
CPU:
sparc
Priority:
P2
Resolution:
Fixed
Affected Versions:
6u12
Fixed Versions:
6u14 (b01)

Related Reports
Backport:
Relates:

Sub Tasks

Description
I have a frame which contains a button. Pressing on the button shows a dialog. When i press the escape key on the dialog , the dialog gets closed but parent is not getting the focus. This happens only if program is started with -Djava.security.manager. It works fine if security option is not applied.   This works fine even in 6u10 with the security option, but fails from 6u10 b01 & b02 promoted build. Hence its a regression.  

Step to reproduce:-
-------------------
1) Run the attached porogram.
java  -Djava.security.manager WindowTest
2) Click the button on the frame. A dialog is seen. 
3)Press 'Escape' key, Dialog gets closed. But Observe that focus is not on the button of the frame. If you see the same , then the bug is reproduced.

                                    

Comments
EVALUATION

The bug can be reproduced from time to time.

What I see is that the parent frame doesn't get WM_TAKE_FOCUS when
its owned modal dialog is closed. It's the WM that should send us that event.
By the way, I can't reproduce the bug with KWM, only with Metacity.
So, this looks like a "special behavior" of the latter. Obviously,
the warning icon window (that is transient for the modal dialog)
somehow affects the WM's behavior.

We should try to create a native app that would emulate the bug.
Then report it against Metacity. Also, we may consider possibility
of requesting activation manually as a workaround.
                                     
2009-01-13
EVALUATION

I've found that the undecorated style of the warning icon window
somehow affects Metacity behavior. Not setting the warning icon
undecorated makes the problem disappear. And here's a native
testcase that 100% reproduces the issue with Metacity 2.16.0:

----------------------------------------------------------------
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>

Display *display;
int screen_num;

Window create_window(char *name, Window parent, int x, int y, int width, int height) 
{
    XSizeHints sh;
    XWMHints wmh;
    Window win = XCreateSimpleWindow(display, parent, x, y, width, height,
                                     2, // border width
                                     BlackPixel(display, screen_num),
                                     WhitePixel(display, screen_num));                 
    XStoreName(display, win, name);
    XSelectInput(display, win, FocusChangeMask | ButtonPressMask  | ButtonReleaseMask | StructureNotifyMask );
    
    sh.width = width;
    sh.height = height;
    sh.x = x;
    sh.y = y;
    sh.flags = USPosition | USSize;
    XSetWMNormalHints(display, win, &sh);

    wmh.input = False;
    wmh.flags = InputHint;
    XSetWMHints(display, win, &wmh);

    return win;
}

int main(int argc, char **argv)
{

    Atom protocols[1];
    Atom XA_WM_TAKE_FOCUS;
    Window root;
    Window win[2], window;
    XEvent ev;
    char *win_name;

    char *display_name = NULL;
    if ((display = XOpenDisplay(display_name)) == NULL)
    {
        fprintf(stderr, "Couldn't open %s\n", XDisplayName(display_name));
        return -1;
    }
    screen_num = DefaultScreen(display);
    root = RootWindow(display, screen_num);

    win[0] = create_window("Frame 0", root, 100, 100, 200, 100);
    win[1] = create_window("Frame 1", root, 200, 200, 200, 100);
    win[2] = create_window("Transient", root, 450, 200, 50, 50);

    protocols[0] = XA_WM_TAKE_FOCUS = XInternAtom(display, "WM_TAKE_FOCUS", True);
    XSetWMProtocols(display, win[0], protocols, 1);
    XSetWMProtocols(display, win[1], protocols, 1);
    XSetWMProtocols(display, win[2], NULL, 0);

    typedef long CARD32;
    typedef struct _mwmhints
    {
        CARD32 flags;
        CARD32 functions;
        CARD32 decorations;
        CARD32 inputMode;
        CARD32 status;
    } MWMHints;

    long MWM_HINTS_DECORATIONS = (1 << 1);
    long PROP_MWM_HINTS_ELEMENTS = 5;

    MWMHints mwmhints;

    Atom XA_MOTIF_WM_HINTS = XInternAtom(display, "_MOTIF_WM_HINTS", False);
    memset(&mwmhints, 0, sizeof(mwmhints));
    mwmhints.flags = MWM_HINTS_DECORATIONS;
    mwmhints.decorations = 0;
    XChangeProperty(display, win[2], XA_MOTIF_WM_HINTS, XA_MOTIF_WM_HINTS, 32,
                    PropModeReplace, (unsigned char *)&mwmhints,
                    PROP_MWM_HINTS_ELEMENTS);

    XSetTransientForHint(display, win[2], win[1]);

    XMapWindow(display, win[0]);

    XFlush(display);
    XSync(display, False);

    while (1)
    {
        XNextEvent(display, &ev);

        window = ev.xany.window;
        XFetchName(display, window, &win_name);

        if (win_name != 0)
            fprintf(stderr, "event on %s: ", win_name);

        switch(ev.xany.type)
        {
        case ClientMessage:
            fprintf(stderr, "ClientMessage\n");
            if (ev.xclient.data.l[0] == XA_WM_TAKE_FOCUS) {
                fprintf(stderr, "  WM_TAKE_FOCUS\n");
                XSetInputFocus(display, window, RevertToPointerRoot, CurrentTime);
            }
            break;
        case FocusIn:
            fprintf(stderr, "FocusIn\n");
            break;
        case FocusOut:
            fprintf(stderr, "FocusOut\n");
            break;
        case ButtonPress:
            fprintf(stderr, "ButtonPress\n");
            if (window == win[0]) {
                XMapWindow(display, win[1]);
                XMapWindow(display, win[2]);
                XSetTransientForHint(display, win[2], win[1]);
            } else if (window == win[1]) {
                XUnmapWindow(display, win[1]);
            }
        case UnmapNotify:
            fprintf(stderr, "UnmapNotify\n");
            if (window == win[1]) {
                XSetTransientForHint(display, win[2], 0);
                XUnmapWindow(display, win[2]);
            }
        default:
            fprintf(stderr, "%d\n", ev.xany.type);
        }
    }
    return 0;
}
----------------------------------------------------------------

To compile it (native.c):

$ gcc native.c -lX11 -o native

By the way, the problem doesn't appear on KWM with this testcase.
                                     
2009-01-14
EVALUATION

The testcase reproduces the problem even without the transient property being set.
So, "transient" doesn't matter.
                                     
2009-01-15
EVALUATION

A bug filed against Metacity: http://bugzilla.gnome.org/show_bug.cgi?id=567851
                                     
2009-01-15
EVALUATION

The solution is to reorder the sequence of disposing (unmapping) a toplevel
and its warning icon. The warning icon should be disposed first and then the
toplevel. This works around the Metacity issue and makes our behavior even
more consistent with respect to User Experience.
                                     
2009-01-20
SUGGESTED FIX

The webrev: http://sa.sfbay.sun.com/projects/awt_data/6u14/6785058


------- XWarningWindow.java -------
*** /tmp/sccs.RCNaYH	Tue Jan 20 16:20:23 2009
--- XWarningWindow.java	Tue Jan 20 14:04:03 2009
***************
*** 360,385 ****
                  }}.start();
          }
      };
  
      public void setSecurityWarningVisible(boolean visible) {
          if (visible) {
              XToolkit.remove(hidingTask);
              XToolkit.remove(showingTask);
              if (isVisible()) {
                  currentIcon = 0;
              } else {
                  currentIcon = 3;
              }
!             XToolkit.schedule(showingTask, 1);
          } else {
              XToolkit.remove(showingTask);
              XToolkit.remove(hidingTask);
              if (!isVisible()) {
                  return;
              }
!             XToolkit.schedule(hidingTask, hidingDelay);
          }
      }
- 
- 
  }
--- 360,395 ----
                  }}.start();
          }
      };
  
      public void setSecurityWarningVisible(boolean visible) {
+         setSecurityWarningVisible(visible, true);
+     }
+  
+     public void setSecurityWarningVisible(boolean visible, boolean doSchedule) {
          if (visible) {
              XToolkit.remove(hidingTask);
              XToolkit.remove(showingTask);
              if (isVisible()) {
                  currentIcon = 0;
              } else {
                  currentIcon = 3;
              }
!             if (doSchedule) {
!                 XToolkit.schedule(showingTask, 1);
!             } else {
!                 showingTask.run();
!             }
          } else {
              XToolkit.remove(showingTask);
              XToolkit.remove(hidingTask);
              if (!isVisible()) {
                  return;
              }
!             if (doSchedule) {
!                 XToolkit.schedule(hidingTask, hidingDelay);
!             } else {
!                 hidingTask.run();
!             }
          }
      }
  }


------- XWindowPeer.java -------
*** /tmp/sccs.TCtP7S	Tue Jan 20 16:20:23 2009
--- XWindowPeer.java	Tue Jan 20 16:14:58 2009
***************
*** 956,965 ****
--- 956,968 ----
      }
      
      public void setVisible(boolean vis) {
          updateFocusability();
          promoteDefaultPosition();
+         if (!vis && warningWindow != null) {
+             warningWindow.setSecurityWarningVisible(false, false);
+         }
          super.setVisible(vis);
          // method called somewhere in parent does not generate configure-notify 
          // event for override-redirect.  
          // Ergo, no reshape and bugs like 5085647 in case setBounds was  
          // called before setVisible. 
***************
*** 1017,1026 ****
--- 1020,1033 ----
  
          boolean show = false;
  
          int state = getWMState();
  
+         if (!isVisible()) {
+             return; // The warning window should already be hidden.
+         }
+ 
          // getWMState() always returns 0 (Withdrawn) for simple windows. Hence
          // we ignore the state for such windows.
          if (isVisible() && (state == NormalState || isSimpleWindow())) {
              if (XKeyboardFocusManagerPeer.getCurrentNativeFocusedWindow() ==
                      getTarget())
                                     
2009-01-22



Hardware and Software, Engineered to Work Together