~ubuntu-branches/ubuntu/trusty/unity-control-center/trusty

« back to all changes in this revision

Viewing changes to panels/color/cc-color-panel.c

  • Committer: Package Import Robot
  • Author(s): Robert Ancell
  • Date: 2014-01-08 16:29:18 UTC
  • Revision ID: package-import@ubuntu.com-20140108162918-g29dd08tr913y2qh
Tags: upstream-14.04.0
ImportĀ upstreamĀ versionĀ 14.04.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
 
2
 *
 
3
 * Copyright (C) 2010 Red Hat, Inc
 
4
 * Copyright (C) 2011 Richard Hughes <richard@hughsie.com>
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; either version 2 of the License, or
 
9
 * (at your option) any later version.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program; if not, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
19
 *
 
20
 */
 
21
 
 
22
#include <config.h>
 
23
 
 
24
#include <glib/gi18n.h>
 
25
#include <colord.h>
 
26
#include <gtk/gtk.h>
 
27
#include <gdk/gdkx.h>
 
28
#include <gio/gio.h>
 
29
 
 
30
#include "cc-color-panel.h"
 
31
 
 
32
#define WID(b, w) (GtkWidget *) gtk_builder_get_object (b, w)
 
33
 
 
34
CC_PANEL_REGISTER (CcColorPanel, cc_color_panel)
 
35
 
 
36
#define COLOR_PANEL_PRIVATE(o) \
 
37
  (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_COLOR_PANEL, CcColorPanelPrivate))
 
38
 
 
39
struct _CcColorPanelPrivate
 
40
{
 
41
  CdClient      *client;
 
42
  CdDevice      *current_device;
 
43
  CdSensor      *sensor;
 
44
  GCancellable  *cancellable;
 
45
  GDBusProxy    *proxy;
 
46
  GSettings     *settings;
 
47
  GtkBuilder    *builder;
 
48
  GtkTreeStore  *list_store_devices;
 
49
  GtkWidget     *main_window;
 
50
};
 
51
 
 
52
enum {
 
53
  GCM_PREFS_COLUMN_DEVICE_PATH,
 
54
  GCM_PREFS_COLUMN_SORT,
 
55
  GCM_PREFS_COLUMN_ICON,
 
56
  GCM_PREFS_COLUMN_TITLE,
 
57
  GCM_PREFS_COLUMN_DEVICE,
 
58
  GCM_PREFS_COLUMN_PROFILE,
 
59
  GCM_PREFS_COLUMN_STATUS,
 
60
  GCM_PREFS_COLUMN_STATUS_IMAGE,
 
61
  GCM_PREFS_COLUMN_TOOLTIP,
 
62
  GCM_PREFS_COLUMN_RADIO_ACTIVE,
 
63
  GCM_PREFS_COLUMN_RADIO_VISIBLE,
 
64
  GCM_PREFS_COLUMN_NUM_COLUMNS
 
65
};
 
66
 
 
67
enum {
 
68
  GCM_PREFS_COMBO_COLUMN_TEXT,
 
69
  GCM_PREFS_COMBO_COLUMN_PROFILE,
 
70
  GCM_PREFS_COMBO_COLUMN_TYPE,
 
71
  GCM_PREFS_COMBO_COLUMN_NUM_COLUMNS
 
72
};
 
73
 
 
74
typedef enum {
 
75
  GCM_PREFS_ENTRY_TYPE_PROFILE,
 
76
  GCM_PREFS_ENTRY_TYPE_IMPORT
 
77
} GcmPrefsEntryType;
 
78
 
 
79
#define GCM_SETTINGS_SCHEMA                             "org.gnome.settings-daemon.plugins.color"
 
80
#define GCM_SETTINGS_RECALIBRATE_PRINTER_THRESHOLD      "recalibrate-printer-threshold"
 
81
#define GCM_SETTINGS_RECALIBRATE_DISPLAY_THRESHOLD      "recalibrate-display-threshold"
 
82
 
 
83
/* max number of devices and profiles to cause auto-expand at startup */
 
84
#define GCM_PREFS_MAX_DEVICES_PROFILES_EXPANDED         5
 
85
 
 
86
static void     gcm_prefs_device_add_cb (GtkWidget *widget, CcColorPanel *prefs);
 
87
 
 
88
static void
 
89
gcm_prefs_combobox_add_profile (GtkWidget *widget,
 
90
                                CdProfile *profile,
 
91
                                GcmPrefsEntryType entry_type,
 
92
                                GtkTreeIter *iter)
 
93
{
 
94
  const gchar *id;
 
95
  GtkTreeModel *model;
 
96
  GtkTreeIter iter_tmp;
 
97
  GString *string;
 
98
 
 
99
  /* iter is optional */
 
100
  if (iter == NULL)
 
101
    iter = &iter_tmp;
 
102
 
 
103
  /* use description */
 
104
  if (entry_type == GCM_PREFS_ENTRY_TYPE_IMPORT)
 
105
    {
 
106
      /* TRANSLATORS: this is where the user can click and import a profile */
 
107
      string = g_string_new (_("Other profileā€¦"));
 
108
    }
 
109
  else
 
110
    {
 
111
      string = g_string_new (cd_profile_get_title (profile));
 
112
 
 
113
      /* any source prefix? */
 
114
      id = cd_profile_get_metadata_item (profile,
 
115
                                         CD_PROFILE_METADATA_DATA_SOURCE);
 
116
      if (g_strcmp0 (id, CD_PROFILE_METADATA_DATA_SOURCE_EDID) == 0)
 
117
        {
 
118
          /* TRANSLATORS: this is a profile prefix to signify the
 
119
           * profile has been auto-generated for this hardware */
 
120
          g_string_prepend (string, _("Default: "));
 
121
        }
 
122
#if CD_CHECK_VERSION(0,1,14)
 
123
      if (g_strcmp0 (id, CD_PROFILE_METADATA_DATA_SOURCE_STANDARD) == 0)
 
124
        {
 
125
          /* TRANSLATORS: this is a profile prefix to signify the
 
126
           * profile his a standard space like AdobeRGB */
 
127
          g_string_prepend (string, _("Colorspace: "));
 
128
        }
 
129
      if (g_strcmp0 (id, CD_PROFILE_METADATA_DATA_SOURCE_TEST) == 0)
 
130
        {
 
131
          /* TRANSLATORS: this is a profile prefix to signify the
 
132
           * profile is a test profile */
 
133
          g_string_prepend (string, _("Test profile: "));
 
134
        }
 
135
#endif
 
136
    }
 
137
 
 
138
  /* also add profile */
 
139
  model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget));
 
140
  gtk_list_store_append (GTK_LIST_STORE(model), iter);
 
141
  gtk_list_store_set (GTK_LIST_STORE(model), iter,
 
142
                      GCM_PREFS_COMBO_COLUMN_TEXT, string->str,
 
143
                      GCM_PREFS_COMBO_COLUMN_PROFILE, profile,
 
144
                      GCM_PREFS_COMBO_COLUMN_TYPE, entry_type,
 
145
                      -1);
 
146
  g_string_free (string, TRUE);
 
147
}
 
148
 
 
149
static void
 
150
gcm_prefs_default_cb (GtkWidget *widget, CcColorPanel *prefs)
 
151
{
 
152
  CdProfile *profile;
 
153
  gboolean ret;
 
154
  GError *error = NULL;
 
155
  CcColorPanelPrivate *priv = prefs->priv;
 
156
 
 
157
  /* TODO: check if the profile is already systemwide */
 
158
  profile = cd_device_get_default_profile (priv->current_device);
 
159
  if (profile == NULL)
 
160
    goto out;
 
161
 
 
162
  /* install somewhere out of $HOME */
 
163
  ret = cd_profile_install_system_wide_sync (profile,
 
164
                                             priv->cancellable,
 
165
                                             &error);
 
166
  if (!ret)
 
167
    {
 
168
      g_warning ("failed to set profile system-wide: %s",
 
169
           error->message);
 
170
      g_error_free (error);
 
171
      goto out;
 
172
    }
 
173
out:
 
174
  if (profile != NULL)
 
175
    g_object_unref (profile);
 
176
}
 
177
 
 
178
static void
 
179
gcm_prefs_treeview_popup_menu (CcColorPanel *prefs, GtkWidget *treeview)
 
180
{
 
181
  GtkWidget *menu, *menuitem;
 
182
 
 
183
  menu = gtk_menu_new ();
 
184
 
 
185
  /* TRANSLATORS: this is when the profile should be set for all users */
 
186
  menuitem = gtk_menu_item_new_with_label (_("Set for all users"));
 
187
  g_signal_connect (menuitem, "activate",
 
188
                    G_CALLBACK (gcm_prefs_default_cb),
 
189
                    prefs);
 
190
  gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
 
191
 
 
192
  /* TRANSLATORS: this is when the profile should be set for all users */
 
193
  menuitem = gtk_menu_item_new_with_label (_("Create virtual device"));
 
194
  g_signal_connect (menuitem, "activate",
 
195
                    G_CALLBACK (gcm_prefs_device_add_cb),
 
196
                    prefs);
 
197
  gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
 
198
 
 
199
  gtk_widget_show_all (menu);
 
200
 
 
201
  /* Note: gdk_event_get_time() accepts a NULL argument */
 
202
  gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0,
 
203
                  gdk_event_get_time (NULL));
 
204
}
 
205
 
 
206
static gboolean
 
207
gcm_prefs_treeview_popup_menu_cb (GtkWidget *treeview, CcColorPanel *prefs)
 
208
{
 
209
  if (prefs->priv->current_device == NULL)
 
210
    return FALSE;
 
211
  gcm_prefs_treeview_popup_menu (prefs, treeview);
 
212
  return TRUE; /* we handled this */
 
213
}
 
214
 
 
215
static GFile *
 
216
gcm_prefs_file_chooser_get_icc_profile (CcColorPanel *prefs)
 
217
{
 
218
  GtkWindow *window;
 
219
  GtkWidget *dialog;
 
220
  GFile *file = NULL;
 
221
  GtkFileFilter *filter;
 
222
  CcColorPanelPrivate *priv = prefs->priv;
 
223
 
 
224
  /* create new dialog */
 
225
  window = GTK_WINDOW(gtk_builder_get_object (priv->builder,
 
226
                                              "dialog_assign"));
 
227
  /* TRANSLATORS: an ICC profile is a file containing colorspace data */
 
228
  dialog = gtk_file_chooser_dialog_new (_("Select ICC Profile File"), window,
 
229
                                        GTK_FILE_CHOOSER_ACTION_OPEN,
 
230
                                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 
231
                                        _("_Import"), GTK_RESPONSE_ACCEPT,
 
232
                                        NULL);
 
233
  gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(dialog), g_get_home_dir ());
 
234
  gtk_file_chooser_set_create_folders (GTK_FILE_CHOOSER(dialog), FALSE);
 
235
  gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER(dialog), FALSE);
 
236
 
 
237
  /* setup the filter */
 
238
  filter = gtk_file_filter_new ();
 
239
  gtk_file_filter_add_mime_type (filter, "application/vnd.iccprofile");
 
240
 
 
241
  /* TRANSLATORS: filter name on the file->open dialog */
 
242
  gtk_file_filter_set_name (filter, _("Supported ICC profiles"));
 
243
  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
 
244
 
 
245
  /* setup the all files filter */
 
246
  filter = gtk_file_filter_new ();
 
247
  gtk_file_filter_add_pattern (filter, "*");
 
248
  /* TRANSLATORS: filter name on the file->open dialog */
 
249
  gtk_file_filter_set_name (filter, _("All files"));
 
250
  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
 
251
 
 
252
  /* did user choose file */
 
253
  if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
 
254
    file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER(dialog));
 
255
 
 
256
  /* we're done */
 
257
  gtk_widget_destroy (dialog);
 
258
 
 
259
  /* or NULL for missing */
 
260
  return file;
 
261
}
 
262
 
 
263
static void
 
264
gcm_packagekit_finished_cb (GObject *source, GAsyncResult *res, gpointer user_data)
 
265
{
 
266
  GPtrArray *argv = (GPtrArray *)user_data;
 
267
  GVariant *reply;
 
268
  GError *error = NULL;
 
269
  gboolean ret;
 
270
 
 
271
  reply = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error);
 
272
  g_variant_unref (reply);
 
273
 
 
274
  if (error != NULL)
 
275
    {
 
276
      g_warning ("failed to install required component: %s", error->message);
 
277
      g_ptr_array_unref (argv);
 
278
      g_error_free (error);
 
279
      return;
 
280
    }
 
281
 
 
282
  ret = g_spawn_async (NULL, (gchar**) argv->pdata, NULL, 0,
 
283
                       NULL, NULL, NULL, &error);
 
284
  g_ptr_array_unref (argv);
 
285
  if (!ret)
 
286
    {
 
287
      g_warning ("failed to run command: %s", error->message);
 
288
      g_error_free (error);
 
289
    }
 
290
}
 
291
 
 
292
struct gcm_packagekit_closure_data
 
293
{
 
294
  GPtrArray *argv;
 
295
  guint xid;
 
296
};
 
297
 
 
298
static void
 
299
gcm_packagekit_proxy_ready_cb (GObject *source, GAsyncResult *res, gpointer user_data)
 
300
{
 
301
  struct gcm_packagekit_closure_data *data =
 
302
    (struct gcm_packagekit_closure_data *)user_data;
 
303
  GDBusProxy *session_installer;
 
304
  GVariantBuilder *builder;
 
305
  GError *error = NULL;
 
306
 
 
307
  session_installer = g_dbus_proxy_new_for_bus_finish (res, &error);
 
308
  if (error != NULL)
 
309
    {
 
310
      g_warning ("failed to connect to PackageKit interface: %s",
 
311
                 error->message);
 
312
      g_ptr_array_unref (data->argv);
 
313
      g_free (data);
 
314
      g_error_free (error);
 
315
      return;
 
316
    }
 
317
 
 
318
  builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
 
319
  g_variant_builder_add (builder, "s",
 
320
                         g_ptr_array_index (data->argv, 0));
 
321
  g_dbus_proxy_call (session_installer,
 
322
                     "InstallProvideFiles",
 
323
                     g_variant_new ("(uass)",
 
324
                                    data->xid,
 
325
                                    builder,
 
326
                                    "hide-finished"
 
327
                                    ),
 
328
                     G_DBUS_CALL_FLAGS_NONE,
 
329
                     -1,
 
330
                     NULL,
 
331
                     &gcm_packagekit_finished_cb,
 
332
                     data->argv);
 
333
 
 
334
  g_free (data);
 
335
  g_variant_builder_unref (builder);
 
336
}
 
