--- old/src/java.desktop/unix/classes/sun/awt/X11/GtkFileDialogPeer.java 2015-07-13 17:38:41.459258500 +0300 +++ new/src/java.desktop/unix/classes/sun/awt/X11/GtkFileDialogPeer.java 2015-07-13 17:38:40.959658600 +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; } } --- old/src/java.desktop/unix/native/libawt_xawt/awt/sun_awt_X11_GtkFileDialogPeer.c 2015-07-13 17:38:44.256817900 +0300 +++ new/src/java.desktop/unix/native/libawt_xawt/awt/sun_awt_X11_GtkFileDialogPeer.c 2015-07-13 17:38:43.729712500 +0300 @@ -27,6 +27,7 @@ #include #include #include +#include #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); + + setWindowMethodID = (*env)->GetMethodID(env, cx, "setWindow", "(J)Z"); + DASSERT(setWindowMethodID != NULL); + CHECK_NULL(setWindowMethodID); } 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(); } --- old/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h 2015-07-13 17:38:46.974361300 +0300 +++ new/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h 2015-07-13 17:38:46.425751600 +0300 @@ -27,6 +27,7 @@ #include #include +#include #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 --- old/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c 2015-07-13 17:38:49.852936900 +0300 +++ new/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c 2015-07-13 17:38:49.236813700 +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) --- old/src/java.desktop/unix/classes/sun/awt/X11/XNETProtocol.java 2015-07-13 17:38:52.692504700 +0300 +++ new/src/java.desktop/unix/classes/sun/awt/X11/XNETProtocol.java 2015-07-13 17:38:52.165899400 +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()); --- old/src/java.desktop/unix/classes/sun/awt/X11/XFramePeer.java 2015-07-13 17:38:55.368039700 +0300 +++ new/src/java.desktop/unix/classes/sun/awt/X11/XFramePeer.java 2015-07-13 17:38:54.864439000 +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); } --- /dev/null 2015-07-13 17:38:58.000000000 +0300 +++ new/test/java/awt/FileDialog/ModalFocus/FileDialogModalFocusTest.java 2015-07-13 17:38:57.533472700 +0300 @@ -0,0 +1,110 @@ +/* + * 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.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.image.BufferedImage; +import java.lang.reflect.InvocationTargetException; + +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; + } + EventQueue.invokeAndWait(new Runnable() { + @Override + public void run() { + frame.setSize(Toolkit.getDefaultToolkit().getScreenSize()); + button.requestFocus(); + } + }); + 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; + }; + } + } + fileDialog.dispose(); + frame.dispose(); + if(!found) { + throw new RuntimeException("file chooser is underneath"); + } + } +} \ No newline at end of file