Mercurial > hg > release > thermostat-0.9
changeset 1103:27b8deb8a6b2
Refactor theme management
review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-May/006692.html
reviewed-by: vanaltj, obryan
author | Mario Torre <neugens.limasoftware@gmail.com> |
---|---|
date | Tue, 21 May 2013 20:13:26 +0200 |
parents | 8757e35030f2 |
children | cf2033a6b021 |
files | client/swing/pom.xml client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/Main.java client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/ThermostatActivator.java distribution/assembly/core-assembly.xml distribution/config/commands/gui.properties distribution/pom.xml laf-utils/Makefile laf-utils/pom.xml laf-utils/src/main/java/com/redhat/thermostat/internal/utils/laf/ThemeManager.java laf-utils/src/main/java/com/redhat/thermostat/internal/utils/laf/gtk/GTKThemeUtils.java laf-utils/src/main/native/GTKThemeUtils.c pom.xml vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapSwingViewTest.java |
diffstat | 13 files changed, 622 insertions(+), 60 deletions(-) [+] |
line wrap: on
line diff
--- a/client/swing/pom.xml Tue May 21 12:43:17 2013 -0400 +++ b/client/swing/pom.xml Tue May 21 20:13:26 2013 +0200 @@ -58,6 +58,11 @@ </dependency> <dependency> <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-laf-utils</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> <artifactId>thermostat-swing-components</artifactId> <version>${project.version}</version> </dependency> @@ -126,7 +131,6 @@ <scope>test</scope> </dependency> </dependencies> - <build> <resources>
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/Main.java Tue May 21 12:43:17 2013 -0400 +++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/Main.java Tue May 21 20:13:26 2013 +0200 @@ -44,12 +44,7 @@ import java.util.logging.Logger; import javax.swing.JOptionPane; -import javax.swing.JPopupMenu; -import javax.swing.SwingConstants; import javax.swing.SwingUtilities; -import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; -import javax.swing.plaf.nimbus.NimbusLookAndFeel; import org.osgi.framework.BundleContext; @@ -62,6 +57,7 @@ import com.redhat.thermostat.common.config.ClientPreferences; import com.redhat.thermostat.common.locale.Translate; import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.internal.utils.laf.ThemeManager; import com.redhat.thermostat.storage.core.Connection.ConnectionListener; import com.redhat.thermostat.storage.core.Connection.ConnectionStatus; import com.redhat.thermostat.storage.core.DbService; @@ -111,62 +107,14 @@ this.shutdown = shutdown; this.mainWindowRunnable = mainWindowRunnable; } - - private void setLAF() { - - boolean useDefault = false; - - // check if the user has other preferences... - String laf = System.getProperty("swing.defaultlaf"); - if (laf == null) { - useDefault = true; - - } else if (laf.equalsIgnoreCase("dolphin")) { - try { - UIManager.setLookAndFeel("com.redhat.swing.laf.dolphin.DolphinLookAndFeel"); - } catch (UnsupportedLookAndFeelException | ClassNotFoundException | - InstantiationException | IllegalAccessException e) { - useDefault = true; - logger.log(Level.WARNING, "cannot set DolphinLookAndFeel"); - } - } else if (laf.equalsIgnoreCase("system")) { - try { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } catch (UnsupportedLookAndFeelException | ClassNotFoundException | - InstantiationException | IllegalAccessException e) { - useDefault = true; - logger.log(Level.WARNING, "cannot set System LookAndFeel"); - } - } - - if (useDefault) { - try { - UIManager.setLookAndFeel(new NimbusLookAndFeel()); - } catch (UnsupportedLookAndFeelException e) { - // well, whatever... - logger.log(Level.WARNING, "cannot set NimbusLookAndFeel"); - } - } - } public void run() { EventQueue.invokeLater(new Runnable() { @Override public void run() { - - setLAF(); - - // Thermostat JPopupMenu instances should all be - // ThermostatPopupmenu, so this is redundant, but done in case - // some client code doesn't use the internal popup - JPopupMenu.setDefaultLightWeightPopupEnabled(false); - - // TODO: move them in an appropriate place - UIManager.getDefaults().put("OptionPane.buttonOrientation", SwingConstants.RIGHT); - UIManager.getDefaults().put("OptionPane.isYesLast", true); - UIManager.getDefaults().put("OptionPane.sameSizeButtons", true); - + ThemeManager themeManager = ThemeManager.getInstance(); + themeManager.setLAF(); } });
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/ThermostatActivator.java Tue May 21 12:43:17 2013 -0400 +++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/internal/osgi/ThermostatActivator.java Tue May 21 20:13:26 2013 +0200 @@ -99,7 +99,7 @@ Class<?>[] deps = new Class<?>[] { Keyring.class, - ApplicationService.class + ApplicationService.class, }; dependencyTracker = new MultipleServiceTracker(context, deps, new Action() { @@ -109,7 +109,6 @@ public void dependenciesAvailable(Map<String, Object> services) { Keyring keyring = (Keyring) services.get(Keyring.class.getName()); ApplicationService appSvc = (ApplicationService) services.get(ApplicationService.class.getName()); - cmdReg = new CommandRegistryImpl(context); main = new Main(context, keyring, appSvc, new String[0]);
--- a/distribution/assembly/core-assembly.xml Tue May 21 12:43:17 2013 -0400 +++ b/distribution/assembly/core-assembly.xml Tue May 21 20:13:26 2013 +0200 @@ -69,6 +69,7 @@ <include>com.redhat.thermostat:thermostat-web-cmd</include> <include>com.redhat.thermostat:thermostat-web-server</include> <include>com.redhat.thermostat:thermostat-system-backend</include> + <include>com.redhat.thermostat:thermostat-laf-utils</include> <include>org.eclipse.jetty:jetty-server</include> <include>org.eclipse.jetty:jetty-webapp</include> </includes>
--- a/distribution/config/commands/gui.properties Tue May 21 12:43:17 2013 -0400 +++ b/distribution/config/commands/gui.properties Tue May 21 20:13:26 2013 +0200 @@ -12,6 +12,7 @@ thermostat-client-cli-@project.version@.jar, \ thermostat-client-swing-@project.version@.jar, \ thermostat-swing-components-@project.version@.jar, \ + thermostat-laf-utils-@project.version@.jar, \ thermostat-client-command-@project.version@.jar, \ thermostat-killvm-client-swing-@project.version@.jar, \ thermostat-osgi-living-vm-filter-core-@project.version@.jar, \
--- a/distribution/pom.xml Tue May 21 12:43:17 2013 -0400 +++ b/distribution/pom.xml Tue May 21 20:13:26 2013 +0200 @@ -233,6 +233,8 @@ todir="${project.build.directory}/libs/native" /> <copy file="${main.basedir}/agent/core/target/libUserNameUtilWrapper.so" todir="${project.build.directory}/libs/native" /> + <copy file="${main.basedir}/laf-utils/target/libGTKThemeUtils.so" + todir="${project.build.directory}/libs/native" /> </target> </configuration> <goals> @@ -427,6 +429,11 @@ </dependency> <dependency> <groupId>com.redhat.thermostat</groupId> + <artifactId>thermostat-laf-utils</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>com.redhat.thermostat</groupId> <artifactId>thermostat-web-client</artifactId> <version>${project.version}</version> </dependency>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/laf-utils/Makefile Tue May 21 20:13:26 2013 +0200 @@ -0,0 +1,48 @@ +CC = gcc +JAVAH = javah +MYCFLAGS = -c -Wall -fPIC +MYLDFLAGS = -fPIC -shared +COPY = cp -a + +CLASSPATH = target/classes/ +TARGET_DIR = target + +INCLUDE = -I $(TARGET_DIR) -I $(JAVA_HOME)/include/ -I $(JAVA_HOME)/include/linux +SOURCES = src/main/native/GTKThemeUtils.c +TARGET = $(TARGET_DIR)/GTKThemeUtils.c +OBJECTS = $(TARGET:.c=.o) + +EXECUTABLE = libGTKThemeUtils.so + +MYCFLAGS += `pkg-config --cflags gtk+-2.0` +MYCFLAGS += `pkg-config gthread-2.0 --cflags` + +MYLDFLAGS += `pkg-config --libs gtk+-2.0` +MYLDFLAGS += `pkg-config gthread-2.0 --libs` + +.PHONY: +JNI_LIST = com.redhat.thermostat.internal.utils.laf.gtk.GTKThemeUtils + +$(JNI_LIST): + $(JAVAH) -force -classpath $(CLASSPATH) -d $(TARGET_DIR) $(JNI_LIST) + +all: $(JNI_LIST) init $(SOURCES) $(EXECUTABLE) + +.PHONY: +init: + $(COPY) $(SOURCES) $(TARGET) + +$(EXECUTABLE): $(OBJECTS) + $(CC) $(OBJECTS) -o $(TARGET_DIR)/$@ $(MYLDFLAGS) $(LDFLAGS) + +.c.o: + $(CC) $(MYCFLAGS) $(CFLAGS) $(INCLUDE) $< -o $@ + +clean-lib: + rm $(TARGET_DIR)/$(EXECUTABLE) + +clean-obj: + rm $(OBJECTS) $(TARGET) + +clean: clean-obj clean-lib +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/laf-utils/pom.xml Tue May 21 20:13:26 2013 +0200 @@ -0,0 +1,114 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <artifactId>thermostat</artifactId> + <groupId>com.redhat.thermostat</groupId> + <version>0.8.0-SNAPSHOT</version> + </parent> + + <artifactId>thermostat-laf-utils</artifactId> + <packaging>bundle</packaging> + <name>Thermostat Look And Feel Utils</name> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <Bundle-SymbolicName>com.redhat.thermostat.internal.utils.laf</Bundle-SymbolicName> + <Private-Package> + com.redhat.thermostat.internal.utils.laf.gtk, + </Private-Package> + <Export-Package> + com.redhat.thermostat.internal.utils.laf, + </Export-Package> + <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor> + <!-- Do not autogenerate uses clauses in Manifests --> + <_nouses>true</_nouses> + </instructions> + </configuration> + </plugin> + + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>exec-maven-plugin</artifactId> + <version>1.2.1</version> + <executions> + <execution> + <phase>compile</phase> + <goals> + <goal>exec</goal> + </goals> + </execution> + </executions> + <configuration> + <executable>make</executable> + <arguments> + <argument>all</argument> + </arguments> + <systemProperties> + <systemProperty> + <key>JAVA_HOME</key> + <value>${java.home}</value> + </systemProperty> + </systemProperties> + </configuration> + </plugin> + + </plugins> + + <pluginManagement> + <plugins> + <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.--> + <plugin> + <groupId>org.eclipse.m2e</groupId> + <artifactId>lifecycle-mapping</artifactId> + <version>1.0.0</version> + <configuration> + <lifecycleMappingMetadata> + <pluginExecutions> + <pluginExecution> + <pluginExecutionFilter> + <groupId>org.codehaus.mojo</groupId> + <artifactId>exec-maven-plugin</artifactId> + <versionRange>[1.2.1,)</versionRange> + <goals> + <goal>exec</goal> + </goals> + </pluginExecutionFilter> + <action> + <ignore></ignore> + </action> + </pluginExecution> + </pluginExecutions> + </lifecycleMappingMetadata> + </configuration> + </plugin> + </plugins> + </pluginManagement> + </build> + + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.core</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.compendium</artifactId> + <scope>provided</scope> + </dependency> + + </dependencies> +</project>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/laf-utils/src/main/java/com/redhat/thermostat/internal/utils/laf/ThemeManager.java Tue May 21 20:13:26 2013 +0200 @@ -0,0 +1,124 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.internal.utils.laf; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.swing.JPopupMenu; +import javax.swing.SwingConstants; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import javax.swing.plaf.nimbus.NimbusLookAndFeel; + +import com.redhat.thermostat.internal.utils.laf.gtk.GTKThemeUtils; + +public class ThemeManager { + + private static final Logger logger = Logger.getLogger(ThemeManager.class.getSimpleName()); + private static final ThemeManager theInstance = new ThemeManager(); + + ThemeManager() {} + + public static ThemeManager getInstance() { + return theInstance; + } + + private boolean setLAF(String laf) { + + boolean set = false; + try { + UIManager.setLookAndFeel(laf); + set = true; + } catch (UnsupportedLookAndFeelException | ClassNotFoundException | + InstantiationException | IllegalAccessException e) { + logger.log(Level.WARNING, "cannot set look and feel {0}", laf); + } + return set; + } + + public void setLAF() { + + boolean tryGTKColors = false; + + // check if the user has other preferences... + String laf = System.getProperty("swing.defaultlaf"); + if (laf == null) { + laf = "nimbus"; + tryGTKColors = true; + } + + switch (laf) { + case "system": + laf = UIManager.getSystemLookAndFeelClassName(); + break; + case "nimbus": + laf = NimbusLookAndFeel.class.getName(); + break; + case "dolphin": + laf = "com.redhat.swing.laf.dolphin.DolphinLookAndFeel"; + break; + default: + break; + } + + if (!setLAF(laf)) { + setLAF(NimbusLookAndFeel.class.getName()); + } + + // Thermostat JPopupMenu instances should all be + // ThermostatPopupmenu, so this is redundant, but done in case + // some client code doesn't use the internal popup + JPopupMenu.setDefaultLightWeightPopupEnabled(false); + + UIManager.getDefaults().put("OptionPane.buttonOrientation", SwingConstants.RIGHT); + UIManager.getDefaults().put("OptionPane.sameSizeButtons", true); + + String desktop = System.getProperty("sun.desktop"); + String os = System.getProperty("os.name"); + if (os != null && os.equalsIgnoreCase("linux") && + desktop != null && !desktop.equalsIgnoreCase("kde")) + { + UIManager.getDefaults().put("OptionPane.isYesLast", true); + } + + if (tryGTKColors && desktop != null && desktop.equalsIgnoreCase("gnome")) { + GTKThemeUtils utils = new GTKThemeUtils(); + utils.setNimbusColours(); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/laf-utils/src/main/java/com/redhat/thermostat/internal/utils/laf/gtk/GTKThemeUtils.java Tue May 21 20:13:26 2013 +0200 @@ -0,0 +1,156 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.internal.utils.laf.gtk; + +import java.awt.Color; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +public class GTKThemeUtils { + + private static boolean initialized; + static { + try { + System.loadLibrary("GTKThemeUtils"); + initialized = init(); + } catch (UnsatisfiedLinkError ignore) {} + } + + native private static boolean init(); + native private static boolean hasColor(String id); + native private static int getColor(String id); + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public static Color getColor(String name, float hOffset, float sOffset, + float bOffset, int aOffset) throws Exception + { + Class derivedColorClass = Class.forName("javax.swing.plaf.nimbus.DerivedColor"); + Constructor constructor = derivedColorClass.getDeclaredConstructor(new Class[] { + String.class, float.class, float.class, float.class, int.class + }); + + constructor.setAccessible(true); + + Color color = (Color) constructor.newInstance(new Object[] { + name, hOffset, sOffset, bOffset, aOffset + }); + + return color; + } + + public static void deriveColor(Color color) throws Exception { + Method rederiveColorMethod = color.getClass().getMethod("rederiveColor"); + rederiveColorMethod.setAccessible(true); + rederiveColorMethod.invoke(color); + } + + private Color deriveColor(String colorID, Color defaultColor, float bOffset) { + + Color result = defaultColor; + + int bgColor = getColor(colorID); + Color bg = new Color(bgColor); + + float hOffset = 0.0f; + float sOffset = 0.0f; + int aOffset = 0; + + UIManager.put("gtk-color", bg); + try { + Color derivedColor = getColor("gtk-color", hOffset, sOffset, bOffset, aOffset); + deriveColor(derivedColor); + result = new Color(derivedColor.getRGB()); + + } catch (Exception ignore) {} + + return result; + } + + public void setNimbusColours() { + + if (!initialized) { + return; + } + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + + // if we at least have the bg colour we can try the rest, + // otherwise, just skip everything and use nimbus defaults + if (hasColor("bg_color")) { + + // Those numbers are some kind of magic, they represent the + // value, or brightness, in the HSV encoding of the colour. + // The idea is to derive a darker version of the + // base colour because nimbus will use a brighter version + // for most components. The version used by nimbus does not + // exactly match because nimbus use many multi-gradient + // paints. + float brightnessOffset = -.300f; + + Color nimbusBase = deriveColor("bg_color", UIManager.getDefaults().getColor("nimbusBase"), brightnessOffset); + Color control = UIManager.getDefaults().getColor("control"); + int bgColor = getColor("bg_color"); + control = new Color(bgColor); + + Color info = control; + + UIManager.put("nimbusBase", nimbusBase); + + UIManager.put("control", control); + UIManager.put("info", info); + + Color nimbusFocus = UIManager.getDefaults().getColor("nimbusFocus"); + if (hasColor("selected_bg_color")) { + int fgColor = getColor("selected_bg_color"); + nimbusFocus = new Color(fgColor); + + UIManager.put("nimbusFocus", nimbusFocus); + UIManager.put("nimbusSelectionBackground", nimbusFocus); + UIManager.put("nimbusSelection", nimbusFocus); + UIManager.put("menu", nimbusFocus); + UIManager.put("Menu.background", nimbusFocus); + } + } + } + }); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/laf-utils/src/main/native/GTKThemeUtils.c Tue May 21 20:13:26 2013 +0200 @@ -0,0 +1,159 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +#include "com_redhat_thermostat_internal_utils_laf_gtk_GTKThemeUtils.h" + +#include <jni.h> +#include <glib.h> + +#include <stdio.h> +#include <stdlib.h> + +#include <gtk/gtk.h> +#include <gdk/gdk.h> +#include <X11/Xlib.h> + +JNIEXPORT jboolean JNICALL +Java_com_redhat_thermostat_internal_utils_laf_gtk_GTKThemeUtils_init + (JNIEnv *env, jclass GTKThemeUtils) +{ + int (*handler)(); + int (*io_handler)(); + + // without this code we will get BadWindow + handler = XSetErrorHandler(NULL); + io_handler = XSetIOErrorHandler(NULL); + + g_thread_init(NULL); + gdk_threads_init(); + + gdk_threads_enter(); + + gboolean result = gtk_init_check(NULL, NULL); + + XSetErrorHandler(handler); + XSetIOErrorHandler(io_handler); + + gdk_threads_leave(); + + return (result == TRUE) ? JNI_TRUE : JNI_FALSE; +} + +JNIEXPORT jboolean JNICALL +Java_com_redhat_thermostat_internal_utils_laf_gtk_GTKThemeUtils_hasColor + (JNIEnv *env, jclass GTKThemeUtils, jstring jColourID) +{ + gdk_threads_enter(); + + const char *colourID = (*env)->GetStringUTFChars(env, jColourID, NULL); + gboolean result = FALSE; + + GtkWidget *dummy = gtk_window_new(GTK_WINDOW_TOPLEVEL); + if (dummy == NULL) { + goto bailString; + } + + gtk_widget_ensure_style(dummy); + + GtkStyle *style = gtk_rc_get_style(dummy); + if (style == NULL) { + goto bailWidget; + } + + GdkColor color; + result = gtk_style_lookup_color(style, colourID, &color); + +bailWidget: + gtk_widget_destroy(dummy); + +bailString: + (*env)->ReleaseStringUTFChars(env, jColourID, colourID); + + gdk_threads_leave(); + + return (result == TRUE) ? JNI_TRUE : JNI_FALSE; +} + +JNIEXPORT jint JNICALL +Java_com_redhat_thermostat_internal_utils_laf_gtk_GTKThemeUtils_getColor + (JNIEnv *env, jclass GTKThemeUtils, jstring jColourID) +{ + + gdk_threads_enter(); + + const char *colourID = (*env)->GetStringUTFChars(env, jColourID, NULL); + + GtkWidget *dummy = gtk_window_new(GTK_WINDOW_TOPLEVEL); + if (dummy == NULL) { + goto bailString; + } + + gtk_widget_ensure_style(dummy); + + GtkStyle *style = gtk_rc_get_style(dummy); + if (style == NULL) { + goto bailWidget; + } + + jint pixel = 0L; + GdkColor color; + if (gtk_style_lookup_color(style, colourID, &color)) { + gdk_color_parse(colourID, &color); + + // GTK uses 48 bits to represent colours, while we want a format with + // 8 bits per channel. We just save the most significant bits rather + // than trying to normalise the values. + jint r = color.red >> 8; + jint g = color.green >> 8; + jint b = color.blue >> 8; + + pixel = (r << 16) | (g << 8) | b; + + // fprintf(stderr, "bg colour: %x%x%x\n", r, g, b); + // fprintf(stderr, "bg colour: %x%x%x\n", color.red, color.green, color.blue); + // fprintf(stderr, "bg colour: %u%u %u\n", color.red, color.green, color.blue); + } + +bailWidget: + gtk_widget_destroy(dummy); + +bailString: + (*env)->ReleaseStringUTFChars(env, jColourID, colourID); + + gdk_threads_leave(); + + return pixel; +}
--- a/pom.xml Tue May 21 12:43:17 2013 -0400 +++ b/pom.xml Tue May 21 20:13:26 2013 +0200 @@ -149,6 +149,7 @@ <module>vm-heap-analysis</module> <module>vm-jmx</module> <module>numa</module> + <module>laf-utils</module> <!-- development related modules --> <module>integration-tests</module> <module>dev</module>
--- a/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapSwingViewTest.java Tue May 21 12:43:17 2013 -0400 +++ b/vm-heap-analysis/client-swing/src/test/java/com/redhat/thermostat/vm/heap/analysis/client/swing/internal/HeapSwingViewTest.java Tue May 21 20:13:26 2013 +0200 @@ -187,8 +187,8 @@ } }); - assertFalse(result[0]); - + assertFalse(result[0]); + final JPanelFixture panel = frame.panel(HeapChartPanel.class.getName()); JPopupMenuFixture popup = panel.showPopupMenu(); popup.click();