Sun Java Solaris Communities My SDN Account Join SDN
 
Article

Developing on the Solaris OS With "Java GNOME" Bindings

 
By John Rice, February 2007  
Contents
 
Introduction
Choices
What Are Java GNOME Bindings?
How Can I Get Them?
Creating Java GNOME "Hello World"
Responding to the User
Mix in a Little Glade
Hooking Up the Glade UI and the Application
Signal Handlers -- Glade's Action Handlers
Accessing Widgets
Doing a Little More -- Calculator Example
Going Further
Conclusion
About the Author
Recommended Reading
Resources
Example Code Listings
 
Introduction

Since its release in August 2005, the Solaris 10 Operating System has generated huge interest. With over 6 million registered downloads, the Solaris OS has become a real target for desktop developers to create and deploy their applications. Key drivers of this success include the tremendous technical innovation in the Solaris platform, with features such as Zones, DTrace, Predictive Self-Healing, and ZFS, as well as the open sourcing of the Solaris OS on OpenSolaris.org.

To what desktop will these developers be deploying? They will be deploying to GNOME, the new alternative desktop in the Solaris 10 OS to replace the now-aging CDE. GNOME offers a modern, contemporary desktop that can help developers to showcase their best-of-breed desktop applications.

The GNOME community has widely agreed that to attract more desktop developers it is important to be able to offer alternatives to developing desktop applications in C. C is a rather low-level, nuts-and-bolts language that does not have all of the productivity features of a modern object-oriented language, such as interface-based programming, automated memory management, exception handling, and so on. The programming language you will be looking at is one of the most successful object-oriented languages in use today, namely the Java programming language, whose popularity should only continue to grow now that it has been open sourced under the GPL license. It should also be noted that in addition to offering the aforementioned language features, the Java programming language, and in particular the Java Development Kit (JDK), gives developers access to a huge wealth of rock-solid Java platform APIs that can greatly simplify many of the non-UI tasks that modern applications need to tackle, such as working with various data streams, parsing XML data sources, interacting with the network, and so on.

Naturally as 95 percent of the GNOME desktop is written in C, many will still continue to develop desktop applications in C using the support of modern IDEs such as the Sun Studio software, NetBeans with its C/C++ module, and Eclipse, but this article will not address this audience. Plenty of online documentation is available for GNOME C-based development at gnome.org for these folks.

In this article, after a brief introduction of the choices for Java developers who want to create GNOME desktop applications, the focus will be on one particular technology, namely the Java GNOME bindings. These bindings are targeted at those developers who are already familiar with the GNOME platform, but who want to move away from a C-based application development to use the Java programming language. The bindings are available as part of Solaris Express, Developer Edition 2/07.

Choices

When Java software developers want to create a desktop application in the Solaris OS, they need to create an application that will integrate well with the existing GNOME desktop. Such an application should share the same native look and feel as the desktop theme, use the native system dialogs, use the native configuration engine, and in every respect look and behave like a native GNOME desktop application.

A number of choices are available to developers. They can use an application framework such as Swing that is part of the Java Platform, Standard Edition (Java SE) or the SWT framework provided by Eclipse. However, if they are already GNOME developers and familiar with Glade/GTK-based development, then they will have to learn yet another framework, which can of course be very time consuming. The Java GNOME bindings offer another alternative. This is a set of Java bindings for the GNOME platform libraries and the Cairo 2D drawing engine from freedesktop.org. The bindings allow GNOME and GTK+ applications to be written in the Java programming language, making use of Java Native Interface (JNI) support to bridge between Java technology and the underlying native GNOME platform and Cairo C libraries.

It should be stressed that choosing to use the Java GNOME bindings means giving up the flexibility offered by other Java UI frameworks such as SWING to "write once run anywhere," because of this tight coupling to the underlying GNOME platform and Cairo libraries. However, if high fidelity and native GNOME integration are key design constraints, then this is a reasonable trade-off. Java GNOME bindings simply give Java technology developers another choice when developing their desktop applications. It is up to developers to weigh both their knowledge of the platform APIs/frameworks and their cross-platform and native integration requirements when choosing the appropriate framework for their desktop application development.

