argh
[synfig.git] / synfig-studio / trunk / src / gtkmm / ipc.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file ipc.cpp
3 **      \brief Template File
4 **
5 **      $Id: ipc.cpp,v 1.6 2005/01/16 19:55:57 darco Exp $
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **
10 **      This package is free software; you can redistribute it and/or
11 **      modify it under the terms of the GNU General Public License as
12 **      published by the Free Software Foundation; either version 2 of
13 **      the License, or (at your option) any later version.
14 **
15 **      This package is distributed in the hope that it will be useful,
16 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 **      General Public License for more details.
19 **      \endlegal
20 */
21 /* ========================================================================= */
22
23 /* === H E A D E R S ======================================================= */
24
25 #ifdef USING_PCH
26 #       include "pch.h"
27 #else
28 #ifdef HAVE_CONFIG_H
29 #       include <config.h>
30 #endif
31
32 #include "ipc.h"
33
34 #ifdef HAVE_SYS_TYPES_H
35 #include <sys/types.h>
36 #endif
37
38 #ifdef HAVE_SYS_STAT_H
39 #include <sys/stat.h>
40 #endif
41
42 #ifdef HAVE_SYS_ERRNO_H
43 #include <sys/errno.h>
44 #endif
45
46 #include <synfig/main.h>
47 #include "app.h"
48
49 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>
51 #endif
52
53 #ifdef HAVE_FCNTL_H
54 #include <fcntl.h>
55 #endif
56
57 #ifdef _WIN32
58 #include <windows.h>
59 #define BUFSIZE   128
60 #define read    _read
61 #endif
62
63 #include "toolbox.h"
64 #include <glibmm/dispatcher.h>
65 #include <synfig/mutex.h>
66 #include <synfig/string.h>
67 #include <glibmm/thread.h>
68
69 #endif
70
71 /* === U S I N G =========================================================== */
72
73 using namespace std;
74 using namespace etl;
75 using namespace synfig;
76 using namespace studio;
77
78 /* === M A C R O S ========================================================= */
79
80 /* === G L O B A L S ======================================================= */
81
82 #ifdef _WIN32
83 #define WIN32_PIPE_PATH "\\\\.\\pipe\\SynfigStudio.Cmd"
84 static synfig::Mutex cmd_mutex;
85 static std::list<synfig::String> cmd_queue;
86 static Glib::Dispatcher* cmd_dispatcher;
87 static void
88 pipe_listen_thread()
89 {
90         for(;;)
91         {
92                 HANDLE pipe_handle;
93                 pipe_handle=CreateNamedPipe(
94                         WIN32_PIPE_PATH, // pipe name
95                         PIPE_ACCESS_INBOUND, // Access type
96                         PIPE_READMODE_BYTE /*|PIPE_NOWAIT*/,
97                         PIPE_UNLIMITED_INSTANCES,
98                         BUFSIZE,
99                         BUFSIZE,
100                         NMPWAIT_USE_DEFAULT_WAIT,
101                         NULL
102                 );
103                 if(pipe_handle==INVALID_HANDLE_VALUE)
104                 {
105                         synfig::error("IPC(): Call to CreateNamedPipe failed. Ignore next error. GetLastError=%d",GetLastError());
106                         return;
107                 }
108                 
109                 bool connected;
110                 connected=ConnectNamedPipe(pipe_handle,NULL)?true:(GetLastError()==ERROR_PIPE_CONNECTED);
111                 DWORD read_bytes;
112                 bool success;
113
114                 Glib::Thread::yield();
115
116                 if(connected)
117                 do {
118                         String data;
119                         char c;                 
120                         do
121                         {
122                                 success= ReadFile(
123                                         pipe_handle,
124                                         &c,             // buffer pointer
125                                         1,              // buffer size
126                                         &read_bytes,
127                                         NULL
128                                 );
129                                 if(success && read_bytes==1 && c!='\n')
130                                         data+=c;
131                         }while(c!='\n');
132                         synfig::Mutex::Lock lock(cmd_mutex);
133                         cmd_queue.push_back(data);
134                         cmd_dispatcher->emit();
135                 } while(success && read_bytes);
136                 
137                 CloseHandle(pipe_handle);
138         }
139 }
140
141 static void
142 empty_cmd_queue()
143 {
144         synfig::Mutex::Lock lock(cmd_mutex);
145         while(!cmd_queue.empty())
146         {
147                 IPC::process_command(cmd_queue.front());
148                 cmd_queue.pop_front();
149         }
150 }
151
152 #endif
153
154 /* === P R O C E D U R E S ================================================= */
155
156 /* === M E T H O D S ======================================================= */
157
158 IPC::IPC()
159 {
160 #ifdef _WIN32
161
162         cmd_dispatcher=new Glib::Dispatcher;
163         cmd_dispatcher->connect(sigc::ptr_fun(empty_cmd_queue));
164         
165         Glib::Thread::create(
166                 sigc::ptr_fun(pipe_listen_thread),
167                 false
168         );
169         
170 #else
171         
172         remove(fifo_path().c_str());
173         fd=-1;
174         
175         if(mkfifo(fifo_path().c_str(), S_IRWXU)!=0)
176         {
177                 synfig::error("IPC(): mkfifo failed for "+fifo_path());
178         }
179         
180         {
181                 fd=open(fifo_path().c_str(),O_RDWR);
182
183
184                 if(fd<0)
185                 {
186                         synfig::error("IPC(): Failed to open fifo \"%s\". (errno=%d)",fifo_path().c_str(),::errno);
187                 }
188                 else
189                 {
190                         file=SmartFILE(fdopen(fd,"r"));
191                         
192                         Glib::signal_io().connect(
193                                 sigc::mem_fun(this,&IPC::fifo_activity),
194                                 fd,
195                                 Glib::IO_IN|Glib::IO_PRI|Glib::IO_ERR|Glib::IO_HUP|Glib::IO_NVAL
196                         );
197                 }
198         }
199 #endif
200 }
201
202 IPC::~IPC()
203 {
204         //if(file)
205         //      fclose(file.get());
206
207         remove(fifo_path().c_str());
208         
209         //if(fd>=0)
210         //      close(fd);
211 }
212
213 synfig::String
214 IPC::fifo_path()
215 {
216 #ifdef _WIN32
217         return WIN32_PIPE_PATH;
218 #else
219         return Glib::build_filename(App::get_user_app_directory(),"fifo");
220 #endif
221 }
222
223 bool
224 IPC::fifo_activity(Glib::IOCondition cond)
225 {
226         synfig::info(__FILE__":%d: fifo activity",__LINE__);
227         
228         if(cond&(Glib::IO_ERR|Glib::IO_HUP|Glib::IO_NVAL))
229         {
230                 if(cond&(Glib::IO_ERR))
231                         synfig::error("IPC::fifo_activity(): IO_ERR");
232                 if(cond&(Glib::IO_HUP))
233                         synfig::error("IPC::fifo_activity(): IO_HUP");
234                 if(cond&(Glib::IO_NVAL))
235                         synfig::error("IPC::fifo_activity(): IO_NVAL");
236                 return false;
237         }
238         synfig::info(__FILE__":%d: fifo activity",__LINE__);
239
240         String command;
241         {
242                 char tmp;
243                 do {
244                         if(read(fd,&tmp,sizeof(tmp))<=0)
245                                 break;
246                         if(tmp!='\n')
247                                 command+=tmp;
248                 } while(tmp!='\n');
249         }
250         
251         process_command(command);
252         return true;
253 }
254
255 bool
256 IPC::process_command(const synfig::String& command_line)
257 {
258         if(command_line.empty())
259                 return false;
260         
261         char cmd=command_line[0];
262         
263         String args(command_line.begin()+1,command_line.end());
264         while(!args.empty() && args[0]==' ') args.erase(args.begin());
265         while(!args.empty() && args[args.size()-1]=='\n' || args[args.size()-1]==' ') args.erase(args.end()-1);
266         
267         switch(toupper(cmd))
268         {
269                 case 'F': // Focus/Foreground
270                         App::signal_present_all()();
271                         break;
272                 case 'N': // New file
273                         App::signal_present_all()();
274                         App::new_instance();
275                         break;
276                 case 'O': // Open <arg>
277                         App::signal_present_all()();
278                         App::open(args);
279                         break;
280                 case 'X': // Quit
281                 case 'Q': // Quit
282                         App::quit();
283                         break;
284                 default:
285                         synfig::warning("Received unknown command '%c' with arg '%s'",cmd,args.c_str());
286                         break;
287         }
288         
289         return true;
290 }
291
292 synfig::SmartFILE
293 IPC::make_connection()
294 {
295         SmartFILE ret;
296 #ifdef _WIN32
297         HANDLE pipe_handle;
298         pipe_handle=CreateFile(
299                 fifo_path().c_str(),
300                 GENERIC_WRITE, // desired access
301                 0, // share mode
302                 NULL, // security attributes
303                 OPEN_EXISTING, // creation disposition
304                 FILE_ATTRIBUTE_NORMAL, // flags and attributes
305                 NULL  // template file 
306         );
307         if(pipe_handle==INVALID_HANDLE_VALUE)
308         {
309                 synfig::warning("IPC::make_connection(): Unable to connect to previous instance. GetLastError=%d",GetLastError());
310         }
311         int fd=_open_osfhandle(reinterpret_cast<long int>(pipe_handle),_O_APPEND|O_WRONLY);
312 #else
313         struct stat file_stat;
314         if(stat(fifo_path().c_str(),&file_stat)!=0)
315                 return ret;
316         
317         if(!S_ISFIFO(file_stat.st_mode))
318                 return ret;
319         
320         int fd=open(fifo_path().c_str(),O_WRONLY|O_NONBLOCK);
321 #endif
322         
323         if(fd>=0)
324                 ret=SmartFILE(fdopen(fd,"w"));
325
326         synfig::info("uplink fd=%d",fd);
327
328         return ret;
329 }