gnome-shell-3.6.3.1/src/st/st-label.c

No issues found

  1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
  2 /*
  3  * st-label.c: Plain label actor
  4  *
  5  * Copyright 2008,2009 Intel Corporation
  6  * Copyright 2009 Red Hat, Inc.
  7  * Copyright 2010 Florian Mç«Żllner
  8  *
  9  * This program is free software; you can redistribute it and/or modify it
 10  * under the terms and conditions of the GNU Lesser General Public License,
 11  * version 2.1, as published by the Free Software Foundation.
 12  *
 13  * This program is distributed in the hope it will be useful, but WITHOUT ANY
 14  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 15  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 16  * more details.
 17  *
 18  * You should have received a copy of the GNU Lesser General Public License
 19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
 20  */
 21 
 22 /**
 23  * SECTION:st-label
 24  * @short_description: Widget for displaying text
 25  *
 26  * #StLabel is a simple widget for displaying text. It derives from
 27  * #StWidget to add extra style and placement functionality over
 28  * #ClutterText. The internal #ClutterText is publicly accessibly to allow
 29  * applications to set further properties.
 30  */
 31 
 32 #ifdef HAVE_CONFIG_H
 33 #include "config.h"
 34 #endif
 35 
 36 #include <stdlib.h>
 37 #include <string.h>
 38 
 39 #include <glib.h>
 40 
 41 #include <clutter/clutter.h>
 42 
 43 #include "st-label.h"
 44 #include "st-private.h"
 45 #include "st-widget.h"
 46 
 47 #include <st/st-widget-accessible.h>
 48 
 49 enum
 50 {
 51   PROP_0,
 52 
 53   PROP_CLUTTER_TEXT,
 54   PROP_TEXT
 55 };
 56 
 57 #define ST_LABEL_GET_PRIVATE(obj)     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ST_TYPE_LABEL, StLabelPrivate))
 58 
 59 struct _StLabelPrivate
 60 {
 61   ClutterActor *label;
 62 
 63   CoglHandle    text_shadow_material;
 64   float         shadow_width;
 65   float         shadow_height;
 66 };
 67 
 68 G_DEFINE_TYPE (StLabel, st_label, ST_TYPE_WIDGET);
 69 
 70 static GType st_label_accessible_get_type (void) G_GNUC_CONST;
 71 
 72 static void
 73 st_label_set_property (GObject      *gobject,
 74                        guint         prop_id,
 75                        const GValue *value,
 76                        GParamSpec   *pspec)
 77 {
 78   StLabel *label = ST_LABEL (gobject);
 79 
 80   switch (prop_id)
 81     {
 82     case PROP_TEXT:
 83       st_label_set_text (label, g_value_get_string (value));
 84       break;
 85 
 86     default:
 87       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
 88       break;
 89     }
 90 }
 91 
 92 static void
 93 st_label_get_property (GObject    *gobject,
 94                        guint       prop_id,
 95                        GValue     *value,
 96                        GParamSpec *pspec)
 97 {
 98   StLabelPrivate *priv = ST_LABEL (gobject)->priv;
 99 
100   switch (prop_id)
101     {
102     case PROP_CLUTTER_TEXT:
103       g_value_set_object (value, priv->label);
104       break;
105 
106     case PROP_TEXT:
107       g_value_set_string (value, clutter_text_get_text (CLUTTER_TEXT (priv->label)));
108       break;
109 
110     default:
111       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
112       break;
113     }
114 }
115 
116 static void
117 st_label_style_changed (StWidget *self)
118 {
119   StLabelPrivate *priv = ST_LABEL(self)->priv;
120 
121   if (priv->text_shadow_material != COGL_INVALID_HANDLE)
122     {
123       cogl_handle_unref (priv->text_shadow_material);
124       priv->text_shadow_material = COGL_INVALID_HANDLE;
125     }
126 
127   _st_set_text_from_style ((ClutterText *)priv->label, st_widget_get_theme_node (self));
128 
129   ST_WIDGET_CLASS (st_label_parent_class)->style_changed (self);
130 }
131 
132 static void
133 st_label_get_preferred_width (ClutterActor *actor,
134                               gfloat        for_height,
135                               gfloat       *min_width_p,
136                               gfloat       *natural_width_p)
137 {
138   StLabelPrivate *priv = ST_LABEL (actor)->priv;
139   StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
140 
141   st_theme_node_adjust_for_height (theme_node, &for_height);
142 
143   clutter_actor_get_preferred_width (priv->label, for_height,
144                                      min_width_p,
145                                      natural_width_p);
146 
147   st_theme_node_adjust_preferred_width (theme_node, min_width_p, natural_width_p);
148 }
149 
150 static void
151 st_label_get_preferred_height (ClutterActor *actor,
152                                gfloat        for_width,
153                                gfloat       *min_height_p,
154                                gfloat       *natural_height_p)
155 {
156   StLabelPrivate *priv = ST_LABEL (actor)->priv;
157   StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
158 
159   st_theme_node_adjust_for_width (theme_node, &for_width);
160 
161   clutter_actor_get_preferred_height (priv->label, for_width,
162                                       min_height_p,
163                                       natural_height_p);
164 
165   st_theme_node_adjust_preferred_height (theme_node, min_height_p, natural_height_p);
166 }
167 
168 static void
169 st_label_allocate (ClutterActor          *actor,
170                    const ClutterActorBox *box,
171                    ClutterAllocationFlags flags)
172 {
173   StLabelPrivate *priv = ST_LABEL (actor)->priv;
174   StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
175   ClutterActorBox content_box;
176 
177   clutter_actor_set_allocation (actor, box, flags);
178 
179   st_theme_node_get_content_box (theme_node, box, &content_box);
180 
181   clutter_actor_allocate (priv->label, &content_box, flags);
182 }
183 
184 static void
185 st_label_dispose (GObject   *object)
186 {
187   StLabelPrivate *priv = ST_LABEL (object)->priv;
188 
189   if (priv->label)
190     {
191       clutter_actor_destroy (priv->label);
192       priv->label = NULL;
193     }
194 
195   if (priv->text_shadow_material != COGL_INVALID_HANDLE)
196     {
197       cogl_handle_unref (priv->text_shadow_material);
198       priv->text_shadow_material = COGL_INVALID_HANDLE;
199     }
200 
201   G_OBJECT_CLASS (st_label_parent_class)->dispose (object);
202 }
203 
204 static void
205 st_label_paint (ClutterActor *actor)
206 {
207   StLabelPrivate *priv = ST_LABEL (actor)->priv;
208   StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
209   StShadow *shadow_spec = st_theme_node_get_text_shadow (theme_node);
210 
211   st_widget_paint_background (ST_WIDGET (actor));
212 
213   if (shadow_spec)
214     {
215       ClutterActorBox allocation;
216       float width, height;
217 
218       clutter_actor_get_allocation_box (priv->label, &allocation);
219       clutter_actor_box_get_size (&allocation, &width, &height);
220 
221       allocation.x1 = allocation.y1 = 0;
222       allocation.x2 = width;
223       allocation.y2 = height;
224 
225       if (priv->text_shadow_material == COGL_INVALID_HANDLE ||
226           width != priv->shadow_width ||
227           height != priv->shadow_height)
228         {
229           CoglHandle material;
230 
231           if (priv->text_shadow_material != COGL_INVALID_HANDLE)
232             cogl_handle_unref (priv->text_shadow_material);
233 
234           material = _st_create_shadow_material_from_actor (shadow_spec,
235                                                             priv->label);
236 
237           priv->shadow_width = width;
238           priv->shadow_height = height;
239           priv->text_shadow_material = material;
240         }
241 
242       if (priv->text_shadow_material != COGL_INVALID_HANDLE)
243         _st_paint_shadow_with_opacity (shadow_spec,
244                                        priv->text_shadow_material,
245                                        &allocation,
246                                        clutter_actor_get_paint_opacity (priv->label));
247     }
248 
249   clutter_actor_paint (priv->label);
250 }
251 
252 static void
253 st_label_class_init (StLabelClass *klass)
254 {
255   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
256   ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
257   StWidgetClass *widget_class = ST_WIDGET_CLASS (klass);
258   GParamSpec *pspec;
259 
260   g_type_class_add_private (klass, sizeof (StLabelPrivate));
261 
262   gobject_class->set_property = st_label_set_property;
263   gobject_class->get_property = st_label_get_property;
264   gobject_class->dispose = st_label_dispose;
265 
266   actor_class->paint = st_label_paint;
267   actor_class->allocate = st_label_allocate;
268   actor_class->get_preferred_width = st_label_get_preferred_width;
269   actor_class->get_preferred_height = st_label_get_preferred_height;
270 
271   widget_class->style_changed = st_label_style_changed;
272   widget_class->get_accessible_type = st_label_accessible_get_type;
273 
274   pspec = g_param_spec_object ("clutter-text",
275 			       "Clutter Text",
276 			       "Internal ClutterText actor",
277 			       CLUTTER_TYPE_TEXT,
278 			       G_PARAM_READABLE);
279   g_object_class_install_property (gobject_class, PROP_CLUTTER_TEXT, pspec);
280 
281   pspec = g_param_spec_string ("text",
282                                "Text",
283                                "Text of the label",
284                                NULL, G_PARAM_READWRITE);
285   g_object_class_install_property (gobject_class, PROP_TEXT, pspec);
286 
287 }
288 
289 static void
290 st_label_init (StLabel *label)
291 {
292   StLabelPrivate *priv;
293 
294   label->priv = priv = ST_LABEL_GET_PRIVATE (label);
295 
296   label->priv->label = g_object_new (CLUTTER_TYPE_TEXT,
297                                      "ellipsize", PANGO_ELLIPSIZE_END,
298                                      NULL);
299   label->priv->text_shadow_material = COGL_INVALID_HANDLE;
300   label->priv->shadow_width = -1.;
301   label->priv->shadow_height = -1.;
302 
303   clutter_actor_add_child (CLUTTER_ACTOR (label), priv->label);
304 }
305 
306 /**
307  * st_label_new:
308  * @text: text to set the label to
309  *
310  * Create a new #StLabel with the specified label
311  *
312  * Returns: a new #StLabel
313  */
314 StWidget *
315 st_label_new (const gchar *text)
316 {
317   if (text == NULL || *text == '\0')
318     return g_object_new (ST_TYPE_LABEL, NULL);
319   else
320     return g_object_new (ST_TYPE_LABEL,
321                          "text", text,
322                          NULL);
323 }
324 
325 /**
326  * st_label_get_text:
327  * @label: a #StLabel
328  *
329  * Get the text displayed on the label
330  *
331  * Returns: the text for the label. This must not be freed by the application
332  */
333 const gchar *
334 st_label_get_text (StLabel *label)
335 {
336   g_return_val_if_fail (ST_IS_LABEL (label), NULL);
337 
338   return clutter_text_get_text (CLUTTER_TEXT (label->priv->label));
339 }
340 
341 /**
342  * st_label_set_text:
343  * @label: a #StLabel
344  * @text: text to set the label to
345  *
346  * Sets the text displayed on the label
347  */
348 void
349 st_label_set_text (StLabel     *label,
350                    const gchar *text)
351 {
352   StLabelPrivate *priv;
353   ClutterText *ctext;
354 
355   g_return_if_fail (ST_IS_LABEL (label));
356   g_return_if_fail (text != NULL);
357 
358   priv = label->priv;
359   ctext = CLUTTER_TEXT (priv->label);
360 
361   if (clutter_text_get_editable (ctext) ||
362       g_strcmp0 (clutter_text_get_text (ctext), text) != 0)
363     {
364       if (priv->text_shadow_material != COGL_INVALID_HANDLE)
365         {
366           cogl_handle_unref (priv->text_shadow_material);
367           priv->text_shadow_material = COGL_INVALID_HANDLE;
368         }
369 
370       clutter_text_set_text (ctext, text);
371 
372       g_object_notify (G_OBJECT (label), "text");
373     }
374 }
375 
376 /**
377  * st_label_get_clutter_text:
378  * @label: a #StLabel
379  *
380  * Retrieve the internal #ClutterText so that extra parameters can be set
381  *
382  * Returns: (transfer none): ethe #ClutterText used by #StLabel. The label
383  * is owned by the #StLabel and should not be unref'ed by the application.
384  */
385 ClutterActor*
386 st_label_get_clutter_text (StLabel *label)
387 {
388   g_return_val_if_fail (ST_LABEL (label), NULL);
389 
390   return label->priv->label;
391 }
392 
393 
394 /******************************************************************************/
395 /*************************** ACCESSIBILITY SUPPORT ****************************/
396 /******************************************************************************/
397 
398 #define ST_TYPE_LABEL_ACCESSIBLE st_label_accessible_get_type ()
399 
400 #define ST_LABEL_ACCESSIBLE(obj) \
401   (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
402   ST_TYPE_LABEL_ACCESSIBLE, StLabelAccessible))
403 
404 #define ST_IS_LABEL_ACCESSIBLE(obj) \
405   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
406   ST_TYPE_LABEL_ACCESSIBLE))
407 
408 #define ST_LABEL_ACCESSIBLE_CLASS(klass) \
409   (G_TYPE_CHECK_CLASS_CAST ((klass), \
410   ST_TYPE_LABEL_ACCESSIBLE, StLabelAccessibleClass))
411 
412 #define ST_IS_LABEL_ACCESSIBLE_CLASS(klass) \
413   (G_TYPE_CHECK_CLASS_TYPE ((klass), \
414   ST_TYPE_LABEL_ACCESSIBLE))
415 
416 #define ST_LABEL_ACCESSIBLE_GET_CLASS(obj) \
417   (G_TYPE_INSTANCE_GET_CLASS ((obj), \
418   ST_TYPE_LABEL_ACCESSIBLE, StLabelAccessibleClass))
419 
420 typedef struct _StLabelAccessible  StLabelAccessible;
421 typedef struct _StLabelAccessibleClass  StLabelAccessibleClass;
422 
423 struct _StLabelAccessible
424 {
425   StWidgetAccessible parent;
426 };
427 
428 struct _StLabelAccessibleClass
429 {
430   StWidgetAccessibleClass parent_class;
431 };
432 
433 static void st_label_accessible_class_init (StLabelAccessibleClass *klass);
434 static void st_label_accessible_init       (StLabelAccessible *label);
435 
436 /* AtkObject */
437 static void          st_label_accessible_initialize (AtkObject *obj,
438                                                      gpointer   data);
439 static const gchar * st_label_accessible_get_name   (AtkObject *obj);
440 
441 G_DEFINE_TYPE (StLabelAccessible, st_label_accessible, ST_TYPE_WIDGET_ACCESSIBLE)
442 
443 static void
444 st_label_accessible_class_init (StLabelAccessibleClass *klass)
445 {
446   AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass);
447 
448   atk_class->initialize = st_label_accessible_initialize;
449   atk_class->get_name = st_label_accessible_get_name;
450 }
451 
452 static void
453 st_label_accessible_init (StLabelAccessible *self)
454 {
455   /* initialization done on AtkObject->initialize */
456 }
457 
458 static void
459 label_text_notify_cb (StLabel    *label,
460                       GParamSpec *pspec,
461                       AtkObject  *accessible)
462 {
463   g_object_notify (G_OBJECT (accessible), "accessible-name");
464 }
465 
466 static void
467 st_label_accessible_initialize (AtkObject *obj,
468                                 gpointer   data)
469 {
470   ATK_OBJECT_CLASS (st_label_accessible_parent_class)->initialize (obj, data);
471 
472   g_signal_connect (data, "notify::text",
473                     G_CALLBACK (label_text_notify_cb),
474                     obj);
475 
476   obj->role = ATK_ROLE_LABEL;
477 }
478 
479 static const gchar *
480 st_label_accessible_get_name (AtkObject *obj)
481 {
482   const gchar *name = NULL;
483 
484   g_return_val_if_fail (ST_IS_LABEL_ACCESSIBLE (obj), NULL);
485 
486   name = ATK_OBJECT_CLASS (st_label_accessible_parent_class)->get_name (obj);
487   if (name == NULL)
488     {
489       ClutterActor *actor = NULL;
490 
491       actor = CLUTTER_ACTOR (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (obj)));
492 
493       if (actor == NULL || st_widget_has_style_class_name (ST_WIDGET (actor), "hidden"))
494         name = NULL;
495       else
496         name = st_label_get_text (ST_LABEL (actor));
497     }
498 
499   return name;
500 }