[gnome-control-center/wip/um-avatar-picker: 3/4] user-accounts: Add a new um-avatar-picker to replace um-photo-dialog



commit 73d1b9bc785f7fffa6eb7fd61ab66a0d15430f17
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Mon Oct 21 14:23:44 2013 -0400

    user-accounts: Add a new um-avatar-picker to replace um-photo-dialog
    
    This is a new implementation using GtkStackSwitcher and composite
    template widgets and friends that implements the new avatar picker
    designs by Allan.
    
    Based-heavily-on-a-patch-by: Bogdan Ciobanu <bgdn ciobanu gmail com>

 panels/user-accounts/Makefile.am                   |   46 +++-
 .../data/avatar-picker-camera-page.ui              |   35 ++
 panels/user-accounts/data/avatar-picker.ui         |   97 ++++++
 panels/user-accounts/test-um-avatar-picker.c       |   66 ++++
 .../user-accounts/um-avatar-picker-camera-page.c   |  126 ++++++++
 .../user-accounts/um-avatar-picker-camera-page.h   |   55 ++++
 panels/user-accounts/um-avatar-picker-private.h    |   36 +++
 panels/user-accounts/um-avatar-picker.c            |  325 ++++++++++++++++++++
 panels/user-accounts/um-avatar-picker.h            |   58 ++++
 .../user-accounts-camera.gresource.xml             |    6 +
 panels/user-accounts/user-accounts.gresource.xml   |    1 +
 11 files changed, 848 insertions(+), 3 deletions(-)
---
diff --git a/panels/user-accounts/Makefile.am b/panels/user-accounts/Makefile.am
index 4bb02ee..ea3da31 100644
--- a/panels/user-accounts/Makefile.am
+++ b/panels/user-accounts/Makefile.am
@@ -25,6 +25,28 @@ BUILT_SOURCES = \
        um-resources.c \
        um-resources.h
 
+if BUILD_CHEESE
+BUILT_SOURCES +=                       \
+       um-camera-resources.c           \
+       um-camera-resources.h           \
+       $(NULL)
+endif
+
+avatar_picker_sources =                \
+       um-avatar-picker.c              \
+       um-avatar-picker.h              \
+       um-avatar-picker-private.h      \
+       online-avatars.c                \
+       online-avatars.h                \
+       $(NULL)
+
+if BUILD_CHEESE
+avatar_picker_sources +=               \
+       um-avatar-picker-camera-page.c  \
+       um-avatar-picker-camera-page.h  \
+       $(NULL)
+endif
+
 libuser_accounts_la_SOURCES =          \
        um-account-type.h               \
        um-account-type.c               \
@@ -55,8 +77,7 @@ libuser_accounts_la_SOURCES =         \
        um-realm-manager.h              \
        um-history-dialog.h             \
        um-history-dialog.c             \
-       online-avatars.c                \
-       online-avatars.h                \
+       $(avatar_picker_sources)        \
        $(BUILT_SOURCES)
 
 libuser_accounts_la_LIBADD =           \
@@ -84,7 +105,13 @@ um-resources.c: user-accounts.gresource.xml $(resource_files)
 um-resources.h: user-accounts.gresource.xml $(resource_files)
        $(AM_V_GEN) glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-header --c-name um $<
 
-noinst_PROGRAMS = frob-account-dialog test-online-avatars
+camera_resource_files = $(shell glib-compile-resources --sourcedir=$(srcdir) --generate-dependencies 
$(srcdir)/user-accounts-camera.gresource.xml)
+um-camera-resources.c: user-accounts-camera.gresource.xml $(resource_files)
+       $(AM_V_GEN) glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-source --c-name 
um_camera $<
+um-camera-resources.h: user-accounts-camera.gresource.xml $(resource_files)
+       $(AM_V_GEN) glib-compile-resources --target=$@ --sourcedir=$(srcdir) --generate-header --c-name 
um_camera $<
+
+noinst_PROGRAMS = frob-account-dialog test-online-avatars test-um-avatar-picker
 
 frob_account_dialog_SOURCES = \
        frob-account-dialog.c \
@@ -115,6 +142,17 @@ test_online_avatars_LDADD = \
 test_online_avatars_CFLAGS = \
        $(AM_CPPFLAGS)
 
