]> git.lyx.org Git - lyx.git/blob - src/Server.h
Avoid full metrics computation with Update:FitCursor
[lyx.git] / src / Server.h
1 // -*- C++ -*-
2 /**
3  * \file Server.h
4  * This file is part of LyX, the document processor.
5  * Licence details can be found in the file COPYING.
6  *
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author Enrico Forestieri
10  *
11  * Full author contact details are available in file CREDITS.
12  */
13
14 #ifndef SERVER_H
15 #define SERVER_H
16
17 #include <memory>
18 #include <string>
19 #include <vector>
20
21 #ifdef _WIN32
22 #include <windows.h>
23 #include <QObject>
24 #include <QEvent>
25 #endif
26
27
28 namespace lyx {
29
30 class Server;
31
32
33 /// A small utility to track the lifetime of an object.
34 class Trackable {
35 public:
36         Trackable() : p_(std::make_shared<int>(0)) {}
37         Trackable(Trackable const &) : Trackable() {}
38         Trackable(Trackable &&) : Trackable() {}
39         Trackable & operator=(Trackable const &) { return *this; }
40         Trackable & operator=(Trackable &&) { return *this; }
41         // This weak pointer lets you know if the parent object has been destroyed
42         std::weak_ptr<void> p() const { return p_; }
43 private:
44         std::shared_ptr<void> const p_;
45 };
46
47
48 /** This class manages the pipes used for communicating with clients.
49  Usage: Initialize with pipe-filename-base, client class to receive
50  messages, and callback-function that will be called with the messages.
51  When you want to send, use "send()".
52  This class encapsulates all the dirty communication and thus provides
53  a clean string interface.
54  */
55 #ifndef _WIN32
56 class LyXComm {
57 #else
58 class LyXComm : public QObject {
59         Q_OBJECT
60
61         friend DWORD WINAPI pipeServerWrapper(void *);
62
63 public:
64         /// Max number of clients
65         enum { MAX_CLIENTS = 10 };
66
67 private:
68         /// Max number of pipe instances
69         enum { MAX_PIPES = 2 * MAX_CLIENTS };
70
71         /// I/O buffer size
72         enum { PIPE_BUFSIZE = 512 };
73
74         /// Pipe client time-out
75         enum { PIPE_TIMEOUT = 5000 };
76
77         /// Pipe states
78         enum PipeState {
79                 CONNECTING_STATE,
80                 READING_STATE,
81                 WRITING_STATE
82         };
83
84         /// Pipe instances
85         typedef struct {
86                 OVERLAPPED overlap;
87                 HANDLE handle;
88                 std::string iobuf;
89                 char readbuf[PIPE_BUFSIZE];
90                 DWORD nbytes;
91                 PipeState state;
92                 bool pending_io;
93         } PipeInst;
94 #endif
95 public:
96         /** When we receive a message, we send it to a client.
97           This is one of the small things that would have been a lot
98           cleaner with a Signal/Slot thing.
99          */
100         typedef void (*ClientCallbackfct)(Server *, std::string const &);
101
102         /// Construct with pipe-basename and callback to receive messages
103         LyXComm(std::string const & pip, Server * cli, ClientCallbackfct ccb = 0);
104
105         ///
106         ~LyXComm() { closeConnection(); }
107
108         /// clean up in emergency
109         void emergencyCleanup();
110
111         /// Send message
112         void send(std::string const &);
113
114         /// asynch ready-to-be-read notification
115 #ifndef _WIN32
116         void read_ready();
117 #else
118         void read_ready(DWORD);
119 #endif
120
121         /// Tell whether we asked another instance of LyX to open the files
122         bool deferredLoading() const { return deferred_loading_; }
123
124 private:
125         /// the filename of the in pipe
126         std::string const inPipeName() const;
127
128         /// the filename of the out pipe
129         std::string const outPipeName() const;
130
131         /// Open pipes
132         void openConnection();
133
134         /// Close pipes
135         void closeConnection();
136
137         /// Load files in another running instance of LyX
138         bool loadFilesInOtherInstance() const;
139
140 #ifndef _WIN32
141         /// start a pipe
142         int startPipe(std::string const &, bool);
143
144         /// finish a pipe
145         void endPipe(int &, std::string const &, bool);
146
147         /// This is -1 if not open
148         int infd_;
149
150         /// This is -1 if not open
151         int outfd_;
152 #else
153         /// The pipe server returns false when exiting due to an error
154         bool pipeServer();
155
156         /// Start an overlapped connection
157         bool startPipe(DWORD);
158
159         /// Reset an overlapped connection
160         bool resetPipe(DWORD, bool close_handle = false);
161
162         /// Close event and pipe handles
163         void closeHandles();
164
165         /// Catch pipe ready-to-be-read notification
166         bool event(QEvent *);
167
168         /// Check whether the pipe server must be stopped
169         bool checkStopServer(DWORD timeout = 0);
170
171         /// The filename of a (in or out) pipe instance
172         std::string const pipeName(DWORD) const;
173
174         /// Pipe instances
175         PipeInst pipe_[MAX_PIPES];
176
177         /// Pipe server control events
178         HANDLE event_[MAX_PIPES + 1];
179
180         /// Reply buffer
181         std::string outbuf_;
182
183         /// Synchronize access to outbuf_
184         HANDLE outbuf_mutex_;
185
186         /// Windows event for stopping the pipe server
187         HANDLE stopserver_;
188
189         /// Pipe server thread handle
190         HANDLE server_thread_;
191 #endif
192
193         /// Are we up and running?
194         bool ready_;
195
196         /// Base of pipename including path
197         std::string pipename_;
198
199         /// The client
200         Server * client_;
201
202         /// The client callback function
203         ClientCallbackfct clientcb_;
204
205         /// Did we defer loading of files to another instance?
206         bool deferred_loading_;
207
208         /// Track object's liveness
209         Trackable tracker_;
210 };
211
212
213 ///
214 class Server {
215 public:
216         // FIXME IN 0.13
217         // Hack! This should be changed in 0.13
218
219         // IMO lyxserver is atypical, and for the moment the only one, non-gui
220         // bufferview. We just have to find a way to handle situations like if
221         // lyxserver is using a buffer that is being edited with a bufferview.
222         // With a common buffer list this is not a problem, maybe. (Alejandro)
223         ///
224         Server(std::string const & pipes);
225         ///
226         ~Server();
227         ///
228         void notifyClient(std::string const &);
229         ///
230         bool deferredLoadingToOtherInstance() const { return pipes_.deferredLoading(); }
231
232         /// whilst crashing etc.
233         void emergencyCleanup() { pipes_.emergencyCleanup(); }
234         ///
235         void callback(std::string const & msg);
236
237 private:
238         /// Names and number of current clients
239 #ifndef _WIN32
240         enum { MAX_CLIENTS = 10 };
241 #else
242         enum { MAX_CLIENTS = LyXComm::MAX_CLIENTS };
243 #endif
244         ///
245         std::string clients_[MAX_CLIENTS];
246         ///
247         int numclients_;
248         ///
249         LyXComm pipes_;
250 };
251
252 /// Implementation is in LyX.cpp
253 Server & theServer();
254
255 /// Implementation is in LyX.cpp
256 extern std::vector<std::string> & theFilesToLoad();
257
258
259 } // namespace lyx
260
261 #endif // SERVER_H