The rest of this article will explore how to use Java GNOME bindings to develop Java technology-based GNOME applications. The examples will be developed using the NetBeans IDE, but you can of course do much the same in Eclipse if you want (refer to the Java GNOME demo listed in Recommended Reading) or any of the other IDEs out there, such as IntelliJ, jEdit, Emacs, or even vi.

What Are Java GNOME Bindings?

As mentioned earlier, this is a set of bindings to the core libraries you need when developing GNOME and GTK+ applications. The bindings provide a Java API that exposes the underlying platform C APIs using the Java Native Interface support in the Java SE platform. The bindings are shipped as a set of Solaris packages containing:

  • API jars, which provide the Java API and allow the import of the Java GNOME APIs in your application
  • API libraries, which support JNI native C libraries that are called by the Java APIs
  • Documentation about the API source jars that can be used for code completion and source browsing in the IDEs
  • API Javadoc, which provides comprehensive documentation for the APIs
How Can I Get Them?

The good news is that these bindings are already part of the Solaris Express, Developer Edition 2/07. The installed Java GNOME packages for the Solaris OS are SUNWgnome-base-libs-java, SUNWgnome-libs-java, SUNWgnome-config-java, and SUNWgnome-terminal-java.

Java GNOME and the NetBeans IDE

NetBeans is a powerful Java technology-based IDE that can be downloaded from netbeans.org. Java GNOME and the NetBeans IDE can readily be used together to create Java GNOME desktop applications and you can use this IDE along with the Java GNOME API to build a number of sample programs mentioned in this article.

Java GNOME Library in the NetBeans IDE

To give your application access to the bindings, you need to create and add a Java GNOME Library to the NetBeans IDE which references all of the Java GNOME API jars, source jars, and Javadoc. Once this has been created you just need to add the library to any new projects you create to give them access to the bindings.

Java GNOME Library Setup in the NetBeans IDE

Follow these steps to manually set up a JavaGnomeLib for your projects to use.

  • Create the Library
    • Select from the top-level NetBeans menu:
      • Tools/Library Manager
    • Click on New Library to create a new library and name it JavaGnomeLib
  • Add the jar files
    • With the Classpath Tab visible click on Add Jar/Folder and browse to the java-gnome installed jar files under /usr/share/lib/java
    • Select the following jar files and add them to the library: cairo1.0.jar, gconf2.12.jar, glade2.12.jar, glib0.4.jar, gnome2.12.jar, gtk2.10.jar, vte0.12.jar
  • Add the source jar files
    • Click on the Sources Tab then click on Add Jar/Folder and browse to the java-gnome installed source jars under /usr/share/lib/java/src/java-gnome
    • Select the following jar files and add them to the library: cairo1.0-src.jar, gconf2.12-src.jar, glade2.12-src.jar, glib0.4-src.jar, gnome2.12-src.jar, gtk2.10-src.jar, vte0.12-src.jar
  • Add the javadoc
    • Click on the Javadoc Tab then click on Add Zip/Folder and browse to the java-gnome installed javadoc under /usr/share/lib/java/javadoc/java-gnome
    • Select the following folders and add them to the library: cairo-java-1.0.6, libgconf-java-2.12.5, libgnome-java-2.12.6, libvte-java-0.12.2, glib-java-0.4.0, libglade-java-2.12.7, libgtk-java-2.10.0

To simplify this setup, we are creating a Java GNOME NetBeans plugin, which is scheduled to be available shortly on the OpenSolaris.org Java Desktop System project downloads area (refer to Resources). When this is installed it will create the JavaGnomeLib automatically. Note that your application might not require all the Java GNOME API jars, but it is very convenient having a single JavaGnomeLibrary to add to any of your Java GNOME based projects.

