gnome-control-center/panels/info/cc-info-panel.c
Giovanni Campagna 4d80e47776 system info: set related mime types when changing preferred apps
Setting the preferred music or video app only changed the handler
for ogg audio/video, leaving an inconsistent state where the previous
(system default) app would be used for other images, audio and video
formats.
Instead make it so that when the user changes his preferences,
the application becomes the default for all mime types in the same
group that it supports.
Nothing changes if configuration is modified externally (e.g.
by hand or through nautilus): expose as preferred app the one that
is configured to handle the primary content type.

https://bugzilla.gnome.org/show_bug.cgi?id=674084
2012-08-24 19:50:21 +02:00

2034 lines
59 KiB
C

/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2010 Red Hat, Inc
* Copyright (C) 2008 William Jon McCann <jmccann@redhat.com>
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#include <config.h>
#include "cc-info-panel.h"
#include <polkit/polkit.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <gio/gio.h>
#include <gio/gunixmounts.h>
#include <gio/gdesktopappinfo.h>
#include <glibtop/fsusage.h>
#include <glibtop/mountlist.h>
#include <glibtop/mem.h>
#include <glibtop/sysinfo.h>
#include "hostname-helper.h"
#include "gsd-disk-space-helper.h"
/* Autorun options */
#define PREF_MEDIA_AUTORUN_NEVER "autorun-never"
#define PREF_MEDIA_AUTORUN_X_CONTENT_START_APP "autorun-x-content-start-app"
#define PREF_MEDIA_AUTORUN_X_CONTENT_IGNORE "autorun-x-content-ignore"
#define PREF_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER "autorun-x-content-open-folder"
#define CUSTOM_ITEM_ASK "cc-item-ask"
#define CUSTOM_ITEM_DO_NOTHING "cc-item-do-nothing"
#define CUSTOM_ITEM_OPEN_FOLDER "cc-item-open-folder"
#define MEDIA_HANDLING_SCHEMA "org.gnome.desktop.media-handling"
/* Session */
#define GNOME_SESSION_MANAGER_SCHEMA "org.gnome.desktop.session"
#define KEY_SESSION_NAME "session-name"
#define WID(w) (GtkWidget *) gtk_builder_get_object (self->priv->builder, w)
CC_PANEL_REGISTER (CcInfoPanel, cc_info_panel)
#define INFO_PANEL_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_INFO_PANEL, CcInfoPanelPrivate))
typedef struct {
/* Will be one of the other two below, or "Unknown" */
const char *hardware_string;
char *xorg_vesa_hardware;
char *glx_renderer;
} GraphicsData;
typedef enum {
PK_NOT_AVAILABLE,
UPDATES_AVAILABLE,
UPDATES_NOT_AVAILABLE,
CHECKING_UPDATES
} UpdatesState;
typedef struct
{
const char *content_type;
const char *label;
/* A pattern used to filter supported mime types
when changing preferred applications. NULL
means no other types should be changed */
const char *extra_type_filter;
} DefaultAppData;
struct _CcInfoPanelPrivate
{
GtkBuilder *builder;
char *gnome_version;
char *gnome_distributor;
char *gnome_date;
UpdatesState updates_state;
gboolean is_fallback;
/* Free space */
GList *primary_mounts;
guint64 total_bytes;
GCancellable *cancellable;
/* Media */
GSettings *media_settings;
GtkWidget *other_application_combo;
GDBusConnection *session_bus;
GDBusProxy *pk_proxy;
GDBusProxy *pk_transaction_proxy;
GDBusProxy *hostnamed_proxy;
GSettings *session_settings;
GraphicsData *graphics_data;
};
static void get_primary_disc_info_start (CcInfoPanel *self);
static void refresh_update_button (CcInfoPanel *self);
typedef struct
{
char *major;
char *minor;
char *micro;
char *distributor;
char *date;
char **current;
} VersionData;
static void
version_start_element_handler (GMarkupParseContext *ctx,
const char *element_name,
const char **attr_names,
const char **attr_values,
gpointer user_data,
GError **error)
{
VersionData *data = user_data;
if (g_str_equal (element_name, "platform"))
data->current = &data->major;
else if (g_str_equal (element_name, "minor"))
data->current = &data->minor;
else if (g_str_equal (element_name, "micro"))
data->current = &data->micro;
else if (g_str_equal (element_name, "distributor"))
data->current = &data->distributor;
else if (g_str_equal (element_name, "date"))
data->current = &data->date;
else
data->current = NULL;
}
static void
version_end_element_handler (GMarkupParseContext *ctx,
const char *element_name,
gpointer user_data,
GError **error)
{
VersionData *data = user_data;
data->current = NULL;
}
static void
version_text_handler (GMarkupParseContext *ctx,
const char *text,
gsize text_len,
gpointer user_data,
GError **error)
{
VersionData *data = user_data;
if (data->current != NULL)
*data->current = g_strstrip (g_strdup (text));
}
static gboolean
load_gnome_version (char **version,
char **distributor,
char **date)
{
GMarkupParser version_parser = {
version_start_element_handler,
version_end_element_handler,
version_text_handler,
NULL,
NULL,
};
GError *error;
GMarkupParseContext *ctx;
char *contents;
gsize length;
VersionData *data;
gboolean ret;
ret = FALSE;
error = NULL;
if (!g_file_get_contents (DATADIR "/gnome/gnome-version.xml",
&contents,
&length,
&error))
return FALSE;
data = g_new0 (VersionData, 1);
ctx = g_markup_parse_context_new (&version_parser, 0, data, NULL);
if (!g_markup_parse_context_parse (ctx, contents, length, &error))
{
g_warning ("Invalid version file: '%s'", error->message);
}
else
{
if (version != NULL)
*version = g_strdup_printf ("%s.%s.%s", data->major, data->minor, data->micro);
if (distributor != NULL)
*distributor = g_strdup (data->distributor);
if (date != NULL)
*date = g_strdup (data->date);
ret = TRUE;
}
g_markup_parse_context_free (ctx);
g_free (data->major);
g_free (data->minor);
g_free (data->micro);
g_free (data->distributor);
g_free (data->date);
g_free (data);
g_free (contents);
return ret;
};
typedef struct
{
char *regex;
char *replacement;
} ReplaceStrings;
static char *
prettify_info (const char *info)
{
char *pretty;
int i;
static const ReplaceStrings rs[] = {
{ "Mesa DRI ", ""},
{ "Intel[(]R[)]", "Intel<sup>\302\256</sup>"},
{ "Core[(]TM[)]", "Core<sup>\342\204\242</sup>"},
{ "Atom[(]TM[)]", "Atom<sup>\342\204\242</sup>"},
{ "Graphics Controller", "Graphics"},
};
pretty = g_markup_escape_text (info, -1);
for (i = 0; i < G_N_ELEMENTS (rs); i++)
{
GError *error;
GRegex *re;
char *new;
error = NULL;
re = g_regex_new (rs[i].regex, 0, 0, &error);
if (re == NULL)
{
g_warning ("Error building regex: %s", error->message);
g_error_free (error);
continue;
}
new = g_regex_replace_literal (re,
pretty,
-1,
0,
rs[i].replacement,
0,
&error);
g_regex_unref (re);
if (error != NULL)
{
g_warning ("Error replacing %s: %s", rs[i].regex, error->message);
g_error_free (error);
continue;
}
g_free (pretty);
pretty = new;
}
return pretty;
}
static void
graphics_data_free (GraphicsData *gdata)
{
g_free (gdata->xorg_vesa_hardware);
g_free (gdata->glx_renderer);
g_slice_free (GraphicsData, gdata);
}
static char *
get_graphics_data_glx_renderer (void)
{
GError *error;
GRegex *re;
GMatchInfo *match_info;
char *output;
char *result;
GString *info;
info = g_string_new (NULL);
error = NULL;
g_spawn_command_line_sync ("glxinfo -l", &output, NULL, NULL, &error);
if (error != NULL)
{
g_warning ("Unable to get graphics info: %s", error->message);
g_error_free (error);
return NULL;
}
re = g_regex_new ("^OpenGL renderer string: (.+)$", G_REGEX_MULTILINE, 0, &error);
if (re == NULL)
{
g_warning ("Error building regex: %s", error->message);
g_error_free (error);
goto out;
}
g_regex_match (re, output, 0, &match_info);
while (g_match_info_matches (match_info))
{
char *device;
device = g_match_info_fetch (match_info, 1);
g_string_append_printf (info, "%s ", device);
g_free (device);
g_match_info_next (match_info, NULL);
}
g_match_info_free (match_info);
g_regex_unref (re);
out:
g_free (output);
result = prettify_info (info->str);
g_string_free (info, TRUE);
return result;
}
static char *
get_graphics_data_xorg_vesa_hardware (void)
{
char *display_num;
char *log_path;
char *log_contents;
gsize log_len;
GError *error = NULL;
GRegex *re;
GMatchInfo *match;
char *result = NULL;
{
const char *display;
display = g_getenv ("DISPLAY");
if (!display)
return NULL;
re = g_regex_new ("^:([0-9]+)", 0, 0, NULL);
g_assert (re != NULL);
g_regex_match (re, display, 0, &match);
if (!g_match_info_matches (match))
{
g_regex_unref (re);
g_match_info_free (match);
return NULL;
}
display_num = g_match_info_fetch (match, 1);
g_regex_unref (re);
re = NULL;
g_match_info_free (match);
match = NULL;
}
log_path = g_strdup_printf ("/var/log/Xorg.%s.log", display_num);
g_free (display_num);
log_contents = NULL;
g_file_get_contents (log_path, &log_contents, &log_len, &error);
g_free (log_path);
if (!log_contents)
return NULL;
re = g_regex_new ("VESA VBE OEM Product: (.*)$", G_REGEX_MULTILINE, 0, NULL);
g_assert (re != NULL);
g_regex_match (re, log_contents, 0, &match);
if (g_match_info_matches (match))
{
char *tmp;
char *pretty_tmp;
tmp = g_match_info_fetch (match, 1);
pretty_tmp = prettify_info (tmp);
g_free (tmp);
/* Translators: VESA is an techncial acronym, don't translate it. */
result = g_strdup_printf (_("VESA: %s"), pretty_tmp);
g_free (pretty_tmp);
}
g_match_info_free (match);
g_regex_unref (re);
return result;
}
static GraphicsData *
get_graphics_data (void)
{
GraphicsData *result;
result = g_slice_new0 (GraphicsData);
result->glx_renderer = get_graphics_data_glx_renderer ();
result->xorg_vesa_hardware = get_graphics_data_xorg_vesa_hardware ();
if (result->xorg_vesa_hardware != NULL)
result->hardware_string = result->xorg_vesa_hardware;
else if (result->glx_renderer != NULL)
result->hardware_string = result->glx_renderer;
else
result->hardware_string = _("Unknown");
return result;
}
static gboolean
get_current_is_fallback (CcInfoPanel *self)
{
GError *error;
GVariant *reply;
GVariant *reply_str;
gboolean is_fallback;
error = NULL;
if (!(reply = g_dbus_connection_call_sync (self->priv->session_bus,
"org.gnome.SessionManager",
"/org/gnome/SessionManager",
"org.freedesktop.DBus.Properties",
"Get",
g_variant_new ("(ss)", "org.gnome.SessionManager", "session-name"),
(GVariantType*)"(v)",
0,
-1,
NULL, &error)))
{
g_warning ("Failed to get fallback mode: %s", error->message);
g_clear_error (&error);
return FALSE;
}
g_variant_get (reply, "(v)", &reply_str);
is_fallback = g_strcmp0 ("gnome-fallback", g_variant_get_string (reply_str, NULL)) == 0;
g_variant_unref (reply_str);
g_variant_unref (reply);
return is_fallback;
}
static void
cc_info_panel_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
switch (property_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
cc_info_panel_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
switch (property_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
cc_info_panel_dispose (GObject *object)
{
CcInfoPanelPrivate *priv = CC_INFO_PANEL (object)->priv;
if (priv->builder != NULL)
{
g_object_unref (priv->builder);
priv->builder = NULL;
}
if (priv->pk_proxy != NULL)
{
g_object_unref (priv->pk_proxy);
priv->pk_proxy = NULL;
}
if (priv->pk_transaction_proxy != NULL)
{
g_object_unref (priv->pk_transaction_proxy);
priv->pk_transaction_proxy = NULL;
}
if (priv->graphics_data != NULL)
{
graphics_data_free (priv->graphics_data);
priv->graphics_data = NULL;
}
G_OBJECT_CLASS (cc_info_panel_parent_class)->dispose (object);
}
static void
cc_info_panel_finalize (GObject *object)
{
CcInfoPanelPrivate *priv = CC_INFO_PANEL (object)->priv;
if (priv->cancellable != NULL)
{
g_cancellable_cancel (priv->cancellable);
priv->cancellable = NULL;
}
g_free (priv->gnome_version);
g_free (priv->gnome_date);
g_free (priv->gnome_distributor);
if (priv->hostnamed_proxy != NULL)
{
g_object_unref (priv->hostnamed_proxy);
priv->hostnamed_proxy = NULL;
}
if (priv->media_settings != NULL)
{
g_object_unref (priv->media_settings);
priv->media_settings = NULL;
}
if (priv->session_settings != NULL)
{
g_object_unref (priv->session_settings);
priv->session_settings = NULL;
}
G_OBJECT_CLASS (cc_info_panel_parent_class)->finalize (object);
}
static void
cc_info_panel_class_init (CcInfoPanelClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (CcInfoPanelPrivate));
object_class->get_property = cc_info_panel_get_property;
object_class->set_property = cc_info_panel_set_property;
object_class->dispose = cc_info_panel_dispose;
object_class->finalize = cc_info_panel_finalize;
}
static char *
get_os_type (void)
{
int bits;
if (GLIB_SIZEOF_VOID_P == 8)
bits = 64;
else
bits = 32;
/* translators: This is the type of architecture, for example:
* "64-bit" or "32-bit" */
return g_strdup_printf (_("%d-bit"), bits);
}
static void
query_done (GFile *file,
GAsyncResult *res,
CcInfoPanel *self)
{
GFileInfo *info;
GError *error = NULL;
self->priv->cancellable = NULL;
info = g_file_query_filesystem_info_finish (file, res, &error);
if (info != NULL)
{
self->priv->total_bytes += g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE);
g_object_unref (info);
}
else
{
char *path;
path = g_file_get_path (file);
g_warning ("Failed to get filesystem free space for '%s': %s", path, error->message);
g_free (path);
g_error_free (error);
}
/* And onto the next element */
get_primary_disc_info_start (self);
}
static void
get_primary_disc_info_start (CcInfoPanel *self)
{
GUnixMountEntry *mount;
GFile *file;
if (self->priv->primary_mounts == NULL)
{
char *size;
GtkWidget *widget;
size = g_format_size (self->priv->total_bytes);
widget = WID ("disk_label");
gtk_label_set_text (GTK_LABEL (widget), size);
g_free (size);
return;
}
mount = self->priv->primary_mounts->data;
self->priv->primary_mounts = g_list_remove (self->priv->primary_mounts, mount);
file = g_file_new_for_path (g_unix_mount_get_mount_path (mount));
g_unix_mount_free (mount);
self->priv->cancellable = g_cancellable_new ();
g_file_query_filesystem_info_async (file,
G_FILE_ATTRIBUTE_FILESYSTEM_SIZE,
0,
self->priv->cancellable,
(GAsyncReadyCallback) query_done,
self);
g_object_unref (file);
}
static void
get_primary_disc_info (CcInfoPanel *self)
{
GList *points;
GList *p;
points = g_unix_mount_points_get (NULL);
for (p = points; p != NULL; p = p->next)
{
GUnixMountEntry *mount = p->data;
const char *mount_path;
mount_path = g_unix_mount_get_mount_path (mount);
if (gsd_should_ignore_unix_mount (mount) ||
gsd_is_removable_mount (mount) ||
g_str_has_prefix (mount_path, "/media/") ||
g_str_has_prefix (mount_path, g_get_home_dir ()))
{
g_unix_mount_free (mount);
continue;
}
self->priv->primary_mounts = g_list_prepend (self->priv->primary_mounts, mount);
}
g_list_free (points);
get_primary_disc_info_start (self);
}
static char *
remove_duplicate_whitespace (const char *old)
{
char *new;
GRegex *re;
GError *error;
error = NULL;
re = g_regex_new ("[ \t\n\r]+", G_REGEX_MULTILINE, 0, &error);
if (re == NULL)
{
g_warning ("Error building regex: %s", error->message);
g_error_free (error);
return g_strdup (old);
}
new = g_regex_replace (re,
old,
-1,
0,
" ",
0,
&error);
g_regex_unref (re);
if (new == NULL)
{
g_warning ("Error replacing string: %s", error->message);
g_error_free (error);
return g_strdup (old);
}
return new;
}
static char *
get_cpu_info (const glibtop_sysinfo *info)
{
GHashTable *counts;
GString *cpu;
char *ret;
GHashTableIter iter;
gpointer key, value;
int i;
int j;
counts = g_hash_table_new (g_str_hash, g_str_equal);
/* count duplicates */
for (i = 0; i != info->ncpu; ++i)
{
const char * const keys[] = { "model name", "cpu" };
char *model;
int *count;
model = NULL;
for (j = 0; model == NULL && j != G_N_ELEMENTS (keys); ++j)
{
model = g_hash_table_lookup (info->cpuinfo[i].values,
keys[j]);
}
if (model == NULL)
model = _("Unknown model");
count = g_hash_table_lookup (counts, model);
if (count == NULL)
g_hash_table_insert (counts, model, GINT_TO_POINTER (1));
else
g_hash_table_replace (counts, model, GINT_TO_POINTER (GPOINTER_TO_INT (count) + 1));
}
cpu = g_string_new (NULL);
g_hash_table_iter_init (&iter, counts);
while (g_hash_table_iter_next (&iter, &key, &value))
{
char *stripped;
int count;
count = GPOINTER_TO_INT (value);
stripped = remove_duplicate_whitespace ((const char *)key);
if (count > 1)
g_string_append_printf (cpu, "%s \303\227 %d ", stripped, count);
else
g_string_append_printf (cpu, "%s ", stripped);
g_free (stripped);
}
g_hash_table_destroy (counts);
ret = prettify_info (cpu->str);
g_string_free (cpu, TRUE);
return ret;
}
static void
on_section_changed (GtkTreeSelection *selection,
gpointer data)
{
CcInfoPanel *self = CC_INFO_PANEL (data);
GtkTreeIter iter;
GtkTreeModel *model;
GtkTreePath *path;
gint *indices;
int index;
if (!gtk_tree_selection_get_selected (selection, &model, &iter))
return;
path = gtk_tree_model_get_path (model, &iter);
indices = gtk_tree_path_get_indices (path);
index = indices[0];
if (index >= 0)
{
g_object_set (G_OBJECT (WID ("notebook")),
"page", index, NULL);
}
gtk_tree_path_free (path);
}
static gboolean
switch_fallback_get_mapping (GValue *value,
GVariant *variant,
gpointer data)
{
const char *setting;
setting = g_variant_get_string (variant, NULL);
g_value_set_boolean (value, strcmp (setting, "gnome") != 0);
return TRUE;
}
static void
toggle_fallback_warning_label (CcInfoPanel *self,
gboolean visible)
{
GtkWidget *widget;
const char *text;
widget = WID ("graphics_logout_warning_label");
if (self->priv->is_fallback)
text = _("The next login will attempt to use the standard experience.");
else
text = _("The next login will use the fallback mode intended for unsupported graphics hardware.");
gtk_label_set_text (GTK_LABEL (widget), text);
if (visible)
gtk_widget_show (widget);
else
gtk_widget_hide (widget);
}
static GVariant *
switch_fallback_set_mapping (const GValue *value,
const GVariantType *expected_type,
gpointer data)
{
CcInfoPanel *self = data;
gboolean is_set;
is_set = g_value_get_boolean (value);
if (is_set != self->priv->is_fallback)
toggle_fallback_warning_label (self, TRUE);
else
toggle_fallback_warning_label (self, FALSE);
return g_variant_new_string (is_set ? "gnome-fallback" : "gnome");
}
static void
info_panel_setup_graphics (CcInfoPanel *self)
{
GtkWidget *widget;
GtkSwitch *sw;
char *text;
widget = WID ("graphics_driver_label");
gtk_label_set_markup (GTK_LABEL (widget), self->priv->graphics_data->hardware_string);
self->priv->is_fallback = get_current_is_fallback (self);
if (self->priv->is_fallback)
{
/* translators: The hardware is not able to run GNOME 3's
* shell, so we use the GNOME "Fallback" session */
text = g_strdup (C_("Experience", "Fallback"));
}
else
{
/* translators: The hardware is able to run GNOME 3's
* shell, also called "Standard" experience */
text = g_strdup (C_("Experience", "Standard"));
}
widget = WID ("graphics_experience_label");
gtk_label_set_markup (GTK_LABEL (widget), text ? text : "");
g_free (text);
widget = WID ("graphics_fallback_switch_box");
sw = GTK_SWITCH (gtk_switch_new ());
g_settings_bind_with_mapping (self->priv->session_settings, KEY_SESSION_NAME,
sw, "active", 0,
switch_fallback_get_mapping,
switch_fallback_set_mapping, self, NULL);
gtk_box_pack_start (GTK_BOX (widget), GTK_WIDGET (sw), FALSE, FALSE, 0);
gtk_widget_show_all (GTK_WIDGET (sw));
widget = WID ("fallback-label");
gtk_label_set_mnemonic_widget (GTK_LABEL (widget), GTK_WIDGET (sw));
}
static void
default_app_changed (GtkAppChooserButton *button,
CcInfoPanel *self)
{
GAppInfo *info;
GError *error = NULL;
DefaultAppData *app_data;
int i;
info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (button));
app_data = g_object_get_data (G_OBJECT (button), "cc-default-app-data");
if (g_app_info_set_as_default_for_type (info, app_data->content_type, &error) == FALSE)
{
g_warning ("Failed to set '%s' as the default application for '%s': %s",
g_app_info_get_name (info), app_data->content_type, error->message);
g_error_free (error);
error = NULL;
}
if (app_data->extra_type_filter)
{
const char *const *mime_types;
GPatternSpec *pattern;
pattern = g_pattern_spec_new (app_data->extra_type_filter);
mime_types = g_app_info_get_supported_types (info);
for (i = 0; mime_types[i]; i++)
{
if (!g_pattern_match_string (pattern, mime_types[i]))
continue;
if (g_app_info_set_as_default_for_type (info, mime_types[i], &error) == FALSE)
{
g_warning ("Failed to set '%s' as the default application for secondary "
"content type '%s': %s",
g_app_info_get_name (info), mime_types[i], error->message);
g_error_free (error);
}
}
g_pattern_spec_free (pattern);
}
g_object_unref (info);
}
static void
info_panel_setup_default_app (CcInfoPanel *self,
DefaultAppData *data,
guint left_attach,
guint right_attach,
guint top_attach,
guint bottom_attach)
{
GtkWidget *button;
GtkWidget *table;
GtkWidget *label;
table = WID ("default_apps_table");
button = gtk_app_chooser_button_new (data->content_type);
g_object_set_data (G_OBJECT (button), "cc-default-app-data", data);
gtk_app_chooser_button_set_show_default_item (GTK_APP_CHOOSER_BUTTON (button), TRUE);
gtk_table_attach (GTK_TABLE (table), button,
left_attach, right_attach,
top_attach, bottom_attach, GTK_FILL, 0, 0, 0);
g_signal_connect (G_OBJECT (button), "changed",
G_CALLBACK (default_app_changed), self);
gtk_widget_show (button);
label = WID(data->label);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), button);
}
static DefaultAppData preferred_app_infos[] = {
/* for web, we need to support text/html,
application/xhtml+xml and x-scheme-handler/https,
hence the "*" pattern
*/
{ "x-scheme-handler/http", "web-label", "*" },
{ "x-scheme-handler/mailto", "mail-label", NULL },
{ "text/calendar", "calendar-label", NULL },
{ "audio/x-vorbis+ogg", "music-label", "audio/*" },
{ "video/x-ogm+ogg", "video-label", "video/*" },
{ "image/jpeg", "photos-label", "image/*" }
};
static void
info_panel_setup_default_apps (CcInfoPanel *self)
{
int i;
for (i = 0; i < G_N_ELEMENTS(preferred_app_infos); i++)
{
info_panel_setup_default_app (self, &preferred_app_infos[i],
1, 2, i, i+1);
}
}
static char **
remove_elem_from_str_array (char **v,
const char *s)
{
GPtrArray *array;
guint idx;
array = g_ptr_array_new ();
for (idx = 0; v[idx] != NULL; idx++) {
if (g_strcmp0 (v[idx], s) == 0) {
continue;
}
g_ptr_array_add (array, v[idx]);
}
g_ptr_array_add (array, NULL);
g_free (v);
return (char **) g_ptr_array_free (array, FALSE);
}
static char **
add_elem_to_str_array (char **v,
const char *s)
{
GPtrArray *array;
guint idx;
array = g_ptr_array_new ();
for (idx = 0; v[idx] != NULL; idx++) {
g_ptr_array_add (array, v[idx]);
}
g_ptr_array_add (array, g_strdup (s));
g_ptr_array_add (array, NULL);
g_free (v);
return (char **) g_ptr_array_free (array, FALSE);
}
static int
media_panel_g_strv_find (char **strv,
const char *find_me)
{
guint index;
g_return_val_if_fail (find_me != NULL, -1);
for (index = 0; strv[index] != NULL; ++index) {
if (g_strcmp0 (strv[index], find_me) == 0) {
return index;
}
}
return -1;
}
static void
autorun_get_preferences (CcInfoPanel *self,
const char *x_content_type,
gboolean *pref_start_app,
gboolean *pref_ignore,
gboolean *pref_open_folder)
{
char **x_content_start_app;
char **x_content_ignore;
char **x_content_open_folder;
g_return_if_fail (pref_start_app != NULL);
g_return_if_fail (pref_ignore != NULL);
g_return_if_fail (pref_open_folder != NULL);
*pref_start_app = FALSE;
*pref_ignore = FALSE;
*pref_open_folder = FALSE;
x_content_start_app = g_settings_get_strv (self->priv->media_settings,
PREF_MEDIA_AUTORUN_X_CONTENT_START_APP);
x_content_ignore = g_settings_get_strv (self->priv->media_settings,
PREF_MEDIA_AUTORUN_X_CONTENT_IGNORE);
x_content_open_folder = g_settings_get_strv (self->priv->media_settings,
PREF_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER);
if (x_content_start_app != NULL) {
*pref_start_app = media_panel_g_strv_find (x_content_start_app, x_content_type) != -1;
}
if (x_content_ignore != NULL) {
*pref_ignore = media_panel_g_strv_find (x_content_ignore, x_content_type) != -1;
}
if (x_content_open_folder != NULL) {
*pref_open_folder = media_panel_g_strv_find (x_content_open_folder, x_content_type) != -1;
}
g_strfreev (x_content_ignore);
g_strfreev (x_content_start_app);
g_strfreev (x_content_open_folder);
}
static void
autorun_set_preferences (CcInfoPanel *self,
const char *x_content_type,
gboolean pref_start_app,
gboolean pref_ignore,
gboolean pref_open_folder)
{
char **x_content_start_app;
char **x_content_ignore;
char **x_content_open_folder;
g_assert (x_content_type != NULL);
x_content_start_app = g_settings_get_strv (self->priv->media_settings,
PREF_MEDIA_AUTORUN_X_CONTENT_START_APP);
x_content_ignore = g_settings_get_strv (self->priv->media_settings,
PREF_MEDIA_AUTORUN_X_CONTENT_IGNORE);
x_content_open_folder = g_settings_get_strv (self->priv->media_settings,
PREF_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER);
x_content_start_app = remove_elem_from_str_array (x_content_start_app, x_content_type);
if (pref_start_app) {
x_content_start_app = add_elem_to_str_array (x_content_start_app, x_content_type);
}
g_settings_set_strv (self->priv->media_settings,
PREF_MEDIA_AUTORUN_X_CONTENT_START_APP, (const gchar * const*) x_content_start_app);
x_content_ignore = remove_elem_from_str_array (x_content_ignore, x_content_type);
if (pref_ignore) {
x_content_ignore = add_elem_to_str_array (x_content_ignore, x_content_type);
}
g_settings_set_strv (self->priv->media_settings,
PREF_MEDIA_AUTORUN_X_CONTENT_IGNORE, (const gchar * const*) x_content_ignore);
x_content_open_folder = remove_elem_from_str_array (x_content_open_folder, x_content_type);
if (pref_open_folder) {
x_content_open_folder = add_elem_to_str_array (x_content_open_folder, x_content_type);
}
g_settings_set_strv (self->priv->media_settings,
PREF_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER, (const gchar * const*) x_content_open_folder);
g_strfreev (x_content_open_folder);
g_strfreev (x_content_ignore);
g_strfreev (x_content_start_app);
}
static void
custom_item_activated_cb (GtkAppChooserButton *button,
const gchar *item,
gpointer user_data)
{
CcInfoPanel *self = user_data;
gchar *content_type;
content_type = gtk_app_chooser_get_content_type (GTK_APP_CHOOSER (button));
if (g_strcmp0 (item, CUSTOM_ITEM_ASK) == 0) {
autorun_set_preferences (self, content_type,
FALSE, FALSE, FALSE);
} else if (g_strcmp0 (item, CUSTOM_ITEM_OPEN_FOLDER) == 0) {
autorun_set_preferences (self, content_type,
FALSE, FALSE, TRUE);
} else if (g_strcmp0 (item, CUSTOM_ITEM_DO_NOTHING) == 0) {
autorun_set_preferences (self, content_type,
FALSE, TRUE, FALSE);
}
g_free (content_type);
}
static void
combo_box_changed_cb (GtkComboBox *combo_box,
gpointer user_data)
{
CcInfoPanel *self = user_data;
GAppInfo *info;
gchar *content_type;
info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (combo_box));
if (info == NULL)
return;
content_type = gtk_app_chooser_get_content_type (GTK_APP_CHOOSER (combo_box));
autorun_set_preferences (self, content_type,
TRUE, FALSE, FALSE);
g_app_info_set_as_default_for_type (info, content_type, NULL);
g_object_unref (info);
g_free (content_type);
}
static void
prepare_combo_box (CcInfoPanel *self,
GtkWidget *combo_box,
const gchar *heading)
{
GtkAppChooserButton *app_chooser = GTK_APP_CHOOSER_BUTTON (combo_box);
gboolean pref_ask;
gboolean pref_start_app;
gboolean pref_ignore;
gboolean pref_open_folder;
GAppInfo *info;
gchar *content_type;
content_type = gtk_app_chooser_get_content_type (GTK_APP_CHOOSER (app_chooser));
/* fetch preferences for this content type */
autorun_get_preferences (self, content_type,
&pref_start_app, &pref_ignore, &pref_open_folder);
pref_ask = !pref_start_app && !pref_ignore && !pref_open_folder;
info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (combo_box));
/* append the separator only if we have >= 1 apps in the chooser */
if (info != NULL) {
gtk_app_chooser_button_append_separator (app_chooser);
g_object_unref (info);
}
gtk_app_chooser_button_append_custom_item (app_chooser, CUSTOM_ITEM_ASK,
_("Ask what to do"),
NULL);
gtk_app_chooser_button_append_custom_item (app_chooser, CUSTOM_ITEM_DO_NOTHING,
_("Do nothing"),
NULL);
gtk_app_chooser_button_append_custom_item (app_chooser, CUSTOM_ITEM_OPEN_FOLDER,
_("Open folder"),
NULL);
gtk_app_chooser_button_set_show_dialog_item (app_chooser, TRUE);
gtk_app_chooser_button_set_heading (app_chooser, _(heading));
if (pref_ask) {
gtk_app_chooser_button_set_active_custom_item (app_chooser, CUSTOM_ITEM_ASK);
} else if (pref_ignore) {
gtk_app_chooser_button_set_active_custom_item (app_chooser, CUSTOM_ITEM_DO_NOTHING);
} else if (pref_open_folder) {
gtk_app_chooser_button_set_active_custom_item (app_chooser, CUSTOM_ITEM_OPEN_FOLDER);
}
g_signal_connect (app_chooser, "changed",
G_CALLBACK (combo_box_changed_cb), self);
g_signal_connect (app_chooser, "custom-item-activated",
G_CALLBACK (custom_item_activated_cb), self);
g_free (content_type);
}
static void
other_type_combo_box_changed (GtkComboBox *combo_box,
CcInfoPanel *self)
{
GtkTreeIter iter;
GtkTreeModel *model;
char *x_content_type;
GtkWidget *action_container;
GtkWidget *action_label;
x_content_type = NULL;
if (!gtk_combo_box_get_active_iter (combo_box, &iter)) {
return;
}
model = gtk_combo_box_get_model (combo_box);
if (model == NULL) {
return;
}
gtk_tree_model_get (model, &iter,
1, &x_content_type,
-1);
action_container = GTK_WIDGET (gtk_builder_get_object (self->priv->builder,
"media_other_action_container"));
if (self->priv->other_application_combo != NULL) {
gtk_widget_destroy (self->priv->other_application_combo);
}
self->priv->other_application_combo = gtk_app_chooser_button_new (x_content_type);
gtk_box_pack_start (GTK_BOX (action_container), self->priv->other_application_combo, TRUE, TRUE, 0);
prepare_combo_box (self, self->priv->other_application_combo, NULL);
gtk_widget_show (self->priv->other_application_combo);
action_label = GTK_WIDGET (gtk_builder_get_object (self->priv->builder,
"media_other_action_label"));
gtk_label_set_mnemonic_widget (GTK_LABEL (action_label), self->priv->other_application_combo);
g_free (x_content_type);
}
static void
on_extra_options_dialog_response (GtkWidget *dialog,
int response,
CcInfoPanel *self)
{
gtk_widget_hide (dialog);
if (self->priv->other_application_combo != NULL) {
gtk_widget_destroy (self->priv->other_application_combo);
self->priv->other_application_combo = NULL;
}
}
static void
on_extra_options_button_clicked (GtkWidget *button,
CcInfoPanel *self)
{
GtkWidget *dialog;
GtkWidget *combo_box;
dialog = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, "extra_options_dialog"));
combo_box = GTK_WIDGET (gtk_builder_get_object (self->priv->builder, "media_other_type_combobox"));
gtk_window_set_transient_for (GTK_WINDOW (dialog),
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self))));
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
gtk_window_set_title (GTK_WINDOW (dialog), _("Other Media"));
g_signal_connect (dialog,
"response",
G_CALLBACK (on_extra_options_dialog_response),
self);
g_signal_connect (dialog,
"delete-event",
G_CALLBACK (gtk_widget_hide_on_delete),
NULL);
/* update other_application_combo */
other_type_combo_box_changed (GTK_COMBO_BOX (combo_box), self);
gtk_window_present (GTK_WINDOW (dialog));
}
static void
info_panel_setup_media (CcInfoPanel *self)
{
guint n;
GList *l, *content_types;
GtkWidget *other_type_combo_box;
GtkWidget *extras_button;
GtkListStore *other_type_list_store;
GtkCellRenderer *renderer;
GtkTreeIter iter;
GtkBuilder *builder = self->priv->builder;
struct {
const gchar *widget_name;
const gchar *content_type;
const gchar *heading;
} const defs[] = {
{ "media_audio_cdda_combobox", "x-content/audio-cdda", N_("Select an application for audio CDs") },
{ "media_video_dvd_combobox", "x-content/video-dvd", N_("Select an application for video DVDs") },
{ "media_music_player_combobox", "x-content/audio-player", N_("Select an application to run when a music player is connected") },
{ "media_dcf_combobox", "x-content/image-dcf", N_("Select an application to run when a camera is connected") },
{ "media_software_combobox", "x-content/unix-software", N_("Select an application for software CDs") },
};
struct {
const gchar *content_type;
const gchar *description;
} const other_defs[] = {
/* translators: these strings are duplicates of shared-mime-info
* strings, just here to fix capitalization of the English originals.
* If the shared-mime-info translation works for your language,
* simply leave these untranslated.
*/
{ "x-content/audio-dvd", N_("audio DVD") },
{ "x-content/blank-bd", N_("blank Blu-ray disc") },
{ "x-content/blank-cd", N_("blank CD disc") },
{ "x-content/blank-dvd", N_("blank DVD disc") },
{ "x-content/blank-hddvd", N_("blank HD DVD disc") },
{ "x-content/video-bluray", N_("Blu-ray video disc") },
{ "x-content/ebook-reader", N_("e-book reader") },
{ "x-content/video-hddvd", N_("HD DVD video disc") },
{ "x-content/image-picturecd", N_("Picture CD") },
{ "x-content/video-svcd", N_("Super Video CD") },
{ "x-content/video-vcd", N_("Video CD") },
{ "x-content/win32-software", N_("Windows software") },
{ "x-content/software", N_("Software") }
};
for (n = 0; n < G_N_ELEMENTS (defs); n++) {
prepare_combo_box (self,
GTK_WIDGET (gtk_builder_get_object (builder, defs[n].widget_name)),
defs[n].heading);
}
other_type_combo_box = GTK_WIDGET (gtk_builder_get_object (builder, "media_other_type_combobox"));
other_type_list_store = gtk_list_store_new (2,
G_TYPE_STRING,
G_TYPE_STRING);
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (other_type_list_store),
1, GTK_SORT_ASCENDING);
content_types = g_content_types_get_registered ();
for (l = content_types; l != NULL; l = l->next) {
char *content_type = l->data;
char *description = NULL;
if (!g_str_has_prefix (content_type, "x-content/"))
continue;
for (n = 0; n < G_N_ELEMENTS (defs); n++) {
if (g_content_type_is_a (content_type, defs[n].content_type)) {
goto skip;
}
}
for (n = 0; n < G_N_ELEMENTS (other_defs); n++) {
if (strcmp (content_type, other_defs[n].content_type) == 0) {
const gchar *s = other_defs[n].description;
if (s == _(s))
description = g_content_type_get_description (content_type);
else
description = g_strdup (_(s));
break;
}
}
if (description == NULL) {
g_debug ("Content type '%s' is missing from the info panel", content_type);
description = g_content_type_get_description (content_type);
}
gtk_list_store_append (other_type_list_store, &iter);
gtk_list_store_set (other_type_list_store, &iter,
0, description,
1, content_type,
-1);
g_free (description);
skip:
;
}
g_list_free_full (content_types, g_free);
gtk_combo_box_set_model (GTK_COMBO_BOX (other_type_combo_box),
GTK_TREE_MODEL (other_type_list_store));
renderer = gtk_cell_renderer_text_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (other_type_combo_box), renderer, TRUE);
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (other_type_combo_box), renderer,
"text", 0,
NULL);
g_signal_connect (other_type_combo_box,
"changed",
G_CALLBACK (other_type_combo_box_changed),
self);
gtk_combo_box_set_active (GTK_COMBO_BOX (other_type_combo_box), 0);
extras_button = GTK_WIDGET (gtk_builder_get_object (builder, "extra_options_button"));
g_signal_connect (extras_button,
"clicked",
G_CALLBACK (on_extra_options_button_clicked),
self);
g_settings_bind (self->priv->media_settings,
PREF_MEDIA_AUTORUN_NEVER,
gtk_builder_get_object (self->priv->builder, "media_autorun_never_checkbutton"),
"active",
G_SETTINGS_BIND_DEFAULT);
g_settings_bind (self->priv->media_settings,
PREF_MEDIA_AUTORUN_NEVER,
GTK_WIDGET (gtk_builder_get_object (self->priv->builder, "media_handling_vbox")),
"sensitive",
G_SETTINGS_BIND_INVERT_BOOLEAN);
}
static void
info_panel_setup_selector (CcInfoPanel *self)
{
GtkTreeView *view;
GtkListStore *model;
GtkTreeSelection *selection;
GtkTreeViewColumn *column;
GtkCellRenderer *renderer;
GtkTreeIter iter;
int section_name_column = 0;
view = GTK_TREE_VIEW (WID ("overview_treeview"));
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
model = gtk_list_store_new (1, G_TYPE_STRING);
gtk_tree_view_set_model (view, GTK_TREE_MODEL (model));
g_object_unref (model);
renderer = gtk_cell_renderer_text_new ();
gtk_cell_renderer_set_padding (renderer, 4, 4);
g_object_set (renderer,
"width-chars", 20,
"ellipsize", PANGO_ELLIPSIZE_END,
NULL);
column = gtk_tree_view_column_new_with_attributes (_("Section"),
renderer,
"text", section_name_column,
NULL);
gtk_tree_view_append_column (view, column);
gtk_list_store_append (model, &iter);
gtk_list_store_set (model, &iter, section_name_column,
_("Overview"),
-1);
gtk_tree_selection_select_iter (selection, &iter);
gtk_list_store_append (model, &iter);
gtk_list_store_set (model, &iter, section_name_column,
_("Default Applications"),
-1);
gtk_list_store_append (model, &iter);
gtk_list_store_set (model, &iter, section_name_column,
_("Removable Media"),
-1);
gtk_list_store_append (model, &iter);
gtk_list_store_set (model, &iter, section_name_column,
_("Graphics"),
-1);
g_signal_connect (selection, "changed",
G_CALLBACK (on_section_changed), self);
on_section_changed (selection, self);
gtk_widget_show_all (GTK_WIDGET (view));
}
static char *
get_hostname_property (CcInfoPanel *self,
const char *property)
{
GVariant *variant;
char *str;
variant = g_dbus_proxy_get_cached_property (self->priv->hostnamed_proxy,
property);
if (!variant)
{
GError *error = NULL;
GVariant *inner;
/* Work around systemd-hostname not sending us back
* the property value when changing values */
variant = g_dbus_proxy_call_sync (self->priv->hostnamed_proxy,
"org.freedesktop.DBus.Properties.Get",
g_variant_new ("(ss)", "org.freedesktop.hostname1", property),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error);
if (variant == NULL)
{
g_warning ("Failed to get property '%s': %s", property, error->message);
g_error_free (error);
return NULL;
}
g_variant_get (variant, "(v)", &inner);
str = g_variant_dup_string (inner, NULL);
g_variant_unref (variant);
}
else
{
str = g_variant_dup_string (variant, NULL);
g_variant_unref (variant);
}
return str;
}
static char *
info_panel_get_hostname (CcInfoPanel *self)
{
char *str;
str = get_hostname_property (self, "PrettyHostname");
/* Empty strings means that we need to fallback */
if (str != NULL &&
*str == '\0')
{
g_free (str);
str = get_hostname_property (self, "Hostname");
}
return str;
}
static void
info_panel_set_hostname (CcInfoPanel *self,
const char *text)
{
char *hostname;
GVariant *variant;
GError *error = NULL;
g_debug ("Setting PrettyHostname to '%s'", text);
variant = g_dbus_proxy_call_sync (self->priv->hostnamed_proxy,
"SetPrettyHostname",
g_variant_new ("(sb)", text, FALSE),
G_DBUS_CALL_FLAGS_NONE,
-1, NULL, &error);
if (variant == NULL)
{
g_warning ("Could not set PrettyHostname: %s", error->message);
g_error_free (error);
error = NULL;
}
else
{
g_variant_unref (variant);
}
/* Set the static hostname */
hostname = pretty_hostname_to_static (text, FALSE);
g_assert (hostname);
g_debug ("Setting StaticHostname to '%s'", hostname);
variant = g_dbus_proxy_call_sync (self->priv->hostnamed_proxy,
"SetStaticHostname",
g_variant_new ("(sb)", hostname, FALSE),
G_DBUS_CALL_FLAGS_NONE,
-1, NULL, &error);
if (variant == NULL)
{
g_warning ("Could not set StaticHostname: %s", error->message);
g_error_free (error);
}
else
{
g_variant_unref (variant);
}
g_free (hostname);
}
static void
text_changed_cb (GtkEntry *entry,
CcInfoPanel *self)
{
const char *text;
text = gtk_entry_get_text (GTK_ENTRY (entry));
info_panel_set_hostname (self, text);
}
static void
info_panel_setup_hostname (CcInfoPanel *self,
GPermission *permission)
{
char *str;
GtkWidget *entry;
GError *error = NULL;
if (permission == NULL)
{
g_debug ("Will not show hostname, hostnamed not installed");
return;
}
entry = WID ("name_entry");
if (g_permission_get_allowed (permission) != FALSE)
{
g_debug ("Not allowed to change the hostname");
gtk_widget_set_sensitive (entry, TRUE);
}
self->priv->hostnamed_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
"org.freedesktop.hostname1",
"/org/freedesktop/hostname1",
"org.freedesktop.hostname1",
NULL,
&error);
/* This could only happen if the policy file was installed
* but not hostnamed, which points to a system bug */
if (self->priv->hostnamed_proxy == NULL)
{
g_debug ("Couldn't get hostnamed to start, bailing: %s", error->message);
g_error_free (error);
return;
}
gtk_widget_show (WID ("label4"));
gtk_widget_show (entry);
str = info_panel_get_hostname (self);
if (str != NULL)
gtk_entry_set_text (GTK_ENTRY (entry), str);
else
gtk_entry_set_text (GTK_ENTRY (entry), "");
g_free (str);
g_signal_connect (G_OBJECT (entry), "changed",
G_CALLBACK (text_changed_cb), self);
}
static void
info_panel_setup_overview (CcInfoPanel *self)
{
GtkWidget *widget;
gboolean res;
glibtop_mem mem;
const glibtop_sysinfo *info;
char *text;
GPermission *permission;
permission = polkit_permission_new_sync ("org.freedesktop.hostname1.set-static-hostname", NULL, NULL, NULL);
/* Is hostnamed installed? */
info_panel_setup_hostname (self, permission);
res = load_gnome_version (&self->priv->gnome_version,
&self->priv->gnome_distributor,
&self->priv->gnome_date);
if (res)
{
widget = WID ("version_label");
text = g_strdup_printf (_("Version %s"), self->priv->gnome_version);
gtk_label_set_text (GTK_LABEL (widget), text);
g_free (text);
}
glibtop_get_mem (&mem);
text = g_format_size_full (mem.total, G_FORMAT_SIZE_IEC_UNITS);
widget = WID ("memory_label");
gtk_label_set_text (GTK_LABEL (widget), text ? text : "");
g_free (text);
info = glibtop_get_sysinfo ();
widget = WID ("processor_label");
text = get_cpu_info (info);
gtk_label_set_markup (GTK_LABEL (widget), text ? text : "");
g_free (text);
widget = WID ("os_type_label");
text = get_os_type ();
gtk_label_set_text (GTK_LABEL (widget), text ? text : "");
g_free (text);
get_primary_disc_info (self);
widget = WID ("graphics_label");
gtk_label_set_markup (GTK_LABEL (widget), self->priv->graphics_data->hardware_string);
widget = WID ("info_vbox");
gtk_widget_reparent (widget, (GtkWidget *) self);
refresh_update_button (self);
}
static void
refresh_update_button (CcInfoPanel *self)
{
GtkWidget *widget;
widget = WID ("updates_button");
if (widget == NULL)
return;
switch (self->priv->updates_state)
{
case PK_NOT_AVAILABLE:
gtk_widget_set_visible (widget, FALSE);
break;
case UPDATES_AVAILABLE:
gtk_widget_set_sensitive (widget, TRUE);
gtk_button_set_label (GTK_BUTTON (widget), _("Install Updates"));
break;
case UPDATES_NOT_AVAILABLE:
gtk_widget_set_sensitive (widget, FALSE);
gtk_button_set_label (GTK_BUTTON (widget), _("System Up-To-Date"));
break;
case CHECKING_UPDATES:
gtk_widget_set_sensitive (widget, FALSE);
gtk_button_set_label (GTK_BUTTON (widget), _("Checking for Updates"));
break;
}
}
static void
on_pk_transaction_signal (GDBusProxy *proxy,
char *sender_name,
char *signal_name,
GVariant *parameters,
CcInfoPanel *self)
{
if (g_strcmp0 (signal_name, "Package") == 0)
{
self->priv->updates_state = UPDATES_AVAILABLE;
}
else if (g_strcmp0 (signal_name, "Finished") == 0)
{
if (self->priv->updates_state == CHECKING_UPDATES)
self->priv->updates_state = UPDATES_NOT_AVAILABLE;
refresh_update_button (self);
}
else if (g_strcmp0 (signal_name, "ErrorCode") == 0)
{
self->priv->updates_state = PK_NOT_AVAILABLE;
refresh_update_button (self);
}
else if (g_strcmp0 (signal_name, "Destroy") == 0)
{
g_object_unref (self->priv->pk_transaction_proxy);
self->priv->pk_transaction_proxy = NULL;
}
}
static void
on_pk_get_updates_ready (GObject *source,
GAsyncResult *res,
CcInfoPanel *self)
{
GError *error;
GVariant *result;
error = NULL;
result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error);
if (result == NULL)
{
g_warning ("Error getting PackageKit updates list: %s", error->message);
g_error_free (error);
return;
}
}
static void
on_pk_get_tid_ready (GObject *source,
GAsyncResult *res,
CcInfoPanel *self)
{
GError *error;
GVariant *result;
char *tid;
error = NULL;
result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error);
if (result == NULL)
{
if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN) == FALSE)
g_warning ("Error getting PackageKit transaction ID: %s", error->message);
g_error_free (error);
return;
}
g_variant_get (result, "(o)", &tid);
self->priv->pk_transaction_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
"org.freedesktop.PackageKit",
tid,
"org.freedesktop.PackageKit.Transaction",
NULL,
NULL);
g_free (tid);
g_variant_unref (result);
if (self->priv->pk_transaction_proxy == NULL)
{
g_warning ("Unable to get PackageKit transaction proxy object");
return;
}
g_signal_connect (self->priv->pk_transaction_proxy,
"g-signal",
G_CALLBACK (on_pk_transaction_signal),
self);
g_dbus_proxy_call (self->priv->pk_transaction_proxy,
"GetUpdates",
g_variant_new ("(t)", 1), /* PK_FILTER_ENUM_NONE */
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
(GAsyncReadyCallback) on_pk_get_updates_ready,
self);
}
static void
refresh_updates (CcInfoPanel *self)
{
self->priv->updates_state = CHECKING_UPDATES;
refresh_update_button (self);
g_assert (self->priv->pk_proxy != NULL);
g_dbus_proxy_call (self->priv->pk_proxy,
"CreateTransaction",
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
(GAsyncReadyCallback) on_pk_get_tid_ready,
self);
}
static void
on_pk_signal (GDBusProxy *proxy,
char *sender_name,
char *signal_name,
GVariant *parameters,
CcInfoPanel *self)
{
if (g_strcmp0 (signal_name, "UpdatesChanged") == 0)
{
refresh_updates (self);
}
}
static void
on_updates_button_clicked (GtkWidget *widget,
CcInfoPanel *self)
{
GError *error;
error = NULL;
g_spawn_command_line_async ("gpk-update-viewer", &error);
if (error != NULL)
{
g_warning ("unable to launch Software Updates: %s", error->message);
g_error_free (error);
}
}
static void
cc_info_panel_init (CcInfoPanel *self)
{
GError *error = NULL;
GtkWidget *widget;
self->priv = INFO_PANEL_PRIVATE (self);
self->priv->builder = gtk_builder_new ();
self->priv->session_settings = g_settings_new (GNOME_SESSION_MANAGER_SCHEMA);
self->priv->media_settings = g_settings_new (MEDIA_HANDLING_SCHEMA);
self->priv->session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
g_assert (self->priv->session_bus);
self->priv->pk_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
"org.freedesktop.PackageKit",
"/org/freedesktop/PackageKit",
"org.freedesktop.PackageKit",
NULL,
NULL);
if (self->priv->pk_proxy == NULL)
{
g_warning ("Unable to get PackageKit proxy object");
self->priv->updates_state = PK_NOT_AVAILABLE;
}
else
{
GVariant *v;
guint32 major, minor, micro;
v = g_dbus_proxy_get_cached_property (self->priv->pk_proxy, "VersionMajor");
g_variant_get (v, "u", &major);
g_variant_unref (v);
v = g_dbus_proxy_get_cached_property (self->priv->pk_proxy, "VersionMinor");
g_variant_get (v, "u", &minor);
g_variant_unref (v);
v = g_dbus_proxy_get_cached_property (self->priv->pk_proxy, "VersionMicro");
g_variant_get (v, "u", &micro);
g_variant_unref (v);
if (major != 0 || minor != 8)
{
g_warning ("PackageKit version %u.%u.%u not supported", major, minor, micro);
g_clear_object (&self->priv->pk_proxy);
self->priv->updates_state = PK_NOT_AVAILABLE;
}
else
{
g_signal_connect (self->priv->pk_proxy,
"g-signal",
G_CALLBACK (on_pk_signal),
self);
refresh_updates (self);
}
}
gtk_builder_add_from_file (self->priv->builder,
GNOMECC_UI_DIR "/info.ui",
&error);
if (error != NULL)
{
g_warning ("Could not load interface file: %s", error->message);
g_error_free (error);
return;
}
self->priv->graphics_data = get_graphics_data ();
widget = WID ("updates_button");
g_signal_connect (widget, "clicked", G_CALLBACK (on_updates_button_clicked), self);
info_panel_setup_selector (self);
info_panel_setup_overview (self);
info_panel_setup_default_apps (self);
info_panel_setup_media (self);
info_panel_setup_graphics (self);
}
void
cc_info_panel_register (GIOModule *module)
{
cc_info_panel_register_type (G_TYPE_MODULE (module));
g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT,
CC_TYPE_INFO_PANEL,
"info", 0);
}