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:
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
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
* library would be needed.
* When this is done, a server_mode could be created and the following two
* line would be moved out from here.
+ * However, note that the first of the two lines below triggers the
+ * "single instance" behavior, which should occur right at this point.
*/
// Note: socket callback must be registered after init(argc, argv)
// such that package().temp_dir() is properly initialized.
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();
" 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;
}
+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") {
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
}
+vector<string> & theFilesToLoad()
+{
+ LASSERT(singleton_, /**/);
+ return singleton_->pimpl_->files_to_load_;
+}
+
+
BufferList & theBufferList()
{
LASSERT(singleton_, /**/);
#include "support/strfwd.h"
+#include <vector>
+
namespace lyx {
class BufferList;
class Session;
class SpellChecker;
+enum RunMode {
+ NEW_INSTANCE,
+ USE_REMOTE,
+ PREFERRED
+};
+
enum OverwriteFiles {
NO_FILES,
MAIN_FILE,
};
extern bool use_gui;
+extern RunMode run_mode;
extern OverwriteFiles force_overwrite;
namespace frontend {
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();
{ "\\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 },
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;
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();
}
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) {
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:
RC_SET_COLOR,
RC_SHOW_BANNER,
RC_SINGLE_CLOSE_TAB_BUTTON,
+ RC_SINGLE_INSTANCE,
RC_SORT_LAYOUTS,
RC_SPELL_COMMAND,
RC_SPELLCHECK_CONTINUOUSLY,
///
bool single_close_tab_button;
///
+ bool single_instance;
+ ///
std::string forward_search_dvi;
///
std::string forward_search_pdf;
#include "support/debug.h"
#include "support/FileName.h"
+#include "support/filetools.h"
#include "support/lassert.h"
#include "support/lstrings.h"
#include "support/os.h"
#ifdef _WIN32
#include <QCoreApplication>
#endif
+#include <QThread>
#include <cerrno>
#ifdef HAVE_SYS_STAT_H
pipe_[i].handle = INVALID_HANDLE_VALUE;
}
ready_ = false;
+ deferred_loading_ = false;
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;
: pipename_(pip), client_(cli), clientcb_(ccb)
{
ready_ = false;
+ deferred_loading_ = false;
openConnection();
}
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;
#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
{
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;
/// 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);
/// The client callback function
ClientCallbackfct clientcb_;
+
+ /// Did we defer loading of files to another instance?
+ bool deferred_loading_;
};
~Server();
///
void notifyClient(std::string const &);
+ ///
+ bool deferredLoadingToOtherInstance() { return pipes_.deferredLoading(); }
/// whilst crashing etc.
void emergencyCleanup() { pipes_.emergencyCleanup(); }
/// Implementation is in LyX.cpp
Server & theServer();
+/// Implementation is in LyX.cpp
+extern std::vector<std::string> & theFilesToLoad();
+
} // namespace lyx
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
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;
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);
}
</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&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>