mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-12-13 09:15:50 +00:00
6ffeab01b7
In order to enable the server, specify the LyXServer pipe in Tools->Preferences->Paths. The path to be entered there must have the form "\\.\pipe\nameofyourchoice" (without quotes). After that, you can send commands to LyX. For example, if the pipe path is \\.\pipe\lyxpipe, typing the following in a terminal: echo LYXCMD:test:file-open > \\.\pipe\lyxpipe.in type \\.\pipe\lyxpipe.out brings up the file dialog and returns the acknowledgment from LyX. Beware of spaces when using cmd.exe. For example, the following: echo LYXCMD:test:file-open:foo.lyx> \\.\pipe\lyxpipe.in will correctly load the document named foo.lyx, but echo LYXCMD:test:file-open:foo.lyx > \\.\pipe\lyxpipe.in (notice the space before the redirection) will try to load a document whose name is "foo.lyx .lyx" because cmd.exe will also pass the space (sigh). git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/branches/BRANCH_1_6_X@31389 a592a061-630c-0410-9148-cb99ea01b6c8
234 lines
4.8 KiB
C++
234 lines
4.8 KiB
C++
// -*- C++ -*-
|
|
/**
|
|
* \file Server.h
|
|
* This file is part of LyX, the document processor.
|
|
* Licence details can be found in the file COPYING.
|
|
*
|
|
* \author Lars Gullik Bjønnes
|
|
* \author Jean-Marc Lasgouttes
|
|
* \author Enrico Forestieri
|
|
*
|
|
* Full author contact details are available in file CREDITS.
|
|
*/
|
|
|
|
#ifndef SERVER_H
|
|
#define SERVER_H
|
|
|
|
#include <boost/signals/trackable.hpp>
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#include <QObject>
|
|
#include <QEvent>
|
|
#endif
|
|
|
|
|
|
namespace lyx {
|
|
|
|
class LyXFunc;
|
|
class Server;
|
|
|
|
|
|
/** This class managed the pipes used for communicating with clients.
|
|
Usage: Initialize with pipe-filename-base, client class to receive
|
|
messages, and callback-function that will be called with the messages.
|
|
When you want to send, use "send()".
|
|
This class encapsulates all the dirty communication and thus provides
|
|
a clean string interface.
|
|
*/
|
|
#ifndef _WIN32
|
|
class LyXComm : public boost::signals::trackable {
|
|
#else
|
|
class LyXComm : public QObject {
|
|
Q_OBJECT
|
|
|
|
friend DWORD WINAPI pipeServerWrapper(void *);
|
|
|
|
public:
|
|
/// Max number of clients
|
|
enum { MAX_CLIENTS = 10 };
|
|
|
|
private:
|
|
/// Max number of pipe instances
|
|
enum { MAX_PIPES = 2 * MAX_CLIENTS };
|
|
|
|
/// I/O buffer size
|
|
enum { PIPE_BUFSIZE = 512 };
|
|
|
|
/// Pipe client time-out
|
|
enum { PIPE_TIMEOUT = 5000 };
|
|
|
|
/// Pipe states
|
|
enum PipeState {
|
|
CONNECTING_STATE,
|
|
READING_STATE,
|
|
WRITING_STATE
|
|
};
|
|
|
|
/// Pipe instances
|
|
typedef struct {
|
|
OVERLAPPED overlap;
|
|
HANDLE handle;
|
|
std::string iobuf;
|
|
char readbuf[PIPE_BUFSIZE];
|
|
DWORD nbytes;
|
|
PipeState state;
|
|
bool pending_io;
|
|
} PipeInst;
|
|
#endif
|
|
public:
|
|
/** When we receive a message, we send it to a client.
|
|
This is one of the small things that would have been a lot
|
|
cleaner with a Signal/Slot thing.
|
|
*/
|
|
typedef void (*ClientCallbackfct)(Server *, std::string const &);
|
|
|
|
/// Construct with pipe-basename and callback to receive messages
|
|
LyXComm(std::string const & pip, Server * cli, ClientCallbackfct ccb = 0);
|
|
|
|
///
|
|
~LyXComm() { closeConnection(); }
|
|
|
|
/// clean up in emergency
|
|
void emergencyCleanup();
|
|
|
|
/// Send message
|
|
void send(std::string const &);
|
|
|
|
/// asynch ready-to-be-read notification
|
|
#ifndef _WIN32
|
|
void read_ready();
|
|
#else
|
|
void read_ready(DWORD);
|
|
#endif
|
|
|
|
private:
|
|
/// the filename of the in pipe
|
|
std::string const inPipeName() const;
|
|
|
|
/// the filename of the out pipe
|
|
std::string const outPipeName() const;
|
|
|
|
/// Open pipes
|
|
void openConnection();
|
|
|
|
/// Close pipes
|
|
void closeConnection();
|
|
|
|
#ifndef _WIN32
|
|
/// start a pipe
|
|
int startPipe(std::string const &, bool);
|
|
|
|
/// finish a pipe
|
|
void endPipe(int &, std::string const &, bool);
|
|
|
|
/// This is -1 if not open
|
|
int infd_;
|
|
|
|
/// This is -1 if not open
|
|
int outfd_;
|
|
#else
|
|
/// The pipe server returns false when exiting due to an error
|
|
bool pipeServer();
|
|
|
|
/// Start an overlapped connection
|
|
bool startPipe(DWORD);
|
|
|
|
/// Reset an overlapped connection
|
|
bool resetPipe(DWORD, bool close_handle = false);
|
|
|
|
/// Close event and pipe handles
|
|
void closeHandles();
|
|
|
|
/// Catch pipe ready-to-be-read notification
|
|
bool event(QEvent *);
|
|
|
|
/// Check whether the pipe server must be stopped
|
|
bool checkStopServer(DWORD timeout = 0);
|
|
|
|
/// The filename of a (in or out) pipe instance
|
|
std::string const pipeName(DWORD) const;
|
|
|
|
/// Pipe instances
|
|
PipeInst pipe_[MAX_PIPES];
|
|
|
|
/// Pipe server control events
|
|
HANDLE event_[MAX_PIPES + 1];
|
|
|
|
/// Reply buffer
|
|
std::string outbuf_;
|
|
|
|
/// Synchronize access to outbuf_
|
|
HANDLE outbuf_mutex_;
|
|
|
|
/// Windows event for stopping the pipe server
|
|
HANDLE stopserver_;
|
|
|
|
/// Pipe server thread handle
|
|
HANDLE server_thread_;
|
|
#endif
|
|
|
|
/// Are we up and running?
|
|
bool ready_;
|
|
|
|
/// Base of pipename including path
|
|
std::string pipename_;
|
|
|
|
/// The client
|
|
Server * client_;
|
|
|
|
/// The client callback function
|
|
ClientCallbackfct clientcb_;
|
|
};
|
|
|
|
|
|
///
|
|
class Server {
|
|
public:
|
|
// FIXME IN 0.13
|
|
// Hack! This should be changed in 0.13
|
|
|
|
// The lyx server should not take an argument "LyXFunc" but this is
|
|
// how it will be done for 0.12. In 0.13 we must write a non-gui
|
|
// bufferview.
|
|
// IMO lyxserver is atypical, and for the moment the only one, non-gui
|
|
// bufferview. We just have to find a way to handle situations like if
|
|
// lyxserver is using a buffer that is being edited with a bufferview.
|
|
// With a common buffer list this is not a problem, maybe. (Alejandro)
|
|
///
|
|
Server(LyXFunc * f, std::string const & pip);
|
|
///
|
|
~Server();
|
|
///
|
|
void notifyClient(std::string const &);
|
|
|
|
/// whilst crashing etc.
|
|
void emergencyCleanup() { pipes_.emergencyCleanup(); }
|
|
///
|
|
void callback(std::string const & msg);
|
|
|
|
private:
|
|
/// Names and number of current clients
|
|
#ifndef _WIN32
|
|
enum { MAX_CLIENTS = 10 };
|
|
#else
|
|
enum { MAX_CLIENTS = LyXComm::MAX_CLIENTS };
|
|
#endif
|
|
///
|
|
std::string clients_[MAX_CLIENTS];
|
|
///
|
|
int numclients_;
|
|
///
|
|
LyXFunc * func_;
|
|
///
|
|
LyXComm pipes_;
|
|
};
|
|
|
|
/// Implementation is in LyX.cpp
|
|
extern Server & theServer();
|
|
|
|
|
|
} // namespace lyx
|
|
|
|
#endif // SERVER_H
|