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