1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package davmail.ui.tray;
20
21 import davmail.BundleMessage;
22 import davmail.DavGateway;
23 import davmail.Settings;
24 import davmail.ui.AboutFrame;
25 import davmail.ui.SettingsFrame;
26 import davmail.util.IOUtil;
27 import org.apache.log4j.Level;
28 import org.apache.log4j.Logger;
29 import org.eclipse.swt.SWT;
30 import org.eclipse.swt.graphics.DeviceData;
31 import org.eclipse.swt.graphics.GC;
32 import org.eclipse.swt.graphics.Image;
33 import org.eclipse.swt.graphics.ImageData;
34 import org.eclipse.swt.internal.gtk.OS;
35 import org.eclipse.swt.widgets.Display;
36 import org.eclipse.swt.widgets.Menu;
37 import org.eclipse.swt.widgets.MenuItem;
38 import org.eclipse.swt.widgets.Shell;
39 import org.eclipse.swt.widgets.ToolTip;
40 import org.eclipse.swt.widgets.Tray;
41 import org.eclipse.swt.widgets.TrayItem;
42
43 import javax.swing.*;
44 import java.io.ByteArrayInputStream;
45 import java.io.IOException;
46 import java.net.URL;
47 import java.util.ArrayList;
48
49
50
51
52 public class SwtGatewayTray implements DavGatewayTrayInterface {
53 private static final Logger LOGGER = Logger.getLogger(SwtGatewayTray.class);
54
55 private static final Object LOCK = new Object();
56
57 protected SwtGatewayTray() {
58 }
59
60 SettingsFrame settingsFrame;
61 AboutFrame aboutFrame;
62
63 private static TrayItem trayItem;
64 private static ArrayList<java.awt.Image> frameIcons;
65
66 private static Image image;
67 private static Image image2;
68 private static Image inactiveImage;
69 private static Display display;
70 private static Shell shell;
71 private boolean isActive = true;
72 private boolean isReady;
73 private Error error;
74 private boolean firstMessage = true;
75
76
77
78
79
80
81 @Override
82 public java.util.List<java.awt.Image> getFrameIcons() {
83 return frameIcons;
84 }
85
86
87
88
89 public void switchIcon() {
90 isActive = true;
91 display.syncExec(() -> {
92 Image currentImage = trayItem.getImage();
93 if (currentImage != null && currentImage.equals(image)) {
94 trayItem.setImage(image2);
95 } else {
96 trayItem.setImage(image);
97 }
98 });
99
100 }
101
102
103
104
105 public void resetIcon() {
106 display.syncExec(() -> trayItem.setImage(image));
107 }
108
109
110
111
112 public void inactiveIcon() {
113 isActive = false;
114 display.syncExec(() -> trayItem.setImage(inactiveImage));
115 }
116
117
118
119
120
121
122 public boolean isActive() {
123 return isActive;
124 }
125
126
127
128
129
130
131
132 public void displayMessage(final String message, final Level level) {
133 if (trayItem != null) {
134 display.asyncExec(() -> {
135 int messageType = 0;
136 if (level.equals(Level.INFO)) {
137 messageType = SWT.ICON_INFORMATION;
138 } else if (level.equals(Level.WARN)) {
139 messageType = SWT.ICON_WARNING;
140 } else if (level.equals(Level.ERROR)) {
141 messageType = SWT.ICON_ERROR;
142 }
143 if (messageType != 0) {
144 final ToolTip toolTip = new ToolTip(shell, SWT.BALLOON | messageType);
145 toolTip.setText(BundleMessage.format("UI_DAVMAIL_GATEWAY"));
146 toolTip.setMessage(message);
147 trayItem.setToolTip(toolTip);
148
149 if (firstMessage) {
150 firstMessage = false;
151 try {
152 Thread.sleep(1000);
153 } catch (InterruptedException e) {
154 Thread.currentThread().interrupt();
155 }
156 }
157 toolTip.setVisible(true);
158 }
159 trayItem.setToolTipText(BundleMessage.format("UI_DAVMAIL_GATEWAY") + '\n' + message);
160 });
161 }
162 }
163
164
165
166
167
168
169
170 public static Image loadSwtImage(String fileName) {
171 Image result = null;
172 try {
173 ClassLoader classloader = DavGatewayTray.class.getClassLoader();
174 URL imageUrl = classloader.getResource(fileName);
175 if (imageUrl == null) {
176 throw new IOException(fileName);
177 }
178 byte[] imageContent = IOUtil.readFully(imageUrl.openStream());
179 Image tempImage = new Image(display, new ByteArrayInputStream(imageContent));
180 Image backgroundImage = new Image(null, 24, 24);
181 ImageData imageData = backgroundImage.getImageData();
182 imageData.transparentPixel = imageData.getPixel(0, 0);
183 backgroundImage.dispose();
184 result = new Image(null, imageData);
185
186 GC gc = new GC(result);
187 gc.drawImage(tempImage, 4, 4);
188 tempImage.dispose();
189
190 } catch (IOException e) {
191 DavGatewayTray.warn(new BundleMessage("LOG_UNABLE_TO_LOAD_IMAGE"), e);
192 }
193 return result;
194 }
195
196
197
198
199 public void init() {
200 boolean isGTK3;
201
202 try {
203 Class gtk = Class.forName("org.eclipse.swt.internal.gtk.GTK");
204 isGTK3 = (Boolean) gtk.getDeclaredField("GTK3").get(null);
205 LOGGER.debug("org.eclipse.swt.internal.gtk.GTK.GTK3="+isGTK3);
206 if (isGTK3) {
207 LOGGER.warn("GTK 3 not supported, please set SWT_GTK3=0");
208 }
209 } catch (Throwable e) {
210
211 }
212 try {
213 Class gdk = Class.forName("org.eclipse.swt.internal.gtk.GDK");
214
215 gdk.getDeclaredMethod("gdk_error_trap_push").invoke(null);
216 LOGGER.debug("Called org.eclipse.swt.internal.gtk.GDK.gdk_error_trap_push");
217 } catch (Throwable e) {
218
219 }
220
221 try {
222
223 OS.class.getDeclaredMethod("gdk_error_trap_push").invoke(null);
224 LOGGER.debug("Called org.eclipse.swt.internal.gtk.OS.gdk_error_trap_push");
225 } catch (Exception e) {
226
227 }
228 try {
229
230 UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
231 } catch (Exception e) {
232 DavGatewayTray.warn(new BundleMessage("LOG_UNABLE_TO_SET_LOOK_AND_FEEL"));
233 }
234
235 new Thread("SWT") {
236 @Override
237 public void run() {
238 try {
239 DeviceData data = new DeviceData();
240 data.debug = true;
241 display = new Display(data);
242 shell = new Shell(display);
243
244 final Tray tray = display.getSystemTray();
245 if (tray != null) {
246
247 trayItem = new TrayItem(tray, SWT.NONE);
248 trayItem.setToolTipText(BundleMessage.format("UI_DAVMAIL_GATEWAY"));
249
250 frameIcons = new ArrayList<>();
251 frameIcons.add(DavGatewayTray.loadImage(AwtGatewayTray.TRAY128_PNG));
252 frameIcons.add(DavGatewayTray.loadImage(AwtGatewayTray.TRAY_PNG));
253
254 image = loadSwtImage(AwtGatewayTray.TRAY_PNG);
255 image2 = loadSwtImage(AwtGatewayTray.TRAY_ACTIVE_PNG);
256 inactiveImage = loadSwtImage(AwtGatewayTray.TRAY_INACTIVE_PNG);
257
258 trayItem.setImage(image);
259 trayItem.addDisposeListener(e -> {
260 if (image != null && !image.isDisposed()) {
261 image.dispose();
262 }
263 if (image2 != null && !image2.isDisposed()) {
264 image2.dispose();
265 }
266 if (inactiveImage != null && !inactiveImage.isDisposed()) {
267 inactiveImage.dispose();
268 }
269 });
270
271
272 final Menu popup = new Menu(shell, SWT.POP_UP);
273 trayItem.addListener(SWT.MenuDetect, event -> display.asyncExec(
274 () -> popup.setVisible(true)));
275
276 MenuItem aboutItem = new MenuItem(popup, SWT.PUSH);
277 aboutItem.setText(BundleMessage.format("UI_ABOUT"));
278 aboutItem.addListener(SWT.Selection, event -> SwingUtilities.invokeLater(
279 () -> {
280 if (aboutFrame == null) {
281 aboutFrame = new AboutFrame();
282 }
283 aboutFrame.update();
284 aboutFrame.setVisible(true);
285 aboutFrame.toFront();
286 aboutFrame.requestFocus();
287 }));
288
289
290 trayItem.addListener(SWT.DefaultSelection, event -> SwingUtilities.invokeLater(
291 () -> openSettingsFrame()));
292
293 MenuItem defaultItem = new MenuItem(popup, SWT.PUSH);
294 defaultItem.setText(BundleMessage.format("UI_SETTINGS"));
295 defaultItem.addListener(SWT.Selection, event -> SwingUtilities.invokeLater(
296 () -> openSettingsFrame()));
297
298 MenuItem logItem = new MenuItem(popup, SWT.PUSH);
299 logItem.setText(BundleMessage.format("UI_SHOW_LOGS"));
300 logItem.addListener(SWT.Selection, event -> SwingUtilities.invokeLater(DavGatewayTray::showLogs));
301
302 MenuItem exitItem = new MenuItem(popup, SWT.PUSH);
303 exitItem.setText(BundleMessage.format("UI_EXIT"));
304 exitItem.addListener(SWT.Selection, event -> DavGateway.stop());
305
306
307 if (Settings.isFirstStart()) {
308 SwingUtilities.invokeLater(() -> {
309
310 if (settingsFrame == null) {
311 settingsFrame = new SettingsFrame();
312 }
313 settingsFrame.setVisible(true);
314 settingsFrame.toFront();
315 settingsFrame.requestFocus();
316 });
317
318 }
319
320 synchronized (LOCK) {
321
322 isReady = true;
323 LOCK.notifyAll();
324 }
325
326 while (!shell.isDisposed()) {
327 if (!display.readAndDispatch()) {
328 display.sleep();
329 }
330 }
331 }
332
333 if (settingsFrame != null) {
334 settingsFrame.dispose();
335 }
336 if (aboutFrame != null) {
337 aboutFrame.dispose();
338 }
339 } catch (Exception exc) {
340 DavGatewayTray.error(exc);
341 } catch (Error exc) {
342 error = exc;
343 throw exc;
344 }
345
346 System.exit(0);
347 }
348 }.start();
349 while (true) {
350
351 try {
352 synchronized (LOCK) {
353 if (error != null) {
354 throw error;
355 }
356 if (isReady) {
357 break;
358 }
359 LOCK.wait(1000);
360 }
361 } catch (InterruptedException e) {
362 DavGatewayTray.error(new BundleMessage("LOG_ERROR_WAITING_FOR_SWT_INIT"), e);
363 Thread.currentThread().interrupt();
364 }
365 }
366 }
367
368 private void openSettingsFrame() {
369
370 if (settingsFrame == null) {
371 settingsFrame = new SettingsFrame();
372 }
373 settingsFrame.reload();
374 settingsFrame.setVisible(true);
375 settingsFrame.toFront();
376 settingsFrame.requestFocus();
377 }
378
379 public void dispose() {
380 shell.dispose();
381 }
382
383 }