]> git.lyx.org Git - lyx.git/blobdiff - src/Server.cpp
Move all python shebangs from /usr/bin/env to python3.
[lyx.git] / src / Server.cpp
index 7f514f19b3c1c9ea4505e6df26f93c9db75bb76c..d4a2120b6ea5e3c0550b5348a59766971259898a 100644 (file)
@@ -34,7 +34,7 @@
           received LyX will inform the client that it's listening its
           messages, and 'bye' will inform that lyx is closing.
 
           received LyX will inform the client that it's listening its
           messages, and 'bye' will inform that lyx is closing.
 
-          See development/server_monitor.c for an example client.
+          See development/lyxserver/server_monitor.cpp for an example client.
   Purpose: implement a client/server lib for LyX
 */
 
   Purpose: implement a client/server lib for LyX
 */
 
 
 #include "support/debug.h"
 #include "support/FileName.h"
 
 #include "support/debug.h"
 #include "support/FileName.h"
+#include "support/filetools.h"
 #include "support/lassert.h"
 #include "support/lstrings.h"
 #include "support/os.h"
 #include "support/lassert.h"
 #include "support/lstrings.h"
 #include "support/os.h"
+#include "support/signals.h"
 
 
-#include <boost/bind.hpp>
+#include <iostream>
 
 #ifdef _WIN32
 
 #ifdef _WIN32
+#include <io.h>
 #include <QCoreApplication>
 #endif
 #include <QCoreApplication>
 #endif
+#include <QThread>
 
 #include <cerrno>
 #ifdef HAVE_SYS_STAT_H
 
 #include <cerrno>
 #ifdef HAVE_SYS_STAT_H
@@ -113,7 +117,7 @@ string errormsg(DWORD const error)
        return message;
 }
 
        return message;
 }
 
-} // namespace anon
+} // namespace
 
 
 DWORD WINAPI pipeServerWrapper(void * arg)
 
 
 DWORD WINAPI pipeServerWrapper(void * arg)
@@ -133,13 +137,14 @@ DWORD WINAPI pipeServerWrapper(void * arg)
 
 
 LyXComm::LyXComm(string const & pip, Server * cli, ClientCallbackfct ccb)
 
 
 LyXComm::LyXComm(string const & pip, Server * cli, ClientCallbackfct ccb)
-       : pipename_(pip), client_(cli), clientcb_(ccb), stopserver_(0)
+       : stopserver_(0),
+         ready_(false), pipename_(pip), client_(cli), clientcb_(ccb),
+         deferred_loading_(false)
 {
        for (int i = 0; i < MAX_PIPES; ++i) {
                event_[i] = 0;
                pipe_[i].handle = INVALID_HANDLE_VALUE;
        }
 {
        for (int i = 0; i < MAX_PIPES; ++i) {
                event_[i] = 0;
                pipe_[i].handle = INVALID_HANDLE_VALUE;
        }
-       ready_ = false;
        openConnection();
 }
 
        openConnection();
 }
 
@@ -194,8 +199,8 @@ bool LyXComm::pipeServer()
        LYXERR(Debug::LYXSERVER, "LyXComm: Connection established");
        ready_ = true;
        outbuf_.erase();
        LYXERR(Debug::LYXSERVER, "LyXComm: Connection established");
        ready_ = true;
        outbuf_.erase();
