gnome-control-center/panels/color/cc-color-panel.c
Richard Hughes e7863d0e02 color: Add the virtual device UI which is used when a physical device connection is impossible
This is designed so power users can create virtual devices (just like in
ColorSync) that represent things like 'Hexachrome Press #2' or 'Cinema'.

This new UI isn't actually wired up yet, and there are no new UI controls as
the UI still needs love from the designers.

This was added at this point for two reasons:

1. To get the translations early so we can enable this later
2. To be able to delete the code out of gcm-prefs.c
2011-05-20 20:40:15 +01:00

2165 lines
67 KiB
C

/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2010 Red Hat, Inc
* Copyright (C) 2011 Richard Hughes <richard@hughsie.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 <glib/gi18n.h>
#include <colord.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include "cc-color-panel.h"
#define WID(b, w) (GtkWidget *) gtk_builder_get_object (b, w)
G_DEFINE_DYNAMIC_TYPE (CcColorPanel, cc_color_panel, CC_TYPE_PANEL)
#define COLOR_PANEL_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_COLOR_PANEL, CcColorPanelPrivate))
struct _CcColorPanelPrivate
{
CdClient *client;
CdDevice *current_device;
CdSensor *sensor;
GCancellable *cancellable;
GDBusProxy *proxy;
GSettings *settings;
GtkBuilder *builder;
GtkTreeStore *list_store_devices;
GtkWidget *main_window;
};
enum {
GCM_PREFS_COLUMN_DEVICE_ID,
GCM_PREFS_COLUMN_SORT,
GCM_PREFS_COLUMN_ICON,
GCM_PREFS_COLUMN_TITLE,
GCM_PREFS_COLUMN_DEVICE,
GCM_PREFS_COLUMN_PROFILE,
GCM_PREFS_COLUMN_STATUS,
GCM_PREFS_COLUMN_STATUS_IMAGE,
GCM_PREFS_COLUMN_TOOLTIP,
GCM_PREFS_COLUMN_RADIO_ACTIVE,
GCM_PREFS_COLUMN_RADIO_VISIBLE,
GCM_PREFS_COLUMN_NUM_COLUMNS
};
enum {
GCM_PREFS_COMBO_COLUMN_TEXT,
GCM_PREFS_COMBO_COLUMN_PROFILE,
GCM_PREFS_COMBO_COLUMN_TYPE,
GCM_PREFS_COMBO_COLUMN_NUM_COLUMNS
};
typedef enum {
GCM_PREFS_ENTRY_TYPE_PROFILE,
GCM_PREFS_ENTRY_TYPE_IMPORT
} GcmPrefsEntryType;
#define GCM_SETTINGS_SCHEMA "org.gnome.settings-daemon.plugins.color"
#define GCM_SETTINGS_RECALIBRATE_PRINTER_THRESHOLD "recalibrate-printer-threshold"
#define GCM_SETTINGS_RECALIBRATE_DISPLAY_THRESHOLD "recalibrate-display-threshold"
static void
gcm_prefs_combobox_add_profile (GtkWidget *widget,
CdProfile *profile,
GcmPrefsEntryType entry_type,
GtkTreeIter *iter)
{
GtkTreeModel *model;
GtkTreeIter iter_tmp;
const gchar *description;
/* iter is optional */
if (iter == NULL)
iter = &iter_tmp;
/* use description */
if (entry_type == GCM_PREFS_ENTRY_TYPE_IMPORT)
{
/* TRANSLATORS: this is where the user can click and import a profile */
description = _("Other profile…");
}
else
{
description = cd_profile_get_title (profile);
}
/* also add profile */
model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget));
gtk_list_store_append (GTK_LIST_STORE(model), iter);
gtk_list_store_set (GTK_LIST_STORE(model), iter,
GCM_PREFS_COMBO_COLUMN_TEXT, description,
GCM_PREFS_COMBO_COLUMN_PROFILE, profile,
GCM_PREFS_COMBO_COLUMN_TYPE, entry_type,
-1);
}
static void
gcm_prefs_default_cb (GtkWidget *widget, CcColorPanel *prefs)
{
CdProfile *profile;
gboolean ret;
GError *error = NULL;
CcColorPanelPrivate *priv = prefs->priv;
/* TODO: check if the profile is already systemwide */
profile = cd_device_get_default_profile (priv->current_device);
if (profile == NULL)
goto out;
/* install somewhere out of $HOME */
ret = cd_profile_install_system_wide_sync (profile,
priv->cancellable,
&error);
if (!ret)
{
g_warning ("failed to set profile system-wide: %s",
error->message);
g_error_free (error);
goto out;
}
out:
if (profile != NULL)
g_object_unref (profile);
}
static GFile *
gcm_prefs_file_chooser_get_icc_profile (CcColorPanel *prefs)
{
GtkWindow *window;
GtkWidget *dialog;
GFile *file = NULL;
GtkFileFilter *filter;
CcColorPanelPrivate *priv = prefs->priv;
/* create new dialog */
window = GTK_WINDOW(gtk_builder_get_object (priv->builder,
"dialog_assign"));
/* TRANSLATORS: an ICC profile is a file containing colorspace data */
dialog = gtk_file_chooser_dialog_new (_("Select ICC Profile File"), window,
GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
_("Import"), GTK_RESPONSE_ACCEPT,
NULL);
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(dialog), g_get_home_dir ());
gtk_file_chooser_set_create_folders (GTK_FILE_CHOOSER(dialog), FALSE);
gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER(dialog), FALSE);
/* setup the filter */
filter = gtk_file_filter_new ();
gtk_file_filter_add_mime_type (filter, "application/vnd.iccprofile");
/* TRANSLATORS: filter name on the file->open dialog */
gtk_file_filter_set_name (filter, _("Supported ICC profiles"));
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
/* setup the all files filter */
filter = gtk_file_filter_new ();
gtk_file_filter_add_pattern (filter, "*");
/* TRANSLATORS: filter name on the file->open dialog */
gtk_file_filter_set_name (filter, _("All files"));
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
/* did user choose file */
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER(dialog));
/* we're done */
gtk_widget_destroy (dialog);
/* or NULL for missing */
return file;
}
static void
gcm_prefs_calibrate_cb (GtkWidget *widget, CcColorPanel *prefs)
{
gboolean ret;
GError *error = NULL;
guint xid;
GPtrArray *argv;
CcColorPanelPrivate *priv = prefs->priv;
/* get xid */
xid = gdk_x11_window_get_xid (gtk_widget_get_window (GTK_WIDGET (priv->main_window)));
/* run with modal set */
argv = g_ptr_array_new_with_free_func (g_free);
g_ptr_array_add (argv, g_build_filename (BINDIR, "gcm-calibrate", NULL));
g_ptr_array_add (argv, g_strdup ("--device"));
g_ptr_array_add (argv, g_strdup (cd_device_get_id (priv->current_device)));
g_ptr_array_add (argv, g_strdup ("--parent-window"));
g_ptr_array_add (argv, g_strdup_printf ("%i", xid));
ret = g_spawn_async (NULL, (gchar**) argv->pdata, NULL, 0,
NULL, NULL, NULL, &error);
if (!ret)
{
g_warning ("failed to run calibrate: %s", error->message);
g_error_free (error);
}
g_ptr_array_unref (argv);
}
static void
gcm_prefs_device_add_cb (GtkWidget *widget, CcColorPanel *prefs)
{
CcColorPanelPrivate *priv = prefs->priv;
/* show ui */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"dialog_virtual"));
gtk_widget_show (widget);
gtk_window_set_transient_for (GTK_WINDOW (widget),
GTK_WINDOW (priv->main_window));
/* clear entries */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"combobox_virtual_type"));
gtk_combo_box_set_active (GTK_COMBO_BOX(widget), 0);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"entry_virtual_model"));
gtk_entry_set_text (GTK_ENTRY (widget), "");
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"entry_virtual_manufacturer"));
gtk_entry_set_text (GTK_ENTRY (widget), "");
}
static gboolean
gcm_prefs_is_profile_suitable_for_device (CdProfile *profile,
CdDevice *device)
{
CdProfileKind profile_kind_tmp;
CdProfileKind profile_kind;
CdColorspace profile_colorspace;
CdColorspace device_colorspace = 0;
gboolean ret = FALSE;
CdDeviceKind device_kind;
/* not the right colorspace */
device_colorspace = cd_device_get_colorspace (device);
profile_colorspace = cd_profile_get_colorspace (profile);
if (device_colorspace != profile_colorspace)
goto out;
/* not the correct kind */
device_kind = cd_device_get_kind (device);
profile_kind_tmp = cd_profile_get_kind (profile);
profile_kind = cd_device_kind_to_profile_kind (device_kind);
if (profile_kind_tmp != profile_kind)
goto out;
/* success */
ret = TRUE;
out:
return ret;
}
static gint
gcm_prefs_combo_sort_func_cb (GtkTreeModel *model,
GtkTreeIter *a,
GtkTreeIter *b,
gpointer user_data)
{
gint type_a, type_b;
gchar *text_a;
gchar *text_b;
gint retval;
/* get data from model */
gtk_tree_model_get (model, a,
GCM_PREFS_COMBO_COLUMN_TYPE, &type_a,
GCM_PREFS_COMBO_COLUMN_TEXT, &text_a,
-1);
gtk_tree_model_get (model, b,
GCM_PREFS_COMBO_COLUMN_TYPE, &type_b,
GCM_PREFS_COMBO_COLUMN_TEXT, &text_b,
-1);
/* prefer normal type profiles over the 'Other Profile...' entry */
if (type_a < type_b)
retval = -1;
else if (type_a > type_b)
retval = 1;
else
retval = g_strcmp0 (text_a, text_b);
g_free (text_a);
g_free (text_b);
return retval;
}
static void
gcm_prefs_add_profiles_suitable_for_devices (CcColorPanel *prefs,
GtkWidget *widget,
CdProfile *profile)
{
CdProfile *profile_tmp;
gboolean ret;
GError *error = NULL;
GPtrArray *profile_array = NULL;
GtkTreeIter iter;
GtkTreeModel *model;
guint i;
CcColorPanelPrivate *priv = prefs->priv;
/* clear existing entries */
model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
gtk_list_store_clear (GTK_LIST_STORE (model));
gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (model),
GCM_PREFS_COMBO_COLUMN_TEXT,
gcm_prefs_combo_sort_func_cb,
model, NULL);
/* get profiles */
profile_array = cd_client_get_profiles_sync (priv->client,
priv->cancellable,
&error);
if (profile_array == NULL)
{
g_warning ("failed to get profiles: %s",
error->message);
g_error_free (error);
goto out;
}
/* add profiles of the right kind */
for (i = 0; i < profile_array->len; i++)
{
profile_tmp = g_ptr_array_index (profile_array, i);
/* don't add the current profile */
if (profile != NULL && cd_profile_equal (profile, profile_tmp))
continue;
/* only add correct types */
ret = gcm_prefs_is_profile_suitable_for_device (profile_tmp,
priv->current_device);
if (!ret)
continue;
/* add */
gcm_prefs_combobox_add_profile (widget,
profile_tmp,
GCM_PREFS_ENTRY_TYPE_PROFILE,
&iter);
}
/* add a import entry */
gcm_prefs_combobox_add_profile (widget, NULL, GCM_PREFS_ENTRY_TYPE_IMPORT, NULL);
gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
out:
if (profile_array != NULL)
g_ptr_array_unref (profile_array);
}
static void
gcm_prefs_profile_add_cb (GtkWidget *widget, CcColorPanel *prefs)
{
CdProfile *profile = NULL;
CcColorPanelPrivate *priv = prefs->priv;
/* add profiles of the right kind */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"combobox_profile"));
profile = cd_device_get_default_profile (priv->current_device);
gcm_prefs_add_profiles_suitable_for_devices (prefs, widget, profile);
/* show the dialog */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"dialog_assign"));
gtk_widget_show (widget);
gtk_window_set_transient_for (GTK_WINDOW (widget), GTK_WINDOW (priv->main_window));
if (profile != NULL)
g_object_unref (profile);
}
static void
gcm_prefs_profile_remove_cb (GtkWidget *widget, CcColorPanel *prefs)
{
GtkTreeIter iter;
GtkTreeSelection *selection;
GtkTreeModel *model;
gboolean ret = FALSE;
CdProfile *profile = NULL;
GError *error = NULL;
CcColorPanelPrivate *priv = prefs->priv;
/* get the selected row */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"treeview_devices"));
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
if (!gtk_tree_selection_get_selected (selection, &model, &iter))
g_assert_not_reached ();
/* if the profile is default, then we'll have to make the first profile default */
gtk_tree_model_get (model, &iter,
GCM_PREFS_COLUMN_PROFILE, &profile,
-1);
/* just remove it, the list store will get ::changed */
ret = cd_device_remove_profile_sync (priv->current_device,
profile,
priv->cancellable,
&error);
if (!ret)
{
g_warning ("failed to remove profile: %s", error->message);
g_error_free (error);
goto out;
}
out:
if (profile != NULL)
g_object_unref (profile);
return;
}
static void
gcm_prefs_profile_make_default_internal (CcColorPanel *prefs,
GtkTreeModel *model,
GtkTreeIter *iter_selected)
{
CdProfile *profile;
GError *error = NULL;
gboolean ret = FALSE;
CcColorPanelPrivate *priv = prefs->priv;
/* get currentlt selected item */
gtk_tree_model_get (model, iter_selected,
GCM_PREFS_COLUMN_PROFILE, &profile,
-1);
if (profile == NULL)
goto out;
/* just set it default */
ret = cd_device_make_profile_default_sync (priv->current_device,
profile,
priv->cancellable,
&error);
if (!ret)
{
g_warning ("failed to set default profile: %s", error->message);
g_error_free (error);
goto out;
}
out:
if (profile != NULL)
g_object_unref (profile);
}
static void
gcm_prefs_profile_view_cb (GtkWidget *widget, CcColorPanel *prefs)
{
CdProfile *profile = NULL;
GtkTreeIter iter;
GtkTreeModel *model;
GtkTreeSelection *selection;
gchar *options = NULL;
GPtrArray *argv = NULL;
guint xid;
gboolean ret;
GError *error = NULL;
CcColorPanelPrivate *priv = prefs->priv;
/* get the selected row */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"treeview_devices"));
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
if (!gtk_tree_selection_get_selected (selection, &model, &iter))
g_assert_not_reached ();
/* get currentlt selected item */
gtk_tree_model_get (model, &iter,
GCM_PREFS_COLUMN_PROFILE, &profile,
-1);
/* get xid */
xid = gdk_x11_window_get_xid (gtk_widget_get_window (GTK_WIDGET (priv->main_window)));
/* open up gcm-viewer as a info pane */
argv = g_ptr_array_new_with_free_func (g_free);
g_ptr_array_add (argv, g_build_filename (BINDIR, "gcm-viewer", NULL));
g_ptr_array_add (argv, g_strdup ("--profile"));
g_ptr_array_add (argv, g_strdup (cd_profile_get_id (profile)));
g_ptr_array_add (argv, g_strdup ("--parent-window"));
g_ptr_array_add (argv, g_strdup_printf ("%i", xid));
ret = g_spawn_async (NULL, (gchar**) argv->pdata, NULL, 0,
NULL, NULL, NULL, &error);
if (!ret)
{
g_warning ("failed to run calibrate: %s", error->message);
g_error_free (error);
}
if (argv != NULL)
g_ptr_array_unref (argv);
g_free (options);
if (profile != NULL)
g_object_unref (profile);
}
static void
gcm_prefs_button_assign_cancel_cb (GtkWidget *widget, CcColorPanel *prefs)
{
CcColorPanelPrivate *priv = prefs->priv;
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"dialog_assign"));
gtk_widget_hide (widget);
}
static void
gcm_prefs_button_assign_ok_cb (GtkWidget *widget, CcColorPanel *prefs)
{
GtkTreeIter iter;
GtkTreeModel *model;
CdProfile *profile = NULL;
gboolean ret = FALSE;
GError *error = NULL;
CcColorPanelPrivate *priv = prefs->priv;
/* hide window */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"dialog_assign"));
gtk_widget_hide (widget);
/* get entry */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"combobox_profile"));
ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter);
if (!ret)
goto out;
model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget));
gtk_tree_model_get (model, &iter,
GCM_PREFS_COMBO_COLUMN_PROFILE, &profile,
-1);
/* just add it, the list store will get ::changed */
ret = cd_device_add_profile_sync (priv->current_device,
CD_DEVICE_RELATION_HARD,
profile,
priv->cancellable,
&error);
if (!ret)
{
g_warning ("failed to add: %s", error->message);
g_error_free (error);
goto out;
}
/* make it default */
ret = cd_device_make_profile_default_sync (priv->current_device,
profile,
priv->cancellable,
&error);
if (!ret)
{
g_warning ("failed to set default: %s", error->message);
g_error_free (error);
goto out;
}
out:
if (profile != NULL)
g_object_unref (profile);
}
static gboolean
gcm_prefs_profile_delete_event_cb (GtkWidget *widget,
GdkEvent *event,
CcColorPanel *prefs)
{
gcm_prefs_button_assign_cancel_cb (widget, prefs);
return TRUE;
}
static void
gcm_prefs_delete_cb (GtkWidget *widget, CcColorPanel *prefs)
{
gboolean ret = FALSE;
GError *error = NULL;
CcColorPanelPrivate *priv = prefs->priv;
/* try to delete device */
ret = cd_client_delete_device_sync (priv->client,
cd_device_get_id (priv->current_device),
priv->cancellable,
&error);
if (!ret)
{
g_warning ("failed to delete device: %s", error->message);
g_error_free (error);
}
}
static void
gcm_prefs_treeview_renderer_toggled (GtkCellRendererToggle *cell,
const gchar *path, CcColorPanel *prefs)
{
gboolean ret;
GtkTreeModel *model;
GtkTreeIter iter;
CcColorPanelPrivate *priv = prefs->priv;
model = GTK_TREE_MODEL (priv->list_store_devices);
ret = gtk_tree_model_get_iter_from_string (model, &iter, path);
if (!ret)
return;
gcm_prefs_profile_make_default_internal (prefs, model, &iter);
}
static void
gcm_prefs_add_devices_columns (CcColorPanel *prefs,
GtkTreeView *treeview)
{
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
CcColorPanelPrivate *priv = prefs->priv;
gtk_tree_view_set_headers_visible (treeview, TRUE);
/* --- column for device image and device title --- */
column = gtk_tree_view_column_new ();
gtk_tree_view_column_set_expand (column, TRUE);
/* TRANSLATORS: column for device list */
gtk_tree_view_column_set_title (column, _("Device"));
/* image */
renderer = gtk_cell_renderer_pixbuf_new ();
g_object_set (renderer, "stock-size", GTK_ICON_SIZE_MENU, NULL);
gtk_tree_view_column_pack_start (column, renderer, FALSE);
gtk_tree_view_column_add_attribute (column, renderer,
"icon-name", GCM_PREFS_COLUMN_ICON);
/* option */
renderer = gtk_cell_renderer_toggle_new ();
g_signal_connect (renderer, "toggled",
G_CALLBACK (gcm_prefs_treeview_renderer_toggled), prefs);
g_object_set (renderer, "radio", TRUE, NULL);
gtk_tree_view_column_pack_start (column, renderer, FALSE);
gtk_tree_view_column_add_attribute (column, renderer,
"active", GCM_PREFS_COLUMN_RADIO_ACTIVE);
gtk_tree_view_column_add_attribute (column, renderer,
"visible", GCM_PREFS_COLUMN_RADIO_VISIBLE);
/* text */
renderer = gtk_cell_renderer_text_new ();
gtk_tree_view_column_pack_start (column, renderer, TRUE);
gtk_tree_view_column_add_attribute (column, renderer,
"markup", GCM_PREFS_COLUMN_TITLE);
gtk_tree_view_column_set_expand (column, TRUE);
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (priv->list_store_devices),
GCM_PREFS_COLUMN_SORT,
GTK_SORT_DESCENDING);
gtk_tree_view_append_column (treeview, GTK_TREE_VIEW_COLUMN(column));
/* --- column for device status --- */
column = gtk_tree_view_column_new ();
gtk_tree_view_column_set_expand (column, TRUE);
/* TRANSLATORS: column for device list */
gtk_tree_view_column_set_title (column, _("Calibration"));
/* image */
renderer = gtk_cell_renderer_pixbuf_new ();
g_object_set (renderer, "stock-size", GTK_ICON_SIZE_MENU, NULL);
gtk_tree_view_column_pack_start (column, renderer, FALSE);
gtk_tree_view_column_add_attribute (column, renderer,
"icon-name", GCM_PREFS_COLUMN_STATUS_IMAGE);
/* text */
renderer = gtk_cell_renderer_text_new ();
gtk_tree_view_column_pack_start (column, renderer, TRUE);
gtk_tree_view_column_add_attribute (column, renderer,
"markup", GCM_PREFS_COLUMN_STATUS);
gtk_tree_view_column_set_expand (column, FALSE);
gtk_tree_view_append_column (treeview, GTK_TREE_VIEW_COLUMN(column));
/* tooltip */
gtk_tree_view_set_tooltip_column (treeview,
GCM_PREFS_COLUMN_TOOLTIP);
}
static void
gcm_prefs_set_calibrate_button_sensitivity (CcColorPanel *prefs)
{
gboolean ret = FALSE;
GtkWidget *widget;
const gchar *tooltip;
CdDeviceKind kind;
CcColorPanelPrivate *priv = prefs->priv;
/* TRANSLATORS: this is when the button is sensitive */
tooltip = _("Create a color profile for the selected device");
/* no device selected */
if (priv->current_device == NULL)
goto out;
/* are we a display */
kind = cd_device_get_kind (priv->current_device);
if (kind == CD_DEVICE_KIND_DISPLAY)
{
/* find whether we have hardware installed */
if (priv->sensor == NULL) {
/* TRANSLATORS: this is when the button is insensitive */
tooltip = _("The measuring instrument is not detected. Please check it is turned on and correctly connected.");
goto out;
}
/* success */
ret = TRUE;
}
else if (kind == CD_DEVICE_KIND_SCANNER ||
kind == CD_DEVICE_KIND_CAMERA ||
kind == CD_DEVICE_KIND_WEBCAM)
{
/* TODO: find out if we can scan using gnome-scan */
ret = TRUE;
}
else if (kind == CD_DEVICE_KIND_PRINTER)
{
/* find whether we have hardware installed */
if (priv->sensor == NULL)
{
/* TRANSLATORS: this is when the button is insensitive */
tooltip = _("The measuring instrument is not detected. Please check it is turned on and correctly connected.");
goto out;
}
/* find whether we have hardware installed */
ret = cd_sensor_has_cap (priv->sensor, CD_SENSOR_CAP_PRINTER);
if (!ret)
{
/* TRANSLATORS: this is when the button is insensitive */
tooltip = _("The measuring instrument does not support printer profiling.");
goto out;
}
/* success */
ret = TRUE;
}
else
{
/* TRANSLATORS: this is when the button is insensitive */
tooltip = _("The device type is not currently supported.");
}
out:
/* control the tooltip and sensitivity of the button */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"toolbutton_device_calibrate"));
gtk_widget_set_tooltip_text (widget, tooltip);
gtk_widget_set_sensitive (widget, ret);
}
static void
gcm_prefs_device_clicked (CcColorPanel *prefs, CdDevice *device)
{
GtkWidget *widget;
CdDeviceMode device_mode;
CcColorPanelPrivate *priv = prefs->priv;
if (device == NULL)
g_assert_not_reached ();
/* get current device */
if (priv->current_device != NULL)
g_object_unref (priv->current_device);
priv->current_device = g_object_ref (device);
/* we have a new device */
g_debug ("selected device is: %s",
cd_device_get_id (device));
/* make sure selectable */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"combobox_profile"));
gtk_widget_set_sensitive (widget, TRUE);
/* can we delete this device? */
device_mode = cd_device_get_mode (priv->current_device);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"toolbutton_device_remove"));
gtk_widget_set_visible (widget, device_mode == CD_DEVICE_MODE_VIRTUAL);
/* can this device calibrate */
gcm_prefs_set_calibrate_button_sensitivity (prefs);
}
static void
gcm_prefs_profile_clicked (CcColorPanel *prefs, CdProfile *profile, CdDevice *device)
{
GtkWidget *widget;
CdDeviceRelation relation;
CcColorPanelPrivate *priv = prefs->priv;
/* get profile */
g_debug ("selected profile = %s",
cd_profile_get_filename (profile));
/* find the profile relationship */
relation = cd_device_get_profile_relation (device,
profile,
NULL, NULL);
/* we can only remove hard relationships */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"toolbutton_profile_remove"));
if (relation == CD_DEVICE_RELATION_HARD)
{
gtk_widget_set_tooltip_text (widget, "");
gtk_widget_set_sensitive (widget, TRUE);
}
else
{
/* TRANSLATORS: this is when an auto-added profile cannot be removed */
gtk_widget_set_tooltip_text (widget, _("Cannot remove automatically added profile"));
gtk_widget_set_sensitive (widget, FALSE);
}
/* allow getting profile info */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"toolbutton_profile_view"));
gtk_widget_set_sensitive (widget, TRUE);
}
static void
gcm_prefs_devices_treeview_clicked_cb (GtkTreeSelection *selection,
CcColorPanel *prefs)
{
GtkTreeModel *model;
GtkTreeIter iter;
CdDevice *device = NULL;
CdProfile *profile = NULL;
GtkWidget *widget;
CcColorPanelPrivate *priv = prefs->priv;
/* get selection */
if (!gtk_tree_selection_get_selected (selection, &model, &iter))
g_assert_not_reached ();
gtk_tree_model_get (model, &iter,
GCM_PREFS_COLUMN_DEVICE, &device,
GCM_PREFS_COLUMN_PROFILE, &profile,
-1);
/* device actions */
if (device != NULL)
gcm_prefs_device_clicked (prefs, device);
if (profile != NULL)
gcm_prefs_profile_clicked (prefs, profile, device);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"toolbutton_device_default"));
gtk_widget_set_visible (widget, FALSE);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"toolbutton_device_add"));
gtk_widget_set_visible (widget, FALSE);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"toolbutton_device_calibrate"));
gtk_widget_set_visible (widget, profile == NULL);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"toolbutton_profile_view"));
gtk_widget_set_visible (widget, profile != NULL);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"toolbutton_profile_remove"));
gtk_widget_set_visible (widget, profile != NULL);
if (device != NULL)
g_object_unref (device);
if (profile != NULL)
g_object_unref (profile);
}
static void
gcm_prefs_treeview_row_activated_cb (GtkTreeView *tree_view,
GtkTreePath *path,
GtkTreeViewColumn *column,
CcColorPanel *prefs)
{
GtkTreeModel *model;
GtkTreeIter iter;
gboolean ret;
CcColorPanelPrivate *priv = prefs->priv;
/* get the iter */
model = GTK_TREE_MODEL (priv->list_store_devices);
ret = gtk_tree_model_get_iter (model, &iter, path);
if (!ret)
return;
/* make this profile the default */
gcm_prefs_profile_make_default_internal (prefs, model, &iter);
}
static const gchar *
gcm_prefs_device_kind_to_sort (CdDeviceKind kind)
{
if (kind == CD_DEVICE_KIND_DISPLAY)
return "4";
if (kind == CD_DEVICE_KIND_SCANNER)
return "3";
if (kind == CD_DEVICE_KIND_CAMERA)
return "2";
if (kind == CD_DEVICE_KIND_PRINTER)
return "1";
return "0";
}
static gchar *
gcm_device_get_title (CdDevice *device)
{
const gchar *model;
const gchar *vendor;
GString *string;
/* try to get a nice string suitable for display */
vendor = cd_device_get_vendor (device);
model = cd_device_get_model (device);
string = g_string_new ("");
if (vendor != NULL && model != NULL)
{
g_string_append_printf (string, "%s - %s",
vendor, model);
goto out;
}
/* just model */
if (model != NULL)
{
g_string_append (string, model);
goto out;
}
/* just vendor */
if (vendor != NULL)
{
g_string_append (string, vendor);
goto out;
}
/* fallback to id */
g_string_append (string, cd_device_get_id (device));
out:
return g_string_free (string, FALSE);
}
static void
gcm_prefs_set_combo_simple_text (GtkWidget *combo_box)
{
GtkCellRenderer *renderer;
GtkListStore *store;
store = gtk_list_store_new (GCM_PREFS_COMBO_COLUMN_NUM_COLUMNS,
G_TYPE_STRING,
CD_TYPE_PROFILE,
G_TYPE_UINT);
gtk_combo_box_set_model (GTK_COMBO_BOX (combo_box),
GTK_TREE_MODEL (store));
g_object_unref (store);
renderer = gtk_cell_renderer_text_new ();
g_object_set (renderer,
"ellipsize", PANGO_ELLIPSIZE_END,
"wrap-mode", PANGO_WRAP_WORD_CHAR,
"width-chars", 60,
NULL);
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE);
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer,
"text", GCM_PREFS_COMBO_COLUMN_TEXT,
NULL);
}
static void
gcm_prefs_profile_combo_changed_cb (GtkWidget *widget,
CcColorPanel *prefs)
{
GFile *file = NULL;
gboolean ret;
CdProfile *profile = NULL;
GtkTreeIter iter;
GtkTreeModel *model;
GcmPrefsEntryType entry_type;
CcColorPanelPrivate *priv = prefs->priv;
/* no devices */
if (priv->current_device == NULL)
return;
/* no selection */
ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter);
if (!ret)
return;
/* get entry */
model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget));
gtk_tree_model_get (model, &iter,
GCM_PREFS_COMBO_COLUMN_TYPE, &entry_type,
-1);
/* import */
if (entry_type == GCM_PREFS_ENTRY_TYPE_IMPORT)
{
file = gcm_prefs_file_chooser_get_icc_profile (prefs);
if (file == NULL)
{
g_warning ("failed to get ICC file");
gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
goto out;
}
/* add to combobox */
gtk_list_store_append (GTK_LIST_STORE(model), &iter);
gtk_list_store_set (GTK_LIST_STORE(model), &iter,
GCM_PREFS_COMBO_COLUMN_PROFILE, profile,
-1);
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (widget), &iter);
}
out:
if (file != NULL)
g_object_unref (file);
if (profile != NULL)
g_object_unref (profile);
}
static void
gcm_prefs_sensor_coldplug (CcColorPanel *prefs)
{
GPtrArray *sensors;
GError *error = NULL;
CcColorPanelPrivate *priv = prefs->priv;
/* unref old */
if (priv->sensor != NULL)
{
g_object_unref (priv->sensor);
priv->sensor = NULL;
}
/* no present */
sensors = cd_client_get_sensors_sync (priv->client, NULL, &error);
if (sensors == NULL)
{
g_warning ("%s", error->message);
g_error_free (error);
goto out;
}
if (sensors->len == 0)
goto out;
/* save a copy of the sensor */
priv->sensor = g_object_ref (g_ptr_array_index (sensors, 0));
out:
if (sensors != NULL)
g_ptr_array_unref (sensors);
}
static void
gcm_prefs_client_sensor_changed_cb (CdClient *client,
CdSensor *sensor,
CcColorPanel *prefs)
{
gcm_prefs_sensor_coldplug (prefs);
gcm_prefs_set_calibrate_button_sensitivity (prefs);
}
static const gchar *
gcm_prefs_device_kind_to_icon_name (CdDeviceKind kind)
{
if (kind == CD_DEVICE_KIND_DISPLAY)
return "video-display";
if (kind == CD_DEVICE_KIND_SCANNER)
return "scanner";
if (kind == CD_DEVICE_KIND_PRINTER)
return "printer";
if (kind == CD_DEVICE_KIND_CAMERA)
return "camera-photo";
if (kind == CD_DEVICE_KIND_CAMERA)
return "camera-photo";
if (kind == CD_DEVICE_KIND_WEBCAM)
return "camera-web";
return "image-missing";
}
static gboolean
gcm_prefs_profile_is_based_from_edid (CdProfile *profile)
{
if (cd_profile_get_kind (profile) != CD_PROFILE_KIND_DISPLAY_DEVICE)
return FALSE;
if (cd_profile_get_metadata_item (profile, "EDID_md5") == NULL)
return FALSE;
return TRUE;
}
static GString *
gcm_prefs_get_profile_age_as_string (CdProfile *profile)
{
gint64 age;
GString *string;
if (profile == NULL)
{
/* TRANSLATORS: this is when there is no profile for the device */
string = g_string_new (_("No profile"));
goto out;
}
/* days */
age = cd_profile_get_age (profile);
if (age == 0)
{
string = g_string_new (NULL);
goto out;
}
age /= 60 * 60 * 24;
string = g_string_new ("");
/* approximate years */
if (age > 365)
{
age /= 365;
g_string_append_printf (string, ngettext (
"%i year",
"%i years",
age), (guint) age);
goto out;
}
/* approximate months */
if (age > 30)
{
age /= 30;
g_string_append_printf (string, ngettext (
"%i month",
"%i months",
age), (guint) age);
goto out;
}
/* approximate weeks */
if (age > 7)
{
age /= 7;
g_string_append_printf (string, ngettext (
"%i week",
"%i weeks",
age), (guint) age);
goto out;
}
/* fallback */
g_string_append_printf (string, _("Less than 1 week"));
out:
return string;
}
static gchar *
gcm_prefs_get_profile_created_for_sort (CdProfile *profile)
{
gint64 created;
gchar *string = NULL;
GDateTime *dt = NULL;
/* get profile age */
created = cd_profile_get_created (profile);
if (created == 0)
goto out;
dt = g_date_time_new_from_unix_utc (created);
/* note: this is not shown in the UI, just used for sorting */
string = g_date_time_format (dt, "%Y%m%d");
out:
if (dt != NULL)
g_date_time_unref (dt);
return string;
}
static gchar *
gcm_prefs_get_profile_title (CdProfile *profile)
{
CdColorspace colorspace;
const gchar *title;
gchar *string;
g_return_val_if_fail (profile != NULL, NULL);
/* add profile description */
title = cd_profile_get_title (profile);
if (title != NULL)
{
string = g_strdup (title);
goto out;
}
/* some meta profiles do not have ICC profiles */
colorspace = cd_profile_get_colorspace (profile);
if (colorspace == CD_COLORSPACE_RGB)
{
string = g_strdup (C_("Colorspace fallback", "Default RGB"));
goto out;
}
if (colorspace == CD_COLORSPACE_CMYK)
{
string = g_strdup (C_("Colorspace fallback", "Default CMYK"));
goto out;
}
if (colorspace == CD_COLORSPACE_GRAY)
{
string = g_strdup (C_("Colorspace fallback", "Default Gray"));
goto out;
}
/* fall back to ID, ick */
string = g_strdup (cd_profile_get_id (profile));
out:
return string;
}
static void
gcm_prefs_device_remove_profiles_phase1 (CcColorPanel *prefs, GtkTreeIter *parent)
{
GtkTreeIter iter;
GtkTreeModel *model;
gboolean ret;
CcColorPanelPrivate *priv = prefs->priv;
/* get first element */
model = GTK_TREE_MODEL (priv->list_store_devices);
ret = gtk_tree_model_iter_children (model, &iter, parent);
if (!ret)
return;
/* mark to be removed */
do {
gtk_tree_store_set (priv->list_store_devices, &iter,
GCM_PREFS_COLUMN_DEVICE_ID, NULL,
-1);
} while (gtk_tree_model_iter_next (model, &iter));
}
static void
gcm_prefs_device_remove_profiles_phase2 (CcColorPanel *prefs, GtkTreeIter *parent)
{
GtkTreeIter iter;
GtkTreeModel *model;
gchar *id_tmp;
gboolean ret;
CcColorPanelPrivate *priv = prefs->priv;
/* get first element */
model = GTK_TREE_MODEL (priv->list_store_devices);
ret = gtk_tree_model_iter_children (model, &iter, parent);
if (!ret)
return;
/* remove the other elements */
do
{
gtk_tree_model_get (model, &iter,
GCM_PREFS_COLUMN_DEVICE_ID, &id_tmp,
-1);
if (id_tmp == NULL)
ret = gtk_tree_store_remove (priv->list_store_devices, &iter);
else
ret = gtk_tree_model_iter_next (model, &iter);
g_free (id_tmp);
} while (ret);
}
static GtkTreeIter *
get_iter_for_profile (GtkTreeModel *model, CdProfile *profile, GtkTreeIter *parent)
{
const gchar *id;
GtkTreeIter iter_tmp;
gboolean ret;
GtkTreeIter *iter = NULL;
CdProfile *profile_tmp;
/* get first element */
ret = gtk_tree_model_iter_children (model, &iter_tmp, parent);
if (!ret)
goto out;
/* remove the other elements */
id = cd_profile_get_id (profile);
do
{
gtk_tree_model_get (model, &iter_tmp,
GCM_PREFS_COLUMN_PROFILE, &profile_tmp,
-1);
if (g_strcmp0 (id, cd_profile_get_id (profile_tmp)) == 0)
iter = &iter_tmp;
g_object_unref (profile_tmp);
} while (iter == NULL && gtk_tree_model_iter_next (model, &iter_tmp));
out:
return iter;
}
static void
gcm_prefs_device_set_model_by_iter (CcColorPanel *prefs, CdDevice *device, GtkTreeIter *iter)
{
GString *status;
const gchar *status_image = NULL;
const gchar *tooltip = NULL;
CdProfile *profile = NULL;
gint age;
GPtrArray *profiles;
CdProfile *profile_tmp;
guint i;
gchar *title_tmp;
GString *date_tmp;
gchar *sort_tmp;
GtkTreeIter iter_tmp;
GtkTreeIter *iter_tmp_p;
guint threshold = 0;
CcColorPanelPrivate *priv = prefs->priv;
/* set status */
profile = cd_device_get_default_profile (device);
if (profile == NULL)
{
status = g_string_new (_("Uncalibrated"));
g_string_prepend (status, "<span foreground='gray'><i>");
g_string_append (status, "</i></span>");
tooltip = _("This device is not color managed.");
goto skip;
}
/* autogenerated printer defaults */
if (cd_device_get_kind (device) == CD_DEVICE_KIND_PRINTER &&
cd_profile_get_filename (profile) == NULL)
{
status = g_string_new (_("Uncalibrated"));
g_string_prepend (status, "<span foreground='gray'><i>");
g_string_append (status, "</i></span>");
tooltip = _("This device is using manufacturing calibrated data.");
goto skip;
}
/* autogenerated profiles are crap */
if (cd_profile_get_kind (profile) == CD_PROFILE_KIND_DISPLAY_DEVICE &&
!cd_profile_get_has_vcgt (profile))
{
status = g_string_new (_("Uncalibrated"));
g_string_prepend (status, "<span foreground='gray'><i>");
g_string_append (status, "</i></span>");
tooltip = _("This device does not have a profile suitable for whole-screen color correction.");
goto skip;
}
/* yay! */
status = gcm_prefs_get_profile_age_as_string (profile);
/* greater than the calibration threshold for the device type */
age = cd_profile_get_age (profile);
age /= 60 * 60 * 24;
if (cd_device_get_kind (device) == CD_DEVICE_KIND_DISPLAY)
{
g_settings_get (priv->settings,
GCM_SETTINGS_RECALIBRATE_DISPLAY_THRESHOLD,
"u",
&threshold);
}
else if (cd_device_get_kind (device) == CD_DEVICE_KIND_DISPLAY)
{
g_settings_get (priv->settings,
GCM_SETTINGS_RECALIBRATE_PRINTER_THRESHOLD,
"u",
&threshold);
}
if (threshold > 0 && age > threshold)
{
status_image = "dialog-warning-symbolic";
tooltip = _("This device has an old profile that may no longer be accurate.");
}
skip:
/* save to store */
gtk_tree_store_set (priv->list_store_devices, iter,
GCM_PREFS_COLUMN_STATUS, status->str,
GCM_PREFS_COLUMN_STATUS_IMAGE, status_image,
GCM_PREFS_COLUMN_TOOLTIP, tooltip,
-1);
/* remove old profiles */
gcm_prefs_device_remove_profiles_phase1 (prefs, iter);
/* add profiles */
profiles = cd_device_get_profiles (device);
if (profiles == NULL)
goto out;
for (i = 0; i < profiles->len; i++)
{
profile_tmp = g_ptr_array_index (profiles, i);
title_tmp = gcm_prefs_get_profile_title (profile_tmp);
/* don't show details for EDID profiles */
if (gcm_prefs_profile_is_based_from_edid (profile_tmp))
{
date_tmp = g_string_new ("Not specified");
g_string_prepend (date_tmp, "<span foreground='gray'><i>");
g_string_append (date_tmp, "</i></span>");
}
else
{
date_tmp = gcm_prefs_get_profile_age_as_string (profile_tmp);
}
sort_tmp = gcm_prefs_get_profile_created_for_sort (profile_tmp);
/* get an existing profile, or create a new one */
iter_tmp_p = get_iter_for_profile (GTK_TREE_MODEL (priv->list_store_devices),
profile_tmp, iter);
if (iter_tmp_p == NULL)
{
gtk_tree_store_append (priv->list_store_devices, &iter_tmp, iter);
iter_tmp_p = &iter_tmp;
}
gtk_tree_store_set (priv->list_store_devices, iter_tmp_p,
GCM_PREFS_COLUMN_DEVICE, device,
GCM_PREFS_COLUMN_PROFILE, profile_tmp,
GCM_PREFS_COLUMN_DEVICE_ID, cd_device_get_id (device),
GCM_PREFS_COLUMN_SORT, sort_tmp,
GCM_PREFS_COLUMN_STATUS, date_tmp->str,
GCM_PREFS_COLUMN_TITLE, title_tmp,
GCM_PREFS_COLUMN_RADIO_VISIBLE, TRUE,
GCM_PREFS_COLUMN_RADIO_ACTIVE, i==0,
-1);
g_free (title_tmp);
g_free (sort_tmp);
g_string_free (date_tmp, TRUE);
}
/* remove old profiles that no longer exist */
gcm_prefs_device_remove_profiles_phase2 (prefs, iter);
out:
g_string_free (status, TRUE);
if (profiles != NULL)
g_ptr_array_unref (profiles);
if (profile != NULL)
g_object_unref (profile);
}
static void
gcm_prefs_device_changed_cb (CdDevice *device, CcColorPanel *prefs)
{
GtkTreeIter iter;
GtkTreeModel *model;
const gchar *id;
gchar *id_tmp;
gboolean ret;
CcColorPanelPrivate *priv = prefs->priv;
/* get first element */
model = GTK_TREE_MODEL (priv->list_store_devices);
ret = gtk_tree_model_get_iter_first (model, &iter);
if (!ret)
return;
/* get the other elements */
id = cd_device_get_id (device);
do
{
gtk_tree_model_get (model, &iter,
GCM_PREFS_COLUMN_DEVICE_ID, &id_tmp,
-1);
if (g_strcmp0 (id_tmp, id) == 0)
gcm_prefs_device_set_model_by_iter (prefs, device, &iter);
g_free (id_tmp);
} while (gtk_tree_model_iter_next (model, &iter));
}
static void
gcm_prefs_add_device (CcColorPanel *prefs, CdDevice *device)
{
CdDeviceKind kind;
const gchar *icon_name;
const gchar *id;
gchar *sort = NULL;
gchar *title = NULL;
GtkTreeIter parent;
CcColorPanelPrivate *priv = prefs->priv;
/* get icon */
kind = cd_device_get_kind (device);
icon_name = gcm_prefs_device_kind_to_icon_name (kind);
/* italic for non-connected devices */
title = gcm_device_get_title (device);
/* create sort order */
sort = g_strdup_printf ("%s%s",
gcm_prefs_device_kind_to_sort (kind),
title);
/* watch for changes to update the status icons */
g_signal_connect (device, "changed",
G_CALLBACK (gcm_prefs_device_changed_cb), prefs);
/* add to list */
id = cd_device_get_id (device);
g_debug ("add %s to device list", id);
gtk_tree_store_append (priv->list_store_devices, &parent, NULL);
gtk_tree_store_set (priv->list_store_devices, &parent,
GCM_PREFS_COLUMN_DEVICE, device,
GCM_PREFS_COLUMN_DEVICE_ID, id,
GCM_PREFS_COLUMN_SORT, sort,
GCM_PREFS_COLUMN_TITLE, title,
GCM_PREFS_COLUMN_ICON, icon_name,
-1);
gcm_prefs_device_set_model_by_iter (prefs, device, &parent);
g_free (sort);
g_free (title);
}
static void
gcm_prefs_remove_device (CcColorPanel *prefs, CdDevice *cd_device)
{
GtkTreeIter iter;
GtkTreeModel *model;
const gchar *id;
gchar *id_tmp;
gboolean ret;
CcColorPanelPrivate *priv = prefs->priv;
/* remove */
id = cd_device_get_id (cd_device);
/* get first element */
model = GTK_TREE_MODEL (priv->list_store_devices);
ret = gtk_tree_model_get_iter_first (model, &iter);
if (!ret)
return;
/* get the other elements */
do
{
gtk_tree_model_get (model, &iter,
GCM_PREFS_COLUMN_DEVICE_ID, &id_tmp,
-1);
if (g_strcmp0 (id_tmp, id) == 0)
{
gtk_list_store_remove (GTK_LIST_STORE(model), &iter);
g_free (id_tmp);
break;
}
g_free (id_tmp);
} while (gtk_tree_model_iter_next (model, &iter));
}
static void
gcm_prefs_device_added_cb (CdClient *client,
CdDevice *device,
CcColorPanel *prefs)
{
/* remove the saved device if it's already there */
gcm_prefs_remove_device (prefs, device);
/* add the device */
gcm_prefs_add_device (prefs, device);
}
static void
gcm_prefs_changed_cb (CdClient *client,
CdDevice *device,
CcColorPanel *prefs)
{
g_debug ("changed: %s (doing nothing)", cd_device_get_id (device));
}
static void
gcm_prefs_device_removed_cb (CdClient *client,
CdDevice *device,
CcColorPanel *prefs)
{
GtkTreeIter iter;
GtkTreeSelection *selection;
GtkWidget *widget;
gboolean ret;
CcColorPanelPrivate *priv = prefs->priv;
/* remove from the UI */
gcm_prefs_remove_device (prefs, device);
/* select the first device */
ret = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->list_store_devices), &iter);
if (!ret)
return;
/* click it */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"treeview_devices"));
gtk_tree_view_set_model (GTK_TREE_VIEW (widget),
GTK_TREE_MODEL (priv->list_store_devices));
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
gtk_tree_selection_select_iter (selection, &iter);
}
static void
gcm_prefs_get_devices_cb (GObject *object,
GAsyncResult *res,
gpointer user_data)
{
CcColorPanel *prefs = (CcColorPanel *) user_data;
CdClient *client = CD_CLIENT (object);
CdDevice *device;
GError *error = NULL;
GPtrArray *devices;
GtkTreePath *path;
GtkWidget *widget;
guint i;
CcColorPanelPrivate *priv = prefs->priv;
/* get devices and add them */
devices = cd_client_get_devices_finish (client, res, &error);
if (devices == NULL)
{
g_warning ("failed to add connected devices: %s",
error->message);
g_error_free (error);
goto out;
}
for (i = 0; i < devices->len; i++)
{
device = g_ptr_array_index (devices, i);
gcm_prefs_add_device (prefs, device);
}
/* set the cursor on the first device */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"treeview_devices"));
path = gtk_tree_path_new_from_string ("0");
gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget), path, NULL, FALSE);
gtk_tree_path_free (path);
out:
if (devices != NULL)
g_ptr_array_unref (devices);
}
static void
gcm_prefs_button_virtual_add_cb (GtkWidget *widget, CcColorPanel *prefs)
{
CdDeviceKind device_kind;
CdDevice *device;
const gchar *model;
const gchar *manufacturer;
gchar *device_id;
GError *error = NULL;
GHashTable *device_props;
CcColorPanelPrivate *priv = prefs->priv;
/* get device details */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"combobox_virtual_type"));
device_kind = gtk_combo_box_get_active (GTK_COMBO_BOX(widget)) + 2;
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"entry_virtual_model"));
model = gtk_entry_get_text (GTK_ENTRY (widget));
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"entry_virtual_manufacturer"));
manufacturer = gtk_entry_get_text (GTK_ENTRY (widget));
/* create device */
device_id = g_strdup_printf ("%s-%s-%s",
cd_device_kind_to_string (device_kind),
manufacturer,
model);
device_props = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_free);
g_hash_table_insert (device_props,
g_strdup ("Kind"),
g_strdup (cd_device_kind_to_string (device_kind)));
g_hash_table_insert (device_props,
g_strdup ("Mode"),
g_strdup (cd_device_mode_to_string (CD_DEVICE_MODE_VIRTUAL)));
g_hash_table_insert (device_props,
g_strdup ("Colorspace"),
g_strdup (cd_colorspace_to_string (CD_COLORSPACE_RGB)));
g_hash_table_insert (device_props,
g_strdup ("Model"),
g_strdup (model));
g_hash_table_insert (device_props,
g_strdup ("Vendor"),
g_strdup (manufacturer));
device = cd_client_create_device_sync (priv->client,
device_id,
CD_OBJECT_SCOPE_DISK,
device_props,
priv->cancellable,
&error);
if (device == NULL)
{
g_warning ("Failed to add create virtual device: %s",
error->message);
g_error_free (error);
goto out;
}
out:
g_hash_table_unref (device_props);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"dialog_virtual"));
gtk_widget_hide (widget);
g_free (device_id);
}
static void
gcm_prefs_button_virtual_cancel_cb (GtkWidget *widget, CcColorPanel *prefs)
{
CcColorPanelPrivate *priv = prefs->priv;
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"dialog_virtual"));
gtk_widget_hide (widget);
}
static gboolean
gcm_prefs_virtual_delete_event_cb (GtkWidget *widget,
GdkEvent *event,
CcColorPanel *prefs)
{
gcm_prefs_button_virtual_cancel_cb (widget, prefs);
return TRUE;
}
static const gchar *
cd_device_kind_to_localised_string (CdDeviceKind device_kind)
{
if (device_kind == CD_DEVICE_KIND_DISPLAY)
return C_("Device kind", "Display");
if (device_kind == CD_DEVICE_KIND_SCANNER)
return C_("Device kind", "Scanner");
if (device_kind == CD_DEVICE_KIND_PRINTER)
return C_("Device kind", "Printer");
if (device_kind == CD_DEVICE_KIND_CAMERA)
return C_("Device kind", "Camera");
if (device_kind == CD_DEVICE_KIND_WEBCAM)
return C_("Device kind", "Webcam");
return NULL;
}
static void
gcm_prefs_setup_virtual_combobox (GtkWidget *widget)
{
guint i;
const gchar *text;
for (i=CD_DEVICE_KIND_SCANNER; i<CD_DEVICE_KIND_LAST; i++)
{
text = cd_device_kind_to_localised_string (i);
if (text == NULL)
continue;
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT(widget), text);
}
gtk_combo_box_set_active (GTK_COMBO_BOX (widget), CD_DEVICE_KIND_PRINTER - 2);
}
static gboolean
gcm_prefs_virtual_set_from_file (CcColorPanel *prefs, GFile *file)
{
/* TODO: use GCM to get the EXIF data */
return FALSE;
}
static void
gcm_prefs_virtual_drag_data_received_cb (GtkWidget *widget,
GdkDragContext *context,
gint x, gint y,
GtkSelectionData *data,
guint info,
guint _time,
CcColorPanel *prefs)
{
const guchar *filename;
gchar **filenames = NULL;
GFile *file = NULL;
guint i;
gboolean ret;
/* get filenames */
filename = gtk_selection_data_get_data (data);
if (filename == NULL)
{
gtk_drag_finish (context, FALSE, FALSE, _time);
goto out;
}
/* import this */
g_debug ("dropped: %p (%s)", data, filename);
/* split, as multiple drag targets are accepted */
filenames = g_strsplit_set ((const gchar *)filename, "\r\n", -1);
for (i = 0; filenames[i] != NULL; i++)
{
/* blank entry */
if (filenames[i][0] == '\0')
continue;
/* check this is a parsable file */
g_debug ("trying to set %s", filenames[i]);
file = g_file_new_for_uri (filenames[i]);
ret = gcm_prefs_virtual_set_from_file (prefs, file);
if (!ret)
{
g_debug ("%s did not set from file correctly",
filenames[i]);
gtk_drag_finish (context, FALSE, FALSE, _time);
goto out;
}
g_object_unref (file);
file = NULL;
}
gtk_drag_finish (context, TRUE, FALSE, _time);
out:
if (file != NULL)
g_object_unref (file);
g_strfreev (filenames);
}
static void
gcm_prefs_setup_drag_and_drop (GtkWidget *widget)
{
GtkTargetEntry entry;
/* setup a dummy entry */
entry.target = g_strdup ("text/plain");
entry.flags = GTK_TARGET_OTHER_APP;
entry.info = 0;
gtk_drag_dest_set (widget,
GTK_DEST_DEFAULT_ALL,
&entry,
1,
GDK_ACTION_MOVE | GDK_ACTION_COPY);
g_free (entry.target);
}
static void
cc_color_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_color_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_color_panel_dispose (GObject *object)
{
CcColorPanelPrivate *priv = CC_COLOR_PANEL (object)->priv;
if (priv->settings)
{
g_object_unref (priv->settings);
priv->settings = NULL;
}
if (priv->cancellable != NULL)
{
g_cancellable_cancel (priv->cancellable);
g_object_unref (priv->cancellable);
priv->cancellable = NULL;
}
if (priv->builder != NULL)
{
g_object_unref (priv->builder);
priv->builder = NULL;
}
if (priv->client != NULL)
{
g_object_unref (priv->client);
priv->client = NULL;
}
if (priv->current_device != NULL)
{
g_object_unref (priv->current_device);
priv->current_device = NULL;
}
if (priv->sensor != NULL)
{
g_object_unref (priv->sensor);
priv->sensor = NULL;
}
G_OBJECT_CLASS (cc_color_panel_parent_class)->dispose (object);
}
static void
cc_color_panel_finalize (GObject *object)
{
G_OBJECT_CLASS (cc_color_panel_parent_class)->finalize (object);
}
static void
cc_color_panel_class_init (CcColorPanelClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (CcColorPanelPrivate));
object_class->get_property = cc_color_panel_get_property;
object_class->set_property = cc_color_panel_set_property;
object_class->dispose = cc_color_panel_dispose;
object_class->finalize = cc_color_panel_finalize;
}
static void
cc_color_panel_class_finalize (CcColorPanelClass *klass)
{
}
static void
cc_color_panel_init (CcColorPanel *prefs)
{
CcColorPanelPrivate *priv;
gboolean ret;
gchar *text = NULL;
GError *error = NULL;
GtkStyleContext *context;
GtkTreeSelection *selection;
GtkWidget *widget;
priv = prefs->priv = COLOR_PANEL_PRIVATE (prefs);
priv->builder = gtk_builder_new ();
gtk_builder_add_from_file (priv->builder,
GNOMECC_UI_DIR "/color.ui",
&error);
if (error != NULL)
{
g_warning ("Could not load interface file: %s", error->message);
g_error_free (error);
return;
}
priv->cancellable = g_cancellable_new ();
/* setup defaults */
priv->settings = g_settings_new (GCM_SETTINGS_SCHEMA);
/* create list stores */
priv->list_store_devices = gtk_tree_store_new (GCM_PREFS_COLUMN_NUM_COLUMNS,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_STRING,
CD_TYPE_DEVICE,
CD_TYPE_PROFILE,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_BOOLEAN,
G_TYPE_BOOLEAN);
/* assign buttons */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"toolbutton_profile_add"));
g_signal_connect (widget, "clicked",
G_CALLBACK (gcm_prefs_profile_add_cb), prefs);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"toolbutton_profile_remove"));
g_signal_connect (widget, "clicked",
G_CALLBACK (gcm_prefs_profile_remove_cb), prefs);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"toolbutton_profile_view"));
g_signal_connect (widget, "clicked",
G_CALLBACK (gcm_prefs_profile_view_cb), prefs);
/* create device tree view */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"treeview_devices"));
gtk_tree_view_set_model (GTK_TREE_VIEW (widget),
GTK_TREE_MODEL (priv->list_store_devices));
gtk_tree_view_set_enable_tree_lines (GTK_TREE_VIEW (widget), TRUE);
gtk_tree_view_set_level_indentation (GTK_TREE_VIEW (widget), 0);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
g_signal_connect (selection, "changed",
G_CALLBACK (gcm_prefs_devices_treeview_clicked_cb),
prefs);
g_signal_connect (GTK_TREE_VIEW (widget), "row-activated",
G_CALLBACK (gcm_prefs_treeview_row_activated_cb),
prefs);
/* add columns to the tree view */
gcm_prefs_add_devices_columns (prefs, GTK_TREE_VIEW (widget));
/* force to be at least ~6 rows high */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"scrolledwindow_devices"));
gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (widget),
200);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"toolbutton_device_default"));
g_signal_connect (widget, "clicked",
G_CALLBACK (gcm_prefs_default_cb), prefs);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"toolbutton_device_remove"));
g_signal_connect (widget, "clicked",
G_CALLBACK (gcm_prefs_delete_cb), prefs);
gtk_widget_set_sensitive (widget, FALSE);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"toolbutton_device_add"));
g_signal_connect (widget, "clicked",
G_CALLBACK (gcm_prefs_device_add_cb), prefs);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"toolbutton_device_calibrate"));
g_signal_connect (widget, "clicked",
G_CALLBACK (gcm_prefs_calibrate_cb), prefs);
/* make devices toolbar sexy */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"scrolledwindow_devices"));
context = gtk_widget_get_style_context (widget);
gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"toolbar_devices"));
context = gtk_widget_get_style_context (widget);
gtk_style_context_add_class (context, GTK_STYLE_CLASS_INLINE_TOOLBAR);
gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
/* set up virtual dialog */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"dialog_virtual"));
g_signal_connect (widget, "delete-event",
G_CALLBACK (gcm_prefs_virtual_delete_event_cb),
prefs);
g_signal_connect (widget, "drag-data-received",
G_CALLBACK (gcm_prefs_virtual_drag_data_received_cb),
prefs);
gcm_prefs_setup_drag_and_drop (widget);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"button_virtual_add"));
g_signal_connect (widget, "clicked",
G_CALLBACK (gcm_prefs_button_virtual_add_cb),
prefs);
gtk_widget_set_sensitive (widget, FALSE);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"button_virtual_cancel"));
g_signal_connect (widget, "clicked",
G_CALLBACK (gcm_prefs_button_virtual_cancel_cb),
prefs);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"combobox_virtual_type"));
gcm_prefs_setup_virtual_combobox (widget);
/* set up assign dialog */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"dialog_assign"));
g_signal_connect (widget, "delete-event",
G_CALLBACK (gcm_prefs_profile_delete_event_cb), prefs);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"button_assign_cancel"));
g_signal_connect (widget, "clicked",
G_CALLBACK (gcm_prefs_button_assign_cancel_cb), prefs);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"button_assign_ok"));
g_signal_connect (widget, "clicked",
G_CALLBACK (gcm_prefs_button_assign_ok_cb), prefs);
/* setup icc profiles list */
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"combobox_profile"));
gcm_prefs_set_combo_simple_text (widget);
gtk_widget_set_sensitive (widget, FALSE);
g_signal_connect (G_OBJECT (widget), "changed",
G_CALLBACK (gcm_prefs_profile_combo_changed_cb), prefs);
/* use a device client array */
priv->client = cd_client_new ();
g_signal_connect (priv->client, "device-added",
G_CALLBACK (gcm_prefs_device_added_cb), prefs);
g_signal_connect (priv->client, "device-removed",
G_CALLBACK (gcm_prefs_device_removed_cb), prefs);
g_signal_connect (priv->client, "changed",
G_CALLBACK (gcm_prefs_changed_cb), prefs);
/* connect to colord */
ret = cd_client_connect_sync (priv->client,
priv->cancellable,
&error);
if (!ret)
{
g_warning ("failed to connect to colord: %s", error->message);
g_error_free (error);
goto out;
}
/* get devices async */
cd_client_get_devices (priv->client,
priv->cancellable,
gcm_prefs_get_devices_cb,
prefs);
/* use the color sensor */
g_signal_connect (priv->client, "sensor-added",
G_CALLBACK (gcm_prefs_client_sensor_changed_cb),
prefs);
g_signal_connect (priv->client, "sensor-removed",
G_CALLBACK (gcm_prefs_client_sensor_changed_cb),
prefs);
out:
g_free (text);
/* set calibrate button sensitivity */
gcm_prefs_sensor_coldplug (prefs);
gcm_prefs_set_calibrate_button_sensitivity (prefs);
widget = WID (priv->builder, "dialog-vbox1");
gtk_widget_reparent (widget, (GtkWidget *) prefs);
priv->main_window = gtk_widget_get_toplevel (widget);
}
void
cc_color_panel_register (GIOModule *module)
{
cc_color_panel_register_type (G_TYPE_MODULE (module));
g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT,
CC_TYPE_COLOR_PANEL,
"color", 0);
}