Here is a complete patch with preferences and command line switches.

It is designed such that an already running instance is contacted only
when a document is to be loaded. So, if you export from command line,
things go as usual.

You can set a preference for the default behavior, but you can also
override the preference setting from the command line. So, I think
this is very flexible and should satisfy any taste.

Without any preference set or command line switch specified, the default
is to try to load documents in an already running instance, as I think
that this the most logical behavior. However, once you untick the
"Single instance" check box in the preferences, LyX behaves exactly as
before the introduction of this feature, such that you should only
experience the bugs that would have anyhow afflicted you.

So, can I commit?

-- 
Enrico
Index: src/LyXRC.h
===================================================================
--- src/LyXRC.h (revisione 36250)
+++ src/LyXRC.h (copia locale)
@@ -162,6 +162,7 @@ public:
                RC_SET_COLOR,
                RC_SHOW_BANNER,
                RC_SINGLE_CLOSE_TAB_BUTTON,
+               RC_SINGLE_INSTANCE,
                RC_SORT_LAYOUTS,
                RC_SPELL_COMMAND,
                RC_SPELLCHECK_CONTINUOUSLY,
@@ -502,6 +503,8 @@ public:
        ///
        bool single_close_tab_button;
        ///
+       bool single_instance;
+       ///
        std::string forward_search_dvi;
        ///
        std::string forward_search_pdf;
Index: src/LyX.cpp
===================================================================
--- src/LyX.cpp (revisione 36250)
+++ src/LyX.cpp (copia locale)
@@ -90,6 +90,13 @@ namespace os = support::os;
 bool use_gui = true;
 
 
+// We default to open documents in an already running instance, provided that
+// the lyxpipe has been setup. This can be overridden either on the command
+// line or through preference settings.
+
+RunMode run_mode = PREFERRED;
+
+
 // Tell what files can be silently overwritten during batch export.
 // Possible values are: NO_FILES, MAIN_FILE, ALL_FILES, UNSPECIFIED.
 // Unless specified on command line (through the -f switch) or through the
@@ -366,6 +373,11 @@ int LyX::exec(int & argc, char * argv[])
                return exit_status;
        }
 
