|
Packit |
d370c2 |
/*
|
|
Packit |
d370c2 |
* Copyright © 2001, 2002 Havoc Pennington
|
|
Packit |
d370c2 |
* Copyright © 2002 Red Hat, Inc.
|
|
Packit |
d370c2 |
* Copyright © 2002 Sun Microsystems
|
|
Packit |
d370c2 |
* Copyright © 2003 Mariano Suarez-Alvarez
|
|
Packit |
d370c2 |
* Copyright © 2008, 2010, 2011 Christian Persch
|
|
Packit |
d370c2 |
*
|
|
Packit |
d370c2 |
* This program is free software: you can redistribute it and/or modify
|
|
Packit |
d370c2 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
d370c2 |
* the Free Software Foundation, either version 3 of the License, or
|
|
Packit |
d370c2 |
* (at your option) any later version.
|
|
Packit |
d370c2 |
*
|
|
Packit |
d370c2 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
d370c2 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
d370c2 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
d370c2 |
* GNU General Public License for more details.
|
|
Packit |
d370c2 |
*
|
|
Packit |
d370c2 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
d370c2 |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
d370c2 |
*/
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
#include "config.h"
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
#include <errno.h>
|
|
Packit |
d370c2 |
#include <locale.h>
|
|
Packit |
d370c2 |
#include <stdlib.h>
|
|
Packit |
d370c2 |
#include <time.h>
|
|
Packit |
d370c2 |
#include <unistd.h>
|
|
Packit |
d370c2 |
#include <sys/wait.h>
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
#include <glib.h>
|
|
Packit |
d370c2 |
#include <glib/gstdio.h>
|
|
Packit |
d370c2 |
#include <gio/gio.h>
|
|
Packit |
d370c2 |
#include <glib/gi18n.h>
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
#include <gtk/gtk.h>
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
#include "terminal-debug.h"
|
|
Packit |
d370c2 |
#include "terminal-defines.h"
|
|
Packit |
d370c2 |
#include "terminal-i18n.h"
|
|
Packit |
d370c2 |
#include "terminal-options.h"
|
|
Packit |
d370c2 |
#include "terminal-gdbus-generated.h"
|
|
Packit |
d370c2 |
#include "terminal-defines.h"
|
|
Packit |
d370c2 |
#include "terminal-client-utils.h"
|
|
Packit |
d370c2 |
#include "terminal-libgsystem.h"
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
GS_DEFINE_CLEANUP_FUNCTION0(TerminalOptions*, gs_local_options_free, terminal_options_free)
|
|
Packit |
d370c2 |
#define gs_free_options __attribute__ ((cleanup(gs_local_options_free)))
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
/* Wait-for-exit helper */
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
typedef struct {
|
|
Packit |
d370c2 |
GMainLoop *loop;
|
|
Packit |
d370c2 |
int status;
|
|
Packit |
d370c2 |
} RunData;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
static void
|
|
Packit |
d370c2 |
receiver_child_exited_cb (TerminalReceiver *receiver,
|
|
Packit |
d370c2 |
int status,
|
|
Packit |
d370c2 |
RunData *data)
|
|
Packit |
d370c2 |
{
|
|
Packit |
d370c2 |
data->status = status;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
if (g_main_loop_is_running (data->loop))
|
|
Packit |
d370c2 |
g_main_loop_quit (data->loop);
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
static int
|
|
Packit |
d370c2 |
run_receiver (TerminalReceiver *receiver)
|
|
Packit |
d370c2 |
{
|
|
Packit |
d370c2 |
RunData data = { g_main_loop_new (NULL, FALSE), 0 };
|
|
Packit |
d370c2 |
gulong id = g_signal_connect (receiver, "child-exited",
|
|
Packit |
d370c2 |
G_CALLBACK (receiver_child_exited_cb), &data);
|
|
Packit |
d370c2 |
g_main_loop_run (data.loop);
|
|
Packit |
d370c2 |
g_signal_handler_disconnect (receiver, id);
|
|
Packit |
d370c2 |
g_main_loop_unref (data.loop);
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
/* Mangle the exit status */
|
|
Packit |
d370c2 |
int exit_code;
|
|
Packit |
d370c2 |
if (WIFEXITED (data.status))
|
|
Packit |
d370c2 |
exit_code = WEXITSTATUS (data.status);
|
|
Packit |
d370c2 |
else if (WIFSIGNALED (data.status))
|
|
Packit |
d370c2 |
exit_code = 128 + (int) WTERMSIG (data.status);
|
|
Packit |
d370c2 |
else if (WCOREDUMP (data.status))
|
|
Packit |
d370c2 |
exit_code = 127;
|
|
Packit |
d370c2 |
else
|
|
Packit |
d370c2 |
exit_code = 127;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
return exit_code;
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
/* Factory helpers */
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
static gboolean
|
|
Packit |
d370c2 |
get_factory_exit_status (const char *service_name,
|
|
Packit |
d370c2 |
const char *message,
|
|
Packit |
d370c2 |
int *exit_status)
|
|
Packit |
d370c2 |
{
|
|
Packit |
d370c2 |
gs_free char *pattern = NULL, *number = NULL;
|
|
Packit |
d370c2 |
gs_unref_regex GRegex *regex = NULL;
|
|
Packit |
d370c2 |
gs_free_match_info GMatchInfo *match_info = NULL;
|
|
Packit |
d370c2 |
gint64 v;
|
|
Packit |
d370c2 |
char *end;
|
|
Packit |
d370c2 |
GError *err = NULL;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
pattern = g_strdup_printf ("org.freedesktop.DBus.Error.Spawn.ChildExited: Process %s exited with status (\\d+)$",
|
|
Packit |
d370c2 |
service_name);
|
|
Packit |
d370c2 |
regex = g_regex_new (pattern, 0, 0, &err;;
|
|
Packit |
d370c2 |
g_assert_no_error (err);
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
if (!g_regex_match (regex, message, 0, &match_info))
|
|
Packit |
d370c2 |
return FALSE;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
number = g_match_info_fetch (match_info, 1);
|
|
Packit |
d370c2 |
g_assert_nonnull (number);
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
errno = 0;
|
|
Packit |
d370c2 |
v = g_ascii_strtoll (number, &end, 10);
|
|
Packit |
d370c2 |
if (errno || end == number || *end != '\0' || v < 0 || v > G_MAXINT)
|
|
Packit |
d370c2 |
return FALSE;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
*exit_status = (int)v;
|
|
Packit |
d370c2 |
return TRUE;
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
static gboolean
|
|
Packit |
d370c2 |
handle_factory_error (const char *service_name,
|
|
Packit |
d370c2 |
GError *error)
|
|
Packit |
d370c2 |
{
|
|
Packit |
d370c2 |
int exit_status;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
if (!g_dbus_error_is_remote_error (error) ||
|
|
Packit |
d370c2 |
!g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_CHILD_EXITED) ||
|
|
Packit |
d370c2 |
!get_factory_exit_status (service_name, error->message, &exit_status))
|
|
Packit |
d370c2 |
return FALSE;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
g_dbus_error_strip_remote_error (error);
|
|
Packit |
d370c2 |
terminal_printerr ("%s\n\n", error->message);
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
switch (exit_status) {
|
|
Packit |
d370c2 |
case _EXIT_FAILURE_WRONG_ID:
|
|
Packit |
d370c2 |
terminal_printerr ("You tried to run gnome-terminal-server with elevated privileged. This is not supported.\n");
|
|
Packit |
d370c2 |
break;
|
|
Packit |
d370c2 |
case _EXIT_FAILURE_NO_UTF8:
|
|
Packit |
d370c2 |
terminal_printerr ("The environment that gnome-terminal-server was launched with specified a non-UTF-8 locale. This is not supported.\n");
|
|
Packit |
d370c2 |
break;
|
|
Packit |
d370c2 |
case _EXIT_FAILURE_UNSUPPORTED_LOCALE:
|
|
Packit |
d370c2 |
terminal_printerr ("The environment that gnome-terminal-server was launched with specified an unsupported locale.\n");
|
|
Packit |
d370c2 |
break;
|
|
Packit |
d370c2 |
case _EXIT_FAILURE_GTK_INIT:
|
|
Packit |
d370c2 |
terminal_printerr ("The environment that gnome-terminal-server was launched with most likely contained an incorrect or unset \"DISPLAY\" variable.\n");
|
|
Packit |
d370c2 |
break;
|
|
Packit |
d370c2 |
default:
|
|
Packit |
d370c2 |
break;
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
terminal_printerr ("See https://wiki.gnome.org/Apps/Terminal/FAQ#Exit_status_%d for more information.\n", exit_status);
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
return TRUE;
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
static gboolean
|
|
Packit |
d370c2 |
handle_create_instance_error (const char *service_name,
|
|
Packit |
d370c2 |
GError *error)
|
|
Packit |
d370c2 |
{
|
|
Packit |
d370c2 |
if (handle_factory_error (service_name, error))
|
|
Packit |
d370c2 |
return TRUE;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
g_dbus_error_strip_remote_error (error);
|
|
Packit |
d370c2 |
terminal_printerr ("Error creating terminal: %s\n", error->message);
|
|
Packit |
d370c2 |
return FALSE; /* don't abort */
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
static gboolean
|
|
Packit |
d370c2 |
handle_create_receiver_proxy_error (const char *service_name,
|
|
Packit |
d370c2 |
GError *error)
|
|
Packit |
d370c2 |
{
|
|
Packit |
d370c2 |
if (handle_factory_error (service_name, error))
|
|
Packit |
d370c2 |
return TRUE;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
g_dbus_error_strip_remote_error (error);
|
|
Packit |
d370c2 |
terminal_printerr ("Failed to create proxy for terminal: %s\n", error->message);
|
|
Packit |
d370c2 |
return FALSE; /* don't abort */
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
static gboolean
|
|
Packit |
d370c2 |
handle_exec_error (const char *service_name,
|
|
Packit |
d370c2 |
GError *error)
|
|
Packit |
d370c2 |
{
|
|
Packit |
d370c2 |
if (handle_factory_error (service_name, error))
|
|
Packit |
d370c2 |
return TRUE;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
g_dbus_error_strip_remote_error (error);
|
|
Packit |
d370c2 |
terminal_printerr ("Error: %s\n", error->message);
|
|
Packit |
d370c2 |
return FALSE; /* don't abort */
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
static gboolean
|
|
Packit |
d370c2 |
factory_proxy_new_for_service_name (const char *service_name,
|
|
Packit |
d370c2 |
gboolean ping_server,
|
|
Packit |
d370c2 |
TerminalFactory **factory_ptr,
|
|
Packit |
d370c2 |
char **service_name_ptr,
|
|
Packit |
d370c2 |
GError **error)
|
|
Packit |
d370c2 |
{
|
|
Packit |
d370c2 |
if (service_name == NULL)
|
|
Packit |
d370c2 |
service_name = TERMINAL_APPLICATION_ID;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
gs_free_error GError *err = NULL;
|
|
Packit |
d370c2 |
gs_unref_object TerminalFactory *factory =
|
|
Packit |
d370c2 |
terminal_factory_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
|
|
Packit |
d370c2 |
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
|
|
Packit |
d370c2 |
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
|
|
Packit |
d370c2 |
service_name,
|
|
Packit |
d370c2 |
TERMINAL_FACTORY_OBJECT_PATH,
|
|
Packit |
d370c2 |
NULL /* cancellable */,
|
|
Packit |
d370c2 |
&err;;
|
|
Packit |
d370c2 |
if (factory == NULL) {
|
|
Packit |
d370c2 |
if (!handle_factory_error (service_name, err))
|
|
Packit |
d370c2 |
terminal_printerr ("Error constructing proxy for %s:%s: %s\n",
|
|
Packit |
d370c2 |
service_name, TERMINAL_FACTORY_OBJECT_PATH, err->message);
|
|
Packit |
d370c2 |
g_propagate_error (error, err);
|
|
Packit |
d370c2 |
err = NULL;
|
|
Packit |
d370c2 |
return FALSE;
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
if (ping_server) {
|
|
Packit |
d370c2 |
/* If we try to use the environment specified server, we need to make
|
|
Packit |
d370c2 |
* sure it actually exists so we can later fall back to the default name.
|
|
Packit |
d370c2 |
* There doesn't appear to a way to fail proxy creation above if the
|
|
Packit |
d370c2 |
* unique name doesn't exist; so we do it this way.
|
|
Packit |
d370c2 |
*/
|
|
Packit |
d370c2 |
gs_unref_variant GVariant *v = g_dbus_proxy_call_sync (G_DBUS_PROXY (factory),
|
|
Packit |
d370c2 |
"org.freedesktop.DBus.Peer.Ping",
|
|
Packit |
d370c2 |
g_variant_new ("()"),
|
|
Packit |
d370c2 |
G_DBUS_CALL_FLAGS_NONE,
|
|
Packit |
d370c2 |
1000 /* 1s */,
|
|
Packit |
d370c2 |
NULL /* cancelleable */,
|
|
Packit |
d370c2 |
&err;;
|
|
Packit |
d370c2 |
if (v == NULL) {
|
|
Packit |
d370c2 |
g_propagate_error (error, err);
|
|
Packit |
d370c2 |
err = NULL;
|
|
Packit |
d370c2 |
return FALSE;
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
gs_transfer_out_value (factory_ptr, &factory);
|
|
Packit |
d370c2 |
*service_name_ptr = g_strdup (service_name);
|
|
Packit |
d370c2 |
return TRUE;
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
static gboolean
|
|
Packit |
d370c2 |
factory_proxy_new (TerminalOptions *options,
|
|
Packit |
d370c2 |
TerminalFactory **factory_ptr,
|
|
Packit |
d370c2 |
char **service_name_ptr,
|
|
Packit |
d370c2 |
char **parent_screen_object_path_ptr,
|
|
Packit |
d370c2 |
GError **error)
|
|
Packit |
d370c2 |
{
|
|
Packit |
d370c2 |
const char *service_name = options->server_app_id;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
/* If --app-id was specified, or the environment does not specify
|
|
Packit |
d370c2 |
* the server to use, create the factory proxy from the given (or default)
|
|
Packit |
d370c2 |
* name, with no fallback.
|
|
Packit |
d370c2 |
*
|
|
Packit |
d370c2 |
* If the server specified by the environment doesn't exist, fall back to the
|
|
Packit |
d370c2 |
* default server, and ignore the environment-specified parent screen.
|
|
Packit |
d370c2 |
*/
|
|
Packit |
d370c2 |
if (options->server_app_id == NULL &&
|
|
Packit |
d370c2 |
options->server_unique_name != NULL) {
|
|
Packit |
d370c2 |
gs_free_error GError *err = NULL;
|
|
Packit |
d370c2 |
if (factory_proxy_new_for_service_name (options->server_unique_name,
|
|
Packit |
d370c2 |
TRUE,
|
|
Packit |
d370c2 |
factory_ptr,
|
|
Packit |
d370c2 |
service_name_ptr,
|
|
Packit |
d370c2 |
&err)) {
|
|
Packit |
d370c2 |
*parent_screen_object_path_ptr = g_strdup (options->parent_screen_object_path);
|
|
Packit |
d370c2 |
return TRUE;
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
terminal_printerr ("Failed to use specified server: %s\n",
|
|
Packit |
d370c2 |
err->message);
|
|
Packit |
d370c2 |
terminal_printerr ("Falling back to default server.\n");
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
/* Fall back to the default */
|
|
Packit |
d370c2 |
service_name = NULL;
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
*parent_screen_object_path_ptr = NULL;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
return factory_proxy_new_for_service_name (service_name,
|
|
Packit |
d370c2 |
FALSE,
|
|
Packit |
d370c2 |
factory_ptr,
|
|
Packit |
d370c2 |
service_name_ptr,
|
|
Packit |
d370c2 |
error);
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
static void
|
|
Packit |
d370c2 |
handle_show_preferences (const char *service_name)
|
|
Packit |
d370c2 |
{
|
|
Packit |
d370c2 |
gs_free_error GError *error = NULL;
|
|
Packit |
d370c2 |
gs_unref_object GDBusConnection *bus = NULL;
|
|
Packit |
d370c2 |
gs_free char *object_path = NULL;
|
|
Packit |
d370c2 |
GVariantBuilder builder;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
|
|
Packit |
d370c2 |
if (bus == NULL) {
|
|
Packit |
d370c2 |
terminal_printerr ("Failed to get session bus: %s\n", error->message);
|
|
Packit |
d370c2 |
return;
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
/* For reasons (!?), the org.gtk.Actions interface's object path
|
|
Packit |
d370c2 |
* is derived from the service name, i.e. for service name
|
|
Packit |
d370c2 |
* "foo.bar.baz" the object path is "/foo/bar/baz".
|
|
Packit |
d370c2 |
* This means that without the name (like when given only the unique name),
|
|
Packit |
d370c2 |
* we cannot activate the action.
|
|
Packit |
d370c2 |
*/
|
|
Packit |
d370c2 |
if (g_dbus_is_unique_name(service_name)) {
|
|
Packit |
d370c2 |
terminal_printerr ("Cannot call this function from within gnome-terminal.\n");
|
|
Packit |
d370c2 |
return;
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
object_path = g_strdelimit (g_strdup_printf (".%s", service_name), ".", '/');
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
g_variant_builder_init (&builder, G_VARIANT_TYPE ("(sava{sv})"));
|
|
Packit |
d370c2 |
g_variant_builder_add (&builder, "s", "preferences");
|
|
Packit |
d370c2 |
g_variant_builder_open (&builder, G_VARIANT_TYPE ("av"));
|
|
Packit |
d370c2 |
g_variant_builder_close (&builder);
|
|
Packit |
d370c2 |
g_variant_builder_open (&builder, G_VARIANT_TYPE ("a{sv}"));
|
|
Packit |
d370c2 |
g_variant_builder_close (&builder);
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
if (!g_dbus_connection_call_sync (bus,
|
|
Packit |
d370c2 |
service_name,
|
|
Packit |
d370c2 |
object_path,
|
|
Packit |
d370c2 |
"org.gtk.Actions",
|
|
Packit |
d370c2 |
"Activate",
|
|
Packit |
d370c2 |
g_variant_builder_end (&builder),
|
|
Packit |
d370c2 |
G_VARIANT_TYPE ("()"),
|
|
Packit |
d370c2 |
G_DBUS_CALL_FLAGS_NO_AUTO_START,
|
|
Packit |
d370c2 |
30 * 1000 /* ms timeout */,
|
|
Packit |
d370c2 |
NULL /* cancelleable */,
|
|
Packit |
d370c2 |
&error)) {
|
|
Packit |
d370c2 |
terminal_printerr ("Activate call failed: %s\n", error->message);
|
|
Packit |
d370c2 |
return;
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
/**
|
|
Packit |
d370c2 |
* handle_options:
|
|
Packit |
d370c2 |
* @app:
|
|
Packit |
d370c2 |
* @options: a #TerminalOptions
|
|
Packit |
d370c2 |
* @allow_resume: whether to merge the terminal configuration from the
|
|
Packit |
d370c2 |
* saved session on resume
|
|
Packit |
d370c2 |
* @wait_for_receiver: location to store the #TerminalReceiver to wait for
|
|
Packit |
d370c2 |
*
|
|
Packit |
d370c2 |
* Processes @options. It loads or saves the terminal configuration, or
|
|
Packit |
d370c2 |
* opens the specified windows and tabs.
|
|
Packit |
d370c2 |
*
|
|
Packit |
d370c2 |
* Returns: %TRUE if @options could be successfully handled, or %FALSE on
|
|
Packit |
d370c2 |
* error
|
|
Packit |
d370c2 |
*/
|
|
Packit |
d370c2 |
static gboolean
|
|
Packit |
d370c2 |
handle_options (TerminalOptions *options,
|
|
Packit |
d370c2 |
TerminalFactory *factory,
|
|
Packit |
d370c2 |
const char *service_name,
|
|
Packit |
d370c2 |
const char *parent_screen_object_path,
|
|
Packit |
d370c2 |
TerminalReceiver **wait_for_receiver)
|
|
Packit |
d370c2 |
{
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
/* We need to forward the locale encoding to the server, see bug #732128 */
|
|
Packit |
d370c2 |
const char *encoding;
|
|
Packit |
d370c2 |
g_get_charset (&encoding);
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
if (options->show_preferences) {
|
|
Packit |
d370c2 |
handle_show_preferences (service_name);
|
|
Packit |
d370c2 |
} else {
|
|
Packit |
d370c2 |
/* Make sure we open at least one window */
|
|
Packit |
d370c2 |
terminal_options_ensure_window (options);
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
const char *factory_unique_name = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (factory));
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
for (GList *lw = options->initial_windows; lw != NULL; lw = lw->next)
|
|
Packit |
d370c2 |
{
|
|
Packit |
d370c2 |
InitialWindow *iw = lw->data;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
g_assert_nonnull (iw);
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
guint window_id = 0;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
gs_free char *previous_screen_object_path = NULL;
|
|
Packit |
d370c2 |
if (iw->implicit_first_window)
|
|
Packit |
d370c2 |
previous_screen_object_path = g_strdup (parent_screen_object_path);
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
/* Now add the tabs */
|
|
Packit |
d370c2 |
for (GList *lt = iw->tabs; lt != NULL; lt = lt->next)
|
|
Packit |
d370c2 |
{
|
|
Packit |
d370c2 |
InitialTab *it = lt->data;
|
|
Packit |
d370c2 |
g_assert_nonnull (it);
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
GVariantBuilder builder;
|
|
Packit |
d370c2 |
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
terminal_client_append_create_instance_options (&builder,
|
|
Packit |
d370c2 |
options->display_name,
|
|
Packit |
d370c2 |
options->startup_id,
|
|
Packit |
d370c2 |
iw->geometry,
|
|
Packit |
d370c2 |
iw->role,
|
|
Packit |
d370c2 |
it->profile ? it->profile : options->default_profile,
|
|
Packit |
d370c2 |
encoding,
|
|
Packit |
d370c2 |
it->title ? it->title : options->default_title,
|
|
Packit |
d370c2 |
it->active,
|
|
Packit |
d370c2 |
iw->start_maximized,
|
|
Packit |
d370c2 |
iw->start_fullscreen);
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
/* This will be used to apply missing defaults */
|
|
Packit |
d370c2 |
if (parent_screen_object_path != NULL)
|
|
Packit |
d370c2 |
g_variant_builder_add (&builder, "{sv}",
|
|
Packit |
d370c2 |
"parent-screen", g_variant_new_object_path (parent_screen_object_path));
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
/* This will be used to get the parent window */
|
|
Packit |
d370c2 |
if (previous_screen_object_path)
|
|
Packit |
d370c2 |
g_variant_builder_add (&builder, "{sv}",
|
|
Packit |
d370c2 |
"window-from-screen", g_variant_new_object_path (previous_screen_object_path));
|
|
Packit |
d370c2 |
if (window_id)
|
|
Packit |
d370c2 |
g_variant_builder_add (&builder, "{sv}",
|
|
Packit |
d370c2 |
"window-id", g_variant_new_uint32 (window_id));
|
|
Packit |
d370c2 |
/* Restored windows shouldn't demand attention; see bug #586308. */
|
|
Packit |
d370c2 |
if (iw->source_tag == SOURCE_SESSION)
|
|
Packit |
d370c2 |
g_variant_builder_add (&builder, "{sv}",
|
|
Packit |
d370c2 |
"present-window", g_variant_new_boolean (FALSE));
|
|
Packit |
d370c2 |
if (options->zoom_set || it->zoom_set)
|
|
Packit |
d370c2 |
g_variant_builder_add (&builder, "{sv}",
|
|
Packit |
d370c2 |
"zoom", g_variant_new_double (it->zoom_set ? it->zoom : options->zoom));
|
|
Packit |
d370c2 |
if (iw->force_menubar_state)
|
|
Packit |
d370c2 |
g_variant_builder_add (&builder, "{sv}",
|
|
Packit |
d370c2 |
"show-menubar", g_variant_new_boolean (iw->menubar_state));
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
gs_free_error GError *err = NULL;
|
|
Packit |
d370c2 |
gs_free char *object_path = NULL;
|
|
Packit |
d370c2 |
if (!terminal_factory_call_create_instance_sync
|
|
Packit |
d370c2 |
(factory,
|
|
Packit |
d370c2 |
g_variant_builder_end (&builder),
|
|
Packit |
d370c2 |
&object_path,
|
|
Packit |
d370c2 |
NULL /* cancellable */,
|
|
Packit |
d370c2 |
&err)) {
|
|
Packit |
d370c2 |
if (handle_create_instance_error (service_name, err))
|
|
Packit |
d370c2 |
return FALSE;
|
|
Packit |
d370c2 |
else
|
|
Packit |
d370c2 |
continue; /* Continue processing the remaining options! */
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
/* Deprecated and not working on new server anymore */
|
|
Packit |
d370c2 |
char *p = strstr (object_path, "/window/");
|
|
Packit |
d370c2 |
if (p) {
|
|
Packit |
d370c2 |
char *end = NULL;
|
|
Packit |
d370c2 |
guint64 value;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
errno = 0;
|
|
Packit |
d370c2 |
p += strlen ("/window/");
|
|
Packit |
d370c2 |
value = g_ascii_strtoull (p, &end, 10);
|
|
Packit |
d370c2 |
if (errno == 0 && end != p && *end == '/')
|
|
Packit |
d370c2 |
window_id = (guint) value;
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
g_free (previous_screen_object_path);
|
|
Packit |
d370c2 |
previous_screen_object_path = g_strdup (object_path);
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
gs_unref_object TerminalReceiver *receiver =
|
|
Packit |
d370c2 |
terminal_receiver_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
|
|
Packit |
d370c2 |
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
|
|
Packit |
d370c2 |
(it->wait ? 0 : G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS),
|
|
Packit |
d370c2 |
factory_unique_name,
|
|
Packit |
d370c2 |
object_path,
|
|
Packit |
d370c2 |
NULL /* cancellable */,
|
|
Packit |
d370c2 |
&err;;
|
|
Packit |
d370c2 |
if (receiver == NULL) {
|
|
Packit |
d370c2 |
if (handle_create_receiver_proxy_error (service_name, err))
|
|
Packit |
d370c2 |
return FALSE;
|
|
Packit |
d370c2 |
else
|
|
Packit |
d370c2 |
continue; /* Continue processing the remaining options! */
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
char **argv = it->exec_argv ? it->exec_argv : options->exec_argv;
|
|
Packit |
d370c2 |
int argc = argv ? g_strv_length (argv) : 0;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
PassFdElement *fd_array = it->fd_array ? (PassFdElement*)it->fd_array->data : NULL;
|
|
Packit |
d370c2 |
gsize fd_array_len = it->fd_array ? it->fd_array->len : 0;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
terminal_client_append_exec_options (&builder,
|
|
Packit |
d370c2 |
it->working_dir ? it->working_dir
|
|
Packit |
d370c2 |
: options->default_working_dir,
|
|
Packit |
d370c2 |
fd_array, fd_array_len,
|
|
Packit |
d370c2 |
argc == 0);
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
if (!terminal_receiver_call_exec_sync (receiver,
|
|
Packit |
d370c2 |
g_variant_builder_end (&builder),
|
|
Packit |
d370c2 |
g_variant_new_bytestring_array ((const char * const *) argv, argc),
|
|
Packit |
d370c2 |
it->fd_list, NULL /* outfdlist */,
|
|
Packit |
d370c2 |
NULL /* cancellable */,
|
|
Packit |
d370c2 |
&err)) {
|
|
Packit |
d370c2 |
if (handle_exec_error (service_name, err))
|
|
Packit |
d370c2 |
return FALSE;
|
|
Packit |
d370c2 |
else
|
|
Packit |
d370c2 |
continue; /* Continue processing the remaining options! */
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
if (it->wait)
|
|
Packit |
d370c2 |
gs_transfer_out_value (wait_for_receiver, &receiver);
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
if (options->print_environment)
|
|
Packit |
d370c2 |
g_print ("%s=%s\n", TERMINAL_ENV_SCREEN, object_path);
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
return TRUE;
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
int
|
|
Packit |
d370c2 |
main (int argc, char **argv)
|
|
Packit |
d370c2 |
{
|
|
Packit |
d370c2 |
int exit_code = EXIT_FAILURE;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
#if GLIB_CHECK_VERSION (2, 50, 0)
|
|
Packit |
d370c2 |
g_log_set_writer_func (terminal_log_writer, NULL, NULL);
|
|
Packit |
d370c2 |
#endif
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
g_set_prgname ("gnome-terminal");
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
setlocale (LC_ALL, "");
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
terminal_i18n_init (TRUE);
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
_terminal_debug_init ();
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
/* Make a NULL-terminated copy since we may need it later */
|
|
Packit |
d370c2 |
gs_free char **argv_copy = g_new (char *, argc + 1);
|
|
Packit |
d370c2 |
int i;
|
|
Packit |
d370c2 |
for (i = 0; i < argc; ++i)
|
|
Packit |
d370c2 |
argv_copy [i] = argv [i];
|
|
Packit |
d370c2 |
argv_copy [i] = NULL;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
gs_free_error GError *error = NULL;
|
|
Packit |
d370c2 |
gs_free_options TerminalOptions *options = terminal_options_parse (&argc, &argv, &error);
|
|
Packit |
d370c2 |
if (options == NULL) {
|
|
Packit |
d370c2 |
terminal_printerr (_("Failed to parse arguments: %s\n"), error->message);
|
|
Packit |
d370c2 |
return exit_code;
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
g_set_application_name (_("Terminal"));
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
gs_unref_object TerminalFactory *factory = NULL;
|
|
Packit |
d370c2 |
gs_free char *service_name = NULL;
|
|
Packit |
d370c2 |
gs_free char *parent_screen_object_path = NULL;
|
|
Packit |
d370c2 |
if (!factory_proxy_new (options,
|
|
Packit |
d370c2 |
&factory,
|
|
Packit |
d370c2 |
&service_name,
|
|
Packit |
d370c2 |
&parent_screen_object_path,
|
|
Packit |
d370c2 |
&error))
|
|
Packit |
d370c2 |
return exit_code;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
if (options->print_environment) {
|
|
Packit |
d370c2 |
const char *name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (factory));
|
|
Packit |
d370c2 |
if (name_owner != NULL)
|
|
Packit |
d370c2 |
g_print ("%s=%s\n", TERMINAL_ENV_SERVICE_NAME, name_owner);
|
|
Packit |
d370c2 |
else
|
|
Packit |
d370c2 |
return exit_code;
|
|
Packit |
d370c2 |
}
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
TerminalReceiver *receiver = NULL;
|
|
Packit |
d370c2 |
if (!handle_options (options, factory, service_name, parent_screen_object_path, &receiver))
|
|
Packit |
d370c2 |
return exit_code;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
if (receiver != NULL) {
|
|
Packit |
d370c2 |
exit_code = run_receiver (receiver);
|
|
Packit |
d370c2 |
g_object_unref (receiver);
|
|
Packit |
d370c2 |
} else
|
|
Packit |
d370c2 |
exit_code = EXIT_SUCCESS;
|
|
Packit |
d370c2 |
|
|
Packit |
d370c2 |
return exit_code;
|
|
Packit |
d370c2 |
}
|