gboolean terminal_encoding_is_valid (TerminalEncoding *encoding) { /* All of the printing ASCII characters from space (32) to the tilde (126) */ static const char ascii_sample[] = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; char *converted; gsize bytes_read = 0, bytes_written = 0; GError *error = NULL; if (encoding->validity_checked) return encoding->valid; /* Test that the encoding is a proper superset of ASCII (which naive * apps are going to use anyway) by attempting to validate the text * using the current encoding. This also flushes out any encodings * which the underlying GIConv implementation can't support. */ converted = g_convert (ascii_sample, sizeof (ascii_sample) - 1, terminal_encoding_get_charset (encoding), "UTF-8", &bytes_read, &bytes_written, &error); /* The encoding is only valid if ASCII passes through cleanly. */ encoding->valid = (bytes_read == (sizeof (ascii_sample) - 1)) && (converted != NULL) && (strcmp (converted, ascii_sample) == 0); #ifdef GNOME_ENABLE_DEBUG _TERMINAL_DEBUG_IF (TERMINAL_DEBUG_ENCODINGS) { if (!encoding->valid) { _terminal_debug_print (TERMINAL_DEBUG_ENCODINGS, "Rejecting encoding %s as invalid:\n", terminal_encoding_get_charset (encoding)); _terminal_debug_print (TERMINAL_DEBUG_ENCODINGS, " input \"%s\"\n", ascii_sample); _terminal_debug_print (TERMINAL_DEBUG_ENCODINGS, " output \"%s\" bytes read %" G_GSIZE_FORMAT " written %" G_GSIZE_FORMAT "\n", converted ? converted : "(null)", bytes_read, bytes_written); if (error) _terminal_debug_print (TERMINAL_DEBUG_ENCODINGS, " Error: %s\n", error->message); } else _terminal_debug_print (TERMINAL_DEBUG_ENCODINGS, "Encoding %s is valid\n\n", terminal_encoding_get_charset (encoding)); } #endif g_clear_error (&error); g_free (converted); encoding->validity_checked = TRUE; return encoding->valid; }
static void terminal_app_startup (GApplication *application) { const GActionEntry app_menu_actions[] = { { "preferences", app_menu_preferences_cb, NULL, NULL, NULL }, { "help", app_menu_help_cb, NULL, NULL, NULL }, { "about", app_menu_about_cb, NULL, NULL, NULL }, { "quit", app_menu_quit_cb, NULL, NULL, NULL } }; g_application_set_resource_base_path (application, TERMINAL_RESOURCES_PATH_PREFIX); G_APPLICATION_CLASS (terminal_app_parent_class)->startup (application); /* Need to set the WM class (bug #685742) */ gdk_set_program_class("Gnome-terminal"); g_action_map_add_action_entries (G_ACTION_MAP (application), app_menu_actions, G_N_ELEMENTS (app_menu_actions), application); app_load_css (application); _terminal_debug_print (TERMINAL_DEBUG_SERVER, "Startup complete\n"); }
static void name_acquired_cb (GDBusConnection *connection, const char *name, gpointer user_data) { OwnData *data = (OwnData *) user_data; GError *error = NULL; _terminal_debug_print (TERMINAL_DEBUG_FACTORY, "Acquired the name %s on the session bus\n", name); if (data->options == NULL) { /* Name re-acquired!? */ g_assert_not_reached (); } if (!terminal_app_handle_options (terminal_app_get (), data->options, TRUE /* do resume */, &error)) { g_printerr ("Failed to handle options: %s\n", error->message); g_error_free (error); data->exit_code = EXIT_FAILURE; gtk_main_quit (); } terminal_options_free (data->options); data->options = NULL; }
static void terminal_app_startup (GApplication *application) { const GActionEntry app_menu_actions[] = { { "preferences", app_menu_preferences_cb, NULL, NULL, NULL }, { "help", app_menu_help_cb, NULL, NULL, NULL }, { "about", app_menu_about_cb, NULL, NULL, NULL }, { "quit", app_menu_quit_cb, NULL, NULL, NULL } }; gs_unref_object GtkBuilder *builder; GError *error = NULL; G_APPLICATION_CLASS (terminal_app_parent_class)->startup (application); /* Need to set the WM class (bug #685742) */ gdk_set_program_class("Gnome-terminal"); g_action_map_add_action_entries (G_ACTION_MAP (application), app_menu_actions, G_N_ELEMENTS (app_menu_actions), application); builder = gtk_builder_new (); gtk_builder_add_from_resource (builder, TERMINAL_RESOURCES_PATH_PREFIX "ui/terminal-appmenu.ui", &error); g_assert_no_error (error); gtk_application_set_app_menu (GTK_APPLICATION (application), G_MENU_MODEL (gtk_builder_get_object (builder, "appmenu"))); _terminal_debug_print (TERMINAL_DEBUG_SERVER, "Startup complete\n"); }
static void size_allocate_cb (GtkWidget *widget, GdkRectangle *rect, TerminalScreenContainer *container) { _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, "[screen %p] scrolled-window size alloc %d : %d\n", container->priv->screen, rect->width, rect->height); }
static void row_changed (GtkTreeModel *tree_model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data) { _terminal_debug_print (TERMINAL_DEBUG_ACCELS, "ROW-CHANGED [%s]\n", gtk_tree_path_to_string (path) /* leak */); }
static void size_request_cb (GtkWidget *widget, GtkRequisition *req, TerminalScreenContainer *container) { _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, "[screen %p] scrolled-window size req %d : %d\n", container->priv->screen, req->width, req->height); }
static void bus_acquired_cb (GDBusConnection *connection, const char *name, gpointer user_data) { static const char dbus_introspection_xml[] = "<node name='/org/mate/Terminal'>" "<interface name='org.mate.Terminal.Factory'>" "<method name='HandleArguments'>" "<arg type='ay' name='working_directory' direction='in' />" "<arg type='ay' name='display_name' direction='in' />" "<arg type='ay' name='startup_id' direction='in' />" "<arg type='ay' name='environment' direction='in' />" "<arg type='i' name='workspace' direction='in' />" "<arg type='ay' name='arguments' direction='in' />" "</method>" "</interface>" "</node>"; static const GDBusInterfaceVTable interface_vtable = { method_call_cb, NULL, NULL, }; OwnData *data = (OwnData *) user_data; GDBusNodeInfo *introspection_data; guint registration_id; GError *error = NULL; _terminal_debug_print (TERMINAL_DEBUG_FACTORY, "Bus %s acquired\n", name); introspection_data = g_dbus_node_info_new_for_xml (dbus_introspection_xml, NULL); g_assert (introspection_data != NULL); registration_id = g_dbus_connection_register_object (connection, TERMINAL_FACTORY_SERVICE_PATH, introspection_data->interfaces[0], &interface_vtable, NULL, NULL, &error); g_dbus_node_info_unref (introspection_data); if (registration_id == 0) { g_printerr ("Failed to register object: %s\n", error->message); g_error_free (error); data->exit_code = EXIT_FAILURE; gtk_main_quit (); } }
static void ensure_pixbuf_property (TerminalProfile *profile, guint path_prop_id, guint pixbuf_prop_id, gboolean *load_failed) { TerminalProfilePrivate *priv = profile->priv; GValue *path_value, *pixbuf_value; GdkPixbuf *pixbuf; const char *path_utf8; char *path; GError *error = NULL; pixbuf_value = g_value_array_get_nth (priv->properties, pixbuf_prop_id); pixbuf = g_value_get_object (pixbuf_value); if (pixbuf) return; if (*load_failed) return; path_value = g_value_array_get_nth (priv->properties, path_prop_id); path_utf8 = g_value_get_string (path_value); if (!path_utf8 || !path_utf8[0]) goto failed; path = g_filename_from_utf8 (path_utf8, -1, NULL, NULL, NULL); if (!path) goto failed; pixbuf = gdk_pixbuf_new_from_file (path, &error); if (!pixbuf) { _terminal_debug_print (TERMINAL_DEBUG_PROFILE, "Failed to load image \"%s\": %s\n", path, error->message); g_error_free (error); g_free (path); goto failed; } g_value_take_object (pixbuf_value, pixbuf); g_free (path); return; failed: *load_failed = TRUE; }
static void accel_changed_callback (GtkAccelGroup *accel_group, guint keyval, GdkModifierType modifier, GClosure *accel_closure, gpointer data) { /* FIXME because GTK accel API is so nonsensical, we get * a notify for each closure, on both the added and the removed * accelerator. We just use the accel closure to find our * accel entry, then update the value of that entry. * We use an idle function to avoid setting the entry * in GSettings when the accelerator gets removed and then * setting it again when it gets added. */ KeyEntry *key_entry; _terminal_debug_print (TERMINAL_DEBUG_ACCELS, "Changed accel %s closure %p\n", binding_name (keyval, modifier), /* memleak */ accel_closure); if (inside_gsettings_notify) { _terminal_debug_print (TERMINAL_DEBUG_ACCELS, "Ignoring change from gtk because we're inside a GSettings notify\n"); return; } key_entry = accel_closure->data; g_assert (key_entry); key_entry->needs_gsettings_sync = TRUE; if (sync_idle_id == 0) sync_idle_id = g_idle_add (sync_idle_cb, NULL); }
static void maybe_migrate_settings (TerminalApp *app) { #ifdef ENABLE_MIGRATION const char * const argv[] = { TERM_LIBEXECDIR "/gnome-terminal-migration", #ifdef ENABLE_DEBUG "--verbose", #endif NULL }; int status; gs_free_error GError *error = NULL; #endif /* ENABLE_MIGRATION */ guint version; version = g_settings_get_uint (terminal_app_get_global_settings (app), TERMINAL_SETTING_SCHEMA_VERSION); if (version >= TERMINAL_SCHEMA_VERSION) { _terminal_debug_print (TERMINAL_DEBUG_SERVER | TERMINAL_DEBUG_PROFILE, "Schema version is %u, already migrated.\n", version); return; } #ifdef ENABLE_MIGRATION if (!g_spawn_sync (NULL /* our home directory */, (char **) argv, NULL /* envv */, 0, NULL, NULL, NULL, NULL, &status, &error)) { g_printerr ("Failed to migrate settings: %s\n", error->message); return; } if (WIFEXITED (status)) { if (WEXITSTATUS (status) != 0) g_printerr ("Profile migrator exited with status %d\n", WEXITSTATUS (status)); } else { g_printerr ("Profile migrator exited abnormally.\n"); } #else g_settings_set_uint (terminal_app_get_global_settings (app), TERMINAL_SETTING_SCHEMA_VERSION, TERMINAL_SCHEMA_VERSION); #endif /* ENABLE_MIGRATION */ }
static void accel_cleared_callback (GtkCellRendererAccel *cell, gchar *path_string, GtkTreeView *view) { GtkTreeModel *model; GtkTreePath *path; GtkTreeIter iter; KeyEntry *ke; char *str; model = gtk_tree_view_get_model (view); path = gtk_tree_path_new_from_string (path_string); if (!path) return; if (!gtk_tree_model_get_iter (model, &iter, path)) { gtk_tree_path_free (path); return; } gtk_tree_path_free (path); gtk_tree_model_get (model, &iter, KEYVAL_COLUMN, &ke, -1); /* sanity check */ if (ke == NULL) return; ke->gsettings_keyval = 0; ke->gsettings_mask = 0; ke->needs_gsettings_sync = TRUE; str = binding_name (0, 0); _terminal_debug_print (TERMINAL_DEBUG_ACCELS, "Cleared keybinding for GSettings %s", ke->gsettings_key); g_settings_set_string (settings_keybindings, ke->gsettings_key, str); g_free (str); }
static void terminal_profile_notify (GObject *object, GParamSpec *pspec) { TerminalProfilePrivate *priv = TERMINAL_PROFILE (object)->priv; void (* notify) (GObject *, GParamSpec *) = G_OBJECT_CLASS (terminal_profile_parent_class)->notify; _terminal_debug_print (TERMINAL_DEBUG_PROFILE, "Property notification for prop %s\n", pspec->name); if (notify) notify (object, pspec); if (pspec->owner_type == TERMINAL_TYPE_PROFILE && (pspec->flags & G_PARAM_WRITABLE) && g_param_spec_get_qdata (pspec, gsettings_key_quark) != NULL && pspec != priv->gsettings_notification_pspec) terminal_profile_schedule_save (TERMINAL_PROFILE (object), pspec); }
static gboolean sync_idle_cb (gpointer data) { GSettings *changeset; _terminal_debug_print (TERMINAL_DEBUG_ACCELS, "GSettings sync handler\n"); sync_idle_id = 0; changeset = g_settings_new (CONF_KEYS_SCHEMA); g_settings_delay (changeset); g_hash_table_foreach (gsettings_key_to_entry, (GHFunc) add_key_entry_to_changeset, changeset); g_settings_apply(changeset); g_object_unref (changeset); return FALSE; }
static char * get_factory_name_for_display (const char *display_name) { GString *name; const char *p; name = g_string_sized_new (strlen (TERMINAL_FACTORY_SERVICE_NAME_PREFIX) + strlen (display_name) + 1 /* NUL */); g_string_append (name, TERMINAL_FACTORY_SERVICE_NAME_PREFIX); for (p = display_name; *p; ++p) { if (g_ascii_isalnum (*p)) g_string_append_c (name, *p); else g_string_append_c (name, '_'); } _terminal_debug_print (TERMINAL_DEBUG_FACTORY, "Factory name is \"%s\"\n", name->str); return g_string_free (name, FALSE); }
static void name_lost_cb (GDBusConnection *connection, const char *name, gpointer user_data) { OwnData *data = (OwnData *) user_data; GError *error = NULL; char **envv; int i; GVariantBuilder builder; GVariant *value; GString *string; char *s; gsize len; _terminal_debug_print (TERMINAL_DEBUG_FACTORY, "Lost the name %s on the session bus\n", name); /* Couldn't get the connection? No way to continue! */ if (connection == NULL) { data->exit_code = EXIT_FAILURE; gtk_main_quit (); return; } if (data->options == NULL) { /* Already handled */ data->exit_code = EXIT_SUCCESS; gtk_main_quit (); return; } _terminal_debug_print (TERMINAL_DEBUG_FACTORY, "Forwarding arguments to existing instance\n"); g_variant_builder_init (&builder, G_VARIANT_TYPE ("(ayayayayiay)")); g_variant_builder_add (&builder, "@ay", string_to_ay (data->options->default_working_dir)); g_variant_builder_add (&builder, "@ay", string_to_ay (data->options->display_name)); g_variant_builder_add (&builder, "@ay", string_to_ay (data->options->startup_id)); string = g_string_new (NULL); envv = g_get_environ (); for (i = 0; envv[i]; ++i) { if (i > 0) g_string_append_c (string, '\0'); g_string_append (string, envv[i]); } g_strfreev (envv); len = string->len; s = g_string_free (string, FALSE); g_variant_builder_add (&builder, "@ay", g_variant_new_from_data (G_VARIANT_TYPE ("ay"), s, len, TRUE, g_free, s)); g_variant_builder_add (&builder, "@i", g_variant_new_int32 (data->options->initial_workspace)); string = g_string_new (NULL); for (i = 0; i < data->argc; ++i) { if (i > 0) g_string_append_c (string, '\0'); g_string_append (string, data->argv[i]); } len = string->len; s = g_string_free (string, FALSE); g_variant_builder_add (&builder, "@ay", g_variant_new_from_data (G_VARIANT_TYPE ("ay"), s, len, TRUE, g_free, s)); value = g_dbus_connection_call_sync (connection, data->factory_name, TERMINAL_FACTORY_SERVICE_PATH, TERMINAL_FACTORY_INTERFACE_NAME, "HandleArguments", g_variant_builder_end (&builder), G_VARIANT_TYPE ("()"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (value == NULL) { g_printerr ("Failed to forward arguments: %s\n", error->message); g_error_free (error); data->exit_code = EXIT_FAILURE; gtk_main_quit (); } else { g_variant_unref (value); data->exit_code = EXIT_SUCCESS; } terminal_options_free (data->options); data->options = NULL; gtk_main_quit (); }
static void method_call_cb (GDBusConnection *connection, const char *sender, const char *object_path, const char *interface_name, const char *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data) { if (g_strcmp0 (method_name, "HandleArguments") == 0) { TerminalOptions *options = NULL; GVariant *v_wd, *v_display, *v_sid, *v_envv, *v_argv; char *working_directory = NULL, *display_name = NULL, *startup_id = NULL; int initial_workspace = -1; char **envv = NULL, **argv = NULL; int argc; GError *error = NULL; g_variant_get (parameters, "(@ay@ay@ay@ayi@ay)", &v_wd, &v_display, &v_sid, &v_envv, &initial_workspace, &v_argv); working_directory = ay_to_string (v_wd, &error); if (error) goto out; display_name = ay_to_string (v_display, &error); if (error) goto out; startup_id = ay_to_string (v_sid, &error); if (error) goto out; envv = ay_to_strv (v_envv, NULL); argv = ay_to_strv (v_argv, &argc); _terminal_debug_print (TERMINAL_DEBUG_FACTORY, "Factory invoked with working-dir='%s' display='%s' startup-id='%s'" "workspace='%d'\n", working_directory ? working_directory : "(null)", display_name ? display_name : "(null)", startup_id ? startup_id : "(null)", initial_workspace); options = terminal_options_parse (working_directory, display_name, startup_id, envv, TRUE, TRUE, &argc, &argv, &error, NULL); options->initial_workspace = initial_workspace; if (options != NULL) { terminal_app_handle_options (terminal_app_get (), options, FALSE /* no resume */, &error); terminal_options_free (options); } out: g_variant_unref (v_wd); g_free (working_directory); g_variant_unref (v_display); g_free (display_name); g_variant_unref (v_sid); g_free (startup_id); g_variant_unref (v_envv); g_strfreev (envv); g_variant_unref (v_argv); g_strfreev (argv); if (error == NULL) { g_dbus_method_invocation_return_value (invocation, g_variant_new ("()")); } else { g_dbus_method_invocation_return_gerror (invocation, error); g_error_free (error); } } }
static void terminal_profile_gsettings_notify_cb (GSettings *settings, gchar *key, gpointer user_data) { TerminalProfile *profile = TERMINAL_PROFILE (user_data); TerminalProfilePrivate *priv = profile->priv; TerminalProfileClass *klass; GVariant *settings_value; GParamSpec *pspec; GValue value = { 0, }; gboolean equal; gboolean force_set = FALSE; if (!key) return; _terminal_debug_print (TERMINAL_DEBUG_PROFILE, "GSettings notification for key %s [%s]\n", key, g_settings_is_writable (settings, key) ? "writable" : "LOCKED"); klass = TERMINAL_PROFILE_GET_CLASS (profile); pspec = g_hash_table_lookup (klass->gsettings_keys, key); if (!pspec) return; /* ignore unknown keys, for future extensibility */ priv->locked[pspec->param_id] = !g_settings_is_writable (settings, key); settings_value = g_settings_get_value (settings, key); if (!settings_value) return; g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); if (G_IS_PARAM_SPEC_BOOLEAN (pspec)) { if (!g_variant_is_of_type (settings_value, G_VARIANT_TYPE_BOOLEAN)) goto out; g_value_set_boolean (&value, g_variant_get_boolean (settings_value)); } else if (G_IS_PARAM_SPEC_STRING (pspec)) { if (!g_variant_is_of_type (settings_value, G_VARIANT_TYPE_STRING)) goto out; g_value_set_string (&value, g_variant_get_string (settings_value, NULL)); } else if (G_IS_PARAM_SPEC_ENUM (pspec)) { if (!g_variant_is_of_type (settings_value, G_VARIANT_TYPE_STRING)) goto out; g_value_set_enum (&value, g_settings_get_enum (settings, key)); } else if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_COLOR) { GdkColor color; if (!g_variant_is_of_type (settings_value, G_VARIANT_TYPE_STRING)) goto out; if (!gdk_color_parse (g_variant_get_string (settings_value, NULL), &color)) goto out; g_value_set_boxed (&value, &color); } else if (G_PARAM_SPEC_VALUE_TYPE (pspec) == PANGO_TYPE_FONT_DESCRIPTION) { if (!g_variant_is_of_type (settings_value, G_VARIANT_TYPE_STRING)) goto out; g_value_take_boxed (&value, pango_font_description_from_string (g_variant_get_string (settings_value, NULL))); } else if (G_IS_PARAM_SPEC_DOUBLE (pspec)) { if (!g_variant_is_of_type (settings_value, G_VARIANT_TYPE_DOUBLE)) goto out; g_value_set_double (&value, g_variant_get_double (settings_value)); } else if (G_IS_PARAM_SPEC_INT (pspec)) { if (!g_variant_is_of_type (settings_value, G_VARIANT_TYPE_INT16) && !g_variant_is_of_type (settings_value, G_VARIANT_TYPE_INT32) && !g_variant_is_of_type (settings_value, G_VARIANT_TYPE_INT64)) goto out; g_value_set_int (&value, g_settings_get_int(settings, key)); } else if (G_IS_PARAM_SPEC_VALUE_ARRAY (pspec) && G_PARAM_SPEC_VALUE_TYPE (G_PARAM_SPEC_VALUE_ARRAY (pspec)->element_spec) == GDK_TYPE_COLOR) { char **color_strings; GdkColor *colors; int n_colors, i; if (!g_variant_is_of_type (settings_value, G_VARIANT_TYPE_STRING)) goto out; color_strings = g_strsplit (g_variant_get_string (settings_value, NULL), ":", -1); if (!color_strings) goto out; n_colors = g_strv_length (color_strings); colors = g_new0 (GdkColor, n_colors); for (i = 0; i < n_colors; ++i) { if (!gdk_color_parse (color_strings[i], &colors[i])) continue; /* ignore errors */ } g_strfreev (color_strings); /* We continue even with a palette size != TERMINAL_PALETTE_SIZE, * so we can change the palette size in future versions without * causing too many issues. */ set_value_from_palette (&value, colors, n_colors); g_free (colors); } else { g_printerr ("Unhandled value type %s of pspec %s\n", g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)), pspec->name); goto out; } if (g_param_value_validate (pspec, &value)) { _terminal_debug_print (TERMINAL_DEBUG_PROFILE, "Invalid value in GSettings for key %s was changed to comply with pspec %s\n", key, pspec->name); force_set = TRUE; } /* Only set the property if the value is different than our current value, * so we don't go into an infinite loop. */ equal = values_equal (pspec, &value, g_value_array_get_nth (priv->properties, pspec->param_id)); #ifdef MATE_ENABLE_DEBUG _TERMINAL_DEBUG_IF (TERMINAL_DEBUG_PROFILE) { if (!equal) _terminal_debug_print (TERMINAL_DEBUG_PROFILE, "Setting property %s to a different value\n" " now: %s\n" " new: %s\n", pspec->name, g_strdup_value_contents (g_value_array_get_nth (priv->properties, pspec->param_id)), g_strdup_value_contents (&value)); } #endif if (!equal || force_set) { priv->gsettings_notification_pspec = pspec; g_object_set_property (G_OBJECT (profile), pspec->name, &value); priv->gsettings_notification_pspec = NULL; } out: /* FIXME: if we arrive here through goto in the error cases, * should we maybe reset the property to its default value? */ g_value_unset (&value); g_variant_unref (settings_value); }
static void terminal_profile_gsettings_changeset_add (TerminalProfile *profile, GSettings *changeset, GParamSpec *pspec) { TerminalProfilePrivate *priv = profile->priv; char *key; const GValue *value; /* FIXME: do this? */ #if 0 if (priv->locked[pspec->param_id]) return; if (!g_settings_is_writable (priv->settings, gsettings_key, NULL)) return; #endif key = g_param_spec_get_qdata (pspec, gsettings_key_quark); if (!key) return; value = g_value_array_get_nth (priv->properties, pspec->param_id); _terminal_debug_print (TERMINAL_DEBUG_PROFILE, "Adding pspec %s with value %s to the GSettings changeset\n", pspec->name, g_strdup_value_contents (value)); if (G_IS_PARAM_SPEC_BOOLEAN (pspec)) g_settings_set_boolean (changeset, key, g_value_get_boolean (value)); else if (G_IS_PARAM_SPEC_STRING (pspec)) { const char *str; str = g_value_get_string (value); g_settings_set_string (changeset, key, str ? str : ""); } else if (G_IS_PARAM_SPEC_ENUM (pspec)) { const GEnumValue *eval; eval = g_enum_get_value (G_PARAM_SPEC_ENUM (pspec)->enum_class, g_value_get_enum (value)); g_settings_set_enum (changeset, key, eval->value); } else if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_COLOR) { GdkColor *color; char str[16]; color = g_value_get_boxed (value); if (!color) goto cleanup; g_snprintf (str, sizeof (str), "#%04X%04X%04X", color->red, color->green, color->blue); g_settings_set_string (changeset, key, str); } else if (G_PARAM_SPEC_VALUE_TYPE (pspec) == PANGO_TYPE_FONT_DESCRIPTION) { PangoFontDescription *font_desc; char *font; font_desc = g_value_get_boxed (value); if (!font_desc) goto cleanup; font = pango_font_description_to_string (font_desc); g_settings_set_string (changeset, key, font); g_free (font); } else if (G_IS_PARAM_SPEC_DOUBLE (pspec)) g_settings_set_double (changeset, key, g_value_get_double (value)); else if (G_IS_PARAM_SPEC_INT (pspec)) g_settings_set_int (changeset, key, g_value_get_int (value)); else if (G_IS_PARAM_SPEC_VALUE_ARRAY (pspec) && G_PARAM_SPEC_VALUE_TYPE (G_PARAM_SPEC_VALUE_ARRAY (pspec)->element_spec) == GDK_TYPE_COLOR) { GValueArray *array; GString *string; guint n_colors, i; /* We need to do this ourselves, because the gtk_color_selection_palette_to_string * does not carry all the bytes, and xterm's palette is messed up... */ array = g_value_get_boxed (value); if (!array) goto cleanup; n_colors = array->n_values; string = g_string_sized_new (n_colors * (1 /* # */ + 3 * 4) + n_colors /* : separators and terminating \0 */); for (i = 0; i < n_colors; ++i) { GdkColor *color; if (i > 0) g_string_append_c (string, ':'); color = g_value_get_boxed (g_value_array_get_nth (array, i)); if (!color) continue; g_string_append_printf (string, "#%04X%04X%04X", color->red, color->green, color->blue); } g_settings_set_string (changeset, key, string->str); g_string_free (string, TRUE); } else g_printerr ("Unhandled value type %s of pspec %s\n", g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)), pspec->name); cleanup: return; }
static void accel_edited_callback (GtkCellRendererAccel *cell, gchar *path_string, guint keyval, GdkModifierType mask, guint hardware_keycode, GtkTreeView *view) { GtkTreeModel *model; GtkTreePath *path; GtkTreeIter iter; KeyEntry *ke; GtkAccelGroupEntry *entries; guint n_entries; char *str; model = gtk_tree_view_get_model (view); path = gtk_tree_path_new_from_string (path_string); if (!path) return; if (!gtk_tree_model_get_iter (model, &iter, path)) { gtk_tree_path_free (path); return; } gtk_tree_path_free (path); gtk_tree_model_get (model, &iter, KEYVAL_COLUMN, &ke, -1); /* sanity check */ if (ke == NULL) return; /* Check if we already have an entry using this accel */ entries = gtk_accel_group_query (notification_group, keyval, mask, &n_entries); if (n_entries > 0) { if (entries[0].accel_path_quark != g_quark_from_string (ke->accel_path)) { GtkWidget *dialog; char *name; KeyEntry *other_key; name = gtk_accelerator_get_label (keyval, mask); other_key = entries[0].closure->data; g_assert (other_key); dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))), GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("The shortcut key “%s” is already bound to the “%s” action"), name, other_key->user_visible_name ? _(other_key->user_visible_name) : other_key->gsettings_key); g_free (name); g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL); gtk_window_present (GTK_WINDOW (dialog)); } return; } str = binding_name (keyval, mask); _terminal_debug_print (TERMINAL_DEBUG_ACCELS, "Edited path %s keyval %s, setting GSettings to %s\n", ke->accel_path, gdk_keyval_name (keyval) ? gdk_keyval_name (keyval) : "null", str); #ifdef MATE_ENABLE_DEBUG _TERMINAL_DEBUG_IF (TERMINAL_DEBUG_ACCELS) { GtkAccelKey old_key; if (gtk_accel_map_lookup_entry (ke->accel_path, &old_key)) { _terminal_debug_print (TERMINAL_DEBUG_ACCELS, " Old entry of path %s is keyval %s mask %x\n", ke->accel_path, gdk_keyval_name (old_key.accel_key), old_key.accel_mods); } else { _terminal_debug_print (TERMINAL_DEBUG_ACCELS, " Failed to look up the old entry of path %s\n", ke->accel_path); } } #endif g_settings_set_string (settings_keybindings, ke->gsettings_key, str); g_free (str); }
static gboolean terminal_factory_impl_create_instance (TerminalFactory *factory, GDBusMethodInvocation *invocation, GVariant *options) { TerminalApp *app = terminal_app_get (); TerminalSettingsList *profiles_list; GDBusObjectManagerServer *object_manager; TerminalWindow *window; TerminalScreen *screen; TerminalReceiverImpl *impl; TerminalObjectSkeleton *skeleton; char *object_path; GSettings *profile = NULL; const char *profile_uuid, *title, *encoding; gboolean zoom_set = FALSE; gdouble zoom = 1.0; guint window_id; gboolean show_menubar; gboolean active; gboolean have_new_window, present_window, present_window_set; GError *err = NULL; /* Look up the profile */ if (!g_variant_lookup (options, "profile", "&s", &profile_uuid)) profile_uuid = NULL; if (!g_variant_lookup (options, "encoding", "&s", &encoding)) encoding = NULL; /* use profile encoding */ profiles_list = terminal_app_get_profiles_list (app); profile = terminal_profiles_list_ref_profile_by_uuid (profiles_list, profile_uuid, &err); if (profile == NULL) { g_dbus_method_invocation_return_gerror (invocation, err); g_error_free (err); goto out; } if (g_variant_lookup (options, "window-id", "u", &window_id)) { GtkWindow *win; win = gtk_application_get_window_by_id (GTK_APPLICATION (app), window_id); if (!TERMINAL_IS_WINDOW (win)) { g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Nonexisting window %u referenced", window_id); goto out; } window = TERMINAL_WINDOW (win); have_new_window = FALSE; } else { const char *startup_id, *display_name, *role; gboolean start_maximized, start_fullscreen; int screen_number; GdkScreen *gdk_screen; /* Create a new window */ if (!g_variant_lookup (options, "display", "^&ay", &display_name)) { g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "No display specified"); goto out; } screen_number = 0; gdk_screen = terminal_util_get_screen_by_display_name (display_name, screen_number); if (gdk_screen == NULL) { g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "No screen %d on display \"%s\"", screen_number, display_name); goto out; } window = terminal_app_new_window (app, gdk_screen); if (g_variant_lookup (options, "desktop-startup-id", "^&ay", &startup_id)) gtk_window_set_startup_id (GTK_WINDOW (window), startup_id); /* Overwrite the default, unique window role set in terminal_window_init */ if (g_variant_lookup (options, "role", "&s", &role)) gtk_window_set_role (GTK_WINDOW (window), role); if (g_variant_lookup (options, "show-menubar", "b", &show_menubar)) terminal_window_set_menubar_visible (window, show_menubar); if (g_variant_lookup (options, "fullscreen-window", "b", &start_fullscreen) && start_fullscreen) { gtk_window_fullscreen (GTK_WINDOW (window)); } if (g_variant_lookup (options, "maximize-window", "b", &start_maximized) && start_maximized) { gtk_window_maximize (GTK_WINDOW (window)); } have_new_window = TRUE; } g_assert (window != NULL); if (!g_variant_lookup (options, "title", "&s", &title)) title = NULL; if (g_variant_lookup (options, "zoom", "d", &zoom)) zoom_set = TRUE; screen = terminal_screen_new (profile, encoding, NULL, title, NULL, NULL, zoom_set ? zoom : 1.0); terminal_window_add_screen (window, screen, -1); object_path = get_object_path_for_screen (window, screen); g_assert (g_variant_is_object_path (object_path)); skeleton = terminal_object_skeleton_new (object_path); impl = terminal_receiver_impl_new (screen); terminal_object_skeleton_set_receiver (skeleton, TERMINAL_RECEIVER (impl)); g_object_unref (impl); object_manager = terminal_app_get_object_manager (app); g_dbus_object_manager_server_export (object_manager, G_DBUS_OBJECT_SKELETON (skeleton)); g_object_set_data_full (G_OBJECT (screen), RECEIVER_IMPL_SKELETON_DATA_KEY, skeleton, (GDestroyNotify) g_object_unref); g_signal_connect (screen, "destroy", G_CALLBACK (screen_destroy_cb), app); if (g_variant_lookup (options, "active", "b", &active) && active) { terminal_window_switch_screen (window, screen); gtk_widget_grab_focus (GTK_WIDGET (screen)); } if (g_variant_lookup (options, "present-window", "b", &present_window)) present_window_set = TRUE; else present_window_set = FALSE; if (have_new_window) { const char *geometry; if (g_variant_lookup (options, "geometry", "&s", &geometry) && !terminal_window_parse_geometry (window, geometry)) _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, "Invalid geometry string \"%s\"", geometry); } if (have_new_window || (present_window_set && present_window)) gtk_window_present (GTK_WINDOW (window)); terminal_factory_complete_create_instance (factory, invocation, object_path); g_free (object_path); out: if (profile) g_object_unref (profile); return TRUE; /* handled */ }
static gboolean terminal_receiver_impl_exec (TerminalReceiver *receiver, GDBusMethodInvocation *invocation, GUnixFDList *fd_list, GVariant *options, GVariant *arguments) { TerminalReceiverImpl *impl = TERMINAL_RECEIVER_IMPL (receiver); TerminalReceiverImplPrivate *priv = impl->priv; const char *working_directory; gboolean shell; char **exec_argv, **envv; gsize exec_argc; GVariant *fd_array; GError *error; if (priv->screen == NULL) { g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Terminal already closed"); goto out; } if (!g_variant_lookup (options, "cwd", "^&ay", &working_directory)) working_directory = NULL; if (!g_variant_lookup (options, "shell", "b", &shell)) shell = FALSE; if (!g_variant_lookup (options, "environ", "^a&ay", &envv)) envv = NULL; if (!g_variant_lookup (options, "fd-set", "@a(ih)", &fd_array)) fd_array = NULL; /* Check FD passing */ if ((fd_list != NULL) ^ (fd_array != NULL)) { g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Must pass both fd-set options and a FD list"); goto out; } if (fd_list != NULL && fd_array != NULL) { const int *fd_array_data; gsize fd_array_data_len, i; int n_fds; fd_array_data = g_variant_get_fixed_array (fd_array, &fd_array_data_len, 2 * sizeof (int)); n_fds = g_unix_fd_list_get_length (fd_list); for (i = 0; i < fd_array_data_len; i++) { const int fd = fd_array_data[2 * i]; const int idx = fd_array_data[2 * i + 1]; if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO) { g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Passing of std%s not supported", fd == STDIN_FILENO ? "in" : fd == STDOUT_FILENO ? "out" : "err"); goto out; } if (idx < 0 || idx >= n_fds) { g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Handle out of range"); goto out; } } } if (working_directory != NULL) _terminal_debug_print (TERMINAL_DEBUG_SERVER, "CWD is '%s'\n", working_directory); exec_argv = (char **) g_variant_get_bytestring_array (arguments, &exec_argc); error = NULL; if (!terminal_screen_exec (priv->screen, exec_argc > 0 ? exec_argv : NULL, envv, shell, working_directory, fd_list, fd_array, &error)) { g_dbus_method_invocation_take_error (invocation, error); } else { terminal_receiver_complete_exec (receiver, invocation, NULL /* outfdlist */); } g_free (exec_argv); g_free (envv); if (fd_array) g_variant_unref (fd_array); out: return TRUE; /* handled */ }
static void keys_change_notify (GSettings *settings, const gchar *key, gpointer user_data) { GVariant *val; KeyEntry *key_entry; GdkModifierType mask; guint keyval; _terminal_debug_print (TERMINAL_DEBUG_ACCELS, "key %s changed\n", key); val = g_settings_get_value (settings, key); #ifdef MATE_ENABLE_DEBUG _TERMINAL_DEBUG_IF (TERMINAL_DEBUG_ACCELS) { if (val == NULL) _terminal_debug_print (TERMINAL_DEBUG_ACCELS, " changed to be unset\n"); else if (!g_variant_is_of_type (val, G_VARIANT_TYPE_STRING)) _terminal_debug_print (TERMINAL_DEBUG_ACCELS, " changed to non-string value\n"); else _terminal_debug_print (TERMINAL_DEBUG_ACCELS, " changed to \"%s\"\n", g_variant_get_string (val, NULL)); } #endif key_entry = g_hash_table_lookup (gsettings_key_to_entry, key); if (!key_entry) { /* shouldn't really happen, but let's be safe */ _terminal_debug_print (TERMINAL_DEBUG_ACCELS, " WARNING: KeyEntry for changed key not found, bailing out\n"); return; } if (!binding_from_value (val, &keyval, &mask)) { const char *str = g_variant_is_of_type (val, G_VARIANT_TYPE_STRING) ? g_variant_get_string (val, NULL) : NULL; g_printerr ("The value \"%s\" of configuration key %s is not a valid accelerator\n", str ? str : "(null)", key_entry->gsettings_key); return; } key_entry->gsettings_keyval = keyval; key_entry->gsettings_mask = mask; /* Unlock the path, so we can change its accel */ if (!key_entry->accel_path_unlocked) gtk_accel_map_unlock_path (key_entry->accel_path); /* sync over to GTK */ _terminal_debug_print (TERMINAL_DEBUG_ACCELS, "changing path %s to %s\n", key_entry->accel_path, binding_name (keyval, mask)); /* memleak */ inside_gsettings_notify += 1; /* Note that this may return FALSE, e.g. when the entry was already set correctly. */ gtk_accel_map_change_entry (key_entry->accel_path, keyval, mask, TRUE); inside_gsettings_notify -= 1; /* Lock the path if the GSettings key isn't writable */ key_entry->accel_path_unlocked = g_settings_is_writable (settings, key); if (!key_entry->accel_path_unlocked) gtk_accel_map_lock_path (key_entry->accel_path); /* This seems necessary to update the tree model, since sometimes the * notification on the notification_group seems not to be emitted correctly. * Without this change, when trying to set an accel to e.g. Alt-T (while the main * menu in the terminal windows is _Terminal with Alt-T mnemonic) only displays * the accel change after a re-expose of the row. * FIXME: Find out *why* the accel-changed signal is wrong here! */ if (edit_keys_store) gtk_tree_model_foreach (GTK_TREE_MODEL (edit_keys_store), update_model_foreach, key_entry); g_variant_unref(val); }