[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