8025815: Child FileDialog of modal dialog does not get focus on Gnome
Reviewed-by: azvegint, serb
--- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/GtkFileDialogPeer.java Tue Jul 28 20:39:43 2015 +0300
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/GtkFileDialogPeer.java Tue Jul 28 20:55:45 2015 +0300
@@ -42,6 +42,8 @@
// A pointer to the native GTK FileChooser widget
private volatile long widget = 0L;
+ private long standaloneWindow;
+ private volatile boolean quit;
GtkFileDialogPeer(FileDialog fd) {
super(fd);
@@ -111,9 +113,11 @@
public void setVisible(boolean b) {
XToolkit.awtLock();
try {
+ quit = !b;
if (b) {
Runnable task = () -> {
showNativeDialog();
+ standaloneWindow = 0;
fd.setVisible(false);
};
new ManagedLocalsThread(task).start();
@@ -128,7 +132,14 @@
@Override
public void dispose() {
- quit();
+ XToolkit.awtLock();
+ try {
+ quit = true;
+ quit();
+ }
+ finally {
+ XToolkit.awtUnlock();
+ }
super.dispose();
}
@@ -144,6 +155,17 @@
// have delegated to FileDialog#setFile
}
+ protected void requestXFocus(long time, boolean timeProvided) {
+ if(standaloneWindow == 0) {
+ super.requestXFocus(time, timeProvided);
+ return;
+ }
+ XNETProtocol net_protocol = XWM.getWM().getNETProtocol();
+ if (net_protocol != null) {
+ net_protocol.setActiveWindow(standaloneWindow);
+ }
+ }
+
@Override
public void setFilenameFilter(FilenameFilter filter) {
// We do not implement this method because we
@@ -170,7 +192,21 @@
dirname = file.getParent();
}
}
- run(fd.getTitle(), fd.getMode(), dirname, filename,
- fd.getFilenameFilter(), fd.isMultipleMode(), fd.getX(), fd.getY());
+ if (!quit) {
+ run(fd.getTitle(), fd.getMode(), dirname, filename,
+ fd.getFilenameFilter(), fd.isMultipleMode(), fd.getX(), fd.getY());
+ }
+ }
+
+ /**
+ * Called by native code when GTK dialog is created.
+ */
+ boolean setWindow(long xid) {
+ if (!quit && widget != 0) {
+ standaloneWindow = xid;
+ requestXFocus();
+ return true;
+ }
+ return false;
}
}
--- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XFramePeer.java Tue Jul 28 20:39:43 2015 +0300
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XFramePeer.java Tue Jul 28 20:55:45 2015 +0300
@@ -289,7 +289,7 @@
XNETProtocol net_protocol = XWM.getWM().getNETProtocol();
if (net_protocol != null) {
- net_protocol.setActiveWindow(this);
+ net_protocol.setActiveWindow(getWindow());
}
xSetVisible(true);
}
--- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XNETProtocol.java Tue Jul 28 20:39:43 2015 +0300
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XNETProtocol.java Tue Jul 28 20:55:45 2015 +0300
@@ -326,7 +326,7 @@
return res;
}
- public void setActiveWindow(XWindow window) {
+ public void setActiveWindow(long window) {
if (!active() || !checkProtocol(XA_NET_SUPPORTED, XA_NET_ACTIVE_WINDOW)) {
return;
}
@@ -336,7 +336,7 @@
msg.set_type(XConstants.ClientMessage);
msg.set_message_type(XA_NET_ACTIVE_WINDOW.getAtom());
msg.set_display(XToolkit.getDisplay());
- msg.set_window(window.getWindow());
+ msg.set_window(window);
msg.set_format(32);
msg.set_data(0, 1);
msg.set_data(1, XToolkit.getCurrentServerTime());
--- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c Tue Jul 28 20:39:43 2015 +0300
+++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c Tue Jul 28 20:55:45 2015 +0300
@@ -576,6 +576,7 @@
fp_gtk_file_chooser_get_filenames = dl_symbol(
"gtk_file_chooser_get_filenames");
fp_gtk_g_slist_length = dl_symbol("g_slist_length");
+ fp_gdk_x11_drawable_get_xid = dl_symbol("gdk_x11_drawable_get_xid");
}
gboolean gtk2_load(JNIEnv *env)
--- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h Tue Jul 28 20:39:43 2015 +0300
+++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h Tue Jul 28 20:55:45 2015 +0300
@@ -27,6 +27,7 @@
#include <stdlib.h>
#include <jni.h>
+#include <X11/X.h>
#define _G_TYPE_CIC(ip, gt, ct) ((ct*) ip)
#define G_TYPE_CHECK_INSTANCE_CAST(instance, g_type, c_type) (_G_TYPE_CIC ((instance), (g_type), c_type))
@@ -820,6 +821,7 @@
void (*fp_gtk_main)(void);
guint (*fp_gtk_main_level)(void);
gchar* (*fp_g_path_get_dirname) (const gchar *file_name);
+XID (*fp_gdk_x11_drawable_get_xid) (GdkWindow *drawable);
/**
* This function is available for GLIB > 2.20, so it MUST be
--- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/sun_awt_X11_GtkFileDialogPeer.c Tue Jul 28 20:39:43 2015 +0300
+++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/sun_awt_X11_GtkFileDialogPeer.c Tue Jul 28 20:55:45 2015 +0300
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 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
@@ -27,6 +27,7 @@
#include <stdio.h>
#include <jni_util.h>
#include <string.h>
+#include <X11/X.h>
#include "gtk2_interface.h"
#include "sun_awt_X11_GtkFileDialogPeer.h"
#include "java_awt_FileDialog.h"
@@ -38,6 +39,7 @@
static jmethodID filenameFilterCallbackMethodID = NULL;
static jmethodID setFileInternalMethodID = NULL;
static jfieldID widgetFieldID = NULL;
+static jmethodID setWindowMethodID = NULL;
JNIEXPORT void JNICALL Java_sun_awt_X11_GtkFileDialogPeer_initIDs
(JNIEnv *env, jclass cx)
@@ -54,6 +56,10 @@
widgetFieldID = (*env)->GetFieldID(env, cx, "widget", "J");
DASSERT(widgetFieldID != NULL);
+ CHECK_NULL(widgetFieldID);
+
+ setWindowMethodID = (*env)->GetMethodID(env, cx, "setWindow", "(J)Z");
+ DASSERT(setWindowMethodID != NULL);
}
static gboolean filenameFilterCallback(const GtkFileFilterInfo * filter_info, gpointer obj)
@@ -401,7 +407,11 @@
fp_gtk_widget_show(dialog);
- fp_gtk_main();
+ XID xid = fp_gdk_x11_drawable_get_xid(dialog->window);
+ if( (*env)->CallBooleanMethod(env, jpeer, setWindowMethodID, xid) ) {
+ fp_gtk_main();
+ }
+
fp_gdk_threads_leave();
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/FileDialog/ModalFocus/FileDialogModalFocusTest.java Tue Jul 28 20:55:45 2015 +0300
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ @bug 8025815
+ @summary Child FileDialog of modal dialog does not get focus on Gnome
+ @author Semyon Sadetsky
+ */
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.image.BufferedImage;
+import java.lang.reflect.InvocationTargetException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+public class FileDialogModalFocusTest {
+ public static void main(String[] args) throws Exception {
+ Frame frame = new Frame();
+ FileDialog fileDialog = new FileDialog((Frame) null);
+ test(frame, fileDialog);
+ frame = new Frame();
+ fileDialog = new FileDialog(frame);
+ test(frame, fileDialog);
+ System.out.println("ok");
+ }
+
+ private static void test(final Frame frame, final FileDialog fileDialog)
+ throws InterruptedException, InvocationTargetException,
+ AWTException {
+ Button button = new Button();
+ button.setBackground(Color.RED);
+ button.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ fileDialog.setVisible(true);
+ }
+ });
+ frame.add(button);
+ frame.setSize(200, 200);
+ EventQueue.invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ frame.setVisible(true);
+ }
+ });
+ Robot robot = new Robot();
+ robot.setAutoDelay(200);
+ robot.waitForIdle();
+ Point point = button.getLocationOnScreen();
+ point.translate(100, 100);
+ robot.mouseMove(point.x, point.y);
+ robot.mousePress(InputEvent.BUTTON1_MASK);
+ robot.mouseRelease(InputEvent.BUTTON1_MASK);
+ int delay = 0;
+ while (frame.isFocused() && delay < 2000) {
+ robot.delay(50);
+ delay += 50;
+ }
+ ReentrantLock lock = new ReentrantLock();
+ Condition condition = lock.newCondition();
+ button.addComponentListener(new ComponentAdapter() {
+ @Override
+ public void componentResized(ComponentEvent e) {
+ lock.lock();
+ condition.signal();
+ lock.unlock();
+ }
+ });
+ lock.lock();
+ EventQueue.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
+ }
+ });
+ condition.await(5, TimeUnit.SECONDS);
+ lock.unlock();
+ robot.delay(200);
+ robot.waitForIdle();
+ EventQueue.invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ button.requestFocus();
+ Point p = new Point(button.getWidth() - 10, button.getHeight() - 10);
+ SwingUtilities.convertPointToScreen(p, button);
+ robot.mouseMove(p.x, p.y);
+ robot.mousePress(InputEvent.BUTTON1_MASK);
+ robot.mouseRelease(InputEvent.BUTTON1_MASK);
+ }
+ });
+ robot.waitForIdle();
+ Point p = new Point(100, 100);
+ SwingUtilities.convertPointToScreen(p, button);
+ BufferedImage image = robot.createScreenCapture(
+ new Rectangle(p,
+ new Dimension(button.getWidth() - 200,
+ button.getHeight() - 200)));
+ boolean found = false;
+ for (int x = 0; x < image.getWidth(); x+=50) {
+ for (int y = 0; y < image.getHeight(); y+=50) {
+ if( (image.getRGB(x, y) & 0x00FFFF) != 0 ) {
+ found = true;
+ break;
+ };
+ }
+ }
+ frame.dispose();
+ robot.waitForIdle();
+ fileDialog.dispose();
+ if(!found) {
+ throw new RuntimeException("file chooser is underneath");
+ }
+ }
+}
\ No newline at end of file