|
24 | 24 | import java.awt.geom.AffineTransform; |
25 | 25 | import javax.swing.JDialog; |
26 | 26 | import javax.swing.JFrame; |
| 27 | +import javax.swing.JOptionPane; |
27 | 28 | import com.formdev.flatlaf.util.SystemInfo; |
28 | 29 |
|
29 | 30 | /** |
|
34 | 35 | * @author Karl Tauber |
35 | 36 | * @since 2.5 |
36 | 37 | */ |
37 | | -class FlatNativeLinuxLibrary |
| 38 | +public class FlatNativeLinuxLibrary |
38 | 39 | { |
39 | | - private static int API_VERSION_LINUX = 3001; |
| 40 | + private static int API_VERSION_LINUX = 3002; |
40 | 41 |
|
41 | 42 | /** |
42 | 43 | * Checks whether native library is loaded/available. |
43 | 44 | * <p> |
44 | 45 | * <b>Note</b>: It is required to invoke this method before invoking any other |
45 | 46 | * method of this class. Otherwise, the native library may not be loaded. |
46 | 47 | */ |
47 | | - static boolean isLoaded() { |
| 48 | + public static boolean isLoaded() { |
48 | 49 | return SystemInfo.isLinux && FlatNativeLibrary.isLoaded( API_VERSION_LINUX ); |
49 | 50 | } |
50 | 51 |
|
| 52 | + |
| 53 | + //---- X Window System ---------------------------------------------------- |
| 54 | + |
51 | 55 | // direction for _NET_WM_MOVERESIZE message |
52 | 56 | // see https://specifications.freedesktop.org/wm-spec/latest/ar01s04.html |
53 | 57 | static final int |
@@ -124,4 +128,109 @@ private static boolean hasCustomDecoration( Window window ) { |
124 | 128 | return (window instanceof JFrame && JFrame.isDefaultLookAndFeelDecorated() && ((JFrame)window).isUndecorated()) || |
125 | 129 | (window instanceof JDialog && JDialog.isDefaultLookAndFeelDecorated() && ((JDialog)window).isUndecorated()); |
126 | 130 | } |
| 131 | + |
| 132 | + |
| 133 | + //---- GTK ---------------------------------------------------------------- |
| 134 | + |
| 135 | + private static Boolean isGtk3Available; |
| 136 | + |
| 137 | + /** |
| 138 | + * Checks whether GTK 3 is available. |
| 139 | + * Use this before invoking any native method that uses GTK. |
| 140 | + * Otherwise the app may terminate immediately if GTK is not installed. |
| 141 | + * <p> |
| 142 | + * This works because Java uses {@code dlopen(RTLD_LAZY)} to load JNI libraries, |
| 143 | + * which only resolves symbols as the code that references them is executed. |
| 144 | + * |
| 145 | + * @since 3.7 |
| 146 | + */ |
| 147 | + public static boolean isGtk3Available() { |
| 148 | + if( isGtk3Available == null ) |
| 149 | + isGtk3Available = isLibAvailable( "libgtk-3.so.0" ) || isLibAvailable( "libgtk-3.so" ); |
| 150 | + return isGtk3Available; |
| 151 | + } |
| 152 | + |
| 153 | + private native static boolean isLibAvailable( String libname ); |
| 154 | + |
| 155 | + /** |
| 156 | + * https://docs.gtk.org/gtk3/iface.FileChooser.html#properties |
| 157 | + * |
| 158 | + * @since 3.7 |
| 159 | + */ |
| 160 | + public static final int |
| 161 | + FC_select_folder = 1 << 0, |
| 162 | + FC_select_multiple = 1 << 1, |
| 163 | + FC_show_hidden = 1 << 2, |
| 164 | + FC_local_only = 1 << 3, // default |
| 165 | + FC_do_overwrite_confirmation = 1 << 4, // GTK 3 only; removed and always-on in GTK 4 |
| 166 | + FC_create_folders = 1 << 5; // default for Save |
| 167 | + |
| 168 | + /** |
| 169 | + * Shows the Linux/GTK system file dialog |
| 170 | + * <a href="https://docs.gtk.org/gtk3/class.FileChooserDialog.html">GtkFileChooserDialog</a>. |
| 171 | + * <p> |
| 172 | + * Uses {@code GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER} if {@link #FC_select_folder} is set in parameter {@code optionsSet}. |
| 173 | + * Otherwise uses {@code GTK_FILE_CHOOSER_ACTION_OPEN} if parameter {@code open} is {@code true}, |
| 174 | + * or {@code GTK_FILE_CHOOSER_ACTION_SAVE} if {@code false}. |
| 175 | + * <p> |
| 176 | + * <b>Note:</b> This method blocks the current thread until the user closes |
| 177 | + * the file dialog. It is highly recommended to invoke it from a new thread |
| 178 | + * to avoid blocking the AWT event dispatching thread. |
| 179 | + * |
| 180 | + * @param owner the owner of the file dialog; or {@code null} |
| 181 | + * @param open if {@code true}, shows the open dialog; if {@code false}, shows the save dialog |
| 182 | + * @param title text displayed in dialog title; or {@code null} |
| 183 | + * @param okButtonLabel text displayed in default button; or {@code null}. |
| 184 | + * Use '_' for mnemonics (e.g. "_Choose") |
| 185 | + * Use '__' for '_' character (e.g. "Choose__and__Quit"). |
| 186 | + * @param currentName user-editable filename currently shown in the filename field in save dialog; or {@code null} |
| 187 | + * @param currentFolder current directory shown in the dialog; or {@code null} |
| 188 | + * @param optionsSet options to set; see {@code FOS_*} constants |
| 189 | + * @param optionsClear options to clear; see {@code FOS_*} constants |
| 190 | + * @param callback approve callback; or {@code null} |
| 191 | + * @param fileTypeIndex the file type that appears as selected (zero-based) |
| 192 | + * @param fileTypes file types that the dialog can open or save. |
| 193 | + * Two or more strings and {@code null} are required for each filter. |
| 194 | + * First string is the display name of the filter shown in the combobox (e.g. "Text Files"). |
| 195 | + * Subsequent strings are the filter patterns (e.g. "*.txt" or "*"). |
| 196 | + * {@code null} is required to mark end of filter. |
| 197 | + * @return file path(s) that the user selected; an empty array if canceled; |
| 198 | + * or {@code null} on failures (no dialog shown) |
| 199 | + * |
| 200 | + * @since 3.7 |
| 201 | + */ |
| 202 | + public native static String[] showFileChooser( Window owner, boolean open, |
| 203 | + String title, String okButtonLabel, String currentName, String currentFolder, |
| 204 | + int optionsSet, int optionsClear, FileChooserCallback callback, |
| 205 | + int fileTypeIndex, String... fileTypes ); |
| 206 | + |
| 207 | + /** @since 3.7 */ |
| 208 | + public interface FileChooserCallback { |
| 209 | + boolean approve( String[] files, long hwndFileDialog ); |
| 210 | + } |
| 211 | + |
| 212 | + /** |
| 213 | + * Shows a GTK message box |
| 214 | + * <a href="https://docs.gtk.org/gtk3/class.MessageDialog.html">GtkMessageDialog</a>. |
| 215 | + * <p> |
| 216 | + * For use in {@link FileChooserCallback} only. |
| 217 | + * |
| 218 | + * @param hwndParent the parent of the message box |
| 219 | + * @param messageType type of message being displayed: |
| 220 | + * {@link JOptionPane#ERROR_MESSAGE}, {@link JOptionPane#INFORMATION_MESSAGE}, |
| 221 | + * {@link JOptionPane#WARNING_MESSAGE}, {@link JOptionPane#QUESTION_MESSAGE} or |
| 222 | + * {@link JOptionPane#PLAIN_MESSAGE} |
| 223 | + * @param primaryText primary text; if the dialog has a secondary text, |
| 224 | + * this will appear as title in a larger bold font |
| 225 | + * @param secondaryText secondary text; shown below of primary text; or {@code null} |
| 226 | + * @param defaultButton index of the default button, which can be pressed using ENTER key |
| 227 | + * @param buttons texts of the buttons; if no buttons given the a default "OK" button is shown. |
| 228 | + * Use '_' for mnemonics (e.g. "_Choose") |
| 229 | + * Use '__' for '_' character (e.g. "Choose__and__Quit"). |
| 230 | + * @return index of pressed button; or -1 for ESC key |
| 231 | + * |
| 232 | + * @since 3.7 |
| 233 | + */ |
| 234 | + public native static int showMessageDialog( long hwndParent, int messageType, |
| 235 | + String primaryText, String secondaryText, int defaultButton, String... buttons ); |
127 | 236 | } |
0 commit comments