| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
These are Java bindings for libayatana-appindicator and libappindicator-gtk3, created with jextract on Java 25. They make it possible to build appindicator tray icons for Java applications.
The icons used for the tray icon itself can be SVG, that scale and should look ok on all desktop environments.
After adding the Maven artifact to your code, you can simply define an appindicator tray icon like this:
A new method allows to set an entry in the tray menu insensitive:
Gtk.widgetSetSensitive(gtkMenuItem, false);A new public API eases use of the bindings:
package com.purejava.fxdemo;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.purejava.appindicator.AppIndicator;
import org.purejava.appindicator.GObject;
import org.purejava.appindicator.Gtk;
import org.purejava.appindicator.GCallback;
import java.io.IOException;
import java.lang.foreign.Arena;
import static org.purejava.appindicator.app_indicator_h.*;
public class HelloApplication extends Application {
private static final Arena ARENA = Arena.global();
@Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 320, 240);
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
try (var arena = Arena.ofConfined()) {
arenaAuto = Arena.ofAuto();
var indicator = AppIndicator.newIndicator("example-simple-client",
"indicator-message",
APP_INDICATOR_CATEGORY_APPLICATION_STATUS());
var gtkSeparator = Gtk.newMenuItem();
var gtkMenu = Gtk.newMenu();
var gtkSubmenu = Gtk.newMenu();
var gtkMenuItem = Gtk.newMenuItem();
Gtk.menuItemSetLabel(gtkMenuItem, "More");
var gtkSMenuItem = Gtk.newMenuItem();
Gtk.menuItemSetLabel(gtkSMenuItem, "Change icon");
var gtkSMenuItem1 = Gtk.newMenuItem();
Gtk.menuItemSetLabel(gtkSMenuItem1, "Quit");
Gtk.menuShellAppend(gtkSubmenu, gtkSMenuItem);
Gtk.menuShellAppend(gtkSubmenu, gtkSeparator);
Gtk.menuShellAppend(gtkSubmenu, gtkSMenuItem1);
Gtk.menuItemSetSubmenu(gtkMenuItem, gtkSubmenu);
GObject.signalConnectObject(gtkSMenuItem1, "activate", GCallback.allocate(new QuitCallback(), arenaAuto), gtkMenu, 0);
GObject.signalConnectObject(gtkSMenuItem, "activate", GCallback.allocate(new ChangeIconCallback(indicator), arenaAuto), gtkMenu, 0);
Gtk.menuShellAppend(gtkMenu, gtkMenuItem);
Gtk.widgetShowAll(gtkMenu);
AppIndicator.setMenu(indicator, gtkMenu);
AppIndicator.setAttentionIcon(indicator, "indicator-messages-new");
AppIndicator.setStatus(indicator, APP_INDICATOR_STATUS_ACTIVE());
launch();
}
}
}package com.purejava.fxdemo;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.purejava.appindicator.GCallback;
import java.io.IOException;
import java.lang.foreign.Arena;
import static org.purejava.appindicator.app_indicator_h.*;
public class HelloApplication extends Application {
private static final Arena ARENA = Arena.global();
@Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 320, 240);
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
try (var arena = Arena.ofConfined()) {
var indicator = app_indicator_new(arena.allocateUtf8String("example-simple-client"),
arena.allocateUtf8String("indicator-message"),
APP_INDICATOR_CATEGORY_APPLICATION_STATUS());
var gtkSeparator = gtk_menu_item_new();
var gtkMenu = gtk_menu_new();
var gtkSubmenu = gtk_menu_new();
var gtkMenuItem = gtk_menu_item_new();
gtk_menu_item_set_label(gtkMenuItem, arena.allocateUtf8String("More"));
var gtkSMenuItem = gtk_menu_item_new();
gtk_menu_item_set_label(gtkSMenuItem, arena.allocateUtf8String("Change icon"));
var gtkSMenuItem1 = gtk_menu_item_new();
gtk_menu_item_set_label(gtkSMenuItem1, arena.allocateUtf8String("Quit"));
gtk_menu_shell_append(gtkSubmenu, gtkSMenuItem);
gtk_menu_shell_append(gtkSubmenu, gtkSeparator);
gtk_menu_shell_append(gtkSubmenu, gtkSMenuItem1);
gtk_menu_item_set_submenu(gtkMenuItem, gtkSubmenu);
g_signal_connect_object(gtkSMenuItem1, arena.allocateUtf8String("activate"), GCallback.allocate(new QuitCallback(), ARENA), gtkMenu, 0);
g_signal_connect_object(gtkSMenuItem, arena.allocateUtf8String("activate"), GCallback.allocate(new ChangeIconCallback(indicator), ARENA), gtkMenu, 0);
gtk_menu_shell_append(gtkMenu, gtkMenuItem);
gtk_widget_show_all(gtkMenu);
app_indicator_set_menu(indicator, gtkMenu);
app_indicator_set_attention_icon(indicator, arena.allocateUtf8String("indicator-messages-new"));
app_indicator_set_status(indicator, APP_INDICATOR_STATUS_ACTIVE());
launch();
}
}
}package com.purejava.fxdemo;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.purejava.appindicator.GCallback;
import java.io.IOException;
import java.lang.foreign.Arena;
import java.lang.foreign.SegmentScope;
import static org.purejava.appindicator.app_indicator_h.*;
public class HelloApplication extends Application {
private static final SegmentScope SCOPE = SegmentScope.global();
@Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 320, 240);
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
try (var arena = Arena.openConfined()) {
var indicator = app_indicator_new(arena.allocateUtf8String("example-simple-client"),
arena.allocateUtf8String("indicator-message"),
APP_INDICATOR_CATEGORY_APPLICATION_STATUS());
var gtkSeparator = gtk_menu_item_new();
var gtkMenu = gtk_menu_new();
var gtkSubmenu = gtk_menu_new();
var gtkMenuItem = gtk_menu_item_new();
gtk_menu_item_set_label(gtkMenuItem, arena.allocateUtf8String("More"));
var gtkSMenuItem = gtk_menu_item_new();
gtk_menu_item_set_label(gtkSMenuItem, arena.allocateUtf8String("Change icon"));
var gtkSMenuItem1 = gtk_menu_item_new();
gtk_menu_item_set_label(gtkSMenuItem1, arena.allocateUtf8String("Quit"));
gtk_menu_shell_append(gtkSubmenu, gtkSMenuItem);
gtk_menu_shell_append(gtkSubmenu, gtkSeparator);
gtk_menu_shell_append(gtkSubmenu, gtkSMenuItem1);
gtk_menu_item_set_submenu(gtkMenuItem, gtkSubmenu);
g_signal_connect_object(gtkSMenuItem1, arena.allocateUtf8String("activate"), GCallback.allocate(new QuitCallback(), SCOPE), gtkMenu, 0);
g_signal_connect_object(gtkSMenuItem, arena.allocateUtf8String("activate"), GCallback.allocate(new ChangeIconCallback(indicator), SCOPE), gtkMenu, 0);
gtk_menu_shell_append(gtkMenu, gtkMenuItem);
gtk_widget_show_all(gtkMenu);
app_indicator_set_menu(indicator, gtkMenu);
app_indicator_set_attention_icon(indicator, arena.allocateUtf8String("indicator-messages-new"));
app_indicator_set_status(indicator, APP_INDICATOR_STATUS_ACTIVE());
launch();
}
}
}Don't forget to add the appindicator module to your module-info.java:
module com.purejava.fxdemo {
requires javafx.controls;
requires javafx.fxml;
requires org.kordamp.bootstrapfx.core;
requires org.slf4j;
requires org.purejava.appindicator;
opens com.purejava.fxdemo to javafx.fxml;
exports com.purejava.fxdemo;
}For wiring a tray icon menu item entry to an action, use the GCallback:
package com.purejava.fxdemo;
import org.purejava.appindicator.GCallback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class QuitCallback implements GCallback.Function {
private static final Logger LOG = LoggerFactory.getLogger(QuitCallback.class);
@Override
public void apply() {
LOG.info("Hit Quit");
System.exit(0);
}
}Some notes on requirements to get appindicator support:
| Back | FazBrowse Home | New Git URL |