Blame synfig-studio/src/gui/ipc.cpp

Carlos Lopez a09598
/* === S Y N F I G ========================================================= */
Carlos Lopez a09598
/*!	\file ipc.cpp
Carlos Lopez a09598
**	\brief Template File
Carlos Lopez a09598
**
Carlos Lopez a09598
**	$Id$
Carlos Lopez a09598
**
Carlos Lopez a09598
**	\legal
Carlos Lopez a09598
**	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
Carlos Lopez a09598
**	Copyright (c) 2007 Chris Moore
Carlos Lopez a09598
**
Carlos Lopez a09598
**	This package is free software; you can redistribute it and/or
Carlos Lopez a09598
**	modify it under the terms of the GNU General Public License as
Carlos Lopez a09598
**	published by the Free Software Foundation; either version 2 of
Carlos Lopez a09598
**	the License, or (at your option) any later version.
Carlos Lopez a09598
**
Carlos Lopez a09598
**	This package is distributed in the hope that it will be useful,
Carlos Lopez a09598
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
Carlos Lopez a09598
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Carlos Lopez a09598
**	General Public License for more details.
Carlos Lopez a09598
**	\endlegal
Carlos Lopez a09598
*/
Carlos Lopez a09598
/* ========================================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
/* === H E A D E R S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
#ifdef USING_PCH
Carlos Lopez a09598
#	include "pch.h"
Carlos Lopez a09598
#else
Carlos Lopez a09598
#ifdef HAVE_CONFIG_H
Carlos Lopez a09598
#	include <config.h></config.h>
Carlos Lopez a09598
#endif
Carlos Lopez a09598
2e0857
#include <atomic></atomic>
2e0857
Carlos Lopez a09598
#include "ipc.h"
Carlos Lopez a09598
Carlos Lopez a09598
#ifdef HAVE_SYS_TYPES_H
Carlos Lopez a09598
#include <sys types.h=""></sys>
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Carlos Lopez a09598
#ifdef HAVE_SYS_STAT_H
Carlos Lopez a09598
#include <sys stat.h=""></sys>
Carlos Lopez a09598
#endif
Carlos Lopez a09598
37ade5
#ifdef __OpenBSD__
37ade5
#include <errno.h></errno.h>
37ade5
#elif defined(HAVE_SYS_ERRNO_H)
Carlos Lopez a09598
#include <sys errno.h=""></sys>
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Carlos Lopez a09598
#include <synfig main.h=""></synfig>
Carlos Lopez a09598
#include "app.h"
Carlos Lopez a09598
Carlos Lopez a09598
#ifdef HAVE_UNISTD_H
Carlos Lopez a09598
#include <unistd.h></unistd.h>
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Carlos Lopez a09598
#ifdef HAVE_FCNTL_H
Carlos Lopez a09598
#include <fcntl.h></fcntl.h>
Carlos Lopez a09598
#endif
Carlos Lopez a09598
bw 94d8a6
#include <synfig general.h=""></synfig>
bw 94d8a6
839371
#include "docks/dock_toolbox.h"
Carlos Lopez a09598
#include <glibmm dispatcher.h=""></glibmm>
Rodolfo Ribeiro Gomes d18249
#include <mutex></mutex>
Rodolfo Ribeiro Gomes d18249
#include <thread></thread>
Carlos Lopez a09598
#include <synfig string.h=""></synfig>
ad24f5
#include <synfigapp main.h=""></synfigapp>
48f525
#include <glibmm miscutils.h=""></glibmm>
Carlos López ff177e
#ifdef _WIN32
Carlos López ff177e
#include <windows.h></windows.h>
Carlos López ff177e
#define BUFSIZE   128
Carlos López ff177e
#define read	_read
Carlos López 375f39
#endif
Carlos López ff177e
abdbf2
#include <gui localization.h=""></gui>
Carlos Lopez a09598
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Carlos Lopez a09598
/* === U S I N G =========================================================== */
Carlos Lopez a09598
Carlos Lopez a09598
using namespace std;
Carlos Lopez a09598
using namespace etl;
Carlos Lopez a09598
using namespace synfig;
Carlos Lopez a09598
using namespace studio;
Carlos Lopez a09598
Carlos Lopez a09598
/* === M A C R O S ========================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
/* === G L O B A L S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
#ifdef _WIN32
Carlos Lopez a09598
#define WIN32_PIPE_PATH "\\\\.\\pipe\\SynfigStudio.Cmd"
Rodolfo Ribeiro Gomes d18249
static std::mutex cmd_mutex;
Carlos Lopez a09598
static std::list<synfig::string> cmd_queue;</synfig::string>
Carlos Lopez a09598
static Glib::Dispatcher* cmd_dispatcher;
2e0857
static std::atimic<bool> thread_should_quit(false);</bool>
Rodolfo Ribeiro Gomes 47146f
std::thread *cmd_thread = nullptr;
Carlos Lopez a09598
static void
Carlos Lopez a09598
pipe_listen_thread()
Carlos Lopez a09598
{
2e0857
	while(!thread_should_quit)
Carlos Lopez a09598
	{
Carlos Lopez a09598
		HANDLE pipe_handle;
Carlos Lopez a09598
		pipe_handle=CreateNamedPipe(
Carlos Lopez a09598
			WIN32_PIPE_PATH, // pipe name
Carlos Lopez a09598
			PIPE_ACCESS_INBOUND, // Access type
Carlos Lopez a09598
			PIPE_READMODE_BYTE /*|PIPE_NOWAIT*/,