337
 
 
338
static void
 
339
gcm_prefs_install_component (guint xid, GPtrArray *argv)
 
340
{
 
341
  struct gcm_packagekit_closure_data *data;
 
342
  data = g_malloc (sizeof (*data));
 
343
  data->argv = argv;
 
344
  data->xid = xid;
 
345
  g_ptr_array_ref (data->argv);
 
346
 
 
347
  g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
 
348
                            G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
 
349
                            G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
 
350
                            NULL,
 
351
                            "org.freedesktop.PackageKit",
 
352
                            "/org/freedesktop/PackageKit",
 
353
                            "org.freedesktop.PackageKit.Modify",
 
354
                            NULL,
 
355
                            &gcm_packagekit_proxy_ready_cb,
 
356
                            data);
 
357
}
 
358
 
 
359
static void
 
360
gcm_prefs_run_maybe_install (guint xid, gchar *filename, GPtrArray *argv)
 
361
{
 
362
  gboolean ret;
 
363
  GError *error = NULL;
 
364
 
 
365
  ret = g_spawn_async (NULL, (gchar**) argv->pdata, NULL, 0,
 
366
                       NULL, NULL, NULL, &error);
 
367
  if (!ret)
 
368
    {
 
369
      if ((error->domain == g_spawn_error_quark ()) &&
 
370
          (error->code == G_SPAWN_ERROR_NOENT))
 
371
        {
 
372
          gcm_prefs_install_component (xid, argv);
 
373
        }
 
374
      else
 
375
        {
 
376
          g_warning ("failed to run command: %s", error->message);
 
377
        }
 
378
      g_error_free (error);
 
379
    }
 
380
}
 
381
 
 
382
static void
 
383
gcm_prefs_calibrate_cb (GtkWidget *widget, CcColorPanel *prefs)
 
384
{
 
385
  guint xid;
 
386
  GPtrArray *argv;
 
387
  gchar *calibrater_filename;
 
388
  CcColorPanelPrivate *priv = prefs->priv;
 
389
 
 
390
  /* get xid */
 
391
  xid = gdk_x11_window_get_xid (gtk_widget_get_window (GTK_WIDGET (priv->main_window)));
 
392
 
 
393
  calibrater_filename = g_build_filename (BINDIR, "gcm-calibrate", NULL);
 
394
 
 
395
  /* run with modal set */
 
396
  argv = g_ptr_array_new_with_free_func (g_free);
 
397
  g_ptr_array_add (argv, calibrater_filename);
 
398
  g_ptr_array_add (argv, g_strdup ("--device"));
 
399
  g_ptr_array_add (argv, g_strdup (cd_device_get_id (priv->current_device)));
 
400
  g_ptr_array_add (argv, g_strdup ("--parent-window"));
 
401
  g_ptr_array_add (argv, g_strdup_printf ("%i", xid));
 
402
  g_ptr_array_add (argv, NULL);
 
403
 
 
404
  gcm_prefs_run_maybe_install (xid, calibrater_filename, argv);
 
405
 
 
406
  g_ptr_array_unref (argv);
 
407
}
 
408
 
 
409
static void
 
410
gcm_prefs_device_add_cb (GtkWidget *widget, CcColorPanel *prefs)
 
411
{
 
412
  CcColorPanelPrivate *priv = prefs->priv;
 
413
 
 
414
  /* show ui */
 
415
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
416
                                               "dialog_virtual"));
 
417
  gtk_widget_show (widget);
 
418
  gtk_window_set_transient_for (GTK_WINDOW (widget),
 
419
                                GTK_WINDOW (priv->main_window));
 
420
 
 
421
  /* clear entries */
 
422
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
423
                                               "combobox_virtual_type"));
 
424
  gtk_combo_box_set_active (GTK_COMBO_BOX(widget), 0);
 
425
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
426
                                               "entry_virtual_model"));
 
427
  gtk_entry_set_text (GTK_ENTRY (widget), "");
 
428
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
429
                                               "entry_virtual_manufacturer"));
 
430
  gtk_entry_set_text (GTK_ENTRY (widget), "");
 
431
}
 
432
 
 
433
static gboolean
 
434
gcm_prefs_is_profile_suitable_for_device (CdProfile *profile,
 
435
                                          CdDevice *device)
 
436
{
 
437
#if CD_CHECK_VERSION(0,1,14)
 
438
  const gchar *data_source;
 
439
#endif
 
440
  CdProfileKind profile_kind_tmp;
 
441
  CdProfileKind profile_kind;
 
442
  CdColorspace profile_colorspace;
 
443
  CdColorspace device_colorspace = 0;
 
444
  gboolean ret = FALSE;
 
445
  CdDeviceKind device_kind;
 
446
 
 
447
  /* not the right colorspace */
 
448
  device_colorspace = cd_device_get_colorspace (device);
 
449
  profile_colorspace = cd_profile_get_colorspace (profile);
 
450
  if (device_colorspace != profile_colorspace)
 
451
    goto out;
 
452
 
 
453
  /* not the correct kind */
 
454
  device_kind = cd_device_get_kind (device);
 
455
  profile_kind_tmp = cd_profile_get_kind (profile);
 
456
  profile_kind = cd_device_kind_to_profile_kind (device_kind);
 
457
  if (profile_kind_tmp != profile_kind)
 
458
    goto out;
 
459
 
 
460
#if CD_CHECK_VERSION(0,1,14)
 
461
  /* ignore the colorspace profiles */
 
462
  data_source = cd_profile_get_metadata_item (profile,
 
463
                                              CD_PROFILE_METADATA_DATA_SOURCE);
 
464
  if (g_strcmp0 (data_source, CD_PROFILE_METADATA_DATA_SOURCE_STANDARD) == 0)
 
465
    goto out;
 
466
#endif
 
467
 
 
468
  /* success */
 
469
  ret = TRUE;
 
470
out:
 
471
  return ret;
 
472
}
 
473
 
 
474
static gint
 
475
gcm_prefs_combo_sort_func_cb (GtkTreeModel *model,
 
476
                              GtkTreeIter *a,
 
477
                              GtkTreeIter *b,
 
478
                              gpointer user_data)
 
479
{
 
480
  gint type_a, type_b;
 
481
  gchar *text_a;
 
482
  gchar *text_b;
 
483
  gint retval;
 
484
 
 
485
  /* get data from model */
 
486
  gtk_tree_model_get (model, a,
 
487
                      GCM_PREFS_COMBO_COLUMN_TYPE, &type_a,
 
488
                      GCM_PREFS_COMBO_COLUMN_TEXT, &text_a,
 
489
                      -1);
 
490
  gtk_tree_model_get (model, b,
 
491
                      GCM_PREFS_COMBO_COLUMN_TYPE, &type_b,
 
492
                      GCM_PREFS_COMBO_COLUMN_TEXT, &text_b,
 
493
                      -1);
 
494
 
 
495
  /* prefer normal type profiles over the 'Other Profile...' entry */
 
496
  if (type_a < type_b)
 
497
    retval = -1;
 
498
  else if (type_a > type_b)
 
499
    retval = 1;
 
500
  else
 
501
    retval = g_strcmp0 (text_a, text_b);
 
502
 
 
503
  g_free (text_a);
 
504
  g_free (text_b);
 
505
  return retval;
 
506
}
 
507
 
 
508
static gboolean
 
509
gcm_prefs_combo_set_default_cb (gpointer user_data)
 
510
{
 
511
  GtkWidget *widget = GTK_WIDGET (user_data);
 
512
  gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
 
513
  return FALSE;
 
514
}
 
515
 
 
516
static gboolean
 
517
gcm_prefs_profile_exists_in_array (GPtrArray *array, CdProfile *profile)
 
518
{
 
519
  CdProfile *profile_tmp;
 
520
  guint i;
 
521
 
 
522
  for (i = 0; i < array->len; i++)
 
523
    {
 
524
      profile_tmp = g_ptr_array_index (array, i);
 
525
      if (cd_profile_equal (profile, profile_tmp))
 
526
         return TRUE;
 
527
    }
 
528
  return FALSE;
 
529
}
 
530
 
 
531
static void
 
532
gcm_prefs_add_profiles_suitable_for_devices (CcColorPanel *prefs,
 
533
                                             GtkWidget *widget,
 
534
                                             GPtrArray *profiles)
 
535
{
 
536
  CdProfile *profile_tmp;
 
537
  gboolean ret;
 
538
  GError *error = NULL;
 
539
  GPtrArray *profile_array = NULL;
 
540
  GtkTreeIter iter;
 
541
  GtkTreeModel *model;
 
542
  guint i;
 
543
  CcColorPanelPrivate *priv = prefs->priv;
 
544
 
 
545
  /* clear existing entries */
 
546
  model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
 
547
  gtk_list_store_clear (GTK_LIST_STORE (model));
 
548
  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
 
549
                                        GCM_PREFS_COMBO_COLUMN_TEXT,
 
550
                                        GTK_SORT_ASCENDING);
 
551
  gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (model),
 
552
                                   GCM_PREFS_COMBO_COLUMN_TEXT,
 
553
                                   gcm_prefs_combo_sort_func_cb,
 
554
                                   model, NULL);
 
555
 
 
556
  /* get profiles */
 
557
  profile_array = cd_client_get_profiles_sync (priv->client,
 
558
                                               priv->cancellable,
 
559
                                               &error);
 
560
  if (profile_array == NULL)
 
561
    {
 
562
      g_warning ("failed to get profiles: %s",
 
563
           error->message);
 
564
      g_error_free (error);
 
565
      goto out;
 
566
    }
 
567
 
 
568
  /* add profiles of the right kind */
 
569
  for (i = 0; i < profile_array->len; i++)
 
570
    {
 
571
      profile_tmp = g_ptr_array_index (profile_array, i);
 
572
 
 
573
      /* get properties */
 
574
      ret = cd_profile_connect_sync (profile_tmp,
 
575
                                     priv->cancellable,
 
576
                                     &error);
 
577
      if (!ret)
 
578
        {
 
579
          g_warning ("failed to get profile: %s", error->message);
 
580
          g_error_free (error);
 
581
          goto out;
 
582
        }
 
583
 
 
584
      /* don't add any of the already added profiles */
 
585
      if (profiles != NULL)
 
586
        {
 
587
          if (gcm_prefs_profile_exists_in_array (profiles, profile_tmp))
 
588
            continue;
 
589
        }
 
590
 
 
591
      /* only add correct types */
 
592
      ret = gcm_prefs_is_profile_suitable_for_device (profile_tmp,
 
593
                                                      priv->current_device);
 
594
      if (!ret)
 
595
        continue;
 
596
 
 
597
#if CD_CHECK_VERSION(0,1,13)
 
598
      /* ignore profiles from other user accounts */
 
599
      if (!cd_profile_has_access (profile_tmp))
 
600
        continue;
 
601
#endif
 
602
 
 
603
      /* add */
 
604
      gcm_prefs_combobox_add_profile (widget,
 
605
                                      profile_tmp,
 
606
                                      GCM_PREFS_ENTRY_TYPE_PROFILE,
 
607
                                      &iter);
 
608
    }
 
609
 
 
610
  /* add a import entry */
 
611
#if CD_CHECK_VERSION(0,1,12)
 
612
  gcm_prefs_combobox_add_profile (widget, NULL, GCM_PREFS_ENTRY_TYPE_IMPORT, NULL);
 
613
#endif
 
614
  g_idle_add (gcm_prefs_combo_set_default_cb, widget);
 
615
out:
 
616
  if (profile_array != NULL)
 
617
    g_ptr_array_unref (profile_array);
 
618
}
 
619
 
 
620
static void
 
621
gcm_prefs_profile_add_cb (GtkWidget *widget, CcColorPanel *prefs)
 
622
{
 
623
  const gchar *title;
 
624
  GPtrArray *profiles;
 
625
  CcColorPanelPrivate *priv = prefs->priv;
 
626
 
 
627
  /* add profiles of the right kind */
 
628
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
629
                                               "combobox_profile"));
 
630
  profiles = cd_device_get_profiles (priv->current_device);
 
631
  gcm_prefs_add_profiles_suitable_for_devices (prefs, widget, profiles);
 
632
 
 
633
  /* set the title */
 
634
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
635
                                               "label_assign_title"));
 
636
  switch (cd_device_get_kind (priv->current_device)) {
 
637
    case CD_DEVICE_KIND_DISPLAY:
 
638
      /* TRANSLATORS: this is the dialog title in the 'Add profile' UI */
 
639
      title = _("Available Profiles for Displays");
 
640
      break;
 
641
    case CD_DEVICE_KIND_SCANNER:
 
642
      /* TRANSLATORS: this is the dialog title in the 'Add profile' UI */
 
643
      title = _("Available Profiles for Scanners");
 
644
      break;
 
645
    case CD_DEVICE_KIND_PRINTER:
 
646
      /* TRANSLATORS: this is the dialog title in the 'Add profile' UI */
 
647
      title = _("Available Profiles for Printers");
 
648
      break;
 
649
    case CD_DEVICE_KIND_CAMERA:
 
650
      /* TRANSLATORS: this is the dialog title in the 'Add profile' UI */
 
651
      title = _("Available Profiles for Cameras");
 
652
      break;
 
653
    case CD_DEVICE_KIND_WEBCAM:
 
654
      /* TRANSLATORS: this is the dialog title in the 'Add profile' UI */
 
655
      title = _("Available Profiles for Webcams");
 
656
      break;
 
657
    default:
 
658
      /* TRANSLATORS: this is the dialog title in the 'Add profile' UI
 
659
       * where the device type is not recognised */
 
660
      title = _("Available Profiles");
 
661
      break;
 
662
  }
 
663
  gtk_label_set_label (GTK_LABEL (widget), title);
 
664
 
 
665
  /* show the dialog */
 
666
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
667
                                               "dialog_assign"));
 
668
  gtk_widget_show (widget);
 
669
  gtk_window_set_transient_for (GTK_WINDOW (widget), GTK_WINDOW (priv->main_window));
 
670
  if (profiles != NULL)
 
671
    g_ptr_array_unref (profiles);
 
672
}
 
673
 
 
674
static void
 
675
gcm_prefs_profile_remove_cb (GtkWidget *widget, CcColorPanel *prefs)
 
676
{
 
677
  GtkTreeIter iter;
 
678
  GtkTreeSelection *selection;
 
679
  GtkTreeModel *model;
 
680
  gboolean ret = FALSE;
 
681
  CdProfile *profile = NULL;
 
682
  GError *error = NULL;
 
683
  CcColorPanelPrivate *priv = prefs->priv;
 
684
 
 
685
  /* get the selected row */
 
686
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
687
                                               "treeview_devices"));
 
