From 0315a6e4a81ebc07d8d7a4a8d8b09e209a9f102c Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Thu, 10 Sep 2009 04:39:27 -0400 Subject: [PATCH] Import MxEntry, MxLabel, MxClipboard 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-st.am | 6 + src/st/st-clipboard.c | 380 +++++++++++++ src/st/st-clipboard.h | 102 ++++ src/st/st-entry.c | 961 ++++++++++++++++++++++++++++++++ src/st/st-entry.h | 88 +++ src/st/st-label.c | 363 ++++++++++++ src/st/st-label.h | 75 +++ tools/build/gnome-shell.modules | 9 + 9 files changed, 1985 insertions(+), 1 deletion(-) create mode 100644 src/st/st-clipboard.c create mode 100644 src/st/st-clipboard.h create mode 100644 src/st/st-entry.c create mode 100644 src/st/st-entry.h create mode 100644 src/st/st-label.c create mode 100644 src/st/st-label.h diff --git a/configure.ac b/configure.ac index 5c7efed63..050b3756f 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(ST, clutter-1.0 gtk+-2.0 libccss-1 >= 0.3.1) +PKG_CHECK_MODULES(ST, 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-st.am b/src/Makefile-st.am index d0f4877e9..2967054c9 100644 --- a/src/Makefile-st.am +++ b/src/Makefile-st.am @@ -70,6 +70,9 @@ st_source_h = \ st/st-box-layout.h \ st/st-box-layout-child.h \ st/st-button.h \ + st/st-clipboard.h \ + st/st-entry.h \ + st/st-label.h \ st/st-private.h \ st/st-stylable.h \ st/st-style.h \ @@ -91,6 +94,9 @@ st_source_c = \ st/st-box-layout.c \ st/st-box-layout-child.c \ st/st-button.c \ + st/st-clipboard.c \ + st/st-entry.c \ + st/st-label.c \ st/st-private.c \ st/st-scrollable.c \ st/st-scroll-bar.c \ diff --git a/src/st/st-clipboard.c b/src/st/st-clipboard.c new file mode 100644 index 000000000..c6507c141 --- /dev/null +++ b/src/st/st-clipboard.c @@ -0,0 +1,380 @@ +/* + * st-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 + * + */ + +/** + * SECTION:st-clipboard + * @short_description: a simple representation of the X clipboard + * + * #StCliboard is a very simple object representation of the clipboard + * available to applications. Text is always assumed to be UTF-8 and non-text + * items are not handled. + */ + + +#include "st-clipboard.h" +#include +#include +#include +#include + +G_DEFINE_TYPE (StClipboard, st_clipboard, G_TYPE_OBJECT) + +#define CLIPBOARD_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), ST_TYPE_CLIPBOARD, StClipboardPrivate)) + +struct _StClipboardPrivate +{ + Window clipboard_window; + gchar *clipboard_text; + + Atom *supported_targets; + gint n_targets; +}; + +typedef struct _EventFilterData EventFilterData; +struct _EventFilterData +{ + StClipboard *clipboard; + StClipboardCallbackFunc callback; + gpointer user_data; +}; + +static Atom __atom_clip = None; +static Atom __utf8_string = None; +static Atom __atom_targets = None; + +static void +st_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 +st_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 +st_clipboard_dispose (GObject *object) +{ + G_OBJECT_CLASS (st_clipboard_parent_class)->dispose (object); +} + +static void +st_clipboard_finalize (GObject *object) +{ + StClipboardPrivate *priv = ((StClipboard *) 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 (st_clipboard_parent_class)->finalize (object); +} + +static ClutterX11FilterReturn +st_clipboard_provider (XEvent *xev, + ClutterEvent *cev, + StClipboard *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 *) ¬ify_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 +st_clipboard_class_init (StClipboardClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (StClipboardPrivate)); + + object_class->get_property = st_clipboard_get_property; + object_class->set_property = st_clipboard_set_property; + object_class->dispose = st_clipboard_dispose; + object_class->finalize = st_clipboard_finalize; +} + +static void +st_clipboard_init (StClipboard *self) +{ + Display *dpy; + StClipboardPrivate *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) st_clipboard_provider, + self); +} + +static ClutterX11FilterReturn +st_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) st_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) st_clipboard_x11_event_filter, + filter_data); + + g_free (filter_data); + + if (data) + XFree (data); + + return CLUTTER_X11_FILTER_REMOVE; +} + +/** + * st_clipboard_get_default: + * + * Get the global #StClipboard object that represents the clipboard. + * + * Returns: a #StClipboard owned by St and must not be unrefferenced or + * freed. + */ +StClipboard* +st_clipboard_get_default (void) +{ + static StClipboard *default_clipboard = NULL; + + if (!default_clipboard) + { + default_clipboard = g_object_new (ST_TYPE_CLIPBOARD, NULL); + } + + return default_clipboard; +} + +/** + * st_clipboard_get_text: + * @clipboard: A #StCliboard + * @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 +st_clipboard_get_text (StClipboard *clipboard, + StClipboardCallbackFunc callback, + gpointer user_data) +{ + EventFilterData *data; + + Display *dpy; + + g_return_if_fail (ST_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) st_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 (); +} + +/** + * st_clipboard_set_text: + * @clipboard: A #StClipboard + * @text: text to copy to the clipboard + * + * Sets text as the current contents of the clipboard. + * + */ +void +st_clipboard_set_text (StClipboard *clipboard, + const gchar *text) +{ + StClipboardPrivate *priv; + Display *dpy; + + g_return_if_fail (ST_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/st/st-clipboard.h b/src/st/st-clipboard.h new file mode 100644 index 000000000..b1751a3a8 --- /dev/null +++ b/src/st/st-clipboard.h @@ -0,0 +1,102 @@ +/* + * st-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 + * + */ + +#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION) +#error "Only can be included directly.h" +#endif + +#ifndef _ST_CLIPBOARD_H +#define _ST_CLIPBOARD_H + +#include + +G_BEGIN_DECLS + +#define ST_TYPE_CLIPBOARD st_clipboard_get_type() + +#define ST_CLIPBOARD(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + ST_TYPE_CLIPBOARD, StClipboard)) + +#define ST_CLIPBOARD_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + ST_TYPE_CLIPBOARD, StClipboardClass)) + +#define ST_IS_CLIPBOARD(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + ST_TYPE_CLIPBOARD)) + +#define ST_IS_CLIPBOARD_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), \ + ST_TYPE_CLIPBOARD)) + +#define ST_CLIPBOARD_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + ST_TYPE_CLIPBOARD, StClipboardClass)) + +typedef struct _StClipboard StClipboard; +typedef struct _StClipboardClass StClipboardClass; +typedef struct _StClipboardPrivate StClipboardPrivate; + +/** + * StClipboard: + * + * The contents of this structure is private and should only be accessed using + * the provided API. + */ +struct _StClipboard +{ + /*< private >*/ + GObject parent; + StClipboardPrivate *priv; +}; + +struct _StClipboardClass +{ + GObjectClass parent_class; +}; + +/** + * StClipboardCallbackFunc: + * @clipboard: A #StClipboard + * @text: text from the clipboard + * @user_data: user data + * + * Callback function called when text is retrieved from the clipboard. + */ +typedef void (*StClipboardCallbackFunc) (StClipboard *clipboard, + const gchar *text, + gpointer user_data); + +GType st_clipboard_get_type (void); + +StClipboard* st_clipboard_get_default (void); + +void st_clipboard_get_text (StClipboard *clipboard, + StClipboardCallbackFunc callback, + gpointer user_data); +void st_clipboard_set_text (StClipboard *clipboard, + const gchar *text); + +G_END_DECLS + +#endif /* _ST_CLIPBOARD_H */ diff --git a/src/st/st-entry.c b/src/st/st-entry.c new file mode 100644 index 000000000..20151bfc8 --- /dev/null +++ b/src/st/st-entry.c @@ -0,0 +1,961 @@ +/* + * st-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 + * + */ + +/** + * SECTION:st-entry + * @short_description: Widget for displaying text + * + * #StEntry is a simple widget for displaying text. It derives from + * #StWidget to add extra style and placement functionality over + * #ClutterText. The internal #ClutterText is publicly accessibly to allow + * applications to set further properties. + * + * #StEntry supports the following pseudo style states: + * + * + * focus: the widget has focus + * + * + * indeterminate: the widget is showing the hint text + * + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include + +#include + +#include +#include + +#include "st-entry.h" + +#include "st-widget.h" +#include "st-stylable.h" +#include "st-texture-cache.h" +#include "st-marshal.h" +#include "st-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 ST_ENTRY_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ST_TYPE_ENTRY, StEntryPrivate)) +#define ST_ENTRY_PRIV(x) ((StEntry *) x)->priv + + +struct _StEntryPrivate +{ + ClutterActor *entry; + gchar *hint; + + ClutterActor *primary_icon; + ClutterActor *secondary_icon; + + gfloat spacing; +}; + +static guint entry_signals[LAST_SIGNAL] = { 0, }; + +static void st_stylable_iface_init (StStylableIface *iface); + +G_DEFINE_TYPE_WITH_CODE (StEntry, st_entry, ST_TYPE_WIDGET, + G_IMPLEMENT_INTERFACE (ST_TYPE_STYLABLE, + st_stylable_iface_init)); + +static void +st_entry_set_property (GObject *gobject, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + StEntry *entry = ST_ENTRY (gobject); + + switch (prop_id) + { + case PROP_ENTRY: + st_entry_set_text (entry, g_value_get_string (value)); + break; + + case PROP_HINT: + st_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 +st_entry_get_property (GObject *gobject, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + StEntryPrivate *priv = ST_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 +st_entry_dispose (GObject *object) +{ + StEntryPrivate *priv = ST_ENTRY_PRIV (object); + + if (priv->entry) + { + clutter_actor_unparent (priv->entry); + priv->entry = NULL; + } +} + +static void +st_entry_finalize (GObject *object) +{ + StEntryPrivate *priv = ST_ENTRY_PRIV (object); + + g_free (priv->hint); + priv->hint = NULL; +} + +static void +st_stylable_iface_init (StStylableIface *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); + st_stylable_iface_install_property (iface, ST_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); + st_stylable_iface_install_property (iface, ST_TYPE_ENTRY, pspec); + } +} + +static void +st_entry_style_changed (StWidget *self) +{ + StEntryPrivate *priv = ST_ENTRY_PRIV (self); + ClutterColor *color = NULL; + ClutterColor *caret_color = NULL; + ClutterColor *selection_background_color = NULL; + gchar *font_name; + gchar *font_string; + gint font_size; + + st_stylable_get (ST_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 +st_entry_get_preferred_width (ClutterActor *actor, + gfloat for_height, + gfloat *min_width_p, + gfloat *natural_width_p) +{ + StEntryPrivate *priv = ST_ENTRY_PRIV (actor); + StPadding padding; + gfloat icon_w; + + st_widget_get_padding (ST_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 +st_entry_get_preferred_height (ClutterActor *actor, + gfloat for_width, + gfloat *min_height_p, + gfloat *natural_height_p) +{ + StEntryPrivate *priv = ST_ENTRY_PRIV (actor); + StPadding padding; + gfloat icon_h; + + st_widget_get_padding (ST_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 +st_entry_allocate (ClutterActor *actor, + const ClutterActorBox *box, + ClutterAllocationFlags flags) +{ + StEntryPrivate *priv = ST_ENTRY_PRIV (actor); + ClutterActorClass *parent_class; + ClutterActorBox child_box, icon_box; + StPadding padding; + gfloat icon_w, icon_h; + gfloat entry_h, min_h, pref_h, avail_h; + + st_widget_get_padding (ST_WIDGET (actor), &padding); + + parent_class = CLUTTER_ACTOR_CLASS (st_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) +{ + StEntryPrivate *priv = ST_ENTRY_PRIV (actor); + + /* remove the hint if visible */ + if (priv->hint + && !strcmp (clutter_text_get_text (text), priv->hint)) + { + clutter_text_set_text (text, ""); + } + st_widget_set_style_pseudo_class (ST_WIDGET (actor), "focus"); + clutter_text_set_cursor_visible (text, TRUE); +} + +static void +clutter_text_focus_out_cb (ClutterText *text, + ClutterActor *actor) +{ + StEntryPrivate *priv = ST_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); + st_widget_set_style_pseudo_class (ST_WIDGET (actor), "indeterminate"); + } + else + { + st_widget_set_style_pseudo_class (ST_WIDGET (actor), NULL); + } + clutter_text_set_cursor_visible (text, FALSE); +} + +static void +st_entry_paint (ClutterActor *actor) +{ + StEntryPrivate *priv = ST_ENTRY_PRIV (actor); + ClutterActorClass *parent_class; + + parent_class = CLUTTER_ACTOR_CLASS (st_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 +st_entry_pick (ClutterActor *actor, + const ClutterColor *c) +{ + StEntryPrivate *priv = ST_ENTRY_PRIV (actor); + + CLUTTER_ACTOR_CLASS (st_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 +st_entry_map (ClutterActor *actor) +{ + StEntryPrivate *priv = ST_ENTRY (actor)->priv; + + CLUTTER_ACTOR_CLASS (st_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 +st_entry_unmap (ClutterActor *actor) +{ + StEntryPrivate *priv = ST_ENTRY (actor)->priv; + + CLUTTER_ACTOR_CLASS (st_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 +st_entry_clipboard_callback (StClipboard *clipboard, + const gchar *text, + gpointer data) +{ + ClutterText *ctext = (ClutterText*)((StEntry *) 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 +st_entry_key_press_event (ClutterActor *actor, + ClutterKeyEvent *event) +{ + StEntryPrivate *priv = ST_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) + { + StClipboard *clipboard; + + clipboard = st_clipboard_get_default (); + + st_clipboard_get_text (clipboard, st_entry_clipboard_callback, actor); + + return TRUE; + } + + /* copy */ + if ((event->modifier_state & CLUTTER_CONTROL_MASK) + && event->keyval == CLUTTER_c) + { + StClipboard *clipboard; + gchar *text; + + clipboard = st_clipboard_get_default (); + + text = clutter_text_get_selection ((ClutterText*) priv->entry); + + if (text && strlen (text)) + st_clipboard_set_text (clipboard, text); + + return TRUE; + } + + + /* cut */ + if ((event->modifier_state & CLUTTER_CONTROL_MASK) + && event->keyval == CLUTTER_x) + { + StClipboard *clipboard; + gchar *text; + + clipboard = st_clipboard_get_default (); + + text = clutter_text_get_selection ((ClutterText*) priv->entry); + + if (text && strlen (text)) + { + st_clipboard_set_text (clipboard, text); + + /* now delete the text */ + clutter_text_delete_selection ((ClutterText *) priv->entry); + } + + return TRUE; + } + + return FALSE; +} + +static void +st_entry_key_focus_in (ClutterActor *actor) +{ + StEntryPrivate *priv = ST_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 +st_entry_class_init (StEntryClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); + GParamSpec *pspec; + + g_type_class_add_private (klass, sizeof (StEntryPrivate)); + + gobject_class->set_property = st_entry_set_property; + gobject_class->get_property = st_entry_get_property; + gobject_class->finalize = st_entry_finalize; + gobject_class->dispose = st_entry_dispose; + + actor_class->get_preferred_width = st_entry_get_preferred_width; + actor_class->get_preferred_height = st_entry_get_preferred_height; + actor_class->allocate = st_entry_allocate; + actor_class->paint = st_entry_paint; + actor_class->pick = st_entry_pick; + actor_class->map = st_entry_map; + actor_class->unmap = st_entry_unmap; + + actor_class->key_press_event = st_entry_key_press_event; + actor_class->key_focus_in = st_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 */ + /** + * StEntry::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 (StEntryClass, primary_icon_clicked), + NULL, NULL, + _st_marshal_VOID__VOID, + G_TYPE_NONE, 0); + /** + * StEntry::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 (StEntryClass, secondary_icon_clicked), + NULL, NULL, + _st_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +st_entry_init (StEntry *entry) +{ + StEntryPrivate *priv; + + priv = entry->priv = ST_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 (st_entry_style_changed), NULL); +} + +/** + * st_entry_new: + * @text: text to set the entry to + * + * Create a new #StEntry with the specified entry + * + * Returns: a new #StEntry + */ +StWidget * +st_entry_new (const gchar *text) +{ + StWidget *entry; + + /* add the entry to the stage, but don't allow it to be visible */ + entry = g_object_new (ST_TYPE_ENTRY, + "text", text, + NULL); + + return entry; +} + +/** + * st_entry_get_text: + * @entry: a #StEntry + * + * 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 * +st_entry_get_text (StEntry *entry) +{ + g_return_val_if_fail (ST_IS_ENTRY (entry), NULL); + + return clutter_text_get_text (CLUTTER_TEXT (entry->priv->entry)); +} + +/** + * st_entry_set_text: + * @entry: a #StEntry + * @text: text to set the entry to + * + * Sets the text displayed on the entry + */ +void +st_entry_set_text (StEntry *entry, + const gchar *text) +{ + StEntryPrivate *priv; + + g_return_if_fail (ST_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; + st_widget_set_style_pseudo_class (ST_WIDGET (entry), "indeterminate"); + } + else + { + if (HAS_FOCUS (priv->entry)) + st_widget_set_style_pseudo_class (ST_WIDGET (entry), "focus"); + else + st_widget_set_style_pseudo_class (ST_WIDGET (entry), NULL); + } + + clutter_text_set_text (CLUTTER_TEXT (priv->entry), text); + + g_object_notify (G_OBJECT (entry), "text"); +} + +/** + * st_entry_get_clutter_text: + * @entry: a #StEntry + * + * Retrieve the internal #ClutterText so that extra parameters can be set + * + * Returns: the #ClutterText used by #StEntry. The entry is owned by the + * #StEntry and should not be unref'ed by the application. + */ +ClutterActor* +st_entry_get_clutter_text (StEntry *entry) +{ + g_return_val_if_fail (ST_ENTRY (entry), NULL); + + return entry->priv->entry; +} + +/** + * st_entry_set_hint_text: + * @entry: a #StEntry + * @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 +st_entry_set_hint_text (StEntry *entry, + const gchar *text) +{ + StEntryPrivate *priv; + + g_return_if_fail (ST_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); + st_widget_set_style_pseudo_class (ST_WIDGET (entry), "indeterminate"); + } +} + +/** + * st_entry_get_hint_text: + * @entry: a #StEntry + * + * 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 + * #StEntry and should not be freed or modified. + */ +G_CONST_RETURN +gchar * +st_entry_get_hint_text (StEntry *entry) +{ + g_return_val_if_fail (ST_IS_ENTRY (entry), NULL); + + return entry->priv->hint; +} + +static gboolean +_st_entry_icon_press_cb (ClutterActor *actor, + ClutterButtonEvent *event, + StEntry *entry) +{ + StEntryPrivate *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 +_st_entry_set_icon_from_file (StEntry *entry, + ClutterActor **icon, + const gchar *filename) +{ + if (*icon) + { + g_signal_handlers_disconnect_by_func (*icon, + _st_entry_icon_press_cb, + entry); + clutter_actor_unparent (*icon); + *icon = NULL; + } + + if (filename) + { + StTextureCache *cache; + + cache = st_texture_cache_get_default (); + + + + *icon = (ClutterActor*) st_texture_cache_get_texture (cache, filename); + + clutter_actor_set_reactive (*icon, TRUE); + clutter_actor_set_parent (*icon, CLUTTER_ACTOR (entry)); + g_signal_connect (*icon, "button-release-event", + G_CALLBACK (_st_entry_icon_press_cb), entry); + } + + clutter_actor_queue_relayout (CLUTTER_ACTOR (entry)); +} + +/** + * st_entry_set_primary_icon_from_file: + * @entry: a #StEntry + * @filename: filename of an icon + * + * Set the primary icon of the entry to the given filename + */ +void +st_entry_set_primary_icon_from_file (StEntry *entry, + const gchar *filename) +{ + StEntryPrivate *priv; + + g_return_if_fail (ST_IS_ENTRY (entry)); + + priv = entry->priv; + + _st_entry_set_icon_from_file (entry, &priv->primary_icon, filename); + +} + +/** + * st_entry_set_secondary_icon_from_file: + * @entry: a #StEntry + * @filename: filename of an icon + * + * Set the primary icon of the entry to the given filename + */ +void +st_entry_set_secondary_icon_from_file (StEntry *entry, + const gchar *filename) +{ + StEntryPrivate *priv; + + g_return_if_fail (ST_IS_ENTRY (entry)); + + priv = entry->priv; + + _st_entry_set_icon_from_file (entry, &priv->secondary_icon, filename); + +} + diff --git a/src/st/st-entry.h b/src/st/st-entry.h new file mode 100644 index 000000000..5f9ff18ad --- /dev/null +++ b/src/st/st-entry.h @@ -0,0 +1,88 @@ +/* + * st-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 + * + */ + +#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION) +#error "Only can be included directly.h" +#endif + +#ifndef __ST_ENTRY_H__ +#define __ST_ENTRY_H__ + +G_BEGIN_DECLS + +#include + +#define ST_TYPE_ENTRY (st_entry_get_type ()) +#define ST_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_ENTRY, StEntry)) +#define ST_IS_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_ENTRY)) +#define ST_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ST_TYPE_ENTRY, StEntryClass)) +#define ST_IS_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ST_TYPE_ENTRY)) +#define ST_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ST_TYPE_ENTRY, StEntryClass)) + +typedef struct _StEntry StEntry; +typedef struct _StEntryPrivate StEntryPrivate; +typedef struct _StEntryClass StEntryClass; + +/** + * StEntry: + * + * The contents of this structure is private and should only be accessed using + * the provided API. + */ +struct _StEntry +{ + /*< private >*/ + StWidget parent_instance; + + StEntryPrivate *priv; +}; + +struct _StEntryClass +{ + StWidgetClass parent_class; + + /* signals */ + void (*primary_icon_clicked) (StEntry *entry); + void (*secondary_icon_clicked) (StEntry *entry); +}; + +GType st_entry_get_type (void) G_GNUC_CONST; + +StWidget * st_entry_new (const gchar *text); +G_CONST_RETURN gchar *st_entry_get_text (StEntry *entry); +void st_entry_set_text (StEntry *entry, + const gchar *text); +ClutterActor* st_entry_get_clutter_text (StEntry *entry); + +void st_entry_set_hint_text (StEntry *entry, + const gchar *text); +G_CONST_RETURN gchar *st_entry_get_hint_text (StEntry *entry); + +void st_entry_set_primary_icon_from_file (StEntry *entry, + const gchar *filename); +void st_entry_set_secondary_icon_from_file (StEntry *entry, + const gchar *filename); + +G_END_DECLS + +#endif /* __ST_ENTRY_H__ */ diff --git a/src/st/st-label.c b/src/st/st-label.c new file mode 100644 index 000000000..bcfcac603 --- /dev/null +++ b/src/st/st-label.c @@ -0,0 +1,363 @@ +/* + * st-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 + * + */ + +/** + * SECTION:st-label + * @short_description: Widget for displaying text + * + * #StLabel is a simple widget for displaying text. It derives from + * #StWidget 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 +#include + +#include + +#include + +#include "st-label.h" + +#include "st-widget.h" +#include "st-stylable.h" + +enum +{ + PROP_0, + + PROP_LABEL +}; + +#define ST_LABEL_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ST_TYPE_LABEL, StLabelPrivate)) + +struct _StLabelPrivate +{ + ClutterActor *label; +}; + +G_DEFINE_TYPE (StLabel, st_label, ST_TYPE_WIDGET); + +static void +st_label_set_property (GObject *gobject, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + StLabel *label = ST_LABEL (gobject); + + switch (prop_id) + { + case PROP_LABEL: + st_label_set_text (label, g_value_get_string (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + break; + } +} + +static void +st_label_get_property (GObject *gobject, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + StLabelPrivate *priv = ST_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 +st_label_style_changed (StWidget *self) +{ + StLabelPrivate *priv = ST_LABEL (self)->priv; + ClutterColor *color = NULL; + gchar *font_name; + gchar *font_string; + gint font_size; + + st_stylable_get (ST_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 +st_label_get_preferred_width (ClutterActor *actor, + gfloat for_height, + gfloat *min_width_p, + gfloat *natural_width_p) +{ + StLabelPrivate *priv = ST_LABEL (actor)->priv; + StPadding padding = { 0, }; + + st_widget_get_padding (ST_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 +st_label_get_preferred_height (ClutterActor *actor, + gfloat for_width, + gfloat *min_height_p, + gfloat *natural_height_p) +{ + StLabelPrivate *priv = ST_LABEL (actor)->priv; + StPadding padding = { 0, }; + + st_widget_get_padding (ST_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 +st_label_allocate (ClutterActor *actor, + const ClutterActorBox *box, + ClutterAllocationFlags flags) +{ + StLabelPrivate *priv = ST_LABEL (actor)->priv; + ClutterActorClass *parent_class; + ClutterActorBox child_box; + StPadding padding = { 0, }; + + st_widget_get_padding (ST_WIDGET (actor), &padding); + + parent_class = CLUTTER_ACTOR_CLASS (st_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 +st_label_paint (ClutterActor *actor) +{ + StLabelPrivate *priv = ST_LABEL (actor)->priv; + ClutterActorClass *parent_class; + + parent_class = CLUTTER_ACTOR_CLASS (st_label_parent_class); + parent_class->paint (actor); + + clutter_actor_paint (priv->label); +} + +static void +st_label_map (ClutterActor *actor) +{ + StLabelPrivate *priv = ST_LABEL (actor)->priv; + + CLUTTER_ACTOR_CLASS (st_label_parent_class)->map (actor); + + clutter_actor_map (priv->label); +} + +static void +st_label_unmap (ClutterActor *actor) +{ + StLabelPrivate *priv = ST_LABEL (actor)->priv; + + CLUTTER_ACTOR_CLASS (st_label_parent_class)->unmap (actor); + + clutter_actor_unmap (priv->label); +} + +static void +st_label_class_init (StLabelClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); + GParamSpec *pspec; + + g_type_class_add_private (klass, sizeof (StLabelPrivate)); + + gobject_class->set_property = st_label_set_property; + gobject_class->get_property = st_label_get_property; + + actor_class->paint = st_label_paint; + actor_class->allocate = st_label_allocate; + actor_class->get_preferred_width = st_label_get_preferred_width; + actor_class->get_preferred_height = st_label_get_preferred_height; + actor_class->map = st_label_map; + actor_class->unmap = st_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 +st_label_init (StLabel *label) +{ + StLabelPrivate *priv; + + label->priv = priv = ST_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 (st_label_style_changed), NULL); +} + +/** + * st_label_new: + * @text: text to set the label to + * + * Create a new #StLabel with the specified label + * + * Returns: a new #StLabel + */ +StWidget * +st_label_new (const gchar *text) +{ + if (text == NULL || *text == '\0') + return g_object_new (ST_TYPE_LABEL, NULL); + else + return g_object_new (ST_TYPE_LABEL, + "text", text, + NULL); +} + +/** + * st_label_get_text: + * @label: a #StLabel + * + * 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 * +st_label_get_text (StLabel *label) +{ + g_return_val_if_fail (ST_IS_LABEL (label), NULL); + + return clutter_text_get_text (CLUTTER_TEXT (label->priv->label)); +} + +/** + * st_label_set_text: + * @label: a #StLabel + * @text: text to set the label to + * + * Sets the text displayed on the label + */ +void +st_label_set_text (StLabel *label, + const gchar *text) +{ + StLabelPrivate *priv; + + g_return_if_fail (ST_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"); +} + +/** + * st_label_get_clutter_text: + * @label: a #StLabel + * + * Retrieve the internal #ClutterText so that extra parameters can be set + * + * Returns: the #ClutterText used by #StLabel. The label is owned by the + * #StLabel and should not be unref'ed by the application. + */ +ClutterActor* +st_label_get_clutter_text (StLabel *label) +{ + g_return_val_if_fail (ST_LABEL (label), NULL); + + return label->priv->label; +} diff --git a/src/st/st-label.h b/src/st/st-label.h new file mode 100644 index 000000000..fe9985ab1 --- /dev/null +++ b/src/st/st-label.h @@ -0,0 +1,75 @@ +/* + * st-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 + * + */ + +#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION) +#error "Only can be included directly.h" +#endif + +#ifndef __ST_LABEL_H__ +#define __ST_LABEL_H__ + +G_BEGIN_DECLS + +#include + +#define ST_TYPE_LABEL (st_label_get_type ()) +#define ST_LABEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_LABEL, StLabel)) +#define ST_IS_LABEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_LABEL)) +#define ST_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ST_TYPE_LABEL, StLabelClass)) +#define ST_IS_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ST_TYPE_LABEL)) +#define ST_LABEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ST_TYPE_LABEL, StLabelClass)) + +typedef struct _StLabel StLabel; +typedef struct _StLabelPrivate StLabelPrivate; +typedef struct _StLabelClass StLabelClass; + +/** + * StLabel: + * + * The contents of this structure is private and should only be accessed using + * the provided API. + */ +struct _StLabel +{ + /*< private >*/ + StWidget parent_instance; + + StLabelPrivate *priv; +}; + +struct _StLabelClass +{ + StWidgetClass parent_class; +}; + +GType st_label_get_type (void) G_GNUC_CONST; + +StWidget * st_label_new (const gchar *text); +G_CONST_RETURN gchar *st_label_get_text (StLabel *label); +void st_label_set_text (StLabel *label, + const gchar *text); +ClutterActor * st_label_get_clutter_text (StLabel *label); + +G_END_DECLS + +#endif /* __ST_LABEL_H__ */ diff --git a/tools/build/gnome-shell.modules b/tools/build/gnome-shell.modules index 095bc9d06..6395eb516 100644 --- a/tools/build/gnome-shell.modules +++ b/tools/build/gnome-shell.modules @@ -7,6 +7,8 @@ href="git://git.clutter-project.org/"/> + @@ -36,6 +38,13 @@ + + + + + + +