Creating Java GNOME "Hello World"

Launch the NetBeans IDE and create a standard Java application.

  • File/ New Project-> General -> Java Application

Name it "hello" and set it up to use the JavaGnomeLib.

  • Go to File/"hello" Properties -> Libraries Category. In both the Compile and Run Tabs, click on Add Library and select the JavaGnomeLib.

Now you are ready to cut some code. Start with a simple "Hello World" just to be different!

 
Figure 1:
Figure 1: "Hello World" Java Code Listing in NetBeans IDE 5.5

First you import the various APIs you want to use from the GTK+ bindings. (Refer to the Java GNOME man page, which is listed in the Resources section, for a full listing of the API imports.) If you want to browse the API sources, just right-click on the import statement and select Go To -> Source. All of the source files from the jar will be displayed in the Project panel, which can be very handy when you are not quite sure which API you want. The NetBeans IDE also supports code completion so just typing window. will display a list of the available APIs on the Window widget, along with the API Javadoc.

In Hello's constructor you create a top-level window and add a button to it with a "Hello!" title, then set its size and show it. The main routine initializes GTK, calls Hello's constructor, and then runs the main GTK event loop to process user input to the display application.

For the sake of brevity I have not shown you how to add a LifeCycleListener handler to the window to to close down the application cleanly when the user presses the close "x". To see how, refer to HelloWorld.java in the java-gnome-code.tar file under Sample Code Listings.

It's not very exciting but you've just created a native GTK application running in the Java programming language that will respond to any GNOME theme change you make on the desktop. Try it and see what I mean. In GNOME use Start Menu -> Preferences-> Theme to switch between Nimbus and Blueprint.

 
Figure 2a:
Figure 2a: "Hello World" Displayed in the Nimbus Theme in GNOME
 
Figure 2a:
Figure 2b: "Hello World" Displayed in the Blueprint Theme in GNOME
Responding to the User

When you click the button nothing happens, so you need to add an action handler, just as you would in any Java desktop application framework. This is an org.gnu.gtk.event.ButtonListener.

Add the following button listener to the Hello constructor after the button, btn, has been created.

btn.addListener(new ButtonListener() {
	public void buttonEvent(ButtonEvent e) {
	 	if (e.isOfType(ButtonEvent.Type.CLICK))
	            { System.out.println("Hello cruel world!"); } } });

If there are any issues in your code, the NetBeans IDE will make suggestions through a little light bulb that appears to the right side of the code as you type. Note that you can also open these code hints by typing Ctrl-Space. So as you type in the aforementioned code, a light bulb will appear. Clicking on the light bulb prompts you to add an import statement for ButtonListener and then ButtonEvent and ButtonEvent.Type. (All very handy for those of us who are a little absent-minded.)

 
Figure 3: Code Hints in the NetBeans IDE
Figure 3: Code Hints in the NetBeans IDE

Running the application now and clicking on the Hello World button will generate the "Hello cruel world!" output on the standard output.

 
Figure 4:
Figure 4: "Hello World" Responding to a Button Click
Mix in a Little Glade

You can continue to build up your UI programmatically as you have done previously, but this can become rather tedious to say the least when you are dealing with a complex real-world desktop application. Wouldn't it be much better to be able to separate the UI definition from the code that manipulates it? This is exactly what Glade is designed to do. It is a GNOME UI designer that allows you to create your UI in a WYSIWYG editor and save it out in a UI XML specification file. This Glade file can then be loaded in any GNOME application that supports the LibGlade API, which is also part of the Java GNOME bindings.

So now you can create a little more complex UI than your Hello World application in Glade and load it in your test application, thanks to Andrew Overholt, whose Flash demo I shamelessly copied (see Recommended Reading).

Launch Glade

  • All Applications -> Developer Tools -> Glade User Interface Designer

