[gnome-shell/nbtk-introduction: 8/8] Import NbtkEntry, NbtkLabel, NbtkClipboard



commit c60a6a49de9f7676c52e323c48fda33aeb969593
Author: Colin Walters <walters verbum org>
Date:   Thu Sep 10 04:39:27 2009 -0400

    Import NbtkEntry, NbtkLabel, NbtkClipboard
    
    For now this commit introduces an external dependency on clutter-imcontext.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=591245

 configure.ac                    |    2 +-
 src/Makefile-nbtk.am            |    6 +
 src/nbtk/nbtk-clipboard.c       |  367 +++++++++++++++
 src/nbtk/nbtk-clipboard.h       |   94 ++++
 src/nbtk/nbtk-entry.c           |  960 +++++++++++++++++++++++++++++++++++++++
 src/nbtk/nbtk-entry.h           |   88 ++++
 src/nbtk/nbtk-label.c           |  363 +++++++++++++++
 src/nbtk/nbtk-label.h           |   75 +++
 tools/build/gnome-shell.modules |    9 +
 9 files changed, 1963 insertions(+), 1 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index edb9603..b65b117 100644
--- a/configure.ac
+++ b/configure.ac
@@ -57,7 +57,7 @@ PKG_CHECK_MODULES(MUTTER_PLUGIN, gio-unix-2.0 gtk+-2.0 dbus-glib-1 mutter-plugin
                                  gnome-desktop-2.0 >= 2.26 libstartup-notification-1.0
                                  gobject-introspection-1.0 >= 0.6.5)
 PKG_CHECK_MODULES(TIDY, clutter-1.0)
-PKG_CHECK_MODULES(NBTK, clutter-1.0 gtk+-2.0 libccss-1 >= 0.3.1)
+PKG_CHECK_MODULES(NBTK, clutter-1.0 gtk+-2.0 libccss-1 >= 0.3.1 clutter-imcontext-0.1)
 PKG_CHECK_MODULES(BIG, clutter-1.0 gtk+-2.0 librsvg-2.0)
 PKG_CHECK_MODULES(GDMUSER, dbus-glib-1 gtk+-2.0)
 PKG_CHECK_MODULES(TRAY, gtk+-2.0)
diff --git a/src/Makefile-nbtk.am b/src/Makefile-nbtk.am
index b9b6a7d..d08e0b5 100644
--- a/src/Makefile-nbtk.am
+++ b/src/Makefile-nbtk.am
@@ -69,6 +69,9 @@ nbtk_source_h =                  \
     nbtk/nbtk-box-layout.h            \
     nbtk/nbtk-box-layout-child.h      \
     nbtk/nbtk-button.h                \
+    nbtk/nbtk-clipboard.h             \
+    nbtk/nbtk-entry.h                 \
+    nbtk/nbtk-label.h                 \
     nbtk/nbtk-private.h               \
     nbtk/nbtk-scrollable.h            \
     nbtk/nbtk-scroll-bar.h            \
@@ -91,6 +94,9 @@ nbtk_source_c =                  \
     nbtk/nbtk-box-layout.c            \
     nbtk/nbtk-box-layout-child.c      \
     nbtk/nbtk-button.c                \
+    nbtk/nbtk-clipboard.c             \
+    nbtk/nbtk-entry.c                 \
+    nbtk/nbtk-label.c                 \
     nbtk/nbtk-private.c               \
     nbtk/nbtk-scrollable.c            \
     nbtk/nbtk-scroll-bar.c            \
