Basic usage

Required Java version

First, download and install JDK 21. Java-GI uses the "Panama" Foreign Function & Memory API that is available as a preview feature in JDK 21.

Dependencies

Make sure that the native GLib, Gtk and/or GStreamer libraries are installed on your operating system.

Next, add the dependencies. For example, if you use Gradle:

repositories {
    mavenCentral()
}

dependencies {
    implementation 'io.github.jwharm.javagi:gtk:0.9.2'
}

This will add the Gtk bindings to the application's compile and runtime classpath. Other libraries, like webkit, gst, adw and gtksourceview can be included likewise. The complete list of available libraries is available here.

Application code

An example Gtk application with a "Hello world" button can be created as follows:

package io.github.jwharm.javagi.examples.helloworld;

import org.gnome.gtk.*;
import org.gnome.gio.ApplicationFlags;

public class HelloWorld {

    public static void main(String[] args) {
        new HelloWorld(args);
    }

    private final Application app;

    public HelloWorld(String[] args) {
        app = new Application("my.example.HelloApp", ApplicationFlags.DEFAULT_FLAGS);
        app.onActivate(this::activate);
        app.run(args);
    }

    public void activate() {
        var window = new ApplicationWindow(app);
        window.setTitle("GTK from Java");
        window.setDefaultSize(300, 200);

        var box = Box.builder()
            .setOrientation(Orientation.VERTICAL)
            .setHalign(Align.CENTER)
            .setValign(Align.CENTER)
            .build();

        var button = Button.withLabel("Hello world!");
        button.onClicked(window::close);

        box.append(button);
        window.setChild(box);
        window.present();
    }
}

Compile and run

Build and run the application with the following parameters:

  • Set the Java language version: --release 21

  • While the Panama foreign function API is still in preview status, set the --enable-preview option both when compiling and running your application.

  • To suppress warnings about native access, also add --enable-native-access=ALL-UNNAMED.

  • If you encounter an error about a missing library, override the java library path with "-Djava.library.path=/usr/lib/...".

See this build.gradle file for a complete example.

Java library path

If you see an error about a missing library, make sure that all dependencies are installed, and available on Java library path (the "java.library.path" system property). If necessary, you can override the Java library path with the -Djava.library.path= JVM argument, for example: -Djava.library.path=/lib/x86_64-linux-gnu on Debian-based systems.

In the Java-GI examples, the JVM arguments are setup for the system library folders of the common (RedHat/Fedora, Arch and Debian/Ubuntu) Linux distributions:

tasks.named('run') {
    jvmArgs += "--enable-preview"
    jvmArgs += "--enable-native-access=ALL-UNNAMED"
    jvmArgs += "-Djava.library.path=/usr/lib64:/lib64:/lib:/usr/lib:/lib/x86_64-linux-gnu"
}

On MacOS, if you installed Gtk using Homebrew, the library path is usually /opt/homebrew/lib. You also need to add the parameter -XstartOnFirstThread. So the complete task definition will look like this:

tasks.named('run') {
    jvmArgs += "--enable-preview"
    jvmArgs += "--enable-native-access=ALL-UNNAMED"
    jvmArgs += '-Djava.library.path=/opt/homebrew/lib'
    jvmArgs += '-XstartOnFirstThread'
}

On Windows, if you installed Gtk with MSYS2, the default path is C:\msys64\mingw64\bin. If that's the case, you can change the build file like this:

tasks.named('run') {
    jvmArgs += "--enable-preview"
    jvmArgs += "--enable-native-access=ALL-UNNAMED"
    jvmArgs += '-Djava.library.path=C:/msys64/mingw64/bin'
}