The Main Glade Window will appear along with a Palette, Widget Tree, and Properties Panel.

 
Figure 5: Glade User Interface Designer
Figure 5: Glade User Interface Designer
  • Click on New to create a new project and select GTK+ Project.

Now from the Palette "GTK+ Basic" section choose Window. Add a Vertical Box with three rows to this window (just hover over the palette items to see what they are called). Then into the top row add a Label, into the middle row a Button, and into the bottom row a Text Entry widget from the palette.

To change any properties of the created widgets, just select them in the Widget Tree or the displayed window and edit their settings in the Properties panel.

  • Change the window1's title to TestGlade, the label1's label to "Label's are cool," the button1's label to "Press Me!". Then resize the main window so you have something along the lines of the UI illustrated in Figure 6.
  • Now create a new NetBeans Java application project called TestGlade and as before set its properties to use the JavaGnomeLib. Then go back to the Glade main window and save the Glade project into the NetBeans TestGlade project directory under a new glade directory, setting the project name to "TestGlade." This will save the UI specification under glade/testglade.glade.
 
Figure 6: TestGlade UI Created in the Glade UI Designer
Figure 6: TestGlade UI Created in the Glade UI Designer
Hooking Up the Glade UI and the Application

To get your GNOME application to use the new Glade UI you need to load the Glade file in our application constructor.

public TestGlade() {
    LibGlade glade = new LibGlade("glade/testglade.glade", this);
  }

The NetBeans IDE will prompt you to add your import for LibGlade and also prompt you to add a try block around this call as it will throw an exception if the Glade file is not found or the XML is malformed. For a full listing refer to TestGlade.java in the java-gnome-code.tar file under Sample Code Listings.

So this is certainly a simple way to create a UI but it's not doing very much at present. What you need to do is somehow pass user events to your application code where you can respond to them. Glade signal handlers provide the tool needed.

Signal Handlers -- Glade's Action Handlers

In Glade if you want to have your Java code respond to any user interaction, you need to associate a signal handler with the widget in Glade and then provide a signal handler implementation in your code, in much the same way as you set up action handlers in the first example. You can associate a broad range of signal handlers with any given widget in Glade. These signal handlers can then be implemented in your application code and will be triggered whenever the appropriate user interaction occurs within the running application.

It should be stressed that the signal handler and the Java implementation must have exactly the same name for all this to work. You can take the default name Glade and generate or modify it in Glade to something else as long as your Java method implementation has the same name.

Extend the TestGlade application so that upon clicking the "Press Me!" button it will display a message "Button Clicked!" to the standard output window.

First go back to your Test Glade project in Glade.

  • Select button1 and in the Properties dialog click on the Signals tab. Click on the Signal selection "..." button and choose the "clicked" signal. Click Add to add the signal handler.

This creates a handler on_button1_clicked. Save the Glade project.

Here's a screen shot of Glade being used to set up the button1 signal handler on_button1_clicked in the Signals tab of the Properties dialog.

 
Figure 7: Adding a Signal Handler in the Glade UI Designer
Figure 7: Adding a Signal Handler in the Glade UI Designer

Go back to the NetBeans TestGlade project.

  • Add in an implementation for the "Press Me!" clicked signal handler.
public void on_button1_clicked() {
    System.out.println("Button Clicked!");
  }

Run the TestGlade application and click on the "Press Me!" button to see the signal handler in action.

Accessing Widgets

When your application responds to user interaction in your signal handlers, you may need to access one or more of the UI widgets to modify the application in some way. For instance, when you click on "Press Me!" rather than just typing out a fixed message, you'd like the application to display on the standard output whatever text the user has entered in the Text Entry widget.

To do this you need to get a handle to the Glade widget and store this internally in the class for reference by the on_button1_clicked signal handler. In production code you would check that "entry" exists after the getWidget() call, if the getWidget() call did not throw an exception.

