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.
128 lines
3.3 KiB
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
|