source: synfigstudio/trunk/fuentes/src/gui/ipc.cpp @ 481

Last change on this file since 481 was 481, checked in by jrpelegrina, 4 years ago

First release to xenial

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