13
0
livetrax/gtk2_ardour/bundle_env_msvc.cc
Robin Gareus 4050ca5633
Update GPL boilerplate and (C)
Copyright-holder and year information is extracted from git log.

git history begins in 2005. So (C) from 1998..2005 is lost. Also some
(C) assignment of commits where the committer didn't use --author.
2019-08-03 15:53:15 +02:00

506 lines
14 KiB
C++
Raw Blame History

/*
* Copyright (C) 2014-2017 John Emmas <john@creativepost.co.uk>
* Copyright (C) 2015-2016 Paul Davis <paul@linuxaudiosystems.com>
* Copyright (C) 2015-2016 Robin Gareus <robin@gareus.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "bundle_env.h"
#include "pbd/i18n.h"
#include <shlobj.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <glibmm.h>
#include "pbd/gstdio_compat.h"
#include <fontconfig/fontconfig.h>
#include "ardour/ardour.h"
#include "ardour/search_paths.h"
#include "ardour/filesystem_paths.h"
#include "pbd/file_utils.h"
#include "pbd/epa.h"
using namespace std;
using namespace PBD;
using namespace ARDOUR;
std::string
get_windows_drive_volume_letter()
{
static std::string ret;
char path[PATH_MAX+1];
LPITEMIDLIST pidl = 0;
if (!ret.length()) {
if (S_OK == SHGetSpecialFolderLocation (0, CSIDL_WINDOWS, &pidl))
{
if (SHGetPathFromIDListA (pidl, path)) {
path[2] = '\0'; // Gives us just the drive letter and colon
ret = path;
}
CoTaskMemFree (pidl);
}
// The above should never fail - but just in case...
else if (char *env_path = getenv ("windir"))
{
strcpy (path, env_path);
path[2] = '\0'; // Gives us just the drive letter and colon
ret = path;
}
}
return ret;
}
const string
get_module_folder ()
{
std::string ret;
// Gives the top-level Ardour installation folder (on Windows)
// Typically, this will be somehwere like "C:\Program Files"
gchar* pExeRoot = g_win32_get_package_installation_directory_of_module (0);
if (0 == pExeRoot) {
pExeRoot = g_build_filename("C:\\", "Program Files", PROGRAM_NAME, 0);
}
if (pExeRoot) {
gchar tmp[PATH_MAX+1];
gchar* p;
strcpy(tmp, pExeRoot);
if (0 != (p = strrchr (tmp, G_DIR_SEPARATOR))) {
*p = '\0';
if (0 != (p = g_build_filename(tmp, 0))) {
ret = p;
g_free (p);
}
}
g_free (pExeRoot);
}
return (ret);
}
bool
fixup_config_file (Glib::ustring str_file_to_fix)
{
FILE* fd;
char buf[4096];
bool conversion_needed = false;
bool succeeded = false;
fstream file_to_fix (fd = g_fopen(str_file_to_fix.c_str(), "r+b"));
if (file_to_fix.is_open()) {
vector<std::string> lines;
std::string line;
file_to_fix.seekg (0, std::ios::beg);
file_to_fix.seekp (0, std::ios::beg);
try {
while (!file_to_fix.eof() && file_to_fix.getline (buf, sizeof(buf))) {
line = buf;
if (!conversion_needed && (std::string::npos != line.find("$(")))
conversion_needed = true;
lines.push_back(line);
}
if (conversion_needed) {
bool error = false;
std::string::size_type token_begin, token_end;
vector<string>::iterator i;
for (i = lines.begin(); i != lines.end(); ++i) {
if (string::npos != (token_begin = i->find("$("))) {
if (string::npos != (token_end = i->find(")", token_begin))) {
std::string str_replace_with;
std::string str_to_replace = i->substr(token_begin, ((token_end+1)-token_begin));
if (0 == str_to_replace.compare("$(CWD)")) {
// Replace our token with the current working directory
if (getcwd(buf, sizeof(buf))) {
if (buf[strlen(buf)-1] == G_DIR_SEPARATOR)
buf[strlen(buf)-1] = '\0';
str_replace_with = buf;
// Replace the first occurrence of our token with the required string
i->erase(token_begin, ((token_end+1)-token_begin));
i->insert(token_begin, str_replace_with);
} else {
error = true;
}
} else if (0 == str_to_replace.compare("$(WINDRIVE)")){
// Replace our token with the drive letter (and colon) for the user's Windows volume
str_replace_with = get_windows_drive_volume_letter();
// Replace the first occurrence of our token with the required string
i->erase(token_begin, ((token_end+1)-token_begin));
i->insert(token_begin, str_replace_with);
} else if (0 == str_to_replace.compare("$(LOCALCACHEDIR)")){
// Replace our token with the path to our Ardour cache directory
str_replace_with = user_cache_directory();
// Replace the first occurrence of our token with the required string
i->erase(token_begin, ((token_end+1)-token_begin));
i->insert(token_begin, str_replace_with);
} else {
// Assume that our token represents an environment variable
std::string envvar_name = str_to_replace.substr(2, str_to_replace.length()-3);
if (const char *envvar_value = getenv(envvar_name.c_str())) {
strcpy(buf, envvar_value);
if (buf[strlen(buf)-1] == G_DIR_SEPARATOR)
buf[strlen(buf)-1] = '\0';
str_replace_with = buf;
// Replace the first occurrence of our token with the required string
i->erase(token_begin, ((token_end+1)-token_begin));
i->insert(token_begin, str_replace_with);
} else {
error = true;
cerr << _("ERROR: unknown environment variable") << endl;
}
}
}
}
}
if (!error) {
file_to_fix.clear (); // Clear the EOF flag etc
file_to_fix.seekg (0, std::ios::beg); // Seek our 'get' ptr to the file start pos
// (our 'put' ptr shouldn't have moved yet).
chsize(fileno (fd), 0); // Truncate the file, ready for re-writing
for (i = lines.begin(); i != lines.end(); ++i) {
// Write the converted contents to our file
file_to_fix << (*i).c_str() << endl;
}
try {
file_to_fix.close();
succeeded = true;
} catch (...) {}
}
} else {
file_to_fix.close();
succeeded = true;
}
} catch (...) {
file_to_fix.close();
succeeded = false;
}
} else {
cerr << _("ERROR: Could not open config file '") << str_file_to_fix << "'" << endl;
}
return succeeded;
}
void
fixup_fonts_config ()
{
string fonts_conf_file;
#ifdef DEBUG
fonts_conf_file = get_module_folder();
if (!fonts_conf_file.empty()) {
fonts_conf_file += "\\";
fonts_conf_file += PROGRAM_NAME;
fonts_conf_file += PROGRAM_VERSION;
fonts_conf_file += FONTS_CONF_LOCATION;
#else
if (PBD::find_file (ARDOUR::ardour_config_search_path(), "fonts.conf", fonts_conf_file)) {
#endif
Glib::setenv ("FONTCONFIG_FILE", fonts_conf_file, true);
if (0 == fixup_config_file (fonts_conf_file))
cerr << _("ERROR: processing error for 'fonts.conf' file") << endl;
} else {
cerr << _("ERROR: Malformed module folder (fonts.conf)") << endl;
}
}
void
fixup_pango_config ()
{
string pango_modules_file;
#if defined(DEBUG) || defined(RDC_BUILD)
// Make sure we pick up the debuggable DLLs !!!
pango_modules_file = get_module_folder();
if (!pango_modules_file.empty()) {
pango_modules_file += "\\";
pango_modules_file += PROGRAM_NAME;
pango_modules_file += PROGRAM_VERSION;
pango_modules_file += PANGO_CONF_LOCATION;
#if 0
// JE - handy for non-English locale testing (Greek, in this case)
Glib::ustring pango_modules_path = Glib::locale_to_utf8("C:\\Program Files\\Mixbus3\\etc\\<5C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>\\pango.modules");
/**/
#else
Glib::ustring pango_modules_path = pango_modules_file;
#endif
pango_modules_path.resize (pango_modules_path.size()-14); // Remove "/pango.modules" from the end
#else
if (PBD::find_file (ARDOUR::ardour_config_search_path(), "pango.modules", pango_modules_file)) {
Glib::ustring pango_modules_path = pango_modules_file;
pango_modules_path.resize (pango_modules_path.size()-14); // Remove "/pango.modules" from the end
#endif
// Set an environment variable so we can find our pango modules. Note
// that this requires a modified version of libpango (pango-utils.c)
Glib::setenv ("PANGO_MODULE_PATH", Glib::filename_from_utf8(pango_modules_path), true);
if (0 == fixup_config_file (pango_modules_file))
cerr << _("ERROR: processing error for 'pango.modules' file") << endl;
} else {
cerr << _("ERROR: Malformed module folder (pango.modules)") << endl;
}
}
void
fixup_pixbuf_loaders_config ()
{
string gdk_pixbuf_loaders_file;
#if defined(DEBUG) || defined(RDC_BUILD)
// Make sure we pick up the debuggable DLLs !!!
gdk_pixbuf_loaders_file = get_module_folder();
if (!gdk_pixbuf_loaders_file.empty()) {
gdk_pixbuf_loaders_file += "\\";
gdk_pixbuf_loaders_file += PROGRAM_NAME;
gdk_pixbuf_loaders_file += PROGRAM_VERSION;
gdk_pixbuf_loaders_file += PIXBUFLOADERS_CONF_LOCATION;
#else
if (PBD::find_file (ARDOUR::ardour_config_search_path(), "gdk-pixbuf.loaders", gdk_pixbuf_loaders_file)) {
#endif
// Set an environment variable so we can find our pixbuf modules.
Glib::setenv ("GDK_PIXBUF_MODULE_FILE", Glib::filename_from_utf8(gdk_pixbuf_loaders_file), true);
if (0 == fixup_config_file (gdk_pixbuf_loaders_file))
cerr << _("ERROR: processing error for 'gdk-pixbuf.loaders' file") << endl;
} else {
cerr << _("ERROR: Malformed module folder (gdk-pixbuf.loaders)") << endl;
}
}
void
fixup_clearlooks_config ()
{
string clearlooks_la_file;
#if defined(DEBUG) || defined(RDC_BUILD)
// Make sure we pick up the debuggable DLLs !!!
clearlooks_la_file = get_module_folder();
if (!clearlooks_la_file.empty()) {
clearlooks_la_file += "\\";
clearlooks_la_file += PROGRAM_NAME;
clearlooks_la_file += PROGRAM_VERSION;
clearlooks_la_file += CLEARLOOKS_CONF_LOCATION;
#else
if (PBD::find_file (ARDOUR::ardour_config_search_path(), "libclearlooks.la", clearlooks_la_file)) {
#endif
// Set an environment variable so we can find our clearlooks engine.
// Note that this requires a modified version of libgtk (gtkthemes.c)
Glib::setenv ("GTK_THEME_ENGINE_FILE", Glib::filename_from_utf8(clearlooks_la_file).c_str(), true);
if (0 == fixup_config_file (clearlooks_la_file))
cerr << _("ERROR: processing error for 'clearlooks.la' file") << endl;
} else {
cerr << _("ERROR: Malformed module folder (clearlooks.la)") << endl;
}
}
void
fixup_bundle_environment (int argc, char* argv[], string & localedir)
{
std::string exec_path = argv[0];
std::string dir_path = Glib::path_get_dirname (exec_path);
// Make sure that our runtime CWD is set to Mixbus's install
// folder, regardless of where the caller's CWD was set to.
g_chdir (dir_path.c_str());
EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true));
// Now set 'dir_path' so we can append some relative paths
dir_path = Glib::path_get_dirname (dir_path);
std::string path;
const char *cstr;
// First, set up 'ARDOUR_DLL_PATH'
path = dir_path;
path += "\\lib\\ardour3\\surfaces;";
path += dir_path;
path += "\\lib\\ardour3\\panners;";
path += dir_path;
path += "\\lib\\ardour3\\backends;";
path += dir_path;
path += "\\bin";
Glib::setenv ("ARDOUR_DLL_PATH", path, true);
// Next, set up 'ARDOUR_DATA_PATH'
path = get_module_folder() + "\\";
path += PROGRAM_NAME;
path += PROGRAM_VERSION;
path += "\\share";
Glib::setenv ("ARDOUR_DATA_PATH", path, true);
// Next, set up 'ARDOUR_CONFIG_PATH'
#ifdef _WIN64
path = user_config_directory() + "\\win64;";
#else
path = user_config_directory() + "\\win32;";
#endif
Glib::setenv ("ARDOUR_CONFIG_PATH", path, true);
// Next, set up 'ARDOUR_INSTANT_XML_PATH'
path = user_config_directory();
Glib::setenv ("ARDOUR_INSTANT_XML_PATH", path, true);
// Next, set up 'LADSPA_PATH'
path = ladspa_search_path().to_string();
Glib::setenv ("LADSPA_PATH", path, true);
// Next, set up 'SUIL_MODULE_DIR'
Glib::setenv ("SUIL_MODULE_DIR", Glib::build_filename(ardour_dll_directory(), "suil"), true);
// Next, set up 'VAMP_PATH'
cstr = getenv ("VAMP_PATH");
if (cstr) {
path = cstr;
path += G_SEARCHPATH_SEPARATOR;
} else {
path = "";
}
path += get_module_folder() + "\\";
path += PROGRAM_NAME;
path += PROGRAM_VERSION;
path += "\\bin\\vamp";
path += G_SEARCHPATH_SEPARATOR;
path += "%ProgramFiles%\\Vamp Plugins";
Glib::setenv ("VAMP_PATH", path, true);
// Next, set up 'ARDOUR_CONTROL_SURFACE_PATH'
cstr = getenv ("ARDOUR_CONTROL_SURFACE_PATH");
if (cstr) {
path = cstr;
path += G_SEARCHPATH_SEPARATOR;
} else {
path = "";
}
path += control_protocol_search_path().to_string();
Glib::setenv ("ARDOUR_CONTROL_SURFACE_PATH", path, true);
// Next, set up 'GTK_LOCALEDIR'
if (ARDOUR::translations_are_enabled ()) {
path = windows_search_path().to_string();
path += "\\locale";
Glib::setenv ("GTK_LOCALEDIR", path, true);
// and return the same path to our caller
localedir = path;
}
// Next, set up 'GTK_PATH'
cstr = getenv ("GTK_PATH");
if (cstr) {
path = cstr;
path += G_SEARCHPATH_SEPARATOR;
} else {
path = "";
}
path += user_config_directory();
path += "\\.gtk-2.0";
Glib::setenv ("GTK_PATH", path, true);
// Unset GTK2_RC_FILES so that we only load the RC files that we define
Glib::unsetenv ("GTK2_RC_FILES");
// and set a '$HOME' environment variable. This variable changes the value returned
// by 'g_get_home_dir()' so to prevent that function from unexpectedly changing its
// mind, we'll set '$HOME' to whatever 'g_get_home_dir()' is already returning!!
if (NULL == getenv("HOME")) {
Glib::setenv ("HOME", Glib::locale_from_utf8(g_get_home_dir()), true);
}
fixup_fonts_config();
fixup_clearlooks_config();
#ifdef DLL_PIXBUF_LOADERS
fixup_pixbuf_loaders_config();
#endif
#ifdef DLL_PANGO_MODULES
fixup_pango_config();
#endif
}
void load_custom_fonts()
{
std::string ardour_mono_file;
if (!find_file (ardour_data_search_path(), "ArdourMono.ttf", ardour_mono_file)) {
cerr << _("Cannot find ArdourMono TrueType font") << endl;
}
FcConfig *config = FcInitLoadConfigAndFonts();
FcBool ret = FcConfigAppFontAddFile(config, reinterpret_cast<const FcChar8*>(ardour_mono_file.c_str()));
if (ret == FcFalse) {
cerr << _("Cannot load ArdourMono TrueType font.") << endl;
}
ret = FcConfigSetCurrent(config);
if (ret == FcFalse) {
cerr << _("Failed to set fontconfig configuration.") << endl;
}
}