1 /*
2  * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 package sun.awt.X11;
26 
27 import java.awt.FileDialog;
28 import java.awt.peer.FileDialogPeer;
29 import java.io.File;
30 import java.io.FilenameFilter;
31 import sun.awt.AWTAccessor;
32 
33 /**
34  * FileDialogPeer for the GtkFileChooser.
35  *
36  * @author Costantino Cerbo (c.cerbo@gmail.com)
37  */
38 final class GtkFileDialogPeer extends XDialogPeer implements FileDialogPeer {
39 
40     private final FileDialog fd;
41 
42     // A pointer to the native GTK FileChooser widget
43     private volatile long widget = 0L;
44     private long standaloneWindow;
45     private volatile boolean quit;
46 
GtkFileDialogPeer(FileDialog fd)47     GtkFileDialogPeer(FileDialog fd) {
48         super(fd);
49         this.fd = fd;
50     }
51 
initIDs()52     private static native void initIDs();
53     static {
initIDs()54         initIDs();
55     }
56 
run(String title, int mode, String dir, String file, FilenameFilter filter, boolean isMultipleMode, int x, int y)57     private native void run(String title, int mode, String dir, String file,
58                             FilenameFilter filter, boolean isMultipleMode, int x, int y);
quit()59     private native void quit();
60 
61     @Override
toFront()62     public native void toFront();
63 
64     @Override
setBounds(int x, int y, int width, int height, int op)65     public native void setBounds(int x, int y, int width, int height, int op);
66 
67     /**
68      * Called exclusively by the native C code.
69      */
setFileInternal(String directory, String[] filenames)70     private void setFileInternal(String directory, String[] filenames) {
71         AWTAccessor.FileDialogAccessor accessor = AWTAccessor
72                 .getFileDialogAccessor();
73 
74         if (filenames == null) {
75             accessor.setDirectory(fd, null);
76             accessor.setFile(fd, null);
77             accessor.setFiles(fd, null);
78         } else {
79             // Fix 6987233: add the trailing slash if it's absent
80             String with_separator = directory;
81             if (directory != null) {
82                 with_separator = directory.endsWith(File.separator) ?
83                         directory : (directory + File.separator);
84             }
85             accessor.setDirectory(fd, with_separator);
86             accessor.setFile(fd, filenames[0]);
87 
88             int filesNumber = (filenames != null) ? filenames.length : 0;
89             File[] files = new File[filesNumber];
90             for (int i = 0; i < filesNumber; i++) {
91                 files[i] = new File(directory, filenames[i]);
92             }
93             accessor.setFiles(fd, files);
94         }
95     }
96 
97     /**
98      * Called exclusively by the native C code.
99      */
filenameFilterCallback(String fullname)100     private boolean filenameFilterCallback(String fullname) {
101         if (fd.getFilenameFilter() == null) {
102             // no filter, accept all.
103             return true;
104         }
105 
106         File filen = new File(fullname);
107         return fd.getFilenameFilter().accept(new File(filen.getParent()),
108                 filen.getName());
109     }
110 
111     @Override
setVisible(boolean b)112     public void setVisible(boolean b) {
113         XToolkit.awtLock();
114         try {
115             quit = !b;
116             if (b) {
117                 Runnable task = () -> {
118                     showNativeDialog();
119                     standaloneWindow = 0;
120                     fd.setVisible(false);
121                 };
122                 new Thread(null, task, "ShowDialog", 0, false).start();
123             } else {
124                 quit();
125                 fd.setVisible(false);
126             }
127         } finally {
128             XToolkit.awtUnlock();
129         }
130     }
131 
132     @Override
dispose()133     public void dispose() {
134         XToolkit.awtLock();
135         try {
136             quit = true;
137             quit();
138         }
139         finally {
140             XToolkit.awtUnlock();
141         }
142         super.dispose();
143     }
144 
145     @Override
setDirectory(String dir)146     public void setDirectory(String dir) {
147         // We do not implement this method because we
148         // have delegated to FileDialog#setDirectory
149     }
150 
151     @Override
setFile(String file)152     public void setFile(String file) {
153         // We do not implement this method because we
154         // have delegated to FileDialog#setFile
155     }
156 
requestXFocus(long time, boolean timeProvided)157     protected void requestXFocus(long time, boolean timeProvided) {
158         if(standaloneWindow == 0) {
159             super.requestXFocus(time, timeProvided);
160             return;
161         }
162         XNETProtocol net_protocol = XWM.getWM().getNETProtocol();
163         if (net_protocol != null) {
164             net_protocol.setActiveWindow(standaloneWindow);
165         }
166     }
167 
168     @Override
setFilenameFilter(FilenameFilter filter)169     public void setFilenameFilter(FilenameFilter filter) {
170         // We do not implement this method because we
171         // have delegated to FileDialog#setFilenameFilter
172     }
173 
showNativeDialog()174     private void showNativeDialog() {
175         String dirname = fd.getDirectory();
176         // File path has a priority against directory path.
177         String filename = fd.getFile();
178         if (filename != null) {
179             final File file = new File(filename);
180             if (fd.getMode() == FileDialog.LOAD
181                 && dirname != null
182                 && file.getParent() == null) {
183                 // File path for gtk_file_chooser_set_filename.
184                 filename = dirname + (dirname.endsWith(File.separator) ? "" :
185                                               File.separator) + filename;
186             }
187             if (fd.getMode() == FileDialog.SAVE && file.getParent() != null) {
188                 // Filename for gtk_file_chooser_set_current_name.
189                 filename = file.getName();
190                 // Directory path for gtk_file_chooser_set_current_folder.
191                 dirname = file.getParent();
192             }
193         }
194         if (!quit) {
195             run(fd.getTitle(), fd.getMode(), dirname, filename,
196                     fd.getFilenameFilter(), fd.isMultipleMode(), fd.getX(), fd.getY());
197         }
198     }
199 
200     /**
201      * Called by native code when GTK dialog is created.
202      */
setWindow(long xid)203     boolean setWindow(long xid) {
204         if (!quit && widget != 0) {
205             standaloneWindow = xid;
206             requestXFocus();
207             return true;
208         }
209         return false;
210     }
211 }
212