688
  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
 
689
  if (!gtk_tree_selection_get_selected (selection, &model, &iter))
 
690
    goto out;
 
691
 
 
692
  /* if the profile is default, then we'll have to make the first profile default */
 
693
  gtk_tree_model_get (model, &iter,
 
694
                      GCM_PREFS_COLUMN_PROFILE, &profile,
 
695
                      -1);
 
696
 
 
697
  /* just remove it, the list store will get ::changed */
 
698
  ret = cd_device_remove_profile_sync (priv->current_device,
 
699
                                       profile,
 
700
                                       priv->cancellable,
 
701
                                       &error);
 
702
  if (!ret)
 
703
    {
 
704
      g_warning ("failed to remove profile: %s", error->message);
 
705
      g_error_free (error);
 
706
      goto out;
 
707
    }
 
708
out:
 
709
  if (profile != NULL)
 
710
    g_object_unref (profile);
 
711
  return;
 
712
}
 
713
 
 
714
static void
 
715
gcm_prefs_make_profile_default_cb (GObject *object,
 
716
                                   GAsyncResult *res,
 
717
                                   gpointer user_data)
 
718
{
 
719
  CdDevice *device = CD_DEVICE (object);
 
720
  gboolean ret = FALSE;
 
721
  GError *error = NULL;
 
722
 
 
723
  ret = cd_device_make_profile_default_finish (device,
 
724
                                               res,
 
725
                                               &error);
 
726
  if (!ret)
 
727
    {
 
728
      g_warning ("failed to set default profile on %s: %s",
 
729
                 cd_device_get_id (device),
 
730
                 error->message);
 
731
      g_error_free (error);
 
732
    }
 
733
}
 
734
 
 
735
static void
 
736
gcm_prefs_profile_make_default_internal (CcColorPanel *prefs,
 
737
                                         GtkTreeModel *model,
 
738
                                         GtkTreeIter *iter_selected)
 
739
{
 
740
  CdDevice *device;
 
741
  CdProfile *profile;
 
742
  CcColorPanelPrivate *priv = prefs->priv;
 
743
 
 
744
  /* get currentlt selected item */
 
745
  gtk_tree_model_get (model, iter_selected,
 
746
                      GCM_PREFS_COLUMN_DEVICE, &device,
 
747
                      GCM_PREFS_COLUMN_PROFILE, &profile,
 
748
                      -1);
 
749
  if (profile == NULL || device == NULL)
 
750
    goto out;
 
751
 
 
752
  /* just set it default */
 
753
  g_debug ("setting %s default on %s",
 
754
           cd_profile_get_id (profile),
 
755
           cd_device_get_id (device));
 
756
  cd_device_make_profile_default (device,
 
757
                                  profile,
 
758
                                  priv->cancellable,
 
759
                                  gcm_prefs_make_profile_default_cb,
 
760
                                  prefs);
 
761
out:
 
762
  if (profile != NULL)
 
763
    g_object_unref (profile);
 
764
  if (device != NULL)
 
765
    g_object_unref (device);
 
766
}
 
767
 
 
768
static void
 
769
gcm_prefs_profile_view_cb (GtkWidget *widget, CcColorPanel *prefs)
 
770
{
 
771
  CdProfile *profile = NULL;
 
772
  GtkTreeIter iter;
 
773
  GtkTreeModel *model;
 
774
  GtkTreeSelection *selection;
 
775
  gchar *options = NULL;
 
776
  gchar *viewer_filename;
 
777
  GPtrArray *argv = NULL;
 
778
  guint xid;
 
779
  CcColorPanelPrivate *priv = prefs->priv;
 
780
 
 
781
  /* get the selected row */
 
782
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
783
                                               "treeview_devices"));
 
784
  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
 
785
  if (!gtk_tree_selection_get_selected (selection, &model, &iter))
 
786
    g_assert_not_reached ();
 
787
 
 
788
  /* get currentlt selected item */
 
789
  gtk_tree_model_get (model, &iter,
 
790
                      GCM_PREFS_COLUMN_PROFILE, &profile,
 
791
                      -1);
 
792
 
 
793
  /* get xid */
 
794
  xid = gdk_x11_window_get_xid (gtk_widget_get_window (GTK_WIDGET (priv->main_window)));
 
795
 
 
796
  viewer_filename = g_build_filename (BINDIR, "gcm-viewer", NULL);
 
797
  /* open up gcm-viewer as a info pane */
 
798
  argv = g_ptr_array_new_with_free_func (g_free);
 
799
  g_ptr_array_add (argv, viewer_filename);
 
800
  g_ptr_array_add (argv, g_strdup ("--profile"));
 
801
  g_ptr_array_add (argv, g_strdup (cd_profile_get_id (profile)));
 
802
  g_ptr_array_add (argv, g_strdup ("--parent-window"));
 
803
  g_ptr_array_add (argv, g_strdup_printf ("%i", xid));
 
804
  g_ptr_array_add (argv, NULL);
 
805
 
 
806
  gcm_prefs_run_maybe_install (xid, viewer_filename, argv);
 
807
 
 
808
  g_ptr_array_unref (argv);
 
809
  g_free (options);
 
810
  if (profile != NULL)
 
811
    g_object_unref (profile);
 
812
}
 
813
 
 
814
static void
 
815
gcm_prefs_button_assign_cancel_cb (GtkWidget *widget, CcColorPanel *prefs)
 
816
{
 
817
  CcColorPanelPrivate *priv = prefs->priv;
 
818
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
819
                                               "dialog_assign"));
 
820
  gtk_widget_hide (widget);
 
821
}
 
822
 
 
823
static void
 
824
gcm_prefs_button_assign_ok_cb (GtkWidget *widget, CcColorPanel *prefs)
 
825
{
 
826
  GtkTreeIter iter;
 
827
  GtkTreeModel *model;
 
828
  CdProfile *profile = NULL;
 
829
  gboolean ret = FALSE;
 
830
  GError *error = NULL;
 
831
  CcColorPanelPrivate *priv = prefs->priv;
 
832
 
 
833
  /* hide window */
 
834
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
835
                                               "dialog_assign"));
 
836
  gtk_widget_hide (widget);
 
837
 
 
838
  /* get entry */
 
839
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
840
                                               "combobox_profile"));
 
841
  ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter);
 
842
  if (!ret)
 
843
    goto out;
 
844
  model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget));
 
845
  gtk_tree_model_get (model, &iter,
 
846
                      GCM_PREFS_COMBO_COLUMN_PROFILE, &profile,
 
847
                      -1);
 
848
  if (profile == NULL)
 
849
    {
 
850
        g_warning ("failed to get the active profile");
 
851
        goto out;
 
852
    }
 
853
 
 
854
  /* just add it, the list store will get ::changed */
 
855
  ret = cd_device_add_profile_sync (priv->current_device,
 
856
                                    CD_DEVICE_RELATION_HARD,
 
857
                                    profile,
 
858
                                    priv->cancellable,
 
859
                                    &error);
 
860
  if (!ret)
 
861
    {
 
862
      g_warning ("failed to add: %s", error->message);
 
863
      g_error_free (error);
 
864
      goto out;
 
865
    }
 
866
 
 
867
  /* make it default */
 
868
  cd_device_make_profile_default (priv->current_device,
 
869
                                  profile,
 
870
                                  priv->cancellable,
 
871
                                  gcm_prefs_make_profile_default_cb,
 
872
                                  prefs);
 
873
out:
 
874
  if (profile != NULL)
 
875
    g_object_unref (profile);
 
876
}
 
877
 
 
878
static gboolean
 
879
gcm_prefs_profile_delete_event_cb (GtkWidget *widget,
 
880
                                   GdkEvent *event,
 
881
                                   CcColorPanel *prefs)
 
882
{
 
883
  gcm_prefs_button_assign_cancel_cb (widget, prefs);
 
884
  return TRUE;
 
885
}
 
886
 
 
887
static void
 
888
gcm_prefs_delete_cb (GtkWidget *widget, CcColorPanel *prefs)
 
889
{
 
890
  gboolean ret = FALSE;
 
891
  GError *error = NULL;
 
892
  CcColorPanelPrivate *priv = prefs->priv;
 
893
 
 
894
  /* try to delete device */
 
895
  ret = cd_client_delete_device_sync (priv->client,
 
896
                                      priv->current_device,
 
897
                                      priv->cancellable,
 
898
                                      &error);
 
899
  if (!ret)
 
900
    {
 
901
      g_warning ("failed to delete device: %s", error->message);
 
902
      g_error_free (error);
 
903
    }
 
904
}
 
905
 
 
906
static void
 
907
gcm_prefs_treeview_renderer_toggled (GtkCellRendererToggle *cell,
 
908
                                     const gchar *path, CcColorPanel *prefs)
 
909
{
 
910
  gboolean ret;
 
911
  GtkTreeModel *model;
 
912
  GtkTreeIter iter;
 
913
  CcColorPanelPrivate *priv = prefs->priv;
 
914
 
 
915
  model = GTK_TREE_MODEL (priv->list_store_devices);
 
916
  ret = gtk_tree_model_get_iter_from_string (model, &iter, path);
 
917
  if (!ret)
 
918
    return;
 
919
  gcm_prefs_profile_make_default_internal (prefs, model, &iter);
 
920
}
 
921
 
 
922
static void
 
923
gcm_prefs_add_devices_columns (CcColorPanel *prefs,
 
924
                               GtkTreeView *treeview)
 
925
{
 
926
  GtkCellRenderer *renderer;
 
927
  GtkTreeViewColumn *column;
 
928
  CcColorPanelPrivate *priv = prefs->priv;
 
929
 
 
930
  gtk_tree_view_set_headers_visible (treeview, TRUE);
 
931
 
 
932
  /* --- column for device image and device title --- */
 
933
  column = gtk_tree_view_column_new ();
 
934
  gtk_tree_view_column_set_expand (column, TRUE);
 
935
  /* TRANSLATORS: column for device list */
 
936
  gtk_tree_view_column_set_title (column, _("Device"));
 
937
 
 
938
  /* image */
 
939
  renderer = gtk_cell_renderer_pixbuf_new ();
 
940
  g_object_set (renderer, "stock-size", GTK_ICON_SIZE_MENU, NULL);
 
941
  gtk_tree_view_column_pack_start (column, renderer, FALSE);
 
942
  gtk_tree_view_column_add_attribute (column, renderer,
 
943
                                      "icon-name", GCM_PREFS_COLUMN_ICON);
 
944
 
 
945
  /* option */
 
946
  renderer = gtk_cell_renderer_toggle_new ();
 
947
  g_signal_connect (renderer, "toggled",
 
948
                    G_CALLBACK (gcm_prefs_treeview_renderer_toggled), prefs);
 
949
  g_object_set (renderer, "radio", TRUE, NULL);
 
950
  gtk_tree_view_column_pack_start (column, renderer, FALSE);
 
951
  gtk_tree_view_column_add_attribute (column, renderer,
 
952
                                      "active", GCM_PREFS_COLUMN_RADIO_ACTIVE);
 
953
  gtk_tree_view_column_add_attribute (column, renderer,
 
954
                                      "visible", GCM_PREFS_COLUMN_RADIO_VISIBLE);
 
955
 
 
956
  /* text */
 
957
  renderer = gtk_cell_renderer_text_new ();
 
958
  gtk_tree_view_column_pack_start (column, renderer, TRUE);
 
959
  gtk_tree_view_column_add_attribute (column, renderer,
 
960
                                      "markup", GCM_PREFS_COLUMN_TITLE);
 
961
  gtk_tree_view_column_set_expand (column, TRUE);
 
962
  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (priv->list_store_devices),
 
963
                                        GCM_PREFS_COLUMN_SORT,
 
964
                                        GTK_SORT_DESCENDING);
 
965
  gtk_tree_view_append_column (treeview, GTK_TREE_VIEW_COLUMN(column));
 
966
 
 
967
  /* --- column for device status --- */
 
968
  column = gtk_tree_view_column_new ();
 
969
  gtk_tree_view_column_set_expand (column, TRUE);
 
970
  /* TRANSLATORS: column for device list */
 
971
  gtk_tree_view_column_set_title (column, _("Calibration"));
 
972
 
 
973
  /* image */
 
974
  renderer = gtk_cell_renderer_pixbuf_new ();
 
975
  g_object_set (renderer, "stock-size", GTK_ICON_SIZE_MENU, NULL);
 
976
  gtk_tree_view_column_pack_start (column, renderer, FALSE);
 
977
  gtk_tree_view_column_add_attribute (column, renderer,
 
978
                                      "icon-name", GCM_PREFS_COLUMN_STATUS_IMAGE);
 
979
 
 
980
  /* text */
 
981
  renderer = gtk_cell_renderer_text_new ();
 
982
  gtk_tree_view_column_pack_start (column, renderer, TRUE);
 
983
  gtk_tree_view_column_add_attribute (column, renderer,
 
984
                                      "markup", GCM_PREFS_COLUMN_STATUS);
 
985
  gtk_tree_view_column_set_expand (column, FALSE);
 
986
  gtk_tree_view_append_column (treeview, GTK_TREE_VIEW_COLUMN(column));
 
987
 
 
988
  /* tooltip */
 
989
  gtk_tree_view_set_tooltip_column (treeview,
 
990
                                    GCM_PREFS_COLUMN_TOOLTIP);
 
991
}
 
992
 
 
993
static void
 
994
gcm_prefs_set_calibrate_button_sensitivity (CcColorPanel *prefs)
 
