#include "terminal.h" namespace Fm { #include #include #include #include #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 allKnownTerminals() { std::vector 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