forked from cryptomator/integrations-linux
/
AppindicatorTrayMenuController.java
118 lines (104 loc) · 3.92 KB
/
AppindicatorTrayMenuController.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package org.cryptomator.linux.tray;
import org.cryptomator.integrations.common.CheckAvailability;
import org.cryptomator.integrations.common.OperatingSystem;
import org.cryptomator.integrations.common.Priority;
import org.cryptomator.integrations.tray.ActionItem;
import org.cryptomator.integrations.tray.SeparatorItem;
import org.cryptomator.integrations.tray.SubMenuItem;
import org.cryptomator.integrations.tray.TrayIconLoader;
import org.cryptomator.integrations.tray.TrayMenuController;
import org.cryptomator.integrations.tray.TrayMenuException;
import org.cryptomator.integrations.tray.TrayMenuItem;
import org.purejava.appindicator.AppIndicator;
import org.purejava.appindicator.GCallback;
import org.purejava.appindicator.GObject;
import org.purejava.appindicator.Gtk;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.util.List;
import java.util.function.Consumer;
import static org.purejava.appindicator.app_indicator_h.APP_INDICATOR_CATEGORY_APPLICATION_STATUS;
import static org.purejava.appindicator.app_indicator_h.APP_INDICATOR_STATUS_ACTIVE;
@Priority(1000)
@CheckAvailability
@OperatingSystem(OperatingSystem.Value.LINUX)
public class AppindicatorTrayMenuController implements TrayMenuController {
private static final String APP_INDICATOR_ID = "org.cryptomator.Cryptomator";
private static final String SVG_SOURCE_PROPERTY = "cryptomator.integrationsLinux.trayIconsDir";
private static final Arena ARENA = Arena.global();
private MemorySegment indicator;
private MemorySegment menu = Gtk.newMenu();
@CheckAvailability
public static boolean isAvailable() {
return AppIndicator.isLoaded();
}
@Override
public void showTrayIcon(Consumer<TrayIconLoader> iconLoader, Runnable runnable, String s) throws TrayMenuException {
TrayIconLoader.FreedesktopIconName callback = this::showTrayIconWithSVG;
iconLoader.accept(callback);
Gtk.widgetShowAll(menu);
AppIndicator.setStatus(indicator, APP_INDICATOR_STATUS_ACTIVE());
}
private void showTrayIconWithSVG(String iconName) {
var svgSourcePath = System.getProperty(SVG_SOURCE_PROPERTY);
// flatpak
if (svgSourcePath == null) {
indicator = AppIndicator.newIndicator(APP_INDICATOR_ID,
iconName,
APP_INDICATOR_CATEGORY_APPLICATION_STATUS());
// AppImage and ppa
} else {
indicator = AppIndicator.newIndicatorWithPath(APP_INDICATOR_ID,
iconName,
APP_INDICATOR_CATEGORY_APPLICATION_STATUS(),
// find tray icons theme in mounted AppImage / installed on system by ppa
svgSourcePath);
}
}
@Override
public void updateTrayIcon(Consumer<TrayIconLoader> iconLoader) {
TrayIconLoader.FreedesktopIconName callback = this::updateTrayIconWithSVG;
iconLoader.accept(callback);
}
private void updateTrayIconWithSVG(String iconName) {
AppIndicator.setIcon(indicator, iconName);
}
@Override
public void updateTrayMenu(List<TrayMenuItem> items) throws TrayMenuException {
menu = Gtk.newMenu();
addChildren(menu, items);
Gtk.widgetShowAll(menu);
AppIndicator.setMenu(indicator, menu);
}
@Override
public void onBeforeOpenMenu(Runnable runnable) {
}
private void addChildren(MemorySegment menu, List<TrayMenuItem> items) {
for (var item : items) {
switch (item) {
case ActionItem a -> {
var gtkMenuItem = Gtk.newMenuItem();
Gtk.menuItemSetLabel(gtkMenuItem, a.title());
GObject.signalConnectObject(gtkMenuItem,
"activate",
GCallback.allocate(new ActionItemCallback(a), ARENA),
menu,
0);
Gtk.menuShellAppend(menu, gtkMenuItem);
}
case SeparatorItem _ -> {
var gtkSeparator = Gtk.newMenuItem();
Gtk.menuShellAppend(menu, gtkSeparator);
}
case SubMenuItem s -> {
var gtkMenuItem = Gtk.newMenuItem();
var gtkSubmenu = Gtk.newMenu();
Gtk.menuItemSetLabel(gtkMenuItem, s.title());
addChildren(gtkSubmenu, s.items());
Gtk.menuItemSetSubmenu(gtkMenuItem, gtkSubmenu);
Gtk.menuShellAppend(menu, gtkMenuItem);
}
}
}
}
}