995
{
 
996
  gboolean ret = FALSE;
 
997
  GtkWidget *widget;
 
998
  const gchar *tooltip;
 
999
  CdDeviceKind kind;
 
1000
  CcColorPanelPrivate *priv = prefs->priv;
 
1001
 
 
1002
  /* TRANSLATORS: this is when the button is sensitive */
 
1003
  tooltip = _("Create a color profile for the selected device");
 
1004
 
 
1005
  /* no device selected */
 
1006
  if (priv->current_device == NULL)
 
1007
    goto out;
 
1008
 
 
1009
  /* are we a display */
 
1010
  kind = cd_device_get_kind (priv->current_device);
 
1011
  if (kind == CD_DEVICE_KIND_DISPLAY)
 
1012
    {
 
1013
 
 
1014
      /* find whether we have hardware installed */
 
1015
      if (priv->sensor == NULL) {
 
1016
        /* TRANSLATORS: this is when the button is insensitive */
 
1017
        tooltip = _("The measuring instrument is not detected. Please check it is turned on and correctly connected.");
 
1018
        goto out;
 
1019
      }
 
1020
 
 
1021
      /* success */
 
1022
      ret = TRUE;
 
1023
 
 
1024
    }
 
1025
  else if (kind == CD_DEVICE_KIND_SCANNER ||
 
1026
           kind == CD_DEVICE_KIND_CAMERA ||
 
1027
           kind == CD_DEVICE_KIND_WEBCAM)
 
1028
    {
 
1029
 
 
1030
      /* TODO: find out if we can scan using gnome-scan */
 
1031
      ret = TRUE;
 
1032
 
 
1033
    }
 
1034
  else if (kind == CD_DEVICE_KIND_PRINTER)
 
1035
    {
 
1036
 
 
1037
    /* find whether we have hardware installed */
 
1038
    if (priv->sensor == NULL)
 
1039
      {
 
1040
        /* TRANSLATORS: this is when the button is insensitive */
 
1041
        tooltip = _("The measuring instrument is not detected. Please check it is turned on and correctly connected.");
 
1042
        goto out;
 
1043
      }
 
1044
 
 
1045
    /* find whether we have hardware installed */
 
1046
    ret = cd_sensor_has_cap (priv->sensor, CD_SENSOR_CAP_PRINTER);
 
1047
    if (!ret)
 
1048
      {
 
1049
        /* TRANSLATORS: this is when the button is insensitive */
 
1050
        tooltip = _("The measuring instrument does not support printer profiling.");
 
1051
        goto out;
 
1052
      }
 
1053
 
 
1054
    /* success */
 
1055
    ret = TRUE;
 
1056
 
 
1057
    }
 
1058
  else
 
1059
    {
 
1060
      /* TRANSLATORS: this is when the button is insensitive */
 
1061
      tooltip = _("The device type is not currently supported.");
 
1062
    }
 
1063
out:
 
1064
  /* control the tooltip and sensitivity of the button */
 
1065
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
1066
                                               "toolbutton_device_calibrate"));
 
1067
  gtk_widget_set_tooltip_text (widget, tooltip);
 
1068
  gtk_widget_set_sensitive (widget, ret);
 
1069
}
 
1070
 
 
1071
static void
 
1072
gcm_prefs_device_clicked (CcColorPanel *prefs, CdDevice *device)
 
1073
{
 
1074
  GtkWidget *widget;
 
1075
  CdDeviceMode device_mode;
 
1076
  CcColorPanelPrivate *priv = prefs->priv;
 
1077
 
 
1078
  if (device == NULL)
 
1079
    g_assert_not_reached ();
 
1080
 
 
1081
  /* get current device */
 
1082
  if (priv->current_device != NULL)
 
1083
    g_object_unref (priv->current_device);
 
1084
  priv->current_device = g_object_ref (device);
 
1085
 
 
1086
  /* we have a new device */
 
1087
  g_debug ("selected device is: %s",
 
1088
           cd_device_get_id (device));
 
1089
 
 
1090
  /* make sure selectable */
 
1091
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
1092
                                               "combobox_profile"));
 
1093
  gtk_widget_set_sensitive (widget, TRUE);
 
1094
 
 
1095
  /* can we delete this device? */
 
1096
  device_mode = cd_device_get_mode (priv->current_device);
 
1097
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
1098
                                               "toolbutton_device_remove"));
 
1099
  gtk_widget_set_visible (widget, device_mode == CD_DEVICE_MODE_VIRTUAL);
 
1100
 
 
1101
  /* can this device calibrate */
 
1102
  gcm_prefs_set_calibrate_button_sensitivity (prefs);
 
1103
}
 
1104
 
 
1105
static void
 
1106
gcm_prefs_profile_clicked (CcColorPanel *prefs, CdProfile *profile, CdDevice *device)
 
1107
{
 
1108
  GtkWidget *widget;
 
1109
  CdDeviceRelation relation;
 
1110
  CcColorPanelPrivate *priv = prefs->priv;
 
1111
 
 
1112
  /* get profile */
 
1113
  g_debug ("selected profile = %s",
 
1114
     cd_profile_get_filename (profile));
 
1115
 
 
1116
 
 
1117
  /* find the profile relationship */
 
1118
  relation = cd_device_get_profile_relation_sync (device,
 
1119
                                                  profile,
 
1120
                                                  NULL, NULL);
 
1121
 
 
1122
  /* we can only remove hard relationships */
 
1123
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
1124
                                               "toolbutton_profile_remove"));
 
1125
  if (relation == CD_DEVICE_RELATION_HARD)
 
1126
    {
 
1127
      gtk_widget_set_tooltip_text (widget, "");
 
1128
      gtk_widget_set_sensitive (widget, TRUE);
 
1129
    }
 
1130
  else
 
1131
    {
 
1132
      /* TRANSLATORS: this is when an auto-added profile cannot be removed */
 
1133
      gtk_widget_set_tooltip_text (widget, _("Cannot remove automatically added profile"));
 
1134
      gtk_widget_set_sensitive (widget, FALSE);
 
1135
    }
 
1136
 
 
1137
  /* allow getting profile info */
 
1138
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
1139
               "toolbutton_profile_view"));
 
1140
  gtk_widget_set_sensitive (widget, TRUE);
 
1141
 
 
1142
  /* hide device specific stuff */
 
1143
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
1144
                                               "toolbutton_device_remove"));
 
1145
  gtk_widget_set_visible (widget, FALSE);
 
1146
}
 
1147
 
 
1148
static void
 
1149
gcm_prefs_devices_treeview_clicked_cb (GtkTreeSelection *selection,
 
1150
                                       CcColorPanel *prefs)
 
1151
{
 
1152
  GtkTreeModel *model;
 
1153
  GtkTreeIter iter;
 
1154
  CdDevice *device = NULL;
 
1155
  CdProfile *profile = NULL;
 
1156
  GtkWidget *widget;
 
1157
  CcColorPanelPrivate *priv = prefs->priv;
 
1158
 
 
1159
  /* get selection */
 
1160
  if (!gtk_tree_selection_get_selected (selection, &model, &iter))
 
1161
    return;
 
1162
 
 
1163
  gtk_tree_model_get (model, &iter,
 
1164
                      GCM_PREFS_COLUMN_DEVICE, &device,
 
1165
                      GCM_PREFS_COLUMN_PROFILE, &profile,
 
1166
                      -1);
 
1167
 
 
1168
  /* device actions */
 
1169
  if (device != NULL)
 
1170
    gcm_prefs_device_clicked (prefs, device);
 
1171
  if (profile != NULL)
 
1172
    gcm_prefs_profile_clicked (prefs, profile, device);
 
1173
 
 
1174
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
1175
                                               "toolbutton_device_default"));
 
1176
  gtk_widget_set_visible (widget, profile != NULL);
 
1177
  if (profile)
 
1178
    gtk_widget_set_sensitive (widget, !cd_profile_get_is_system_wide (profile));
 
1179
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
1180
                                               "toolbutton_device_add"));
 
1181
  gtk_widget_set_visible (widget, FALSE);
 
1182
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
1183
                                               "toolbutton_device_calibrate"));
 
1184
  gtk_widget_set_visible (widget, device != NULL);
 
1185
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
1186
                                               "toolbutton_profile_add"));
 
1187
  gtk_widget_set_visible (widget, device != NULL);
 
1188
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
1189
                                               "toolbutton_profile_view"));
 
1190
  gtk_widget_set_visible (widget, profile != NULL);
 
1191
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
1192
                                               "toolbutton_profile_remove"));
 
1193
  gtk_widget_set_visible (widget, profile != NULL);
 
1194
 
 
1195
  /* if no buttons then hide toolbar */
 
1196
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
1197
                                               "toolbar_devices"));
 
1198
  gtk_widget_set_visible (widget, profile != NULL || device != NULL);
 
1199
 
 
1200
  if (device != NULL)
 
1201
    g_object_unref (device);
 
1202
  if (profile != NULL)
 
1203
    g_object_unref (profile);
 
1204
}
 
1205
 
 
1206
static void
 
1207
gcm_prefs_treeview_row_activated_cb (GtkTreeView *tree_view,
 
1208
                                     GtkTreePath *path,
 
1209
                                     GtkTreeViewColumn *column,
 
1210
                                     CcColorPanel *prefs)
 
1211
{
 
1212
  GtkTreeModel *model;
 
1213
  GtkTreeIter iter;
 
1214
  gboolean ret;
 
1215
  CcColorPanelPrivate *priv = prefs->priv;
 
1216
 
 
1217
  /* get the iter */
 
1218
  model = GTK_TREE_MODEL (priv->list_store_devices);
 
1219
  ret = gtk_tree_model_get_iter (model, &iter, path);
 
1220
  if (!ret)
 
1221
    return;
 
1222
 
 
1223
  /* make this profile the default */
 
1224
  gcm_prefs_profile_make_default_internal (prefs, model, &iter);
 
1225
}
 
1226
 
 
1227
static const gchar *
 
1228
gcm_prefs_device_kind_to_sort (CdDeviceKind kind)
 
1229
{
 
1230
  if (kind == CD_DEVICE_KIND_DISPLAY)
 
1231
    return "4";
 
1232
  if (kind == CD_DEVICE_KIND_SCANNER)
 
1233
    return "3";
 
1234
  if (kind == CD_DEVICE_KIND_CAMERA)
 
1235
    return "2";
 
1236
  if (kind == CD_DEVICE_KIND_PRINTER)
 
1237
    return "1";
 
1238
  return "0";
 
1239
}
 
1240
 
 
1241
static gchar *
 
1242
gcm_device_get_title (CdDevice *device)
 
1243
{
 
1244
  const gchar *model;
 
1245
  const gchar *vendor;
 
1246
  GString *string;
 
1247
 
 
1248
  /* try to get a nice string suitable for display */
 
1249
  vendor = cd_device_get_vendor (device);
 
1250
  model = cd_device_get_model (device);
 
1251
  string = g_string_new ("");
 
1252
 
 
1253
  if (vendor != NULL && model != NULL)
 
1254
    {
 
1255
      g_string_append_printf (string, "%s - %s",
 
1256
                              vendor, model);
 
1257
      goto out;
 
1258
    }
 
1259
 
 
1260
  /* just model */
 
1261
  if (model != NULL)
 
1262
    {
 
1263
      g_string_append (string, model);
 
1264
      goto out;
 
1265
    }
 
1266
 
 
1267
  /* just vendor */
 
1268
  if (vendor != NULL)
 
1269
    {
 
1270
      g_string_append (string, vendor);
 
1271
      goto out;
 
1272
    }
 
1273
 
 
1274
  /* fallback to id */
 
1275
  g_string_append (string, cd_device_get_id (device));
 
1276
out:
 
1277
  return g_string_free (string, FALSE);
 
1278
}
 
1279
 
 
1280
static void
 
1281
gcm_prefs_set_combo_simple_text (GtkWidget *combo_box)
 
1282
{
 
1283
  GtkCellRenderer *renderer;
 
1284
  GtkListStore *store;
 
1285
 
 
1286
  store = gtk_list_store_new (GCM_PREFS_COMBO_COLUMN_NUM_COLUMNS,
 
1287
                              G_TYPE_STRING,
 
1288
                              CD_TYPE_PROFILE,
 
1289
                              G_TYPE_UINT);
 
1290
  gtk_combo_box_set_model (GTK_COMBO_BOX (combo_box),
 
1291
                           GTK_TREE_MODEL (store));
 
1292
  g_object_unref (store);
 
1293
 
 
1294
  renderer = gtk_cell_renderer_text_new ();
 
1295
  g_object_set (renderer,
 
1296
                "ellipsize", PANGO_ELLIPSIZE_END,
 
1297
                "wrap-mode", PANGO_WRAP_WORD_CHAR,
 
1298
                NULL);
 
1299
  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE);
 
1300
  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), renderer,
 
1301
                                  "text", GCM_PREFS_COMBO_COLUMN_TEXT,
 
1302
                                  NULL);
 
1303
}
 
1304
 
 
1305
static void
 
1306
gcm_prefs_profile_combo_changed_cb (GtkWidget *widget,
 
1307
                                    CcColorPanel *prefs)
 
1308
{
 
1309
  GFile *file = NULL;
 
1310
  GError *error = NULL;
 
1311
  gboolean ret;
 
1312
  CdProfile *profile = NULL;
 
1313
  GtkTreeIter iter;
 
1314
  GtkTreeModel *model;
 
1315
  GcmPrefsEntryType entry_type;
 
1316
  CcColorPanelPrivate *priv = prefs->priv;
 
1317
 
 
1318
  /* no devices */
 
1319
  if (priv->current_device == NULL)
 
1320
    return;
 
1321
 
 
1322
  /* no selection */
 
1323
  ret = gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter);
 
1324
  if (!ret)
 
1325
    return;
 
1326
 
 
1327
  /* get entry */
 
1328
  model = gtk_combo_box_get_model (GTK_COMBO_BOX(widget));
 
1329
  gtk_tree_model_get (model, &iter,
 
1330
                      GCM_PREFS_COMBO_COLUMN_TYPE, &entry_type,
 
1331
                      -1);
 
1332
 
 
1333
  /* import */
 
1334
  if (entry_type == GCM_PREFS_ENTRY_TYPE_IMPORT)
 
1335
    {
 
1336
      file = gcm_prefs_file_chooser_get_icc_profile (prefs);
 
1337
      if (file == NULL)
 
1338
        {
 
1339
          g_warning ("failed to get ICC file");
 
1340
          gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
 
1341
 
 
1342
          /* if we've got no other existing profiles to choose, then
 
1343
           * just close the assign dialog */
 
1344
          gtk_combo_box_get_active_iter (GTK_COMBO_BOX(widget), &iter);
 
1345
          gtk_tree_model_get (model, &iter,
 
1346
                              GCM_PREFS_COMBO_COLUMN_TYPE, &entry_type,
 
1347
                              -1);
 
1348
          if (entry_type == GCM_PREFS_ENTRY_TYPE_IMPORT)
 
1349
            {
 
1350
              widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
1351
                                                           "dialog_assign"));
 
1352
              gtk_widget_hide (widget);
 
1353
            }
 
1354
          goto out;
 
1355
        }
 
1356
 
 
1357
#if CD_CHECK_VERSION(0,1,12)
 
1358
      profile = cd_client_import_profile_sync (priv->client,
 
1359
                                               file,
 
1360
                                               priv->cancellable,
 
1361
                                               &error);
 
1362
      if (profile == NULL)
 
1363
        {
 
1364
          g_warning ("failed to get imported profile: %s", error->message);
 
1365
          g_error_free (error);
 
1366
          goto out;
 
1367
        }
 
