On Thu, Nov 11, 2010 at 04:59:01AM +0100, Enrico Forestieri wrote:
> On Thu, Nov 11, 2010 at 02:57:48AM +0100, Vincent van Ravesteijn wrote:
> > I'd like you to guide me a bit in with respect to using the pipes
> > then. Detecting whether a pipe exists is indeed easy. However, I need
> > to add some public functions to the Server interface that relays to
> > LyXComm. Moreover, sending a new command over the pipe to the existing
> > application needs some of the client code.. right ?
> > 
> > If you can share your thoughts with me, I'd appreciate it.
> 
> Please find attached a rough patch as proof of concept. It has to be
> improved in many respects, but already does the job. I tested it on
> both *nix and windows (with mingw) and it works for me. Simply setup
> the lyxpipe and when you run lyx with a filename as argument, it
> will be opened in already running instance.

Here is another somewhat polished version.

-- 
Enrico
Index: src/LyX.cpp
===================================================================
--- src/LyX.cpp (revisione 36244)
+++ src/LyX.cpp (copia locale)
@@ -380,7 +380,15 @@ int LyX::exec(int & argc, char * argv[])
                        FileName(package().temp_dir().absFileName() + 
"/lyxsocket")));
 
        // Start the real execution loop.
-       exit_status = pimpl_->application_->exec();
+       if (!theServer().isAlreadyRunning())
+               exit_status = pimpl_->application_->exec();
+       else if (!pimpl_->files_to_load_.empty()) {
+               vector<string>::const_iterator it = 
pimpl_->files_to_load_.begin();
+               vector<string>::const_iterator end = 
pimpl_->files_to_load_.end();
+               lyxerr << "The following files could not be loaded:" << endl;
+               for (; it != end; ++it)
+                       lyxerr << *it << endl;
+       }
 
        prepareExit();
 
@@ -1236,6 +1244,13 @@ void dispatch(FuncRequest const & action
 }
 
 
+vector<string> & theFilesToLoad()
+{
+       LASSERT(singleton_, /**/);
+       return singleton_->pimpl_->files_to_load_;
+}
+
+
 BufferList & theBufferList()
 {
        LASSERT(singleton_, /**/);
Index: src/Server.cpp
===================================================================
--- src/Server.cpp      (revisione 36244)
+++ src/Server.cpp      (copia locale)
@@ -51,6 +51,7 @@
 
 #include "support/debug.h"
 #include "support/FileName.h"
+#include "support/filetools.h"
 #include "support/lassert.h"
 #include "support/lstrings.h"
 #include "support/os.h"
@@ -60,6 +61,7 @@
 #ifdef _WIN32
 #include <QCoreApplication>
 #endif
+#include <QThread>
 
 #include <cerrno>
 #ifdef HAVE_SYS_STAT_H
@@ -140,6 +142,7 @@ LyXComm::LyXComm(string const & pip, Ser
                pipe_[i].handle = INVALID_HANDLE_VALUE;
        }
        ready_ = false;
+       used_running_instance_ = false;
        openConnection();
 }
 
@@ -515,8 +518,14 @@ void LyXComm::openConnection()
                return;
        }
 