diff --git a/src/nbtk/nbtk-clipboard.c b/src/nbtk/nbtk-clipboard.c
new file mode 100644
index 0000000..f103372
--- /dev/null
+++ b/src/nbtk/nbtk-clipboard.c
@@ -0,0 +1,367 @@
+/*
+ * nbtk-clipboard.c: clipboard object
+ *
+ * Copyright 2009 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by: Thomas Wood <thomas wood intel com>
+ *
+ */
+
+
+#include "nbtk-clipboard.h"
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <clutter/x11/clutter-x11.h>
+#include <string.h>
+
+G_DEFINE_TYPE (NbtkClipboard, nbtk_clipboard, G_TYPE_OBJECT)
+
+#define CLIPBOARD_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), NBTK_TYPE_CLIPBOARD, NbtkClipboardPrivate))
+
+struct _NbtkClipboardPrivate
+{
+  Window clipboard_window;
+  gchar *clipboard_text;
+
+  Atom *supported_targets;
+  gint n_targets;
+};
+
+typedef struct _EventFilterData EventFilterData;
+struct _EventFilterData
+{
+  NbtkClipboard *clipboard;
+  NbtkClipboardCallbackFunc callback;
+  gpointer user_data;
+};
+
+static Atom __atom_clip = None;
+static Atom __utf8_string = None;
+static Atom __atom_targets = None;
+
+static void
+nbtk_clipboard_get_property (GObject *object, guint property_id,
+                              GValue *value, GParamSpec *pspec)
+{
+  switch (property_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+nbtk_clipboard_set_property (GObject *object, guint property_id,
+                              const GValue *value, GParamSpec *pspec)
+{
+  switch (property_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+nbtk_clipboard_dispose (GObject *object)
+{
+  G_OBJECT_CLASS (nbtk_clipboard_parent_class)->dispose (object);
+}
+
+static void
+nbtk_clipboard_finalize (GObject *object)
+{
+  NbtkClipboardPrivate *priv = ((NbtkClipboard *) object)->priv;
+
+  g_free (priv->clipboard_text);
+  priv->clipboard_text = NULL;
+
+  g_free (priv->supported_targets);
+  priv->supported_targets = NULL;
+  priv->n_targets = 0;
+
+  G_OBJECT_CLASS (nbtk_clipboard_parent_class)->finalize (object);
+}
+
+static ClutterX11FilterReturn
+nbtk_clipboard_provider (XEvent        *xev,
+                         ClutterEvent  *cev,
+                         NbtkClipboard *clipboard)
+{
+  XSelectionEvent notify_event;
+  XSelectionRequestEvent *req_event;
+
+  if (xev->type != SelectionRequest)
+    return CLUTTER_X11_FILTER_CONTINUE;
+
+  req_event = &xev->xselectionrequest;
+
+  clutter_x11_trap_x_errors ();
+
+  if (req_event->target == __atom_targets)
+    {
+      XChangeProperty (req_event->display,
+                       req_event->requestor,
+                       req_event->property,
+                       XA_ATOM,
+                       32,
+                       PropModeReplace,
+                       (guchar*) clipboard->priv->supported_targets,
+                       clipboard->priv->n_targets);
+    }
+  else
+    {
+      XChangeProperty (req_event->display,
+                       req_event->requestor,
+                       req_event->property,
+                       req_event->target,
+                       8,
+                       PropModeReplace,
+                       (guchar*) clipboard->priv->clipboard_text,
+                       strlen (clipboard->priv->clipboard_text));
+    }
+
+  notify_event.type = SelectionNotify;
+  notify_event.display = req_event->display;
+  notify_event.requestor = req_event->requestor;
+  notify_event.selection = req_event->selection;
+  notify_event.target = req_event->target;
+  notify_event.time = req_event->time;
+
+  if (req_event->property == None)
+    notify_event.property = req_event->target;
+  else
+    notify_event.property = req_event->property;
+
+  /* notify the requestor that they have a copy of the selection */
+  XSendEvent (req_event->display, req_event->requestor, False, 0,
+              (XEvent *) &notify_event);
+  /* Make it happen non async */
+  XSync (clutter_x11_get_default_display(), FALSE);
+
+  clutter_x11_untrap_x_errors (); /* FIXME: Warn here on fail ? */
+
+  return CLUTTER_X11_FILTER_REMOVE;
+}
+
+
+static void
+nbtk_clipboard_class_init (NbtkClipboardClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (NbtkClipboardPrivate));
+
+  object_class->get_property = nbtk_clipboard_get_property;
+  object_class->set_property = nbtk_clipboard_set_property;
+  object_class->dispose = nbtk_clipboard_dispose;
+  object_class->finalize = nbtk_clipboard_finalize;
+}
+
+static void
+nbtk_clipboard_init (NbtkClipboard *self)
+{
+  Display *dpy;
+  NbtkClipboardPrivate *priv;
+
+  priv = self->priv = CLIPBOARD_PRIVATE (self);
+
+  priv->clipboard_window =
+    XCreateSimpleWindow (clutter_x11_get_default_display (),
+                         clutter_x11_get_root_window (),
+                         -1, -1, 1, 1, 0, 0, 0);
+
+  dpy = clutter_x11_get_default_display ();
+
+  /* Only create once */
+  if (__atom_clip == None)
+    __atom_clip = XInternAtom (dpy, "CLIPBOARD", 0);
+
+  if (__utf8_string == None)
+    __utf8_string = XInternAtom (dpy, "UTF8_STRING", 0);
+
+  if (__atom_targets == None)
+    __atom_targets = XInternAtom (dpy, "TARGETS", 0);
+
+  priv->n_targets = 2;
+  priv->supported_targets = g_new (Atom, priv->n_targets);
+
+  priv->supported_targets[0] = __utf8_string;
+  priv->supported_targets[1] = __atom_targets;
+
+  clutter_x11_add_filter ((ClutterX11FilterFunc) nbtk_clipboard_provider,
+                          self);
+}
+
+static ClutterX11FilterReturn
+nbtk_clipboard_x11_event_filter (XEvent          *xev,
+                                 ClutterEvent    *cev,
+                                 EventFilterData *filter_data)
+{
+  Atom actual_type;
+  int actual_format, result;
+  unsigned long nitems, bytes_after;
+  unsigned char *data = NULL;
+
+  if(xev->type != SelectionNotify)
+    return CLUTTER_X11_FILTER_CONTINUE;
+
+  if (xev->xselection.property == None)
+    {
+      /* clipboard empty */
+      filter_data->callback (filter_data->clipboard,
+                             NULL,
+                             filter_data->user_data);
+
+      clutter_x11_remove_filter ((ClutterX11FilterFunc) nbtk_clipboard_x11_event_filter,
+                                 filter_data);
+      g_free (filter_data);
+      return CLUTTER_X11_FILTER_REMOVE;
+    }
+
+  clutter_x11_trap_x_errors ();
+
+  result = XGetWindowProperty (xev->xselection.display,
+                               xev->xselection.requestor,
+                               xev->xselection.property,
+                               0L, G_MAXINT,
+                               True,
+                               AnyPropertyType,
+                               &actual_type,
+                               &actual_format,
+                               &nitems,
+                               &bytes_after,
+                               &data);
+
+  if (clutter_x11_untrap_x_errors () || result != Success)
+    {
+      /* FIXME: handle failure better */
+      g_warning ("Clipboard: prop retrival failed");
+    }
+
+  filter_data->callback (filter_data->clipboard, (char*) data,
+                         filter_data->user_data);
+
+  clutter_x11_remove_filter
+                    ((ClutterX11FilterFunc) nbtk_clipboard_x11_event_filter,
+                     filter_data);
+
+  g_free (filter_data);
+
+  if (data)
+    XFree (data);
+
+  return CLUTTER_X11_FILTER_REMOVE;
+}
+
+/**
+ * nbtk_clipboard_get_default:
+ *
+ * Get the global #NbtkClipboard object that represents the clipboard.
+ *
+ * Returns: a #NbtkClipboard owned by Nbtk and must not be unrefferenced or
+ * freed.
+ */
+NbtkClipboard*
+nbtk_clipboard_get_default ()
+{
+  static NbtkClipboard *default_clipboard = NULL;
+
+  if (!default_clipboard)
+    {
+      default_clipboard = g_object_new (NBTK_TYPE_CLIPBOARD, NULL);
+    }
+
+  return default_clipboard;
+}
+
+/**
+ * nbtk_clipboard_get_text:
+ * @clipboard: A #NbtkCliboard
+ * @callback: function to be called when the text is retreived
+ * @user_data: data to be passed to the callback
+ *
+ * Request the data from the clipboard in text form. @callback is executed
+ * when the data is retreived.
+ *
+ */
+void
+nbtk_clipboard_get_text (NbtkClipboard             *clipboard,
+                         NbtkClipboardCallbackFunc  callback,
+                         gpointer                   user_data)
+{
+  EventFilterData *data;
+
+  Display *dpy;
+
+  g_return_if_fail (NBTK_IS_CLIPBOARD (clipboard));
+  g_return_if_fail (callback != NULL);
+
+  data = g_new0 (EventFilterData, 1);
+  data->clipboard = clipboard;
+  data->callback = callback;
+  data->user_data = user_data;
+
+  clutter_x11_add_filter ((ClutterX11FilterFunc)nbtk_clipboard_x11_event_filter,
+                          data);
+
+  dpy = clutter_x11_get_default_display ();
+
+  clutter_x11_trap_x_errors (); /* safety on */
+
+  XConvertSelection (dpy,
+                     __atom_clip,
+                     __utf8_string, __utf8_string,
+                     clipboard->priv->clipboard_window,
+                     CurrentTime);
+
+  clutter_x11_untrap_x_errors ();
+}
+
+/**
+ * nbtk_clipboard_set_text:
+ * @clipboard: A #NbtkClipboard
+ * @text: text to copy to the clipboard
+ *
+ * Sets text as the current contents of the clipboard.
+ *
+ */
+void
+nbtk_clipboard_set_text (NbtkClipboard *clipboard,
+                         const gchar   *text)
+{
+  NbtkClipboardPrivate *priv;
+  Display *dpy;
+
+  g_return_if_fail (NBTK_IS_CLIPBOARD (clipboard));
+  g_return_if_fail (text != NULL);
+
+  priv = clipboard->priv;
+
+  /* make a copy of the text */
+  g_free (priv->clipboard_text);
+  priv->clipboard_text = g_strdup (text);
+
+  /* tell X we own the clipboard selection */
+  dpy = clutter_x11_get_default_display ();
+
+  clutter_x11_trap_x_errors ();
+
+  XSetSelectionOwner (dpy, __atom_clip, priv->clipboard_window, CurrentTime);
+  XSync (dpy, FALSE);
+
+  clutter_x11_untrap_x_errors ();
+}
diff --git a/src/nbtk/nbtk-clipboard.h b/src/nbtk/nbtk-clipboard.h
new file mode 100644
index 0000000..7592548
--- /dev/null
+++ b/src/nbtk/nbtk-clipboard.h
@@ -0,0 +1,94 @@
+/*
+ * nbtk-clipboard.h: clipboard object
+ *
+ * Copyright 2009 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by: Thomas Wood <thomas wood intel com>
+ *
+ */
+
+#ifndef _NBTK_CLIPBOARD_H
+#define _NBTK_CLIPBOARD_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define NBTK_TYPE_CLIPBOARD nbtk_clipboard_get_type()
+
+#define NBTK_CLIPBOARD(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+  NBTK_TYPE_CLIPBOARD, NbtkClipboard))
+
+#define NBTK_CLIPBOARD_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+  NBTK_TYPE_CLIPBOARD, NbtkClipboardClass))
+
+#define NBTK_IS_CLIPBOARD(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+  NBTK_TYPE_CLIPBOARD))
+
+#define NBTK_IS_CLIPBOARD_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+  NBTK_TYPE_CLIPBOARD))
+
+#define NBTK_CLIPBOARD_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+  NBTK_TYPE_CLIPBOARD, NbtkClipboardClass))
+
+typedef struct _NbtkClipboard NbtkClipboard;
+typedef struct _NbtkClipboardClass NbtkClipboardClass;
+typedef struct _NbtkClipboardPrivate NbtkClipboardPrivate;
+
+/**
+ * NbtkClipboard:
+ *
+ * The contents of this structure is private and should only be accessed using
+ * the provided API.
+ */
+struct _NbtkClipboard
+{
+  /*< private >*/
+  GObject parent;
+  NbtkClipboardPrivate *priv;
+};
+
+struct _NbtkClipboardClass
+{
+  GObjectClass parent_class;
+};
+
+/**
+ * NbtkClipboardCallbackFunc:
+ * @clipboard: A #NbtkClipboard
+ * @text: text from the clipboard
+ * @user_data: user data
+ *
+ * Callback function called when text is retrieved from the clipboard.
+ */
+typedef void (*NbtkClipboardCallbackFunc) (NbtkClipboard *clipboard,
+                                           const gchar   *text,
+                                           gpointer       user_data);
+
+GType nbtk_clipboard_get_type (void);
+
+NbtkClipboard* nbtk_clipboard_get_default ();
+void nbtk_clipboard_get_text (NbtkClipboard *clipboard, NbtkClipboardCallbackFunc callback, gpointer user_data);
+void nbtk_clipboard_set_text (NbtkClipboard *clipboard, const gchar *text);
+
+G_END_DECLS
+
+#endif /* _NBTK_CLIPBOARD_H */
diff --git a/src/nbtk/nbtk-entry.c b/src/nbtk/nbtk-entry.c
new file mode 100644
index 0000000..9cc762a
--- /dev/null
+++ b/src/nbtk/nbtk-entry.c
@@ -0,0 +1,960 @@
+/*
+ * nbtk-entry.c: Plain entry actor
+ *
+ * Copyright 2008, 2009 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by: Thomas Wood <thomas wood intel com>
+ *
+ */
+
+/**
+ * SECTION:nbtk-entry
+ * @short_description: Widget for displaying text
+ *
+ * #NbtkEntry is a simple widget for displaying text. It derives from
+ * #NbtkWidget to add extra style and placement functionality over
+ * #ClutterText. The internal #ClutterText is publicly accessibly to allow
+ * applications to set further properties.
+ *
+ * #NbtkEntry supports the following pseudo style states:
+ * <itemizedlist>
+ *  <listitem>
+ *   <para>focus: the widget has focus</para>
+ *  </listitem>
+ *  <listitem>
+ *   <para>indeterminate: the widget is showing the hint text</para>
+ *  </listitem>
+ * </itemizedlist>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <clutter/clutter.h>
+#include <clutter-imcontext/clutter-imtext.h>
+
+#include "nbtk-entry.h"
+
+#include "nbtk-widget.h"
+#include "nbtk-stylable.h"
+#include "nbtk-texture-cache.h"
+#include "nbtk-marshal.h"
+#include "nbtk-clipboard.h"
+
+#define HAS_FOCUS(actor) (clutter_actor_get_stage (actor) && clutter_stage_get_key_focus ((ClutterStage *) clutter_actor_get_stage (actor)) == actor)
+
+
+/* properties */
+enum
+{
+  PROP_0,
+
+  PROP_ENTRY,
+  PROP_HINT
+};
+
+/* signals */
+enum
+{
+  PRIMARY_ICON_CLICKED,
+  SECONDARY_ICON_CLICKED,
+
+  LAST_SIGNAL
+};
+
+#define NBTK_ENTRY_GET_PRIVATE(obj)     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NBTK_TYPE_ENTRY, NbtkEntryPrivate))
+#define NBTK_ENTRY_PRIV(x) ((NbtkEntry *) x)->priv
+
+
+struct _NbtkEntryPrivate
+{
+  ClutterActor *entry;
+  gchar        *hint;
+
+  ClutterActor *primary_icon;
+  ClutterActor *secondary_icon;
+
+  gfloat   spacing;
+};
+
+static guint entry_signals[LAST_SIGNAL] = { 0, };
+
+static void nbtk_stylable_iface_init (NbtkStylableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (NbtkEntry, nbtk_entry, NBTK_TYPE_WIDGET,
+                         G_IMPLEMENT_INTERFACE (NBTK_TYPE_STYLABLE,
+                                                nbtk_stylable_iface_init));
+
+static void
+nbtk_entry_set_property (GObject      *gobject,
+                         guint         prop_id,
+                         const GValue *value,
+                         GParamSpec   *pspec)
+{
+  NbtkEntry *entry = NBTK_ENTRY (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_ENTRY:
+      nbtk_entry_set_text (entry, g_value_get_string (value));
+      break;
+
+    case PROP_HINT:
+      nbtk_entry_set_hint_text (entry, g_value_get_string (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+nbtk_entry_get_property (GObject    *gobject,
+                         guint       prop_id,
+                         GValue     *value,
+                         GParamSpec *pspec)
+{
+  NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_ENTRY:
+      g_value_set_string (value, clutter_text_get_text (CLUTTER_TEXT (priv->entry)));
+      break;
+
+    case PROP_HINT:
+      g_value_set_string (value, priv->hint);
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+nbtk_entry_dispose (GObject *object)
+{
+  NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (object);
+
+  if (priv->entry)
+    {
+      clutter_actor_unparent (priv->entry);
+      priv->entry = NULL;
+    }
+}
+
+static void
+nbtk_entry_finalize (GObject *object)
+{
+  NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (object);
+
+  g_free (priv->hint);
+  priv->hint = NULL;
+}
+
+static void
+nbtk_stylable_iface_init (NbtkStylableIface *iface)
+{
+  static gboolean is_initialized = FALSE;
+
+  if (!is_initialized)
+    {
+      GParamSpec *pspec;
+      static const ClutterColor default_color
+        = { 0x0, 0x9c, 0xcf, 0xff };
+
+      is_initialized = TRUE;
+
+      pspec = clutter_param_spec_color ("caret-color",
+                                        "Caret Color",
+                                        "Color of the entry's caret",
+                                        &default_color,
+                                        G_PARAM_READWRITE);
+      nbtk_stylable_iface_install_property (iface, NBTK_TYPE_ENTRY, pspec);
+
+      pspec = clutter_param_spec_color ("selection-background-color",
+                                        "Selection Background Color",
+                                        "Color of the entry's selection",
+                                        &default_color,
+                                        G_PARAM_READWRITE);
+      nbtk_stylable_iface_install_property (iface, NBTK_TYPE_ENTRY, pspec);
+    }
+}
+
+static void
+nbtk_entry_style_changed (NbtkWidget *self)
+{
+  NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (self);
+  ClutterColor *color = NULL;
+  ClutterColor *caret_color = NULL;
+  ClutterColor *selection_background_color = NULL;
+  gchar *font_name;
+  gchar *font_string;
+  gint font_size;
+
+  nbtk_stylable_get (NBTK_STYLABLE (self),
+                     "color", &color,
+                     "caret-color", &caret_color,
+                     "selection-background-color", &selection_background_color,
+                     "font-family", &font_name,
+                     "font-size", &font_size,
+                     NULL);
+
+  if (color)
+    {
+      clutter_text_set_color (CLUTTER_TEXT (priv->entry), color);
+      clutter_color_free (color);
+    }
+
+  if (caret_color)
+    {
+      clutter_text_set_cursor_color (CLUTTER_TEXT (priv->entry), caret_color);
+      clutter_color_free (caret_color);
+    }
+
+  if (selection_background_color)
+    {
+      clutter_text_set_selection_color (CLUTTER_TEXT (priv->entry),
+                                        selection_background_color);
+      clutter_color_free (selection_background_color);
+    }
+
+  if (font_name || font_size)
+    {
+      if (font_name && font_size)
+        {
+          font_string = g_strdup_printf ("%s %dpx", font_name, font_size);
+          g_free (font_name);
+        }
+      else
+        {
+          if (font_size)
+            font_string = g_strdup_printf ("%dpx", font_size);
+          else
+            font_string = font_name;
+        }
+
+      clutter_text_set_font_name (CLUTTER_TEXT (priv->entry), font_string);
+      g_free (font_string);
+    }
+}
+
+static void
+nbtk_entry_get_preferred_width (ClutterActor *actor,
+                                gfloat   for_height,
+                                gfloat  *min_width_p,
+                                gfloat  *natural_width_p)
+{
+  NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (actor);
+  NbtkPadding padding;
+  gfloat icon_w;
+
+  nbtk_widget_get_padding (NBTK_WIDGET (actor), &padding);
+
+  for_height -= padding.top + padding.bottom;
+
+  clutter_actor_get_preferred_width (priv->entry, for_height,
+                                     min_width_p,
+                                     natural_width_p);
+
+  if (priv->primary_icon)
+    {
+      clutter_actor_get_preferred_width (priv->primary_icon, -1, NULL, &icon_w);
+
+      if (min_width_p)
+        *min_width_p += icon_w + priv->spacing;
+
+      if (natural_width_p)
+        *natural_width_p += icon_w + priv->spacing;
+    }
+
+  if (priv->secondary_icon)
+    {
+      clutter_actor_get_preferred_width (priv->secondary_icon,
+                                         -1, NULL, &icon_w);
+
+      if (min_width_p)
+        *min_width_p += icon_w + priv->spacing;
+
+      if (natural_width_p)
+        *natural_width_p += icon_w + priv->spacing;
+    }
+
+  if (min_width_p)
+    *min_width_p += padding.left + padding.right;
+
+  if (natural_width_p)
+    *natural_width_p += padding.left + padding.right;
+}
+
+static void
+nbtk_entry_get_preferred_height (ClutterActor *actor,
+                                 gfloat   for_width,
+                                 gfloat  *min_height_p,
+                                 gfloat  *natural_height_p)
+{
+  NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (actor);
+  NbtkPadding padding;
+  gfloat icon_h;
+
+  nbtk_widget_get_padding (NBTK_WIDGET (actor), &padding);
+
+  for_width -= padding.left + padding.right;
+
+  clutter_actor_get_preferred_height (priv->entry, for_width,
+                                      min_height_p,
+                                      natural_height_p);
+
+  if (priv->primary_icon)
+    {
+      clutter_actor_get_preferred_height (priv->primary_icon,
+                                          -1, NULL, &icon_h);
+
+      if (min_height_p && icon_h > *min_height_p)
+        *min_height_p = icon_h;
+
+      if (natural_height_p && icon_h > *natural_height_p)
+        *natural_height_p = icon_h;
+    }
+
+  if (priv->secondary_icon)
+    {
+      clutter_actor_get_preferred_height (priv->secondary_icon,
+                                          -1, NULL, &icon_h);
+
+      if (min_height_p && icon_h > *min_height_p)
+        *min_height_p = icon_h;
+
+      if (natural_height_p && icon_h > *natural_height_p)
+        *natural_height_p = icon_h;
+    }
+
+  if (min_height_p)
+    *min_height_p += padding.top + padding.bottom;
+
+  if (natural_height_p)
+    *natural_height_p += padding.top + padding.bottom;
+}
+
+static void
+nbtk_entry_allocate (ClutterActor          *actor,
+                     const ClutterActorBox *box,
+                     ClutterAllocationFlags flags)
+{
+  NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (actor);
+  ClutterActorClass *parent_class;
+  ClutterActorBox child_box, icon_box;
+  NbtkPadding padding;
+  gfloat icon_w, icon_h;
+  gfloat entry_h, min_h, pref_h, avail_h;
+
+  nbtk_widget_get_padding (NBTK_WIDGET (actor), &padding);
+
+  parent_class = CLUTTER_ACTOR_CLASS (nbtk_entry_parent_class);
+  parent_class->allocate (actor, box, flags);
+
+  avail_h = (box->y2 - box->y1) - padding.top - padding.bottom;
+
+  child_box.x1 = padding.left;
+  child_box.x2 = box->x2 - box->x1 - padding.right;
+
+  if (priv->primary_icon)
+    {
+      clutter_actor_get_preferred_width (priv->primary_icon,
+                                         -1, NULL, &icon_w);
+      clutter_actor_get_preferred_height (priv->primary_icon,
+                                          -1, NULL, &icon_h);
+
+      icon_box.x1 = padding.left;
+      icon_box.x2 = icon_box.x1 + icon_w;
+
+      icon_box.y1 = (int) (padding.top + avail_h / 2 - icon_h / 2);
+      icon_box.y2 = icon_box.y1 + icon_h;
+
+      clutter_actor_allocate (priv->primary_icon,
+                              &icon_box,
+                              flags);
+
+      /* reduce the size for the entry */
+      child_box.x1 += icon_w + priv->spacing;
+    }
+
+  if (priv->secondary_icon)
+    {
+      clutter_actor_get_preferred_width (priv->secondary_icon,
+                                         -1, NULL, &icon_w);
+      clutter_actor_get_preferred_height (priv->secondary_icon,
+                                          -1, NULL, &icon_h);
+
+      icon_box.x2 = (box->x2 - box->x1) - padding.right;
+      icon_box.x1 = icon_box.x2 - icon_w;
+
+      icon_box.y1 = (int) (padding.top + avail_h / 2 - icon_h / 2);
+      icon_box.y2 = icon_box.y1 + icon_h;
+
+      clutter_actor_allocate (priv->secondary_icon,
+                              &icon_box,
+                              flags);
+
+      /* reduce the size for the entry */
+      child_box.x2 -= icon_w - priv->spacing;
+    }
+
+  clutter_actor_get_preferred_height (priv->entry, child_box.x2 - child_box.x1,
+                                      &min_h, &pref_h);
+
+  entry_h = CLAMP (pref_h, min_h, avail_h);
+
+  child_box.y1 = (int) (padding.top + avail_h / 2 - entry_h / 2);
+  child_box.y2 = child_box.y1 + entry_h;
+
+  clutter_actor_allocate (priv->entry, &child_box, flags);
+}
+
+static void
+clutter_text_focus_in_cb (ClutterText *text,
+                          ClutterActor *actor)
+{
+  NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (actor);
+
+  /* remove the hint if visible */
+  if (priv->hint
+      && !strcmp (clutter_text_get_text (text), priv->hint))
+    {
+      clutter_text_set_text (text, "");
+    }
+  nbtk_widget_set_style_pseudo_class (NBTK_WIDGET (actor), "focus");
+  clutter_text_set_cursor_visible (text, TRUE);
+}
+
+static void
+clutter_text_focus_out_cb (ClutterText  *text,
+                           ClutterActor *actor)
+{
+  NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (actor);
+
+  /* add a hint if the entry is empty */
+  if (priv->hint && !strcmp (clutter_text_get_text (text), ""))
+    {
+      clutter_text_set_text (text, priv->hint);
+      nbtk_widget_set_style_pseudo_class (NBTK_WIDGET (actor), "indeterminate");
+    }
+  else
+    {
+      nbtk_widget_set_style_pseudo_class (NBTK_WIDGET (actor), NULL);
+    }
+  clutter_text_set_cursor_visible (text, FALSE);
+}
+
+static void
+nbtk_entry_paint (ClutterActor *actor)
+{
+  NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (actor);
+  ClutterActorClass *parent_class;
+
+  parent_class = CLUTTER_ACTOR_CLASS (nbtk_entry_parent_class);
+  parent_class->paint (actor);
+
+  clutter_actor_paint (priv->entry);
+
+  if (priv->primary_icon)
+    clutter_actor_paint (priv->primary_icon);
+
+  if (priv->secondary_icon)
+    clutter_actor_paint (priv->secondary_icon);
+}
+
+static void
+nbtk_entry_pick (ClutterActor *actor,
+                 const ClutterColor *c)
+{
+  NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (actor);
+
+  CLUTTER_ACTOR_CLASS (nbtk_entry_parent_class)->pick (actor, c);
+
+  clutter_actor_paint (priv->entry);
+
+  if (priv->primary_icon)
+    clutter_actor_paint (priv->primary_icon);
+
+  if (priv->secondary_icon)
+    clutter_actor_paint (priv->secondary_icon);
+}
+
+static void
+nbtk_entry_map (ClutterActor *actor)
+{
+  NbtkEntryPrivate *priv = NBTK_ENTRY (actor)->priv;
+
+  CLUTTER_ACTOR_CLASS (nbtk_entry_parent_class)->map (actor);
+
+  clutter_actor_map (priv->entry);
+
+  if (priv->primary_icon)
+    clutter_actor_map (priv->primary_icon);
+
+  if (priv->secondary_icon)
+    clutter_actor_map (priv->secondary_icon);
+}
+
+static void
+nbtk_entry_unmap (ClutterActor *actor)
+{
+  NbtkEntryPrivate *priv = NBTK_ENTRY (actor)->priv;
+
+  CLUTTER_ACTOR_CLASS (nbtk_entry_parent_class)->unmap (actor);
+
+  clutter_actor_unmap (priv->entry);
+
+  if (priv->primary_icon)
+    clutter_actor_unmap (priv->primary_icon);
+
+  if (priv->secondary_icon)
+    clutter_actor_unmap (priv->secondary_icon);
+}
+
+static void
+nbtk_entry_clipboard_callback (NbtkClipboard *clipboard,
+                               const gchar   *text,
+                               gpointer       data)
+{
+  ClutterText *ctext = (ClutterText*) ((NbtkEntry *) data)->priv->entry;
+  gint cursor_pos;
+
+  if (!text)
+    return;
+
+  /* delete the current selection before pasting */
+  clutter_text_delete_selection (ctext);
+
+  /* "paste" the clipboard text into the entry */
+  cursor_pos = clutter_text_get_cursor_position (ctext);
+  clutter_text_insert_text (ctext, text, cursor_pos);
+}
+
+static gboolean
+nbtk_entry_key_press_event (ClutterActor    *actor,
+                            ClutterKeyEvent *event)
+{
+  NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (actor);
+
+  /* This is expected to handle events that were emitted for the inner
+     ClutterText. They only reach this function if the ClutterText
+     didn't handle them */
+
+  /* paste */
+  if ((event->modifier_state & CLUTTER_CONTROL_MASK)
+      && event->keyval == CLUTTER_v)
+    {
+      NbtkClipboard *clipboard;
+
+      clipboard = nbtk_clipboard_get_default ();
+
+      nbtk_clipboard_get_text (clipboard, nbtk_entry_clipboard_callback, actor);
+
+      return TRUE;
+    }
+
+  /* copy */
+  if ((event->modifier_state & CLUTTER_CONTROL_MASK)
+      && event->keyval == CLUTTER_c)
+    {
+      NbtkClipboard *clipboard;
+      gchar *text;
+
+      clipboard = nbtk_clipboard_get_default ();
+
+      text = clutter_text_get_selection ((ClutterText*) priv->entry);
+
+      if (text && strlen (text))
+        nbtk_clipboard_set_text (clipboard, text);
+
+      return TRUE;
+    }
+
+
+  /* cut */
+  if ((event->modifier_state & CLUTTER_CONTROL_MASK)
+      && event->keyval == CLUTTER_x)
+    {
+      NbtkClipboard *clipboard;
+      gchar *text;
+
+      clipboard = nbtk_clipboard_get_default ();
+
+      text = clutter_text_get_selection ((ClutterText*) priv->entry);
+
+      if (text && strlen (text))
+        {
+          nbtk_clipboard_set_text (clipboard, text);
+
+          /* now delete the text */
+          clutter_text_delete_selection ((ClutterText *) priv->entry);
+        }
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static void
+nbtk_entry_key_focus_in (ClutterActor *actor)
+{
+  NbtkEntryPrivate *priv = NBTK_ENTRY_PRIV (actor);
+
+  /* We never want key focus. The ClutterText should be given first
+     pass for all key events */
+  clutter_actor_grab_key_focus (priv->entry);
+}
+
+static void
+nbtk_entry_class_init (NbtkEntryClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+  GParamSpec *pspec;
+
+  g_type_class_add_private (klass, sizeof (NbtkEntryPrivate));
+
+  gobject_class->set_property = nbtk_entry_set_property;
+  gobject_class->get_property = nbtk_entry_get_property;
+  gobject_class->finalize = nbtk_entry_finalize;
+  gobject_class->dispose = nbtk_entry_dispose;
+
+  actor_class->get_preferred_width = nbtk_entry_get_preferred_width;
+  actor_class->get_preferred_height = nbtk_entry_get_preferred_height;
+  actor_class->allocate = nbtk_entry_allocate;
+  actor_class->paint = nbtk_entry_paint;
+  actor_class->pick = nbtk_entry_pick;
+  actor_class->map = nbtk_entry_map;
+  actor_class->unmap = nbtk_entry_unmap;
+
+  actor_class->key_press_event = nbtk_entry_key_press_event;
+  actor_class->key_focus_in = nbtk_entry_key_focus_in;
+
+  pspec = g_param_spec_string ("text",
+                               "Text",
+                               "Text of the entry",
+                               NULL, G_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class, PROP_ENTRY, pspec);
+
+  pspec = g_param_spec_string ("hint-text",
+                               "Hint Text",
+                               "Text to display when the entry is not focused "
+                               "and the text property is empty",
+                               NULL, G_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class, PROP_ENTRY, pspec);
+
+  /* signals */
+  /**
+   * NbtkEntry::primary-icon-clicked:
+   *
+   * Emitted when the primary icon is clicked
+   */
+  entry_signals[PRIMARY_ICON_CLICKED] =
+    g_signal_new ("primary-icon-clicked",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (NbtkEntryClass, primary_icon_clicked),
+                  NULL, NULL,
+                  _nbtk_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+  /**
+   * NbtkEntry::secondary-icon-clicked:
+   *
+   * Emitted when the secondary icon is clicked
+   */
+  entry_signals[SECONDARY_ICON_CLICKED] =
+    g_signal_new ("secondary-icon-clicked",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (NbtkEntryClass, secondary_icon_clicked),
+                  NULL, NULL,
+                  _nbtk_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+}
+
+static void
+nbtk_entry_init (NbtkEntry *entry)
+{
+  NbtkEntryPrivate *priv;
+
+  priv = entry->priv = NBTK_ENTRY_GET_PRIVATE (entry);
+
+  priv->entry = g_object_new (CLUTTER_TYPE_IMTEXT,
+                              "line-alignment", PANGO_ALIGN_LEFT,
+                              "editable", TRUE,
+                              "reactive", TRUE,
+                              "single-line-mode", TRUE,
+                              NULL);
+
+  g_signal_connect (priv->entry, "key-focus-in",
+                    G_CALLBACK (clutter_text_focus_in_cb), entry);
+
+  g_signal_connect (priv->entry, "key-focus-out",
+                    G_CALLBACK (clutter_text_focus_out_cb), entry);
+
+  priv->spacing = 6.0f;
+
+  clutter_actor_set_parent (priv->entry, CLUTTER_ACTOR (entry));
+  clutter_actor_set_reactive ((ClutterActor *) entry, TRUE);
+
+  /* set cursor hidden until we receive focus */
+  clutter_text_set_cursor_visible ((ClutterText *) priv->entry, FALSE);
+
+  g_signal_connect (entry, "style-changed",
+                    G_CALLBACK (nbtk_entry_style_changed), NULL);
+}
+
+/**
+ * nbtk_entry_new:
+ * @text: text to set the entry to
+ *
+ * Create a new #NbtkEntry with the specified entry
+ *
+ * Returns: a new #NbtkEntry
+ */
+NbtkWidget *
+nbtk_entry_new (const gchar *text)
+{
+  NbtkWidget *entry;
+
+  /* add the entry to the stage, but don't allow it to be visible */
+  entry = g_object_new (NBTK_TYPE_ENTRY,
+                        "text", text,
+                        NULL);
+
+  return entry;
+}
+
+/**
+ * nbtk_entry_get_text:
+ * @entry: a #NbtkEntry
+ *
+ * Get the text displayed on the entry
+ *
+ * Returns: the text for the entry. This must not be freed by the application
+ */
+G_CONST_RETURN gchar *
+nbtk_entry_get_text (NbtkEntry *entry)
+{
+  g_return_val_if_fail (NBTK_IS_ENTRY (entry), NULL);
+
+  return clutter_text_get_text (CLUTTER_TEXT (entry->priv->entry));
+}
+
+/**
+ * nbtk_entry_set_text:
+ * @entry: a #NbtkEntry
+ * @text: text to set the entry to
+ *
+ * Sets the text displayed on the entry
+ */
+void
+nbtk_entry_set_text (NbtkEntry *entry,
+                     const gchar *text)
+{
+  NbtkEntryPrivate *priv;
+
+  g_return_if_fail (NBTK_IS_ENTRY (entry));
+
+  priv = entry->priv;
+
+  /* set a hint if we are blanking the entry */
+  if (priv->hint
+      && text && !strcmp ("", text)
+      && !HAS_FOCUS (priv->entry))
+    {
+      text = priv->hint;
+      nbtk_widget_set_style_pseudo_class (NBTK_WIDGET (entry), "indeterminate");
+    }
+  else
+    {
+      if (HAS_FOCUS (priv->entry))
+        nbtk_widget_set_style_pseudo_class (NBTK_WIDGET (entry), "focus");
+      else
+        nbtk_widget_set_style_pseudo_class (NBTK_WIDGET (entry), NULL);
+    }
+
+  clutter_text_set_text (CLUTTER_TEXT (priv->entry), text);
+
+  g_object_notify (G_OBJECT (entry), "text");
+}
+
+/**
+ * nbtk_entry_get_clutter_text:
+ * @entry: a #NbtkEntry
+ *
+ * Retrieve the internal #ClutterText so that extra parameters can be set
+ *
+ * Returns: the #ClutterText used by #NbtkEntry. The entry is owned by the
+ * #NbtkEntry and should not be unref'ed by the application.
+ */
+ClutterActor*
+nbtk_entry_get_clutter_text (NbtkEntry *entry)
+{
+  g_return_val_if_fail (NBTK_ENTRY (entry), NULL);
+
+  return entry->priv->entry;
+}
+
+/**
+ * nbtk_entry_set_hint_text:
+ * @entry: a #NbtkEntry
+ * @text: text to set as the entry hint
+ *
+ * Sets the text to display when the entry is empty and unfocused. When the
+ * entry is displaying the hint, it has a pseudo class of "indeterminate".
+ * A value of NULL unsets the hint.
+ */
+void
+nbtk_entry_set_hint_text (NbtkEntry *entry,
+                          const gchar *text)
+{
+  NbtkEntryPrivate *priv;
+
+  g_return_if_fail (NBTK_IS_ENTRY (entry));
+
+  priv = entry->priv;
+
+  g_free (priv->hint);
+
+  priv->hint = g_strdup (text);
+
+  if (!strcmp (clutter_text_get_text (CLUTTER_TEXT (priv->entry)), ""))
+    {
+      clutter_text_set_text (CLUTTER_TEXT (priv->entry), priv->hint);
+      nbtk_widget_set_style_pseudo_class (NBTK_WIDGET (entry), "indeterminate");
+    }
+}
+
+/**
+ * nbtk_entry_get_hint_text:
+ * @entry: a #NbtkEntry
+ *
+ * Gets the text that is displayed when the entry is empty and unfocused
+ *
+ * Returns: the current value of the hint property. This string is owned by the
+ * #NbtkEntry and should not be freed or modified.
+ */
+G_CONST_RETURN
+gchar *
+nbtk_entry_get_hint_text (NbtkEntry *entry)
+{
+  g_return_val_if_fail (NBTK_IS_ENTRY (entry), NULL);
+
+  return entry->priv->hint;
+}
+
+static gboolean
+_nbtk_entry_icon_press_cb (ClutterActor       *actor,
+                           ClutterButtonEvent *event,
+                           NbtkEntry          *entry)
+{
+  NbtkEntryPrivate *priv = entry->priv;
+
+  if (actor == priv->primary_icon)
+    g_signal_emit (entry, entry_signals[PRIMARY_ICON_CLICKED], 0);
+  else
+    g_signal_emit (entry, entry_signals[SECONDARY_ICON_CLICKED], 0);
+
+  return FALSE;
+}
+
+static void
+_nbtk_entry_set_icon_from_file (NbtkEntry     *entry,
+                                ClutterActor **icon,
+                                const gchar   *filename)
+{
+  if (*icon)
+    {
+      g_signal_handlers_disconnect_by_func (*icon,
+                                            _nbtk_entry_icon_press_cb,
+                                            entry);
+      clutter_actor_unparent (*icon);
+      *icon = NULL;
+    }
+
+  if (filename)
+    {
+      NbtkTextureCache *cache;
+
+      cache = nbtk_texture_cache_get_default ();
+
+
+
+      *icon = (ClutterActor*) nbtk_texture_cache_get_texture (cache, filename, FALSE);
+
+      clutter_actor_set_reactive (*icon, TRUE);
+      clutter_actor_set_parent (*icon, CLUTTER_ACTOR (entry));
+      g_signal_connect (*icon, "button-release-event",
+                        G_CALLBACK (_nbtk_entry_icon_press_cb), entry);
+    }
+
+  clutter_actor_queue_relayout (CLUTTER_ACTOR (entry));
+}
+
+/**
+ * nbtk_entry_set_primary_icon_from_file:
+ * @entry: a #NbtkEntry
+ * @filename: filename of an icon
+ *
+ * Set the primary icon of the entry to the given filename
+ */
+void
+nbtk_entry_set_primary_icon_from_file (NbtkEntry   *entry,
+                                       const gchar *filename)
+{
+  NbtkEntryPrivate *priv;
+
+  g_return_if_fail (NBTK_IS_ENTRY (entry));
+
+  priv = entry->priv;
+
+  _nbtk_entry_set_icon_from_file (entry, &priv->primary_icon, filename);
+
+}
+
+/**
+ * nbtk_entry_set_secondary_icon_from_file:
+ * @entry: a #NbtkEntry
+ * @filename: filename of an icon
+ *
+ * Set the primary icon of the entry to the given filename
+ */
+void
+nbtk_entry_set_secondary_icon_from_file (NbtkEntry   *entry,
+                                         const gchar *filename)
+{
+  NbtkEntryPrivate *priv;
+
+  g_return_if_fail (NBTK_IS_ENTRY (entry));
+
+  priv = entry->priv;
+
+  _nbtk_entry_set_icon_from_file (entry, &priv->secondary_icon, filename);
+
+}
diff --git a/src/nbtk/nbtk-entry.h b/src/nbtk/nbtk-entry.h
new file mode 100644
index 0000000..aca4c8c
--- /dev/null
+++ b/src/nbtk/nbtk-entry.h
@@ -0,0 +1,88 @@
+/*
+ * nbtk-entry.h: Plain entry actor
+ *
+ * Copyright 2008, 2009 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Thomas Wood <thomas linux intel com>
+ *
+ */
+
+#if !defined(NBTK_H_INSIDE) && !defined(NBTK_COMPILATION)
+#error "Only <nbtk/nbtk.h> can be included directly.h"
+#endif
+
+#ifndef __NBTK_ENTRY_H__
+#define __NBTK_ENTRY_H__
+
+G_BEGIN_DECLS
+
+#include <nbtk/nbtk-widget.h>
+
+#define NBTK_TYPE_ENTRY                (nbtk_entry_get_type ())
+#define NBTK_ENTRY(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NBTK_TYPE_ENTRY, NbtkEntry))
+#define NBTK_IS_ENTRY(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NBTK_TYPE_ENTRY))
+#define NBTK_ENTRY_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST ((klass), NBTK_TYPE_ENTRY, NbtkEntryClass))
+#define NBTK_IS_ENTRY_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE ((klass), NBTK_TYPE_ENTRY))
+#define NBTK_ENTRY_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), NBTK_TYPE_ENTRY, NbtkEntryClass))
+
+typedef struct _NbtkEntry              NbtkEntry;
+typedef struct _NbtkEntryPrivate       NbtkEntryPrivate;
+typedef struct _NbtkEntryClass         NbtkEntryClass;
+
+/**
+ * NbtkEntry:
+ *
+ * The contents of this structure is private and should only be accessed using
+ * the provided API.
+ */
+struct _NbtkEntry
+{
+  /*< private >*/
+  NbtkWidget parent_instance;
+
+  NbtkEntryPrivate *priv;
+};
+
+struct _NbtkEntryClass
+{
+  NbtkWidgetClass parent_class;
+
+  /* signals */
+  void (*primary_icon_clicked) (NbtkEntry *entry);
+  void (*secondary_icon_clicked) (NbtkEntry *entry);
+};
+
+GType nbtk_entry_get_type (void) G_GNUC_CONST;
+
+NbtkWidget *          nbtk_entry_new              (const gchar *text);
+G_CONST_RETURN gchar *nbtk_entry_get_text         (NbtkEntry   *entry);
+void                  nbtk_entry_set_text         (NbtkEntry   *entry,
+                                                   const gchar *text);
+ClutterActor*         nbtk_entry_get_clutter_text (NbtkEntry   *entry);
+
+void                  nbtk_entry_set_hint_text (NbtkEntry *entry,
+                                                const gchar *text);
+G_CONST_RETURN gchar *nbtk_entry_get_hint_text (NbtkEntry *entry);
+
+void nbtk_entry_set_primary_icon_from_file (NbtkEntry   *entry,
+                                            const gchar *filename);
+void nbtk_entry_set_secondary_icon_from_file (NbtkEntry   *entry,
+                                              const gchar *filename);
+
+G_END_DECLS
+
+#endif /* __NBTK_ENTRY_H__ */
diff --git a/src/nbtk/nbtk-label.c b/src/nbtk/nbtk-label.c
new file mode 100644
index 0000000..3763724
--- /dev/null
+++ b/src/nbtk/nbtk-label.c
@@ -0,0 +1,363 @@
+/*
+ * nbtk-label.c: Plain label actor
+ *
+ * Copyright 2008,2009 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by: Thomas Wood <thomas linux intel com>
+ *
+ */
+
+/**
+ * SECTION:nbtk-label
+ * @short_description: Widget for displaying text
+ *
+ * #NbtkLabel is a simple widget for displaying text. It derives from
+ * #NbtkWidget to add extra style and placement functionality over
+ * #ClutterText. The internal #ClutterText is publicly accessibly to allow
+ * applications to set further properties.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <clutter/clutter.h>
+
+#include "nbtk-label.h"
+
+#include "nbtk-widget.h"
+#include "nbtk-stylable.h"
+
+enum
+{
+  PROP_0,
+
+  PROP_LABEL
+};
+
+#define NBTK_LABEL_GET_PRIVATE(obj)     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NBTK_TYPE_LABEL, NbtkLabelPrivate))
+
+struct _NbtkLabelPrivate
+{
+  ClutterActor *label;
+};
+
+G_DEFINE_TYPE (NbtkLabel, nbtk_label, NBTK_TYPE_WIDGET);
+
+static void
+nbtk_label_set_property (GObject      *gobject,
+                           guint         prop_id,
+                           const GValue *value,
+                           GParamSpec   *pspec)
+{
+  NbtkLabel *label = NBTK_LABEL (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_LABEL:
+      nbtk_label_set_text (label, g_value_get_string (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+nbtk_label_get_property (GObject    *gobject,
+                           guint       prop_id,
+                           GValue     *value,
+                           GParamSpec *pspec)
+{
+  NbtkLabelPrivate *priv = NBTK_LABEL (gobject)->priv;
+
+  switch (prop_id)
+    {
+    case PROP_LABEL:
+      g_value_set_string (value, clutter_text_get_text (CLUTTER_TEXT (priv->label)));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+nbtk_label_style_changed (NbtkWidget *self)
+{
+  NbtkLabelPrivate *priv = NBTK_LABEL (self)->priv;
+  ClutterColor *color = NULL;
+  gchar *font_name;
+  gchar *font_string;
+  gint font_size;
+
+  nbtk_stylable_get (NBTK_STYLABLE (self),
+                     "color", &color,
+                     "font-family", &font_name,
+                     "font-size", &font_size,
+                     NULL);
+
+  if (color)
+    {
+      clutter_text_set_color (CLUTTER_TEXT (priv->label), color);
+      clutter_color_free (color);
+    }
+
+  if (font_name || font_size)
+    {
+      if (font_name && font_size)
+        {
+          font_string = g_strdup_printf ("%s %dpx", font_name, font_size);
+          g_free (font_name);
+        }
+      else
+        {
+          if (font_size)
+            font_string = g_strdup_printf ("%dpx", font_size);
+          else
+            font_string = font_name;
+        }
+
+      clutter_text_set_font_name (CLUTTER_TEXT (priv->label), font_string);
+      g_free (font_string);
+    }
+
+}
+
+static void
+nbtk_label_get_preferred_width (ClutterActor *actor,
+                                gfloat        for_height,
+                                gfloat       *min_width_p,
+                                gfloat       *natural_width_p)
+{
+  NbtkLabelPrivate *priv = NBTK_LABEL (actor)->priv;
+  NbtkPadding padding = { 0, };
+
+  nbtk_widget_get_padding (NBTK_WIDGET (actor), &padding);
+
+  clutter_actor_get_preferred_width (priv->label, for_height,
+                                     min_width_p,
+                                     natural_width_p);
+
+  if (min_width_p)
+    *min_width_p += padding.left + padding.right;
+
+  if (natural_width_p)
+    *natural_width_p += padding.left + padding.right;
+}
+
+static void
+nbtk_label_get_preferred_height (ClutterActor *actor,
+                                 gfloat        for_width,
+                                 gfloat       *min_height_p,
+                                 gfloat       *natural_height_p)
+{
+  NbtkLabelPrivate *priv = NBTK_LABEL (actor)->priv;
+  NbtkPadding padding = { 0, };
+
+  nbtk_widget_get_padding (NBTK_WIDGET (actor), &padding);
+
+  clutter_actor_get_preferred_height (priv->label, for_width,
+                                      min_height_p,
+                                      natural_height_p);
+
+  if (min_height_p)
+    *min_height_p += padding.top + padding.bottom;
+
+  if (natural_height_p)
+    *natural_height_p += padding.top + padding.bottom;
+}
+
+static void
+nbtk_label_allocate (ClutterActor          *actor,
+                     const ClutterActorBox *box,
+                     ClutterAllocationFlags flags)
+{
+  NbtkLabelPrivate *priv = NBTK_LABEL (actor)->priv;
+  ClutterActorClass *parent_class;
+  ClutterActorBox child_box;
+  NbtkPadding padding = { 0, };
+
+  nbtk_widget_get_padding (NBTK_WIDGET (actor), &padding);
+
+  parent_class = CLUTTER_ACTOR_CLASS (nbtk_label_parent_class);
+  parent_class->allocate (actor, box, flags);
+
+  child_box.x1 = padding.left;
+  child_box.y1 = padding.top;
+  child_box.x2 = box->x2 - box->x1 - padding.right;
+  child_box.y2 = box->y2 - box->y1 - padding.bottom;
+
+  clutter_actor_allocate (priv->label, &child_box, flags);
+}
+
+static void
+nbtk_label_paint (ClutterActor *actor)
+{
+  NbtkLabelPrivate *priv = NBTK_LABEL (actor)->priv;
+  ClutterActorClass *parent_class;
+
+  parent_class = CLUTTER_ACTOR_CLASS (nbtk_label_parent_class);
+  parent_class->paint (actor);
+
+  clutter_actor_paint (priv->label);
+}
+
+static void
+nbtk_label_map (ClutterActor *actor)
+{
+  NbtkLabelPrivate *priv = NBTK_LABEL (actor)->priv;
+
+  CLUTTER_ACTOR_CLASS (nbtk_label_parent_class)->map (actor);
+
+  clutter_actor_map (priv->label);
+}
+
+static void
+nbtk_label_unmap (ClutterActor *actor)
+{
+  NbtkLabelPrivate *priv = NBTK_LABEL (actor)->priv;
+
+  CLUTTER_ACTOR_CLASS (nbtk_label_parent_class)->unmap (actor);
+
+  clutter_actor_unmap (priv->label);
+}
+
+static void
+nbtk_label_class_init (NbtkLabelClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+  GParamSpec *pspec;
+
+  g_type_class_add_private (klass, sizeof (NbtkLabelPrivate));
+
+  gobject_class->set_property = nbtk_label_set_property;
+  gobject_class->get_property = nbtk_label_get_property;
+
+  actor_class->paint = nbtk_label_paint;
+  actor_class->allocate = nbtk_label_allocate;
+  actor_class->get_preferred_width = nbtk_label_get_preferred_width;
+  actor_class->get_preferred_height = nbtk_label_get_preferred_height;
+  actor_class->map = nbtk_label_map;
+  actor_class->unmap = nbtk_label_unmap;
+
+  pspec = g_param_spec_string ("text",
+                               "Text",
+                               "Text of the label",
+                               NULL, G_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class, PROP_LABEL, pspec);
+
+}
+
+static void
+nbtk_label_init (NbtkLabel *label)
+{
+  NbtkLabelPrivate *priv;
+
+  label->priv = priv = NBTK_LABEL_GET_PRIVATE (label);
+
+  label->priv->label = g_object_new (CLUTTER_TYPE_TEXT,
+                                     "ellipsize", PANGO_ELLIPSIZE_END,
+                                     NULL);
+
+  clutter_actor_set_parent (priv->label, CLUTTER_ACTOR (label));
+
+  g_signal_connect (label, "style-changed",
+                    G_CALLBACK (nbtk_label_style_changed), NULL);
+}
+
+/**
+ * nbtk_label_new:
+ * @text: text to set the label to
+ *
+ * Create a new #NbtkLabel with the specified label
+ *
+ * Returns: a new #NbtkLabel
+ */
+NbtkWidget *
+nbtk_label_new (const gchar *text)
+{
+  if (text == NULL || *text == '\0')
+    return g_object_new (NBTK_TYPE_LABEL, NULL);
+  else
+    return g_object_new (NBTK_TYPE_LABEL,
+                         "text", text,
+                         NULL);
+}
+
+/**
+ * nbtk_label_get_text:
+ * @label: a #NbtkLabel
+ *
+ * Get the text displayed on the label
+ *
+ * Returns: the text for the label. This must not be freed by the application
+ */
+G_CONST_RETURN gchar *
+nbtk_label_get_text (NbtkLabel *label)
+{
+  g_return_val_if_fail (NBTK_IS_LABEL (label), NULL);
+
+  return clutter_text_get_text (CLUTTER_TEXT (label->priv->label));
+}
+
+/**
+ * nbtk_label_set_text:
+ * @label: a #NbtkLabel
+ * @text: text to set the label to
+ *
+ * Sets the text displayed on the label
+ */
+void
+nbtk_label_set_text (NbtkLabel *label,
+                     const gchar *text)
+{
+  NbtkLabelPrivate *priv;
+
+  g_return_if_fail (NBTK_IS_LABEL (label));
+  g_return_if_fail (text != NULL);
+
+  priv = label->priv;
+
+  clutter_text_set_text (CLUTTER_TEXT (priv->label), text);
+
+  g_object_notify (G_OBJECT (label), "text");
+}
+
+/**
+ * nbtk_label_get_clutter_text:
+ * @label: a #NbtkLabel
+ *
+ * Retrieve the internal #ClutterText so that extra parameters can be set
+ *
+ * Returns: the #ClutterText used by #NbtkLabel. The label is owned by the
+ * #NbtkLabel and should not be unref'ed by the application.
+ */
+ClutterActor*
+nbtk_label_get_clutter_text (NbtkLabel *label)
+{
+  g_return_val_if_fail (NBTK_LABEL (label), NULL);
+
+  return label->priv->label;
+}
diff --git a/src/nbtk/nbtk-label.h b/src/nbtk/nbtk-label.h
new file mode 100644
index 0000000..613e0fd
--- /dev/null
+++ b/src/nbtk/nbtk-label.h
@@ -0,0 +1,75 @@
+/*
+ * nbtk-label.h: Plain label actor
+ *
+ * Copyright 2008, 2009 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Thomas Wood <thomas linux intel com>
+ *
+ */
+
+#if !defined(NBTK_H_INSIDE) && !defined(NBTK_COMPILATION)
+#error "Only <nbtk/nbtk.h> can be included directly.h"
+#endif
+
+#ifndef __NBTK_LABEL_H__
+#define __NBTK_LABEL_H__
+
+G_BEGIN_DECLS
+
+#include <nbtk/nbtk-widget.h>
+
+#define NBTK_TYPE_LABEL                (nbtk_label_get_type ())
+#define NBTK_LABEL(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NBTK_TYPE_LABEL, NbtkLabel))
+#define NBTK_IS_LABEL(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NBTK_TYPE_LABEL))
+#define NBTK_LABEL_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST ((klass), NBTK_TYPE_LABEL, NbtkLabelClass))
+#define NBTK_IS_LABEL_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE ((klass), NBTK_TYPE_LABEL))
+#define NBTK_LABEL_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), NBTK_TYPE_LABEL, NbtkLabelClass))
+
+typedef struct _NbtkLabel              NbtkLabel;
+typedef struct _NbtkLabelPrivate       NbtkLabelPrivate;
+typedef struct _NbtkLabelClass         NbtkLabelClass;
+
+/**
+ * NbtkLabel:
+ *
+ * The contents of this structure is private and should only be accessed using
+ * the provided API.
+ */
+struct _NbtkLabel
+{
+  /*< private >*/
+  NbtkWidget parent_instance;
+
+  NbtkLabelPrivate *priv;
+};
+
+struct _NbtkLabelClass
+{
+  NbtkWidgetClass parent_class;
+};
+
+GType nbtk_label_get_type (void) G_GNUC_CONST;
+
+NbtkWidget *          nbtk_label_new              (const gchar *text);
+G_CONST_RETURN gchar *nbtk_label_get_text         (NbtkLabel   *label);
+void                  nbtk_label_set_text         (NbtkLabel   *label,
+                                                   const gchar *text);
+ClutterActor *        nbtk_label_get_clutter_text (NbtkLabel   *label);
+
+G_END_DECLS
+
+#endif /* __NBTK_LABEL_H__ */
diff --git a/tools/build/gnome-shell.modules b/tools/build/gnome-shell.modules
index 095bc9d..6395eb5 100644
--- a/tools/build/gnome-shell.modules
+++ b/tools/build/gnome-shell.modules
@@ -7,6 +7,8 @@
       href="git://git.clutter-project.org/"/>
   <repository type="git" name="git.gnome.org"
       href="git://git.gnome.org/"/>
+  <repository type="git" name="git.moblin.org"
+      href="git://git.moblin.org"/>
 
   <autotools id="gobject-introspection">
     <branch repo="git.gnome.org" module="gobject-introspection"/>
@@ -36,6 +38,13 @@
     </dependencies>
   </autotools>
 
+  <autotools id="clutter-imcontext">
+    <branch repo="git.moblin.org" module="clutter-imcontext"/>
+    <dependencies>
+        <dep package="clutter"/>
+    </dependencies>
+  </autotools>
+
   <autotools id="gconf" autogenargs="--disable-defaults-service">
     <branch repo="git.gnome.org" module="gconf"/>
   </autotools>



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