1368
#endif
 
1369
 
 
1370
      /* add to combobox */
 
1371
      gtk_list_store_append (GTK_LIST_STORE(model), &iter);
 
1372
      gtk_list_store_set (GTK_LIST_STORE(model), &iter,
 
1373
                          GCM_PREFS_COMBO_COLUMN_PROFILE, profile,
 
1374
                          -1);
 
1375
      gtk_combo_box_set_active_iter (GTK_COMBO_BOX (widget), &iter);
 
1376
    }
 
1377
out:
 
1378
  if (file != NULL)
 
1379
    g_object_unref (file);
 
1380
  if (profile != NULL)
 
1381
    g_object_unref (profile);
 
1382
}
 
1383
 
 
1384
static void
 
1385
gcm_prefs_sensor_coldplug (CcColorPanel *prefs)
 
1386
{
 
1387
  GPtrArray *sensors;
 
1388
  GError *error = NULL;
 
1389
  gboolean ret;
 
1390
  CcColorPanelPrivate *priv = prefs->priv;
 
1391
 
 
1392
  /* unref old */
 
1393
  if (priv->sensor != NULL)
 
1394
    {
 
1395
      g_object_unref (priv->sensor);
 
1396
      priv->sensor = NULL;
 
1397
    }
 
1398
 
 
1399
  /* no present */
 
1400
  sensors = cd_client_get_sensors_sync (priv->client, NULL, &error);
 
1401
  if (sensors == NULL)
 
1402
    {
 
1403
      g_warning ("%s", error->message);
 
1404
      g_error_free (error);
 
1405
      goto out;
 
1406
    }
 
1407
  if (sensors->len == 0)
 
1408
    goto out;
 
1409
 
 
1410
  /* save a copy of the sensor */
 
1411
  priv->sensor = g_object_ref (g_ptr_array_index (sensors, 0));
 
1412
 
 
1413
  /* connect to the sensor */
 
1414
  ret = cd_sensor_connect_sync (priv->sensor, NULL, &error);
 
1415
  if (!ret)
 
1416
    {
 
1417
      g_warning ("%s", error->message);
 
1418
      g_error_free (error);
 
1419
      goto out;
 
1420
    }
 
1421
out:
 
1422
  if (sensors != NULL)
 
1423
    g_ptr_array_unref (sensors);
 
1424
}
 
1425
 
 
1426
static void
 
1427
gcm_prefs_client_sensor_changed_cb (CdClient *client,
 
1428
                                    CdSensor *sensor,
 
1429
                                    CcColorPanel *prefs)
 
1430
{
 
1431
  gcm_prefs_sensor_coldplug (prefs);
 
1432
  gcm_prefs_set_calibrate_button_sensitivity (prefs);
 
1433
}
 
1434
 
 
1435
static const gchar *
 
1436
gcm_prefs_device_kind_to_icon_name (CdDeviceKind kind)
 
1437
{
 
1438
  switch (kind) {
 
1439
  case CD_DEVICE_KIND_DISPLAY:
 
1440
    return "video-display";
 
1441
  case CD_DEVICE_KIND_SCANNER:
 
1442
    return "scanner";
 
1443
  case CD_DEVICE_KIND_PRINTER:
 
1444
    return "printer";
 
1445
  case CD_DEVICE_KIND_CAMERA:
 
1446
    return "camera-photo";
 
1447
  case CD_DEVICE_KIND_WEBCAM:
 
1448
    return "camera-web";
 
1449
  default:
 
1450
    return "image-missing";
 
1451
  }
 
1452
}
 
1453
 
 
1454
static GString *
 
1455
gcm_prefs_get_profile_age_as_string (CdProfile *profile)
 
1456
{
 
1457
  const gchar *id;
 
1458
  gint64 age;
 
1459
  GString *string = NULL;
 
1460
 
 
1461
  if (profile == NULL)
 
1462
    {
 
1463
      /* TRANSLATORS: this is when there is no profile for the device */
 
1464
      string = g_string_new (_("No profile"));
 
1465
      goto out;
 
1466
    }
 
1467
 
 
1468
  /* don't show details for EDID, colorspace or test profiles */
 
1469
  id = cd_profile_get_metadata_item (profile,
 
1470
                                     CD_PROFILE_METADATA_DATA_SOURCE);
 
1471
  if (g_strcmp0 (id, CD_PROFILE_METADATA_DATA_SOURCE_EDID) == 0)
 
1472
    goto out;
 
1473
#if CD_CHECK_VERSION(0,1,14)
 
1474
  if (g_strcmp0 (id, CD_PROFILE_METADATA_DATA_SOURCE_STANDARD) == 0)
 
1475
    goto out;
 
1476
  if (g_strcmp0 (id, CD_PROFILE_METADATA_DATA_SOURCE_TEST) == 0)
 
1477
    goto out;
 
1478
#endif
 
1479
 
 
1480
  /* days */
 
1481
  age = cd_profile_get_age (profile);
 
1482
  if (age == 0)
 
1483
    {
 
1484
      string = g_string_new (NULL);
 
1485
      goto out;
 
1486
    }
 
1487
  age /= 60 * 60 * 24;
 
1488
  string = g_string_new ("");
 
1489
 
 
1490
  /* approximate years */
 
1491
  if (age > 365)
 
1492
    {
 
1493
      age /= 365;
 
1494
      g_string_append_printf (string, ngettext (
 
1495
                              "%i year",
 
1496
                              "%i years",
 
1497
                              age), (guint) age);
 
1498
      goto out;
 
1499
    }
 
1500
 
 
1501
  /* approximate months */
 
1502
  if (age > 30)
 
1503
    {
 
1504
      age /= 30;
 
1505
      g_string_append_printf (string, ngettext (
 
1506
                              "%i month",
 
1507
                              "%i months",
 
1508
                              age), (guint) age);
 
1509
      goto out;
 
1510
    }
 
1511
 
 
1512
  /* approximate weeks */
 
1513
  if (age > 7)
 
1514
    {
 
1515
      age /= 7;
 
1516
      g_string_append_printf (string, ngettext (
 
1517
                              "%i week",
 
1518
                              "%i weeks",
 
1519
                              age), (guint) age);
 
1520
      goto out;
 
1521
    }
 
1522
 
 
1523
  /* fallback */
 
1524
  g_string_append_printf (string, _("Less than 1 week"));
 
1525
out:
 
1526
  return string;
 
1527
}
 
1528
 
 
1529
static gchar *
 
1530
gcm_prefs_get_profile_created_for_sort (CdProfile *profile)
 
1531
{
 
1532
  gint64 created;
 
1533
  gchar *string = NULL;
 
1534
  GDateTime *dt = NULL;
 
1535
 
 
1536
  /* get profile age */
 
1537
  created = cd_profile_get_created (profile);
 
1538
  if (created == 0)
 
1539
    goto out;
 
1540
  dt = g_date_time_new_from_unix_utc (created);
 
1541
  /* note: this is not shown in the UI, just used for sorting */
 
1542
  string = g_date_time_format (dt, "%Y%m%d");
 
1543
out:
 
1544
  if (dt != NULL)
 
1545
    g_date_time_unref (dt);
 
1546
  return string;
 
1547
}
 
1548
 
 
1549
static gchar *
 
1550
gcm_prefs_get_profile_title (CcColorPanel *prefs, CdProfile *profile)
 
1551
{
 
1552
  CdColorspace colorspace;
 
1553
  const gchar *title;
 
1554
  gchar *string;
 
1555
  gboolean ret;
 
1556
  GError *error = NULL;
 
1557
  CcColorPanelPrivate *priv = prefs->priv;
 
1558
 
 
1559
  g_return_val_if_fail (profile != NULL, NULL);
 
1560
 
 
1561
  string = NULL;
 
1562
 
 
1563
  /* get properties */
 
1564
  ret = cd_profile_connect_sync (profile,
 
1565
                                 priv->cancellable,
 
1566
                                 &error);
 
1567
  if (!ret)
 
1568
    {
 
1569
      g_warning ("failed to get profile: %s", error->message);
 
1570
      g_error_free (error);
 
1571
      goto out;
 
1572
    }
 
1573
 
 
1574
  /* add profile description */
 
1575
  title = cd_profile_get_title (profile);
 
1576
  if (title != NULL)
 
1577
    {
 
1578
      string = g_markup_escape_text (title, -1);
 
1579
      goto out;
 
1580
    }
 
1581
 
 
1582
  /* some meta profiles do not have ICC profiles */
 
1583
  colorspace = cd_profile_get_colorspace (profile);
 
1584
  if (colorspace == CD_COLORSPACE_RGB)
 
1585
    {
 
1586
      string = g_strdup (C_("Colorspace fallback", "Default RGB"));
 
1587
      goto out;
 
1588
    }
 
1589
  if (colorspace == CD_COLORSPACE_CMYK)
 
1590
    {
 
1591
      string = g_strdup (C_("Colorspace fallback", "Default CMYK"));
 
1592
      goto out;
 
1593
    }
 
1594
  if (colorspace == CD_COLORSPACE_GRAY)
 
1595
    {
 
1596
      string = g_strdup (C_("Colorspace fallback", "Default Gray"));
 
1597
      goto out;
 
1598
    }
 
1599
 
 
1600
  /* fall back to ID, ick */
 
1601
  string = g_strdup (cd_profile_get_id (profile));
 
1602
out:
 
1603
  return string;
 
1604
}
 
1605
 
 
1606
static void
 
1607
gcm_prefs_device_remove_profiles_phase1 (CcColorPanel *prefs, GtkTreeIter *parent)
 
1608
{
 
1609
  GtkTreeIter iter;
 
1610
  GtkTreeModel *model;
 
1611
  gboolean ret;
 
1612
  CcColorPanelPrivate *priv = prefs->priv;
 
1613
 
 
1614
  /* get first element */
 
1615
  model = GTK_TREE_MODEL (priv->list_store_devices);
 
1616
  ret = gtk_tree_model_iter_children (model, &iter, parent);
 
1617
  if (!ret)
 
1618
    return;
 
1619
 
 
1620
  /* mark to be removed */
 
1621
  do {
 
1622
    gtk_tree_store_set (priv->list_store_devices, &iter,
 
1623
                        GCM_PREFS_COLUMN_DEVICE_PATH, NULL,
 
1624
                        -1);
 
1625
  } while (gtk_tree_model_iter_next (model, &iter));
 
1626
}
 
1627
 
 
1628
static void
 
1629
gcm_prefs_device_remove_profiles_phase2 (CcColorPanel *prefs, GtkTreeIter *parent)
 
1630
{
 
1631
  GtkTreeIter iter;
 
1632
  GtkTreeModel *model;
 
1633
  gchar *id_tmp;
 
1634
  gboolean ret;
 
1635
  CcColorPanelPrivate *priv = prefs->priv;
 
1636
 
 
1637
  /* get first element */
 
1638
  model = GTK_TREE_MODEL (priv->list_store_devices);
 
1639
  ret = gtk_tree_model_iter_children (model, &iter, parent);
 
1640
  if (!ret)
 
1641
    return;
 
1642
 
 
1643
  /* remove the other elements */
 
1644
  do
 
1645
    {
 
1646
      gtk_tree_model_get (model, &iter,
 
1647
              GCM_PREFS_COLUMN_DEVICE_PATH, &id_tmp,
 
1648
              -1);
 
1649
      if (id_tmp == NULL)
 
1650
        ret = gtk_tree_store_remove (priv->list_store_devices, &iter);
 
1651
      else
 
1652
        ret = gtk_tree_model_iter_next (model, &iter);
 
1653
      g_free (id_tmp);
 
1654
    } while (ret);
 
1655
}
 
1656
 
 
1657
static GtkTreeIter *
 
1658
get_iter_for_profile (GtkTreeModel *model, CdProfile *profile, GtkTreeIter *parent)
 
1659
{
 
1660
  const gchar *id;
 
1661
  gboolean ret;
 
1662
  GtkTreeIter iter;
 
1663
  CdProfile *profile_tmp;
 
1664
 
 
1665
  /* get first element */
 
1666
  ret = gtk_tree_model_iter_children (model, &iter, parent);
 
1667
  if (!ret)
 
1668
    return NULL;
 
1669
 
 
1670
  /* remove the other elements */
 
1671
  id = cd_profile_get_id (profile);
 
1672
  while (ret)
 
1673
    {
 
1674
      gtk_tree_model_get (model, &iter,
 
1675
              GCM_PREFS_COLUMN_PROFILE, &profile_tmp,
 
1676
              -1);
 
1677
      if (g_strcmp0 (id, cd_profile_get_id (profile_tmp)) == 0)
 
1678
        {
 
1679
          g_object_unref (profile_tmp);
 
1680
          return gtk_tree_iter_copy (&iter);
 
1681
        }
 
1682
      g_object_unref (profile_tmp);
 
1683
      ret = gtk_tree_model_iter_next (model, &iter);
 
1684
    }
 
1685
 
 
1686
  return NULL;
 
1687
}
 
1688
 
 
1689
static void
 
1690
gcm_prefs_device_set_model_by_iter (CcColorPanel *prefs, CdDevice *device, GtkTreeIter *iter)
 
