more updates
[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 #include <synfig/main.h>
43 #include "app.h"
44
45 #ifdef HAVE_UNISTD_H
46 #include <unistd.h>
47 #endif
48
49 #ifdef HAVE_FCNTL_H
50 #include <fcntl.h>
51 #endif
52
53 #ifdef _WIN32
54 #include <windows.h>
55 #define BUFSIZE   128
56 #define read    _read
57 #endif
58
59 #include "toolbox.h"
60 #include <glibmm/dispatcher.h>
61 #include <synfig/mutex.h>
62 #include <synfig/string.h>
63 #include <glibmm/thread.h>
64
65 #endif
66
67 /* === U S I N G =========================================================== */
68
69 using namespace std;
70 using namespace etl;
71 using namespace synfig;
72 using namespace studio;
73
74 /* === M A C R O S ========================================================= */
75
76 /* === G L O B A L S ======================================================= */
77
78 #ifdef _WIN32
79 #define WIN32_PIPE_PATH "\\\\.\\pipe\\SynfigStudio.Cmd"
80 static synfig::Mutex cmd_mutex;
81 static std::list<synfig::String> cmd_queue;
82 static Glib::Dispatcher* cmd_dispatcher;
83 static void
84 pipe_listen_thread()
85 {
86         for(;;)
87         {
88                 HANDLE pipe_handle;
89                 pipe_handle=CreateNamedPipe(
90                         WIN32_PIPE_PATH, // pipe name
91                         PIPE_ACCESS_INBOUND, // Access type
92                         PIPE_READMODE_BYTE /*|PIPE_NOWAIT*/,
93                         PIPE_UNLIMITED_INSTANCES,
94                         BUFSIZE,
95                         BUFSIZE,
96                         NMPWAIT_USE_DEFAULT_WAIT,
97                         NULL
98                 );
99                 if(pipe_handle==INVALID_HANDLE_VALUE)
100                 {
101                         synfig::error("IPC(): Call to CreateNamedPipe failed. Ignore next error. GetLastError=%d",GetLastError());
102                         return;
103                 }
104                 
105                 bool connected;
106                 connected=ConnectNamedPipe(pipe_handle,NULL)?true:(GetLastError()==ERROR_PIPE_CONNECTED);
107                 DWORD read_bytes;
108                 bool success;
109
110                 Glib::Thread::yield();
111
112                 if(connected)
113                 do {
114                         String data;
115                         char c;                 
116                         do
117                         {
118                                 success= ReadFile(
119                                         pipe_handle,
120                                         &c,             // buffer pointer
121                                         1,              // buffer size
122                                         &read_bytes,
123                                         NULL
124                                 );
125                                 if(success && read_bytes==1 && c!='\n')
126                                         data+=c;
127                         }while(c!='\n');
128                         synfig::Mutex::Lock lock(cmd_mutex);
129                         cmd_queue.push_back(data);
130                         cmd_dispatcher->emit();
131                 } while(success && read_bytes);
132                 
133                 CloseHandle(pipe_handle);
134         }
135 }
136
137 static void
138 empty_cmd_queue()
139 {
140         synfig::Mutex::Lock lock(cmd_mutex);
141         while(!cmd_queue.empty())
142         {
143                 IPC::process_command(cmd_queue.front());
144                 cmd_queue.pop_front();
145         }
146 }
147
148 #endif
149
150 /* === P R O C E D U R E S ================================================= */
151
152 /* === M E T H O D S ======================================================= */
153
154 IPC::IPC()
155 {
156 #ifdef _WIN32
157
158         cmd_dispatcher=new Glib::Dispatcher;
159         cmd_dispatcher->connect(sigc::ptr_fun(empty_cmd_queue));
160         
161         Glib::Thread::create(
162                 sigc::ptr_fun(pipe_listen_thread),
163                 false
164         );
165         
166 #else
167         
168         remove(fifo_path().c_str());
169         fd=-1;
170         
171         if(mkfifo(fifo_path().c_str(), S_IRWXU)!=0)
172         {
173                 synfig::error("IPC(): mkfifo failed for "+fifo_path());
174         }
175         
176         {
177                 fd=open(fifo_path().c_str(),O_RDWR);
178
179
180                 if(fd<0)
181                 {
182                         synfig::error("IPC(): Failed to open fifo \"%s\". (errno=%d)",fifo_path().c_str(),errno);
183                 }
184                 else
185                 {
186                         file=SmartFILE(fdopen(fd,"r"));
187                         
188                         Glib::signal_io().connect(
189                                 sigc::mem_fun(this,&IPC::fifo_activity),
190                                 fd,
191                                 Glib::IO_IN|Glib::IO_PRI|Glib::IO_ERR|Glib::IO_HUP|Glib::IO_NVAL
192                         );
193                 }
194         }
195 #endif
196 }
197
198 IPC::~IPC()
199 {
200         //if(file)
201         //      fclose(file.get());
202
203         remove(fifo_path().c_str());
204         
205         //if(fd>=0)
206         //      close(fd);
207 }
208
209 synfig::String
210 IPC::fifo_path()
211 {
212 #ifdef _WIN32
213         return WIN32_PIPE_PATH;
214 #else
215         return Glib::build_filename(App::get_user_app_directory(),"fifo");
216 #endif
217 }
218
219 bool
220 IPC::fifo_activity(Glib::IOCondition cond)
221 {
222         synfig::info(__FILE__":%d: fifo activity",__LINE__);
223         
224         if(cond&(Glib::IO_ERR|Glib::IO_HUP|Glib::IO_NVAL))
225         {
226                 if(cond&(Glib::IO_ERR))
227                         synfig::error("IPC::fifo_activity(): IO_ERR");
228                 if(cond&(Glib::IO_HUP))
229                         synfig::error("IPC::fifo_activity(): IO_HUP");
230                 if(cond&(Glib::IO_NVAL))
231                         synfig::error("IPC::fifo_activity(): IO_NVAL");
232                 return false;
233         }
234         synfig::info(__FILE__":%d: fifo activity",__LINE__);
235
236         String command;
237         {
238                 char tmp;
239                 do {
240                         if(read(fd,&tmp,sizeof(tmp))<=0)
241                                 break;
242                         if(tmp!='\n')
243                                 command+=tmp;
244                 } while(tmp!='\n');
245         }
246         
247         process_command(command);
248         return true;
249 }
250
251 bool
252 IPC::process_command(const synfig::String& command_line)
253 {
254         if(command_line.empty())
255                 return false;
256         
257         char cmd=command_line[0];
258         
259         String args(command_line.begin()+1,command_line.end());
260         while(!args.empty() && args[0]==' ') args.erase(args.begin());
261         while(!args.empty() && args[args.size()-1]=='\n' || args[args.size()-1]==' ') args.erase(args.end()-1);
262         
263         switch(toupper(cmd))
264         {
265                 case 'F': // Focus/Foreground
266                         App::signal_present_all()();
267                         break;
268                 case 'N': // New file
269                         App::signal_present_all()();
270                         App::new_instance();
271                         break;
272                 case 'O': // Open <arg>
273                         App::signal_present_all()();
274                         App::open(args);
275                         break;
276                 case 'X': // Quit
277                 case 'Q': // Quit
278                         App::quit();
279                         break;
280                 default:
281                         synfig::warning("Received unknown command '%c' with arg '%s'",cmd,args.c_str());
282                         break;
283         }
284         
285         return true;
286 }
287
288 synfig::SmartFILE
289 IPC::make_connection()
290 {
291         SmartFILE ret;
292 #ifdef _WIN32
293         HANDLE pipe_handle;
294         pipe_handle=CreateFile(
295                 fifo_path().c_str(),
296                 GENERIC_WRITE, // desired access
297                 0, // share mode
298                 NULL, // security attributes
299                 OPEN_EXISTING, // creation disposition
300                 FILE_ATTRIBUTE_NORMAL, // flags and attributes
301                 NULL  // template file 
302         );
303         if(pipe_handle==INVALID_HANDLE_VALUE)
304         {
305                 synfig::warning("IPC::make_connection(): Unable to connect to previous instance. GetLastError=%d",GetLastError());
306         }
307         int fd=_open_osfhandle(reinterpret_cast<long int>(pipe_handle),_O_APPEND|O_WRONLY);
308 #else
309         struct stat file_stat;
310         if(stat(fifo_path().c_str(),&file_stat)!=0)
311                 return ret;
312         
313         if(!S_ISFIFO(file_stat.st_mode))
314                 return ret;
315         
316         int fd=open(fifo_path().c_str(),O_WRONLY|O_NONBLOCK);
317 #endif
318         
319         if(fd>=0)
320                 ret=SmartFILE(fdopen(fd,"w"));
321
322         synfig::info("uplink fd=%d",fd);
323
324         return ret;
325 }