diff --git a/src/dorkbox/util/jna/linux/AppIndicator.java b/src/dorkbox/util/jna/linux/AppIndicator.java new file mode 100644 index 0000000..bc0ea2f --- /dev/null +++ b/src/dorkbox/util/jna/linux/AppIndicator.java @@ -0,0 +1,197 @@ +/* + * Copyright 2015 dorkbox, llc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package dorkbox.util.jna.linux; + +import org.slf4j.LoggerFactory; + +import com.sun.jna.NativeLibrary; +import com.sun.jna.Pointer; + +import dorkbox.util.OS; +import dorkbox.util.jna.JnaHelper; +import dorkbox.util.jna.linux.structs.AppIndicatorInstanceStruct; + +/** + * bindings for libappindicator + * + * Direct-mapping, See: https://github.com/java-native-access/jna/blob/master/www/DirectMapping.md + */ +@SuppressWarnings({"Duplicates", "SameParameterValue", "DanglingJavadoc"}) +public +class AppIndicator { + public static final boolean isVersion3; + public static final boolean isLoaded; + + /** + * Loader for AppIndicator, because it is absolutely mindboggling how those whom maintain the standard, can't agree to what that + * standard library naming convention or features/API set is. We just try until we find one that works, and are able to map the + * symbols we need. There are bash commands that will tell us the linked library name, however - I'd rather not run bash commands + * to determine this. + * + * This is so hacky it makes me sick. + */ + static { + boolean _isVersion3 = false; + boolean _isLoaded = false; + + boolean shouldLoadAppIndicator = !(OS.isWindows() || OS.isMacOsX()); + if (!shouldLoadAppIndicator) { + _isLoaded = true; + } + + // objdump -T /usr/lib/x86_64-linux-gnu/libappindicator.so.1 | grep foo + // objdump -T /usr/lib/x86_64-linux-gnu/libappindicator3.so.1 | grep foo + + // NOTE: + // ALSO WHAT VERSION OF GTK to use? appindiactor1 -> GTK2, appindicator3 -> GTK3. + // appindiactor1 is GKT2 only (can't use GTK3 bindings with it) + // appindicator3 doesn't support menu icons via GTK2!! + +// if (!_isLoaded && SystemTray.FORCE_TRAY_TYPE == SystemTray.TrayType.GtkStatusIcon) { +// // if we force GTK type system tray, don't attempt to load AppIndicator libs +// if (GtkEventDispatch.DEBUG) { +// LoggerFactory.getLogger(AppIndicator.class).debug("Forced GtkStatusIcon tray type, not using AppIndicator"); +// } +// _isLoaded = true; +// } + + if (!_isLoaded && GtkEventDispatch.FORCE_GTK2) { + // if specified, try loading appindicator1 first, maybe it's there? + // note: we can have GTK2 + appindicator3, but NOT ALWAYS. + try { + // deliberately without the "1" at the end. + final NativeLibrary library = JnaHelper.register("appindicator", AppIndicator.class); + if (library != null) { + _isLoaded = true; + } + } catch (Throwable e) { + if (GtkEventDispatch.DEBUG) { + LoggerFactory.getLogger(AppIndicator.class).debug("Error loading GTK2 explicit appindicator. {}", e.getMessage()); + } + } + } + + String nameToCheck1; + String nameToCheck2; + + if (Gtk.isGtk2) { + nameToCheck1 = "appindicator"; // deliberately without the "1" at the end. + } + else { + nameToCheck1 = "appindicator3"; + } + + // start with base version using whatever the OS specifies as the proper symbolic link + if (!_isLoaded) { + try { + final NativeLibrary library = JnaHelper.register(nameToCheck1, AppIndicator.class); + String s = library.getFile().getName(); + + if (GtkEventDispatch.DEBUG) { + LoggerFactory.getLogger(AppIndicator.class).debug("Loading library (first attempt): '{}'", s); + } + + if (s.contains("appindicator3")) { + _isVersion3 = true; + } + + _isLoaded = true; + } catch (Throwable e) { + if (GtkEventDispatch.DEBUG) { + LoggerFactory.getLogger(AppIndicator.class).debug("Error loading library: '{}'. \n{}", nameToCheck1, e.getMessage()); + } + } + } + + // maybe it's really GTK2 version? who knows... + if (!_isLoaded) { + try { + JnaHelper.register("appindicator", AppIndicator.class); + _isLoaded = true; + } catch (Throwable e) { + if (GtkEventDispatch.DEBUG) { + LoggerFactory.getLogger(AppIndicator.class).debug("Error loading library: '{}'. \n{}", "appindicator", e.getMessage()); + } + } + } + + // If we are GTK2, change the order we check and load libraries + + if (Gtk.isGtk2) { + nameToCheck1 = "appindicator-gtk"; + nameToCheck2 = "appindicator-gtk3"; + } + else { + nameToCheck1 = "appindicator-gtk3"; + nameToCheck2 = "appindicator-gtk"; + } + + // another type. who knows... + if (!_isLoaded) { + try { + JnaHelper.register(nameToCheck1, AppIndicator.class); + _isLoaded = true; + } catch (Throwable e) { + if (GtkEventDispatch.DEBUG) { + LoggerFactory.getLogger(AppIndicator.class).debug("Error loading library: '{}'. \n{}", nameToCheck1, e.getMessage()); + } + } + } + + // this is HORRID. such a PITA + if (!_isLoaded) { + try { + JnaHelper.register(nameToCheck2, AppIndicator.class); + _isLoaded = true; + } catch (Throwable e) { + if (GtkEventDispatch.DEBUG) { + LoggerFactory.getLogger(AppIndicator.class).debug("Error loading library: '{}'. \n{}", nameToCheck2, e.getMessage()); + } + } + } + + // We fall back to GtkStatusIndicator or Swing if this cannot load + if (shouldLoadAppIndicator && _isLoaded) { + isLoaded = true; + isVersion3 = _isVersion3; + } else { + isLoaded = false; + isVersion3 = false; + } + } + + // Note: AppIndicators DO NOT support tooltips, as per mark shuttleworth. Rather stupid IMHO. + // See: https://bugs.launchpad.net/indicator-application/+bug/527458/comments/12 + + public static final int CATEGORY_APPLICATION_STATUS = 0; +// public static final int CATEGORY_COMMUNICATIONS = 1; +// public static final int CATEGORY_SYSTEM_SERVICES = 2; +// public static final int CATEGORY_HARDWARE = 3; +// public static final int CATEGORY_OTHER = 4; + + public static final int STATUS_PASSIVE = 0; + public static final int STATUS_ACTIVE = 1; +// public static final int STATUS_ATTENTION = 2; + + + public static native + AppIndicatorInstanceStruct app_indicator_new(String id, String icon_name, int category); + + public static native void app_indicator_set_title(AppIndicatorInstanceStruct self, String title); + public static native void app_indicator_set_status(AppIndicatorInstanceStruct self, int status); + public static native void app_indicator_set_menu(AppIndicatorInstanceStruct self, Pointer menu); + public static native void app_indicator_set_icon(AppIndicatorInstanceStruct self, String icon_name); +} diff --git a/src/dorkbox/util/jna/linux/FuncCallback.java b/src/dorkbox/util/jna/linux/FuncCallback.java new file mode 100644 index 0000000..7039979 --- /dev/null +++ b/src/dorkbox/util/jna/linux/FuncCallback.java @@ -0,0 +1,29 @@ +/* + * Copyright 2015 dorkbox, llc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package dorkbox.util.jna.linux; + +import com.sun.jna.Callback; +import com.sun.jna.Pointer; + +import dorkbox.util.Keep; + +@Keep +interface FuncCallback extends Callback { + /** + * @return Gtk.FALSE if it will be automatically removed from the stack once it's handled + */ + int callback(Pointer data); +} diff --git a/src/dorkbox/util/jna/linux/GCallback.java b/src/dorkbox/util/jna/linux/GCallback.java new file mode 100644 index 0000000..03e258c --- /dev/null +++ b/src/dorkbox/util/jna/linux/GCallback.java @@ -0,0 +1,30 @@ +/* + * Copyright 2015 dorkbox, llc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package dorkbox.util.jna.linux; + +import com.sun.jna.Callback; +import com.sun.jna.Pointer; + +import dorkbox.util.Keep; + +@Keep +public +interface GCallback extends Callback { + /** + * @return Gtk.TRUE if we handled this event + */ + int callback(Pointer instance, Pointer data); +} diff --git a/src/dorkbox/util/jna/linux/GEventCallback.java b/src/dorkbox/util/jna/linux/GEventCallback.java new file mode 100644 index 0000000..8c61ebe --- /dev/null +++ b/src/dorkbox/util/jna/linux/GEventCallback.java @@ -0,0 +1,28 @@ +/* + * Copyright 2015 dorkbox, llc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package dorkbox.util.jna.linux; + +import com.sun.jna.Callback; +import com.sun.jna.Pointer; + +import dorkbox.util.Keep; +import dorkbox.util.jna.linux.structs.GdkEventButton; + +@Keep +public +interface GEventCallback extends Callback { + void callback(Pointer instance, GdkEventButton event); +} diff --git a/src/dorkbox/util/jna/linux/Glib.java b/src/dorkbox/util/jna/linux/Glib.java new file mode 100644 index 0000000..5d8aa9d --- /dev/null +++ b/src/dorkbox/util/jna/linux/Glib.java @@ -0,0 +1,73 @@ +/* + * Copyright 2017 dorkbox, llc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package dorkbox.util.jna.linux; + +import org.slf4j.LoggerFactory; + +import com.sun.jna.Callback; +import com.sun.jna.NativeLibrary; +import com.sun.jna.Pointer; + +import dorkbox.util.jna.JnaHelper; + +/** + * bindings for glib-2.0 + * + * Direct-mapping, See: https://github.com/java-native-access/jna/blob/master/www/DirectMapping.md + */ +public +class Glib { + static { + try { + NativeLibrary library = JnaHelper.register("glib-2.0", Glib.class); + if (library == null) { + LoggerFactory.getLogger(Glib.class).error("Error loading Glib library, it failed to load."); + } + } catch (Throwable e) { + LoggerFactory.getLogger(Glib.class).error("Error loading Glib library, it failed to load {}", e.getMessage()); + } + } + + public interface GLogLevelFlags { + public static final int RECURSION = 1 << 0; + public static final int FATAL = 1 << 1; + /* GLib log levels */ + public static final int ERROR = 1 << 2; /* always fatal */ + public static final int CRITICAL = 1 << 3; + public static final int WARNING = 1 << 4; + public static final int MESSAGE = 1 << 5; + public static final int INFO = 1 << 6; + public static final int DEBUG = 1 << 7; + public static final int MASK = ~(RECURSION | FATAL); + } + + public interface GLogFunc extends Callback { + void callback (String log_domain, int log_level, String message, Pointer data); + } + + public static final Glib.GLogFunc nullLogFunc = new Glib.GLogFunc() { + @Override + public + void callback(final String log_domain, final int log_level, final String message, final Pointer data) { + // do nothing + } + }; + + public static native int g_log_set_handler(String log_domain, int levels, GLogFunc handler, Pointer user_data); + public static native void g_log_default_handler (String log_domain, int log_level, String message, Pointer unused_data); + public static native GLogFunc g_log_set_default_handler(GLogFunc log_func, Pointer user_data); + public static native void g_log_remove_handler (String log_domain, int handler_id); +} diff --git a/src/dorkbox/util/jna/linux/Gobject.java b/src/dorkbox/util/jna/linux/Gobject.java new file mode 100644 index 0000000..7b60aad --- /dev/null +++ b/src/dorkbox/util/jna/linux/Gobject.java @@ -0,0 +1,76 @@ +/* + * Copyright 2015 dorkbox, llc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package dorkbox.util.jna.linux; + +import org.slf4j.LoggerFactory; + +import com.sun.jna.Callback; +import com.sun.jna.NativeLibrary; +import com.sun.jna.Pointer; + +import dorkbox.util.jna.JnaHelper; + +/** + * bindings for libgobject-2.0 + * + * Direct-mapping, See: https://github.com/java-native-access/jna/blob/master/www/DirectMapping.md + */ +public +class Gobject { + + static { + try { + NativeLibrary library = JnaHelper.register("gobject-2.0", Gobject.class); + if (library == null) { + LoggerFactory.getLogger(Gobject.class).error("Error loading GObject library, it failed to load."); + } + } catch (Throwable e) { + LoggerFactory.getLogger(Gobject.class).error("Error loading GObject library, it failed to load {}", e.getMessage()); + } + } + + // objdump -T /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0 | grep block + + public static native void g_object_unref(Pointer object); + + public static native void g_object_force_floating(Pointer object); + public static native void g_object_ref_sink(Pointer object); + + // note: the return type here MUST be long to avoid issues on freeBSD. NativeLong (previously used) worked on everything except BSD. + public static native long g_signal_connect_object(Pointer instance, String detailed_signal, Callback c_handler, Pointer object, int connect_flags); + + public static native void g_signal_handler_block(Pointer instance, long handlerId); + public static native void g_signal_handler_unblock(Pointer instance, long handlerId); + + public static native void g_object_get(Pointer instance, String property_name, Pointer value, Pointer terminator); + + + + // Types are here https://developer.gnome.org/gobject/stable/gobject-Type-Information.html + public static native void g_value_init(Pointer gvalue, double type); + + /** + * Clears the current value in value (if any) and "unsets" the type, this releases all resources associated with this GValue. + * An unset value is the same as an uninitialized (zero-filled) GValue structure. + */ + public static native void g_value_unset(Pointer gvalue); + + public static native String g_value_get_string(Pointer gvalue); + public static native int g_value_get_int(Pointer gvalue); + + public static native Pointer g_type_class_ref(Pointer widgetType); + public static native void g_type_class_unref(Pointer widgetClass); +} diff --git a/src/dorkbox/util/jna/linux/Gtk.java b/src/dorkbox/util/jna/linux/Gtk.java new file mode 100644 index 0000000..76355af --- /dev/null +++ b/src/dorkbox/util/jna/linux/Gtk.java @@ -0,0 +1,383 @@ +/* + * Copyright 2015 dorkbox, llc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package dorkbox.util.jna.linux; + +import com.sun.jna.Function; +import com.sun.jna.Pointer; + +import dorkbox.util.jna.linux.structs.GtkStyle; + +/** + * Bindings for GTK+ 2. Bindings that are exclusively for GTK+ 3 are in that respective class + *
+ * Direct-mapping, See: https://github.com/java-native-access/jna/blob/master/www/DirectMapping.md + */ +@SuppressWarnings({"Duplicates", "SameParameterValue", "DeprecatedIsStillUsed", "WeakerAccess"}) +public +interface Gtk { + // objdump -T /usr/lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0 | grep gtk + // objdump -T /usr/lib/x86_64-linux-gnu/libgtk-3.so.0 | grep gtk + // objdump -T /usr/local/lib/libgtk-3.so.0 | grep gtk + + // For funsies to look at, SyncThing did a LOT of work on compatibility in python (unfortunate for us, but interesting). + // https://github.com/syncthing/syncthing-gtk/blob/b7a3bc00e3bb6d62365ae62b5395370f3dcc7f55/syncthing_gtk/statusicon.py + + + // make specific versions of GTK2 vs GTK3 APIs + // ALSO, GTK must be loaded via .init() + Gtk Gtk2 = GtkLoader.init() && GtkLoader.isGtk2 ? new Gtk2() : new Gtk3(); + Gtk3 Gtk3 = GtkLoader.isGtk2 ? null : (Gtk3) Gtk2; + + boolean isGtk2 = GtkLoader.isGtk2; + boolean isGtk3 = GtkLoader.isGtk3; + boolean isLoaded = GtkLoader.isLoaded; + + boolean alreadyRunningGTK = GtkLoader.alreadyRunningGTK; + + Function gtk_status_icon_position_menu = GtkLoader.gtk_status_icon_position_menu; + + int FALSE = 0; + int TRUE = 1; + + int MAJOR = GtkLoader.MAJOR; + int MINOR = GtkLoader.MINOR; + int MICRO = GtkLoader.MICRO; + + /** + * Adds a function to be called whenever there are no higher priority events pending. If the function returns FALSE it is automatically + * removed from the list of event sources and will not be called again. + *
+ * This variant of g_idle_add_full() calls function with the GDK lock held. It can be thought of a MT-safe version for GTK+ widgets + * for the following use case, where you have to worry about idle_callback() running in thread A and accessing self after it has + * been finalized in thread B. + */ + int gdk_threads_add_idle_full(int priority, FuncCallback function, Pointer data, Pointer notify); + + /** + * This would NORMALLY have a 2nd argument that is a String[] -- however JNA direct-mapping DOES NOT support this. We are lucky + * enough that we just pass 'null' as the second argument, therefore, we don't have to define that parameter here. + */ + boolean gtk_init_check(int argc); + + /** + * Runs the main loop until gtk_main_quit() is called. You can nest calls to gtk_main(). In that case gtk_main_quit() will make the + * innermost invocation of the main loop return. + */ + void gtk_main(); + + /** + * aks for the current nesting level of the main loop. Useful to determine (at startup) if GTK is already running + */ + int gtk_main_level(); + + /** + * Makes the innermost invocation of the main loop return when it regains control. ONLY CALL FROM THE GtkSupport class, UNLESS you know + * what you're doing! + */ + void gtk_main_quit(); + + + + /** + * Creates a new GtkMenu + */ + Pointer gtk_menu_new(); + + /** + * Sets or replaces the menu item’s submenu, or removes it when a NULL submenu is passed. + */ + void gtk_menu_item_set_submenu(Pointer menuEntry, Pointer menu); + + /** + * Creates a new GtkSeparatorMenuItem. + */ + Pointer gtk_separator_menu_item_new(); + + /** + * Creates a new GtkImage displaying the file filename . If the file isn’t found or can’t be loaded, the resulting GtkImage will + * display a “broken image” icon. This function never returns NULL, it always returns a valid GtkImage widget. + *
+ * If the file contains an animation, the image will contain an animation. + */ + Pointer gtk_image_new_from_file(String iconPath); + + /** + * Sets the active state of the menu item’s check box. + */ + void gtk_check_menu_item_set_active(Pointer check_menu_item, boolean isChecked); + + /** + * Creates a new GtkImageMenuItem containing a label. The label will be created using gtk_label_new_with_mnemonic(), so underscores + * in label indicate the mnemonic for the menu item. + *
+ * uses '_' to define which key is the mnemonic + *
+ * gtk_image_menu_item_new_with_mnemonic has been deprecated since version 3.10 and should not be used in newly-written code. + * NOTE: Use gtk_menu_item_new_with_mnemonic() instead. + */ + Pointer gtk_image_menu_item_new_with_mnemonic(String label); + + Pointer gtk_check_menu_item_new_with_mnemonic(String label); + + /** + * Sets the image of image_menu_item to the given widget. Note that it depends on the show-menu-images setting whether the image + * will be displayed or not. + *
+ * gtk_image_menu_item_set_image has been deprecated since version 3.10 and should not be used in newly-written code. + */ + void gtk_image_menu_item_set_image(Pointer image_menu_item, Pointer image); + + /** + * If TRUE, the menu item will ignore the “gtk-menu-images” setting and always show the image, if available. + * Use this property if the menuitem would be useless or hard to use without the image + *
+ * gtk_image_menu_item_set_always_show_image has been deprecated since version 3.10 and should not be used in newly-written code. + */ + void gtk_image_menu_item_set_always_show_image(Pointer menu_item, boolean forceShow); + + /** + * Creates an empty status icon object. + *
+ * gtk_status_icon_new has been deprecated since version 3.14 and should not be used in newly-written code. + * Use notifications + */ + Pointer gtk_status_icon_new(); + + /** + * Obtains the root window (parent all other windows are inside) for the default display and screen. + * + * @return the default root window + */ + Pointer gdk_get_default_root_window(); + + /** + * Gets the default screen for the default display. (See gdk_display_get_default()). + * + * @return a GdkScreen, or NULL if there is no default display. + * + * @since 2.2 + */ + Pointer gdk_screen_get_default(); + + /** + * Gets the resolution for font handling on the screen; see gdk_screen_set_resolution() for full details. + * + * IE: + * + * The resolution for font handling on the screen. This is a scale factor between points specified in a PangoFontDescription and + * cairo units. The default value is 96, meaning that a 10 point font will be 13 units high. (10 * 96. / 72. = 13.3). + * + * @return the current resolution, or -1 if no resolution has been set. + * + * @since Since: 2.10 + */ + double gdk_screen_get_resolution(Pointer screen); + + /** + * Makes status_icon display the file filename . See gtk_status_icon_new_from_file() for details. + *
+ * gtk_status_icon_set_from_file has been deprecated since version 3.14 and should not be used in newly-written code. + * Use notifications + */ + void gtk_status_icon_set_from_file(Pointer widget, String label); + + /** + * Shows or hides a status icon. + *
+ * gtk_status_icon_set_visible has been deprecated since version 3.14 and should not be used in newly-written code. + * Use notifications + */ + void gtk_status_icon_set_visible(Pointer widget, boolean visible); + + + /** + * Sets text as the contents of the tooltip. + * This function will take care of setting “has-tooltip” to TRUE and of the default handler for the “query-tooltip” signal. + * + * app indicators don't support this + * + * gtk_status_icon_set_tooltip_text has been deprecated since version 3.14 and should not be used in newly-written code. + * Use notifications + */ + void gtk_status_icon_set_tooltip_text(Pointer widget, String tooltipText); + + /** + * Sets the title of this tray icon. This should be a short, human-readable, localized string describing the tray icon. It may be used + * by tools like screen readers to render the tray icon. + *
+ * gtk_status_icon_set_title has been deprecated since version 3.14 and should not be used in newly-written code. + * Use notifications + */ + void gtk_status_icon_set_title(Pointer widget, String titleText); + + /** + * Sets the name of this tray icon. This should be a string identifying this icon. It is may be used for sorting the icons in the + * tray and will not be shown to the user. + *
+ * gtk_status_icon_set_name has been deprecated since version 3.14 and should not be used in newly-written code. + * Use notifications + */ + void gtk_status_icon_set_name(Pointer widget, String name); + + /** + * Displays a menu and makes it available for selection. + *
+ * gtk_menu_popup has been deprecated since version 3.22 and should not be used in newly-written code. + * NOTE: Please use gtk_menu_popup_at_widget(), gtk_menu_popup_at_pointer(). or gtk_menu_popup_at_rect() instead + */ + void gtk_menu_popup(Pointer menu, Pointer widget, Pointer bla, Function func, Pointer data, int button, int time); + + /** + * Sets text on the menu_item label + */ + void gtk_menu_item_set_label(Pointer menu_item, String label); + + /** + * Adds a new GtkMenuItem to the end of the menu shell's item list. + */ + void gtk_menu_shell_append(Pointer menu_shell, Pointer child); + + /** + * Sets the sensitivity of a widget. A widget is sensitive if the user can interact with it. Insensitive widgets are “grayed out” + * and the user can’t interact with them. Insensitive widgets are known as “inactive”, “disabled”, or “ghosted” in some other toolkits. + */ + void gtk_widget_set_sensitive(Pointer widget, boolean sensitive); + + /** + * Recursively shows a widget, and any child widgets (if the widget is a container) + */ + void gtk_widget_show_all(Pointer widget); + + /** + * Removes widget from container . widget must be inside container . Note that container will own a reference to widget , and that + * this may be the last reference held; so removing a widget from its container can destroy that widget. + *
+ * If you want to use widget again, you need to add a reference to it before removing it from a container, using g_object_ref(). + * If you don’t want to use widget again it’s usually more efficient to simply destroy it directly using gtk_widget_destroy() + * since this will remove it from the container and help break any circular reference count cycles. + */ + void gtk_container_remove(Pointer parentWidget, Pointer widget); + + /** + * Destroys a widget. + * When a widget is destroyed all references it holds on other objects will be released: + * - if the widget is inside a container, it will be removed from its parent + * - if the widget is a container, all its children will be destroyed, recursively + * - if the widget is a top level, it will be removed from the list of top level widgets that GTK+ maintains internally + *
+ * It's expected that all references held on the widget will also be released; you should connect to the “destroy” signal if you + * hold a reference to widget and you wish to remove it when this function is called. It is not necessary to do so if you are + * implementing a GtkContainer, as you'll be able to use the GtkContainerClass.remove() virtual function for that. + *
+ * It's important to notice that gtk_widget_destroy() will only cause the widget to be finalized if no additional references, + * acquired using g_object_ref(), are held on it. In case additional references are in place, the widget will be in an "inert" state + * after calling this function; widget will still point to valid memory, allowing you to release the references you hold, but you + * may not query the widget's own state. + *
+ * NOTE You should typically call this function on top level widgets, and rarely on child widgets. + */ + void gtk_widget_destroy(Pointer widget); + + /** + * Gets the GtkSettings object for screen , creating it if necessary. + * + * @since 2.2 + */ + Pointer gtk_settings_get_for_screen(Pointer screen); + + /** + * Finds all matching RC styles for a given widget, composites them together, and then creates a GtkStyle representing the composite + * appearance. (GTK+ actually keeps a cache of previously created styles, so a new style may not be created.) + */ + GtkStyle gtk_rc_get_style(Pointer widget); + + /** + * Adds widget to container . Typically used for simple containers such as GtkWindow, GtkFrame, or GtkButton; for more complicated + * layout containers such as GtkBox or GtkTable, this function will pick default packing parameters that may not be correct. So + * consider functions such as gtk_box_pack_start() and gtk_table_attach() as an alternative to gtk_container_add() in those cases. + * A widget may be added to only one container at a time; you can't place the same widget inside two different containers. + */ + void gtk_container_add(Pointer offscreen, Pointer widget); + + /** + * Get's the child from a GTK Bin object + */ + Pointer gtk_bin_get_child(Pointer bin); + + /** + * Gets the PangoLayout used to display the label. The layout is useful to e.g. convert text positions to pixel positions, in + * combination with gtk_label_get_layout_offsets(). The returned layout is owned by the label so need not be freed by the caller. + * + * The label is free to recreate its layout at any time, so it should be considered read-only. + */ + Pointer gtk_label_get_layout(Pointer label); + + /** + * Computes the logical and ink extents of layout in device units. This function just calls pango_layout_get_extents() followed + * by two pango_extents_to_pixels() calls, rounding ink_rect and logical_rect such that the rounded rectangles fully contain the + * unrounded one (that is, passes them as first argument to pango_extents_to_pixels()). + * + * @param layout a PangoLayout + * @param ink_rect rectangle used to store the extents of the layout as drawn or NULL to indicate that the result is not needed. + * @param logical_rect rectangle used to store the logical extents of the layout or NULL to indicate that the result is not needed. + */ + void pango_layout_get_pixel_extents(Pointer layout, Pointer ink_rect, Pointer logical_rect); + + /** + * Creates the GDK (windowing system) resources associated with a widget. For example, widget->window will be created when a widget + * is realized. Normally realization happens implicitly; if you show a widget and all its parent containers, then the widget will + * be realized and mapped automatically. + * + * Realizing a widget requires all the widget’s parent widgets to be realized; calling gtk_widget_realize() realizes the widget’s + * parents in addition to widget itself. If a widget is not yet inside a toplevel window when you realize it, bad things will happen. + * + * This function is primarily used in widget implementations, and isn’t very useful otherwise. Many times when you think you might + * need it, a better approach is to connect to a signal that will be called after the widget is realized automatically, such as + * “draw”. Or simply g_signal_connect() to the “realize” signal. + */ + void gtk_widget_realize(Pointer widget); + + /** + * Creates a toplevel container widget that is used to retrieve snapshots of widgets without showing them on the screen. + * + * @since 2.20 + */ + Pointer gtk_offscreen_window_new(); + + /** + * This function is typically used when implementing a GtkContainer subclass. Obtains the preferred size of a widget. The + * container uses this information to arrange its child widgets and decide what size allocations to give them with + * gtk_widget_size_allocate(). + * + * You can also call this function from an application, with some caveats. Most notably, getting a size request requires the + * widget to be associated with a screen, because font information may be needed. Multihead-aware applications should keep this in mind. + * + * Also remember that the size request is not necessarily the size a widget will actually be allocated. + */ + void gtk_widget_size_request(final Pointer widget, final Pointer requisition); + + /** + * Creates a new GtkImageMenuItem containing the image and text from a stock item. Some stock ids have preprocessor macros + * like GTK_STOCK_OK and GTK_STOCK_APPLY. + * + * @param stock_id the name of the stock item. + * @param accel_group the GtkAccelGroup to add the menu items accelerator to, or NULL. + * + * @return a new GtkImageMenuItem. + */ + Pointer gtk_image_menu_item_new_from_stock(String stock_id, Pointer accel_group); +} + diff --git a/src/dorkbox/util/jna/linux/Gtk2.java b/src/dorkbox/util/jna/linux/Gtk2.java new file mode 100644 index 0000000..685ee0d --- /dev/null +++ b/src/dorkbox/util/jna/linux/Gtk2.java @@ -0,0 +1,197 @@ +/* + * Copyright 2017 dorkbox, llc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package dorkbox.util.jna.linux; + +import com.sun.jna.Function; +import com.sun.jna.Pointer; + +import dorkbox.util.jna.linux.structs.GtkStyle; + +/** + * Bindings for GTK+ 2. Bindings that are exclusively for GTK+ 3 are in that respective class + *
+ * Direct-mapping, See: https://github.com/java-native-access/jna/blob/master/www/DirectMapping.md + */ +public +class Gtk2 implements Gtk { + // objdump -T /usr/lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0 | grep gtk + + @Override + public native + int gdk_threads_add_idle_full(final int priority, final FuncCallback function, final Pointer data, final Pointer notify); + + @Override + public native + boolean gtk_init_check(final int argc); + + @Override + public native + void gtk_main(); + + @Override + public native + int gtk_main_level(); + + @Override + public native + void gtk_main_quit(); + + @Override + public native + Pointer gtk_menu_new(); + + @Override + public native + void gtk_menu_item_set_submenu(final Pointer menuEntry, final Pointer menu); + + @Override + public native + Pointer gtk_separator_menu_item_new(); + + @Override + public native + Pointer gtk_image_new_from_file(final String iconPath); + + @Override + public native + void gtk_check_menu_item_set_active(final Pointer check_menu_item, final boolean isChecked); + + @Override + public native + Pointer gtk_image_menu_item_new_with_mnemonic(final String label); + + @Override + public native + Pointer gtk_check_menu_item_new_with_mnemonic(final String label); + + @Override + public native + void gtk_image_menu_item_set_image(final Pointer image_menu_item, final Pointer image); + + @Override + public native + void gtk_image_menu_item_set_always_show_image(final Pointer menu_item, final boolean forceShow); + + @Override + public native + Pointer gtk_status_icon_new(); + + @Override + public native + Pointer gdk_get_default_root_window(); + + @Override + public native + Pointer gdk_screen_get_default(); + + @Override + public native + double gdk_screen_get_resolution(final Pointer screen); + + @Override + public native + void gtk_status_icon_set_from_file(final Pointer widget, final String label); + + @Override + public native + void gtk_status_icon_set_visible(final Pointer widget, final boolean visible); + + @Override + public native + void gtk_status_icon_set_tooltip_text(final Pointer widget, final String tooltipText); + + @Override + public native + void gtk_status_icon_set_title(final Pointer widget, final String titleText); + + @Override + public native + void gtk_status_icon_set_name(final Pointer widget, final String name); + + @Override + public native + void gtk_menu_popup(final Pointer menu, + final Pointer widget, + final Pointer bla, + final Function func, + final Pointer data, + final int button, + final int time); + + @Override + public native + void gtk_menu_item_set_label(final Pointer menu_item, final String label); + + @Override + public native + void gtk_menu_shell_append(final Pointer menu_shell, final Pointer child); + + @Override + public native + void gtk_widget_set_sensitive(final Pointer widget, final boolean sensitive); + + @Override + public native + void gtk_widget_show_all(final Pointer widget); + + @Override + public native + void gtk_container_remove(final Pointer parentWidget, final Pointer widget); + + @Override + public native + void gtk_widget_destroy(final Pointer widget); + + @Override + public native + Pointer gtk_settings_get_for_screen(final Pointer screen); + + @Override + public native + GtkStyle gtk_rc_get_style(final Pointer widget); + + @Override + public native + void gtk_container_add(final Pointer offscreen, final Pointer widget); + + @Override + public native + Pointer gtk_bin_get_child(final Pointer bin); + + @Override + public native + Pointer gtk_label_get_layout(final Pointer label); + + @Override + public native + void pango_layout_get_pixel_extents(final Pointer layout, final Pointer ink_rect, final Pointer logical_rect); + + @Override + public native + void gtk_widget_realize(final Pointer widget); + + @Override + public native + Pointer gtk_offscreen_window_new(); + + @Override + public native + void gtk_widget_size_request(final Pointer widget, final Pointer requisition); + + @Override + public native + Pointer gtk_image_menu_item_new_from_stock(final String stock_id, final Pointer accel_group); +} diff --git a/src/dorkbox/util/jna/linux/Gtk3.java b/src/dorkbox/util/jna/linux/Gtk3.java new file mode 100644 index 0000000..af9fac3 --- /dev/null +++ b/src/dorkbox/util/jna/linux/Gtk3.java @@ -0,0 +1,257 @@ +/* + * Copyright 2017 dorkbox, llc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package dorkbox.util.jna.linux; + +import com.sun.jna.Function; +import com.sun.jna.Pointer; + +import dorkbox.util.jna.linux.structs.GtkStyle; + +/** + * bindings for GTK+ 3. + *
+ * Direct-mapping, See: https://github.com/java-native-access/jna/blob/master/www/DirectMapping.md + */ +public +class Gtk3 implements Gtk { + // objdump -T /usr/lib/x86_64-linux-gnu/libgtk-3.so.0 | grep gtk + // objdump -T /usr/local/lib/libgtk-3.so.0 | grep gtk + + /** + * This function is typically used when implementing a GtkContainer subclass. Obtains the preferred size of a widget. The + * container uses this information to arrange its child widgets and decide what size allocations to give them with + * gtk_widget_size_allocate(). + * + * You can also call this function from an application, with some caveats. Most notably, getting a size request requires the + * widget to be associated with a screen, because font information may be needed. Multihead-aware applications should keep this in mind. + * + * Also remember that the size request is not necessarily the size a widget will actually be allocated. + */ + @Override + public + void gtk_widget_size_request(final Pointer widget, final Pointer requisition) { + this.gtk_widget_get_preferred_size(widget, requisition, null); + } + + /** + * Retrieves the minimum and natural size of a widget, taking into account the widget’s preference for height-for-width management. + *
+ * This is used to retrieve a suitable size by container widgets which do not impose any restrictions on the child placement. + * It can be used to deduce toplevel window and menu sizes as well as child widgets in free-form containers such as GtkLayout. + *
+ * Handle with care. Note that the natural height of a height-for-width widget will generally be a smaller size than the minimum + * height, since the required height for the natural width is generally smaller than the required height for the minimum width. + *
+ * Use gtk_widget_get_preferred_height_and_baseline_for_width() if you want to support baseline alignment. + * + * @param widget a GtkWidget instance + * @param minimum_size location for storing the minimum size, or NULL. + * @param natural_size location for storing the natural size, or NULL. + */ + public native + void gtk_widget_get_preferred_size(final Pointer widget, final Pointer minimum_size, final Pointer natural_size); + + public native + int gtk_get_major_version(); + + public native + int gtk_get_minor_version(); + + public native + int gtk_get_micro_version(); + + /** + * Returns the internal scale factor that maps from window coordinates to the actual device pixels. On traditional systems this is 1, + * but on very high density outputs this can be a higher value (often 2). + *
+ * A higher value means that drawing is automatically scaled up to a higher resolution, so any code doing drawing will automatically + * look nicer. However, if you are supplying pixel-based data the scale value can be used to determine whether to use a pixel + * resource with higher resolution data. + *
+ * The scale of a window may change during runtime, if this happens a configure event will be sent to the toplevel window. + * + * @return the scale factor + * + * @since 3.10 + */ + public native + int gdk_window_get_scale_factor(Pointer window); + + + + + @Override + public native + int gdk_threads_add_idle_full(final int priority, final FuncCallback function, final Pointer data, final Pointer notify); + + @Override + public native + boolean gtk_init_check(final int argc); + + @Override + public native + void gtk_main(); + + @Override + public native + int gtk_main_level(); + + @Override + public native + void gtk_main_quit(); + + @Override + public native + Pointer gtk_menu_new(); + + @Override + public native + void gtk_menu_item_set_submenu(final Pointer menuEntry, final Pointer menu); + + @Override + public native + Pointer gtk_separator_menu_item_new(); + + @Override + public native + Pointer gtk_image_new_from_file(final String iconPath); + + @Override + public native + void gtk_check_menu_item_set_active(final Pointer check_menu_item, final boolean isChecked); + + @Override + public native + Pointer gtk_image_menu_item_new_with_mnemonic(final String label); + + @Override + public native + Pointer gtk_check_menu_item_new_with_mnemonic(final String label); + + @Override + public native + void gtk_image_menu_item_set_image(final Pointer image_menu_item, final Pointer image); + + @Override + public native + void gtk_image_menu_item_set_always_show_image(final Pointer menu_item, final boolean forceShow); + + @Override + public native + Pointer gtk_status_icon_new(); + + @Override + public native + Pointer gdk_get_default_root_window(); + + @Override + public native + Pointer gdk_screen_get_default(); + + @Override + public native + double gdk_screen_get_resolution(final Pointer screen); + + @Override + public native + void gtk_status_icon_set_from_file(final Pointer widget, final String label); + + @Override + public native + void gtk_status_icon_set_visible(final Pointer widget, final boolean visible); + + @Override + public native + void gtk_status_icon_set_tooltip_text(final Pointer widget, final String tooltipText); + + @Override + public native + void gtk_status_icon_set_title(final Pointer widget, final String titleText); + + @Override + public native + void gtk_status_icon_set_name(final Pointer widget, final String name); + + @Override + public native + void gtk_menu_popup(final Pointer menu, + final Pointer widget, + final Pointer bla, + final Function func, + final Pointer data, + final int button, + final int time); + + @Override + public native + void gtk_menu_item_set_label(final Pointer menu_item, final String label); + + @Override + public native + void gtk_menu_shell_append(final Pointer menu_shell, final Pointer child); + + @Override + public native + void gtk_widget_set_sensitive(final Pointer widget, final boolean sensitive); + + @Override + public native + void gtk_widget_show_all(final Pointer widget); + + @Override + public native + void gtk_container_remove(final Pointer parentWidget, final Pointer widget); + + @Override + public native + void gtk_widget_destroy(final Pointer widget); + + @Override + public native + Pointer gtk_settings_get_for_screen(final Pointer screen); + + @Override + public native + GtkStyle gtk_rc_get_style(final Pointer widget); + + @Override + public native + void gtk_container_add(final Pointer offscreen, final Pointer widget); + + @Override + public native + Pointer gtk_bin_get_child(final Pointer bin); + + @Override + public native + Pointer gtk_label_get_layout(final Pointer label); + + @Override + public native + void pango_layout_get_pixel_extents(final Pointer layout, final Pointer ink_rect, final Pointer logical_rect); + + @Override + public native + void gtk_widget_realize(final Pointer widget); + + @Override + public native + Pointer gtk_offscreen_window_new(); + + @Override + public native + Pointer gtk_image_menu_item_new_from_stock(final String stock_id, final Pointer accel_group); +} diff --git a/src/dorkbox/util/jna/linux/GtkEventDispatch.java b/src/dorkbox/util/jna/linux/GtkEventDispatch.java new file mode 100644 index 0000000..ae318ff --- /dev/null +++ b/src/dorkbox/util/jna/linux/GtkEventDispatch.java @@ -0,0 +1,362 @@ +/* + * Copyright 2015 dorkbox, llc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package dorkbox.util.jna.linux; + +import static dorkbox.util.jna.linux.Gtk.Gtk2; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.LinkedList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.slf4j.LoggerFactory; + +import com.sun.jna.Pointer; + +import dorkbox.util.Framework; +import dorkbox.util.JavaFX; +import dorkbox.util.Swt; + +public +class GtkEventDispatch { + static boolean FORCE_GTK2 = false; + static boolean DEBUG = false; + + private static final boolean isSwtLoaded = Framework.isSwtLoaded; + private static final boolean isJavaFxLoaded = Framework.isJavaFxLoaded; + + // have to save these in a field to prevent GC on the objects (since they go out-of-scope from java) + private static final LinkedList