1691
{
 
1692
  GString *status = NULL;
 
1693
  const gchar *status_image = NULL;
 
1694
  const gchar *tooltip = NULL;
 
1695
  CdProfile *profile = NULL;
 
1696
  gint age;
 
1697
  GPtrArray *profiles = NULL;
 
1698
  CdProfile *profile_tmp;
 
1699
  guint i;
 
1700
  gchar *title_tmp;
 
1701
  GString *date_tmp;
 
1702
  gchar *sort_tmp;
 
1703
  GtkTreeIter iter_tmp;
 
1704
  GtkTreeIter *iter_tmp_p;
 
1705
  guint threshold = 0;
 
1706
  gboolean ret;
 
1707
  GError *error = NULL;
 
1708
  CcColorPanelPrivate *priv = prefs->priv;
 
1709
 
 
1710
  /* set status */
 
1711
  profile = cd_device_get_default_profile (device);
 
1712
  if (profile == NULL)
 
1713
    {
 
1714
      status = g_string_new (_("Uncalibrated"));
 
1715
      g_string_prepend (status, "<span foreground='gray'><i>");
 
1716
      g_string_append (status, "</i></span>");
 
1717
      tooltip = _("This device is not color managed.");
 
1718
      goto skip;
 
1719
    }
 
1720
 
 
1721
  /* get properties */
 
1722
  ret = cd_profile_connect_sync (profile,
 
1723
                                 priv->cancellable,
 
1724
                                 &error);
 
1725
  if (!ret)
 
1726
    {
 
1727
      g_warning ("failed to get profile: %s", error->message);
 
1728
      g_error_free (error);
 
1729
      goto out;
 
1730
    }
 
1731
 
 
1732
#if CD_CHECK_VERSION(0,1,13)
 
1733
      /* ignore profiles from other user accounts */
 
1734
      if (!cd_profile_has_access (profile))
 
1735
        {
 
1736
          /* only print the filename if it exists */
 
1737
          if (cd_profile_get_filename (profile) != NULL)
 
1738
            {
 
1739
              g_warning ("%s is not usable by this user",
 
1740
                         cd_profile_get_filename (profile));
 
1741
            }
 
1742
          else
 
1743
            {
 
1744
              g_warning ("%s is not usable by this user",
 
1745
                         cd_profile_get_id (profile));
 
1746
            }
 
1747
          goto out;
 
1748
        }
 
1749
#endif
 
1750
 
 
1751
  /* autogenerated printer defaults */
 
1752
  if (cd_device_get_kind (device) == CD_DEVICE_KIND_PRINTER &&
 
1753
      cd_profile_get_filename (profile) == NULL)
 
1754
    {
 
1755
      status = g_string_new (_("Uncalibrated"));
 
1756
      g_string_prepend (status, "<span foreground='gray'><i>");
 
1757
      g_string_append (status, "</i></span>");
 
1758
      tooltip = _("This device is using manufacturing calibrated data.");
 
1759
      goto skip;
 
1760
    }
 
1761
 
 
1762
  /* autogenerated profiles are crap */
 
1763
  if (cd_profile_get_kind (profile) == CD_PROFILE_KIND_DISPLAY_DEVICE &&
 
1764
      !cd_profile_get_has_vcgt (profile))
 
1765
    {
 
1766
      status = g_string_new (_("Uncalibrated"));
 
1767
      g_string_prepend (status, "<span foreground='gray'><i>");
 
1768
      g_string_append (status, "</i></span>");
 
1769
      tooltip = _("This device does not have a profile suitable for whole-screen color correction.");
 
1770
      goto skip;
 
1771
    }
 
1772
 
 
1773
  /* yay! */
 
1774
  status = gcm_prefs_get_profile_age_as_string (profile);
 
1775
  if (status == NULL)
 
1776
    {
 
1777
      status = g_string_new (_("Uncalibrated"));
 
1778
      g_string_prepend (status, "<span foreground='gray'><i>");
 
1779
      g_string_append (status, "</i></span>");
 
1780
    }
 
1781
 
 
1782
  /* greater than the calibration threshold for the device type */
 
1783
  age = cd_profile_get_age (profile);
 
1784
  age /= 60 * 60 * 24;
 
1785
  if (cd_device_get_kind (device) == CD_DEVICE_KIND_DISPLAY)
 
1786
    {
 
1787
      g_settings_get (priv->settings,
 
1788
                      GCM_SETTINGS_RECALIBRATE_DISPLAY_THRESHOLD,
 
1789
                      "u",
 
1790
                      &threshold);
 
1791
    }
 
1792
  else if (cd_device_get_kind (device) == CD_DEVICE_KIND_DISPLAY)
 
1793
    {
 
1794
      g_settings_get (priv->settings,
 
1795
                      GCM_SETTINGS_RECALIBRATE_PRINTER_THRESHOLD,
 
1796
                      "u",
 
1797
                      &threshold);
 
1798
    }
 
1799
  if (threshold > 0 && age > threshold)
 
1800
    {
 
1801
      status_image = "dialog-warning-symbolic";
 
1802
      tooltip = _("This device has an old profile that may no longer be accurate.");
 
1803
    }
 
1804
skip:
 
1805
  /* save to store */
 
1806
  gtk_tree_store_set (priv->list_store_devices, iter,
 
1807
                      GCM_PREFS_COLUMN_STATUS, status->str,
 
1808
                      GCM_PREFS_COLUMN_STATUS_IMAGE, status_image,
 
1809
                      GCM_PREFS_COLUMN_TOOLTIP, tooltip,
 
1810
                      -1);
 
1811
 
 
1812
  /* remove old profiles */
 
1813
  gcm_prefs_device_remove_profiles_phase1 (prefs, iter);
 
1814
 
 
1815
  /* add profiles */
 
1816
  profiles = cd_device_get_profiles (device);
 
1817
  if (profiles == NULL)
 
1818
    goto out;
 
1819
  for (i = 0; i < profiles->len; i++)
 
1820
    {
 
1821
      profile_tmp = g_ptr_array_index (profiles, i);
 
1822
      title_tmp = gcm_prefs_get_profile_title (prefs, profile_tmp);
 
1823
 
 
1824
      /* get profile age */
 
1825
      date_tmp = gcm_prefs_get_profile_age_as_string (profile_tmp);
 
1826
      if (date_tmp == NULL)
 
1827
        {
 
1828
          /* TRANSLATORS: this is when the calibration profile age is not
 
1829
           * specified as it has been autogenerated from the hardware */
 
1830
          date_tmp = g_string_new (_("Not specified"));
 
1831
          g_string_prepend (date_tmp, "<span foreground='gray'><i>");
 
1832
          g_string_append (date_tmp, "</i></span>");
 
1833
        }
 
1834
      sort_tmp = gcm_prefs_get_profile_created_for_sort (profile_tmp);
 
1835
 
 
1836
      /* get an existing profile, or create a new one */
 
1837
      iter_tmp_p = get_iter_for_profile (GTK_TREE_MODEL (priv->list_store_devices),
 
1838
                                         profile_tmp, iter);
 
1839
      if (iter_tmp_p == NULL)
 
1840
        gtk_tree_store_append (priv->list_store_devices, &iter_tmp, iter);
 
1841
 
 
1842
      gtk_tree_store_set (priv->list_store_devices, iter_tmp_p ? iter_tmp_p : &iter_tmp,
 
1843
                          GCM_PREFS_COLUMN_DEVICE, device,
 
1844
                          GCM_PREFS_COLUMN_PROFILE, profile_tmp,
 
1845
                          GCM_PREFS_COLUMN_DEVICE_PATH, cd_device_get_object_path (device),
 
1846
                          GCM_PREFS_COLUMN_SORT, sort_tmp,
 
1847
                          GCM_PREFS_COLUMN_STATUS, date_tmp->str,
 
1848
                          GCM_PREFS_COLUMN_TITLE, title_tmp,
 
1849
                          GCM_PREFS_COLUMN_RADIO_VISIBLE, TRUE,
 
1850
                          GCM_PREFS_COLUMN_RADIO_ACTIVE, i==0,
 
1851
                          -1);
 
1852
      if (iter_tmp_p != NULL)
 
1853
        gtk_tree_iter_free (iter_tmp_p);
 
1854
      g_free (title_tmp);
 
1855
      g_free (sort_tmp);
 
1856
      g_string_free (date_tmp, TRUE);
 
1857
    }
 
1858
 
 
1859
  /* remove old profiles that no longer exist */
 
1860
  gcm_prefs_device_remove_profiles_phase2 (prefs, iter);
 
1861
out:
 
1862
  if (status != NULL)
 
1863
    g_string_free (status, TRUE);
 
1864
  if (profiles != NULL)
 
1865
    g_ptr_array_unref (profiles);
 
1866
  if (profile != NULL)
 
1867
    g_object_unref (profile);
 
1868
}
 
1869
 
 
1870
static void
 
1871
gcm_prefs_device_changed_cb (CdDevice *device, CcColorPanel *prefs)
 
1872
{
 
1873
  const gchar *id;
 
1874
  gboolean ret;
 
1875
  gchar *id_tmp;
 
1876
  GtkTreeIter iter;
 
1877
  GtkTreeModel *model;
 
1878
  CcColorPanelPrivate *priv = prefs->priv;
 
1879
 
 
1880
  /* get first element */
 
1881
  model = GTK_TREE_MODEL (priv->list_store_devices);
 
1882
  ret = gtk_tree_model_get_iter_first (model, &iter);
 
1883
  if (!ret)
 
1884
    return;
 
1885
 
 
1886
  /* get the other elements */
 
1887
  id = cd_device_get_object_path (device);
 
1888
  do
 
1889
    {
 
1890
      gtk_tree_model_get (model, &iter,
 
1891
                          GCM_PREFS_COLUMN_DEVICE_PATH, &id_tmp,
 
1892
                          -1);
 
1893
      if (g_strcmp0 (id_tmp, id) == 0)
 
1894
        {
 
1895
          /* populate device */
 
1896
          gcm_prefs_device_set_model_by_iter (prefs, device, &iter);
 
1897
        }
 
1898
      g_free (id_tmp);
 
1899
    } while (gtk_tree_model_iter_next (model, &iter));
 
1900
}
 
1901
 
 
1902
static void
 
1903
gcm_prefs_add_device (CcColorPanel *prefs, CdDevice *device)
 
1904
{
 
1905
  gboolean ret;
 
1906
  GError *error = NULL;
 
1907
  CdDeviceKind kind;
 
1908
  const gchar *icon_name;
 
1909
  const gchar *id;
 
1910
  gchar *sort = NULL;
 
1911
  gchar *title = NULL;
 
1912
  GtkTreeIter parent;
 
1913
  CcColorPanelPrivate *priv = prefs->priv;
 
1914
 
 
1915
 
 
1916
  /* get device properties */
 
1917
  ret = cd_device_connect_sync (device, priv->cancellable, &error);
 
1918
  if (!ret)
 
1919
    {
 
1920
      g_warning ("failed to connect to the device: %s", error->message);
 
1921
      g_error_free (error);
 
1922
      goto out;
 
1923
    }
 
1924
 
 
1925
  /* get icon */
 
1926
  kind = cd_device_get_kind (device);
 
1927
  icon_name = gcm_prefs_device_kind_to_icon_name (kind);
 
1928
 
 
1929
  /* italic for non-connected devices */
 
1930
  title = gcm_device_get_title (device);
 
1931
 
 
1932
  /* create sort order */
 
1933
  sort = g_strdup_printf ("%s%s",
 
1934
                          gcm_prefs_device_kind_to_sort (kind),
 
1935
                          title);
 
1936
 
 
1937
  /* watch for changes to update the status icons */
 
1938
  g_signal_connect (device, "changed",
 
1939
                    G_CALLBACK (gcm_prefs_device_changed_cb), prefs);
 
1940
 
 
1941
  /* add to list */
 
1942
  id = cd_device_get_object_path (device);
 
1943
  g_debug ("add %s to device list", id);
 
1944
  gtk_tree_store_append (priv->list_store_devices, &parent, NULL);
 
1945
  gtk_tree_store_set (priv->list_store_devices, &parent,
 
1946
                      GCM_PREFS_COLUMN_DEVICE, device,
 
1947
                      GCM_PREFS_COLUMN_DEVICE_PATH, id,
 
1948
                      GCM_PREFS_COLUMN_SORT, sort,
 
1949
                      GCM_PREFS_COLUMN_TITLE, title,
 
1950
                      GCM_PREFS_COLUMN_ICON, icon_name,
 
1951
                      -1);
 
1952
  gcm_prefs_device_set_model_by_iter (prefs, device, &parent);
 
1953
out:
 
1954
  g_free (sort);
 
1955
  g_free (title);
 
1956
}
 
1957
 
 
1958
static void
 
1959
gcm_prefs_remove_device (CcColorPanel *prefs, CdDevice *cd_device)
 
1960
{
 
1961
  GtkTreeIter iter;
 
1962
  GtkTreeModel *model;
 
1963
  const gchar *id;
 
1964
  gchar *id_tmp;
 
1965
  gboolean ret;
 
1966
  CdDevice *device_tmp;
 
1967
  CcColorPanelPrivate *priv = prefs->priv;
 
1968
 
 
1969
  /* remove */
 
1970
  id = cd_device_get_object_path (cd_device);
 
1971
 
 
1972
  /* get first element */
 
1973
  model = GTK_TREE_MODEL (priv->list_store_devices);
 
1974
  ret = gtk_tree_model_get_iter_first (model, &iter);
 
1975
  if (!ret)
 
1976
    return;
 
1977
 
 
1978
  /* get the other elements */
 
1979
  do
 
1980
    {
 
1981
      gtk_tree_model_get (model, &iter,
 
1982
                          GCM_PREFS_COLUMN_DEVICE_PATH, &id_tmp,
 
1983
                          -1);
 
1984
      if (g_strcmp0 (id_tmp, id) == 0)
 
1985
        {
 
1986
          gtk_tree_model_get (model, &iter,
 
1987
                              GCM_PREFS_COLUMN_DEVICE, &device_tmp,
 
1988
                              -1);
 
1989
          g_signal_handlers_disconnect_by_func (device_tmp,
 
1990
                                                G_CALLBACK (gcm_prefs_device_changed_cb),
 
1991
                                                prefs);
 
1992
          gtk_tree_store_remove (GTK_TREE_STORE (model), &iter);
 
1993
          g_free (id_tmp);
 
1994
          g_object_unref (device_tmp);
 
1995
          break;
 
1996
        }
 
1997
      g_free (id_tmp);
 
1998
    } while (gtk_tree_model_iter_next (model, &iter));
 
1999
}
 
2000
 
 
2001
static void
 
2002
gcm_prefs_update_device_list_extra_entry (CcColorPanel *prefs)
 
2003
{
 
2004
  CcColorPanelPrivate *priv = prefs->priv;
 
2005
  gboolean ret;
 
2006
  gchar *id_tmp;
 
2007
  gchar *title = NULL;
 
2008
  GtkTreeIter iter;
 
2009
 
 
2010
  /* select the first device */
 
2011
  ret = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->list_store_devices), &iter);
 
2012
  if (!ret)
 
2013
    {
 
2014
      /* add the 'No devices detected' entry */
 
2015
      title = g_strdup_printf ("<i>%s</i>", _("No devices supporting color management detected"));
 
2016
      gtk_tree_store_append (priv->list_store_devices, &iter, NULL);
 
2017
      gtk_tree_store_set (priv->list_store_devices, &iter,
 
2018
                          GCM_PREFS_COLUMN_RADIO_VISIBLE, FALSE,
 
2019
                          GCM_PREFS_COLUMN_TITLE, title,
 
2020
                          -1);
 
2021
      g_free (title);
 
2022
      return;
 
2023
    }
 
2024
 
 
2025
  /* remove the 'No devices detected' entry */
 
2026
  do
 
