From 2b819cf74759aff7842698e7abd403798c4dd441 Mon Sep 17 00:00:00 2001 From: Ingo Bauersachs Date: Sat, 14 Jan 2017 16:04:21 +0100 Subject: Add option to choose tray icon mode (Native, Disabled, AppIndicator) --- .../sip/communicator/impl/gui/UIServiceImpl.java | 39 +++------- .../sip/communicator/impl/gui/main/MainFrame.java | 57 +++++++++++---- .../osdependent/jdic/SystrayServiceJdicImpl.java | 40 +++++++++-- .../impl/osdependent/systemtray/SystemTray.java | 72 ++++++++++++++----- .../systemtray/appindicator/AppIndicatorTray.java | 24 ++----- .../generalconfig/GeneralConfigurationPanel.java | 82 +++++++++++++++++++++- .../sip/communicator/service/gui/UIService.java | 26 ++----- .../service/systray/SystrayService.java | 20 ++++++ .../util/launchutils/LaunchArgHandler.java | 6 ++ 9 files changed, 258 insertions(+), 108 deletions(-) (limited to 'src') diff --git a/src/net/java/sip/communicator/impl/gui/UIServiceImpl.java b/src/net/java/sip/communicator/impl/gui/UIServiceImpl.java index b7e1d9c..db2eac9 100644 --- a/src/net/java/sip/communicator/impl/gui/UIServiceImpl.java +++ b/src/net/java/sip/communicator/impl/gui/UIServiceImpl.java @@ -200,6 +200,7 @@ public class UIServiceImpl } if(ConfigurationUtils.isApplicationVisible() + || Boolean.getBoolean("disable-tray") || ConfigurationUtils.isMinimizeInsteadOfHide()) { mainFrame.setFrameVisible(true); @@ -433,38 +434,16 @@ public class UIServiceImpl } /** - * Implements {@link UIService#setExitOnMainWindowClose}. Sets the boolean - * property which indicates whether the application should be exited when - * the main application window is closed. - * - * @param exitOnMainWindowClose true if closing the main - * application window should also be exiting the application; otherwise, - * false - */ - public void setExitOnMainWindowClose(boolean exitOnMainWindowClose) - { - mainFrame.setDefaultCloseOperation( - exitOnMainWindowClose - ? JFrame.DISPOSE_ON_CLOSE - : ConfigurationUtils.isMinimizeInsteadOfHide() - ? JFrame.DO_NOTHING_ON_CLOSE - : JFrame.HIDE_ON_CLOSE); - } - - /** - * Implements {@link UIService#getExitOnMainWindowClose()}. Gets the boolean - * property which indicates whether the application should be exited when - * the main application window is closed. - * - * @return determines whether the UI impl would exit the application when - * the main application window is closed. + * Called from the systray service when a tray has been initialized and + * hiding (instead of minimizing or exiting) is possible). If hiding is + * possible and the option to minimize is not selected, the application + * gets hidden on clicking 'X'. + * + * @param true if a tray icon was loaded. */ - public boolean getExitOnMainWindowClose() + public void setMainWindowCanHide(boolean canHide) { - return - (mainFrame != null) - && (mainFrame.getDefaultCloseOperation() - == JFrame.DISPOSE_ON_CLOSE); + mainFrame.updateCloseAction(canHide); } /** diff --git a/src/net/java/sip/communicator/impl/gui/main/MainFrame.java b/src/net/java/sip/communicator/impl/gui/main/MainFrame.java index 4762df8..b450efe 100644 --- a/src/net/java/sip/communicator/impl/gui/main/MainFrame.java +++ b/src/net/java/sip/communicator/impl/gui/main/MainFrame.java @@ -334,13 +334,9 @@ public class MainFrame */ private void init() { - setDefaultCloseOperation( - GuiActivator.getUIService().getExitOnMainWindowClose() - ? JFrame.DISPOSE_ON_CLOSE - : JFrame.HIDE_ON_CLOSE); - + // at startup, we cannot hide yet + updateCloseAction(false); registerKeyActions(); - JComponent northPanel = createTopComponent(); this.setJMenuBar(menu); @@ -394,6 +390,30 @@ public class MainFrame } } + /** + * If hiding is possible and the option to minimize is not selected, the + * application gets hidden on clicking 'X'. + * + * @param true if hiding is possible, i.e. a tray icon is loaded + */ + public void updateCloseAction(boolean canHide) + { + if (ConfigurationUtils.isMinimizeInsteadOfHide()) + { + logger.info("Updating close action: DO_NOTHING_ON_CLOSE"); + setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + } + else + { + logger.info("Updating close action: " + (canHide + ? "HIDE_ON_CLOSE" + : "DISPOSE_ON_CLOSE")); + setDefaultCloseOperation(canHide + ? JFrame.HIDE_ON_CLOSE + : JFrame.DISPOSE_ON_CLOSE); + } + } + private Component createButtonPanel() { boolean isCallButtonEnabled = false; @@ -1885,7 +1905,8 @@ public class MainFrame */ protected void windowClosed(WindowEvent event) { - if(GuiActivator.getUIService().getExitOnMainWindowClose()) + if(getDefaultCloseOperation() == JFrame.EXIT_ON_CLOSE || + getDefaultCloseOperation() == JFrame.DISPOSE_ON_CLOSE) { try { @@ -1919,10 +1940,17 @@ public class MainFrame // On Mac systems the application is not quited on window close, so we // don't need to warn the user. - if (!GuiActivator.getUIService().getExitOnMainWindowClose() - && !OSUtils.IS_MAC - && GuiActivator.getSystrayService().checkInitialized()) + if (OSUtils.IS_MAC) { + return; + } + + switch (getDefaultCloseOperation()) + { + case JFrame.EXIT_ON_CLOSE: + case JFrame.DISPOSE_ON_CLOSE: + return; + case JFrame.HIDE_ON_CLOSE: SwingUtilities.invokeLater(new Runnable() { public void run() @@ -1941,12 +1969,11 @@ public class MainFrame } } }); - ConfigurationUtils.setApplicationVisible(false); - if (ConfigurationUtils.isMinimizeInsteadOfHide()) - { - this.minimize(); - } + break; + case JFrame.DO_NOTHING_ON_CLOSE: + this.minimize(); + break; } } diff --git a/src/net/java/sip/communicator/impl/osdependent/jdic/SystrayServiceJdicImpl.java b/src/net/java/sip/communicator/impl/osdependent/jdic/SystrayServiceJdicImpl.java index fd9d43e..0b40798 100644 --- a/src/net/java/sip/communicator/impl/osdependent/jdic/SystrayServiceJdicImpl.java +++ b/src/net/java/sip/communicator/impl/osdependent/jdic/SystrayServiceJdicImpl.java @@ -21,6 +21,8 @@ import java.awt.*; import java.awt.event.*; import java.awt.image.*; import java.net.*; +import java.util.HashMap; +import java.util.Map; import javax.swing.*; import javax.swing.event.*; @@ -54,7 +56,6 @@ import com.apple.eawt.*; public class SystrayServiceJdicImpl extends AbstractSystrayService { - /** * The systray. */ @@ -130,7 +131,6 @@ public class SystrayServiceJdicImpl super(OsDependentActivator.bundleContext); SystemTray systray; - try { systray = SystemTray.getSystemTray(); @@ -146,10 +146,39 @@ public class SystrayServiceJdicImpl logger.error("Failed to create a systray!", t); } } - this.systray = systray; + this.systray = systray; if (this.systray != null) + { initSystray(); + } + } + + @Override + public Map getSystrayModes() + { + return new HashMap() + {{ + put("disabled", "service.systray.mode.DISABLED"); + if (java.awt.SystemTray.isSupported()) + { + put("native", "service.systray.mode.NATIVE"); + } + + if (!OSUtils.IS_MAC && !OSUtils.IS_WINDOWS) + { + put("appindicator", + "service.systray.mode.APPINDICATOR"); + put("appindicator_static", + "service.systray.mode.APPINDICATOR_STATIC"); + } + }}; + } + + @Override + public String getActiveSystrayMode() + { + return SystemTray.getSystemTrayMode(); } /** @@ -323,8 +352,7 @@ public class SystrayServiceJdicImpl }); initialized = true; - - uiService.setExitOnMainWindowClose(false); + uiService.setMainWindowCanHide(true); } /** @@ -432,8 +460,6 @@ public class SystrayServiceJdicImpl @Override public boolean checkInitialized() { - if (!initialized) - logger.error("Systray not init"); return initialized; } diff --git a/src/net/java/sip/communicator/impl/osdependent/systemtray/SystemTray.java b/src/net/java/sip/communicator/impl/osdependent/systemtray/SystemTray.java index 74baa16..818d1e7 100644 --- a/src/net/java/sip/communicator/impl/osdependent/systemtray/SystemTray.java +++ b/src/net/java/sip/communicator/impl/osdependent/systemtray/SystemTray.java @@ -26,6 +26,7 @@ import org.jitsi.util.*; import net.java.sip.communicator.impl.osdependent.*; import net.java.sip.communicator.impl.osdependent.systemtray.appindicator.*; import net.java.sip.communicator.impl.osdependent.systemtray.awt.*; +import net.java.sip.communicator.service.systray.*; import net.java.sip.communicator.util.Logger; /** @@ -33,11 +34,9 @@ import net.java.sip.communicator.util.Logger; */ public abstract class SystemTray { - private static final String PNMAE_DISABLE_TRY = - "net.java.sip.communicator.osdependent.systemtray.DISABLE"; - private static final Logger logger = Logger.getLogger(SystemTray.class); private static SystemTray systemTray; + private static final String DISABLED_TRAY_MODE = "disabled"; /** * Gets or creates the supported SystemTray implementations. @@ -45,37 +44,78 @@ public abstract class SystemTray */ public final static SystemTray getSystemTray() { - boolean disable = OsDependentActivator.getConfigurationService() - .getBoolean(PNMAE_DISABLE_TRY, false); - if (disable || GraphicsEnvironment.isHeadless()) - { - return null; - } - if (systemTray == null) { - if (OSUtils.IS_LINUX) + String mode = getSystemTrayMode(); + logger.info("Tray for " + mode + " requested"); + switch (mode) { + case DISABLED_TRAY_MODE: + return null; + case "native": + if (java.awt.SystemTray.isSupported()) + { + systemTray = new AWTSystemTray(); + } + + break; + case "appindicator": + try + { + systemTray = new AppIndicatorTray(true); + } + catch(Exception ex) + { + logger.error("AppIndicator tray not available", ex); + } + break; + case "appindicator_static": try { - systemTray = new AppIndicatorTray(); - return systemTray; + systemTray = new AppIndicatorTray(false); } catch(Exception ex) { - logger.info(ex.getMessage()); + logger.error("AppIndicator tray not available", ex); } + + break; } - if (java.awt.SystemTray.isSupported()) + if (systemTray == null) { - systemTray = new AWTSystemTray(); + OsDependentActivator.getConfigurationService() + .setProperty(SystrayService.PNMAE_TRAY_MODE, "disabled"); } } return systemTray; } + public static String getSystemTrayMode() + { + String defaultTrayMode = DISABLED_TRAY_MODE; + if (GraphicsEnvironment.isHeadless()) + { + return DISABLED_TRAY_MODE; + } + + // setting from cmd-line: request to disable tray in case it failed + if (Boolean.getBoolean("disable-tray")) + { + OsDependentActivator.getConfigurationService().setProperty( + SystrayService.PNMAE_TRAY_MODE, DISABLED_TRAY_MODE); + } + + if (OSUtils.IS_WINDOWS || OSUtils.IS_MAC) + { + defaultTrayMode = "native"; + } + + return OsDependentActivator.getConfigurationService() + .getString(SystrayService.PNMAE_TRAY_MODE, defaultTrayMode); + } + /** * Adds a TrayIcon to this system tray implementation. * diff --git a/src/net/java/sip/communicator/impl/osdependent/systemtray/appindicator/AppIndicatorTray.java b/src/net/java/sip/communicator/impl/osdependent/systemtray/appindicator/AppIndicatorTray.java index 3f4e267..90c949a 100644 --- a/src/net/java/sip/communicator/impl/osdependent/systemtray/appindicator/AppIndicatorTray.java +++ b/src/net/java/sip/communicator/impl/osdependent/systemtray/appindicator/AppIndicatorTray.java @@ -32,25 +32,11 @@ import net.java.sip.communicator.util.*; */ public class AppIndicatorTray extends SystemTray { - private static final String PNMAE_APPINDICATOR_DISABLED = - "net.java.sip.communicator.osdependent.systemtray.appindicator.DISABLED"; - private static final String PNMAE_APPINDICATOR_DYNAMIC_MENU = - "net.java.sip.communicator.osdependent.systemtray.appindicator.DYNAMIC_MENU"; + private boolean dynamicMenu; - public AppIndicatorTray() throws Exception + public AppIndicatorTray(boolean dynamicMenu) throws Exception { - boolean disable = OsDependentActivator.getConfigurationService() - .getBoolean(PNMAE_APPINDICATOR_DISABLED, false); - if (disable) - { - throw new Exception("AppIndicator is disabled"); - } - - if (!OSUtils.IS_LINUX) - { - throw new Exception("Not running Linux, AppIndicator1 is not available"); - } - + this.dynamicMenu = dynamicMenu; try { // pre-initialize the JNA libraries before attempting to use them @@ -74,7 +60,6 @@ public class AppIndicatorTray extends SystemTray @Override public TrayIcon createTrayIcon(ImageIcon icon, String tooltip, Object popup) { - return new AppIndicatorTrayIcon(icon, tooltip, (JPopupMenu) popup); } @@ -88,7 +73,6 @@ public class AppIndicatorTray extends SystemTray @Override public boolean supportsDynamicMenu() { - return OsDependentActivator.getConfigurationService() - .getBoolean(PNMAE_APPINDICATOR_DYNAMIC_MENU, true); + return dynamicMenu; } } diff --git a/src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigurationPanel.java b/src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigurationPanel.java index 6319455..04d55a5 100644 --- a/src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigurationPanel.java +++ b/src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigurationPanel.java @@ -98,6 +98,13 @@ public class GeneralConfigurationPanel = "net.java.sip.communicator.plugin.generalconfig.localeconfig.DISABLED"; + /** + * Indicates if the systray config panel should be disabled, i.e. not + * visible to the user. + */ + private static final String SYSTRAY_CONFIG_DISABLED_PROP = + "net.java.sip.communicator.plugin.generalconfig.systrayconfig.DISABLED"; + /** * Indicates if the Call configuration panel should be disabled, i.e. * not visible to the user. @@ -169,6 +176,13 @@ public class GeneralConfigurationPanel } if(!GeneralConfigPluginActivator.getConfigurationService() + .getBoolean(SYSTRAY_CONFIG_DISABLED_PROP, false)) + { + mainPanel.add(createSystrayeConfigPanel()); + mainPanel.add(Box.createVerticalStrut(10)); + } + + if(!GeneralConfigPluginActivator.getConfigurationService() .getBoolean(CALL_CONFIG_DISABLED_PROP, false)) { mainPanel.add(createCallConfigPanel()); @@ -251,7 +265,7 @@ public class GeneralConfigurationPanel { boolean value = ((JCheckBox) e.getSource()).isSelected(); ConfigurationUtils.setIsMinimizeInsteadOfHide(value); - UtilActivator.getUIService().setExitOnMainWindowClose( + UtilActivator.getUIService().setMainWindowCanHide( !UtilActivator.getSystrayService().checkInitialized()); } }); @@ -856,6 +870,72 @@ public class GeneralConfigurationPanel return localeConfigPanel; } + private static class Item + { + public String key; + public String value; + + public Item(String key, String value) + { + this.key = key; + this.value = value; + } + + @Override + public String toString() + { + return GeneralConfigPluginActivator.getResources() + .getI18NString(value); + } + } + + /** + * Initializes the systray configuration panel. + * @return the created component + */ + private Component createSystrayeConfigPanel() + { + JPanel panel = GeneralConfigPluginActivator. + createConfigSectionComponent( + Resources.getString("service.systray.MODE")); + + final JComboBox systrayModes = new JComboBox<>(); + SystrayService ss = GeneralConfigPluginActivator.getSystrayService(); + for (Map.Entry mode : ss.getSystrayModes().entrySet()) + { + Item i = new Item(mode.getKey(), mode.getValue()); + systrayModes.addItem(i); + if (mode.getKey().equals(ss.getActiveSystrayMode())) + { + systrayModes.setSelectedItem(i); + } + } + + systrayModes.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + GeneralConfigPluginActivator.getConfigurationService() + .setProperty(SystrayService.PNMAE_TRAY_MODE, + ((Item) systrayModes.getSelectedItem()).key); + } + }); + + panel.add(systrayModes); + String label = "* " + + Resources.getString("service.systray.CLI_NOTE", new String[]{ + Resources.getSettingsString("service.gui.APPLICATION_NAME") + }) + ""; + JLabel warnLabel = new JLabel(label); + warnLabel.setToolTipText(label); + warnLabel.setForeground(Color.GRAY); + warnLabel.setFont(warnLabel.getFont().deriveFont(8)); + warnLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 8, 0)); + panel.add(warnLabel); + return panel; + } + /** * Creates the call configuration panel. * diff --git a/src/net/java/sip/communicator/service/gui/UIService.java b/src/net/java/sip/communicator/service/gui/UIService.java index 33219d8..48994d4 100644 --- a/src/net/java/sip/communicator/service/gui/UIService.java +++ b/src/net/java/sip/communicator/service/gui/UIService.java @@ -157,26 +157,14 @@ public interface UIService public void bringToFront(); /** - * Sets the exitOnClose property. When TRUE, the user could exit the - * application by simply closing the main application window (by clicking - * the X button or pressing Alt-F4). When set to FALSE the main application - * window will be only hidden. - * - * @param exitOnClose When TRUE, the user could exit the application by - * simply closing the main application window (by clicking the X - * button or pressing Alt-F4). When set to FALSE the main - * application window will be only hidden. - */ - public void setExitOnMainWindowClose(boolean exitOnClose); - - /** - * Returns TRUE if the application could be exited by closing the main - * application window, otherwise returns FALSE. - * - * @return Returns TRUE if the application could be exited by closing the - * main application window, otherwise returns FALSE + * Called from the systray service when a tray has been initialized and + * hiding (instead of minimizing or exiting) is possible). If hiding is + * possible and the option to minimize is not selected, the application + * gets hidden on clicking 'X'. + * + * @param true if a tray icon was loaded. */ - public boolean getExitOnMainWindowClose(); + public void setMainWindowCanHide(boolean exitOnClose); /** * Returns an exported window given by the WindowID. This could be diff --git a/src/net/java/sip/communicator/service/systray/SystrayService.java b/src/net/java/sip/communicator/service/systray/SystrayService.java index bcde841..9d88852 100644 --- a/src/net/java/sip/communicator/service/systray/SystrayService.java +++ b/src/net/java/sip/communicator/service/systray/SystrayService.java @@ -17,6 +17,8 @@ */ package net.java.sip.communicator.service.systray; +import java.util.*; + import net.java.sip.communicator.service.systray.event.*; /** @@ -27,6 +29,9 @@ import net.java.sip.communicator.service.systray.event.*; */ public interface SystrayService { + public static final String PNMAE_TRAY_MODE = + "net.java.sip.communicator.osdependent.systemtray.MODE"; + /** * Message type corresponding to an error message. */ @@ -136,4 +141,19 @@ public interface SystrayService * @param count The number of pending notifications. */ public void setNotificationCount(int count); + + /** + * Gets a map of systray modes and resource-keys that describe them. + * @return key: mode for config property, value: resource key + */ + public Map getSystrayModes(); + + /** + * Gets the systray mode that was chosen at startup, either by default or as + * an override selected by the user. + * + * @return The selected mode or {@code disabled} if the user selected mode + * is not available. + */ + public String getActiveSystrayMode(); } diff --git a/src/net/java/sip/communicator/util/launchutils/LaunchArgHandler.java b/src/net/java/sip/communicator/util/launchutils/LaunchArgHandler.java index 90041fc..d5cbf14 100644 --- a/src/net/java/sip/communicator/util/launchutils/LaunchArgHandler.java +++ b/src/net/java/sip/communicator/util/launchutils/LaunchArgHandler.java @@ -299,6 +299,11 @@ public class LaunchArgHandler // do nothing already handled by startup script/binary continue; } + else if (args[i].startsWith("--notray")) + { + System.setProperty("disable-tray", "true"); + continue; + } //if this is the last arg and it's not an option then it's probably //an URI else if ( i == args.length - 1 @@ -521,6 +526,7 @@ public class LaunchArgHandler System.out.println(" -6, --ipv6 prefer IPv6 addresses where possible only"); System.out.println(" -4, --ipv4 forces use of IPv4 only"); System.out.println(" -v, --version display the current version and exit"); + System.out.println(" -n, --notray disable the tray icon and show the GUI"); } /** -- cgit v1.1