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;
}
示例#2
0
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");
}
示例#3
0
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);
}
示例#6
0
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);
}
示例#8
0
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;
}
示例#10
0
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);
}
示例#11
0
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 */
}
示例#12
0
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);
}
示例#14
0
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;
}
示例#15
0
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);
}
示例#16
0
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 ();
}
示例#17
0
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;
}
示例#20
0
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);
}
示例#21
0
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 */
}
示例#22
0
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 */
}
示例#23
0
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);
}