8056915: Focus lost in applet when browser window is minimized and restored
authoraivanov
Thu, 19 Feb 2015 12:50:32 +0000
changeset 29260 77797a65dc63
parent 29259 57e6ba59a1b3
child 29261 ea6e20f98dfa
8056915: Focus lost in applet when browser window is minimized and restored Reviewed-by: ant, dtitov, dcherepanov
jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java
jdk/src/java.desktop/share/classes/sun/awt/EmbeddedFrame.java
jdk/src/java.desktop/windows/classes/sun/awt/windows/WEmbeddedFrame.java
jdk/src/java.desktop/windows/classes/sun/awt/windows/WEmbeddedFramePeer.java
jdk/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp
jdk/src/java.desktop/windows/native/libawt/windows/awt_Frame.h
--- a/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java	Wed Feb 18 11:15:24 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java	Thu Feb 19 12:50:32 2015 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -686,7 +686,12 @@
 
         if (toFocus != null) {
             if (parent instanceof EmbeddedFrame) {
-                ((EmbeddedFrame)parent).synthesizeWindowActivation(true);
+                // JDK-8056915: Try to request focus to the embedder first and
+                // activate the embedded frame through it
+                if (!((EmbeddedFrame) parent).requestFocusToEmbedder()) {
+                    // Otherwise activate the embedded frame directly
+                    ((EmbeddedFrame) parent).synthesizeWindowActivation(true);
+                }
             }
             // EmbeddedFrame might have focus before the applet was added.
             // Thus after its activation the most recent focus owner will be
--- a/jdk/src/java.desktop/share/classes/sun/awt/EmbeddedFrame.java	Wed Feb 18 11:15:24 2015 -0800
+++ b/jdk/src/java.desktop/share/classes/sun/awt/EmbeddedFrame.java	Thu Feb 19 12:50:32 2015 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -361,6 +361,15 @@
     public void synthesizeWindowActivation(boolean doActivate) {}
 
     /**
+     * Requests the focus to the embedder.
+     *
+     * @return {@code true} if focus request was successful, and {@code false} otherwise.
+     */
+    public boolean requestFocusToEmbedder() {
+        return false;
+    }
+
+    /**
      * Moves this embedded frame to a new location. The top-left corner of
      * the new location is specified by the <code>x</code> and <code>y</code>
      * parameters relative to the native parent component.
--- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WEmbeddedFrame.java	Wed Feb 18 11:15:24 2015 -0800
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WEmbeddedFrame.java	Thu Feb 19 12:50:32 2015 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -52,6 +52,11 @@
     private static int pScale = 0;
     private static final int MAX_BAND_SIZE = (1024*30);
 
+    /**
+     * This flag is set to {@code true} if this embedded frame is hosted by Internet Explorer.
+     */
+    private boolean isEmbeddedInIE = false;
+
     private static String printScale = AccessController.doPrivileged(
         new GetPropertyAction("sun.java2d.print.pluginscalefactor"));
 
@@ -244,6 +249,14 @@
         }
     }
 
+    @SuppressWarnings("deprecation")
+    public boolean requestFocusToEmbedder() {
+        if (isEmbeddedInIE) {
+            return ((WEmbeddedFramePeer) getPeer()).requestFocusToEmbedder();
+        }
+        return false;
+    }
+
     public void registerAccelerator(AWTKeyStroke stroke) {}
     public void unregisterAccelerator(AWTKeyStroke stroke) {}
 
--- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WEmbeddedFramePeer.java	Wed Feb 18 11:15:24 2015 -0800
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WEmbeddedFramePeer.java	Thu Feb 19 12:50:32 2015 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -78,4 +78,11 @@
         // false on other systems.
         return !Win32GraphicsEnvironment.isDWMCompositionEnabled();
     }
+
+    /**
+     * Sets the focus to plugin control window, the parent of embedded frame.
+     * Eventually, it will synthesizeWindowActivation to activate the embedded frame,
+     * if plugin control window gets the focus.
+     */
+    public native boolean requestFocusToEmbedder();
 }
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp	Wed Feb 18 11:15:24 2015 -0800
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp	Thu Feb 19 12:50:32 2015 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -82,6 +82,15 @@
     HHOOK mouseHook;
     HHOOK modalHook;
 };
+
+
+// Communication with plugin control
+
+// The value must be the same as in AxControl.h
+#define WM_AX_REQUEST_FOCUS_TO_EMBEDDER (WM_USER + 197)
+
+static bool SetFocusToPluginControl(HWND hwndPlugin);
+
 /************************************************************************
  * AwtFrame fields
  */
@@ -93,6 +102,7 @@
 jmethodID AwtFrame::setExtendedStateMID;
 
 jmethodID AwtFrame::activateEmbeddingTopLevelMID;
+jfieldID AwtFrame::isEmbeddedInIEID;
 
 Hashtable AwtFrame::sm_BlockedThreads("AWTBlockedThreads");
 
@@ -104,6 +114,7 @@
     m_parentWnd = NULL;
     menuBar = NULL;
     m_isEmbedded = FALSE;
+    m_isEmbeddedInIE = FALSE;
     m_isLightweight = FALSE;
     m_ignoreWmSize = FALSE;
     m_isMenuDropped = FALSE;