LibGlade glade = new LibGlade("glade/testglade.glade", this);
entry = (Entry)glade.getWidget("entry1");

When you type in the previous code, the NetBeans IDE will prompt you to "Create field entry in testglade.TestGlade" to add a "private Entry entry;" instance variable for yourself. You then change the signal handler to access the text in the Text Entry widget.

public void on_button1_clicked() {
    System.out.println("User typed: " + entry.getText());
  }

Doing a Little More -- Calculator Example

As an example of a little more interesting application I took the NetBeans BlueJ Calculator example (created by David J. Barnes and Michael Kolling) and ported it over to use a Glade UI and the Java GNOME API. The core calculation CalcEngine is essentially unchanged. For code listings refer to the conclusion of this article.

 
Figure 8: Java GNOME Calculator Example
Figure 8: Java GNOME Calculator Example

Since the engine only supports addition and subtraction, I modeled the UI on the GNOME Calculator in the Solaris OS using Glade and just set the Sensitivity to "No" to disable unsupported buttons (Properties Panel -> Common Tab).

If you look at the code it is worth pointing out a few things.

GNOME application -- This is a GNOME application as opposed to a GTK+ application. This means that when you create a GNOME application in Glade you can create an application window in the Palette "GNOME" section as opposed to using a plain window as your starting point. The application window has a top-level menu, a toolbar, and an app bar (status message) that you can edit as required.

This is initialized slightly differently than the GTK applications already discussed using Program.initGnomeUI:

public static void main(String[] args) {

    Program prog = Program.initGnomeUI("Calculator", "1.0", args);

    new CalculatorApp();

    Gtk.main();

  }

Passing named objects to the signal handlers -- Sometimes you need to associate a given object with a signal handler and have it passed to the signal handler when it is triggered by the UI. In the calculator example for instance, rather than having a separate signal handler for each function button, you wanted to have just one signal handler and process the user input depending on which button the user had pressed. The way to do this in Glade is when you set up the signal handler for a button, also set the Object field to the name of the button. In this way the named button will be passed to the signal handler. To process this object just use the overloaded signal handler signature in your Java code, which takes the appropriate Event widget and a generic target Object, which must then be cast appropriately to use.

