Added support for opening images in an already-running RT instance

This is enabled by the new -R switch of rawtherapee.
The idea is that you first start the "server" with

  `$ rawtherapee -R`

and then open images on this server by using

  `$ rawtherapee -R /path/to/raw.file`

Currently disables on OSX (there seems to be some "legacy" support for this in
rtwindow, but I have no way of testing it and/or integrating it with this at
the moment)
This commit is contained in:
Alberto Griggio 2017-05-18 16:38:09 +02:00
parent 86c5cc1826
commit c4863e5f89
2 changed files with 346 additions and 221 deletions

View File

@ -59,7 +59,7 @@ Glib::ustring argv0;
Glib::ustring creditsPath;
Glib::ustring licensePath;
Glib::ustring argv1;
bool simpleEditor;
//bool simpleEditor;
//Glib::Threads::Thread* mainThread;
namespace

View File

@ -63,6 +63,7 @@ Glib::ustring argv1;
Glib::ustring argv2;
bool simpleEditor = false;
bool gimpPlugin = false;
bool remote = false;
Glib::RefPtr<Gtk::CssProvider> cssForced;
Glib::RefPtr<Gtk::CssProvider> cssRT;
//Glib::Threads::Thread* mainThread;
@ -89,8 +90,6 @@ Glib::ustring fname_to_utf8 (const char* fname)
#endif
}
}
// This recursive mutex will be used by gdk_threads_enter/leave instead of a simple mutex
static Glib::Threads::RecMutex myGdkRecMutex;
@ -110,6 +109,7 @@ static void myGdkLockLeave()
myGdkRecMutex.unlock();
}
/* Process line command options
* Returns
* 0 if process in batch has executed
@ -118,20 +118,319 @@ static void myGdkLockLeave()
* -1 if there is an error in parameters
* -2 if an error occurred during processing
* -3 if at least one required procparam file was not found */
int processLineParams( int argc, char **argv );
int processLineParams( int argc, char **argv )
{
for( int iArg = 1; iArg < argc; iArg++) {
Glib::ustring currParam(argv[iArg]);
#if ECLIPSE_ARGS
currParam = currParam.substr(1, currParam.length()-2);
#endif
if( currParam.at(0) == '-' ) {
switch( currParam.at(1) ) {
#ifdef WIN32
case 'w': // This case is handled outside this function
break;
#endif
case 'v':
return 0;
#ifndef __APPLE__ // TODO agriggio - there seems to be already some "single instance app" support for OSX in rtwindow. Disabling it here until I understand how to merge the two
case 'R':
if (!gimpPlugin) {
remote = true;
}
break;
#endif
case 'g':
if (currParam == "-gimp") {
gimpPlugin = true;
simpleEditor = true;
remote = false;
break;
}
// no break here on purpose
case 'h':
case '?':
default: {
Glib::ustring pparamsExt = paramFileExtension.substr(1);
std::cout << " An advanced, cross-platform program for developing raw photos." << std::endl;
std::cout << std::endl;
std::cout << " Website: http://www.rawtherapee.com/" << std::endl;
std::cout << " Documentation: http://rawpedia.rawtherapee.com/" << std::endl;
std::cout << " Forum: https://discuss.pixls.us/c/software/rawtherapee" << std::endl;
std::cout << " Code and bug reports: https://github.com/Beep6581/RawTherapee" << std::endl;
std::cout << std::endl;
std::cout << "Symbols:" << std::endl;
std::cout << " <Chevrons> indicate parameters you can change." << std::endl;
//std::cout << " [Square brackets] mean the parameter is optional." << std::endl;
//std::cout << " The pipe symbol | indicates a choice of one or the other." << std::endl;
//std::cout << " The dash symbol - denotes a range of possible values from one to the other." << std::endl;
std::cout << std::endl;
std::cout << "Usage:" << std::endl;
std::cout << " " << Glib::path_get_basename(argv[0]) << " <folder> Start File Browser inside folder." << std::endl;
std::cout << " " << Glib::path_get_basename(argv[0]) << " <file> Start Image Editor with file." << std::endl;
std::cout << std::endl;
std::cout << "Options:" << std::endl;
#ifdef WIN32
std::cout << " -w Do not open the Windows console" << std::endl;
#endif
std::cout << " -v Print RawTherapee version number and exit" << std::endl;
#ifndef __APPLE__
std::cout << " -R Raise an already running RawTherapee instance (if available)" << std::endl;
#endif
std::cout << " -h -? Display this help message" << std::endl;
return -1;
}
}
} else {
if (argv1.empty()) {
argv1 = Glib::ustring(fname_to_utf8(argv[iArg]));
#if ECLIPSE_ARGS
argv1 = argv1.substr(1, argv1.length()-2);
#endif
} else if (gimpPlugin) {
argv2 = Glib::ustring(fname_to_utf8(argv[iArg]));
break;
}
if (!gimpPlugin) {
break;
}
}
}
return 1;
}
bool init_rt()
{
if (!Options::load ()) {
return false;
}
extProgStore->init();
SoundManager::init();
if( !options.rtSettings.verbose ) {
TIFFSetWarningHandler(nullptr); // avoid annoying message boxes
}
#ifndef WIN32
// Move the old path to the new one if the new does not exist
if (Glib::file_test(Glib::build_filename(options.rtdir, "cache"), Glib::FILE_TEST_IS_DIR) && !Glib::file_test(options.cacheBaseDir, Glib::FILE_TEST_IS_DIR)) {
g_rename(Glib::build_filename (options.rtdir, "cache").c_str (), options.cacheBaseDir.c_str ());
}
#endif
return true;
}
void cleanup_rt()
{
rtengine::cleanup();
}
RTWindow *create_rt_window()
{
Glib::ustring icon_path = Glib::build_filename(argv0, "images");
Glib::RefPtr<Gtk::IconTheme> defaultIconTheme = Gtk::IconTheme::get_default();
defaultIconTheme->append_search_path(icon_path);
rtengine::setPaths(options);
MyExpander::init(); // has to stay AFTER rtengine::setPaths
// ------- loading theme files
Glib::RefPtr<Gdk::Screen> screen = Gdk::Screen::get_default();
if (screen) {
Gtk::Settings::get_for_screen(screen)->property_gtk_theme_name() = "Adwaita";
Gtk::Settings::get_for_screen(screen)->property_gtk_application_prefer_dark_theme() = true;
Glib::RefPtr<Glib::Regex> regex = Glib::Regex::create(THEMEREGEXSTR, Glib::RegexCompileFlags::REGEX_CASELESS);
Glib::ustring filename = Glib::build_filename(argv0, "themes", options.theme + ".css");
if (!regex->match(options.theme + ".css") || !Glib::file_test(filename, Glib::FILE_TEST_EXISTS)) {
options.theme = "RawTherapee-GTK";
// We're not testing GTK_MAJOR_VERSION == 3 here, since this branch requires Gtk3 only
if (GTK_MINOR_VERSION < 20) {
options.theme = options.theme + "3-_19";
} else {
options.theme = options.theme + "3-20_";
}
filename = Glib::build_filename(argv0, "themes", options.theme + ".css");
}
cssRT = Gtk::CssProvider::create();
try {
cssRT->load_from_path (filename);
Gtk::StyleContext::add_provider_for_screen(screen, cssRT, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
} catch (Glib::Error &err) {
printf("Error: Can't load css file \"%s\"\nMessage: %s\n", filename.c_str(), err.what().c_str());
} catch (...) {
printf("Error: Can't load css file \"%s\"\n", filename.c_str());
}
// Set the font face and size
if (options.fontFamily != "default") {
try {
cssForced = Gtk::CssProvider::create();
//GTK318
#if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 20
cssForced->load_from_data (Glib::ustring::compose("* { font-family: %1; font-size: %2px }", options.fontFamily, options.fontSize));
#else
cssForced->load_from_data (Glib::ustring::compose("* { font-family: %1; font-size: %2pt }", options.fontFamily, options.fontSize));
#endif
//GTK318
Gtk::StyleContext::add_provider_for_screen(screen, cssForced, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
} catch (Glib::Error &err) {
printf("Error: \"%s\"\n", err.what().c_str());
} catch (...) {
printf("Error: Can't find the font named \"%s\"\n", options.fontFamily.c_str());
}
}
}
#ifndef NDEBUG
else if (!screen) {
printf("ERROR: Can't get default screen!\n");
}
#endif
// ------- end loading theme files
//gdk_threads_enter ();
RTWindow *rtWindow = new RTWindow();
// alerting users if the default raw and image profiles are missing
if (options.is_defProfRawMissing()) {
Gtk::MessageDialog msgd (Glib::ustring::compose(M("OPTIONS_DEFRAW_MISSING"), options.defProfRaw), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
msgd.run ();
}
if (options.is_defProfImgMissing()) {
Gtk::MessageDialog msgd (Glib::ustring::compose(M("OPTIONS_DEFIMG_MISSING"), options.defProfImg), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
msgd.run ();
}
return rtWindow;
}
class RTApplication: public Gtk::Application {
public:
RTApplication():
Gtk::Application("com.rawtherapee.application",
Gio::APPLICATION_HANDLES_OPEN),
rtWindow(nullptr)
{
}
~RTApplication()
{
if (rtWindow) {
delete rtWindow;
}
cleanup_rt();
}
private:
bool create_window()
{
if (rtWindow) {
return true;
}
if (!init_rt()) {
Gtk::MessageDialog msgd ("Fatal error!\nThe RT_SETTINGS and/or RT_PATH environment variables are set, but use a relative path. The path must be absolute!", true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
add_window(msgd);
msgd.run ();
return false;
} else {
rtWindow = create_rt_window();
add_window(*rtWindow);
return true;
}
}
// Override default signal handlers:
void on_activate() override
{
if (create_window()) {
rtWindow->present();
}
}
void on_open(const Gio::Application::type_vec_files& files,
const Glib::ustring& hint) override
{
if (create_window()) {
struct Data {
std::vector<Thumbnail *> entries;
Glib::ustring lastfilename;
FileCatalog *filecatalog;
};
Data *d = new Data;
d->filecatalog = rtWindow->fpanel->fileCatalog;
for (const auto &f : files) {
Thumbnail *thm = cacheMgr->getEntry(f->get_path());
if (thm) {
d->entries.push_back(thm);
d->lastfilename = f->get_path();
}
}
if (!d->entries.empty()) {
const auto doit =
[](gpointer data) -> gboolean
{
Data *d = static_cast<Data *>(data);
d->filecatalog->openRequested(d->entries);
d->filecatalog->selectImage(d->lastfilename, true);
delete d;
return FALSE;
};
gdk_threads_add_idle(doit, d);
} else {
delete d;
}
rtWindow->present();
}
}
private:
RTWindow *rtWindow;
};
} // namespace
int main(int argc, char **argv)
{
setlocale(LC_ALL, "");
setlocale(LC_NUMERIC, "C"); // to set decimal point to "."
simpleEditor = false;
gimpPlugin = false;
remote = false;
argv0 = "";
argv1 = "";
argv2 = "";
Glib::init(); // called by Gtk::Main, but this may be important for thread handling, so we call it ourselves now
gdk_threads_set_lock_functions(G_CALLBACK(myGdkLockEnter), (G_CALLBACK(myGdkLockLeave)));
gdk_threads_init();
gtk_init (&argc, &argv); // use the "--g-fatal-warnings" command line flag to make warnings fatal
Gio::init ();
//mainThread = Glib::Threads::Thread::self();
#ifdef BUILD_BUNDLE
char exname[512] = {0};
@ -175,15 +474,6 @@ int main(int argc, char **argv)
licensePath = LICENCE_SEARCH_PATH;
#endif
if (!Options::load ()) {
Gtk::Main m(&argc, &argv);
Gtk::MessageDialog msgd ("Fatal error!\nThe RT_SETTINGS and/or RT_PATH environment variables are set, but use a relative path. The path must be absolute!", true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
msgd.run ();
return -2;
}
extProgStore->init();
SoundManager::init();
#ifdef WIN32
bool consoleOpened = false;
@ -281,24 +571,6 @@ int main(int argc, char **argv)
#endif
if( !options.rtSettings.verbose ) {
TIFFSetWarningHandler(nullptr); // avoid annoying message boxes
}
#ifndef WIN32
// Move the old path to the new one if the new does not exist
if (Glib::file_test(Glib::build_filename(options.rtdir, "cache"), Glib::FILE_TEST_IS_DIR) && !Glib::file_test(options.cacheBaseDir, Glib::FILE_TEST_IS_DIR)) {
g_rename(Glib::build_filename (options.rtdir, "cache").c_str (), options.cacheBaseDir.c_str ());
}
#endif
if (!argv1.empty()) {
if( Glib::file_test(argv1, Glib::FILE_TEST_EXISTS) && !Glib::file_test(argv1, Glib::FILE_TEST_IS_DIR)) {
simpleEditor = true;
}
}
if (gimpPlugin) {
if (!Glib::file_test(argv1, Glib::FILE_TEST_EXISTS) || Glib::file_test(argv1, Glib::FILE_TEST_IS_DIR)) {
printf("Error: argv1 doesn't exist\n");
@ -308,108 +580,50 @@ int main(int argc, char **argv)
printf("Error: -gimp requires two arguments\n");
return 1;
}
} else if (!remote && Glib::file_test(argv1, Glib::FILE_TEST_EXISTS)) {
simpleEditor = true;
}
Gtk::Main m(&argc, &argv);
Glib::ustring icon_path = Glib::build_filename(argv0, "images");
Glib::RefPtr<Gtk::IconTheme> defaultIconTheme = Gtk::IconTheme::get_default();
defaultIconTheme->append_search_path(icon_path);
rtengine::setPaths(options);
MyExpander::init(); // has to stay AFTER rtengine::setPaths
// ------- loading theme files
Glib::RefPtr<Gdk::Screen> screen = Gdk::Screen::get_default();
if (screen) {
Gtk::Settings::get_for_screen(screen)->property_gtk_theme_name() = "Adwaita";
Gtk::Settings::get_for_screen(screen)->property_gtk_application_prefer_dark_theme() = true;
Glib::RefPtr<Glib::Regex> regex = Glib::Regex::create(THEMEREGEXSTR, Glib::RegexCompileFlags::REGEX_CASELESS);
Glib::ustring filename = Glib::build_filename(argv0, "themes", options.theme + ".css");
if (!regex->match(options.theme + ".css") || !Glib::file_test(filename, Glib::FILE_TEST_EXISTS)) {
options.theme = "RawTherapee-GTK";
// We're not testing GTK_MAJOR_VERSION == 3 here, since this branch requires Gtk3 only
if (GTK_MINOR_VERSION < 20) {
options.theme = options.theme + "3-_19";
int ret = 0;
if (remote) {
char *app_argv[2] = { nullptr, nullptr };
app_argv[0] = const_cast<char *>(argv0.c_str());
int app_argc = 1;
if (!argv1.empty()) {
app_argc = 2;
app_argv[1] = const_cast<char *>(argv1.c_str());
}
RTApplication app;
ret = app.run(app_argc, app_argv);
} else {
options.theme = options.theme + "3-20_";
}
filename = Glib::build_filename(argv0, "themes", options.theme + ".css");
}
cssRT = Gtk::CssProvider::create();
try {
cssRT->load_from_path (filename);
Gtk::StyleContext::add_provider_for_screen(screen, cssRT, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
} catch (Glib::Error &err) {
printf("Error: Can't load css file \"%s\"\nMessage: %s\n", filename.c_str(), err.what().c_str());
} catch (...) {
printf("Error: Can't load css file \"%s\"\n", filename.c_str());
}
// Set the font face and size
if (options.fontFamily != "default") {
try {
cssForced = Gtk::CssProvider::create();
//GTK318
#if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 20
cssForced->load_from_data (Glib::ustring::compose("* { font-family: %1; font-size: %2px }", options.fontFamily, options.fontSize));
#else
cssForced->load_from_data (Glib::ustring::compose("* { font-family: %1; font-size: %2pt }", options.fontFamily, options.fontSize));
#endif
//GTK318
Gtk::StyleContext::add_provider_for_screen(screen, cssForced, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
} catch (Glib::Error &err) {
printf("Error: \"%s\"\n", err.what().c_str());
} catch (...) {
printf("Error: Can't find the font named \"%s\"\n", options.fontFamily.c_str());
}
}
}
#ifndef NDEBUG
else if (!screen) {
printf("ERROR: Can't get default screen!\n");
}
#endif
// ------- end loading theme files
gdk_threads_enter ();
RTWindow *rtWindow = new class RTWindow();
// alerting users if the default raw and image profiles are missing
if (options.is_defProfRawMissing()) {
Gtk::MessageDialog msgd (Glib::ustring::compose(M("OPTIONS_DEFRAW_MISSING"), options.defProfRaw), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
msgd.run ();
}
if (options.is_defProfImgMissing()) {
Gtk::MessageDialog msgd (Glib::ustring::compose(M("OPTIONS_DEFIMG_MISSING"), options.defProfImg), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
msgd.run ();
}
// opening the main window
if (init_rt()) {
Gtk::Main m(&argc, &argv);
gdk_threads_enter();
RTWindow *rtWindow = create_rt_window();
m.run(*rtWindow);
gdk_threads_leave();
if (gimpPlugin && rtWindow->epanel && rtWindow->epanel->isRealized()) {
if (gimpPlugin &&
rtWindow->epanel && rtWindow->epanel->isRealized()) {
SaveFormat sf;
sf.format = "tif";
sf.tiffBits = 16;
sf.tiffUncompressed = true;
sf.saveParams = true;
rtWindow->epanel->saveImmediately(argv2, sf);
if (!rtWindow->epanel->saveImmediately(argv2, sf)) {
ret = -2;
}
}
gdk_threads_leave ();
delete rtWindow;
rtengine::cleanup();
cleanup_rt();
} else {
Gtk::Main m(&argc, &argv);
Gtk::MessageDialog msgd ("Fatal error!\nThe RT_SETTINGS and/or RT_PATH environment variables are set, but use a relative path. The path must be absolute!", true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
msgd.run ();
ret = -2;
}
}
#ifdef WIN32
@ -421,95 +635,6 @@ int main(int argc, char **argv)
#endif
return 0;
return ret;
}
void deleteProcParams(std::vector<rtengine::procparams::PartialProfile*> &pparams)
{
for (unsigned int i = 0; i < pparams.size(); i++) {
pparams[i]->deleteInstance();
delete pparams[i];
pparams[i] = NULL;
}
return;
}
int processLineParams( int argc, char **argv )
{
for( int iArg = 1; iArg < argc; iArg++) {
Glib::ustring currParam(argv[iArg]);
#if ECLIPSE_ARGS
currParam = currParam.substr(1, currParam.length()-2);
#endif
if( currParam.at(0) == '-' ) {
switch( currParam.at(1) ) {
#ifdef WIN32
case 'w': // This case is handled outside this function
break;
#endif
case 'g':
if (currParam == "-gimp") {
simpleEditor = true;
gimpPlugin = true;
break;
}
// no break here on purpose
case 'v':
return 0;
case 'h':
case '?':
default: {
Glib::ustring pparamsExt = paramFileExtension.substr(1);
std::cout << " An advanced, cross-platform program for developing raw photos." << std::endl;
std::cout << std::endl;
std::cout << " Website: http://www.rawtherapee.com/" << std::endl;
std::cout << " Documentation: http://rawpedia.rawtherapee.com/" << std::endl;
std::cout << " Forum: https://discuss.pixls.us/c/software/rawtherapee" << std::endl;
std::cout << " Code and bug reports: https://github.com/Beep6581/RawTherapee" << std::endl;
std::cout << std::endl;
std::cout << "Symbols:" << std::endl;
std::cout << " <Chevrons> indicate parameters you can change." << std::endl;
//std::cout << " [Square brackets] mean the parameter is optional." << std::endl;
//std::cout << " The pipe symbol | indicates a choice of one or the other." << std::endl;
//std::cout << " The dash symbol - denotes a range of possible values from one to the other." << std::endl;
std::cout << std::endl;
std::cout << "Usage:" << std::endl;
std::cout << " " << Glib::path_get_basename(argv[0]) << " <folder> Start File Browser inside folder." << std::endl;
std::cout << " " << Glib::path_get_basename(argv[0]) << " <file> Start Image Editor with file." << std::endl;
std::cout << std::endl;
std::cout << "Options:" << std::endl;
#ifdef WIN32
std::cout << " -w Do not open the Windows console" << std::endl;
#endif
std::cout << " -v Print RawTherapee version number and exit" << std::endl;
std::cout << " -h -? Display this help message" << std::endl;
return -1;
}
}
} else {
if (argv1.empty()) {
argv1 = Glib::ustring(fname_to_utf8(argv[iArg]));
#if ECLIPSE_ARGS
argv1 = argv1.substr(1, argv1.length()-2);
#endif
} else if (gimpPlugin) {
argv2 = Glib::ustring(fname_to_utf8(argv[iArg]));
break;
}
if (!gimpPlugin) {
break;
}
}
}
if( !argv1.empty() ) {
return 1;
}
return 0;
}