@@ -199,6 +210,13 @@
 
             if (isEmbedded) {
                 hwndParent = (HWND)handle;
+
+                // JDK-8056915: Handle focus communication between plugin and frame
+                frame->m_isEmbeddedInIE = IsEmbeddedInIE(hwndParent);
+                if (frame->m_isEmbeddedInIE) {
+                    env->SetBooleanField(target, isEmbeddedInIEID, JNI_TRUE);
+                }
+
                 RECT rect;
                 ::GetClientRect(hwndParent, &rect);
                 //Fix for 6328675: SWT_AWT.new_Frame doesn't occupy client area under JDK6
@@ -338,6 +356,21 @@
     return frame;
 }
 
+/*
+ * Returns true if the frame is embedded into Internet Explorer.
+ * The function checks the class name of the parent window of the embedded frame.
+ */
+BOOL AwtFrame::IsEmbeddedInIE(HWND hwndParent)
+{
+    const char *pluginClass = "Java Plug-in Control Window";
+    #define PARENT_CLASS_BUFFER_SIZE 64
+    char parentClass[PARENT_CLASS_BUFFER_SIZE];
+
+    return (::GetClassNameA(hwndParent, parentClass, PARENT_CLASS_BUFFER_SIZE) > 0)
+           && (strncmp(parentClass, pluginClass, PARENT_CLASS_BUFFER_SIZE) == 0);
+}
+
+
 LRESULT AwtFrame::ProxyWindowProc(UINT message, WPARAM wParam, LPARAM lParam, MsgRouting &mr)
 {
     LRESULT retValue = 0L;
@@ -1039,6 +1072,19 @@
     if (IsLightweightFrame()) {
         return TRUE;
     }
+    if (isMouseEventCause && IsEmbeddedFrame() && m_isEmbeddedInIE) {
+        HWND hwndProxy = GetProxyFocusOwner();
+        // Do nothing if this frame is focused already
+        if (::GetFocus() != hwndProxy) {
+            // Fix for JDK-8056915:
+            // If window activated with mouse, set focus to plugin control window
+            // first to preserve focus owner inside browser window
+            if (SetFocusToPluginControl(::GetParent(GetHWnd()))) {
+                return TRUE;
+            }
+            // Plugin control window is already focused, so do normal processing
+        }
+    }
     return AwtWindow::AwtSetActiveWindow(isMouseEventCause);
 }
 
@@ -1819,6 +1865,9 @@
     AwtFrame::activateEmbeddingTopLevelMID = env->GetMethodID(cls, "activateEmbeddingTopLevel", "()V");
     DASSERT(AwtFrame::activateEmbeddingTopLevelMID != NULL);
 
+    AwtFrame::isEmbeddedInIEID = env->GetFieldID(cls, "isEmbeddedInIE", "Z");
+    DASSERT(AwtFrame::isEmbeddedInIEID != NULL);
+
     CATCH_BAD_ALLOC;
 }
 
@@ -1911,4 +1960,44 @@
     CATCH_BAD_ALLOC;
 }
 
+JNIEXPORT jboolean JNICALL
+Java_sun_awt_windows_WEmbeddedFramePeer_requestFocusToEmbedder(JNIEnv *env, jobject self)
+{
+    jboolean result = JNI_FALSE;
+
+    TRY;
+
+    AwtFrame *frame = NULL;
+
+    PDATA pData;
+    JNI_CHECK_PEER_GOTO(self, ret);
+    frame = (AwtFrame *)pData;
+
+    // JDK-8056915: During initial applet activation, set focus to plugin control window
+    HWND hwndParent = ::GetParent(frame->GetHWnd());
+
+    result = SetFocusToPluginControl(hwndParent);
+
+    CATCH_BAD_ALLOC_RET(JNI_FALSE);
+ret:
+    return result;
+}
+
 } /* extern "C" */
+
+static bool SetFocusToPluginControl(HWND hwndPlugin)
+{
+    HWND hwndFocus = ::GetFocus();
+
+    if (hwndFocus == hwndPlugin) {
+        return false;
+    }
+
+    ::SetFocus(hwndPlugin);
+    DWORD dwError = ::GetLastError();
+    if (dwError != ERROR_SUCCESS) {
+        // If direct call failed, use a special message to set focus
+        return (::SendMessage(hwndPlugin, WM_AX_REQUEST_FOCUS_TO_EMBEDDER, 0, 0) == 0);
+    }
+    return true;
+}
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Frame.h	Wed Feb 18 11:15:24 2015 -0800
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Frame.h	Thu Feb 19 12:50:32 2015 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -60,6 +60,9 @@
     /* method id for WEmbeddedFrame.requestActivate() method */
     static jmethodID activateEmbeddingTopLevelMID;
 
+    /* field id for WEmbeddedFrame.isEmbeddedInIE */
+    static jfieldID isEmbeddedInIEID;
+
     AwtFrame();
     virtual ~AwtFrame();
 
@@ -171,6 +174,13 @@
     /* The frame is an EmbeddedFrame. */
     BOOL m_isEmbedded;
 
+    /* Fix for JDK-8056915:
+       The embedded frame must gain focus by setting focus to its parent. */
+    BOOL m_isEmbeddedInIE;
+
+    /* Checks whether the frame is embedded in IE */
+    static BOOL IsEmbeddedInIE(HWND hwndParent);
+
     /* The frame is a LightweightFrame */
     BOOL m_isLightweight;