-       // Check whether the pipe name is being used by some other program.
+       // Check whether the pipe name is being used by some other instance.
        if (!stopserver_ && WaitNamedPipe(inPipeName().c_str(), 0)) {
+               // Tell the running instance to load the files
+               if (loadFilesInOtherInstance()) {
+                       used_running_instance_ = true;
+                       pipename_.erase();
+                       return;
+               }
                lyxerr << "LyXComm: Pipe " << external_path(inPipeName())
                       << " already exists.\nMaybe another instance of LyX"
                          " is using it." << endl;
@@ -721,6 +730,7 @@ LyXComm::LyXComm(string const & pip, Ser
        : pipename_(pip), client_(cli), clientcb_(ccb)
 {
        ready_ = false;
+       used_running_instance_ = false;
        openConnection();
 }
 
@@ -798,6 +808,12 @@ int LyXComm::startPipe(string const & fi
                        if (fd >= 0) {
                                // Another LyX instance is using it.
                                ::close(fd);
+                               // Tell the running instance to load the files
+                               if (loadFilesInOtherInstance()) {
+                                       used_running_instance_ = true;
+                                       pipename_.erase();
+                                       return -1;
+                               }
                        } else if (errno == ENXIO) {
                                // No process is reading from the other end.
                                stalepipe = true;
@@ -964,6 +980,47 @@ void LyXComm::send(string const & msg)
 
 #endif // defined (HAVE_MKFIFO)
 
+namespace {
+
+struct Sleep : QThread {
+       static void millisec(unsigned long ms)
+       {
+               QThread::usleep(ms * 1000);
+       }
+};
+
+} // namespace anon
+
+
+bool LyXComm::loadFilesInOtherInstance()
+{
+       int pipefd;
+       int loaded_files = 0;
+       FileName const pipe(inPipeName());
+       vector<string>::iterator it = theFilesToLoad().begin();
+       while (it != theFilesToLoad().end()) {
+               FileName fname = fileSearch(string(), os::internal_path(*it),
+                                               "lyx", may_not_exist);
+               if (fname.empty()) {
+                       ++it;
+                       continue;
+               }
+               // Wait a while to allow time for the other
+               // instance to reset the connection
+               Sleep::millisec(200);
+               pipefd = ::open(pipe.toFilesystemEncoding().c_str(), O_WRONLY);
+               if (pipefd < 0)
+                       break;
+               string const cmd = "LYXCMD:pipe:file-open:" +
+                                       fname.absFileName() + '\n';
+               ::write(pipefd, cmd.c_str(), cmd.length());
+               ::close(pipefd);
+               ++loaded_files;
+               it = theFilesToLoad().erase(it);
+       }
+       return loaded_files > 0;
+}
+
 
 string const LyXComm::inPipeName() const
 {
Index: src/Server.h
===================================================================
--- src/Server.h        (revisione 36244)
+++ src/Server.h        (copia locale)
@@ -101,6 +101,9 @@ public:
        void read_ready(DWORD);
 #endif
 
+       /// Tell whether we asked another instance of LyX to open the files
+       bool deferredLoadingToOtherInstance() { return used_running_instance_; }
+
 private:
        /// the filename of the in pipe
        std::string const inPipeName() const;
@@ -114,6 +117,9 @@ private:
        /// Close pipes
        void closeConnection();
 
+       /// Load files in another running instance of LyX
+       bool loadFilesInOtherInstance();
+
 #ifndef _WIN32
        /// start a pipe
        int startPipe(std::string const &, bool);
@@ -178,6 +184,9 @@ private:
 
        /// The client callback function
        ClientCallbackfct clientcb_;
+
+       /// Did we defer loading of files to another instance?
+       bool used_running_instance_;
 };
 
 
@@ -197,6 +206,8 @@ public:
        ~Server();
        ///
        void notifyClient(std::string const &);
+       ///
+       bool isAlreadyRunning() { return 
pipes_.deferredLoadingToOtherInstance(); }
 
        /// whilst crashing etc.
        void emergencyCleanup() { pipes_.emergencyCleanup(); }
@@ -221,6 +232,9 @@ private:
 /// Implementation is in LyX.cpp
 Server & theServer();
 
+/// Implementation is in LyX.cpp
+extern std::vector<std::string> & theFilesToLoad();
+
 
 } // namespace lyx
 
Index: src/LyX.h
===================================================================
--- src/LyX.h   (revisione 36244)
+++ src/LyX.h   (copia locale)
@@ -16,6 +16,8 @@
 
 #include "support/strfwd.h"
 
+#include <vector>
+
 namespace lyx {
 
 class BufferList;
@@ -126,6 +128,7 @@ private:
        friend FuncStatus getStatus(FuncRequest const & action);
        friend void dispatch(FuncRequest const & action);
        friend void dispatch(FuncRequest const & action, DispatchResult & dr);
+       friend std::vector<std::string> & theFilesToLoad();
        friend BufferList & theBufferList();
        friend Server & theServer();
        friend ServerSocket & theServerSocket();

Reply via email to