[Date Prev][Date Next][Thread Prev][Thread Next][Thread Index]
[XaraXtreme-commits] Commit Complete
Commit by : alex
Repository : xara
Revision : 1589
Date : Fri Jul 28 21:53:49 BST 2006
Changed paths:
M /Trunk/XaraLX/wxOil/camelot.cpp
M /Trunk/XaraLX/wxOil/camelot.h
M /Trunk/XaraLX/wxOil/stdwx.h
Implemented wxSingleInstanceChecker so only one instance of camelot runs at a time.
THIS IS DELIBERATELY DISABLED ON DEBUG BUILDS (because it's annoying not to be able to run more than one instance)
Diff:
Index: Trunk/XaraLX/wxOil/camelot.h
===================================================================
--- Trunk/XaraLX/wxOil/camelot.h (revision 1588)
+++ Trunk/XaraLX/wxOil/camelot.h (revision 1589)
@@ -169,6 +169,12 @@
wxTimer m_Timer;
+ wxSingleInstanceChecker * m_pSingleInstanceChecker;
+ wxServerBase * m_pServer; // IPC server
+
+public:
+ BOOL OnSecondInstance(wxChar** argv, INT32 argc = 0);
+
private:
static BOOL LaunchBrowserApp(const wxString& strAppName, wxString strCommand);
Index: Trunk/XaraLX/wxOil/camelot.cpp
===================================================================
--- Trunk/XaraLX/wxOil/camelot.cpp (revision 1588)
+++ Trunk/XaraLX/wxOil/camelot.cpp (revision 1589)
@@ -381,11 +381,6 @@
return -1;
}
-/***************************************************************************************************************************/
-//
-// Initialisation.
-//
-
static bool GiveFocusToFocusableOffspring( wxWindow* pWnd )
{
TRACEUSER( "jlh92", _T("GF2FO class %s
"), pWnd->GetClassInfo()->GetClassName() );
@@ -413,30 +408,124 @@
return false;
}
+
+/***************************************************************************************************************************/
+//
+// Initialisation.
+//
+
+const wxString camIPC_START = _T("StartOther");
+
+class CamIPCConnection : public wxConnection
+{
+
+public:
+ CamIPCConnection() : wxConnection(m_pBuffer, WXSIZEOF(m_pBuffer)) {}
+
+ virtual bool OnExecute (const wxString& WXUNUSED(topic),
+ wxChar *data,
+ int /* TYPENOTE: Correct */ size,
+ wxIPCFormat WXUNUSED(format))
+ {
+ // argv buffer
+ INT32 argc = 0;
+
+ INT32 i;
+ for (i=0; i<size; i++)
+ {
+ // exit if this is a NULL, and the last character was a NULL
+ if (!data[i] && i && !data[i-1])
+ break;
+
+ if (!data[i])
+ argc++;
+ }
+
+ wxChar ** argv = new wxChar*[argc];
+
+ wxChar* p = data;
+ for (i=0; i<argc; i++)
+ {
+ argv[i] = camStrdup(p);
+ p+=wxStrlen(argv[i])+1; // move past null
+ }
+
+ BOOL result = wxGetApp().OnSecondInstance(argv, argc);
+
+ // free memory
+ for (i=0; i<argc; i++)
+ {
+ free(argv[i]);
+ }
+ delete [] argv;
+
+ // return
+ return result;
+ }
+
+private:
+ wxChar m_pBuffer[4096];
+
+};
+
+class CamIPCServer : public wxServer
+{
+public:
+ virtual wxConnectionBase *OnAcceptConnection (const wxString& topic)
+ {
+ if (topic != camIPC_START)
+ return NULL;
+ else
+ return new CamIPCConnection;
+ }
+};
+
+// Global so we can use it for parsing second instance
+static const wxCmdLineEntryDesc cmdLineDesc[] =
+{
+#if defined(_DEBUG)
+ { wxCMD_LINE_OPTION, _T("u"), _T("user"), _T("set username for debug tracing") },
+ { wxCMD_LINE_SWITCH, _T("m"), _T("memorycheck"), _T("check memory") },
+ { wxCMD_LINE_SWITCH, _T("x"), _T("xrccheckgen"), _T("generate xrc.check file") },
+ { wxCMD_LINE_OPTION, _T("l"), _T("listdebug"), _T("list debug level") , wxCMD_LINE_VAL_NUMBER },
+#endif
+ { wxCMD_LINE_SWITCH, _T("h"), _T("help"), _T("Display this help"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
+ { wxCMD_LINE_SWITCH, _T("v"), _T("version"), _T("Display the version information") },
+ { wxCMD_LINE_OPTION, _T("r"), _T("resource"), _T("resource directory") },
+ { wxCMD_LINE_PARAM, NULL, NULL, _T("input file"), wxCMD_LINE_VAL_STRING,
+ wxCMD_LINE_PARAM_OPTIONAL|wxCMD_LINE_PARAM_MULTIPLE },
+ { wxCMD_LINE_NONE }
+};
+
+BOOL CCamApp::OnSecondInstance(wxChar** argv, INT32 argc)
+{
+ // Parse command line. We do this early so we get flags which
+ // are useful for init, such as -u
+ //
+ wxCmdLineParser parser(argc,argv);
+ parser.SetDesc(cmdLineDesc);
+ if (parser.Parse()) // Handles help automatically
+ {
+ return FALSE;
+ }
+ if (parser.GetParamCount()>=1)
+ {
+ for ( UINT32 i=0 ; i<parser.GetParamCount() ; i++ )
+ m_docManager->CreateDocument(parser.GetParam(i),wxDOC_SILENT);
+ m_pMainFrame->Raise();
+ }
+ return TRUE;
+}
+
bool CCamApp::OnInit()
{
InInitOrDeInit = TRUE; // Don't allow the user to try carrying on working
::wxHandleFatalExceptions(TRUE);
+
//
// Parse command line. We do this early so we get flags which
// are useful for init, such as -u
//
- static const wxCmdLineEntryDesc cmdLineDesc[] =
- {
-
-#if defined(_DEBUG)
- { wxCMD_LINE_OPTION, _T("u"), _T("user"), _T("set username for debug tracing") },
- { wxCMD_LINE_SWITCH, _T("m"), _T("memorycheck"), _T("check memory") },
- { wxCMD_LINE_SWITCH, _T("x"), _T("xrccheckgen"), _T("generate xrc.check file") },
- { wxCMD_LINE_OPTION, _T("l"), _T("listdebug"), _T("list debug level") , wxCMD_LINE_VAL_NUMBER },
-#endif
- { wxCMD_LINE_SWITCH, _T("h"), _T("help"), _T("Display this help"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
- { wxCMD_LINE_SWITCH, _T("v"), _T("version"), _T("Display the version information") },
- { wxCMD_LINE_OPTION, _T("r"), _T("resource"), _T("resource directory") },
- { wxCMD_LINE_PARAM, NULL, NULL, _T("input file"), wxCMD_LINE_VAL_STRING,
- wxCMD_LINE_PARAM_OPTIONAL|wxCMD_LINE_PARAM_MULTIPLE },
- { wxCMD_LINE_NONE }
- };
wxCmdLineParser parser(argc,argv);
parser.SetDesc(cmdLineDesc);
if (parser.Parse()) // Handles help automatically
@@ -516,6 +605,100 @@
#endif
+ // OK, now we've handled the help case, and some VERY early init, we should see if another instance
+ // is running.
+
+ // Set and check for single instance running
+ wxString IPCname = wxString(_T("XARA-XTREME-WX-")) +GetAppName()+wxString::Format(_T("%s.ipc"), wxGetUserId().c_str());
+
+ m_pSingleInstanceChecker = NULL;
+ m_pServer = NULL;
+
+#ifdef _DEBUG
+ BOOL SingleInstanceCheck = FALSE;
+#else
+ BOOL SingleInstanceCheck = TRUE;
+#endif
+
+ if (SingleInstanceCheck)
+ {
+ // Create a single instance checker at that location
+ m_pSingleInstanceChecker = new wxSingleInstanceChecker(IPCname);
+ if (!m_pSingleInstanceChecker)
+ {
+ ERROR2(FALSE, "Failed to create single instance checker");
+ }
+
+ // Now see if another is running
+ if (m_pSingleInstanceChecker->IsAnotherRunning())
+ {
+ wxClient Client;
+ wxConnectionBase * Connection = Client.MakeConnection(wxEmptyString, IPCname, camIPC_START);
+
+ // If there is no connection, perhaps the other end is dead. We will start up anyway.
+ if (Connection)
+ {
+ INT32 len=1; // terminating null
+ INT32 i;
+
+ wxArrayString docs;
+ INT32 doccount = parser.GetParamCount()+1; // add one for the dummy
+
+ // Add all docs with a dummy argv[0]
+ for ( i=0 ; i<doccount; i++ )
+ {
+ wxString docname;
+ if (i)
+ {
+ docname = parser.GetParam(i-1);
+ wxFileName fn(docname);
+ fn.Normalize(wxPATH_NORM_ALL);
+ docname=fn.GetFullPath();
+ }
+ else
+ {
+ docname=argv[0];
+ }
+ len+=docname.length()+1; // include the trailing zero
+ docs.Add(docname);
+ }
+
+ wxChar * Data = new wxChar[len];
+ if (!Data)
+ {
+ ERROR2(FALSE, "Failed to create single instance checker data");
+ }
+
+ // Copy the
+ wxChar * p = Data;
+ for (i = 0; i < doccount; i++)
+ {
+ wxStrcpy(p, docs[i]);
+ p+=docs[i].length()+1; // move past string and terminating NULL
+ }
+ *p = _T('
+
+ // Now send the data over the connection
+ if (Connection->Execute (Data, len*sizeof(wxChar)))
+ {
+ delete [] Data;
+ delete Connection;
+
+ //.Free up the single instance checker
+ delete m_pSingleInstanceChecker;
+ m_pSingleInstanceChecker = NULL;
+
+ // We're out of here...
+ return FALSE;
+ }
+
+ // Hmmmm, it didn't want to execute it. perhaps the other process is stuck. We'll run anyway
+ delete [] Data;
+ delete Connection;
+ }
+ }
+ }
+
// Register the image handler which loads CURs (used for Cursors, obviously)
wxImage::AddHandler( new wxCURHandler );
@@ -808,6 +991,29 @@
CXMLUtils::Initialise();
+ if (SingleInstanceCheck)
+ {
+ // We are able to load documents, so now start our own IPC server
+ m_pServer = new CamIPCServer();
+ if (!m_pServer)
+ {
+ delete (m_pSingleInstanceChecker);
+ m_pSingleInstanceChecker = NULL;
+ ERROR2(FALSE, "Failed to create IPC server");
+ }
+
+ // and initialize it
+ if (!(m_pServer->Create(IPCname)))
+ {
+ delete m_pServer;
+ m_pServer = NULL;
+
+ delete (m_pSingleInstanceChecker);
+ m_pSingleInstanceChecker = NULL;
+ ERROR2(FALSE, "Failed to init IPC server");
+ }
+ }
+
// Give focus to any child that will take it, parent can't have it since
// it's a frame (see gtk_widget_grab_focus)
GiveFocusToFocusableOffspring( m_pMainFrame );
@@ -832,6 +1038,20 @@
// We can no longer stop the closedown, so flag this fact
Camelot.ShuttingDown(TRUE);
+ // we can't load documents any more - delete IPC server
+ if (m_pServer)
+ {
+ delete m_pServer;
+ m_pServer = NULL;
+ }
+
+ // delete single instance checked
+ if (m_pSingleInstanceChecker)
+ {
+ delete m_pSingleInstanceChecker;
+ m_pSingleInstanceChecker = NULL;
+ }
+
// Rendering is back on idle events for now as it actually works
// m_Timer.Stop();
@@ -961,6 +1181,7 @@
// Now close the main frame
m_pMainFrame->Close();
+
}
Index: Trunk/XaraLX/wxOil/stdwx.h
===================================================================
--- Trunk/XaraLX/wxOil/stdwx.h (revision 1588)
+++ Trunk/XaraLX/wxOil/stdwx.h (revision 1589)
@@ -124,8 +124,10 @@
#include <wx/hashmap.h>
#include <wx/image.h>
#include <wx/imagpng.h>
+#include <wx/ipc.h>
#include <wx/log.h>
#include <wx/rawbmp.h>
+#include <wx/snglinst.h>
#include <wx/splash.h>
#include <wx/stdpaths.h>
#include <wx/sysopt.h>
Xara