diff --git a/src/dorkbox/systemTray/jna/linux/Gtk.java b/src/dorkbox/systemTray/jna/linux/Gtk.java index f4257ea..05faefc 100644 --- a/src/dorkbox/systemTray/jna/linux/Gtk.java +++ b/src/dorkbox/systemTray/jna/linux/Gtk.java @@ -541,7 +541,7 @@ class Gtk { * appearance. (GTK+ actually keeps a cache of previously created styles, so a new style may not be created.) */ public static - Pointer gtk_rc_get_style(Pointer widget) { + GtkStyle gtk_rc_get_style(Pointer widget) { return Gtk2.gtk_rc_get_style(widget); } diff --git a/src/dorkbox/systemTray/jna/linux/Gtk2.java b/src/dorkbox/systemTray/jna/linux/Gtk2.java index e6e7db6..3d6005e 100644 --- a/src/dorkbox/systemTray/jna/linux/Gtk2.java +++ b/src/dorkbox/systemTray/jna/linux/Gtk2.java @@ -325,7 +325,7 @@ class Gtk2 { * appearance. (GTK+ actually keeps a cache of previously created styles, so a new style may not be created.) */ public static native - Pointer gtk_rc_get_style(Pointer widget); + GtkStyle gtk_rc_get_style(Pointer widget); /** * Looks up color_name in the style’s logical color mappings, filling in color and returning TRUE if found, otherwise returning @@ -365,14 +365,28 @@ class Gtk2 { * 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. * */ public static native - void pango_layout_get_pixel_extents (Pointer layout, Pointer ink_rect, Pointer logical_rect); + 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. + */ + public static native + 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. diff --git a/src/dorkbox/systemTray/jna/linux/Gtk3.java b/src/dorkbox/systemTray/jna/linux/Gtk3.java index 66e544b..404c5e8 100644 --- a/src/dorkbox/systemTray/jna/linux/Gtk3.java +++ b/src/dorkbox/systemTray/jna/linux/Gtk3.java @@ -36,120 +36,6 @@ class Gtk3 { public static native int gtk_get_micro_version(); - - /** - * Loads a theme from the usual theme paths - * - * @param name A theme name - * @param variant variant to load, for example, "dark", or NULL for the default. - * - * @return a GtkCssProvider with the theme loaded. This memory is owned by GTK+, and you must not free it. - * - * @since 3.0 - */ - public static native - Pointer gtk_css_provider_get_named(String name, String variant); - - /** - * Returns the provider containing the style settings used as a fallback for all widgets. - * - * @return a GtkCssProvider with the theme loaded. This memory is owned by GTK+, and you must not free it. - * - * @since 3.0 - */ - public static native - Pointer gtk_css_provider_get_default(); - - /** - * Converts the provider into a string representation in CSS format. - *
- * Using gtk_css_provider_load_from_data() with the return value from this function on a new provider created with - * gtk_css_provider_new() will basically create a duplicate of this provider . - * - * @since 3.2 (released in 2011) - */ - public static native - String gtk_css_provider_to_string(Pointer provider); - - /** - * Gets the foreground color for a given state. - * - * @since 3.0 - */ - public static native - void gtk_style_context_get_color(Pointer context, int stateFlags, Pointer color); - - /** - * Returns the state used for style matching. - * - * @since 3.0 - */ - public static native - int gtk_style_context_get_state(Pointer context); - - /** - * Looks up and resolves a color name in the context color map. - * - * @since 3.0 (but not in the documentation...) - */ - public static native - boolean gtk_style_context_lookup_color(Pointer widget, String name, Pointer color); - - /** - * Returns the style context associated to widget . The returned object is guaranteed to be the same for the lifetime of widget . - * - * @since 3.0 (but not in the documentation...) - */ - public static native - Pointer gtk_widget_get_style_context(Pointer widget); - - /** - * Saves the context state, so temporary modifications done through gtk_style_context_add_class(), gtk_style_context_remove_class(), - * gtk_style_context_set_state(), etc. can quickly be reverted in one go through gtk_style_context_restore(). - *
- * The matching call to gtk_style_context_restore() must be done before GTK returns to the main loop. - * - * @since 3.0 - */ - public static native - void gtk_style_context_save(Pointer context); - - - /** - * Restores context state to a previous stage. See gtk_style_context_save(). - * - * @since 3.0 - */ - public static native - void gtk_style_context_restore(Pointer context); - - /** - * Adds a style class to context , so posterior calls to gtk_style_context_get() or any of the gtk_render_*() functions will make - * use of this new class for styling. - * - * @since 3.0 - */ - public static native - void gtk_style_context_add_class(Pointer context, String className); - - /** - * Gets the padding for a given state as a GtkBorder. See gtk_style_context_get() and GTK_STYLE_PROPERTY_PADDING for details. - * - * @since 3.0 - */ - public static native - void gtk_style_context_get_padding(Pointer context, int state, Pointer border); - - /** - * Gets the border for a given state as a GtkBorder. - *
- * See gtk_style_context_get_property() and GTK_STYLE_PROPERTY_BORDER_WIDTH for details.
- *
- * @since 3.0
- */
- public static native
- void gtk_style_context_get_border(Pointer context, int state, Pointer border);
-
/**
* 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).
diff --git a/src/dorkbox/systemTray/jna/linux/GtkTheme.java b/src/dorkbox/systemTray/jna/linux/GtkTheme.java
index afdd638..daf40ab 100644
--- a/src/dorkbox/systemTray/jna/linux/GtkTheme.java
+++ b/src/dorkbox/systemTray/jna/linux/GtkTheme.java
@@ -15,15 +15,11 @@
*/
package dorkbox.systemTray.jna.linux;
-import static dorkbox.systemTray.util.CssParser.injectAdditionalCss;
-import static dorkbox.systemTray.util.CssParser.removeComments;
-
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.io.ByteArrayOutputStream;
import java.io.File;
-import java.io.IOException;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.List;
@@ -34,16 +30,9 @@ import com.sun.jna.Pointer;
import com.sun.jna.ptr.PointerByReference;
import dorkbox.systemTray.SystemTray;
-import dorkbox.systemTray.Tray;
-import dorkbox.systemTray.jna.linux.structs.GdkColor;
-import dorkbox.systemTray.jna.linux.structs.GdkRGBAColor;
import dorkbox.systemTray.jna.linux.structs.GtkRequisition;
import dorkbox.systemTray.jna.linux.structs.GtkStyle;
import dorkbox.systemTray.jna.linux.structs.PangoRectangle;
-import dorkbox.systemTray.util.CssParser;
-import dorkbox.systemTray.util.CssParser.Css;
-import dorkbox.systemTray.util.CssParser.CssNode;
-import dorkbox.systemTray.util.CssParser.Entry;
import dorkbox.util.FileUtil;
import dorkbox.util.MathUtil;
import dorkbox.util.OS;
@@ -63,68 +52,40 @@ import dorkbox.util.process.ShellProcessBuilder;
@SuppressWarnings({"deprecation", "WeakerAccess"})
public
class GtkTheme {
- private static final boolean DEBUG = false;
- private static final boolean DEBUG_SHOW_CSS = false;
- private static final boolean DEBUG_VERBOSE = false;
-
- // CSS nodes that we care about, in oder of preference from left to right.
- private static final
- String[] cssNodes = new String[] {".menuitem", ".entry", "*"};
+ private static final boolean DEBUG = true;
public static
Rectangle getPixelTextHeight(String text) {
- // have to use pango to get the size of text (for the checkmark size)
- Pointer offscreen = Gtk.gtk_offscreen_window_new();
+ // the following method requires an offscreen widget to get the size of text (for the checkmark size) via pango
+ // don't forget to destroy everything!
+ Pointer menu = null;
+ Pointer item = null;
- // we use the size of "X" as the checkmark
- Pointer item = Gtk.gtk_image_menu_item_new_with_mnemonic(text);
+ try {
+ menu = Gtk.gtk_menu_new();
+ item = Gtk.gtk_image_menu_item_new_with_mnemonic(text);
- Gtk.gtk_container_add(offscreen, item);
+ Gtk.gtk_container_add(menu, item);
- // get the text widget (GtkAccelLabel) from inside the GtkMenuItem
- Pointer textLabel = Gtk.gtk_bin_get_child(item);
- Pointer pangoLayout = Gtk.gtk_label_get_layout(textLabel);
+ Gtk2.gtk_widget_realize(menu);
+ Gtk2.gtk_widget_realize(item);
+ Gtk2.gtk_widget_show_all(menu);
- // ink pixel size is how much exact space it takes on the screen
- PangoRectangle ink = new PangoRectangle();
+ // get the text widget (GtkAccelLabel/GtkLabel) from inside the GtkMenuItem
+ Pointer textLabel = Gtk.gtk_bin_get_child(item);
+ Pointer pangoLayout = Gtk.gtk_label_get_layout(textLabel);
- Gtk.pango_layout_get_pixel_extents(pangoLayout, ink.getPointer(), null);
- ink.read();
+ // ink pixel size is how much exact space it takes on the screen
+ PangoRectangle ink = new PangoRectangle();
- Rectangle size = new Rectangle(ink.width, ink.height);
+ Gtk.pango_layout_get_pixel_extents(pangoLayout, ink.getPointer(), null);
+ ink.read();
- Gtk.gtk_widget_destroy(item);
- Gtk.gtk_widget_destroy(offscreen);
-
- return size;
- }
-
- public static
- Rectangle getLogicalTextHeight(String text) {
- // have to use pango to get the size of text (for the checkmark size)
- Pointer offscreen = Gtk.gtk_offscreen_window_new();
-
- // we use the size of "X" as the checkmark
- Pointer item = Gtk.gtk_image_menu_item_new_with_mnemonic(text);
-
- Gtk.gtk_container_add(offscreen, item);
-
- // get the text widget (GtkAccelLabel) from inside the GtkMenuItem
- Pointer textLabel = Gtk.gtk_bin_get_child(item);
- Pointer pangoLayout = Gtk.gtk_label_get_layout(textLabel);
-
- // logical pixel size (ascent + descent)
- PangoRectangle logical = new PangoRectangle();
-
- Gtk.pango_layout_get_pixel_extents(pangoLayout, null, logical.getPointer());
- logical.read();
-
- Rectangle size = new Rectangle(logical.width, logical.height);
-
- Gtk.gtk_widget_destroy(item);
- Gtk.gtk_widget_destroy(offscreen);
-
- return size;
+ return new Rectangle(ink.width, ink.height);
+ } finally {
+ Gtk.gtk_widget_destroy(item);
+ Gtk.gtk_widget_destroy(menu);
+ }
}
/**
@@ -172,7 +133,7 @@ class GtkTheme {
* - GtkStatusIndicator: ??
*/
public static
- int getIndicatorSize(final Class extends Tray> trayType) {
+ int getIndicatorSize() {
// Linux is similar enough, that it just uses this method
// https://wiki.archlinux.org/index.php/HiDPI
@@ -181,6 +142,8 @@ class GtkTheme {
final AtomicReference
- * > GTK+ 3.2 uses an API, GTK2 gets it from disk
- *
- * @return the color string, parsed from CSS,
- */
- private static
- Color getColorFromCss() {
- Css css = getCss();
- if (css != null) {
- if (DEBUG_SHOW_CSS) {
- System.err.println(css);
- }
-
- try {
- // collect a list of all of the sections that have what we are interested in.
- List
- * /usr/share/themes
- * /opt/gnome/share/themes
- */
- private static
- String getGtk3ThemeCssViaFile() {
- File themeDirectory = getThemeDirectory(true);
-
- if (themeDirectory == null) {
- return null;
- }
-
- File gtkFile = new File(themeDirectory, "gtk.css");
- try {
- StringBuilder stringBuilder = new StringBuilder((int) (gtkFile.length()));
- FileUtil.read(gtkFile, stringBuilder);
-
- removeComments(stringBuilder);
-
- // only comments in the file
- if (stringBuilder.length() < 2) {
- return null;
- }
-
- injectAdditionalCss(themeDirectory, stringBuilder);
-
- return stringBuilder.toString();
- } catch (IOException e) {
- // cant read the file or something else.
- if (SystemTray.DEBUG) {
- SystemTray.logger.error("Error getting RAW GTK3 theme file.", e);
- }
- }
-
- return null;
- }
-
- /**
- * @return the discovered fg[NORMAL] or text[NORMAL] color for this theme or null
- */
- public static
- Color getFromGtk2ThemeText() {
- String gtk2ThemeText = getGtk2ThemeText();
-
- if (gtk2ThemeText != null) {
- String[] colorText = new String[] {"fg[NORMAL]", "text[NORMAL]"};
- for (String text : colorText) {
- int i = 0;
- while (i != -1) {
- i = gtk2ThemeText.indexOf(text, i);
- if (i != -1) {
- if (i > 0 && gtk2ThemeText.charAt(i - 1) != '_') {
- i += text.length();
- continue;
- }
-
-
- int j = gtk2ThemeText.indexOf("=", i);
- if (j != -1) {
- int lineEnd = gtk2ThemeText.indexOf('\n', j);
-
- if (lineEnd != -1) {
- String colorName = gtk2ThemeText.substring(j + 1, lineEnd)
- .trim();
-
- colorName = colorName.replaceAll("\"", "");
- return parseColor(colorName);
- }
- }
- }
- }
- }
- }
-
- return null;
- }
-
-
- /**
- * Checks in the following locations for the current GTK2 theme.
- *
- * /usr/share/themes
- * /opt/gnome/share/themes
- */
- private static
- String getGtk2ThemeText() {
- File themeDirectory = getThemeDirectory(false);
-
- if (themeDirectory == null) {
- return null;
- }
-
-
- // ie: /usr/share/themes/Numix/gtk-2.0/gtkrc
- File gtkFile = new File(themeDirectory, "gtkrc");
-
- try {
- StringBuilder stringBuilder = new StringBuilder((int) (gtkFile.length()));
- FileUtil.read(gtkFile, stringBuilder);
-
- removeComments(stringBuilder);
-
- // only comments in the file
- if (stringBuilder.length() < 2) {
- return null;
- }
-
- return stringBuilder.toString();
- } catch (IOException ignored) {
- // cant read the file or something else.
- }
-
- return null;
- }
-
-
- /**
- * Figures out what the directory is for the specified type of GTK theme files (css/gtkrc/etc)
- *
- * @param gtk3 true if you want to look for the GTK3 theme dir, false if you want the GTK2 theme dir
- *
- * @return the directory or null if it cannot be found
- */
- public static
- File getThemeDirectory(boolean gtk3) {
- String themeName = getThemeName();
-
- if (themeName == null) {
- return null;
- }
-
- String gtkType;
- if (gtk3) {
- gtkType = "gtk-3.0";
- }
- else {
- gtkType = "gtk-2.0";
- }
-
-
- String[] dirs = new String[] {"/usr/share/themes", "/opt/gnome/share/themes"};
-
- // ie: /usr/share/themes
- for (String dirName : dirs) {
- File themesDir = new File(dirName);
-
- File[] themeDirs = themesDir.listFiles();
- if (themeDirs != null) {
- // ie: /usr/share/themes/Numix
- for (File themeDir : themeDirs) {
- File[] files1 = themeDir.listFiles();
- if (files1 != null) {
- boolean isCorrectTheme;
-
- File themeIndexFile = new File(themeDir, "index.theme");
- try {
- List
- * - the word "transparent"
- * - hex 12 digit #ffffaaaaffff
- * - hex 6 digit #ffaaff
- * - hex 3 digit #faf
- * - rgb(r, g, b) rgb(33, 33, 33)
- * - rgb(r, g, b) rgb(.6, .3, .3)
- * - rgb(r%, g%, b%) rgb(10%, 20%, 30%)
- * - rgba(r, g, b, a) rgb(33, 33, 33, 0.53)
- * - rgba(r, g, b, a) rgb(.33, .33, .33, 0.53)
- * - rgba(r, g, b, a) rgb(10%, 20%, 30%, 0.53)
- *
- * Notes:
- * - rgb(), when an int, is between 0-255
- * - rgb(), when a float, is between 0.0-1.0
- * - rgb(), when a percent, is between 0-100
- * - alpha is always a float
- *
- * @return the parsed color
- */
- @SuppressWarnings("Duplicates")
- private static
- Color parseColor(String colorString) {
- if (colorString == null) {
- return null;
- }
-
- int red = 0;
- int green = 0;
- int blue = 0;
- int alpha = 255;
-
- if (colorString.startsWith("#")) {
- colorString = colorString.substring(1);
-
- if (colorString.length() > 11) {
- red = Integer.parseInt(colorString.substring(0, 4), 16);
- green = Integer.parseInt(colorString.substring(4, 8), 16);
- blue = Integer.parseInt(colorString.substring(8), 16);
-
- // Have to convert to positive int (value between 0 and 65535, these are 16 bits per pixel) that is from 0-255
- red = red & 0x0000FFFF;
- green = green & 0x0000FFFF;
- blue = blue & 0x0000FFFF;
-
- red = (red >> 8) & 0xFF;
- green = (green >> 8) & 0xFF;
- blue = (blue >> 8) & 0xFF;
- }
- else if (colorString.length() > 5) {
- red = Integer.parseInt(colorString.substring(0, 2), 16);
- green = Integer.parseInt(colorString.substring(2, 4), 16);
- blue = Integer.parseInt(colorString.substring(4), 16);
- }
- else {
- red = Integer.parseInt(colorString.substring(0, 1), 16);
- green = Integer.parseInt(colorString.substring(1, 2), 16);
- blue = Integer.parseInt(colorString.substring(2), 16);
- }
- }
- else if (colorString.startsWith("rgba")) {
- colorString = colorString.substring(colorString.indexOf('(') + 1, colorString.indexOf(')'));
- String[] split = colorString.split(",");
-
- String trim1 = split[0].trim();
- String trim2 = split[1].trim();
- String trim3 = split[2].trim();
- String trim4 = split[3].trim();
-
- if (colorString.contains("%")) {
- trim1 = trim1.replace("%", "");
- trim2 = trim2.replace("%", "");
- trim3 = trim3.replace("%", "");
-
- red = Integer.parseInt(trim1) * 255;
- green = Integer.parseInt(trim2) * 255;
- blue = Integer.parseInt(trim3) * 255;
- }
- else if (colorString.contains(".")) {
- red = (int) (Float.parseFloat(trim1) * 255);
- green = (int) (Float.parseFloat(trim2) * 255);
- blue = (int) (Float.parseFloat(trim3) * 255);
- }
- else {
- red = Integer.parseInt(trim1);
- green = Integer.parseInt(trim2);
- blue = Integer.parseInt(trim3);
- }
-
- float alphaF = Float.parseFloat(trim4);
- alpha = (int) (alphaF * 255);
- }
- else if (colorString.startsWith("rgb")) {
- colorString = colorString.substring(colorString.indexOf('(') + 1, colorString.indexOf(')'));
- String[] split = colorString.split(",");
-
- String trim1 = split[0].trim();
- String trim2 = split[1].trim();
- String trim3 = split[2].trim();
-
- if (colorString.contains("%")) {
- trim1 = trim1.replace("%", "");
- trim2 = trim2.replace("%", "");
- trim3 = trim3.replace("%", "");
-
- red = Integer.parseInt(trim1) * 255;
- green = Integer.parseInt(trim2) * 255;
- blue = Integer.parseInt(trim3) * 255;
- }
- else if (colorString.contains(".")) {
- red = (int) (Float.parseFloat(trim1) * 255);
- green = (int) (Float.parseFloat(trim2) * 255);
- blue = (int) (Float.parseFloat(trim3) * 255);
- }
- else {
- red = Integer.parseInt(trim1);
- green = Integer.parseInt(trim2);
- blue = Integer.parseInt(trim3);
- }
- }
- else if (colorString.contains("transparent")) {
- alpha = 0;
- }
- else {
- int index = colorString.indexOf(";");
- if (index > 0) {
- colorString = colorString.substring(0, index);
- }
- colorString = colorString.replaceAll("\"", "");
- colorString = colorString.replaceAll("'", "");
-
- // maybe it's just a "color" description, such as "red"?
- try {
- return Color.decode(colorString);
- } catch (Exception e) {
- return null;
- }
- }
-
- return new Color(red, green, blue, alpha);
- }
-
- /**
- * https://wiki.archlinux.org/index.php/GTK%2B
- *
- * gets the name of the currently loaded theme
- * GTK+ 2:
- * ~/.gtkrc-2.0
- * gtk-icon-theme-name = "Adwaita"
- * gtk-theme-name = "Adwaita"
- * gtk-font-name = "DejaVu Sans 11"
- *
- *
- * GTK+ 3:
- * $XDG_CONFIG_HOME/gtk-3.0/settings.ini
- * [Settings]
- * gtk-icon-theme-name = Adwaita
- * gtk-theme-name = Adwaita
- * gtk-font-name = DejaVu Sans 11
- *
- *
- * Note: The icon theme name is the name defined in the theme's index file, not the name of its directory.
- *
- * directories:
- * /usr/share/themes
- * /opt/gnome/share/themes
- *
- * GTK+ 2 user specific: ~/.gtkrc-2.0
- * GTK+ 2 system wide: /etc/gtk-2.0/gtkrc
- *
- * GTK+ 3 user specific: $XDG_CONFIG_HOME/gtk-3.0/settings.ini, or $HOME/.config/gtk-3.0/settings.ini if $XDG_CONFIG_HOME is not set
- * GTK+ 3 system wide: /etc/gtk-3.0/settings.ini
- *
- * @return the theme name, or null if it cannot find it.
- */
- public static
- String getThemeName() {
- final AtomicReference