+       // If not otherwise specified by a command line option or
+       // by preferences, we default to reuse a running instance.
+       if (run_mode == PREFERRED)
+               run_mode = USE_REMOTE;
+
        // FIXME
        /* Create a CoreApplication class that will provide the main event loop
        * and the socket callback registering. With Qt4, only QtCore
@@ -380,7 +392,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().deferredLoadingToOtherInstance())
+               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();
 
@@ -1040,8 +1060,13 @@ int parse_help(string const &, string co
                  "                  specifying whether all files, main file 
only, or no files,\n"
                  "                  respectively, are to be overwritten during 
a batch export.\n"
                  "                  Anything else is equivalent to `all', but 
is not consumed.\n"
-                 "\t-batch          execute commands without launching GUI and 
exit.\n"
-                 "\t-version        summarize version and build info\n"
+                 "\t-n [--no-remote]\n"
+                 "                  open documents in a new instance\n"
+                 "\t-r [--remote]\n"
+                 "                  open documents in an already running 
instance\n"
+                 "                  (a working lyxpipe is needed)\n"
+                 "\t-batch    execute commands without launching GUI and 
exit.\n"
+                 "\t-version  summarize version and build info\n"
                               "Check the LyX man page for more details.")) << 
endl;
        exit(0);
        return 0;
@@ -1142,6 +1167,20 @@ int parse_batch(string const &, string c
 }
 
 
+int parse_noremote(string const &, string const &, string &)
+{
+       run_mode = NEW_INSTANCE;
+       return 0;
+}
+
+
+int parse_remote(string const &, string const &, string &)
+{
+       run_mode = USE_REMOTE;
+       return 0;
+}
+
+
 int parse_force(string const & arg, string const &, string &)
 {
        if (arg == "all") {
@@ -1183,6 +1222,10 @@ void LyX::easyParse(int & argc, char * a
        cmdmap["-batch"] = parse_batch;
        cmdmap["-f"] = parse_force;
        cmdmap["--force-overwrite"] = parse_force;
+       cmdmap["-n"] = parse_noremote;
+       cmdmap["--no-remote"] = parse_noremote;
+       cmdmap["-r"] = parse_remote;
+       cmdmap["--remote"] = parse_remote;
 
        for (int i = 1; i < argc; ++i) {
                map<string, cmd_helper>::const_iterator it
@@ -1236,6 +1279,13 @@ void dispatch(FuncRequest const & action
 }
 
 
+vector<string> & theFilesToLoad()
+{
+       LASSERT(singleton_, /**/);
+       return singleton_->pimpl_->files_to_load_;
+}
+
+
 BufferList & theBufferList()
 {
        LASSERT(singleton_, /**/);
Index: src/frontends/qt4/GuiPrefs.cpp
===================================================================
--- src/frontends/qt4/GuiPrefs.cpp      (revisione 36250)
+++ src/frontends/qt4/GuiPrefs.cpp      (copia locale)
@@ -2358,6 +2358,8 @@ PrefUserInterface::PrefUserInterface(Gui
                TextLabel1, SLOT(setEnabled(bool)));
        connect(openDocumentsInTabsCB, SIGNAL(clicked()),
                this, SIGNAL(changed()));
+       connect(singleInstanceCB, SIGNAL(clicked()),
+               this, SIGNAL(changed()));
 #if QT_VERSION < 0x040500
        singleCloseTabButtonCB->setEnabled(false);
 #endif
@@ -2401,6 +2403,7 @@ void PrefUserInterface::apply(LyXRC & rc
        rc.num_lastfiles = lastfilesSB->value();
        rc.use_tooltip = tooltipCB->isChecked();
        rc.open_buffers_in_tabs = openDocumentsInTabsCB->isChecked();
+       rc.single_instance = singleInstanceCB->isChecked();
        rc.single_close_tab_button = singleCloseTabButtonCB->isChecked();
 #if QT_VERSION < 0x040500
        rc.single_close_tab_button = true;
@@ -2427,6 +2430,7 @@ void PrefUserInterface::update(LyXRC con
        lastfilesSB->setValue(rc.num_lastfiles);
        tooltipCB->setChecked(rc.use_tooltip);
        openDocumentsInTabsCB->setChecked(rc.open_buffers_in_tabs);
+       singleInstanceCB->setChecked(rc.single_instance);
        singleCloseTabButtonCB->setChecked(rc.single_close_tab_button);
 }
 
Index: src/frontends/qt4/ui/PrefUi.ui
===================================================================
--- src/frontends/qt4/ui/PrefUi.ui      (revisione 36250)
+++ src/frontends/qt4/ui/PrefUi.ui      (copia locale)
@@ -240,6 +240,16 @@
        </widget>
       </item>
       <item row="5" column="0" colspan="2">
+       <widget class="QCheckBox" name="singleInstanceCB">
+        <property name="toolTip">
+         <string>Whether to open documents in an already running instance of 
LyX.</string>
+        </property>
+        <property name="text">
+         <string>S&amp;ingle instance</string>
+        </property>
+       </widget>
+      </item>
+      <item row="6" column="0" colspan="2">
        <widget class="QCheckBox" name="singleCloseTabButtonCB">
         <property name="toolTip">
          <string>Whether to place close button on each tab or only one in the 
top left.</string>
Index: src/Server.cpp
===================================================================
--- src/Server.cpp      (revisione 36250)
+++ 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;
+       deferred_loading_ = 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 (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;
@@ -721,6 +730,7 @@ LyXComm::LyXComm(string const & pip, Ser
        : pipename_(pip), client_(cli), clientcb_(ccb)
 {
        ready_ = false;
+       deferred_loading_ = 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 (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;
@@ -964,6 +980,48 @@ 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/LyXRC.cpp
===================================================================
--- src/LyXRC.cpp       (revisione 36250)
+++ src/LyXRC.cpp       (copia locale)
@@ -179,6 +179,7 @@ LexerKeyword lyxrcTags[] = {
        { "\\set_color", LyXRC::RC_SET_COLOR },
        { "\\show_banner", LyXRC::RC_SHOW_BANNER },
        { "\\single_close_tab_button", LyXRC::RC_SINGLE_CLOSE_TAB_BUTTON },
+       { "\\single_instance", LyXRC::RC_SINGLE_INSTANCE },
        { "\\sort_layouts", LyXRC::RC_SORT_LAYOUTS },
        { "\\spell_command", LyXRC::RC_SPELL_COMMAND },
        { "\\spellcheck_continuously", LyXRC::RC_SPELLCHECK_CONTINUOUSLY },
@@ -341,6 +342,7 @@ void LyXRC::setDefaults()
        user_email = to_utf8(support::user_email());
        open_buffers_in_tabs = true;
        single_close_tab_button = false;
+       single_instance = true;
        forward_search_dvi = string();
        forward_search_pdf = string();
        export_overwrite = NO_FILES;
@@ -1185,6 +1187,11 @@ int LyXRC::read(Lexer & lexrc)
                case RC_SINGLE_CLOSE_TAB_BUTTON:
                        lexrc >> single_close_tab_button;
                        break;
+               case RC_SINGLE_INSTANCE:
+                       lexrc >> single_instance;
+                       if (run_mode == PREFERRED)
+                               run_mode = single_instance ? USE_REMOTE : 
NEW_INSTANCE;
+                       break;
                case RC_FORWARD_SEARCH_DVI:
                        if (lexrc.next(true)) 
                                forward_search_dvi = lexrc.getString();
@@ -1951,6 +1958,15 @@ void LyXRC::write(ostream & os, bool ign
                }
                if (tag != RC_LAST)
                        break;
+       case RC_SINGLE_INSTANCE:
+               if (ignore_system_lyxrc ||
+                   single_instance != system_lyxrc.single_instance) {
+                       os << "\\single_instance "
+                          << convert<string>(single_instance)
+                          << '\n';
+               }
+               if (tag != RC_LAST)
+                       break;
        case RC_FORWARD_SEARCH_DVI:
                if (ignore_system_lyxrc ||
                    forward_search_dvi != system_lyxrc.forward_search_dvi) {
@@ -2968,6 +2984,7 @@ void actOnUpdatedPrefs(LyXRC const & lyx
        case LyXRC::RC_USE_SPELL_LIB:
        case LyXRC::RC_VIEWDVI_PAPEROPTION:
        case LyXRC::RC_SINGLE_CLOSE_TAB_BUTTON:
+       case LyXRC::RC_SINGLE_INSTANCE:
        case LyXRC::RC_SORT_LAYOUTS:
        case LyXRC::RC_FULL_SCREEN_LIMIT:
        case LyXRC::RC_FULL_SCREEN_SCROLLBAR:
Index: src/Server.h
===================================================================
--- src/Server.h        (revisione 36250)
+++ 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 deferredLoading() { return deferred_loading_; }
+
 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 deferred_loading_;
 };
 
 
@@ -197,6 +206,8 @@ public:
        ~Server();
        ///
        void notifyClient(std::string const &);
+       ///
+       bool deferredLoadingToOtherInstance() { return 
pipes_.deferredLoading(); }
 
        /// 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 36250)
+++ src/LyX.h   (copia locale)
@@ -16,6 +16,8 @@
 
 #include "support/strfwd.h"
 
+#include <vector>
+
 namespace lyx {
 
 class BufferList;
@@ -34,6 +36,12 @@ class ServerSocket;
 class Session;
 class SpellChecker;
 
+enum RunMode {
+       NEW_INSTANCE,
+       USE_REMOTE,
+       PREFERRED
+};
+
 enum OverwriteFiles {
        NO_FILES,
        MAIN_FILE,
@@ -42,6 +50,7 @@ enum OverwriteFiles {
 };
 
 extern bool use_gui;
+extern RunMode run_mode;
 extern OverwriteFiles force_overwrite;
 
 namespace frontend {
@@ -126,6 +135,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();
Index: lyx.1in
===================================================================
--- lyx.1in     (revisione 36250)
+++ lyx.1in     (copia locale)
@@ -83,6 +83,15 @@ else other than "\fBall\fR", "\fBmain\fR
 if "\fBall\fR" was specified, but what follows is left on the command line for
 further processing.
 .TP
+\fB \-n [\-\-no\-remote]\fP
+open documents passed as arguments in a new instance, even if another
+instance of LyX is already running.
+.TP
+\fB \-r [\-\-remote]\fP
+by using the lyxpipe, ask an already running instance of LyX to open the
+documents passed as arguments and then exit. If the lyxpipe is not set up or
+is not working, a new instance is created and execution continues normally.
+.TP
 .BI -batch
 causes LyX to run the given commands without opening a GUI window.
 Thus, something like:

Reply via email to