1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
3
* st-widget.c: Base class for St actors
5
* Copyright 2007 OpenedHand
6
* Copyright 2008, 2009 Intel Corporation.
8
* This program is free software; you can redistribute it and/or modify it
9
* under the terms and conditions of the GNU Lesser General Public License,
10
* version 2.1, as published by the Free Software Foundation.
12
* This program is distributed in the hope it will be useful, but WITHOUT ANY
13
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
17
* You should have received a copy of the GNU Lesser General Public License
18
* along with this program; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
20
* Boston, MA 02111-1307, USA.
22
* Written by: Emmanuele Bassi <ebassi@openedhand.com>
23
* Thomas Wood <thomas@linux.intel.com>
34
#include <clutter/clutter.h>
36
#include "st-widget.h"
38
#include "st-marshal.h"
39
#include "st-private.h"
40
#include "st-texture-cache.h"
41
#include "st-texture-frame.h"
42
#include "st-theme-context.h"
43
#include "st-tooltip.h"
45
#include <big/rectangle.h>
48
* Forward declaration for sake of StWidgetChild
50
struct _StWidgetPrivate
53
StThemeNode *theme_node;
58
ClutterActor *border_image;
59
ClutterActor *background_image;
60
ClutterColor bg_color;
62
gboolean is_stylable : 1;
63
gboolean has_tooltip : 1;
64
gboolean is_style_dirty : 1;
65
gboolean draw_bg_color : 1;
72
* @short_description: Base class for stylable actors
74
* #StWidget is a simple abstract class on top of #ClutterActor. It
75
* provides basic themeing properties.
77
* Actors in the St library should subclass #StWidget if they plan
78
* to obey to a certain #StStyle.
103
static guint signals[LAST_SIGNAL] = { 0, };
105
G_DEFINE_ABSTRACT_TYPE (StWidget, st_widget, CLUTTER_TYPE_ACTOR);
107
#define ST_WIDGET_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ST_TYPE_WIDGET, StWidgetPrivate))
109
static void st_widget_recompute_style (StWidget *widget,
110
StThemeNode *old_theme_node);
113
st_widget_set_property (GObject *gobject,
118
StWidget *actor = ST_WIDGET (gobject);
123
st_widget_set_theme (actor, g_value_get_object (value));
126
case PROP_PSEUDO_CLASS:
127
st_widget_set_style_pseudo_class (actor, g_value_get_string (value));
130
case PROP_STYLE_CLASS:
131
st_widget_set_style_class_name (actor, g_value_get_string (value));
135
st_widget_set_style (actor, g_value_get_string (value));
139
if (actor->priv->is_stylable != g_value_get_boolean (value))
141
actor->priv->is_stylable = g_value_get_boolean (value);
142
clutter_actor_queue_relayout ((ClutterActor *) gobject);
146
case PROP_HAS_TOOLTIP:
147
st_widget_set_has_tooltip (actor, g_value_get_boolean (value));
150
case PROP_TOOLTIP_TEXT:
151
st_widget_set_tooltip_text (actor, g_value_get_string (value));
155
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
161
st_widget_get_property (GObject *gobject,
166
StWidget *actor = ST_WIDGET (gobject);
167
StWidgetPrivate *priv = actor->priv;
172
g_value_set_object (value, priv->theme);
175
case PROP_PSEUDO_CLASS:
176
g_value_set_string (value, priv->pseudo_class);
179
case PROP_STYLE_CLASS:
180
g_value_set_string (value, priv->style_class);
184
g_value_set_string (value, priv->inline_style);
188
g_value_set_boolean (value, priv->is_stylable);
191
case PROP_HAS_TOOLTIP:
192
g_value_set_boolean (value, priv->has_tooltip);
195
case PROP_TOOLTIP_TEXT:
196
g_value_set_string (value, st_widget_get_tooltip_text (actor));
200
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
206
st_widget_dispose (GObject *gobject)
208
StWidget *actor = ST_WIDGET (gobject);
209
StWidgetPrivate *priv = ST_WIDGET (actor)->priv;
213
g_object_unref (priv->theme);
217
if (priv->border_image)
219
clutter_actor_unparent (priv->border_image);
220
priv->border_image = NULL;
225
ClutterContainer *parent;
226
ClutterActor *tooltip = CLUTTER_ACTOR (priv->tooltip);
228
/* this is just a little bit awkward because the tooltip is parented
229
* on the stage, but we still want to "own" it */
230
parent = CLUTTER_CONTAINER (clutter_actor_get_parent (tooltip));
233
clutter_container_remove_actor (parent, tooltip);
235
priv->tooltip = NULL;
238
G_OBJECT_CLASS (st_widget_parent_class)->dispose (gobject);
242
st_widget_finalize (GObject *gobject)
244
StWidgetPrivate *priv = ST_WIDGET (gobject)->priv;
246
g_free (priv->style_class);
247
g_free (priv->pseudo_class);
249
G_OBJECT_CLASS (st_widget_parent_class)->finalize (gobject);
253
st_widget_allocate (ClutterActor *actor,
254
const ClutterActorBox *box,
255
ClutterAllocationFlags flags)
257
StWidgetPrivate *priv = ST_WIDGET (actor)->priv;
258
ClutterActorClass *klass;
259
ClutterGeometry area;
260
ClutterVertex in_v, out_v;
262
klass = CLUTTER_ACTOR_CLASS (st_widget_parent_class);
263
klass->allocate (actor, box, flags);
265
/* update tooltip position */
268
in_v.x = in_v.y = in_v.z = 0;
269
clutter_actor_apply_transform_to_point (actor, &in_v, &out_v);
273
in_v.x = box->x2 - box->x1;
274
in_v.y = box->y2 - box->y1;
275
clutter_actor_apply_transform_to_point (actor, &in_v, &out_v);
276
area.width = out_v.x - area.x;
277
area.height = out_v.y - area.y;
279
st_tooltip_set_tip_area (priv->tooltip, &area);
284
if (priv->border_image)
286
ClutterActorBox frame_box = {
293
clutter_actor_allocate (CLUTTER_ACTOR (priv->border_image),
298
if (priv->background_image)
300
ClutterActorBox frame_box = {
301
0, 0, box->x2 - box->x1, box->y2 - box->y1
305
clutter_actor_get_size (CLUTTER_ACTOR (priv->background_image), &w, &h);
307
/* scale the background into the allocated bounds */
308
if (w > frame_box.x2 || h > frame_box.y2)
310
gint new_h, new_w, offset;
313
box_w = (int) frame_box.x2;
314
box_h = (int) frame_box.y2;
317
new_h = (int)((h / w) * ((gfloat) box_w));
318
new_w = (int)((w / h) * ((gfloat) box_h));
322
/* center for new width */
323
offset = ((box_w) - new_w) * 0.5;
324
frame_box.x1 = offset;
325
frame_box.x2 = offset + new_w;
327
frame_box.y2 = box_h;
331
/* center for new height */
332
offset = ((box_h) - new_h) * 0.5;
333
frame_box.y1 = offset;
334
frame_box.y2 = offset + new_h;
336
frame_box.x2 = box_w;
342
/* center the background on the widget */
343
frame_box.x1 = (int)(((box->x2 - box->x1) / 2) - (w / 2));
344
frame_box.y1 = (int)(((box->y2 - box->y1) / 2) - (h / 2));
345
frame_box.x2 = frame_box.x1 + w;
346
frame_box.y2 = frame_box.y1 + h;
349
clutter_actor_allocate (CLUTTER_ACTOR (priv->background_image),
356
st_widget_real_draw_background (StWidget *self)
358
StWidgetPrivate *priv = self->priv;
360
/* Default implementation just draws the background
361
* colour and the image on top
363
if (priv->draw_bg_color)
365
ClutterActor *actor = CLUTTER_ACTOR (self);
366
ClutterActorBox allocation = { 0, };
367
ClutterColor bg_color = priv->bg_color;
370
bg_color.alpha = clutter_actor_get_paint_opacity (actor)
374
clutter_actor_get_allocation_box (actor, &allocation);
376
w = allocation.x2 - allocation.x1;
377
h = allocation.y2 - allocation.y1;
379
cogl_set_source_color4ub (bg_color.red,
383
cogl_rectangle (0, 0, w, h);
386
if (priv->border_image)
387
clutter_actor_paint (priv->border_image);
391
st_widget_paint (ClutterActor *self)
393
StWidgetPrivate *priv = ST_WIDGET (self)->priv;
394
StWidgetClass *klass = ST_WIDGET_GET_CLASS (self);
396
klass->draw_background (ST_WIDGET (self));
398
if (priv->background_image != NULL)
399
clutter_actor_paint (priv->background_image);
403
st_widget_parent_set (ClutterActor *widget,
404
ClutterActor *old_parent)
406
ClutterActorClass *parent_class;
407
ClutterActor *new_parent;
409
parent_class = CLUTTER_ACTOR_CLASS (st_widget_parent_class);
410
if (parent_class->parent_set)
411
parent_class->parent_set (widget, old_parent);
413
new_parent = clutter_actor_get_parent (widget);
415
/* don't send the style changed signal if we no longer have a parent actor */
417
st_widget_style_changed (ST_WIDGET (widget));
421
st_widget_map (ClutterActor *actor)
423
StWidgetPrivate *priv = ST_WIDGET (actor)->priv;
425
CLUTTER_ACTOR_CLASS (st_widget_parent_class)->map (actor);
427
st_widget_ensure_style ((StWidget*) actor);
429
if (priv->border_image)
430
clutter_actor_map (priv->border_image);
432
if (priv->background_image)
433
clutter_actor_map (priv->background_image);
436
clutter_actor_map ((ClutterActor *) priv->tooltip);
440
st_widget_unmap (ClutterActor *actor)
442
StWidgetPrivate *priv = ST_WIDGET (actor)->priv;
444
CLUTTER_ACTOR_CLASS (st_widget_parent_class)->unmap (actor);
446
if (priv->border_image)
447
clutter_actor_unmap (priv->border_image);
449
if (priv->background_image)
450
clutter_actor_unmap (priv->background_image);
453
clutter_actor_unmap ((ClutterActor *) priv->tooltip);
456
static void notify_children_of_style_change (ClutterContainer *container);
459
notify_children_of_style_change_foreach (ClutterActor *actor,
462
if (ST_IS_WIDGET (actor))
463
st_widget_style_changed (ST_WIDGET (actor));
464
else if (CLUTTER_IS_CONTAINER (actor))
465
notify_children_of_style_change ((ClutterContainer *)actor);
469
notify_children_of_style_change (ClutterContainer *container)
471
/* notify our children that their parent stylable has changed */
472
clutter_container_foreach (container,
473
notify_children_of_style_change_foreach,
478
st_widget_real_style_changed (StWidget *self)
480
StWidgetPrivate *priv = ST_WIDGET (self)->priv;
481
StThemeNode *theme_node;
482
StBorderImage *border_image;
483
StTextureCache *texture_cache;
484
ClutterTexture *texture;
485
const char *bg_file = NULL;
486
gboolean relayout_needed = FALSE;
487
gboolean has_changed = FALSE;
489
guint border_width = 0;
490
guint border_radius = 0;
491
ClutterColor border_color = { 0, };
495
/* application has request this widget is not stylable */
496
if (!priv->is_stylable)
499
theme_node = st_widget_get_theme_node (self);
501
st_theme_node_get_background_color (theme_node, &color);
502
if (!clutter_color_equal (&color, &priv->bg_color))
504
priv->bg_color = color;
505
priv->draw_bg_color = color.alpha != 0;
509
if (priv->border_image)
511
clutter_actor_unparent (priv->border_image);
512
priv->border_image = NULL;
515
if (priv->background_image)
517
clutter_actor_unparent (priv->background_image);
518
priv->background_image = NULL;
521
texture_cache = st_texture_cache_get_default ();
523
/* StThemeNode supports different widths and colors for different sides
524
* of the border, and different radii for the different corners. We take
525
* the different border widths into account when positioning, but our current
526
* drawing code (using BigRectangle) can only handle a single width, color,
527
* and radius, so we arbitrarily pick the first non-zero width and radius,
530
for (side = ST_SIDE_TOP; side <= ST_SIDE_LEFT; side++)
532
double width = st_theme_node_get_border_width (theme_node, side);
535
border_width = (int)(0.5 + width);
536
st_theme_node_get_border_color (theme_node, side, &border_color);
541
for (corner = ST_CORNER_TOPLEFT; corner <= ST_CORNER_BOTTOMLEFT; corner++)
543
double radius = st_theme_node_get_border_radius (theme_node, corner);
546
border_radius = (int)(0.5 + radius);
551
/* Rough notes about the relationship of borders and backgrounds in CSS3;
552
* see http://www.w3.org/TR/css3-background/ for more accurate details.
554
* - Things are drawn in 4 layers, from the bottom:
557
* Border color or border image
559
* - The background color and image extend to and are clipped by the
560
* edge of the border area, so will be rounded if the border is rounded.
561
* (CSS3 background-clip property modifies this)
562
* - The border image replaces what would normally be drawn by the border
563
* - The border image is not clipped by a rounded border-radius
564
* - The border radius rounds the background even if the border is
565
* zero width or a border image is being used.
567
* Deviations from the above as implemented here:
568
* - The combination of border image and a non-zero border radius is
569
* not supported; the background color will be drawn with square
571
* - The background image is drawn above the border color or image,
573
* - We don't clip the background image to the (rounded) border area.
575
* The first two allow us always draw with no more than single border_image
576
* and a single background image above it.
579
border_image = st_theme_node_get_border_image (theme_node);
582
const char *filename;
583
gint border_left, border_right, border_top, border_bottom;
586
filename = st_border_image_get_filename (border_image);
588
/* `border-image' takes precedence over `background-image'.
589
* Firefox lets the background-image shine thru when border-image has
590
* alpha an channel, maybe that would be an option for the future. */
591
texture = st_texture_cache_get_texture (texture_cache,
594
clutter_texture_get_base_size (CLUTTER_TEXTURE (texture),
597
st_border_image_get_borders (border_image,
598
&border_left, &border_right, &border_top, &border_bottom);
600
priv->border_image = st_texture_frame_new (texture,
605
clutter_actor_set_parent (priv->border_image, CLUTTER_ACTOR (self));
608
relayout_needed = TRUE;
610
else if ((border_width > 0 && border_color.alpha != 0) ||
611
(border_radius > 0 && priv->bg_color.alpha != 0))
613
priv->draw_bg_color = FALSE;
614
priv->border_image = g_object_new (BIG_TYPE_RECTANGLE,
615
"color", &priv->bg_color,
616
"border-width", border_width,
617
"border-color", &border_color,
618
"corner-radius", border_radius,
621
clutter_actor_set_parent (priv->border_image, CLUTTER_ACTOR (self));
624
relayout_needed = TRUE;
627
bg_file = st_theme_node_get_background_image (theme_node);
630
texture = st_texture_cache_get_texture (texture_cache, bg_file);
631
priv->background_image = (ClutterActor*) texture;
633
if (priv->background_image != NULL)
635
clutter_actor_set_parent (priv->background_image,
636
CLUTTER_ACTOR (self));
639
g_warning ("Could not load %s", bg_file);
642
relayout_needed = TRUE;
645
/* If there are any properties above that need to cause a relayout thay
646
* should set this flag.
651
clutter_actor_queue_relayout ((ClutterActor *) self);
653
clutter_actor_queue_redraw ((ClutterActor *) self);
656
if (CLUTTER_IS_CONTAINER (self))
657
notify_children_of_style_change ((ClutterContainer *)self);
661
st_widget_style_changed (StWidget *widget)
663
StThemeNode *old_theme_node = NULL;
665
widget->priv->is_style_dirty = TRUE;
666
if (widget->priv->theme_node)
668
old_theme_node = widget->priv->theme_node;
669
widget->priv->theme_node = NULL;
672
/* update the style only if we are mapped */
673
if (CLUTTER_ACTOR_IS_MAPPED (CLUTTER_ACTOR (widget)))
674
st_widget_recompute_style (widget, old_theme_node);
677
g_object_unref (old_theme_node);
681
on_theme_context_changed (StThemeContext *context,
684
notify_children_of_style_change (CLUTTER_CONTAINER (stage));
688
get_root_theme_node (ClutterStage *stage)
690
StThemeContext *context = st_theme_context_get_for_stage (stage);
692
if (!g_object_get_data (G_OBJECT (context), "st-theme-initialized"))
694
g_object_set_data (G_OBJECT (context), "st-theme-initialized", GUINT_TO_POINTER (1));
695
g_signal_connect (G_OBJECT (context), "changed",
696
G_CALLBACK (on_theme_context_changed), stage);
699
return st_theme_context_get_root_node (context);
703
* st_widget_get_theme_node:
704
* @widget: a #StWidget
706
* Gets the theme node holding style information for the widget.
707
* The theme node is used to access standard and custom CSS
708
* properties of the widget.
710
* Return value: (transfer none): the theme node for the widget.
711
* This is owned by the widget. When attributes of the widget
712
* or the environment that affect the styling change (for example
713
* the style_class property of the widget), it will be recreated,
714
* and the ::style-changed signal will be emitted on the widget.
717
st_widget_get_theme_node (StWidget *widget)
719
StWidgetPrivate *priv = widget->priv;
721
if (priv->theme_node == NULL)
723
StThemeNode *parent_node = NULL;
724
ClutterStage *stage = NULL;
725
ClutterActor *parent;
727
parent = clutter_actor_get_parent (CLUTTER_ACTOR (widget));
728
while (parent != NULL)
730
if (parent_node == NULL && ST_IS_WIDGET (parent))
731
parent_node = st_widget_get_theme_node (ST_WIDGET (parent));
732
else if (CLUTTER_IS_STAGE (parent))
733
stage = CLUTTER_STAGE (parent);
735
parent = clutter_actor_get_parent (parent);
740
g_warning ("st_widget_get_theme_node called on a widget not in a stage");
741
stage = CLUTTER_STAGE (clutter_stage_get_default ());
744
if (parent_node == NULL)
745
parent_node = get_root_theme_node (CLUTTER_STAGE (stage));
747
priv->theme_node = st_theme_node_new (st_theme_context_get_for_stage (stage),
748
parent_node, priv->theme,
749
G_OBJECT_TYPE (widget),
750
clutter_actor_get_name (CLUTTER_ACTOR (widget)),
756
return priv->theme_node;
760
st_widget_enter (ClutterActor *actor,
761
ClutterCrossingEvent *event)
763
StWidgetPrivate *priv = ST_WIDGET (actor)->priv;
766
if (priv->has_tooltip)
767
st_widget_show_tooltip ((StWidget*) actor);
769
if (CLUTTER_ACTOR_CLASS (st_widget_parent_class)->enter_event)
770
return CLUTTER_ACTOR_CLASS (st_widget_parent_class)->enter_event (actor, event);
776
st_widget_leave (ClutterActor *actor,
777
ClutterCrossingEvent *event)
779
StWidgetPrivate *priv = ST_WIDGET (actor)->priv;
781
if (priv->has_tooltip)
782
st_tooltip_hide (priv->tooltip);
784
if (CLUTTER_ACTOR_CLASS (st_widget_parent_class)->leave_event)
785
return CLUTTER_ACTOR_CLASS (st_widget_parent_class)->leave_event (actor, event);
791
st_widget_hide (ClutterActor *actor)
793
StWidget *widget = (StWidget *) actor;
795
/* hide the tooltip, if there is one */
796
if (widget->priv->tooltip)
797
st_tooltip_hide (ST_TOOLTIP (widget->priv->tooltip));
799
CLUTTER_ACTOR_CLASS (st_widget_parent_class)->hide (actor);
805
st_widget_class_init (StWidgetClass *klass)
807
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
808
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
811
g_type_class_add_private (klass, sizeof (StWidgetPrivate));
813
gobject_class->set_property = st_widget_set_property;
814
gobject_class->get_property = st_widget_get_property;
815
gobject_class->dispose = st_widget_dispose;
816
gobject_class->finalize = st_widget_finalize;
818
actor_class->allocate = st_widget_allocate;
819
actor_class->paint = st_widget_paint;
820
actor_class->parent_set = st_widget_parent_set;
821
actor_class->map = st_widget_map;
822
actor_class->unmap = st_widget_unmap;
824
actor_class->enter_event = st_widget_enter;
825
actor_class->leave_event = st_widget_leave;
826
actor_class->hide = st_widget_hide;
828
klass->draw_background = st_widget_real_draw_background;
829
klass->style_changed = st_widget_real_style_changed;
832
* StWidget:pseudo-class:
834
* The pseudo-class of the actor. Typical values include "hover", "active",
837
g_object_class_install_property (gobject_class,
839
g_param_spec_string ("pseudo-class",
841
"Pseudo class for styling",
843
ST_PARAM_READWRITE));
845
* StWidget:style-class:
847
* The style-class of the actor for use in styling.
849
g_object_class_install_property (gobject_class,
851
g_param_spec_string ("style-class",
853
"Style class for styling",
855
ST_PARAM_READWRITE));
860
* Inline style information for the actor as a ';'-separated list of
863
g_object_class_install_property (gobject_class,
865
g_param_spec_string ("style",
867
"Inline style string",
869
ST_PARAM_READWRITE));
874
* A theme set on this actor overriding the global theming for this actor
875
* and its descendants
877
g_object_class_install_property (gobject_class,
879
g_param_spec_object ("theme",
883
ST_PARAM_READWRITE));
888
* Enable or disable styling of the widget
890
pspec = g_param_spec_boolean ("stylable",
892
"Whether the table should be styled",
895
g_object_class_install_property (gobject_class,
900
* StWidget:has-tooltip:
902
* Determines whether the widget has a tooltip. If set to TRUE, causes the
903
* widget to monitor enter and leave events (i.e. sets the widget reactive).
905
pspec = g_param_spec_boolean ("has-tooltip",
907
"Determines whether the widget has a tooltip",
910
g_object_class_install_property (gobject_class,
916
* StWidget:tooltip-text:
918
* text displayed on the tooltip
920
pspec = g_param_spec_string ("tooltip-text",
922
"Text displayed on the tooltip",
925
g_object_class_install_property (gobject_class, PROP_TOOLTIP_TEXT, pspec);
928
* StWidget::style-changed:
930
* Emitted when the style information that the widget derives from the
933
signals[STYLE_CHANGED] =
934
g_signal_new ("style-changed",
935
G_TYPE_FROM_CLASS (klass),
937
G_STRUCT_OFFSET (StWidgetClass, style_changed),
939
_st_marshal_VOID__VOID,
944
* st_widget_set_theme:
945
* @actor: a #StWidget
946
* @theme: a new style class string
948
* Overrides the theme that would be inherited from the actor's parent
949
* or the stage with an entirely new theme (set of stylesheets).
952
st_widget_set_theme (StWidget *actor,
955
StWidgetPrivate *priv = actor->priv;
957
g_return_if_fail (ST_IS_WIDGET (actor));
961
if (theme !=priv->theme)
964
g_object_unref (priv->theme);
965
priv->theme = g_object_ref (priv->theme);
967
st_widget_style_changed (actor);
969
g_object_notify (G_OBJECT (actor), "theme");
974
* st_widget_get_theme:
975
* @actor: a #StWidget
977
* Gets the overriding theme set on the actor. See st_widget_set_theme()
979
* Return value: (transfer none): the overriding theme, or %NULL
982
st_widget_get_theme (StWidget *actor)
984
g_return_val_if_fail (ST_IS_WIDGET (actor), NULL);
986
return actor->priv->theme;
990
* st_widget_set_style_class_name:
991
* @actor: a #StWidget
992
* @style_class: a new style class string
994
* Set the style class name
997
st_widget_set_style_class_name (StWidget *actor,
998
const gchar *style_class)
1000
StWidgetPrivate *priv = actor->priv;
1002
g_return_if_fail (ST_IS_WIDGET (actor));
1006
if (g_strcmp0 (style_class, priv->style_class))
1008
g_free (priv->style_class);
1009
priv->style_class = g_strdup (style_class);
1011
st_widget_style_changed (actor);
1013
g_object_notify (G_OBJECT (actor), "style-class");
1019
* st_widget_get_style_class_name:
1020
* @actor: a #StWidget
1022
* Get the current style class name
1024
* Returns: the class name string. The string is owned by the #StWidget and
1025
* should not be modified or freed.
1028
st_widget_get_style_class_name (StWidget *actor)
1030
g_return_val_if_fail (ST_IS_WIDGET (actor), NULL);
1032
return actor->priv->style_class;
1036
* st_widget_get_style_pseudo_class:
1037
* @actor: a #StWidget
1039
* Get the current style pseudo class
1041
* Returns: the pseudo class string. The string is owned by the #StWidget and
1042
* should not be modified or freed.
1045
st_widget_get_style_pseudo_class (StWidget *actor)
1047
g_return_val_if_fail (ST_IS_WIDGET (actor), NULL);
1049
return actor->priv->pseudo_class;
1053
* st_widget_set_style_pseudo_class:
1054
* @actor: a #StWidget
1055
* @pseudo_class: a new pseudo class string
1057
* Set the style pseudo class
1060
st_widget_set_style_pseudo_class (StWidget *actor,
1061
const gchar *pseudo_class)
1063
StWidgetPrivate *priv;
1065
g_return_if_fail (ST_IS_WIDGET (actor));
1069
if (g_strcmp0 (pseudo_class, priv->pseudo_class))
1071
g_free (priv->pseudo_class);
1072
priv->pseudo_class = g_strdup (pseudo_class);
1074
st_widget_style_changed (actor);
1076
g_object_notify (G_OBJECT (actor), "pseudo-class");
1081
* st_widget_set_style:
1082
* @actor: a #StWidget
1083
* @style_class: (allow-none): a inline style string, or %NULL
1085
* Set the inline style string for this widget. The inline style string is an
1086
* optional ';'-separated list of CSS properties that override the style as
1087
* determined from the stylesheets of the current theme.
1090
st_widget_set_style (StWidget *actor,
1093
StWidgetPrivate *priv = actor->priv;
1095
g_return_if_fail (ST_IS_WIDGET (actor));
1099
if (g_strcmp0 (style, priv->inline_style))
1101
g_free (priv->inline_style);
1102
priv->inline_style = g_strdup (style);
1104
st_widget_style_changed (actor);
1106
g_object_notify (G_OBJECT (actor), "style");
1111
* st_widget_get_style:
1112
* @actor: a #StWidget
1114
* Get the current inline style string. See st_widget_set_style().
1116
* Returns: The inline style string, or %NULL. The string is owned by the
1117
* #StWidget and should not be modified or freed.
1120
st_widget_get_style (StWidget *actor)
1122
g_return_val_if_fail (ST_IS_WIDGET (actor), NULL);
1124
return actor->priv->inline_style;
1128
st_widget_name_notify (StWidget *widget,
1132
st_widget_style_changed (widget);
1136
st_widget_init (StWidget *actor)
1138
StWidgetPrivate *priv;
1140
actor->priv = priv = ST_WIDGET_GET_PRIVATE (actor);
1141
priv->is_stylable = TRUE;
1143
/* connect style changed */
1144
g_signal_connect (actor, "notify::name", G_CALLBACK (st_widget_name_notify), NULL);
1148
st_widget_recompute_style (StWidget *widget,
1149
StThemeNode *old_theme_node)
1151
StThemeNode *new_theme_node = st_widget_get_theme_node (widget);
1153
if (!old_theme_node ||
1154
!st_theme_node_geometry_equal (old_theme_node, new_theme_node))
1155
clutter_actor_queue_relayout ((ClutterActor *) widget);
1157
g_signal_emit (widget, signals[STYLE_CHANGED], 0);
1158
widget->priv->is_style_dirty = FALSE;
1162
* st_widget_ensure_style:
1163
* @widget: A #StWidget
1165
* Ensures that @widget has read its style information.
1169
st_widget_ensure_style (StWidget *widget)
1171
g_return_if_fail (ST_IS_WIDGET (widget));
1173
if (widget->priv->is_style_dirty)
1174
st_widget_recompute_style (widget, NULL);
1178
* st_widget_get_border_image:
1179
* @actor: A #StWidget
1181
* Get the texture used as the border image. This is set using the
1182
* "border-image" CSS property. This function should normally only be used
1185
* Returns: (transfer none): #ClutterActor
1188
st_widget_get_border_image (StWidget *actor)
1190
StWidgetPrivate *priv = ST_WIDGET (actor)->priv;
1191
return priv->border_image;
1195
* st_widget_get_background_image:
1196
* @actor: A #StWidget
1198
* Get the texture used as the background image. This is set using the
1199
* "background-image" CSS property. This function should normally only be used
1202
* Returns: (transfer none): a #ClutterActor
1205
st_widget_get_background_image (StWidget *actor)
1207
StWidgetPrivate *priv = ST_WIDGET (actor)->priv;
1208
return priv->background_image;
1212
* st_widget_set_has_tooltip:
1213
* @widget: A #StWidget
1214
* @has_tooltip: #TRUE if the widget should display a tooltip
1216
* Enables tooltip support on the #StWidget.
1218
* Note that setting has-tooltip to #TRUE will cause the widget to be set
1219
* reactive. If you no longer need tooltip support and do not need the widget
1220
* to be reactive, you need to set ClutterActor::reactive to FALSE.
1224
st_widget_set_has_tooltip (StWidget *widget,
1225
gboolean has_tooltip)
1227
StWidgetPrivate *priv;
1229
g_return_if_fail (ST_IS_WIDGET (widget));
1231
priv = widget->priv;
1233
priv->has_tooltip = has_tooltip;
1237
clutter_actor_set_reactive ((ClutterActor*) widget, TRUE);
1241
priv->tooltip = g_object_new (ST_TYPE_TOOLTIP, NULL);
1242
clutter_actor_set_parent ((ClutterActor *) priv->tooltip,
1243
(ClutterActor *) widget);
1250
clutter_actor_unparent (CLUTTER_ACTOR (priv->tooltip));
1251
priv->tooltip = NULL;
1257
* st_widget_get_has_tooltip:
1258
* @widget: A #StWidget
1260
* Returns the current value of the has-tooltip property. See
1261
* st_tooltip_set_has_tooltip() for more information.
1263
* Returns: current value of has-tooltip on @widget
1266
st_widget_get_has_tooltip (StWidget *widget)
1268
g_return_val_if_fail (ST_IS_WIDGET (widget), FALSE);
1270
return widget->priv->has_tooltip;
1274
* st_widget_set_tooltip_text:
1275
* @widget: A #StWidget
1276
* @text: text to set as the tooltip
1278
* Set the tooltip text of the widget. This will set StWidget::has-tooltip to
1279
* #TRUE. A value of #NULL will unset the tooltip and set has-tooltip to #FALSE.
1283
st_widget_set_tooltip_text (StWidget *widget,
1286
StWidgetPrivate *priv;
1288
g_return_if_fail (ST_IS_WIDGET (widget));
1290
priv = widget->priv;
1293
st_widget_set_has_tooltip (widget, FALSE);
1295
st_widget_set_has_tooltip (widget, TRUE);
1297
st_tooltip_set_label (priv->tooltip, text);
1301
* st_widget_get_tooltip_text:
1302
* @widget: A #StWidget
1304
* Get the current tooltip string
1306
* Returns: The current tooltip string, owned by the #StWidget
1309
st_widget_get_tooltip_text (StWidget *widget)
1311
StWidgetPrivate *priv;
1313
g_return_val_if_fail (ST_IS_WIDGET (widget), NULL);
1314
priv = widget->priv;
1316
if (!priv->has_tooltip)
1319
return st_tooltip_get_label (widget->priv->tooltip);
1323
* st_widget_show_tooltip:
1324
* @widget: A #StWidget
1326
* Show the tooltip for @widget
1330
st_widget_show_tooltip (StWidget *widget)
1332
gfloat x, y, width, height;
1333
ClutterGeometry area;
1335
g_return_if_fail (ST_IS_WIDGET (widget));
1337
/* XXX not necceary, but first allocate transform is wrong */
1339
clutter_actor_get_transformed_position ((ClutterActor*) widget,
1342
clutter_actor_get_size ((ClutterActor*) widget, &width, &height);
1347
area.height = height;
1350
if (widget->priv->tooltip)
1352
st_tooltip_set_tip_area (widget->priv->tooltip, &area);
1353
st_tooltip_show (widget->priv->tooltip);
1358
* st_widget_hide_tooltip:
1359
* @widget: A #StWidget
1361
* Hide the tooltip for @widget
1365
st_widget_hide_tooltip (StWidget *widget)
1367
g_return_if_fail (ST_IS_WIDGET (widget));
1369
if (widget->priv->tooltip)
1370
st_tooltip_hide (widget->priv->tooltip);
1374
* st_widget_draw_background:
1375
* @widget: a #StWidget
1377
* Invokes #StWidget::draw_background() using the default background
1378
* image and/or color from the @widget style
1380
* This function should be used by subclasses of #StWidget that override
1381
* the paint() virtual function and cannot chain up
1384
st_widget_draw_background (StWidget *self)
1386
StWidgetPrivate *priv;
1387
StWidgetClass *klass;
1389
g_return_if_fail (ST_IS_WIDGET (self));
1393
klass = ST_WIDGET_GET_CLASS (self);
1394
klass->draw_background (ST_WIDGET (self));