From 046b8ff337f9d3e7ea311db26c65d64a3e483efa Mon Sep 17 00:00:00 2001 From: Emil Ivov Date: Sat, 6 Sep 2008 12:12:13 +0000 Subject: [PATCH] Trying to launch a second instance of SIP Communicator now brings the first one to front Clicking on the systray icon when SC is minimized, now restores it also, when SC is on another desktop the systray click now takes you to that desktop --- .../argdelegation/ArgDelegationActivator.java | 4 +- ...erImpl.java => ArgDelegationPeerImpl.java} | 22 ++++-- .../communicator/impl/gui/main/MainFrame.java | 1 + .../systray/jdic/SystrayServiceJdicImpl.java | 76 +++++++++---------- .../launcher/SIPCommunicator.java | 4 +- ...gationPeer.java => ArgDelegationPeer.java} | 11 ++- .../{UriArgManager.java => ArgDelegator.java} | 39 +++++++--- .../util/launchutils/LaunchArgHandler.java | 51 +++++++++---- .../util/launchutils/SipCommunicatorLock.java | 3 +- 9 files changed, 136 insertions(+), 75 deletions(-) rename src/net/java/sip/communicator/impl/argdelegation/{UriDelegationPeerImpl.java => ArgDelegationPeerImpl.java} (89%) rename src/net/java/sip/communicator/util/launchutils/{UriDelegationPeer.java => ArgDelegationPeer.java} (63%) rename src/net/java/sip/communicator/util/launchutils/{UriArgManager.java => ArgDelegator.java} (60%) diff --git a/src/net/java/sip/communicator/impl/argdelegation/ArgDelegationActivator.java b/src/net/java/sip/communicator/impl/argdelegation/ArgDelegationActivator.java index 99ed0e389..3b0bc88b3 100644 --- a/src/net/java/sip/communicator/impl/argdelegation/ArgDelegationActivator.java +++ b/src/net/java/sip/communicator/impl/argdelegation/ArgDelegationActivator.java @@ -31,7 +31,7 @@ public class ArgDelegationActivator * A reference to the delegation peer implementation that is currently * handling uri arguments. */ - private UriDelegationPeerImpl delegationPeer = null; + private ArgDelegationPeerImpl delegationPeer = null; /** * A reference to the UIService currently in use in @@ -49,7 +49,7 @@ public class ArgDelegationActivator public void start(BundleContext bc) throws Exception { bundleContext = bc; - delegationPeer = new UriDelegationPeerImpl(bc); + delegationPeer = new ArgDelegationPeerImpl(bc); bc.addServiceListener(delegationPeer); //register our instance of delegation peer. diff --git a/src/net/java/sip/communicator/impl/argdelegation/UriDelegationPeerImpl.java b/src/net/java/sip/communicator/impl/argdelegation/ArgDelegationPeerImpl.java similarity index 89% rename from src/net/java/sip/communicator/impl/argdelegation/UriDelegationPeerImpl.java rename to src/net/java/sip/communicator/impl/argdelegation/ArgDelegationPeerImpl.java index 9d58951a0..ad89d1b11 100644 --- a/src/net/java/sip/communicator/impl/argdelegation/UriDelegationPeerImpl.java +++ b/src/net/java/sip/communicator/impl/argdelegation/ArgDelegationPeerImpl.java @@ -24,11 +24,11 @@ * * @author Emil Ivov */ -public class UriDelegationPeerImpl - implements UriDelegationPeer, ServiceListener +public class ArgDelegationPeerImpl + implements ArgDelegationPeer, ServiceListener { private static final Logger logger = - Logger.getLogger(UriDelegationPeerImpl.class); + Logger.getLogger(ArgDelegationPeerImpl.class); /** * The list of uriHandlers that we are currently aware of. @@ -38,12 +38,12 @@ public class UriDelegationPeerImpl /** * Creates an instance of this peer and scans bundleContext for all - * existing UriHandlers + * existing UriHandler * * @param bundleContext a reference to a currently valid instance of a * bundle context. */ - public UriDelegationPeerImpl(BundleContext bundleContext) + public ArgDelegationPeerImpl(BundleContext bundleContext) { ServiceReference[] uriHandlerRefs = null; @@ -182,5 +182,17 @@ public void handleUri(String uriArg) } } + /** + * This method would simply bring the application on focus as it is called + * when the user has tried to launch a second instance of SIP Communicator + * while a first one was already running. Future implementations may also + * show an error/information message to the user notifying them that a + * second instance is not to be launched. + */ + public void handleConcurrentInvocationRequest() + { + ArgDelegationActivator.getUIService().setVisible(true); + } + } 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 862fa9a69..38c9e9a3a 100755 --- a/src/net/java/sip/communicator/impl/gui/main/MainFrame.java +++ b/src/net/java/sip/communicator/impl/gui/main/MainFrame.java @@ -1579,6 +1579,7 @@ public void run() { MainFrame.this.addNativePlugins(); MainFrame.super.setVisible(isVisible); + MainFrame.super.setExtendedState(MainFrame.NORMAL); MainFrame.super.toFront(); } else diff --git a/src/net/java/sip/communicator/impl/systray/jdic/SystrayServiceJdicImpl.java b/src/net/java/sip/communicator/impl/systray/jdic/SystrayServiceJdicImpl.java index 672f1ca28..a58a57115 100644 --- a/src/net/java/sip/communicator/impl/systray/jdic/SystrayServiceJdicImpl.java +++ b/src/net/java/sip/communicator/impl/systray/jdic/SystrayServiceJdicImpl.java @@ -72,9 +72,9 @@ public class SystrayServiceJdicImpl private int maxMessageNumber = 3; private SystrayMessage aggregatedMessage; - + /** - * Stores the system time, when the main window was restored the last time + * Stores the system time, when the main window was restored the last time */ private long setVisibleTime = 0; @@ -95,14 +95,14 @@ public class SystrayServiceJdicImpl private ImageIcon logoIconWhite; private ImageIcon envelopeIcon; private ImageIcon envelopeIconWhite; - + /** * The dock Icons used only in Mac version */ private URL dockIconOffline; private URL dockIconAway; private URL dockIconFFC; - + private boolean initialized = false; /** @@ -153,7 +153,7 @@ private void initSystray() logoIconFFC = Resources.getImage("trayIconWindowsFFC"); envelopeIcon = Resources.getImage("messageIconWindows"); } - // If we're running under MacOSX, we use a special black and + // If we're running under MacOSX, we use a special black and // white icons without background. else if (osName.startsWith("Mac OS X")) { @@ -173,19 +173,19 @@ else if (osName.startsWith("Mac OS X")) if (!osName.startsWith("Mac OS X")) { - // default to set offline , if any protocols become + // default to set offline , if any protocols become // online will set it to online currentIcon = logoIconOffline; } else currentIcon = logoIcon; - + trayIcon = new TrayIcon(currentIcon, Resources.getApplicationString("applicationName"), menu); trayIcon.setIconAutoSize(true); - + if (osName.startsWith("Mac OS X")) { // init dock Icons @@ -208,7 +208,7 @@ public void actionPerformed(ActionEvent e) if (isVisible) { setVisibleTime = currentTime; } - else if (currentTime < (setVisibleTime + doubleClickSpeed)) + else if (currentTime < (setVisibleTime + doubleClickSpeed)) { // Do nothing. the last restore is less than 2 seconds, so it is very // likely, that the user made a double click. prevent the main window @@ -227,7 +227,7 @@ else if (currentTime < (setVisibleTime + doubleClickSpeed)) } }); - // Change the MacOSX icon with the white one when the popup + // Change the MacOSX icon with the white one when the popup // menu appears if (osName.startsWith("Mac OS X")) { @@ -243,11 +243,11 @@ public void popupMenuWillBecomeVisible(PopupMenuEvent e) else { trayIcon.setIcon(logoIconWhite); - currentIcon = logoIconWhite; + currentIcon = logoIconWhite; } } - public void popupMenuWillBecomeInvisible(PopupMenuEvent e) + public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { if (currentIcon == envelopeIconWhite) { @@ -260,11 +260,11 @@ public void popupMenuWillBecomeInvisible(PopupMenuEvent e) currentIcon = logoIcon; } } - - public void popupMenuCanceled(PopupMenuEvent e) + + public void popupMenuCanceled(PopupMenuEvent e) { popupMenuWillBecomeInvisible(e); - } + } }); } @@ -297,8 +297,8 @@ public void actionPerformed(ActionEvent e) * Saves the last status for all accounts. This information is used * on logging. Each time user logs in he's logged with the same status * as he was the last time before closing the application. - * - * @param protocolProvider the protocol provider for which we save the + * + * @param protocolProvider the protocol provider for which we save the * last selected status * @param statusName the status name to save */ @@ -359,10 +359,10 @@ public void saveStatusInformation( * Implements the SystratService.showPopupMessage method. Shows * a pop up message, above the Systray icon, which has the given title, * message content and message type. - * + * * @param title the title of the message * @param messageContent the content text - * @param messageType the type of the message + * @param messageType the type of the message */ public void showPopupMessage( String title, String messageContent, @@ -370,7 +370,7 @@ public void showPopupMessage( String title, { if(!checkInitialized()) return; - + int trayMsgType = TrayIcon.NONE_MESSAGE_TYPE; if (messageType == SystrayService.ERROR_MESSAGE_TYPE) @@ -391,7 +391,7 @@ else if (messageType == SystrayService.WARNING_MESSAGE_TYPE) /** * Implements the SystrayService.addPopupMessageListener method. - * + * * @param listener the listener to add */ public void addPopupMessageListener(SystrayPopupMessageListener listener) @@ -404,7 +404,7 @@ public void addPopupMessageListener(SystrayPopupMessageListener listener) /** * Implements the SystrayService.removePopupMessageListener method. - * + * * @param listener the listener to remove */ public void removePopupMessageListener(SystrayPopupMessageListener listener) @@ -418,7 +418,7 @@ public void removePopupMessageListener(SystrayPopupMessageListener listener) /** * Notifies all interested listeners that a SystrayPopupMessageEvent * has occured. - * + * * @param sourceObject the source of this event */ private void firePopupMessageEvent(Object sourceObject) @@ -445,16 +445,16 @@ private void firePopupMessageEvent(Object sourceObject) /** * Sets a new Systray icon. - * + * * @param imageType the type of the image to set. */ public void setSystrayIcon(int imageType) { if(!checkInitialized()) return; - + String osName = System.getProperty("os.name"); - + ImageIcon toChangeSystrayIcon = null; if (imageType == SystrayService.SC_IMG_TYPE) @@ -500,13 +500,13 @@ else if (imageType == SystrayService.ENVELOPE_IMG_TYPE) toChangeSystrayIcon = envelopeIcon; } } - + if(toChangeSystrayIcon != null) { this.trayIcon.setIcon(toChangeSystrayIcon); this.currentIcon = toChangeSystrayIcon; } - + if (osName.startsWith("Mac OS X")) { URL toChangeDockIcon = null; @@ -522,7 +522,7 @@ else if (imageType == SystrayService.ENVELOPE_IMG_TYPE) case SystrayService.SC_IMG_FFC_TYPE : toChangeDockIcon = dockIconFFC; break; } - + try { if(toChangeDockIcon != null) @@ -538,7 +538,7 @@ else if (imageType == SystrayService.ENVELOPE_IMG_TYPE) } } } - + private boolean checkInitialized() { if(!initialized) @@ -549,7 +549,7 @@ private boolean checkInitialized() else return true; } - + /** * Shows the oldest message in the message queue and then removes it from * the queue. @@ -616,7 +616,7 @@ private class SystrayMessage * Creates an instance of SystrayMessage by specifying the * message title, the content of the message and the type of * the message. - * + * * @param title the title of the message * @param messageContent the content of the message * @param messageType the type of the message @@ -635,7 +635,7 @@ public SystrayMessage( String title, * message title, the content of the message, the type of * the message and the number of messages that this message has * aggregated. - * + * * @param messageContent the content of the message * @param aggregatedMessageNumber the number of messages that this * message has aggregated @@ -655,7 +655,7 @@ public SystrayMessage( String messageContent, /** * Returns the title of the message. - * + * * @return the title of the message */ public String getTitle() @@ -665,7 +665,7 @@ public String getTitle() /** * Returns the message content. - * + * * @return the message content */ public String getMessageContent() @@ -675,7 +675,7 @@ public String getMessageContent() /** * Returns the message type. - * + * * @return the message type */ public int getMessageType() @@ -685,7 +685,7 @@ public int getMessageType() /** * Returns the number of aggregated messages this message represents. - * + * * @return the number of aggregated messages this message represents. */ public int getAggregatedMessageNumber() @@ -696,7 +696,7 @@ public int getAggregatedMessageNumber() /** * Adds the given number of messages to the number of aggregated * messages contained in this message. - * + * * @param messageNumber the number of messages to add to the number of * aggregated messages contained in this message */ diff --git a/src/net/java/sip/communicator/launcher/SIPCommunicator.java b/src/net/java/sip/communicator/launcher/SIPCommunicator.java index e3d65fafc..5926aca41 100644 --- a/src/net/java/sip/communicator/launcher/SIPCommunicator.java +++ b/src/net/java/sip/communicator/launcher/SIPCommunicator.java @@ -81,10 +81,10 @@ else if (osName.startsWith("Windows")) System.exit(argHandler.getErrorCode()); } - //lock our config di so that we would only have a single instance of + //lock our config dir so that we would only have a single instance of //sip communicator, no matter how many times we start it (use mainly //for handling sip: uris after starting the application) - if ( argHandlerRes != LaunchArgHandler.ACTION_CONTINUE_MULTIINSTANCE ) + if ( argHandlerRes != LaunchArgHandler.ACTION_CONTINUE_LOCK_DISABLED ) { SipCommunicatorLock lock = new SipCommunicatorLock(); diff --git a/src/net/java/sip/communicator/util/launchutils/UriDelegationPeer.java b/src/net/java/sip/communicator/util/launchutils/ArgDelegationPeer.java similarity index 63% rename from src/net/java/sip/communicator/util/launchutils/UriDelegationPeer.java rename to src/net/java/sip/communicator/util/launchutils/ArgDelegationPeer.java index e19bc180b..7e9918744 100644 --- a/src/net/java/sip/communicator/util/launchutils/UriDelegationPeer.java +++ b/src/net/java/sip/communicator/util/launchutils/ArgDelegationPeer.java @@ -15,7 +15,7 @@ * * @author Emil Ivov */ -public interface UriDelegationPeer +public interface ArgDelegationPeer { /** * Handles uriArg in whatever way it finds fit. @@ -23,4 +23,13 @@ public interface UriDelegationPeer * @param uriArg the uri argument that this delegate has to handle. */ public void handleUri(String uriArg); + + /** + * Called when the user has tried to launch a second instance of + * SIP Communicator while a first one was already running. A typical + * implementation of this method would simply bring the application on + * focus but it may also show an error/information message to the user + * notifying them that a second instance is not to be launched. + */ + public void handleConcurrentInvocationRequest(); } diff --git a/src/net/java/sip/communicator/util/launchutils/UriArgManager.java b/src/net/java/sip/communicator/util/launchutils/ArgDelegator.java similarity index 60% rename from src/net/java/sip/communicator/util/launchutils/UriArgManager.java rename to src/net/java/sip/communicator/util/launchutils/ArgDelegator.java index 6c669fc39..931b92a85 100644 --- a/src/net/java/sip/communicator/util/launchutils/UriArgManager.java +++ b/src/net/java/sip/communicator/util/launchutils/ArgDelegator.java @@ -10,25 +10,26 @@ import net.java.sip.communicator.util.*; /** - * The UriArgManager implements an utility for handling URIs that have - * been passed as command line arguments. The class maintains a list of - * registered delegates that do the actual URI handling. The UriArgDelegator - * is previewed for use with SIP Communicator argdelegation service. It would - * therefore record all URIs until the corresponding DelegationPeer has been - * registered with the UriArgManager. + * The ArgDelegator implements an utility for handling args that have + * been passed as command line arguments but that need the OSGi environment + * and SIP Communicator to be fully loaded. The class maintains a list of + * registered delegates (ArgDelegationPeers) that do the actual arg + * handling. The ArgDelegator is previewed for use with the SIP + * Communicator argdelegation service. It would therefore record all args + * until the corresponding DelegationPeer has registered here. * * @author Emil Ivov */ -class UriArgManager +class ArgDelegator { - private static final Logger logger = Logger.getLogger(UriArgManager.class); + private static final Logger logger = Logger.getLogger(ArgDelegator.class); /** * The delegation peer that we pass arguments to. This peer is going to * get set only after Felix starts and all its services have been properly * loaded. */ - private UriDelegationPeer uriDelegationPeer = null; + private ArgDelegationPeer uriDelegationPeer = null; /** * We use this list to store arguments that we have been asked to handle @@ -64,7 +65,7 @@ protected void handleUri(String uriArg) * @param delegationPeer the delegation peer that we can use to deliver * command line URIs to. */ - public void setDelegationPeer(UriDelegationPeer delegationPeer) + public void setDelegationPeer(ArgDelegationPeer delegationPeer) { synchronized(recordedArgs) { @@ -81,4 +82,22 @@ public void setDelegationPeer(UriDelegationPeer delegationPeer) recordedArgs.clear(); } } + + /** + * Called when the user has tried to launch a second instance of + * SIP Communicator while a first one was already running. This method + * simply calls its peer method from the ArgDelegationPeer and + * does nothing if no peer is currently registered. + */ + public void handleConcurrentInvocationRequest() + { + synchronized(recordedArgs) + { + if(uriDelegationPeer != null) + { + uriDelegationPeer.handleConcurrentInvocationRequest(); + } + } + + } } diff --git a/src/net/java/sip/communicator/util/launchutils/LaunchArgHandler.java b/src/net/java/sip/communicator/util/launchutils/LaunchArgHandler.java index fe08c2ca6..22fbd758f 100644 --- a/src/net/java/sip/communicator/util/launchutils/LaunchArgHandler.java +++ b/src/net/java/sip/communicator/util/launchutils/LaunchArgHandler.java @@ -66,7 +66,7 @@ public class LaunchArgHandler * successfully parsed and one of them indicates that the user has requested * a multi instance launch. */ - public static final int ACTION_CONTINUE_MULTIINSTANCE = 3; + public static final int ACTION_CONTINUE_LOCK_DISABLED = 3; /** * The error code returned when we couldn't parse one of the options. @@ -112,7 +112,7 @@ public class LaunchArgHandler /** * A reference to the instance of the */ - private UriArgManager uriArgManager = new UriArgManager(); + private ArgDelegator argDelegator = new ArgDelegator(); /** * The singleton instance of this handler. @@ -205,7 +205,8 @@ else if (args[i].equals("-c")) //make sure we have at least one more argument left. if( i == args.length - 1) { - System.out.println("The \"-c\" option expects a directory parameter."); + System.out.println( + "The \"-c\" option expects a directory parameter."); returnAction = ACTION_ERROR; break; } @@ -214,7 +215,7 @@ else if (args[i].equals("-c")) } else if (args[i].equals("--multiple") || args[i].equals("-m")) { - handleMultipleArg(args[i]); + returnAction = ACTION_CONTINUE_LOCK_DISABLED; continue; } //if this is the last arg and it's not an option then it's probably @@ -245,7 +246,7 @@ else if ( i == args.length - 1 private void handleUri(String uri) { logger.trace("Handling uri "+ uri); - uriArgManager.handleUri(uri); + argDelegator.handleUri(uri); } /** @@ -256,15 +257,6 @@ private void handleDebugArg(String arg) System.out.println("Option " + arg + " is not yet implemented!"); } - /** - * Instructs SIP Communicator to allow for more than a single running - * instance. - */ - private void handleMultipleArg(String arg) - { - System.out.println("Option " + arg + " is not yet implemented!"); - } - /** * Instructs SIP Communicator to allow for more than a single running * instance. @@ -397,8 +389,35 @@ public int getErrorCode() * @param delegationPeer the delegationPeer that should handle URIs * or null if we'd like to unset a previously set peer. */ - public void setDelegationPeer(UriDelegationPeer delegationPeer) + public void setDelegationPeer(ArgDelegationPeer delegationPeer) + { + this.argDelegator.setDelegationPeer(delegationPeer); + } + + /** + * Called when the user has tried to launch a second instance of + * SIP Communicator while a first one was already running. This method + * only handles arguments that need to be handled by a running instance + * of SIP Communicator assuming that simple ones such as "--version" or + * "--help" have been handled by the calling instance. + * + * @param args the args that we need to handle. + */ + public void handleConcurrentInvocationRequestArgs(String[] args) { - this.uriArgManager.setDelegationPeer(delegationPeer); + //if the arg list is empty, then we simply notify SC of the request + //so that it could do stuff like showing the contact list for example. + if(args.length == 0) + { + this.argDelegator.handleConcurrentInvocationRequest(); + } + //if we 1 or more args then we only handle the last one as the only + //interinstance arg we currently know how to handle are URIs. Change + //this if we one day implement fun stuff like inter instance command + //execution. + else if(args.length >=1) + { + this.argDelegator.handleUri(args[args.length -1]); + } } } \ No newline at end of file diff --git a/src/net/java/sip/communicator/util/launchutils/SipCommunicatorLock.java b/src/net/java/sip/communicator/util/launchutils/SipCommunicatorLock.java index 51198e0fa..a56b622e6 100644 --- a/src/net/java/sip/communicator/util/launchutils/SipCommunicatorLock.java +++ b/src/net/java/sip/communicator/util/launchutils/SipCommunicatorLock.java @@ -769,7 +769,8 @@ else if (line.startsWith(ARGUMENT)) // now let's handle what we've got String[] args = new String[argsList.size()]; - LaunchArgHandler.getInstance().handleArgs( + LaunchArgHandler.getInstance() + .handleConcurrentInvocationRequestArgs( argsList.toArray(args)); } catch (IOException exc)