Skip to content

Commit 97632d3

Browse files
mkartashevjbrbot
authored and
jbrbot
committed
JBR-7087 Wayland: GtkFileDialogPeer implementation
1 parent c43d03d commit 97632d3

File tree

8 files changed

+598
-5
lines changed

8 files changed

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

src/java.desktop/unix/classes/sun/awt/wl/WLToolkit.java

+19-3
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ public class WLToolkit extends UNIXToolkit implements Runnable {
160160

161161
private static Cursor currentCursor;
162162

163+
private static Boolean sunAwtDisableGtkFileDialogs = null;
164+
163165
private static native void initIDs(long displayPtr);
164166

165167
static {
@@ -202,6 +204,13 @@ public WLToolkit() {
202204
}
203205
}
204206

207+
public static synchronized boolean getSunAwtDisableGtkFileDialogs() {
208+
if (sunAwtDisableGtkFileDialogs == null) {
209+
sunAwtDisableGtkFileDialogs = Boolean.getBoolean("sun.awt.disableGtkFileDialogs");
210+
}
211+
return sunAwtDisableGtkFileDialogs;
212+
}
213+
205214
private static void initSystemProperties() {
206215
final String extraButtons = "sun.awt.enableExtraMouseButtons";
207216
areExtraMouseButtonsEnabled =
@@ -680,10 +689,17 @@ public DialogPeer createDialog(Dialog target) {
680689

681690
@Override
682691
public FileDialogPeer createFileDialog(FileDialog target) {
683-
if (log.isLoggable(PlatformLogger.Level.FINE)) {
684-
log.fine("Not implemented: WLToolkit.createFileDialog()");
692+
FileDialogPeer peer = null;
693+
if (!getSunAwtDisableGtkFileDialogs() && checkGtkVersion(3, 0, 0)) {
694+
peer = new GtkFileDialogPeer(target);
695+
targetCreatedPeer(target, peer);
696+
return peer;
697+
} else {
698+
if (log.isLoggable(PlatformLogger.Level.FINE)) {
699+
log.fine("Not implemented: WLToolkit.createFileDialog()");
700+
}
701+
return null;
685702
}
686-
return null;
687703
}
688704

689705
@Override

0 commit comments

Comments
 (0)