2027
    {
 
2028
      gtk_tree_model_get (GTK_TREE_MODEL (priv->list_store_devices), &iter,
 
2029
                          GCM_PREFS_COLUMN_DEVICE_PATH, &id_tmp,
 
2030
                          -1);
 
2031
      if (id_tmp == NULL)
 
2032
        {
 
2033
          gtk_tree_store_remove (priv->list_store_devices, &iter);
 
2034
          break;
 
2035
        }
 
2036
      g_free (id_tmp);
 
2037
    } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->list_store_devices), &iter));
 
2038
}
 
2039
 
 
2040
static void
 
2041
gcm_prefs_device_added_cb (CdClient *client,
 
2042
                           CdDevice *device,
 
2043
                           CcColorPanel *prefs)
 
2044
{
 
2045
  /* add the device */
 
2046
  gcm_prefs_add_device (prefs, device);
 
2047
 
 
2048
  /* ensure we're not showing the 'No devices detected' entry */
 
2049
  gcm_prefs_update_device_list_extra_entry (prefs);
 
2050
}
 
2051
 
 
2052
static void
 
2053
gcm_prefs_changed_cb (CdClient *client,
 
2054
                      CdDevice *device,
 
2055
                      CcColorPanel *prefs)
 
2056
{
 
2057
  g_debug ("changed: %s (doing nothing)", cd_device_get_id (device));
 
2058
}
 
2059
 
 
2060
static void
 
2061
gcm_prefs_device_removed_cb (CdClient *client,
 
2062
                             CdDevice *device,
 
2063
                             CcColorPanel *prefs)
 
2064
{
 
2065
  GtkTreeIter iter;
 
2066
  GtkTreeSelection *selection;
 
2067
  GtkWidget *widget;
 
2068
  gboolean ret;
 
2069
  CcColorPanelPrivate *priv = prefs->priv;
 
2070
 
 
2071
  /* remove from the UI */
 
2072
  gcm_prefs_remove_device (prefs, device);
 
2073
 
 
2074
  /* ensure we showing the 'No devices detected' entry if required */
 
2075
  gcm_prefs_update_device_list_extra_entry (prefs);
 
2076
 
 
2077
  /* select the first device */
 
2078
  ret = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->list_store_devices), &iter);
 
2079
  if (!ret)
 
2080
    return;
 
2081
 
 
2082
  /* click it */
 
2083
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2084
                                               "treeview_devices"));
 
2085
  gtk_tree_view_set_model (GTK_TREE_VIEW (widget),
 
2086
                           GTK_TREE_MODEL (priv->list_store_devices));
 
2087
  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
 
2088
  gtk_tree_selection_select_iter (selection, &iter);
 
2089
}
 
2090
 
 
2091
static gboolean
 
2092
gcm_prefs_tree_model_count_cb (GtkTreeModel *model,
 
2093
                               GtkTreePath *path,
 
2094
                               GtkTreeIter *iter,
 
2095
                               gpointer user_data)
 
2096
{
 
2097
  guint *i = (guint *) user_data;
 
2098
  (*i)++;
 
2099
  return FALSE;
 
2100
}
 
2101
 
 
2102
static void
 
2103
gcm_prefs_get_devices_cb (GObject *object,
 
2104
                          GAsyncResult *res,
 
2105
                          gpointer user_data)
 
2106
{
 
2107
  CcColorPanel *prefs = (CcColorPanel *) user_data;
 
2108
  CdClient *client = CD_CLIENT (object);
 
2109
  CdDevice *device;
 
2110
  GError *error = NULL;
 
2111
  GPtrArray *devices;
 
2112
  GtkTreePath *path;
 
2113
  GtkWidget *widget;
 
2114
  guint i;
 
2115
  guint devices_and_profiles = 0;
 
2116
  CcColorPanelPrivate *priv = prefs->priv;
 
2117
 
 
2118
  /* get devices and add them */
 
2119
  devices = cd_client_get_devices_finish (client, res, &error);
 
2120
  if (devices == NULL)
 
2121
    {
 
2122
      g_warning ("failed to add connected devices: %s",
 
2123
                 error->message);
 
2124
      g_error_free (error);
 
2125
      goto out;
 
2126
    }
 
2127
  for (i = 0; i < devices->len; i++)
 
2128
    {
 
2129
      device = g_ptr_array_index (devices, i);
 
2130
      gcm_prefs_add_device (prefs, device);
 
2131
    }
 
2132
 
 
2133
  /* ensure we show the 'No devices detected' entry if empty */
 
2134
  gcm_prefs_update_device_list_extra_entry (prefs);
 
2135
 
 
2136
  /* set the cursor on the first device */
 
2137
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2138
                                               "treeview_devices"));
 
2139
  path = gtk_tree_path_new_from_string ("0");
 
2140
  gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget), path, NULL, FALSE);
 
2141
  gtk_tree_path_free (path);
 
2142
 
 
2143
  /* if we have only a few devices and profiles expand the treeview
 
2144
   * devices so they can all be seen */
 
2145
  gtk_tree_model_foreach (GTK_TREE_MODEL (priv->list_store_devices),
 
2146
                          gcm_prefs_tree_model_count_cb,
 
2147
                          &devices_and_profiles);
 
2148
  if (devices_and_profiles <= GCM_PREFS_MAX_DEVICES_PROFILES_EXPANDED)
 
2149
    gtk_tree_view_expand_all (GTK_TREE_VIEW (widget));
 
2150
 
 
2151
out:
 
2152
  if (devices != NULL)
 
2153
    g_ptr_array_unref (devices);
 
2154
}
 
2155
 
 
2156
static void
 
2157
gcm_prefs_button_virtual_add_cb (GtkWidget *widget, CcColorPanel *prefs)
 
2158
{
 
2159
  CdDeviceKind device_kind;
 
2160
  CdDevice *device;
 
2161
  const gchar *model;
 
2162
  const gchar *manufacturer;
 
2163
  gchar *device_id;
 
2164
  GError *error = NULL;
 
2165
  GHashTable *device_props;
 
2166
  CcColorPanelPrivate *priv = prefs->priv;
 
2167
 
 
2168
  /* get device details */
 
2169
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2170
                                               "combobox_virtual_type"));
 
2171
  device_kind = gtk_combo_box_get_active (GTK_COMBO_BOX(widget)) + 2;
 
2172
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2173
                                               "entry_virtual_model"));
 
2174
  model = gtk_entry_get_text (GTK_ENTRY (widget));
 
2175
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2176
                                               "entry_virtual_manufacturer"));
 
2177
  manufacturer = gtk_entry_get_text (GTK_ENTRY (widget));
 
2178
 
 
2179
  /* create device */
 
2180
  device_id = g_strdup_printf ("%s-%s-%s",
 
2181
                               cd_device_kind_to_string (device_kind),
 
2182
                               manufacturer,
 
2183
                               model);
 
2184
  device_props = g_hash_table_new_full (g_str_hash, g_str_equal,
 
2185
                                        g_free, g_free);
 
2186
  g_hash_table_insert (device_props,
 
2187
                       g_strdup ("Kind"),
 
2188
                       g_strdup (cd_device_kind_to_string (device_kind)));
 
2189
  g_hash_table_insert (device_props,
 
2190
                       g_strdup ("Mode"),
 
2191
                       g_strdup (cd_device_mode_to_string (CD_DEVICE_MODE_VIRTUAL)));
 
2192
  g_hash_table_insert (device_props,
 
2193
                       g_strdup ("Colorspace"),
 
2194
                       g_strdup (cd_colorspace_to_string (CD_COLORSPACE_RGB)));
 
2195
  g_hash_table_insert (device_props,
 
2196
                       g_strdup ("Model"),
 
2197
                       g_strdup (model));
 
2198
  g_hash_table_insert (device_props,
 
2199
                       g_strdup ("Vendor"),
 
2200
                       g_strdup (manufacturer));
 
2201
  device = cd_client_create_device_sync (priv->client,
 
2202
                                         device_id,
 
2203
                                         CD_OBJECT_SCOPE_DISK,
 
2204
                                         device_props,
 
2205
                                         priv->cancellable,
 
2206
                                         &error);
 
2207
  if (device == NULL)
 
2208
    {
 
2209
      g_warning ("Failed to add create virtual device: %s",
 
2210
                 error->message);
 
2211
      g_error_free (error);
 
2212
      goto out;
 
2213
    }
 
2214
out:
 
2215
  g_hash_table_unref (device_props);
 
2216
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2217
                                               "dialog_virtual"));
 
2218
  gtk_widget_hide (widget);
 
2219
  g_free (device_id);
 
2220
}
 
2221
 
 
2222
static void
 
2223
gcm_prefs_button_virtual_cancel_cb (GtkWidget *widget, CcColorPanel *prefs)
 
2224
{
 
2225
  CcColorPanelPrivate *priv = prefs->priv;
 
2226
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2227
                                               "dialog_virtual"));
 
2228
  gtk_widget_hide (widget);
 
2229
}
 
2230
 
 
2231
static gboolean
 
2232
gcm_prefs_virtual_delete_event_cb (GtkWidget *widget,
 
2233
                                   GdkEvent *event,
 
2234
                                   CcColorPanel *prefs)
 
2235
{
 
2236
  gcm_prefs_button_virtual_cancel_cb (widget, prefs);
 
2237
  return TRUE;
 
2238
}
 
2239
 
 
2240
static const gchar *
 
2241
cd_device_kind_to_localised_string (CdDeviceKind device_kind)
 
2242
{
 
2243
  if (device_kind == CD_DEVICE_KIND_DISPLAY)
 
2244
    return C_("Device kind", "Display");
 
2245
  if (device_kind == CD_DEVICE_KIND_SCANNER)
 
2246
    return C_("Device kind", "Scanner");
 
2247
  if (device_kind == CD_DEVICE_KIND_PRINTER)
 
2248
    return C_("Device kind", "Printer");
 
2249
  if (device_kind == CD_DEVICE_KIND_CAMERA)
 
2250
    return C_("Device kind", "Camera");
 
2251
  if (device_kind == CD_DEVICE_KIND_WEBCAM)
 
2252
    return C_("Device kind", "Webcam");
 
2253
  return NULL;
 
2254
}
 
2255
 
 
2256
static void
 
2257
gcm_prefs_setup_virtual_combobox (GtkWidget *widget)
 
2258
{
 
2259
  guint i;
 
2260
  const gchar *text;
 
2261
 
 
2262
  for (i=CD_DEVICE_KIND_SCANNER; i<CD_DEVICE_KIND_LAST; i++)
 
2263
    {
 
2264
      text = cd_device_kind_to_localised_string (i);
 
2265
      if (text == NULL)
 
2266
        continue;
 
2267
      gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT(widget), text);
 
2268
    }
 
2269
  gtk_combo_box_set_active (GTK_COMBO_BOX (widget), CD_DEVICE_KIND_PRINTER - 2);
 
2270
}
 
2271
 
 
2272
static gboolean
 
2273
gcm_prefs_virtual_set_from_file (CcColorPanel *prefs, GFile *file)
 
2274
{
 
2275
  /* TODO: use GCM to get the EXIF data */
 
2276
  return FALSE;
 
2277
}
 
2278
 
 
2279
static void
 
2280
gcm_prefs_virtual_drag_data_received_cb (GtkWidget *widget,
 
2281
                                         GdkDragContext *context,
 
2282
                                         gint x, gint y,
 
2283
                                         GtkSelectionData *data,
 
2284
                                         guint info,
 
2285
                                         guint _time,
 
2286
                                         CcColorPanel *prefs)
 
2287
{
 
2288
  const guchar *filename;
 
2289
  gchar **filenames = NULL;
 
2290
  GFile *file = NULL;
 
2291
  guint i;
 
2292
  gboolean ret;
 
2293
 
 
2294
  /* get filenames */
 
2295
  filename = gtk_selection_data_get_data (data);
 
2296
  if (filename == NULL)
 
2297
    {
 
2298
      gtk_drag_finish (context, FALSE, FALSE, _time);
 
2299
      goto out;
 
2300
    }
 
2301
 
 
2302
  /* import this */
 
2303
  g_debug ("dropped: %p (%s)", data, filename);
 
2304
 
 
2305
  /* split, as multiple drag targets are accepted */
 
2306
  filenames = g_strsplit_set ((const gchar *)filename, "\r\n", -1);
 
2307
  for (i = 0; filenames[i] != NULL; i++)
 
2308
    {
 
2309
      /* blank entry */
 
2310
      if (filenames[i][0] == '\0')
 
2311
        continue;
 
2312
 
 
2313
      /* check this is a parsable file */
 
2314
      g_debug ("trying to set %s", filenames[i]);
 
2315
      file = g_file_new_for_uri (filenames[i]);
 
2316
      ret = gcm_prefs_virtual_set_from_file (prefs, file);
 
2317
      if (!ret)
 
2318
        {
 
2319
          g_debug ("%s did not set from file correctly",
 
2320
                   filenames[i]);
 
2321
          gtk_drag_finish (context, FALSE, FALSE, _time);
 
2322
          goto out;
 
2323
        }
 
2324
      g_object_unref (file);
 
2325
      file = NULL;
 
2326
    }
 
2327
 
 
2328
  gtk_drag_finish (context, TRUE, FALSE, _time);
 
2329
out:
 
2330
  if (file != NULL)
 
2331
    g_object_unref (file);
 
2332
  g_strfreev (filenames);
 
2333
}
 
2334
 
 
2335
static void
 
2336
gcm_prefs_setup_drag_and_drop (GtkWidget *widget)
 
2337
{
 
2338
  GtkTargetEntry entry;
 
2339
 
 
2340
  /* setup a dummy entry */
 
2341
  entry.target = g_strdup ("text/plain");
 
2342
  entry.flags = GTK_TARGET_OTHER_APP;
 
2343
  entry.info = 0;
 
2344
 
 
2345
  gtk_drag_dest_set (widget,
 
2346
                     GTK_DEST_DEFAULT_ALL,
 
2347
                     &entry,
 
2348
                     1,
 
2349
                     GDK_ACTION_MOVE | GDK_ACTION_COPY);
 
2350
  g_free (entry.target);
 
2351
}
 
2352
 
 
2353
static void
 
2354
gcm_prefs_connect_cb (GObject *object,
 
2355
                      GAsyncResult *res,
 
2356
                      gpointer user_data)
 