-       DWORD status;
-       bool success;
+       DWORD status = 0;
+       bool success = false;
 
        while (!checkStopServer()) {
                // Indefinitely wait for the completion of an overlapped
 
        while (!checkStopServer()) {
                // Indefinitely wait for the completion of an overlapped
@@ -205,7 +210,7 @@ bool LyXComm::pipeServer()
 
                // Determine which pipe instance completed the operation.
                i = wait - WAIT_OBJECT_0;
 
                // Determine which pipe instance completed the operation.
                i = wait - WAIT_OBJECT_0;
-               LASSERT(i >= 0 && i <= MAX_PIPES, /**/);
+               LASSERT(i <= MAX_PIPES, /**/);
 
                // Check whether we were waked up for stopping the pipe server.
                if (i == MAX_PIPES)
 
                // Check whether we were waked up for stopping the pipe server.
                if (i == MAX_PIPES)
@@ -351,7 +356,7 @@ bool LyXComm::pipeServer()
 
                        error = GetLastError();
 
 
                        error = GetLastError();
 
-                       if (success && error == ERROR_IO_PENDING) {
+                       if (success && (error == ERROR_IO_PENDING || error == NO_ERROR)) {
                                // The write operation is still pending.
                                // We get here when a reader is started
                                // well before a reply is ready, so delay
                                // The write operation is still pending.
                                // We get here when a reader is started
                                // well before a reply is ready, so delay
@@ -515,8 +520,14 @@ void LyXComm::openConnection()
                return;
        }
 
                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)) {
        if (!stopserver_ && WaitNamedPipe(inPipeName().c_str(), 0)) {
+               // Tell the running instance to load the files
+               if (run_mode == USE_REMOTE && loadFilesInOtherInstance()) {
+                       deferred_loading_ = true;
+                       pipename_.erase();
+                       return;
+               }
                lyxerr << "LyXComm: Pipe " << external_path(inPipeName())
                       << " already exists.\nMaybe another instance of LyX"
                          " is using it." << endl;
                lyxerr << "LyXComm: Pipe " << external_path(inPipeName())
                       << " already exists.\nMaybe another instance of LyX"
                          " is using it." << endl;
@@ -685,6 +696,7 @@ string const LyXComm::pipeName(DWORD index) const
 LyXComm::LyXComm(string const &, Server *, ClientCallbackfct)
 {}
 
 LyXComm::LyXComm(string const &, Server *, ClientCallbackfct)
 {}
 
+
 void LyXComm::openConnection()
 {}
 
 void LyXComm::openConnection()
 {}
 
@@ -706,6 +718,7 @@ void LyXComm::endPipe(int & fd, string const & filename, bool write)
 void LyXComm::emergencyCleanup()
 {}
 
 void LyXComm::emergencyCleanup()
 {}
 
+
 void LyXComm::read_ready()
 {}
 
 void LyXComm::read_ready()
 {}
 
@@ -716,11 +729,11 @@ void LyXComm::send(string const & msg)
 
 #else // defined (HAVE_MKFIFO)
 
 
 #else // defined (HAVE_MKFIFO)
 
-
 LyXComm::LyXComm(string const & pip, Server * cli, ClientCallbackfct ccb)
 LyXComm::LyXComm(string const & pip, Server * cli, ClientCallbackfct ccb)
-       : pipename_(pip), client_(cli), clientcb_(ccb)
+       : infd_(-1), outfd_(-1),
+         ready_(false), pipename_(pip), client_(cli), clientcb_(ccb),
+         deferred_loading_(false)
 {
 {
-       ready_ = false;
        openConnection();
 }
 
        openConnection();
 }
 
@@ -798,6 +811,12 @@ int LyXComm::startPipe(string const & file, bool write)
                        if (fd >= 0) {
                                // Another LyX instance is using it.
                                ::close(fd);
                        if (fd >= 0) {
                                // Another LyX instance is using it.
                                ::close(fd);
+                               // Tell the running instance to load the files
+                               if (run_mode == USE_REMOTE && loadFilesInOtherInstance()) {
+                                       deferred_loading_ = true;
+                                       pipename_.erase();
+                                       return -1;
+                               }
                        } else if (errno == ENXIO) {
                                // No process is reading from the other end.
                                stalepipe = true;
                        } else if (errno == ENXIO) {
                                // No process is reading from the other end.
                                stalepipe = true;
@@ -839,8 +858,12 @@ int LyXComm::startPipe(string const & file, bool write)
        }
 
        if (!write) {
        }
 
        if (!write) {
-               theApp()->registerSocketCallback(fd,
-                       boost::bind(&LyXComm::read_ready, this));
+               // Make sure not to call read_ready after destruction.
+               weak_ptr<void> tracker = tracker_.p();
+               theApp()->registerSocketCallback(fd, [=](){
+                               if (!tracker.expired())
+                                       read_ready();
+                       });
        }
 
        return fd;
        }
 
        return fd;
@@ -860,7 +883,7 @@ void LyXComm::endPipe(int & fd, string const & filename, bool write)
                       << '\n' << strerror(errno) << endl;
        }
 
                       << '\n' << strerror(errno) << endl;
        }
 
-       if (FileName(filename).removeFile() < 0) {
+       if (!FileName(filename).removeFile()) {
                lyxerr << "LyXComm: Could not remove pipe " << filename
                       << '\n' << strerror(errno) << endl;
        }
                lyxerr << "LyXComm: Could not remove pipe " << filename
                       << '\n' << strerror(errno) << endl;
        }
@@ -898,7 +921,6 @@ void LyXComm::read_ready()
        int status;
        // the single = is intended here.
        while ((status = ::read(infd_, charbuf, charbuf_size - 1))) {
        int status;
        // the single = is intended here.
        while ((status = ::read(infd_, charbuf, charbuf_size - 1))) {
-
                if (status > 0) {
                        charbuf[status] = '\0'; // turn it into a c string
                        read_buffer_ += rtrim(charbuf, "\r");
                if (status > 0) {
                        charbuf[status] = '\0'; // turn it into a c string
                        read_buffer_ += rtrim(charbuf, "\r");
@@ -949,7 +971,8 @@ void LyXComm::send(string const & msg)
 
        LYXERR(Debug::LYXSERVER, "LyXComm: Sending '" << msg << '\'');
 
 
        LYXERR(Debug::LYXSERVER, "LyXComm: Sending '" << msg << '\'');
 
-       if (pipename_.empty()) return;
+       if (pipename_.empty())
+               return;
 
        if (!ready_) {
                LYXERR0("LyXComm: Pipes are closed. Could not send " << msg);
 
        if (!ready_) {
                LYXERR0("LyXComm: Pipes are closed. Could not send " << msg);
@@ -964,6 +987,49 @@ void LyXComm::send(string const & msg)
 
 #endif // defined (HAVE_MKFIFO)
 
 
 #endif // defined (HAVE_MKFIFO)
 
+namespace {
+
+struct Sleep : QThread
+{
+       static void millisec(unsigned long ms)
+       {
+               QThread::usleep(ms * 1000);
+       }
+};
+
+} // namespace
+
+
+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';
+               if (::write(pipefd, cmd.c_str(), cmd.length()) < 0)
+                       LYXERR0("Cannot write to pipe!");
+               ::close(pipefd);
+               ++loaded_files;
+               it = theFilesToLoad().erase(it);
+       }
+       return loaded_files > 0;
+}
+
 
 string const LyXComm::inPipeName() const
 {
 
 string const LyXComm::inPipeName() const
 {
@@ -1008,7 +1074,6 @@ Server::~Server()
 
 int compare(char const * a, char const * b, unsigned int len)
 {
 
 int compare(char const * a, char const * b, unsigned int len)
 {
-       using namespace std;
        return strncmp(a, b, len);
 }
 
        return strncmp(a, b, len);
 }
 
@@ -1097,7 +1162,7 @@ void Server::callback(string const & msg)
                                                << client << " said goodbye");
                                } else {
                                        LYXERR(Debug::LYXSERVER,
                                                << client << " said goodbye");
                                } else {
                                        LYXERR(Debug::LYXSERVER,
-                                               "Server: ignoring bye messge from unregistered client" << client);
+                                               "Server: ignoring bye message from unregistered client" << client);
                                }
                        } else {
                                LYXERR0("Server: Undefined server command " << cmd << '.');
                                }
                        } else {
                                LYXERR0("Server: Undefined server command " << cmd << '.');
@@ -1113,7 +1178,8 @@ void Server::callback(string const & msg)
                        // connect to the lyxfunc in the single GuiView we
                        // support currently. (Lgb)
 
                        // connect to the lyxfunc in the single GuiView we
                        // support currently. (Lgb)
 
-                       FuncRequest const fr(lyxaction.lookupFunc(cmd), arg);
+                       FuncRequest fr(lyxaction.lookupFunc(cmd), from_utf8(arg));
+                       fr.setOrigin(FuncRequest::LYXSERVER);
                        DispatchResult dr;
                        theApp()->dispatch(fr, dr);
                        string const rval = to_utf8(dr.message());
                        DispatchResult dr;
                        theApp()->dispatch(fr, dr);
                        string const rval = to_utf8(dr.message());