Carlos Lopez a09598
			PIPE_UNLIMITED_INSTANCES,
Carlos Lopez a09598
			BUFSIZE,
Carlos Lopez a09598
			BUFSIZE,
Carlos Lopez a09598
			NMPWAIT_USE_DEFAULT_WAIT,
Carlos Lopez a09598
			NULL
Carlos Lopez a09598
		);
Carlos Lopez a09598
		if(pipe_handle==INVALID_HANDLE_VALUE)
Carlos Lopez a09598
		{
Carlos Lopez a09598
			synfig::error("IPC(): Call to CreateNamedPipe failed. Ignore next error. GetLastError=%d",GetLastError());
Carlos Lopez a09598
			return;
Carlos Lopez a09598
		}
Carlos Lopez a09598
Carlos Lopez a09598
		bool connected;
Carlos Lopez a09598
		connected=ConnectNamedPipe(pipe_handle,NULL)?true:(GetLastError()==ERROR_PIPE_CONNECTED);
Carlos Lopez a09598
		DWORD read_bytes;
Carlos Lopez a09598
		bool success;
Carlos Lopez a09598
Rodolfo Ribeiro Gomes d18249
		std::this_thread::yield();
Carlos Lopez a09598
Carlos Lopez a09598
		if(connected)
Carlos Lopez a09598
		do {
Carlos Lopez a09598
			String data;
Carlos Lopez a09598
			char c;
Carlos Lopez a09598
			do
Carlos Lopez a09598
			{
Carlos Lopez a09598
				success= ReadFile(
Carlos Lopez a09598
					pipe_handle,
Carlos Lopez a09598
					&c,		// buffer pointer
Carlos Lopez a09598
					1,		// buffer size
Carlos Lopez a09598
					&read_bytes,
Carlos Lopez a09598
					NULL
Carlos Lopez a09598
				);
Carlos Lopez a09598
				if(success && read_bytes==1 && c!='\n')
Carlos Lopez a09598
					data+=c;
Carlos Lopez a09598
			}while(c!='\n');
Rodolfo Ribeiro Gomes d18249
			std::lock_guard<std::mutex> lock(cmd_mutex);</std::mutex>
Carlos Lopez a09598
			cmd_queue.push_back(data);
Carlos Lopez a09598
			cmd_dispatcher->emit();
Rodolfo Ribeiro Gomes 3e9448
		} while(success && read_bytes && !thread_should_quit);
Carlos Lopez a09598
Carlos Lopez a09598
		CloseHandle(pipe_handle);