public void on_button_clicked(ButtonEvent event, Object target) {
    // Get the Named Button Widget set as the Signal Handler Object in Glade

    String command = ((Button) target).getLabel();

    System.out.println("Button Clicked: " + command);


    if( command.equals("0") || command.equals("1") ||
        command.equals("2") || command.equals("3") ||

	:

GConf -- This is GNOME's configuration system and should be used by applications to store user application preferences and data. In addition it can also be used by applications to retrieve GNOME system-wide data that are of use to the application, such as network proxy settings for a networked client. To demonstrate the use of GConf a number of functions have been added to UserInterface.java to both initialize GConf and get/set the last number typed into the calculator. This data is persisted between invocations of the calculator in the GConf system if you close the application using the File-> Quit menu. The use of GConf just requires you to get a handle on the GConf system. You then instruct the ConfClient which directories you want to interact with and after that you use this client instance to create, get, and set the GConf key values.

private final String lastResultKey = 
        "/apps/javagnome_calculator_app/last_result";
		:
public void setupGconfAccess() {
  client = ConfClient.getInstance();
  try {

    client.addDirectory("/apps/javagnome-calculator-app", 
        ConfClientPreloadType.NONE);
     
     :
 public String getGconfKeyValue(String configKey){
   try {
      return client.getString(configKey);
      :

 public void setGconfKeyValue(String configKey, String configKeyValue){
   try {
      if (null != configKeyValue)
        client.setString(configKey, configKeyValue);
      :

You can also add a ConfClientListener to the ConfClient instance to get notification for changes in specific GConf key values, if you want, using client.addListener (listener, configKey).

Going Further

There is a lot more to do. Check out the examples provided with the Java GNOME bindings. In particular, look at the following TestGtk and TestGnome applications:

/usr/share/lib/java/javadoc/java-gnome/libgtk-java-##/examples/testgtk/TestGTK

/usr/share/lib/java/javadoc/java-gnome/libgnome-java-##/examples/testgnome/TestGNOME

GConf and Glade examples are also found under the libgconf and libglade subdirectories under the aforementioned javadoc/java-gnome directory. Check out some of the real-world applications on the Java GNOME community site (refer to "Java GNOME applications" in the Recommended Reading section). Feel free to drop on by the #java-gnome channel (irc.gimp.net) to chat with the developers and ask any questions you might have about using the bindings. If you create a cool app let them know, so they can help you strut your stuff!

Conclusion

The Java GNOME bindings offer developers who are already familiar with Glade-based GNOME/GTK+ application development a viable route to developing these types of desktop applications in the Java programming language. At present you can find reasonable coverage of the core libraries, but there are some obvious omissions, such as GNOME applet support and system tray support.

The Java GNOME community is already in the middle of a redesign of the bindings to allow a more automated generation of the bindings. This will help to provide nearly 100 percent API coverage of all the underlying GNOME platform and Cairo native libraries and ensure that they stay in sync with future releases of the GNOME platform.

Be sure to check out the community site for the latest updates. The community is always happy to get new contributors to the project. So get hacking in Java GNOME!

About the Author

John Rice is a staff engineer at Sun who has been working with the OpenSolaris Desktop group over the past number of years. Before this he spent time with the OpenOffice team, helping to automate migration of macros from Microsoft Office to OpenOffice. He has more than 18 years of development experience in the software industry, mostly in the area of document management and desktop application development. A member of the GNOME Advisory Board, John lives by the sea on the east coast of Ireland and can be found at unseasonably early hours of the morning running along the nearby shore, preparing for his next marathon.

Recommended Reading
Resources

Solaris Express, Developer Edition 2/07 - Java GNOME 2.16 installation:

  • Installed packages:
    • SUNWgnome-base-libs-java
    • SUNWgnome-libs-java
    • SUNWgnome-config-java
    • SUNWgnome-terminal-java
  • API jars (/usr/share/lib/java/):
    • cairo1.0.jar
    • glib0.4.jar
    • gtk2.10.jar
    • gnome2.12.jar
    • glade2.12.jar
    • gconf2.12.jar
    • vte0.12.jar
  • API libraries (/usr/lib/):
    • libcairojni.so
    • libglibjni.so
    • libgtkjni.so
    • libgnomejni.so
    • libgladejni.so
    • libgconfjni.so
    • libvtejni.so
  • API Javadoc: /usr/share/lib/java/javadoc/java-gnome/*/index.html
  • API source jars: /usr/share/lib/java/src/java-gnome/*-src.jar
  • API examples: /usr/share/lib/java/javadoc/java-gnome/*/examples/
  • Man page (3): man java-gnome
  • NetBeans IDE 5.5 download
  • OpenSolaris.org Java Desktop System Project
Example Code Listings

Sample code listings are available in the java-gnome-code.tar file. The contents of the tar file are listed here:

java-gnome-code/
java-gnome-code/testglade/
java-gnome-code/testglade/TestGlade.java
java-gnome-code/testglade/glade/
java-gnome-code/testglade/glade/testglade.glade.txt
java-gnome-code/licensing.txt
java-gnome-code/hello/
java-gnome-code/hello/Hello.java
java-gnome-code/calculator/
java-gnome-code/calculator/UserInterface.java
java-gnome-code/calculator/CalcEngine.java
java-gnome-code/calculator/CalculatorApp.java
java-gnome-code/calculator/glade/
java-gnome-code/calculator/glade/calculator.glade.txt

Note: Files ending in glade.txt should be renamed as .glade files before use.

Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
Your email address (no reply is possible without an address):
Sun Privacy Policy

Note: We are not able to respond to all submitted comments.