You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libfm-qt-packaging/src/core/terminal.cpp

128 lines
3.3 KiB

#include "terminal.h"
namespace Fm {
#include <glib.h>
#include <gio/gdesktopappinfo.h>
#include <string.h>
#include <unistd.h>
#if !GLIB_CHECK_VERSION(2, 28, 0) && !HAVE_DECL_ENVIRON
extern char** environ;
#endif
static void child_setup(gpointer user_data) {
/* Move child to grandparent group so it will not die with parent */
setpgid(0, (pid_t)(gsize)user_data);
}
bool launchTerminal(const char* programName, const FilePath& workingDir, Fm::GErrorPtr& error) {
/* read system terminals file */
GKeyFile* kf = g_key_file_new();
if(!g_key_file_load_from_file(kf, LIBFM_QT_DATA_DIR "/terminals.list", G_KEY_FILE_NONE, &error)) {
g_key_file_free(kf);
return false;
}
auto launch = g_key_file_get_string(kf, programName, "launch", nullptr);
auto desktop_id = g_key_file_get_string(kf, programName, "desktop_id", nullptr);
GDesktopAppInfo* appinfo = nullptr;
if(desktop_id) {
appinfo = g_desktop_app_info_new(desktop_id);
}
const gchar* cmd;
gchar* _cmd = nullptr;
if(appinfo) {
cmd = g_app_info_get_commandline(G_APP_INFO(appinfo));
}
else if(launch) {
cmd = _cmd = g_strdup_printf("%s %s", programName, launch);
}
else {
cmd = programName;
}
#if 0 // FIXME: what's this?
if(custom_args) {
cmd = g_strdup_printf("%s %s", cmd, custom_args);
g_free(_cmd);
_cmd = (char*)cmd;
}
#endif
char** argv;
int argc;
if(!g_shell_parse_argv(cmd, &argc, &argv, nullptr)) {
argv = nullptr;
}
g_free(_cmd);
if(appinfo) {
g_object_unref(appinfo);
}
if(!argv) { /* parsing failed */
return false;
}
char** envp;
#if GLIB_CHECK_VERSION(2, 28, 0)
envp = g_get_environ();
#else
envp = g_strdupv(environ);
#endif
auto dir = workingDir ? workingDir.localPath() : nullptr;
if(dir) {
#if GLIB_CHECK_VERSION(2, 32, 0)
envp = g_environ_setenv(envp, "PWD", dir.get(), TRUE);
#else
char** env = envp;
if(env) while(*env != nullptr) {
if(strncmp(*env, "PWD=", 4) == 0) {
break;
}
env++;
}
if(env == nullptr || *env == nullptr) {
gint length;
length = envp ? g_strv_length(envp) : 0;
envp = g_renew(gchar*, envp, length + 2);
env = &envp[length];
env[1] = nullptr;
}
else {
g_free(*env);
}
*env = g_strdup_printf("PWD=%s", dir);
#endif
}
bool ret = g_spawn_async(dir.get(), argv, envp, G_SPAWN_SEARCH_PATH,
child_setup, (gpointer)(gsize)getpgid(getppid()),
nullptr, &error);
g_strfreev(argv);
g_strfreev(envp);
g_key_file_free(kf);
return ret;
}
std::vector<CStrPtr> allKnownTerminals() {
std::vector<CStrPtr> terminals;
GKeyFile* kf = g_key_file_new();
if(g_key_file_load_from_file(kf, LIBFM_QT_DATA_DIR "/terminals.list", G_KEY_FILE_NONE, nullptr)) {
gsize n;
auto programs = g_key_file_get_groups(kf, &n);
terminals.reserve(n);
for(auto name = programs; *name; ++name) {
terminals.emplace_back(*name);
}
g_free(programs);
}
g_key_file_free(kf);
return terminals;
}
} // namespace Fm