/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2012 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see .
*
* Written by:
* Jasper St. Pierre
*/
#include "config.h"
#include "gnome-initial-setup.h"
#include
#include
#include
#ifdef HAVE_WEBKITGTK_6_0
#include
#else
#include
#endif
#include "cc-common-language.h"
#include "gis-assistant.h"
#define GIS_TYPE_DRIVER_MODE (gis_driver_mode_get_type ())
/* Statically include this for now. Maybe later
* we'll generate this from glib-mkenums. */
GType
gis_driver_mode_get_type (void) {
static GType enum_type_id = 0;
if (G_UNLIKELY (!enum_type_id))
{
static const GEnumValue values[] = {
{ GIS_DRIVER_MODE_NEW_USER, "GIS_DRIVER_MODE_NEW_USER", "new_user" },
{ GIS_DRIVER_MODE_EXISTING_USER, "GIS_DRIVER_MODE_EXISTING_USER", "existing_user" },
{ 0, NULL, NULL }
};
enum_type_id = g_enum_register_static("GisDriverMode", values);
}
return enum_type_id;
}
enum {
REBUILD_PAGES,
LOCALE_CHANGED,
LAST_SIGNAL,
};
static guint signals[LAST_SIGNAL];
typedef enum {
PROP_MODE = 1,
PROP_USERNAME,
PROP_SMALL_SCREEN,
PROP_PARENTAL_CONTROLS_ENABLED,
PROP_FULL_NAME,
PROP_AVATAR,
} GisDriverProperty;
static GParamSpec *obj_props[PROP_AVATAR + 1];
struct _GisDriver {
AdwApplication parent_instance;
GtkWindow *main_window;
GisAssistant *assistant;
GdmClient *client;
GdmGreeter *greeter;
GdmUserVerifier *user_verifier;
ActUser *user_account;
gchar *user_password;
ActUser *parent_account; /* (owned) (nullable) */
gchar *parent_password; /* (owned) (nullable) */
gboolean parental_controls_enabled;
gchar *lang_id;
gchar *username;
gchar *full_name; /* (owned) (nullable) */
GdkPaintable *avatar; /* (owned) (nullable) */
GisDriverMode mode;
UmAccountMode account_mode;
gboolean small_screen;
locale_t locale;
const gchar *vendor_conf_file_path;
GKeyFile *vendor_conf_file;
};
G_DEFINE_TYPE (GisDriver, gis_driver, ADW_TYPE_APPLICATION)
static void
gis_driver_dispose (GObject *object)
{
GisDriver *driver = GIS_DRIVER (object);
g_clear_object (&driver->user_verifier);
g_clear_object (&driver->greeter);
g_clear_object (&driver->client);
G_OBJECT_CLASS (gis_driver_parent_class)->dispose (object);
}
static void
gis_driver_finalize (GObject *object)
{
GisDriver *driver = GIS_DRIVER (object);
g_free (driver->lang_id);
g_free (driver->username);
g_free (driver->full_name);
g_free (driver->user_password);
g_clear_object (&driver->avatar);
g_clear_object (&driver->user_account);
g_clear_pointer (&driver->vendor_conf_file, g_key_file_free);
g_clear_object (&driver->parent_account);
g_free (driver->parent_password);
if (driver->locale != (locale_t) 0)
{
uselocale (LC_GLOBAL_LOCALE);
freelocale (driver->locale);
}
G_OBJECT_CLASS (gis_driver_parent_class)->finalize (object);
}
static void
assistant_page_changed (GtkScrolledWindow *sw)
{
gtk_adjustment_set_value (gtk_scrolled_window_get_vadjustment (sw), 0);
}
static void
prepare_main_window (GisDriver *driver)
{
GtkWidget *child, *sw;
child = gtk_window_get_child (GTK_WINDOW (driver->main_window));
g_object_ref (child);
gtk_window_set_child (GTK_WINDOW (driver->main_window), NULL);
sw = gtk_scrolled_window_new ();
gtk_window_set_child (GTK_WINDOW (driver->main_window), sw);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child);
g_object_unref (child);
g_signal_connect_swapped (driver->assistant,
"page-changed",
G_CALLBACK (assistant_page_changed),
sw);
gtk_window_set_titlebar (driver->main_window,
gis_assistant_get_titlebar (driver->assistant));
}
static void
rebuild_pages (GisDriver *driver)
{
g_signal_emit (G_OBJECT (driver), signals[REBUILD_PAGES], 0);
}
GisAssistant *
gis_driver_get_assistant (GisDriver *driver)
{
return driver->assistant;
}
static void
gis_driver_locale_changed (GisDriver *driver)
{
GtkTextDirection direction;
direction = gtk_get_locale_direction ();
gtk_widget_set_default_direction (direction);
rebuild_pages (driver);
gis_assistant_locale_changed (driver->assistant);
g_signal_emit (G_OBJECT (driver), signals[LOCALE_CHANGED], 0);
}
void
gis_driver_set_user_language (GisDriver *driver, const gchar *lang_id, gboolean update_locale)
{
g_free (driver->lang_id);
driver->lang_id = g_strdup (lang_id);
cc_common_language_set_current_language (lang_id);
if (update_locale)
{
locale_t locale = newlocale (LC_MESSAGES_MASK, lang_id, (locale_t) 0);
if (locale == (locale_t) 0)
{
g_warning ("Failed to create locale %s: %s", lang_id, g_strerror (errno));
return;
}
uselocale (locale);
if (driver->locale != (locale_t) 0 && driver->locale != LC_GLOBAL_LOCALE)
freelocale (driver->locale);
driver->locale = locale;
gis_driver_locale_changed (driver);
}
}
const gchar *
gis_driver_get_user_language (GisDriver *driver)
{
return driver->lang_id;
}
void
gis_driver_set_username (GisDriver *driver, const gchar *username)
{
g_free (driver->username);
driver->username = g_strdup (username);
g_object_notify (G_OBJECT (driver), "username");
}
const gchar *
gis_driver_get_username (GisDriver *driver)
{
return driver->username;
}
/**
* gis_driver_set_full_name:
* @driver: a #GisDriver
* @full_name: (nullable): full name of the main user, or %NULL if not known
*
* Set the #GisDriver:full-name property.
*
* Since: 3.36
*/
void
gis_driver_set_full_name (GisDriver *driver,
const gchar *full_name)
{
g_return_if_fail (GIS_IS_DRIVER (driver));
g_return_if_fail (full_name == NULL ||
g_utf8_validate (full_name, -1, NULL));
if (g_strcmp0 (driver->full_name, full_name) == 0)
return;
g_free (driver->full_name);
driver->full_name = g_strdup (full_name);
g_object_notify_by_pspec (G_OBJECT (driver), obj_props[PROP_FULL_NAME]);
}
/**
* gis_driver_get_full_name:
* @driver: a #GisDriver
*
* Get the #GisDriver:full-name property.
*
* Returns: (nullable): full name of the main user, or %NULL if not known
* Since: 3.36
*/
const gchar *
gis_driver_get_full_name (GisDriver *driver)
{
g_return_val_if_fail (GIS_IS_DRIVER (driver), NULL);
return driver->full_name;
}
/**
* gis_driver_set_avatar:
* @driver: a #GisDriver
* @avatar: (nullable) (transfer none): avatar of the main user, or %NULL if not known
*
* Set the #GisDriver:avatar property.
*
* Since: 3.36
*/
void
gis_driver_set_avatar (GisDriver *driver,
GdkPaintable *avatar)
{
g_return_if_fail (GIS_IS_DRIVER (driver));
g_return_if_fail (avatar == NULL || GDK_IS_PAINTABLE (avatar));
if (g_set_object (&driver->avatar, avatar))
g_object_notify_by_pspec (G_OBJECT (driver), obj_props[PROP_AVATAR]);
}
/**
* gis_driver_get_avatar:
* @driver: a #GisDriver
*
* Get the #GisDriver:avatar property.
*
* Returns: (nullable) (transfer none): avatar of the main user, or %NULL if not known
* Since: 3.36
*/
GdkPaintable *
gis_driver_get_avatar (GisDriver *driver)
{
g_return_val_if_fail (GIS_IS_DRIVER (driver), NULL);
return driver->avatar;
}
void
gis_driver_set_user_permissions (GisDriver *driver,
ActUser *user,
const gchar *password)
{
g_set_object (&driver->user_account, user);
g_free (driver->user_password);
driver->user_password = g_strdup (password);
}
void
gis_driver_get_user_permissions (GisDriver *driver,
ActUser **user,
const gchar **password)
{
if (user != NULL)
*user = driver->user_account;
if (password != NULL)
*password = driver->user_password;
}
/**
* gis_driver_set_parent_permissions:
* @driver: a #GisDriver
* @parent: (transfer none): user account for the parent
* @password: password for the parent
*
* Stores the parent account details for later use when saving the initial setup
* data.
*
* Since: 3.36
*/
void
gis_driver_set_parent_permissions (GisDriver *driver,
ActUser *parent,
const gchar *password)
{
g_set_object (&driver->parent_account, parent);
g_free (driver->parent_password);
driver->parent_password = g_strdup (password);
}
/**
* gis_driver_get_parent_permissions:
* @driver: a #GisDriver
* @parent: (out) (transfer none) (optional) (nullable): return location for the
* user account for the parent, which may be %NULL
* @password: (out) (transfer none) (optional) (nullable): return location for
* the password for the parent
*
* Gets the parent account details saved from an earlier step in the initial
* setup process. They may be %NULL if not set yet.
*
* Since: 3.36
*/
void
gis_driver_get_parent_permissions (GisDriver *driver,
ActUser **parent,
const gchar **password)
{
if (parent != NULL)
*parent = driver->parent_account;
if (password != NULL)
*password = driver->parent_password;
}
void
gis_driver_set_account_mode (GisDriver *driver,
UmAccountMode mode)
{
driver->account_mode = mode;
}
UmAccountMode
gis_driver_get_account_mode (GisDriver *driver)
{
return driver->account_mode;
}
/**
* gis_driver_set_parental_controls_enabled:
* @driver: a #GisDriver
* @parental_controls_enabled: whether parental controls are enabled for the main user
*
* Set the #GisDriver:parental-controls-enabled property.
*
* Since: 3.36
*/
void
gis_driver_set_parental_controls_enabled (GisDriver *driver,
gboolean parental_controls_enabled)
{
if (driver->parental_controls_enabled == parental_controls_enabled)
return;
driver->parental_controls_enabled = parental_controls_enabled;
rebuild_pages (driver);
g_object_notify_by_pspec (G_OBJECT (driver), obj_props[PROP_PARENTAL_CONTROLS_ENABLED]);
}
/**
* gis_driver_get_parental_controls_enabled:
* @driver: a #GisDriver
*
* Get the #GisDriver:parental-controls-enabled property.
*
* Returns: whether parental controls are enabled for the main user
* Since: 3.36
*/
gboolean
gis_driver_get_parental_controls_enabled (GisDriver *driver)
{
return driver->parental_controls_enabled;
}
gboolean
gis_driver_get_gdm_objects (GisDriver *driver,
GdmGreeter **greeter,
GdmUserVerifier **user_verifier)
{
if (driver->greeter == NULL || driver->user_verifier == NULL)
return FALSE;
*greeter = driver->greeter;
*user_verifier = driver->user_verifier;
return TRUE;
}
void
gis_driver_add_page (GisDriver *driver,
GisPage *page)
{
gis_assistant_add_page (driver->assistant, page);
}
void
gis_driver_hide_window (GisDriver *driver)
{
gtk_widget_hide (GTK_WIDGET (driver->main_window));
}
static gboolean
load_vendor_conf_file_at_path (GisDriver *driver,
const char *path)
{
g_autoptr(GError) error = NULL;
g_autoptr(GKeyFile) vendor_conf_file = g_key_file_new ();
if (!g_key_file_load_from_file (vendor_conf_file, path, G_KEY_FILE_NONE, &error))
{
if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
g_warning ("Could not read file %s: %s:", path, error->message);
return FALSE;
}
driver->vendor_conf_file_path = path;
driver->vendor_conf_file = g_steal_pointer (&vendor_conf_file);
return TRUE;
}
static void
load_vendor_conf_file (GisDriver *driver)
{
#ifdef VENDOR_CONF_FILE
load_vendor_conf_file_at_path (driver, VENDOR_CONF_FILE);
#else
/* If no path was passed at build time, then we have search path:
*
* - First check $(sysconfdir)/gnome-initial-setup/vendor.conf
* - Then check $(datadir)/gnome-initial-setup/vendor.conf
*
* This allows distributions to provide a default packaged config in a
* location that might be managed by ostree, and allows OEMs to
* override using an unmanaged location.
*/
if (!load_vendor_conf_file_at_path (driver, PKGSYSCONFDIR "/vendor.conf"))
load_vendor_conf_file_at_path (driver, PKGDATADIR "/vendor.conf");
#endif
}
static void
report_conf_error_if_needed (GisDriver *driver,
const gchar *group,
const gchar *key,
const GError *error)
{
if (!g_error_matches (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND) &&
!g_error_matches (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND))
g_warning ("Error getting the value for key '%s' of group [%s] in %s: %s",
group, key, driver->vendor_conf_file_path, error->message);
}
gboolean
gis_driver_conf_get_boolean (GisDriver *driver,
const gchar *group,
const gchar *key,
gboolean default_value)
{
if (driver->vendor_conf_file) {
g_autoptr(GError) error = NULL;
gboolean new_value = g_key_file_get_boolean (driver->vendor_conf_file, group,
key, &error);
if (error == NULL)
return new_value;
report_conf_error_if_needed (driver, group, key, error);
}
return default_value;
}
GStrv
gis_driver_conf_get_string_list (GisDriver *driver,
const gchar *group,
const gchar *key,
gsize *out_length)
{
if (driver->vendor_conf_file) {
g_autoptr(GError) error = NULL;
GStrv new_value = g_key_file_get_string_list (driver->vendor_conf_file, group,
key, out_length, &error);
if (error == NULL)
return new_value;
report_conf_error_if_needed (driver, group, key, error);
}
return NULL;
}
gchar *
gis_driver_conf_get_string (GisDriver *driver,
const gchar *group,
const gchar *key)
{
if (driver->vendor_conf_file) {
g_autoptr(GError) error = NULL;
gchar *new_value = g_key_file_get_string (driver->vendor_conf_file, group,
key, &error);
if (error == NULL)
return new_value;
report_conf_error_if_needed (driver, group, key, error);
}
return NULL;
}
GisDriverMode
gis_driver_get_mode (GisDriver *driver)
{
return driver->mode;
}
gboolean
gis_driver_is_small_screen (GisDriver *driver)
{
return driver->small_screen;
}
static gboolean
monitor_is_small (GdkMonitor *monitor)
{
GdkRectangle geom;
if (g_getenv ("GIS_SMALL_SCREEN"))
return TRUE;
gdk_monitor_get_geometry (monitor, &geom);
return geom.height < 800;
}
static void
gis_driver_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GisDriver *driver = GIS_DRIVER (object);
switch ((GisDriverProperty) prop_id)
{
case PROP_MODE:
g_value_set_enum (value, driver->mode);
break;
case PROP_USERNAME:
g_value_set_string (value, driver->username);
break;
case PROP_SMALL_SCREEN:
g_value_set_boolean (value, driver->small_screen);
break;
case PROP_PARENTAL_CONTROLS_ENABLED:
g_value_set_boolean (value, driver->parental_controls_enabled);
break;
case PROP_FULL_NAME:
g_value_set_string (value, driver->full_name);
break;
case PROP_AVATAR:
g_value_set_object (value, driver->avatar);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gis_driver_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GisDriver *driver = GIS_DRIVER (object);
switch ((GisDriverProperty) prop_id)
{
case PROP_MODE:
driver->mode = g_value_get_enum (value);
break;
case PROP_USERNAME:
g_free (driver->username);
driver->username = g_value_dup_string (value);
break;
case PROP_PARENTAL_CONTROLS_ENABLED:
gis_driver_set_parental_controls_enabled (driver, g_value_get_boolean (value));
break;
case PROP_FULL_NAME:
gis_driver_set_full_name (driver, g_value_get_string (value));
break;
case PROP_AVATAR:
gis_driver_set_avatar (driver, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gis_driver_activate (GApplication *app)
{
GisDriver *driver = GIS_DRIVER (app);
G_APPLICATION_CLASS (gis_driver_parent_class)->activate (app);
gtk_window_present (GTK_WINDOW (driver->main_window));
}
/* Recompute driver->small_screen based on the monitor where the window is
* located, if the window is actually realized. If not, recompute it based on
* the primary monitor of the default display. */
static void
recompute_small_screen (GisDriver *driver)
{
GdkMonitor *active_monitor;
gboolean old_value = driver->small_screen;
if (gtk_widget_get_realized (GTK_WIDGET (driver->main_window)))
{
GdkDisplay *default_display = gdk_display_get_default ();
GdkSurface *surface;
surface = gtk_native_get_surface (GTK_NATIVE (driver->main_window));
active_monitor = gdk_display_get_monitor_at_surface (default_display, surface);
driver->small_screen = monitor_is_small (active_monitor);
}
if (driver->small_screen != old_value)
g_object_notify (G_OBJECT (driver), "small-screen");
}
static void
update_screen_size (GisDriver *driver)
{
GtkWidget *sw;
recompute_small_screen (driver);
if (!gtk_widget_get_realized (GTK_WIDGET (driver->main_window)))
return;
sw = gtk_window_get_child (GTK_WINDOW (driver->main_window));
if (driver->small_screen)
{
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_window_set_default_size (driver->main_window, -1, -1);
gtk_window_set_resizable (driver->main_window, TRUE);
gtk_window_maximize (driver->main_window);
gtk_window_present (driver->main_window);
}
else
{
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_NEVER,
GTK_POLICY_NEVER);
gtk_window_set_default_size (driver->main_window, 1024, 768);
gtk_window_set_resizable (driver->main_window, FALSE);
gtk_window_unmaximize (driver->main_window);
gtk_window_present (driver->main_window);
}
}
static void
on_surface_enter_monitor_cb (GdkSurface *surface,
GdkMonitor *monitor,
GisDriver *driver)
{
update_screen_size (driver);
}
static void
window_realize_cb (GtkWidget *widget, gpointer user_data)
{
GdkSurface *surface;
GisDriver *driver;
driver = GIS_DRIVER (user_data);
surface = gtk_native_get_surface (GTK_NATIVE (widget));
g_signal_connect (surface, "enter-monitor", G_CALLBACK (on_surface_enter_monitor_cb), driver);
update_screen_size (driver);
}
static void
connect_to_gdm (GisDriver *driver)
{
g_autoptr(GError) error = NULL;
driver->client = gdm_client_new ();
driver->greeter = gdm_client_get_greeter_sync (driver->client, NULL, &error);
if (error == NULL)
driver->user_verifier = gdm_client_get_user_verifier_sync (driver->client, NULL, &error);
if (error != NULL) {
g_warning ("Failed to open connection to GDM: %s", error->message);
g_clear_object (&driver->user_verifier);
g_clear_object (&driver->greeter);
g_clear_object (&driver->client);
}
}
static void
gis_driver_startup (GApplication *app)
{
GisDriver *driver = GIS_DRIVER (app);
WebKitWebContext *context = webkit_web_context_get_default ();
G_APPLICATION_CLASS (gis_driver_parent_class)->startup (app);
webkit_web_context_set_sandbox_enabled (context, TRUE);
if (driver->mode == GIS_DRIVER_MODE_NEW_USER)
connect_to_gdm (driver);
driver->main_window = g_object_new (GTK_TYPE_APPLICATION_WINDOW,
"application", app,
"icon-name", "preferences-system",
"deletable", FALSE,
NULL);
g_signal_connect (driver->main_window,
"realize",
G_CALLBACK (window_realize_cb),
(gpointer)app);
driver->assistant = g_object_new (GIS_TYPE_ASSISTANT, NULL);
gtk_window_set_child (GTK_WINDOW (driver->main_window),
GTK_WIDGET (driver->assistant));
gis_driver_set_user_language (driver, setlocale (LC_MESSAGES, NULL), FALSE);
prepare_main_window (driver);
rebuild_pages (driver);
}
static void
gis_driver_init (GisDriver *driver)
{
load_vendor_conf_file (driver);
}
static void
gis_driver_class_init (GisDriverClass *klass)
{
GApplicationClass *application_class = G_APPLICATION_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = gis_driver_get_property;
gobject_class->set_property = gis_driver_set_property;
gobject_class->dispose = gis_driver_dispose;
gobject_class->finalize = gis_driver_finalize;
application_class->startup = gis_driver_startup;
application_class->activate = gis_driver_activate;
signals[REBUILD_PAGES] =
g_signal_new ("rebuild-pages",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 0);
signals[LOCALE_CHANGED] =
g_signal_new ("locale-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 0);
obj_props[PROP_MODE] =
g_param_spec_enum ("mode", "", "",
GIS_TYPE_DRIVER_MODE,
GIS_DRIVER_MODE_EXISTING_USER,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
obj_props[PROP_USERNAME] =
g_param_spec_string ("username", "", "",
NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
obj_props[PROP_SMALL_SCREEN] =
g_param_spec_boolean ("small-screen", "", "",
FALSE,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
/**
* GisDriver:parental-controls-enabled:
*
* Whether parental controls are enabled for the main user. If this is %TRUE,
* two user accounts will be created when this page is saved: one for the main
* user (a child) which will be a standard account; and one for the parent
* which will be an administrative account.
*
* Since: 3.36
*/
obj_props[PROP_PARENTAL_CONTROLS_ENABLED] =
g_param_spec_boolean ("parental-controls-enabled",
"Parental Controls Enabled",
"Whether parental controls are enabled for the main user.",
FALSE,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
/**
* GisDriver:full-name: (nullable)
*
* Full name of the main user. May be %NULL if unknown or not set yet.
*
* Since: 3.36
*/
obj_props[PROP_FULL_NAME] =
g_param_spec_string ("full-name",
"Full Name",
"Full name of the main user.",
NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
/**
* GisDriver:avatar: (nullable)
*
* Avatar of the main user. May be %NULL if unknown or not set yet.
*
* Since: 3.36
*/
obj_props[PROP_AVATAR] =
g_param_spec_object ("avatar",
"Avatar",
"Avatar of the main user.",
GDK_TYPE_PAINTABLE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_properties (gobject_class, G_N_ELEMENTS (obj_props), obj_props);
}
gboolean
gis_driver_save_data (GisDriver *driver,
GError **error)
{
if (gis_get_mock_mode ())
{
g_message ("%s: Skipping saving data due to being in mock mode", G_STRFUNC);
return TRUE;
}
return gis_assistant_save_data (driver->assistant, error);
}
GisDriver *
gis_driver_new (GisDriverMode mode)
{
return g_object_new (GIS_TYPE_DRIVER,
"application-id", "org.gnome.InitialSetup",
"mode", mode,
NULL);
}