Carlos Lopez a09598
	}
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
static void
Carlos Lopez a09598
empty_cmd_queue()
Carlos Lopez a09598
{
Rodolfo Ribeiro Gomes d18249
	std::lock_guard<std::mutex> lock(cmd_mutex);</std::mutex>
Carlos Lopez a09598
	while(!cmd_queue.empty())
Carlos Lopez a09598
	{
Carlos Lopez a09598
		IPC::process_command(cmd_queue.front());
Carlos Lopez a09598
		cmd_queue.pop_front();
Carlos Lopez a09598
	}
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Carlos Lopez a09598
/* === P R O C E D U R E S ================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
/* === M E T H O D S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
IPC::IPC()
Carlos Lopez a09598
{
Carlos Lopez a09598
#ifdef _WIN32
Carlos Lopez a09598
Carlos Lopez a09598
	cmd_dispatcher=new Glib::Dispatcher;
Carlos Lopez a09598
	cmd_dispatcher->connect(sigc::ptr_fun(empty_cmd_queue));
Carlos Lopez a09598
Rodolfo Ribeiro Gomes 47146f
	thread_should_quit = false;
Rodolfo Ribeiro Gomes 47146f
Rodolfo Ribeiro Gomes 47146f
	cmd_thread = new std::thread(pipe_listen_thread);
Carlos Lopez a09598
#else
Carlos Lopez a09598
Carlos Lopez a09598
	remove(fifo_path().c_str());
Carlos Lopez a09598
	fd=-1;
Carlos Lopez a09598
Carlos Lopez a09598
	if(mkfifo(fifo_path().c_str(), S_IRWXU)!=0)
Carlos Lopez a09598
	{
Carlos Lopez a09598
		synfig::error("IPC(): mkfifo failed for "+fifo_path());
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	{
Carlos Lopez a09598
		fd=open(fifo_path().c_str(),O_RDWR);
Carlos Lopez a09598
Carlos Lopez a09598
Carlos Lopez a09598
		if(fd<0)
Carlos Lopez a09598
		{
Carlos Lopez a09598
			synfig::error("IPC(): Failed to open fifo \"%s\". (errno=?)",fifo_path().c_str());
Carlos Lopez a09598
			//synfig::error("IPC(): Failed to open fifo \"%s\". (errno=%d)",fifo_path().c_str(),::errno);
Carlos Lopez a09598
		}
Carlos Lopez a09598
		else
Carlos Lopez a09598
		{
Carlos Lopez a09598
			file=SmartFILE(fdopen(fd,"r"));
Carlos Lopez a09598
Carlos Lopez a09598
			Glib::signal_io().connect(
Carlos Lopez a09598
				sigc::mem_fun(this,&IPC::fifo_activity),
Carlos Lopez a09598
				fd,
Carlos Lopez a09598
				Glib::IO_IN|Glib::IO_PRI|Glib::IO_ERR|Glib::IO_HUP|Glib::IO_NVAL
Carlos Lopez a09598
			);
Carlos Lopez a09598
		}
Carlos Lopez a09598
	}
Carlos Lopez a09598
#endif
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
IPC::~IPC()
Carlos Lopez a09598
{
Carlos Lopez a09598
	//if(file)
Carlos Lopez a09598
	//	fclose(file.get());
Carlos Lopez a09598
Carlos Lopez a09598
	remove(fifo_path().c_str());
Rodolfo Ribeiro Gomes 47146f
#ifdef _WIN32
Rodolfo Ribeiro Gomes 47146f
	thread_should_quit = true;
Rodolfo Ribeiro Gomes 47146f
	if (cmd_thread->joinable())
Rodolfo Ribeiro Gomes 47146f
		cmd_thread->join();
Rodolfo Ribeiro Gomes 47146f
	delete cmd_thread;
Rodolfo Ribeiro Gomes 47146f
	delete cmd_dispatcher;
Rodolfo Ribeiro Gomes 47146f
#endif
Carlos Lopez a09598
	//if(fd>=0)
Carlos Lopez a09598
	//	close(fd);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
synfig::String
Carlos Lopez a09598
IPC::fifo_path()
Carlos Lopez a09598
{
Carlos Lopez a09598
#ifdef _WIN32
Carlos Lopez a09598
	return WIN32_PIPE_PATH;
Carlos Lopez a09598
#else
ad24f5
	return Glib::build_filename(synfigapp::Main::get_user_app_directory(),"fifo");
Carlos Lopez a09598
#endif
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
bool
Carlos Lopez a09598
IPC::fifo_activity(Glib::IOCondition cond)
Carlos Lopez a09598
{
Carlos Lopez a09598
	if(cond&(Glib::IO_ERR|Glib::IO_HUP|Glib::IO_NVAL))
Carlos Lopez a09598
	{
Carlos Lopez a09598
		if(cond&(Glib::IO_ERR))
Carlos Lopez a09598
			synfig::error("IPC::fifo_activity(): IO_ERR");
Carlos Lopez a09598
		if(cond&(Glib::IO_HUP))
Carlos Lopez a09598
			synfig::error("IPC::fifo_activity(): IO_HUP");
Carlos Lopez a09598
		if(cond&(Glib::IO_NVAL))
Carlos Lopez a09598
			synfig::error("IPC::fifo_activity(): IO_NVAL");
Carlos Lopez a09598
		return false;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	String command;
Carlos Lopez a09598
	{
Carlos Lopez a09598
		char tmp;
Carlos Lopez a09598
		do {
Carlos Lopez a09598
			if(read(fd,&tmp,sizeof(tmp))<=0)
Carlos Lopez a09598
				break;
Carlos Lopez a09598
			if(tmp!='\n')
Carlos Lopez a09598
				command+=tmp;
Carlos Lopez a09598
		} while(tmp!='\n');
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	synfig::info("%s:%d: fifo activity: '%s'", __FILE__, __LINE__, command.c_str());
Carlos Lopez a09598
	process_command(command);
Carlos Lopez a09598
	return true;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
bool
Carlos Lopez a09598
IPC::process_command(const synfig::String& command_line)
Carlos Lopez a09598
{
Carlos Lopez a09598
	if(command_line.empty())
Carlos Lopez a09598
		return false;
Carlos Lopez a09598
Carlos Lopez a09598
	char cmd = command_line[0];
Carlos Lopez a09598
Carlos Lopez a09598
	String args(command_line.begin()+1,command_line.end());
Carlos Lopez a09598
Carlos Lopez a09598
	// erase leading spaces
Carlos Lopez a09598
	while (!args.empty() && args[0] == ' ')
Carlos Lopez a09598
		args.erase(args.begin());
Carlos Lopez a09598
Carlos Lopez a09598
	// erase trailing newlines and spaces
Carlos Lopez a09598
	while (!args.empty() && (args[args.size()-1] == '\n' || args[args.size()-1] == ' '))
Carlos Lopez a09598
		args.erase(args.end()-1);
Carlos Lopez a09598
Carlos Lopez a09598
	switch(toupper(cmd))
Carlos Lopez a09598
	{
Carlos Lopez a09598
		case 'F': // Focus/Foreground
Carlos Lopez a09598
			App::signal_present_all()();
Carlos Lopez a09598
			break;
Carlos Lopez a09598
		case 'N': // New file
Carlos Lopez a09598
			App::signal_present_all()();
Carlos Lopez a09598
			App::new_instance();
Carlos Lopez a09598
			break;
Carlos Lopez a09598
		case 'O': // Open <arg></arg>
Carlos Lopez a09598
			App::signal_present_all()();
Carlos Lopez a09598
			App::open(args);
Carlos Lopez a09598
			break;
Carlos Lopez a09598
		case 'X': // Quit
Carlos Lopez a09598
		case 'Q': // Quit
Carlos Lopez a09598
			App::quit();
Carlos Lopez a09598
			break;
Carlos Lopez a09598
		default:
Carlos Lopez a09598
			synfig::warning("Received unknown command '%c' with arg '%s'",cmd,args.c_str());
Carlos Lopez a09598
			break;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	return true;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
synfig::SmartFILE
Carlos Lopez a09598
IPC::make_connection()
Carlos Lopez a09598
{
Carlos Lopez a09598
	SmartFILE ret;
Carlos Lopez a09598
#ifdef _WIN32
Carlos Lopez a09598
	HANDLE pipe_handle;
Carlos Lopez a09598
	pipe_handle=CreateFile(
Carlos Lopez a09598
		fifo_path().c_str(),
Carlos Lopez a09598
		GENERIC_WRITE, // desired access
Carlos Lopez a09598
		0, // share mode
Carlos Lopez a09598
		NULL, // security attributes
Carlos Lopez a09598
		OPEN_EXISTING, // creation disposition
Carlos Lopez a09598
		FILE_ATTRIBUTE_NORMAL, // flags and attributes
Carlos Lopez a09598
		NULL  // template file
Carlos Lopez a09598
	);
90d880
	int fd;
Carlos Lopez a09598
	if(pipe_handle==INVALID_HANDLE_VALUE)
Carlos Lopez a09598
	{
Carlos Lopez a09598
		DWORD error = GetLastError();
Carlos Lopez a09598
#ifndef _DEBUG
Carlos Lopez a09598
		if( error != ERROR_FILE_NOT_FOUND )
Carlos Lopez a09598
#endif
Carlos Lopez a09598
			synfig::warning("IPC::make_connection(): Unable to connect to previous instance. GetLastError=%d",error);
90d880
		fd=-1;
90d880
	} else {
90d880
		fd=_open_osfhandle(reinterpret_cast<intptr_t>(pipe_handle),_O_APPEND|O_WRONLY);</intptr_t>
Carlos Lopez a09598
	}
Carlos Lopez a09598
#else
Carlos Lopez a09598
	struct stat file_stat;
Carlos Lopez a09598
	if(stat(fifo_path().c_str(),&file_stat)!=0)
Carlos Lopez a09598
		return ret;
Carlos Lopez a09598
Carlos Lopez a09598
	if(!S_ISFIFO(file_stat.st_mode))
Carlos Lopez a09598
		return ret;
Carlos Lopez a09598
Carlos Lopez a09598
	int fd=open(fifo_path().c_str(),O_WRONLY|O_NONBLOCK);
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Carlos Lopez a09598
	if(fd>=0)
Carlos Lopez a09598
		ret=SmartFILE(fdopen(fd,"w"));
Carlos Lopez a09598
Carlos Lopez a09598
#ifdef _DEBUG
Carlos Lopez a09598
	// synfig::info("uplink fd=%d",fd);
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Carlos Lopez a09598
	return ret;
Carlos Lopez a09598
}