2357
{
 
2358
  gboolean ret;
 
2359
  GError *error = NULL;
 
2360
  CcColorPanel *prefs = CC_COLOR_PANEL (user_data);
 
2361
  CcColorPanelPrivate *priv = prefs->priv;
 
2362
 
 
2363
  ret = cd_client_connect_finish (priv->client,
 
2364
                                  res,
 
2365
                                  &error);
 
2366
  if (!ret)
 
2367
    {
 
2368
      g_warning ("failed to connect to colord: %s", error->message);
 
2369
      g_error_free (error);
 
2370
      return;
 
2371
    }
 
2372
 
 
2373
  /* set calibrate button sensitivity */
 
2374
  gcm_prefs_sensor_coldplug (prefs);
 
2375
 
 
2376
 
 
2377
  /* get devices */
 
2378
  cd_client_get_devices (priv->client,
 
2379
                         priv->cancellable,
 
2380
                         gcm_prefs_get_devices_cb,
 
2381
                         prefs);
 
2382
}
 
2383
 
 
2384
static void
 
2385
gcm_prefs_window_realize_cb (GtkWidget *widget, CcColorPanel *prefs)
 
2386
{
 
2387
  prefs->priv->main_window = gtk_widget_get_toplevel (widget);
 
2388
}
 
2389
 
 
2390
static const char *
 
2391
cc_color_panel_get_help_uri (CcPanel *panel)
 
2392
{
 
2393
  if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity"))
 
2394
    return "help:ubuntu-help/color";
 
2395
  else
 
2396
    return "help:gnome-help/color";
 
2397
}
 
2398
 
 
2399
static void
 
2400
cc_color_panel_get_property (GObject    *object,
 
2401
                              guint       property_id,
 
2402
                              GValue     *value,
 
2403
                              GParamSpec *pspec)
 
2404
{
 
2405
  switch (property_id)
 
2406
    {
 
2407
    default:
 
2408
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 
2409
    }
 
2410
}
 
2411
 
 
2412
static void
 
2413
cc_color_panel_set_property (GObject      *object,
 
2414
                              guint         property_id,
 
2415
                              const GValue *value,
 
2416
                              GParamSpec   *pspec)
 
2417
{
 
2418
  switch (property_id)
 
2419
    {
 
2420
    default:
 
2421
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 
2422
    }
 
2423
}
 
2424
 
 
2425
static void
 
2426
cc_color_panel_dispose (GObject *object)
 
2427
{
 
2428
  CcColorPanelPrivate *priv = CC_COLOR_PANEL (object)->priv;
 
2429
 
 
2430
  if (priv->settings)
 
2431
    {
 
2432
      g_object_unref (priv->settings);
 
2433
      priv->settings = NULL;
 
2434
    }
 
2435
  if (priv->cancellable != NULL)
 
2436
    {
 
2437
      g_cancellable_cancel (priv->cancellable);
 
2438
      g_object_unref (priv->cancellable);
 
2439
      priv->cancellable = NULL;
 
2440
    }
 
2441
  if (priv->builder != NULL)
 
2442
    {
 
2443
      g_object_unref (priv->builder);
 
2444
      priv->builder = NULL;
 
2445
    }
 
2446
  if (priv->client != NULL)
 
2447
    {
 
2448
      g_object_unref (priv->client);
 
2449
      priv->client = NULL;
 
2450
    }
 
2451
  if (priv->current_device != NULL)
 
2452
    {
 
2453
      g_object_unref (priv->current_device);
 
2454
      priv->current_device = NULL;
 
2455
    }
 
2456
  if (priv->sensor != NULL)
 
2457
    {
 
2458
      g_object_unref (priv->sensor);
 
2459
      priv->sensor = NULL;
 
2460
    }
 
2461
 
 
2462
  G_OBJECT_CLASS (cc_color_panel_parent_class)->dispose (object);
 
2463
}
 
2464
 
 
2465
static void
 
2466
cc_color_panel_finalize (GObject *object)
 
2467
{
 
2468
  G_OBJECT_CLASS (cc_color_panel_parent_class)->finalize (object);
 
2469
}
 
2470
 
 
2471
static void
 
2472
cc_color_panel_class_init (CcColorPanelClass *klass)
 
2473
{
 
2474
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
2475
  CcPanelClass *panel_class = CC_PANEL_CLASS (klass);
 
2476
 
 
2477
  g_type_class_add_private (klass, sizeof (CcColorPanelPrivate));
 
2478
 
 
2479
  panel_class->get_help_uri = cc_color_panel_get_help_uri;
 
2480
 
 
2481
  object_class->get_property = cc_color_panel_get_property;
 
2482
  object_class->set_property = cc_color_panel_set_property;
 
2483
  object_class->dispose = cc_color_panel_dispose;
 
2484
  object_class->finalize = cc_color_panel_finalize;
 
2485
}
 
2486
 
 
2487
static void
 
2488
cc_color_panel_init (CcColorPanel *prefs)
 
2489
{
 
2490
  CcColorPanelPrivate *priv;
 
2491
  GError *error = NULL;
 
2492
  GtkStyleContext *context;
 
2493
  GtkTreeSelection *selection;
 
2494
  GtkWidget *widget;
 
2495
 
 
2496
  priv = prefs->priv = COLOR_PANEL_PRIVATE (prefs);
 
2497
 
 
2498
  priv->builder = gtk_builder_new ();
 
2499
  gtk_builder_add_from_file (priv->builder,
 
2500
                             GNOMECC_UI_DIR "/color.ui",
 
2501
                             &error);
 
2502
 
 
2503
  if (error != NULL)
 
2504
    {
 
2505
      g_warning ("Could not load interface file: %s", error->message);
 
2506
      g_error_free (error);
 
2507
      return;
 
2508
    }
 
2509
 
 
2510
  priv->cancellable = g_cancellable_new ();
 
2511
 
 
2512
  /* setup defaults */
 
2513
  priv->settings = g_settings_new (GCM_SETTINGS_SCHEMA);
 
2514
 
 
2515
  /* create list stores */
 
2516
  priv->list_store_devices = gtk_tree_store_new (GCM_PREFS_COLUMN_NUM_COLUMNS,
 
2517
                                                 G_TYPE_STRING,
 
2518
                                                 G_TYPE_STRING,
 
2519
                                                 G_TYPE_STRING,
 
2520
                                                 G_TYPE_STRING,
 
2521
                                                 CD_TYPE_DEVICE,
 
2522
                                                 CD_TYPE_PROFILE,
 
2523
                                                 G_TYPE_STRING,
 
2524
                                                 G_TYPE_STRING,
 
2525
                                                 G_TYPE_STRING,
 
2526
                                                 G_TYPE_BOOLEAN,
 
2527
                                                 G_TYPE_BOOLEAN);
 
2528
 
 
2529
  /* assign buttons */
 
2530
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2531
                                               "toolbutton_profile_add"));
 
2532
  g_signal_connect (widget, "clicked",
 
2533
                    G_CALLBACK (gcm_prefs_profile_add_cb), prefs);
 
2534
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2535
                                               "toolbutton_profile_remove"));
 
2536
  g_signal_connect (widget, "clicked",
 
2537
                    G_CALLBACK (gcm_prefs_profile_remove_cb), prefs);
 
2538
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2539
                                               "toolbutton_profile_view"));
 
2540
  g_signal_connect (widget, "clicked",
 
2541
                    G_CALLBACK (gcm_prefs_profile_view_cb), prefs);
 
2542
 
 
2543
  /* create device tree view */
 
2544
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2545
                                               "treeview_devices"));
 
2546
  gtk_tree_view_set_model (GTK_TREE_VIEW (widget),
 
2547
                           GTK_TREE_MODEL (priv->list_store_devices));
 
2548
  gtk_tree_view_set_enable_tree_lines (GTK_TREE_VIEW (widget), TRUE);
 
2549
  gtk_tree_view_set_level_indentation (GTK_TREE_VIEW (widget), 0);
 
2550
  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
 
2551
  g_signal_connect (selection, "changed",
 
2552
                    G_CALLBACK (gcm_prefs_devices_treeview_clicked_cb),
 
2553
                    prefs);
 
2554
  g_signal_connect (GTK_TREE_VIEW (widget), "row-activated",
 
2555
                    G_CALLBACK (gcm_prefs_treeview_row_activated_cb),
 
2556
                    prefs);
 
2557
  g_signal_connect (GTK_TREE_VIEW (widget), "popup-menu",
 
2558
                    G_CALLBACK (gcm_prefs_treeview_popup_menu_cb),
 
2559
                    prefs);
 
2560
 
 
2561
  /* add columns to the tree view */
 
2562
  gcm_prefs_add_devices_columns (prefs, GTK_TREE_VIEW (widget));
 
2563
 
 
2564
  /* force to be at least ~6 rows high */
 
2565
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2566
                                               "scrolledwindow_devices"));
 
2567
  gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (widget),
 
2568
                                              200);
 
2569
 
 
2570
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2571
                                               "toolbutton_device_default"));
 
2572
  g_signal_connect (widget, "clicked",
 
2573
                    G_CALLBACK (gcm_prefs_default_cb), prefs);
 
2574
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2575
                                               "toolbutton_device_remove"));
 
2576
  g_signal_connect (widget, "clicked",
 
2577
                    G_CALLBACK (gcm_prefs_delete_cb), prefs);
 
2578
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2579
                                               "toolbutton_device_add"));
 
2580
  g_signal_connect (widget, "clicked",
 
2581
                    G_CALLBACK (gcm_prefs_device_add_cb), prefs);
 
2582
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2583
                                               "toolbutton_device_calibrate"));
 
2584
  g_signal_connect (widget, "clicked",
 
2585
                    G_CALLBACK (gcm_prefs_calibrate_cb), prefs);
 
2586
 
 
2587
  /* make devices toolbar sexy */
 
2588
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2589
                                               "scrolledwindow_devices"));
 
2590
  context = gtk_widget_get_style_context (widget);
 
2591
  gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);
 
2592
 
 
2593
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2594
                                               "toolbar_devices"));
 
2595
  context = gtk_widget_get_style_context (widget);
 
2596
  gtk_style_context_add_class (context, GTK_STYLE_CLASS_INLINE_TOOLBAR);
 
2597
  gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
 
2598
 
 
2599
  /* set up virtual dialog */
 
2600
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2601
                                               "dialog_virtual"));
 
2602
  g_signal_connect (widget, "delete-event",
 
2603
                    G_CALLBACK (gcm_prefs_virtual_delete_event_cb),
 
2604
                    prefs);
 
2605
  g_signal_connect (widget, "drag-data-received",
 
2606
                    G_CALLBACK (gcm_prefs_virtual_drag_data_received_cb),
 
2607
                    prefs);
 
2608
  gcm_prefs_setup_drag_and_drop (widget);
 
2609
 
 
2610
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2611
                                               "button_virtual_add"));
 
2612
  g_signal_connect (widget, "clicked",
 
2613
                    G_CALLBACK (gcm_prefs_button_virtual_add_cb),
 
2614
                    prefs);
 
2615
 
 
2616
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2617
                                               "button_virtual_cancel"));
 
2618
  g_signal_connect (widget, "clicked",
 
2619
                    G_CALLBACK (gcm_prefs_button_virtual_cancel_cb),
 
2620
                    prefs);
 
2621
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2622
                                               "combobox_virtual_type"));
 
2623
  gcm_prefs_setup_virtual_combobox (widget);
 
2624
 
 
2625
  /* set up assign dialog */
 
2626
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2627
                                               "dialog_assign"));
 
2628
  g_signal_connect (widget, "delete-event",
 
2629
                    G_CALLBACK (gcm_prefs_profile_delete_event_cb), prefs);
 
2630
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2631
                                               "button_assign_cancel"));
 
2632
  g_signal_connect (widget, "clicked",
 
2633
                    G_CALLBACK (gcm_prefs_button_assign_cancel_cb), prefs);
 
2634
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2635
                                               "button_assign_ok"));
 
2636
  g_signal_connect (widget, "clicked",
 
2637
                    G_CALLBACK (gcm_prefs_button_assign_ok_cb), prefs);
 
2638
 
 
2639
  /* setup icc profiles list */
 
2640
  widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
2641
                                               "combobox_profile"));
 
2642
  gcm_prefs_set_combo_simple_text (widget);
 
2643
  gtk_widget_set_sensitive (widget, FALSE);
 
2644
  g_signal_connect (G_OBJECT (widget), "changed",
 
2645
                    G_CALLBACK (gcm_prefs_profile_combo_changed_cb), prefs);
 
2646
 
 
2647
  /* use a device client array */
 
2648
  priv->client = cd_client_new ();
 
2649
  g_signal_connect_object (priv->client, "device-added",
 
2650
                           G_CALLBACK (gcm_prefs_device_added_cb), prefs, 0);
 
2651
  g_signal_connect_object (priv->client, "device-removed",
 
2652
                           G_CALLBACK (gcm_prefs_device_removed_cb), prefs, 0);
 
2653
  g_signal_connect_object (priv->client, "changed",
 
2654
                           G_CALLBACK (gcm_prefs_changed_cb), prefs, 0);
 
2655
 
 
2656
  /* connect to colord */
 
2657
  cd_client_connect (priv->client,
 
2658
                     priv->cancellable,
 
2659
                     gcm_prefs_connect_cb,
 
2660
                     prefs);
 
2661
 
 
2662
  /* use the color sensor */
 
2663
  g_signal_connect_object (priv->client, "sensor-added",
 
2664
                           G_CALLBACK (gcm_prefs_client_sensor_changed_cb),
 
2665
                           prefs, 0);
 
2666
  g_signal_connect_object (priv->client, "sensor-removed",
 
2667
                           G_CALLBACK (gcm_prefs_client_sensor_changed_cb),
 
2668
                           prefs, 0);
 
2669
 
 
2670
  /* set calibrate button sensitivity */
 
2671
  gcm_prefs_set_calibrate_button_sensitivity (prefs);
 
2672
 
 
2673
  widget = WID (priv->builder, "dialog-vbox1");
 
2674
  gtk_widget_reparent (widget, (GtkWidget *) prefs);
 
2675
  g_signal_connect (widget, "realize",
 
2676
                    G_CALLBACK (gcm_prefs_window_realize_cb),
 
2677
                    prefs);
 
2678
 
 
2679
  widget = WID (priv->builder, "linkbutton_help");
 
2680
  if (!g_strcmp0(g_getenv("XDG_CURRENT_DESKTOP"), "Unity"))
 
2681
    g_object_set (G_OBJECT (widget),
 
2682
              "uri", "help:ubuntu-help/color-whyimportant",
 
2683
              NULL);
 
2684
}
 
2685
 
 
2686
void
 
2687
cc_color_panel_register (GIOModule *module)
 
2688
{
 
2689
  cc_color_panel_register_type (G_TYPE_MODULE (module));
 
2690
  g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT,
 
2691
                                  CC_TYPE_COLOR_PANEL,
 
2692
                                  "color", 0);
 
2693
}
 
2694