+test_um_avatar_picker_SOURCES =        \
+       test-um-avatar-picker.c         \
+       $(avatar_picker_sources)        \
+       $(BUILT_SOURCES)
+
+test_um_avatar_picker_LDADD = \
+       $(libuser_accounts_la_LIBADD)
+
+test_um_avatar_picker_CFLAGS = \
+       $(AM_CPPFLAGS)
+
 polkitdir = $(datadir)/polkit-1/actions
 polkit_in_files = org.gnome.controlcenter.user-accounts.policy.in
 
@@ -125,6 +163,8 @@ EXTRA_DIST =                                \
        $(polkit_in_files)              \
        $(resource_files)               \
        user-accounts.gresource.xml     \
+       $(camera_resource_files)        \
+       user-accounts-camera.gresource.xml \
        $(NULL)
 
 CLEANFILES =                           \
diff --git a/panels/user-accounts/data/avatar-picker-camera-page.ui 
b/panels/user-accounts/data/avatar-picker-camera-page.ui
new file mode 100644
index 0000000..88ee048
--- /dev/null
+++ b/panels/user-accounts/data/avatar-picker-camera-page.ui
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.10 -->
+  <template class="UmAvatarPickerCameraPage" parent="GtkBox">
+    <property name="orientation">vertical</property>
+    <child>
+      <object class="GtkBox" id="camera_placeholder">
+        <property name="visible">True</property>
+        <property name="vexpand">True</property>
+      </object>
+    </child>
+    <child>
+      <object class="GtkToolbar" id="camera_toolbar">
+        <property name="visible">True</property>
+        <property name="icon-size">menu</property>
+        <child>
+          <object class="GtkToolButton" id="camera_photo_button">
+            <property name="visible">True</property>
+            <property name="width-request">80</property>
+            <property name="margin-top">4</property>
+            <property name="margin-bottom">4</property>
+            <property name="halign">center</property>
+            <property name="icon-name">camera-photo-symbolic</property>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+          </packing>
+        </child>
+        <style>
+          <class name="inline-toolbar" />
+        </style>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/panels/user-accounts/data/avatar-picker.ui b/panels/user-accounts/data/avatar-picker.ui
new file mode 100644
index 0000000..a90c8a0
--- /dev/null
+++ b/panels/user-accounts/data/avatar-picker.ui
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.10 -->
+  <template class="UmAvatarPicker" parent="GtkDialog">
+    <property name="title" translatable="yes">Account Picture</property>
+    <property name="default-width">600</property>
+    <property name="default-height">500</property>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="content_box">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">10</property>
+        <child>
+          <object class="GtkStackSwitcher" id="tabs">
+            <property name="visible">True</property>
+            <property name="stack">stack</property>
+            <property name="halign">center</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkStack" id="stack">
+            <property name="visible">True</property>
+            <property name="vexpand">True</property>
+            <property name="transition-type">crossfade</property>
+            <child>
+              <object class="GtkScrolledWindow" id="avatars_page">
+                <property name="visible">True</property>
+                <property name="vexpand">True</property>
+                <property name="shadow-type">etched-in</property>
+                <child>
+                  <object class="GtkBox" id="avatars_box">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <property name="spacing">10</property>
+                    <child>
+                      <object class="GtkFlowBox" id="avatars_online">
+                        <property name="visible">True</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkSeparator" id="avatars_separator">
+                        <property name="visible">True</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkFlowBox" id="avatars_stock">
+                        <property name="visible">True</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="name">avatars</property>
+                <property name="title" translatable="yes">Avatars</property>
+              </packing>
+            </child>
+
+            <!--
+            <child>
+              <object class="GtkBox" id="pictures_page">
+                <property name="visible">True</property>
+              </object>
+              <packing>
+                <property name="name">pictures</property>
+                <property name="title" translatable="yes">Pictures</property>
+              </packing>
+            </child>
+            -->
+          </object>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkBox" id="button_box">
+            <property name="visible">True</property>
+            <property name="halign">end</property>
+            <child>
+              <object class="GtkButton" id="cancel_button">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Cancel</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkButton" id="select_button">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Select</property>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-3">select_button</action-widget>
+      <action-widget response="-5">cancel_button</action-widget>
+    </action-widgets>
+  </template>
+</interface>
diff --git a/panels/user-accounts/test-um-avatar-picker.c b/panels/user-accounts/test-um-avatar-picker.c
new file mode 100644
index 0000000..e9221a7
--- /dev/null
+++ b/panels/user-accounts/test-um-avatar-picker.c
@@ -0,0 +1,66 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright 2013 Red Hat, Inc,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Written by:
+ *   Jasper St. Pierre <jstpierre mecheye net>
+ */
+
+#include "config.h"
+
+#include "um-avatar-picker.h"
+
+#ifdef HAVE_CHEESE
+#include <cheese-gtk.h>
+#include <clutter-gtk/clutter-gtk.h>
+#endif /* HAVE_CHEESE */
+
+#include <gtk/gtk.h>
+
+int
+main (int argc, char *argv[])
+{
+    GtkWidget *picker;
+    GdkPixbuf *pixbuf = NULL;
+    int response;
+
+#ifdef HAVE_CHEESE
+    cheese_gtk_init (&argc, &argv);
+    if (gtk_clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
+        g_error ("could not init clutter-gtk");
+#endif /* HAVE_CHEESE */
+
+    gtk_init (&argc, &argv);
+
+    picker = um_avatar_picker_new ();
+    response = gtk_dialog_run (GTK_DIALOG (picker));
+
+    if (response == GTK_RESPONSE_ACCEPT) {
+        g_print ("Selected an avatar\n");
+        pixbuf = um_avatar_picker_get_avatar (UM_AVATAR_PICKER (picker));
+        gdk_pixbuf_save (pixbuf, "picked-avatar.png", "png", NULL, NULL);
+    } else if (response == GTK_RESPONSE_CANCEL) {
+        g_print ("Cancelled\n");
+    } else {
+        g_warning ("Unexpected response %d\n", response);
+        g_assert_not_reached ();
+    }
+
+    gtk_widget_destroy (GTK_WIDGET (picker));
+
+    return 0;
+}
diff --git a/panels/user-accounts/um-avatar-picker-camera-page.c 
b/panels/user-accounts/um-avatar-picker-camera-page.c
new file mode 100644
index 0000000..5169b5c
--- /dev/null
+++ b/panels/user-accounts/um-avatar-picker-camera-page.c
@@ -0,0 +1,126 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright 2013 Red Hat, Inc,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Written by:
+ *   Jasper St. Pierre <jstpierre mecheye net>
+ *   Bogdan Ciobanu <bgdn ciobanu gmail com>
+ */
+
+#if 0
+
+#include "config.h"
+
+#include <cheese-widget.h>
+#include <cheese-camera.h>
+#include <cheese-camera-device.h>
+#include <cheese-camera-device-monitor.h>
+
+#include "um-avatar-picker-camera-page.h"
+
+struct _UmAvatarPickerCameraPagePrivate
+{
+    GtkWidget *camera_photo_button;
+    GtkWidget *camera_placeholder;
+    GtkWidget *camera;
+
+    CheeseCameraDeviceMonitor *monitor;
+    guint num_cameras;
+};
+
+typedef struct _UmAvatarPickerCameraPagePrivate UmAvatarPickerCameraPagePrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (UmAvatarPickerCameraPage, um_avatar_picker_camera_page, GTK_TYPE_BOX);
+
+static void
+update_visibility (UmAvatarPickerCameraPage *page)
+{
+    UmAvatarPickerCameraPagePrivate *priv = um_avatar_picker_camera_page_get_instance_private (page);
+    gtk_widget_set_visible (GTK_WIDGET (page), priv->num_cameras > 0);
+}
+
+static void
+camera_photo_taken (CheeseCamera *camera,
+                    GdkPixbuf    *pixbuf,
+                    gpointer      user_data)
+{
+}
+
+static void
+device_added (CheeseCameraDeviceMonitor *monitor,
+              CheeseCameraDevice        *device,
+              UmAvatarPickerCameraPage  *page)
+{
+    UmAvatarPickerCameraPagePrivate *priv = um_avatar_picker_camera_page_get_instance_private (page);
+    priv->num_cameras++;
+    update_visibility (page);
+}
+
+static void
+device_removed (CheeseCameraDeviceMonitor *monitor,
+                const char                *id,
+                UmAvatarPickerCameraPage  *page)
+{
+    UmAvatarPickerCameraPagePrivate *priv = um_avatar_picker_camera_page_get_instance_private (page);
+    priv->num_cameras--;
+    update_visibility (page);
+}
+
+static void
+um_avatar_picker_camera_page_dispose (GObject *object)
+{
+    UmAvatarPickerCameraPage *page = UM_AVATAR_PICKER_CAMERA_PAGE (object);
+    UmAvatarPickerCameraPagePrivate *priv = um_avatar_picker_camera_page_get_instance_private (page);
+
+    g_clear_object (&priv->monitor);
+}
+
+static void
+um_avatar_picker_camera_page_class_init (UmAvatarPickerCameraPageClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    object_class->dispose = um_avatar_picker_camera_page_dispose;
+
+    gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (klass), 
"/org/gnome/control-center/user-accounts/avatar-picker-camera-page.ui");
+
+    gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), UmAvatarPickerCameraPage, 
camera_placeholder);
+    gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), UmAvatarPickerCameraPage, 
camera_photo_button);
+}
+
+static void
+um_avatar_picker_camera_page_init (UmAvatarPickerCameraPage *page)
+{
+    UmAvatarPickerCameraPagePrivate *priv = um_avatar_picker_camera_page_get_instance_private (page);
+
+    gtk_widget_init_template (GTK_WIDGET (page));
+
+    priv->camera = cheese_widget_new ();
+    g_signal_connect (cheese_widget_get_camera (CHEESE_CAMERA (priv->camera)), "photo-taken",
+                      G_CALLBACK (camera_photo_taken), page);
+    gtk_widget_show (priv->camera);
+    gtk_container_add (GTK_CONTAINER (priv->camera_placeholder), priv->camera);
+
+    priv->monitor = cheese_camera_device_monitor_new ();
+    g_signal_connect (G_OBJECT (priv->monitor), "added",
+                      G_CALLBACK (device_added), page);
+    g_signal_connect (G_OBJECT (priv->monitor), "removed",
+                      G_CALLBACK (device_removed), page);
+    cheese_camera_device_monitor_coldplug (priv->monitor);
+}
+
+#endif
diff --git a/panels/user-accounts/um-avatar-picker-camera-page.h 
b/panels/user-accounts/um-avatar-picker-camera-page.h
new file mode 100644
index 0000000..f70d40a
--- /dev/null
+++ b/panels/user-accounts/um-avatar-picker-camera-page.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright 2013 Red Hat, Inc,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Written by:
+ *   Jasper St. Pierre <jstpierre mecheye net>
+ *   Bogdan Ciobanu <bgdn ciobanu gmail com>
+ */
+
+#ifndef __UM_AVATAR_PICKER_CAMERA_PAGE_H__
+#define __UM_AVATAR_PICKER_CAMERA_PAGE_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define UM_TYPE_AVATAR_PICKER_CAMERA_PAGE               (um_avatar_picker_camera_page_get_type ())
+#define UM_AVATAR_PICKER_CAMERA_PAGE(obj)                           (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
UM_TYPE_AVATAR_PICKER_CAMERA_PAGE, UmAvatarPickerCameraPage))
+#define UM_AVATAR_PICKER_CAMERA_PAGE_CLASS(klass)                   (G_TYPE_CHECK_CLASS_CAST ((klass),  
UM_TYPE_AVATAR_PICKER_CAMERA_PAGE, UmAvatarPickerCameraPageClass))
+#define UM_IS_AVATAR_PICKER_CAMERA_PAGE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
UM_TYPE_AVATAR_PICKER_CAMERA_PAGE))
+#define UM_IS_AVATAR_PICKER_CAMERA_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  
UM_TYPE_AVATAR_PICKER_CAMERA_PAGE))
+#define UM_AVATAR_PICKER_CAMERA_PAGE_GET_CLASS(obj)                 (G_TYPE_INSTANCE_GET_CLASS ((obj),  
UM_TYPE_AVATAR_PICKER_CAMERA_PAGE, UmAvatarPickerCameraPageClass))
+
+typedef struct _UmAvatarPickerCameraPage        UmAvatarPickerCameraPage;
+typedef struct _UmAvatarPickerCameraPageClass   UmAvatarPickerCameraPageClass;
+
+struct _UmAvatarPickerCameraPage
+{
+    GtkBox parent;
+};
+
+struct _UmAvatarPickerCameraPageClass
+{
+    GtkBoxClass parent_class;
+};
+
+GType um_avatar_picker_camera_page_get_type (void);
+
+G_END_DECLS
+
+#endif /* __UM_AVATAR_PICKER_CAMERA_PAGE_H__ */
diff --git a/panels/user-accounts/um-avatar-picker-private.h b/panels/user-accounts/um-avatar-picker-private.h
new file mode 100644
index 0000000..a89e220
--- /dev/null
+++ b/panels/user-accounts/um-avatar-picker-private.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright 2013 Red Hat, Inc,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Written by:
+ *   Jasper St. Pierre <jstpierre mecheye net>
+ *   Bogdan Ciobanu <bgdn ciobanu gmail com>
+ */
+
+#ifndef __UM_AVATAR_PICKER_PRIVATE_H__
+#define __UM_AVATAR_PICKER_PRIVATE_H__
+
+#include "um-avatar-picker-private.h"
+
+G_BEGIN_DECLS
+
+void _um_avatar_picker_set_avatar (UmAvatarPicker *picker,
+                                   GdkPixbuf      *pixbuf);
+
+G_END_DECLS
+
+#endif /* __UM_AVATAR_PICKER_PRIVATE_H__ */
diff --git a/panels/user-accounts/um-avatar-picker.c b/panels/user-accounts/um-avatar-picker.c
new file mode 100644
index 0000000..b09a741
--- /dev/null
+++ b/panels/user-accounts/um-avatar-picker.c
@@ -0,0 +1,325 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright 2013 Red Hat, Inc,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Written by:
+ *   Jasper St. Pierre <jstpierre mecheye net>
+ *   Bogdan Ciobanu <bgdn ciobanu gmail com>
+ */
+
+#define IMAGE_SIZE 96
+
+#include "config.h"
+#include "um-avatar-picker.h"
+#include "um-avatar-picker-private.h"
+
+#include <glib/gi18n.h>
+#include "online-avatars.h"
+
+/* Camera page is disabled until we can fix libcheese. */
+#undef HAVE_CHEESE
+
+#ifdef HAVE_CHEESE
+#include "um-avatar-picker-camera-page.h"
+#endif /* HAVE_CHEESE */
+
+struct _UmAvatarPickerPrivate
+{
+    GtkWidget *stack;
+    GtkWidget *avatars_online;
+    GtkWidget *avatars_stock;
+    GtkWidget *select_button;
+
+    GtkWidget *camera_placeholder;
+
+    GdkPixbuf *selected_avatar;
+
+    GtkWidget *selected_avatar_widget;
+    gboolean clearing_selection;
+};
+typedef struct _UmAvatarPickerPrivate UmAvatarPickerPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (UmAvatarPicker, um_avatar_picker, GTK_TYPE_DIALOG);
+
+static void
+image_set_from_bytes (GtkImage *image,
+                      GBytes   *bytes)
+{
+    GdkPixbufLoader *loader;
+    GdkPixbuf *pixbuf = NULL;
+    GdkPixbuf *scaled_pixbuf = NULL;
+    GError *error = NULL;
+
+    if (!bytes) {
+        GtkWidget *flow_box_child = gtk_widget_get_parent (GTK_WIDGET (image));
+        gtk_widget_destroy (flow_box_child);
+        return;
+    }
+
+    loader = gdk_pixbuf_loader_new ();
+    if (!gdk_pixbuf_loader_write_bytes (loader, bytes, &error)) {
+        g_warning ("Could not load image: %s\n", error->message);
+        goto out;
+    }
+
+    if (!gdk_pixbuf_loader_close (loader, NULL)) {
+        g_warning ("Could not load image: %s\n", error->message);
+        goto out;
+    }
+
+    pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+    if (!pixbuf) {
+        g_warning ("Could not load image\n");
+        goto out;
+    }
+
+    scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf, IMAGE_SIZE, IMAGE_SIZE,
+                                             GDK_INTERP_BILINEAR);
+    gtk_image_set_from_pixbuf (image, scaled_pixbuf);
+    gtk_widget_show (GTK_WIDGET (image));
+
+ out:
+    g_clear_error (&error);
+    g_object_unref (loader);
+    if (scaled_pixbuf)
+        g_object_unref (scaled_pixbuf);
+}
+
+static void
+got_avatar_cb (GObject      *source_object,
+               GAsyncResult *result,
+               gpointer      user_data)
+{
+    GtkImage *image = GTK_IMAGE (user_data);
+    GBytes *bytes;
+    bytes = get_avatar_from_online_account_finish (GOA_ACCOUNT (source_object), result, NULL);
+    image_set_from_bytes (image, bytes);
+}
+
+static void
+got_gravatar_cb (GObject      *source_object,
+                 GAsyncResult *result,
+                 gpointer      user_data)
+{
+    GtkImage *image = GTK_IMAGE (user_data);
+    GBytes *bytes;
+    bytes = get_gravatar_from_email_finish (result, NULL);
+    image_set_from_bytes (image, bytes);
+}
+
+static void
+fill_online_icons (UmAvatarPicker *picker)
+{
+    UmAvatarPickerPrivate *priv = um_avatar_picker_get_instance_private (picker);
+    GHashTable *used_emails;
+    GoaClient *client;
+    GList *accounts, *l;
+
+    client = goa_client_new_sync (NULL, NULL);
+    if (!client)
+        return;
+
+    used_emails = g_hash_table_new (g_str_hash, g_str_equal);
+    accounts = goa_client_get_accounts (client);
+
+    for (l = accounts; l; l = l->next) {
+        GoaObject *object = GOA_OBJECT (l->data);
+        GoaAccount *account = goa_object_peek_account (object);
+        GoaMail *mail = goa_object_peek_mail (object);
+        GtkWidget *image;
+
+        image = gtk_image_new ();
+        gtk_widget_set_size_request (image, IMAGE_SIZE, IMAGE_SIZE);
+        get_avatar_from_online_account (account, NULL, got_avatar_cb, image);
+        gtk_container_add (GTK_CONTAINER (priv->avatars_online), image);
+
+        if (mail) {
+            const char *email = goa_mail_get_email_address (mail);
+            if (!g_hash_table_contains (used_emails, email)) {
+                image = gtk_image_new ();
+                gtk_widget_set_size_request (image, IMAGE_SIZE, IMAGE_SIZE);
+                get_gravatar_from_email (email, NULL, got_gravatar_cb, image);
+                gtk_container_add (GTK_CONTAINER (priv->avatars_online), image);
+
+                g_hash_table_add (used_emails, (gpointer) email);
+            }
+        }
+    }
+
+    g_list_free_full (accounts, (GDestroyNotify) g_object_unref);
+    g_hash_table_destroy (used_emails);
+}
+
+static void
+fill_stock_icons_from_dir (UmAvatarPicker *picker,
+                           char           *path,
+                           GDir           *dir)
+{
+    UmAvatarPickerPrivate *priv = um_avatar_picker_get_instance_private (picker);
+    const char *face;
+    GtkWidget *image;
+
+    while ((face = g_dir_read_name (dir)) != NULL) {
+        char *filename = g_build_filename (path, face, NULL);
+
+        image = gtk_image_new_from_file (filename);
+        gtk_widget_set_size_request (image, IMAGE_SIZE, IMAGE_SIZE);
+        gtk_widget_show (image);
+
+        gtk_container_add (GTK_CONTAINER (priv->avatars_stock), image);
+
+        g_free (filename);
+    }
+}
+
+static void
+fill_stock_icons (UmAvatarPicker *picker)
+{
+    const char * const * dirs = g_get_system_data_dirs ();
+    int i;
+
+    for (i = 0; dirs[i] != NULL; i++) {
+        char *path = g_build_filename (dirs[i], "pixmaps", "faces", NULL);
+        GDir *dir = g_dir_open (path, 0, NULL);
+
+        if (!dir)
+            goto next;
+
+        fill_stock_icons_from_dir (picker, path, dir);
+
+    next:
+        g_free (path);
+        if (dir)
+            g_dir_close (dir);
+    }
+}
+
+static void
+selection_changed (GtkFlowBox *box,
+                   gpointer    user_data)
+{
+    UmAvatarPicker *picker = user_data;
+    UmAvatarPickerPrivate *priv = um_avatar_picker_get_instance_private (picker);
+    GtkFlowBox *boxen[3] = { (GtkFlowBox *) priv->avatars_stock, (GtkFlowBox *) priv->avatars_online, NULL };
+    GtkFlowBox **widget;
+    GList *l;
+
+    if (priv->clearing_selection)
+        return;
+
+    /* The flow box is in single selection mode, so I know this
+     * list will always contain either one item or NULL. */
+    l = gtk_flow_box_get_selected_children (box);
+    priv->selected_avatar_widget = l ? GTK_WIDGET (l->data) : NULL;
+    g_list_free (l);
+
+    priv->clearing_selection = TRUE;
+    for (widget = boxen; *widget != NULL; widget++) {
+        if (*widget == box)
+            continue;
+
+        gtk_flow_box_unselect_all (GTK_FLOW_BOX (*widget));
+    }
+    priv->clearing_selection = FALSE;
+
+    if (priv->selected_avatar_widget) {
+        GtkWidget *child = gtk_bin_get_child (GTK_BIN (priv->selected_avatar_widget));
+        _um_avatar_picker_set_avatar (picker, gtk_image_get_pixbuf (GTK_IMAGE (child)));
+    } else {
+        _um_avatar_picker_set_avatar (picker, NULL);
+    }
+}
+
+static void
+sync_select_sensivitity (UmAvatarPicker *picker)
+{
+    UmAvatarPickerPrivate *priv = um_avatar_picker_get_instance_private (picker);
+    gboolean has_selection = (priv->selected_avatar != NULL);
+
+    gtk_widget_set_sensitive (priv->select_button, has_selection);
+}
+
+static void
+um_avatar_picker_class_init (UmAvatarPickerClass *klass)
+{
+    gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (klass), 
"/org/gnome/control-center/user-accounts/avatar-picker.ui");
+
+    gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), UmAvatarPicker, stack);
+    gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), UmAvatarPicker, avatars_online);
+    gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), UmAvatarPicker, avatars_stock);
+    gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), UmAvatarPicker, select_button);
+}
+
+static void
+um_avatar_picker_init (UmAvatarPicker *picker)
+{
+    UmAvatarPickerPrivate *priv = um_avatar_picker_get_instance_private (picker);
+
+    gtk_window_set_modal (GTK_WINDOW (picker), TRUE);
+
+    gtk_widget_init_template (GTK_WIDGET (picker));
+
+    fill_stock_icons (picker);
+    fill_online_icons (picker);
+
+    g_signal_connect (priv->avatars_online, "selected-children-changed",
+                      G_CALLBACK (selection_changed), picker);
+    g_signal_connect (priv->avatars_stock, "selected-children-changed",
+                      G_CALLBACK (selection_changed), picker);
+
+#ifdef HAVE_CHEESE
+    /* The camera page is disabled until we can get it working better. */
+    gtk_container_add_with_properties (GTK_CONTAINER (priv->stack),
+                                       g_object_new (UM_TYPE_AVATAR_PICKER_CAMERA_PAGE, NULL),
+                                       "name", "camera",
+                                       "title", _("Camera"),
+                                       NULL);
+#endif /* HAVE_CHEESE */
+
+    sync_select_sensivitity (picker);
+}
+
+GdkPixbuf *
+um_avatar_picker_get_avatar (UmAvatarPicker *picker)
+{
+    UmAvatarPickerPrivate *priv = um_avatar_picker_get_instance_private (picker);
+
+    return priv->selected_avatar;
+}
+
+void
+_um_avatar_picker_set_avatar (UmAvatarPicker *picker,
+                              GdkPixbuf      *pixbuf)
+{
+    UmAvatarPickerPrivate *priv = um_avatar_picker_get_instance_private (picker);
+
+    if (priv->selected_avatar)
+        g_object_unref (priv->selected_avatar);
+
+    if (pixbuf)
+        priv->selected_avatar = g_object_ref (pixbuf);
+    else
+        priv->selected_avatar = NULL;
+
+    sync_select_sensivitity (picker);
+}
+
+GtkWidget *
+um_avatar_picker_new (void)
+{
+    return g_object_new (UM_TYPE_AVATAR_PICKER, NULL);
+}
diff --git a/panels/user-accounts/um-avatar-picker.h b/panels/user-accounts/um-avatar-picker.h
new file mode 100644
index 0000000..91807d9
--- /dev/null
+++ b/panels/user-accounts/um-avatar-picker.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * Copyright 2013 Red Hat, Inc,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Written by:
+ *   Jasper St. Pierre <jstpierre mecheye net>
+ *   Bogdan Ciobanu <bgdn ciobanu gmail com>
+ */
+
+#ifndef __UM_AVATAR_PICKER_H__
+#define __UM_AVATAR_PICKER_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define UM_TYPE_AVATAR_PICKER               (um_avatar_picker_get_type ())
+#define UM_AVATAR_PICKER(obj)                           (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
UM_TYPE_AVATAR_PICKER, UmAvatarPicker))
+#define UM_AVATAR_PICKER_CLASS(klass)                   (G_TYPE_CHECK_CLASS_CAST ((klass),  
UM_TYPE_AVATAR_PICKER, UmAvatarPickerClass))
+#define UM_IS_AVATAR_PICKER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UM_TYPE_AVATAR_PICKER))
+#define UM_IS_AVATAR_PICKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  UM_TYPE_AVATAR_PICKER))
+#define UM_AVATAR_PICKER_GET_CLASS(obj)                 (G_TYPE_INSTANCE_GET_CLASS ((obj),  
UM_TYPE_AVATAR_PICKER, UmAvatarPickerClass))
+
+typedef struct _UmAvatarPicker        UmAvatarPicker;
+typedef struct _UmAvatarPickerClass   UmAvatarPickerClass;
+
+struct _UmAvatarPicker
+{
+    GtkDialog parent;
+};
+
+struct _UmAvatarPickerClass
+{
+    GtkDialogClass parent_class;
+};
+
+G_GNUC_CONST GType um_avatar_picker_get_type (void);
+
+GtkWidget *um_avatar_picker_new (void);
+GdkPixbuf *um_avatar_picker_get_avatar (UmAvatarPicker *picker);
+
+G_END_DECLS
+
+#endif /* __UM_AVATAR_PICKER_H__ */
diff --git a/panels/user-accounts/user-accounts-camera.gresource.xml 
b/panels/user-accounts/user-accounts-camera.gresource.xml
new file mode 100644
index 0000000..cb0ed12
--- /dev/null
+++ b/panels/user-accounts/user-accounts-camera.gresource.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+  <gresource prefix="/org/gnome/control-center/user-accounts">
+    <file alias="avatar-picker-camera-page.ui" 
preprocess="xml-stripblanks">data/avatar-picker-camera-page.ui</file>
+  </gresource>
+</gresources>
diff --git a/panels/user-accounts/user-accounts.gresource.xml 
b/panels/user-accounts/user-accounts.gresource.xml
index c8fc11e..5db8c1c 100644
--- a/panels/user-accounts/user-accounts.gresource.xml
+++ b/panels/user-accounts/user-accounts.gresource.xml
@@ -6,6 +6,7 @@
     <file alias="password-dialog.ui" preprocess="xml-stripblanks">data/password-dialog.ui</file>
     <file alias="history-dialog.ui" preprocess="xml-stripblanks">data/history-dialog.ui</file>
     <file alias="user-accounts-dialog.ui" preprocess="xml-stripblanks">data/user-accounts-dialog.ui</file>
+    <file alias="avatar-picker.ui" preprocess="xml-stripblanks">data/avatar-picker.ui</file>
     <file alias="left-index-finger.png">data/icons/left-index-finger.png</file>
     <file alias="left-middle-finger.png">data/icons/left-middle-finger.png</file>
     <file alias="left-little-finger.png">data/icons/left-little-finger.png</file>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]