diff --git a/configure.ac b/configure.ac index 9a0452f64..88ca8715b 100644 --- a/configure.ac +++ b/configure.ac @@ -57,10 +57,9 @@ 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 clutter-imcontext-0.1) +PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-2.0 clutter-imcontext-0.1 libcroco-0.6) 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(TOOLKIT, clutter-1.0 libcroco-0.6) PKG_CHECK_MODULES(TRAY, gtk+-2.0) MUTTER_BIN_DIR=`$PKG_CONFIG --variable=exec_prefix mutter-plugins`/bin diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css index 4eac5f6bb..c8d698994 100644 --- a/data/theme/gnome-shell.css +++ b/data/theme/gnome-shell.css @@ -25,38 +25,38 @@ StScrollBar StScrollView { - scrollbar-width: 16; - scrollbar-height: 16; + scrollbar-width: 16px; + scrollbar-height: 16px; } StButton#up-stepper { - border-image: url("file://scroll-button-up.png") 5; + -st-background-image: url("scroll-button-up.png") 5px; } StButton#up-stepper:hover, StButton#up-stepper:active { - border-image: url("file://scroll-button-up-hover.png") 5; + -st-background-image: url("scroll-button-up-hover.png") 5px; } StButton#down-stepper { - border-image: url("file://scroll-button-down.png") 5; + -st-background-image: url("scroll-button-down.png") 5px; } StButton#down-stepper:hover, StButton#down-stepper:active { - border-image: url("file://scroll-button-down-hover.png") 5; + -st-background-image: url("scroll-button-down-hover.png") 5px; } StScrollBar StButton#vhandle { - border-image: url("file://scroll-vhandle.png") 5; + -st-background-image: url("scroll-vhandle.png") 5px; } StScrollBar StButton#vhandle:hover { - border-image: url("file://scroll-vhandle.png") 5; + -st-background-image: url("scroll-vhandle.png") 5px; } diff --git a/js/ui/main.js b/js/ui/main.js index b699d9261..2a0d73bf8 100644 --- a/js/ui/main.js +++ b/js/ui/main.js @@ -76,9 +76,10 @@ function start() { for (let i = 0; i < children.length; i++) children[i].destroy(); - let style = St.Style.get_default(); + let themeContext = St.ThemeContext.get_for_stage (global.stage); let stylesheetPath = global.datadir + "/theme/gnome-shell.css"; - style.load_from_file(stylesheetPath); + let theme = new St.Theme ({ application_stylesheet: stylesheetPath }); + themeContext.set_theme (theme); global.connect('panel-run-dialog', function(panel) { // Make sure not more than one run dialog is shown. diff --git a/src/Makefile-st.am b/src/Makefile-st.am index 454dce413..d8070ce64 100644 --- a/src/Makefile-st.am +++ b/src/Makefile-st.am @@ -73,8 +73,6 @@ st_source_h = \ st/st-clipboard.h \ st/st-entry.h \ st/st-label.h \ - st/st-stylable.h \ - st/st-style.h \ st/st-scrollable.h \ st/st-scroll-bar.h \ st/st-scroll-view.h \ @@ -108,8 +106,6 @@ st_source_c = \ st/st-scrollable.c \ st/st-scroll-bar.c \ st/st-scroll-view.c \ - st/st-stylable.c \ - st/st-style.c \ st/st-subtexture.c \ st/st-texture-cache.c \ st/st-texture-frame.c \ diff --git a/src/st/st-bin.c b/src/st/st-bin.c index bc3eecbaf..f48e735e7 100644 --- a/src/st/st-bin.c +++ b/src/st/st-bin.c @@ -40,7 +40,6 @@ #include "st-bin.h" #include "st-enum-types.h" #include "st-private.h" -#include "st-stylable.h" #define ST_BIN_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ST_TYPE_BIN, StBinPrivate)) diff --git a/src/st/st-button.c b/src/st/st-button.c index c17a48583..19493fb19 100644 --- a/src/st/st-button.c +++ b/src/st/st-button.c @@ -35,6 +35,7 @@ #include "config.h" #endif +#include #include #include @@ -45,8 +46,6 @@ #include "st-button.h" #include "st-marshal.h" -#include "st-stylable.h" -#include "st-style.h" #include "st-texture-frame.h" #include "st-texture-cache.h" #include "st-private.h" @@ -94,51 +93,16 @@ struct _StButtonPrivate static guint button_signals[LAST_SIGNAL] = { 0, }; -static void st_stylable_iface_init (StStylableIface *iface); - -G_DEFINE_TYPE_WITH_CODE (StButton, st_button, ST_TYPE_BIN, - G_IMPLEMENT_INTERFACE (ST_TYPE_STYLABLE, - st_stylable_iface_init)); - -static void -st_stylable_iface_init (StStylableIface *iface) -{ - static gboolean is_initialized = FALSE; - - if (G_UNLIKELY (!is_initialized)) - { - ClutterColor bg_color = { 0xcc, 0xcc, 0xcc, 0x00 }; - GParamSpec *pspec; - - is_initialized = TRUE; - - pspec = g_param_spec_int ("border-spacing", - "Border Spacing", - "Spacing between internal elements", - 0, G_MAXINT, 6, - G_PARAM_READWRITE); - st_stylable_iface_install_property (iface, ST_TYPE_BUTTON, pspec); - - - is_initialized = TRUE; - - pspec = clutter_param_spec_color ("background-color", - "Background Color", - "The background color of an actor", - &bg_color, - G_PARAM_READWRITE); - st_stylable_iface_install_property (iface, ST_TYPE_BUTTON, pspec); - } -} +G_DEFINE_TYPE (StButton, st_button, ST_TYPE_BIN); static void st_button_update_label_style (StButton *button) { - ClutterColor *real_color = NULL; - gchar *font_string = NULL; - gchar *font_name = NULL; - gint font_size = 0; ClutterActor *label; + StThemeNode *theme_node; + ClutterColor color; + const PangoFontDescription *font; + gchar *font_string = NULL; label = st_bin_get_child ((StBin*) button); @@ -146,37 +110,15 @@ st_button_update_label_style (StButton *button) if (!CLUTTER_IS_TEXT (label)) return; - st_stylable_get (ST_STYLABLE (button), - "color", &real_color, - "font-family", &font_name, - "font-size", &font_size, - NULL); + theme_node = st_widget_get_theme_node (ST_WIDGET (button)); - if (font_name || font_size) - { - if (font_name && font_size) - font_string = g_strdup_printf ("%s %dpx", font_name, font_size); - else - { - if (font_size) - font_string = g_strdup_printf ("%dpx", font_size); - else - font_string = font_name; - } + st_theme_node_get_foreground_color (theme_node, &color); + clutter_text_set_color (CLUTTER_TEXT (label), &color); - clutter_text_set_font_name (CLUTTER_TEXT (label), font_string); - - if (font_string != font_name) - g_free (font_string); - } - - g_free (font_name); - - if (real_color) - { - clutter_text_set_color (CLUTTER_TEXT (label), real_color); - clutter_color_free (real_color); - } + font = st_theme_node_get_font (theme_node); + font_string = pango_font_description_to_string (font); + clutter_text_set_font_name (CLUTTER_TEXT (label), font_string); + g_free (font_string); } static void @@ -196,19 +138,6 @@ st_button_dispose_old_bg (StButton *button) } } -static void -st_button_stylable_changed (StStylable *stylable) -{ - StButton *button = ST_BUTTON (stylable); - ClutterActor *bg_image; - - st_button_dispose_old_bg (button); - - bg_image = st_widget_get_border_image ((StWidget*) button); - if (bg_image) - button->priv->old_bg = g_object_ref (bg_image); -} - static void st_animation_completed (ClutterAnimation *animation, StButton *button) @@ -222,11 +151,21 @@ st_button_style_changed (StWidget *widget) StButton *button = ST_BUTTON (widget); StButtonPrivate *priv = button->priv; StButtonClass *button_class = ST_BUTTON_GET_CLASS (button); + StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (button)); + ClutterActor *bg_image; + double spacing; - /* get the spacing value */ - st_stylable_get (ST_STYLABLE (widget), - "border-spacing", &priv->spacing, - NULL); + st_button_dispose_old_bg (button); + + bg_image = st_widget_get_border_image ((StWidget*) button); + if (bg_image) + button->priv->old_bg = g_object_ref (bg_image); + + ST_WIDGET_CLASS (st_button_parent_class)->style_changed (widget); + + spacing = 6; + st_theme_node_get_length (theme_node, "border-spacing", FALSE, &spacing); + priv->spacing = round (spacing); /* update the label styling */ st_button_update_label_style (button); @@ -527,6 +466,7 @@ st_button_class_init (StButtonClass *klass) actor_class->unmap = st_button_unmap; widget_class->draw_background = st_button_draw_background; + widget_class->style_changed = st_button_style_changed; pspec = g_param_spec_string ("label", "Label", @@ -580,12 +520,6 @@ st_button_init (StButton *button) button->priv->spacing = 6; clutter_actor_set_reactive ((ClutterActor *) button, TRUE); - - g_signal_connect (button, "style-changed", - G_CALLBACK (st_button_style_changed), NULL); - - g_signal_connect (button, "stylable-changed", - G_CALLBACK (st_button_stylable_changed), NULL); } /** @@ -673,7 +607,8 @@ st_button_set_label (StButton *button, st_bin_set_child ((StBin*) button, label); } - st_stylable_changed ((StStylable*) button); + /* Fake a style change so that we reset the style properties on the label */ + st_widget_style_changed (ST_WIDGET (button)); g_object_notify (G_OBJECT (button), "label"); } diff --git a/src/st/st-entry.c b/src/st/st-entry.c index f22562576..9a17b5185 100644 --- a/src/st/st-entry.c +++ b/src/st/st-entry.c @@ -58,7 +58,6 @@ #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" @@ -101,11 +100,7 @@ struct _StEntryPrivate 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)); +G_DEFINE_TYPE (StEntry, st_entry, ST_TYPE_WIDGET); static void st_entry_set_property (GObject *gobject, @@ -175,91 +170,32 @@ st_entry_finalize (GObject *object) 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; + StThemeNode *theme_node; + ClutterColor color; + const PangoFontDescription *font; 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); + theme_node = st_widget_get_theme_node (self); + + st_theme_node_get_foreground_color (theme_node, &color); + clutter_text_set_color (CLUTTER_TEXT (priv->entry), &color); - if (color) - { - clutter_text_set_color (CLUTTER_TEXT (priv->entry), color); - clutter_color_free (color); - } + if (st_theme_node_get_color (theme_node, "caret-color", FALSE, &color)) + clutter_text_set_cursor_color (CLUTTER_TEXT (priv->entry), &color); - if (caret_color) - { - clutter_text_set_cursor_color (CLUTTER_TEXT (priv->entry), caret_color); - clutter_color_free (caret_color); - } + if (st_theme_node_get_color (theme_node, "selection-background-color", FALSE, &color)) + clutter_text_set_selection_color (CLUTTER_TEXT (priv->entry), &color); - if (selection_background_color) - { - clutter_text_set_selection_color (CLUTTER_TEXT (priv->entry), - selection_background_color); - clutter_color_free (selection_background_color); - } + font = st_theme_node_get_font (theme_node); + font_string = pango_font_description_to_string (font); + clutter_text_set_font_name (CLUTTER_TEXT (priv->entry), font_string); + g_free (font_string); - 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); - } + ST_WIDGET_CLASS (st_entry_parent_class)->style_changed (self); } static void @@ -636,6 +572,7 @@ st_entry_class_init (StEntryClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); + StWidgetClass *widget_class = ST_WIDGET_CLASS (klass); GParamSpec *pspec; g_type_class_add_private (klass, sizeof (StEntryPrivate)); @@ -656,6 +593,8 @@ st_entry_class_init (StEntryClass *klass) actor_class->key_press_event = st_entry_key_press_event; actor_class->key_focus_in = st_entry_key_focus_in; + widget_class->style_changed = st_entry_style_changed; + pspec = g_param_spec_string ("text", "Text", "Text of the entry", @@ -725,9 +664,6 @@ st_entry_init (StEntry *entry) /* 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); } /** diff --git a/src/st/st-label.c b/src/st/st-label.c index 0701a0b35..8d719dc94 100644 --- a/src/st/st-label.c +++ b/src/st/st-label.c @@ -45,7 +45,6 @@ #include "st-label.h" #include "st-widget.h" -#include "st-stylable.h" enum { @@ -106,43 +105,23 @@ st_label_get_property (GObject *gobject, static void st_label_style_changed (StWidget *self) { - StLabelPrivate *priv = ST_LABEL (self)->priv; - ClutterColor *color = NULL; - gchar *font_name; + StLabelPrivate *priv; + StThemeNode *theme_node; + ClutterColor color; + const PangoFontDescription *font; gchar *font_string; - gint font_size; - st_stylable_get (ST_STYLABLE (self), - "color", &color, - "font-family", &font_name, - "font-size", &font_size, - NULL); + priv = ST_LABEL (self)->priv; + theme_node = st_widget_get_theme_node (self); + st_theme_node_get_foreground_color (theme_node, &color); + clutter_text_set_color (CLUTTER_TEXT (priv->label), &color); - 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); - } + font = st_theme_node_get_font (theme_node); + font_string = pango_font_description_to_string (font); + clutter_text_set_font_name (CLUTTER_TEXT (priv->label), font_string); + g_free (font_string); + ST_WIDGET_CLASS (st_label_parent_class)->style_changed (self); } static void @@ -249,6 +228,7 @@ st_label_class_init (StLabelClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); + StWidgetClass *widget_class = ST_WIDGET_CLASS (klass); GParamSpec *pspec; g_type_class_add_private (klass, sizeof (StLabelPrivate)); @@ -263,6 +243,8 @@ st_label_class_init (StLabelClass *klass) actor_class->map = st_label_map; actor_class->unmap = st_label_unmap; + widget_class->style_changed = st_label_style_changed; + pspec = g_param_spec_string ("text", "Text", "Text of the label", @@ -283,9 +265,6 @@ st_label_init (StLabel *label) NULL); clutter_actor_set_parent (priv->label, CLUTTER_ACTOR (label)); - - g_signal_connect (label, "style-changed", - G_CALLBACK (st_label_style_changed), NULL); } /** diff --git a/src/st/st-scroll-bar.c b/src/st/st-scroll-bar.c index 5e33d4308..fdfbd5941 100644 --- a/src/st/st-scroll-bar.c +++ b/src/st/st-scroll-bar.c @@ -40,16 +40,11 @@ #include "st-scroll-bar.h" #include "st-bin.h" #include "st-marshal.h" -#include "st-stylable.h" #include "st-enum-types.h" #include "st-private.h" #include "st-button.h" -static void st_stylable_iface_init (StStylableIface *iface); - -G_DEFINE_TYPE_WITH_CODE (StScrollBar, st_scroll_bar, ST_TYPE_BIN, - G_IMPLEMENT_INTERFACE (ST_TYPE_STYLABLE, - st_stylable_iface_init)) +G_DEFINE_TYPE (StScrollBar, st_scroll_bar, ST_TYPE_BIN) #define ST_SCROLL_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ST_TYPE_SCROLL_BAR, StScrollBarPrivate)) @@ -345,10 +340,10 @@ st_scroll_bar_allocate (ClutterActor *actor, if (priv->adjustment) { - gfloat handle_size, position, avail_size; - gdouble value, lower, upper, page_size, increment; + StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor)); + float handle_size, position, avail_size; + gdouble value, lower, upper, page_size, increment, min_size, max_size; ClutterActorBox handle_box = { 0, }; - guint min_size, max_size; st_adjustment_get_values (priv->adjustment, &value, @@ -364,10 +359,10 @@ st_scroll_bar_allocate (ClutterActor *actor, else increment = page_size / (upper - lower); - st_stylable_get (ST_STYLABLE (actor), - "min-size", &min_size, - "max-size", &max_size, - NULL); + min_size = 32.; + st_theme_node_get_length (theme_node, "min-size", FALSE, &min_size); + max_size = G_MAXINT16; + st_theme_node_get_length (theme_node, "max-size", FALSE, &max_size); if (upper - lower - page_size <= 0) position = 0; @@ -416,11 +411,12 @@ st_scroll_bar_style_changed (StWidget *widget) { StScrollBarPrivate *priv = ST_SCROLL_BAR (widget)->priv; - st_stylable_changed ((StStylable *) priv->bw_stepper); - st_stylable_changed ((StStylable *) priv->fw_stepper); - st_stylable_changed ((StStylable *) priv->trough); - st_stylable_changed ((StStylable *) priv->handle); + st_widget_style_changed (ST_WIDGET (priv->bw_stepper)); + st_widget_style_changed (ST_WIDGET (priv->fw_stepper)); + st_widget_style_changed (ST_WIDGET (priv->trough)); + st_widget_style_changed (ST_WIDGET (priv->handle)); + ST_WIDGET_CLASS (st_scroll_bar_parent_class)->style_changed (widget); } static void @@ -503,6 +499,7 @@ st_scroll_bar_class_init (StScrollBarClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); + StWidgetClass *widget_class = ST_WIDGET_CLASS (klass); GParamSpec *pspec; g_type_class_add_private (klass, sizeof (StScrollBarPrivate)); @@ -519,6 +516,8 @@ st_scroll_bar_class_init (StScrollBarClass *klass) actor_class->map = st_scroll_bar_map; actor_class->unmap = st_scroll_bar_unmap; + widget_class->style_changed = st_scroll_bar_style_changed; + g_object_class_install_property (object_class, PROP_ADJUSTMENT, @@ -554,35 +553,6 @@ st_scroll_bar_class_init (StScrollBarClass *klass) G_TYPE_NONE, 0); } -static void -st_stylable_iface_init (StStylableIface *iface) -{ - static gboolean is_initialized = FALSE; - - if (!is_initialized) - { - GParamSpec *pspec; - - is_initialized = TRUE; - - pspec = g_param_spec_uint ("min-size", - "Minimum grabber size", - "Minimum size of the scroll grabber, in px", - 0, G_MAXUINT, 32, - G_PARAM_READWRITE); - st_stylable_iface_install_property (iface, - ST_TYPE_SCROLL_BAR, pspec); - - pspec = g_param_spec_uint ("max-size", - "Maximum grabber size", - "Maximum size of the scroll grabber, in px", - 0, G_MAXINT16, G_MAXINT16, - G_PARAM_READWRITE); - st_stylable_iface_install_property (iface, - ST_TYPE_SCROLL_BAR, pspec); - } -} - static void move_slider (StScrollBar *bar, gfloat x, @@ -1046,8 +1016,6 @@ st_scroll_bar_init (StScrollBar *self) clutter_actor_set_reactive (CLUTTER_ACTOR (self), TRUE); - g_signal_connect (self, "style-changed", - G_CALLBACK (st_scroll_bar_style_changed), NULL); g_signal_connect (self, "notify::reactive", G_CALLBACK (st_scroll_bar_notify_reactive), NULL); } diff --git a/src/st/st-scroll-view.c b/src/st/st-scroll-view.c index 17c31e24a..09fb075ae 100644 --- a/src/st/st-scroll-view.c +++ b/src/st/st-scroll-view.c @@ -36,24 +36,23 @@ #include "st-marshal.h" #include "st-scroll-bar.h" #include "st-scrollable.h" -#include "st-stylable.h" #include static void clutter_container_iface_init (ClutterContainerIface *iface); -static void st_stylable_iface_init (StStylableIface *iface); static ClutterContainerIface *st_scroll_view_parent_iface = NULL; G_DEFINE_TYPE_WITH_CODE (StScrollView, st_scroll_view, ST_TYPE_BIN, G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER, - clutter_container_iface_init) - G_IMPLEMENT_INTERFACE (ST_TYPE_STYLABLE, - st_stylable_iface_init)) + clutter_container_iface_init)) #define SCROLL_VIEW_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ ST_TYPE_SCROLL_VIEW, \ StScrollViewPrivate)) +/* Default width (or height - the narrow dimension) for the scrollbars*/ +#define DEFAULT_SCROLLBAR_WIDTH 24 + struct _StScrollViewPrivate { /* a pointer to the child; this is actually stored @@ -180,6 +179,28 @@ st_scroll_view_pick (ClutterActor *actor, clutter_actor_paint (priv->vscroll); } +static double +get_scrollbar_width (StScrollView *scroll_view) +{ + StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (scroll_view)); + double result = DEFAULT_SCROLLBAR_WIDTH; + + st_theme_node_get_length (theme_node, "scrollbar-width", FALSE, &result); + + return result; +} + +static double +get_scrollbar_height (StScrollView *scroll_view) +{ + StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (scroll_view)); + double result = DEFAULT_SCROLLBAR_WIDTH; + + st_theme_node_get_length (theme_node, "scrollbar-height", FALSE, &result); + + return result; +} + static void st_scroll_view_get_preferred_width (ClutterActor *actor, gfloat for_height, @@ -187,7 +208,6 @@ st_scroll_view_get_preferred_width (ClutterActor *actor, gfloat *natural_width_p) { StPadding padding; - guint xthickness; StScrollViewPrivate *priv = ST_SCROLL_VIEW (actor)->priv; @@ -195,9 +215,6 @@ st_scroll_view_get_preferred_width (ClutterActor *actor, return; st_widget_get_padding (ST_WIDGET (actor), &padding); - st_stylable_get (ST_STYLABLE (actor), - "scrollbar-width", &xthickness, - NULL); /* Our natural width is the natural width of the child */ clutter_actor_get_preferred_width (priv->child, @@ -214,7 +231,7 @@ st_scroll_view_get_preferred_width (ClutterActor *actor, NULL, &natural_height); if (for_height < natural_height) - *natural_width_p += xthickness; + *natural_width_p += get_scrollbar_width (ST_SCROLL_VIEW (actor)); } /* Add space for padding */ @@ -232,7 +249,6 @@ st_scroll_view_get_preferred_height (ClutterActor *actor, gfloat *natural_height_p) { StPadding padding; - guint ythickness; StScrollViewPrivate *priv = ST_SCROLL_VIEW (actor)->priv; @@ -240,9 +256,6 @@ st_scroll_view_get_preferred_height (ClutterActor *actor, return; st_widget_get_padding (ST_WIDGET (actor), &padding); - st_stylable_get (ST_STYLABLE (actor), - "scrollbar-height", &ythickness, - NULL); /* Our natural height is the natural height of the child */ clutter_actor_get_preferred_height (priv->child, @@ -259,7 +272,7 @@ st_scroll_view_get_preferred_height (ClutterActor *actor, NULL, &natural_width); if (for_width < natural_width) - *natural_height_p += ythickness; + *natural_height_p += get_scrollbar_height (ST_SCROLL_VIEW (actor)); } /* Add space for padding */ @@ -300,10 +313,8 @@ st_scroll_view_allocate (ClutterActor *actor, avail_width = (box->x2 - box->x1) - padding.left - padding.right; avail_height = (box->y2 - box->y1) - padding.top - padding.bottom; - st_stylable_get (ST_STYLABLE (actor), - "scrollbar-width", &sb_width, - "scrollbar-height", &sb_height, - NULL); + sb_width = get_scrollbar_width (ST_SCROLL_VIEW (actor)); + sb_height = get_scrollbar_width (ST_SCROLL_VIEW (actor)); if (!CLUTTER_ACTOR_IS_VISIBLE (priv->vscroll)) sb_width = 0; @@ -349,8 +360,10 @@ st_scroll_view_style_changed (StWidget *widget) { StScrollViewPrivate *priv = ST_SCROLL_VIEW (widget)->priv; - st_stylable_changed ((StStylable *) priv->hscroll); - st_stylable_changed ((StStylable *) priv->vscroll); + st_widget_style_changed (ST_WIDGET (priv->hscroll)); + st_widget_style_changed (ST_WIDGET (priv->vscroll)); + + ST_WIDGET_CLASS (st_scroll_view_parent_class)->style_changed (widget); } static gboolean @@ -433,6 +446,7 @@ st_scroll_view_class_init (StScrollViewClass *klass) GParamSpec *pspec; GObjectClass *object_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); + StWidgetClass *widget_class = ST_WIDGET_CLASS (klass); g_type_class_add_private (klass, sizeof (StScrollViewPrivate)); @@ -448,6 +462,8 @@ st_scroll_view_class_init (StScrollViewClass *klass) actor_class->allocate = st_scroll_view_allocate; actor_class->scroll_event = st_scroll_view_scroll_event; + widget_class->style_changed = st_scroll_view_style_changed; + g_object_class_install_property (object_class, PROP_HSCROLL, g_param_spec_object ("hscroll", @@ -475,33 +491,6 @@ st_scroll_view_class_init (StScrollViewClass *klass) } -static void -st_stylable_iface_init (StStylableIface *iface) -{ - static gboolean is_initialized = FALSE; - - if (!is_initialized) - { - GParamSpec *pspec; - - is_initialized = TRUE; - - pspec = g_param_spec_uint ("scrollbar-width", - "Vertical scroll-bar thickness", - "Thickness of vertical scrollbar, in px", - 0, G_MAXUINT, 24, - G_PARAM_READWRITE); - st_stylable_iface_install_property (iface, ST_TYPE_SCROLL_VIEW, pspec); - - pspec = g_param_spec_uint ("scrollbar-height", - "Horizontal scroll-bar thickness", - "Thickness of horizontal scrollbar, in px", - 0, G_MAXUINT, 24, - G_PARAM_READWRITE); - st_stylable_iface_install_property (iface, ST_TYPE_SCROLL_VIEW, pspec); - } -} - static void child_adjustment_changed_cb (StAdjustment *adjustment, ClutterActor *bar) @@ -609,9 +598,6 @@ st_scroll_view_init (StScrollView *self) priv->mouse_scroll = TRUE; g_object_set (G_OBJECT (self), "reactive", TRUE, "clip-to-allocation", TRUE, NULL); - - g_signal_connect (self, "style-changed", - G_CALLBACK (st_scroll_view_style_changed), NULL); } static void diff --git a/src/st/st-stylable.c b/src/st/st-stylable.c deleted file mode 100644 index 35e5e647c..000000000 --- a/src/st/st-stylable.c +++ /dev/null @@ -1,850 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* - * st-stylable.c: Interface for stylable objects - * - * Copyright 2008 Intel Corporation - * 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: Emmanuele Bassi - * Thomas Wood - * - */ - -/** - * SECTION:st-stylable - * @short_description: Interface for stylable objects - * - * Stylable objects are classes that can have "style properties", that is - * properties that can be changed by attaching a #StStyle to them. - * - * Objects can choose to subclass #StWidget, and thus inherit all the - * #StWidget style properties; or they can subclass #StWidget and - * reimplement the #StStylable interface to add new style properties - * specific for them (and their subclasses); or, finally, they can simply - * subclass #GObject and implement #StStylable to install new properties. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include - -#include -#include -#include - -#include "st-marshal.h" -#include "st-private.h" -#include "st-stylable.h" - -enum -{ - STYLE_CHANGED, - STYLE_NOTIFY, - CHANGED, - - LAST_SIGNAL -}; - -static GObjectNotifyContext property_notify_context = { 0, }; - -static GParamSpecPool *style_property_spec_pool = NULL; - -static GQuark quark_real_owner = 0; -static GQuark quark_style = 0; - -static guint stylable_signals[LAST_SIGNAL] = { 0, }; - -static void -st_stylable_notify_dispatcher (GObject *gobject, - guint n_pspecs, - GParamSpec **pspecs) -{ - guint i; - - for (i = 0; i < n_pspecs; i++) - g_signal_emit (gobject, stylable_signals[STYLE_NOTIFY], - g_quark_from_string (pspecs[i]->name), - pspecs[i]); -} - -static void -st_stylable_base_finalize (gpointer g_iface) -{ - GList *list, *node; - - list = g_param_spec_pool_list_owned (style_property_spec_pool, - G_TYPE_FROM_INTERFACE (g_iface)); - - for (node = list; node; node = node->next) - { - GParamSpec *pspec = node->data; - - g_param_spec_pool_remove (style_property_spec_pool, pspec); - g_param_spec_unref (pspec); - } - - g_list_free (list); -} - -static void -st_stylable_base_init (gpointer g_iface) -{ - static gboolean initialised = FALSE; - - if (G_UNLIKELY (!initialised)) - { - GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); - - initialised = TRUE; - - quark_real_owner = g_quark_from_static_string ("st-stylable-real-owner-quark"); - quark_style = g_quark_from_static_string ("st-stylable-style-quark"); - - style_property_spec_pool = g_param_spec_pool_new (FALSE); - - property_notify_context.quark_notify_queue = g_quark_from_static_string ("StStylable-style-property-notify-queue"); - property_notify_context.dispatcher = st_stylable_notify_dispatcher; - - /** - * StStylable:style: - * - * The #StStyle attached to a stylable object. - */ - g_object_interface_install_property (g_iface, - g_param_spec_object ("style", - "Style", - "A style object", - ST_TYPE_STYLE, - ST_PARAM_READWRITE)); - - /** - * StStylable::style-changed: - * @stylable: the #StStylable that received the signal - * @old_style: the previously set #StStyle for @stylable - * - * The ::style-changed signal is emitted each time one of the style - * properties have changed. - */ - stylable_signals[STYLE_CHANGED] = - g_signal_new (I_("style-changed"), - iface_type, - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (StStylableIface, style_changed), - NULL, NULL, - _st_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - /** - * StStylable::stylable-changed: - * @actor: the actor that received the signal - * - * The ::changed signal is emitted each time any of the properties of the - * stylable has changed. - */ - stylable_signals[CHANGED] = - g_signal_new (I_("stylable-changed"), - iface_type, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (StStylableIface, stylable_changed), - NULL, NULL, - _st_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - stylable_signals[STYLE_NOTIFY] = - g_signal_new (I_("style-notify"), - iface_type, - G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (StStylableIface, style_notify), - NULL, NULL, - _st_marshal_VOID__PARAM, - G_TYPE_NONE, 1, - G_TYPE_PARAM); - } -} - -GType -st_stylable_get_type (void) -{ - static GType our_type = 0; - - if (G_UNLIKELY (our_type == 0)) - { - GTypeInfo stylable_info = { - sizeof (StStylableIface), - st_stylable_base_init, - st_stylable_base_finalize - }; - - our_type = g_type_register_static (G_TYPE_INTERFACE, - I_("StStylable"), - &stylable_info, 0); - } - - return our_type; -} - -void -st_stylable_freeze_notify (StStylable *stylable) -{ - g_return_if_fail (ST_IS_STYLABLE (stylable)); - - g_object_ref (stylable); - g_object_notify_queue_freeze (G_OBJECT (stylable), &property_notify_context); - g_object_unref (stylable); -} - -void -st_stylable_thaw_notify (StStylable *stylable) -{ - GObjectNotifyQueue *nqueue; - - g_return_if_fail (ST_IS_STYLABLE (stylable)); - - g_object_ref (stylable); - - nqueue = g_object_notify_queue_from_object (G_OBJECT (stylable), - &property_notify_context); - - if (!nqueue || !nqueue->freeze_count) - g_warning ("%s: property-changed notification for %s(%p) is not frozen", - G_STRFUNC, G_OBJECT_TYPE_NAME (stylable), stylable); - else - g_object_notify_queue_thaw (G_OBJECT (stylable), nqueue); - - g_object_unref (stylable); -} - -void -st_stylable_notify (StStylable *stylable, - const gchar *property_name) -{ - GParamSpec *pspec; - - g_return_if_fail (ST_IS_STYLABLE (stylable)); - g_return_if_fail (property_name != NULL); - - g_object_ref (stylable); - - pspec = g_param_spec_pool_lookup (style_property_spec_pool, - property_name, - G_OBJECT_TYPE (stylable), - TRUE); - - if (!pspec) - g_warning ("%s: object class `%s' has no style property named `%s'", - G_STRFUNC, - G_OBJECT_TYPE_NAME (stylable), - property_name); - else - { - GObjectNotifyQueue *nqueue; - - nqueue = g_object_notify_queue_freeze (G_OBJECT (stylable), - &property_notify_context); - g_object_notify_queue_add (G_OBJECT (stylable), nqueue, pspec); - g_object_notify_queue_thaw (G_OBJECT (stylable), nqueue); - } - - g_object_unref (stylable); -} - -/** - * st_stylable_iface_install_property: - * @iface: a #StStylableIface - * @owner_type: #GType of the style property owner - * @pspec: a #GParamSpec - * - * Installs a property for @owner_type using @pspec as the property - * description. - * - * This function should be used inside the #StStylableIface initialization - * function of a class, for instance: - * - * - * G_DEFINE_TYPE_WITH_CODE (FooActor, foo_actor, CLUTTER_TYPE_ACTOR, - * G_IMPLEMENT_INTERFACE (ST_TYPE_STYLABLE, - * st_stylable_init)); - * ... - * static void - * st_stylable_init (StStylableIface *iface) - * { - * static gboolean is_initialized = FALSE; - * - * if (!is_initialized) - * { - * ... - * st_stylable_iface_install_property (stylable, - * FOO_TYPE_ACTOR, - * g_param_spec_int ("x-spacing", - * "X Spacing", - * "Horizontal spacing", - * -1, G_MAXINT, - * 2, - * G_PARAM_READWRITE)); - * ... - * } - * } - * - */ -void -st_stylable_iface_install_property (StStylableIface *iface, - GType owner_type, - GParamSpec *pspec) -{ - g_return_if_fail (ST_IS_STYLABLE_IFACE (iface)); - g_return_if_fail (owner_type != G_TYPE_INVALID); - g_return_if_fail (G_IS_PARAM_SPEC (pspec)); - g_return_if_fail (pspec->flags & G_PARAM_READABLE); - g_return_if_fail (!(pspec->flags & (G_PARAM_CONSTRUCT_ONLY | G_PARAM_CONSTRUCT - ))); - - if (g_param_spec_pool_lookup (style_property_spec_pool, pspec->name, - owner_type, - FALSE)) - { - g_warning ("%s: class `%s' already contains a style property named `%s'", - G_STRLOC, - g_type_name (owner_type), - pspec->name); - return; - } - - g_param_spec_ref_sink (pspec); - g_param_spec_set_qdata_full (pspec, quark_real_owner, - g_strdup (g_type_name (owner_type)), - g_free); - - g_param_spec_pool_insert (style_property_spec_pool, - pspec, - owner_type); -} - -/** - * st_stylable_list_properties: - * @stylable: a #StStylable - * @n_props: (out): return location for the number of properties, or %NULL - * - * Retrieves all the #GParamSpecs installed by @stylable. - * - * Return value: (transfer container) (array length=n_props): an array - * of #GParamSpecs. Free it with g_free() when done. - */ -GParamSpec ** -st_stylable_list_properties (StStylable *stylable, - guint *n_props) -{ - GParamSpec **pspecs = NULL; - guint n; - - g_return_val_if_fail (ST_IS_STYLABLE (stylable), NULL); - - pspecs = g_param_spec_pool_list (style_property_spec_pool, - G_OBJECT_TYPE (stylable), - &n); - if (n_props) - *n_props = n; - - return pspecs; -} - -/** - * st_stylable_find_property: - * @stylable: a #StStylable - * @property_name: the name of the property to find - * - * Finds the #GParamSpec installed by @stylable for the property - * with @property_name. - * - * Return value: (transfer none): a #GParamSpec for the given property, - * or %NULL if no property with that name was found - */ -GParamSpec * -st_stylable_find_property (StStylable *stylable, - const gchar *property_name) -{ - g_return_val_if_fail (ST_IS_STYLABLE (stylable), NULL); - g_return_val_if_fail (property_name != NULL, NULL); - - return g_param_spec_pool_lookup (style_property_spec_pool, - property_name, - G_OBJECT_TYPE (stylable), - TRUE); -} - -static inline void -st_stylable_get_property_internal (StStylable *stylable, - GParamSpec *pspec, - GValue *value) -{ - StStyle *style; - GValue real_value = { 0, }; - - style = st_stylable_get_style (stylable); - - if (!style) - { - g_value_reset (value); - return; - } - - st_style_get_property (style, stylable, pspec, &real_value); - - g_value_copy (&real_value, value); - g_value_unset (&real_value); - -} - -/** - * st_stylable_get_property: - * @stylable: a #StStylable - * @property_name: the name of the property - * @value: (out): return location for an empty #GValue - * - * Retrieves the value of @property_name for @stylable, and puts it - * into @value. - */ -void -st_stylable_get_property (StStylable *stylable, - const gchar *property_name, - GValue *value) -{ - GParamSpec *pspec; - - g_return_if_fail (ST_IS_STYLABLE (stylable)); - g_return_if_fail (property_name != NULL); - g_return_if_fail (value != NULL); - - pspec = st_stylable_find_property (stylable, property_name); - if (!pspec) - { - g_warning ("Stylable class `%s' doesn't have a property named `%s'", - g_type_name (G_OBJECT_TYPE (stylable)), - property_name); - return; - } - - if (!(pspec->flags & G_PARAM_READABLE)) - { - g_warning ("Style property `%s' of class `%s' is not readable", - pspec->name, - g_type_name (G_OBJECT_TYPE (stylable))); - return; - } - - if (G_VALUE_TYPE (value) != G_PARAM_SPEC_VALUE_TYPE (pspec)) - { - g_warning ("Passed value is not of the requested type `%s' for " - "the style property `%s' of class `%s'", - g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)), - pspec->name, - g_type_name (G_OBJECT_TYPE (stylable))); - return; - } - - st_stylable_get_property_internal (stylable, pspec, value); -} - -/** - * st_stylable_get: - * @stylable: a #StStylable - * @first_property_name: name of the first property to get - * @Varargs: return location for the first property, followed optionally - * by more name/return location pairs, followed by %NULL - * - * Gets the style properties for @stylable. - * - * In general, a copy is made of the property contents and the called - * is responsible for freeing the memory in the appropriate manner for - * the property type. - * - * - * Using st_stylable_get(<!-- -->) - * An example of using st_stylable_get() to get the contents of - * two style properties - one of type #G_TYPE_INT and one of type - * #CLUTTER_TYPE_COLOR: - * - * gint x_spacing; - * ClutterColor *bg_color; - * - * st_stylable_get (stylable, - * "x-spacing", &x_spacing, - * "bg-color", &bg_color, - * NULL); - * - * /* do something with x_spacing and bg_color */ - * - * clutter_color_free (bg_color); - * - * - */ -void -st_stylable_get (StStylable *stylable, - const gchar *first_property_name, - ...) -{ - StStyle *style; - va_list args; - - g_return_if_fail (ST_IS_STYLABLE (stylable)); - g_return_if_fail (first_property_name != NULL); - - style = st_stylable_get_style (stylable); - - va_start (args, first_property_name); - st_style_get_valist (style, stylable, first_property_name, args); - va_end (args); -} - -/** - * st_stylable_get_default_value: - * @stylable: a #StStylable - * @property_name: name of the property to query - * @value_out: (out): return location for the default value - * - * Query @stylable for the default value of property @property_name and - * fill @value_out with the result. - * - * Returns: %TRUE if property @property_name exists and the default value has - * been returned. - */ -gboolean -st_stylable_get_default_value (StStylable *stylable, - const gchar *property_name, - GValue *value_out) -{ - GParamSpec *pspec; - - pspec = st_stylable_find_property (stylable, property_name); - if (!pspec) - { - g_warning ("%s: no style property named `%s' found for class `%s'", - G_STRLOC, - property_name, - g_type_name (G_OBJECT_TYPE (stylable))); - return FALSE; - } - - if (!(pspec->flags & G_PARAM_READABLE)) - { - g_warning ("Style property `%s' of class `%s' is not readable", - pspec->name, - g_type_name (G_OBJECT_TYPE (stylable))); - return FALSE; - } - - g_value_init (value_out, G_PARAM_SPEC_VALUE_TYPE (pspec)); - g_param_value_set_default (pspec, value_out); - return TRUE; -} - -/** - * st_stylable_get_style: - * @stylable: a #StStylable - * - * Retrieves the #StStyle used by @stylable. This function does not - * alter the reference count of the returned object. - * - * Return value: (transfer none): a #StStyle - */ -StStyle * -st_stylable_get_style (StStylable *stylable) -{ - StStylableIface *iface; - - g_return_val_if_fail (ST_IS_STYLABLE (stylable), NULL); - - iface = ST_STYLABLE_GET_IFACE (stylable); - if (iface->get_style) - return iface->get_style (stylable); - - return g_object_get_data (G_OBJECT (stylable), "st-stylable-style"); -} - -/** - * st_stylable_set_style: - * @stylable: a #StStylable - * @style: a #StStyle - * - * Sets @style as the new #StStyle to be used by @stylable. - * - * The #StStylable will take ownership of the passed #StStyle. - * - * After the #StStle has been set, the StStylable::style-set signal - * will be emitted. - */ -void -st_stylable_set_style (StStylable *stylable, - StStyle *style) -{ - StStylableIface *iface; - StStyle *old_style; - - g_return_if_fail (ST_IS_STYLABLE (stylable)); - g_return_if_fail (ST_IS_STYLE (style)); - - iface = ST_STYLABLE_GET_IFACE (stylable); - - old_style = st_stylable_get_style (stylable); - g_object_ref (old_style); - - if (iface->set_style) - iface->set_style (stylable, style); - else - { - g_object_set_qdata_full (G_OBJECT (stylable), - quark_style, - g_object_ref_sink (style), - g_object_unref); - } - - g_signal_emit (stylable, stylable_signals[STYLE_CHANGED], 0, old_style); - g_object_unref (old_style); - - g_object_notify (G_OBJECT (stylable), "style"); -} - -/** - * st_stylable_get_container: - * @stylable: a #StStylable - * - * Obtain the parent #StStylable that contains @stylable. - * - * Return value: (transfer none): The parent #StStylable - */ -StStylable* -st_stylable_get_container (StStylable *stylable) -{ - StStylableIface *iface; - - g_return_val_if_fail (ST_IS_STYLABLE (stylable), NULL); - - iface = ST_STYLABLE_GET_IFACE (stylable); - - if (iface->get_container) - return iface->get_container (stylable); - else - return NULL; -} - -/** - * st_stylable_get_base_style: - * @stylable: a #StStylable - * - * Get the parent ancestor #StStylable of @stylable. - * - * Return value: (transfer none): the parent #StStylable - */ -StStylable* -st_stylable_get_base_style (StStylable *stylable) -{ - StStylableIface *iface; - - g_return_val_if_fail (ST_IS_STYLABLE (stylable), NULL); - - iface = ST_STYLABLE_GET_IFACE (stylable); - - if (iface->get_base_style) - return iface->get_base_style (stylable); - else - return NULL; -} - - -/** - * st_stylable_get_style_id: - * @stylable: a #StStylable - * - * Get the ID value of @stylable - * - * Return value: the id of @stylable - */ -const gchar* -st_stylable_get_style_id (StStylable *stylable) -{ - StStylableIface *iface; - - g_return_val_if_fail (ST_IS_STYLABLE (stylable), NULL); - - iface = ST_STYLABLE_GET_IFACE (stylable); - - if (iface->get_style_id) - return iface->get_style_id (stylable); - else - return NULL; -} - -/** - * st_stylable_get_style_type: - * @stylable: a #StStylable - * - * Get the type name of @stylable - * - * Return value: the type name of @stylable - */ -const gchar* -st_stylable_get_style_type (StStylable *stylable) -{ - StStylableIface *iface; - - g_return_val_if_fail (ST_IS_STYLABLE (stylable), NULL); - - iface = ST_STYLABLE_GET_IFACE (stylable); - - if (iface->get_style_type) - return iface->get_style_type (stylable); - else - return G_OBJECT_TYPE_NAME (stylable); -} - -/** - * st_stylable_get_style_class: - * @stylable: a #StStylable - * - * Get the style class name of @stylable - * - * Return value: the type name of @stylable - */ -const gchar* -st_stylable_get_style_class (StStylable *stylable) -{ - StStylableIface *iface; - - g_return_val_if_fail (ST_IS_STYLABLE (stylable), NULL); - - iface = ST_STYLABLE_GET_IFACE (stylable); - - if (iface->get_style_class) - return iface->get_style_class (stylable); - else - return NULL; -} - -/** - * st_stylable_get_pseudo_class: - * @stylable: a #StStylable - * - * Get the pseudo class name of @stylable - * - * Return value: the pseudo class name of @stylable - */ -const gchar* -st_stylable_get_pseudo_class (StStylable *stylable) -{ - StStylableIface *iface; - - g_return_val_if_fail (ST_IS_STYLABLE (stylable), NULL); - - iface = ST_STYLABLE_GET_IFACE (stylable); - - if (iface->get_pseudo_class) - return iface->get_pseudo_class (stylable); - else - return NULL; -} - -/** - * st_stylable_get_attribute: - * @stylable: a #StStylable - * @name: attribute name - * - * Get the named attribute from @stylable - * - * Return value: the value of the attribute - */ -gchar* -st_stylable_get_attribute (StStylable *stylable, - const gchar *name) -{ - StStylableIface *iface; - GValue value = { 0, }; - GValue string_value = { 0, }; - gchar *ret; - GParamSpec *pspec; - - g_return_val_if_fail (ST_IS_STYLABLE (stylable), NULL); - - iface = ST_STYLABLE_GET_IFACE (stylable); - - if (iface->get_attribute) - return iface->get_attribute (stylable, name); - - /* look up a generic gobject property */ - pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (stylable), name); - - /* if no such property exists, return NULL */ - if (pspec == NULL) - return NULL; - - g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); - g_object_get_property (G_OBJECT (stylable), name, &value); - - g_value_init (&string_value, G_TYPE_STRING); - if (g_value_transform (&value, &string_value)) - ret = g_strdup (g_value_get_string (&string_value)); - else - ret = NULL; - - g_value_unset (&value); - g_value_unset (&string_value); - - return ret; -} - -/** - * st_stylable_get_viewport: - * @stylable: a #StStylable - * @x: location to store X coordinate - * @y: location to store Y coordinate - * @width: location to store width - * @height: location to store height - * - * Obtain the position and dimensions of @stylable. - * - * Return value: true if the function succeeded - */ -gboolean -st_stylable_get_viewport (StStylable *stylable, - gint *x, - gint *y, - gint *width, - gint *height) -{ - StStylableIface *iface; - - g_return_val_if_fail (ST_IS_STYLABLE (stylable), FALSE); - - iface = ST_STYLABLE_GET_IFACE (stylable); - if (iface->get_viewport) - return iface->get_viewport (stylable, x, y, width, height); - else - return FALSE; -} - - -/** - * st_stylable_changed: - * @stylable: A #StStylable - * - * Emit the "stylable-changed" signal on @stylable - */ -void -st_stylable_changed (StStylable *stylable) -{ - g_signal_emit (stylable, stylable_signals[CHANGED], 0, NULL); -} diff --git a/src/st/st-stylable.h b/src/st/st-stylable.h deleted file mode 100644 index fe88b2088..000000000 --- a/src/st/st-stylable.h +++ /dev/null @@ -1,125 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* - * st-stylable.h: Interface for stylable objects - * - * 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: Emmanuele Bassi - * Thomas Wood - * - */ - -#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION) -#error "Only can be included directly.h" -#endif - -#ifndef __ST_STYLABLE_H__ -#define __ST_STYLABLE_H__ - -#include -#include - -G_BEGIN_DECLS - -#define ST_TYPE_STYLABLE (st_stylable_get_type ()) -#define ST_STYLABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_STYLABLE, StStylable)) -#define ST_IS_STYLABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_STYLABLE)) -#define ST_STYLABLE_IFACE(iface) (G_TYPE_CHECK_CLASS_CAST ((iface), ST_TYPE_STYLABLE, StStylableIface)) -#define ST_IS_STYLABLE_IFACE(iface) (G_TYPE_CHECK_CLASS_TYPE ((iface), ST_TYPE_STYLABLE)) -#define ST_STYLABLE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), ST_TYPE_STYLABLE, StStylableIface)) - -/* StStylableIface is defined in st-style.h */ - -struct _StStylableIface -{ - GTypeInterface g_iface; - - /* virtual functions */ - StStyle * (* get_style) (StStylable *stylable); - void (* set_style) (StStylable *stylable, - StStyle *style); - - /* context virtual functions */ - StStylable *(*get_container) (StStylable *stylable); - StStylable *(*get_base_style) (StStylable *stylable); - const gchar *(*get_style_id) (StStylable *stylable); - const gchar *(*get_style_type) (StStylable *stylable); - const gchar *(*get_style_class) (StStylable *stylable); - const gchar *(*get_pseudo_class) (StStylable *stylable); - gchar *(*get_attribute) (StStylable *stylable, - const gchar *name); - gboolean (*get_viewport) (StStylable *stylable, - gint *x, - gint *y, - gint *width, - gint *height); - - /* signals, not vfuncs */ - void (* style_notify) (StStylable *stylable, - GParamSpec *pspec); - void (* style_changed) (StStylable *stylable); - - void (* stylable_changed) (StStylable *stylable); -}; - -GType st_stylable_get_type (void) G_GNUC_CONST; - -void st_stylable_iface_install_property (StStylableIface *iface, - GType owner_type, - GParamSpec *pspec); - -void st_stylable_freeze_notify (StStylable *stylable); -void st_stylable_notify (StStylable *stylable, - const gchar *property_name); -void st_stylable_thaw_notify (StStylable *stylable); -GParamSpec **st_stylable_list_properties (StStylable *stylable, - guint *n_props); -GParamSpec * st_stylable_find_property (StStylable *stylable, - const gchar *property_name); -void st_stylable_set_style (StStylable *stylable, - StStyle *style); -StStyle * st_stylable_get_style (StStylable *stylable); - -void st_stylable_get (StStylable *stylable, - const gchar *first_property_name, - ...) G_GNUC_NULL_TERMINATED; -void st_stylable_get_property (StStylable *stylable, - const gchar *property_name, - GValue *value); -gboolean st_stylable_get_default_value (StStylable *stylable, - const gchar *property_name, - GValue *value_out); - -StStylable* st_stylable_get_container (StStylable *stylable); -StStylable* st_stylable_get_base_style (StStylable *stylable); -const gchar* st_stylable_get_style_id (StStylable *stylable); -const gchar* st_stylable_get_style_type (StStylable *stylable); -const gchar* st_stylable_get_style_class (StStylable *stylable); -const gchar* st_stylable_get_pseudo_class (StStylable *stylable); -gchar* st_stylable_get_attribute (StStylable *stylable, - const gchar *name); -gboolean st_stylable_get_viewport (StStylable *stylable, - gint *x, - gint *y, - gint *width, - gint *height); - -void st_stylable_changed (StStylable *stylable); - -G_END_DECLS - -#endif /* __ST_STYLABLE_H__ */ diff --git a/src/st/st-style.c b/src/st/st-style.c deleted file mode 100644 index d599bb6e8..000000000 --- a/src/st/st-style.c +++ /dev/null @@ -1,781 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* - * 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. - * - */ - -/** - * SECTION:st-style - * @short_description: a data store for style properties - * - * #StStyle is a property data store that can read properties from a style - * sheet. It is queried with objects that implement the StStylable - * interface. - */ - - -#include - -#include -#include - -#include -#include -#include - -#include - -#include - -#include "st-stylable.h" -#include "st-style.h" -#include "st-types.h" -#include "st-marshal.h" -#include "st-widget.h" - -enum -{ - CHANGED, - - LAST_SIGNAL -}; - -#define ST_STYLE_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ST_TYPE_STYLE, StStylePrivate)) - -#define ST_STYLE_ERROR g_style_error_quark () - -typedef struct { - GType value_type; - gchar *value_name; - GValue value; -} StyleProperty; - -struct _StStylePrivate -{ - ccss_stylesheet_t *stylesheet; - GList *image_paths; - - GHashTable *style_hash; - GHashTable *node_hash; -}; - -typedef struct { - ccss_node_t parent; - StStylable *stylable; - StStylableIface *iface; -} st_style_node_t; - -static ccss_function_t const * peek_css_functions (void); - -static ccss_node_class_t * peek_node_class (void); - -static guint style_signals[LAST_SIGNAL] = { 0, }; - -static StStyle *default_style = NULL; - -G_DEFINE_TYPE (StStyle, st_style, G_TYPE_OBJECT); - -static GQuark -g_style_error_quark (void) -{ - return g_quark_from_static_string ("st-style-error-quark"); -} - -static gboolean -st_style_real_load_from_file (StStyle *style, - const gchar *filename, - GError **error, - gint priority) -{ - StStylePrivate *priv; - ccss_grammar_t *grammar; - GError *internal_error; - gchar *path; - GList *l; - - g_return_val_if_fail (ST_IS_STYLE (style), FALSE); - g_return_val_if_fail (filename != NULL, FALSE); - - priv = ST_STYLE (style)->priv; - - if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) - { - internal_error = g_error_new (ST_STYLE_ERROR, - ST_STYLE_ERROR_INVALID_FILE, - _("Invalid theme file '%s'"), filename); - g_propagate_error (error, internal_error); - return FALSE; - } - - - /* add the path of the stylesheet to the search path */ - path = g_path_get_dirname (filename); - - /* make sure path is valid */ - if (!path) - return TRUE; - - for (l = priv->image_paths; l; l = l->next) - { - if (g_str_equal ((gchar *) l->data, path)) - { - /* we have this path already */ - g_free (path); - path = NULL; - } - } - - /* Add the new path */ - if (path) - priv->image_paths = g_list_append (priv->image_paths, path); - - /* now load the stylesheet */ - if (!priv->stylesheet) - { - grammar = ccss_grammar_create_css (); - ccss_grammar_add_functions (grammar, peek_css_functions ()); - priv->stylesheet = ccss_grammar_create_stylesheet_from_file (grammar, - filename, - path); - ccss_grammar_destroy (grammar); - } - else - { - ccss_stylesheet_add_from_file (priv->stylesheet, filename, priority, path); - } - - g_signal_emit (style, style_signals[CHANGED], 0, NULL); - - return TRUE; -} - -/** - * st_style_load_from_file: - * @style: a #StStyle - * @filename: filename of the style sheet to load - * @error: a #GError or #NULL - * - * Load style information from the specified file. - * - * returns: TRUE if the style information was loaded successfully. Returns - * FALSE on error. - */ -gboolean -st_style_load_from_file (StStyle *style, - const gchar *filename, - GError **error) -{ - return st_style_real_load_from_file (style, filename, error, - CCSS_STYLESHEET_AUTHOR); -} - -static void -st_style_load (StStyle *style) -{ - const gchar *env_var; - gchar *rc_file = NULL; - GError *error; - - env_var = g_getenv ("ST_RC_FILE"); - if (env_var && *env_var) - rc_file = g_strdup (env_var); - - if (!rc_file) - rc_file = g_build_filename (PACKAGE_DATA_DIR, - "st", - "style", - "default.css", - NULL); - - error = NULL; - - if (g_file_test (rc_file, G_FILE_TEST_EXISTS)) - { - /* load the default theme with lowest priority */ - if (!st_style_real_load_from_file (style, rc_file, &error, CCSS_STYLESHEET_USER_AGENT)) - { - g_critical ("Unable to load resource file '%s': %s", - rc_file, - error->message); - g_error_free (error); - } - } - - g_free (rc_file); -} - -static void -st_style_finalize (GObject *gobject) -{ - StStylePrivate *priv = ((StStyle *) gobject)->priv; - GList *l; - - for (l = priv->image_paths; l; l = g_list_delete_link (l, l)) - { - g_free (l->data); - } - - G_OBJECT_CLASS (st_style_parent_class)->finalize (gobject); -} - -static void -st_style_class_init (StStyleClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (StStylePrivate)); - - gobject_class->finalize = st_style_finalize; - - /** - * StStyle::changed: - * - * Indicates that the style data has changed in some way. For example, a new - * stylesheet may have been loaded. - */ - - style_signals[CHANGED] = - g_signal_new ("changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (StStyleClass, changed), - NULL, NULL, - _st_marshal_VOID__VOID, - G_TYPE_NONE, 0); -} - -/* url loader for libccss */ -static char * -ccss_url (GSList const *args, - void *user_data) -{ - const gchar *given_path, *filename; - gchar *test_path; - - g_return_val_if_fail (args, NULL); - - given_path = (char const *) args->data; - - /* we can only deal with local paths */ - if (!g_str_has_prefix (given_path, "file://")) - return NULL; - filename = &given_path[7]; - - /* - * Handle absolute paths correctly - */ - if (*filename == '/') - return strdup (filename); - - /* first try looking in the theme dir */ - test_path = g_build_filename (g_get_user_config_dir (), - "st", - filename, - NULL); - if (g_file_test (test_path, G_FILE_TEST_IS_REGULAR)) - return test_path; - g_free (test_path); - - if (user_data) - { - test_path = g_build_filename ((gchar *) user_data, filename, NULL); - - if (g_file_test (test_path, G_FILE_TEST_IS_REGULAR)) - return test_path; - - g_free (test_path); - } - else - { - g_warning ("No path available css url resolver!"); - } - - /* couldn't find the image anywhere, so just return the filename */ - return strdup (given_path); -} - -static ccss_function_t const * -peek_css_functions (void) -{ - static ccss_function_t const ccss_functions[] = - { - { "url", ccss_url }, - { NULL } - }; - - return ccss_functions; -} - - -static void -st_style_init (StStyle *style) -{ - StStylePrivate *priv; - - style->priv = priv = ST_STYLE_GET_PRIVATE (style); - - /* create a hash table to look up pointer keys and values */ - style->priv->node_hash = g_hash_table_new_full (NULL, NULL, - NULL, g_free); - style->priv->style_hash = g_hash_table_new_full (NULL, NULL, - NULL, (GDestroyNotify) ccss_style_destroy); - - st_style_load (style); -} - -/** - * st_style_new: - * - * Creates a new #StStyle object. This must be freed using #g_object_unref - * when no longer required. - * - * Returns: a newly allocated #StStyle - */ -StStyle * -st_style_new (void) -{ - return g_object_new (ST_TYPE_STYLE, NULL); -} - -/** - * st_style_get_default: - * - * Return the default StStyle object. This includes the current theme (if - * any). - * - * Returns: (transfer none): a #StStyle object. This must not be freed or - * unref'd by applications - */ -StStyle * -st_style_get_default (void) -{ - if (G_LIKELY (default_style)) - return default_style; - - default_style = g_object_new (ST_TYPE_STYLE, NULL); - - return default_style; -} - -/* functions for ccss */ - -static st_style_node_t * -get_container (st_style_node_t *node) -{ - st_style_node_t *container; - ClutterActor *parent; - - g_return_val_if_fail (node, NULL); - g_return_val_if_fail (node->iface, NULL); - g_return_val_if_fail (node->stylable, NULL); - - parent = clutter_actor_get_parent (CLUTTER_ACTOR (node->stylable)); - while (parent && !ST_IS_WIDGET (parent)) - parent = clutter_actor_get_parent (CLUTTER_ACTOR (parent)); - - if (!parent) - return NULL; - - container = g_new0 (st_style_node_t, 1); - ccss_node_init ((ccss_node_t*) container, peek_node_class ()); - container->iface = node->iface; - container->stylable = ST_STYLABLE (parent); - - return container; -} - -static const gchar* -get_style_id (st_style_node_t *node) -{ - return st_stylable_get_style_id (node->stylable); -} - -static const gchar* -get_style_type (st_style_node_t *node) -{ - return st_stylable_get_style_type (node->stylable); -} - -static const gchar* -get_style_class (st_style_node_t *node) -{ - return st_stylable_get_style_class (node->stylable); -} - -static const gchar* -get_pseudo_class (st_style_node_t *node) -{ - return st_stylable_get_pseudo_class (node->stylable); -} - -static const gchar* -get_attribute (st_style_node_t *node, - const char *name) -{ - return st_stylable_get_attribute (node->stylable, name); -} - -static void -release (st_style_node_t *node) -{ - g_return_if_fail (node); - - g_free (node); -} - -static ccss_node_class_t * -peek_node_class (void) -{ - static ccss_node_class_t _node_class = { - .is_a = NULL, - .get_container = (ccss_node_get_container_f) get_container, - .get_id = (ccss_node_get_id_f) get_style_id, - .get_type = (ccss_node_get_type_f) get_style_type, - .get_class = (ccss_node_get_class_f) get_style_class, - .get_pseudo_class = (ccss_node_get_pseudo_class_f) get_pseudo_class, - .get_viewport = NULL, // (ccss_node_get_viewport_f) get_viewport, - .get_attribute = (ccss_node_get_attribute_f) get_attribute, - .release = (ccss_node_release_f) release - }; - - return &_node_class; -} - -static void -st_style_fetch_ccss_property (ccss_style_t *ccss_style, - GParamSpec *pspec, - GValue *value) -{ - gboolean value_set = FALSE; - - g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec)); - - if (G_PARAM_SPEC_VALUE_TYPE (pspec)) - { - double number; - - if (G_IS_PARAM_SPEC_INT (pspec)) - { - if (ccss_style_get_double (ccss_style, pspec->name, &number)) - { - g_value_set_int (value, (gint) number); - value_set = TRUE; - } - } - else if (G_IS_PARAM_SPEC_UINT (pspec)) - { - if (ccss_style_get_double (ccss_style, pspec->name, &number)) - { - g_value_set_uint (value, (guint) number); - value_set = TRUE; - } - } - else if (G_PARAM_SPEC_VALUE_TYPE (pspec) == ST_TYPE_BORDER_IMAGE && - !g_strcmp0 ("border-image", pspec->name)) - { - ccss_border_image_t const *border_image; - - if (ccss_style_get_property (ccss_style, - "border-image", - (ccss_property_base_t const **) &border_image)) - { - if (border_image && - border_image->base.state == CCSS_PROPERTY_STATE_SET) - { - g_value_set_boxed (value, border_image); - value_set = TRUE; - } - } - } - else if (ST_TYPE_PADDING == G_PARAM_SPEC_VALUE_TYPE (pspec) && - 0 == g_strcmp0 ("padding", pspec->name)) - { - StPadding padding = { 0, }; - gboolean padding_set = 0; - - if (ccss_style_get_double (ccss_style, "padding-top", &number)) - { - padding.top = number; - padding_set = TRUE; - } - - if (ccss_style_get_double (ccss_style, "padding-right", &number)) - { - padding.right = number; - padding_set = TRUE; - } - - if (ccss_style_get_double (ccss_style, "padding-bottom", &number)) - { - padding.bottom = number; - padding_set = TRUE; - } - - if (ccss_style_get_double (ccss_style, "padding-left", &number)) - { - padding.left = number; - padding_set = TRUE; - } - - if (padding_set) - { - g_value_set_boxed (value, &padding); - value_set = TRUE; - } - } - else - { - gchar *string = NULL; - - ccss_style_get_string (ccss_style, pspec->name, &string); - - if (string) - { - if (CLUTTER_IS_PARAM_SPEC_COLOR (pspec)) - { - ClutterColor color = { 0, }; - - clutter_color_from_string (&color, string); - clutter_value_set_color (value, &color); - - value_set = TRUE; - } - else - if (G_IS_PARAM_SPEC_STRING (pspec)) - { - g_value_set_string (value, string); - value_set = TRUE; - } - g_free (string); - } - } - } - - /* no value was found in css, so copy in the default value */ - if (!value_set) - g_param_value_set_default (pspec, value); -} - -static ccss_style_t* -st_style_get_ccss_query (StStyle *style, - StStylable *stylable) -{ - StStylableIface *iface = ST_STYLABLE_GET_IFACE (stylable); - ccss_style_t *ccss_style; - st_style_node_t *ccss_node; - - ccss_node = g_hash_table_lookup (style->priv->node_hash, stylable); - - if (!ccss_node) - { - ccss_node = g_new0 (st_style_node_t, 1); - ccss_node_init ((ccss_node_t*) ccss_node, peek_node_class ()); - ccss_node->iface = iface; - ccss_node->stylable = stylable; - - g_hash_table_insert (style->priv->node_hash, stylable, ccss_node); - g_signal_connect_swapped (stylable, "stylable-changed", - G_CALLBACK (g_hash_table_remove), - style->priv->node_hash); - - - g_object_weak_ref ((GObject*) stylable, - (GWeakNotify) g_hash_table_remove, style->priv->node_hash); - } - - - ccss_style = g_hash_table_lookup (style->priv->style_hash, stylable); - - if (!ccss_style) - { - ccss_style = ccss_stylesheet_query (style->priv->stylesheet, - (ccss_node_t *) ccss_node); - - g_hash_table_insert (style->priv->style_hash, stylable, ccss_style); - - /* remove the cache if the stylable changes */ - g_signal_connect_swapped (stylable, "stylable-changed", - G_CALLBACK (g_hash_table_remove), - style->priv->style_hash); - - g_object_weak_ref ((GObject*) stylable, - (GWeakNotify) g_hash_table_remove, style->priv->style_hash); - } - - return ccss_style; - -} - - -/** - * st_style_get_property: - * @style: the style data store object - * @stylable: a stylable to retreive the data for - * @pspec: a #GParamSpec describing the property required - * @value: (out): a #GValue to place the return value in - * - * Requests the property described in @pspec for the specified stylable - */ - -void -st_style_get_property (StStyle *style, - StStylable *stylable, - GParamSpec *pspec, - GValue *value) -{ - StStylePrivate *priv; - gboolean value_set = FALSE; - - g_return_if_fail (ST_IS_STYLE (style)); - g_return_if_fail (ST_IS_STYLABLE (stylable)); - g_return_if_fail (pspec != NULL); - g_return_if_fail (value != NULL); - - priv = style->priv; - - /* look up the property in the css */ - if (priv->stylesheet) - { - ccss_style_t *ccss_style; - - ccss_style = st_style_get_ccss_query (style, stylable); - if (ccss_style) - { - st_style_fetch_ccss_property (ccss_style, pspec, value); - value_set = TRUE; - } - } - - /* no value was found in css, so copy in the default value */ - if (!value_set) - { - g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec)); - g_param_value_set_default (pspec, value); - } -} - -/** - * st_style_get_valist: - * @style: a #StStyle - * @stylable: a #StStylable - * @first_property_name: name of the first property to get - * @va_args: return location for the first property, followed optionally - * by more name/return location pairs, followed by %NULL - * - * Gets the style properties for @stylable from @style. - * - * Please refer to st_style_get() for further information. - */ -void -st_style_get_valist (StStyle *style, - StStylable *stylable, - const gchar *first_property_name, - va_list va_args) -{ - StStylePrivate *priv; - const gchar *name = first_property_name; - gboolean values_set = FALSE; - - g_return_if_fail (ST_IS_STYLE (style)); - g_return_if_fail (ST_IS_STYLABLE (stylable)); - g_return_if_fail (style->priv != NULL); - - priv = style->priv; - - /* look up the property in the css */ - if (priv->stylesheet) - { - ccss_style_t *ccss_style; - - ccss_style = st_style_get_ccss_query (style, stylable); - - if (ccss_style) - { - while (name) - { - GValue value = { 0, }; - gchar *error = NULL; - GParamSpec *pspec = st_stylable_find_property (stylable, name); - st_style_fetch_ccss_property (ccss_style, pspec, &value); - G_VALUE_LCOPY (&value, va_args, 0, &error); - if (error) - { - g_warning ("%s: %s", G_STRLOC, error); - g_free (error); - g_value_unset (&value); - break; - } - g_value_unset (&value); - name = va_arg (va_args, gchar*); - } - values_set = TRUE; - } - } - - if (!values_set) - { - /* Set the remaining properties to their default values - * even if broken out of the above loop. */ - while (name) - { - GValue value = { 0, }; - gchar *error = NULL; - st_stylable_get_default_value (stylable, name, &value); - G_VALUE_LCOPY (&value, va_args, 0, &error); - if (error) - { - g_warning ("%s: %s", G_STRLOC, error); - g_free (error); - g_value_unset (&value); - break; - } - g_value_unset (&value); - name = va_arg (va_args, gchar*); - } - } -} - -/** - * st_style_get: - * @style: a #StStyle - * @stylable: a #StStylable - * @first_property_name: name of the first property to get - * @Varargs: return location for the first property, followed optionally - * by more name/return location pairs, followed by %NULL - * - * Gets the style properties for @stylable from @style. - * - * In general, a copy is made of the property contents and the caller - * is responsible for freeing the memory in the appropriate manner for - * the property type. - */ -void -st_style_get (StStyle *style, - StStylable *stylable, - const gchar *first_property_name, - ...) -{ - va_list va_args; - - g_return_if_fail (ST_IS_STYLE (style)); - g_return_if_fail (first_property_name != NULL); - - va_start (va_args, first_property_name); - st_style_get_valist (style, stylable, first_property_name, va_args); - va_end (va_args); -} - diff --git a/src/st/st-style.h b/src/st/st-style.h deleted file mode 100644 index 7773905e1..000000000 --- a/src/st/st-style.h +++ /dev/null @@ -1,95 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* - * 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. - * - */ - -#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION) -#error "Only can be included directly.h" -#endif - -#ifndef __ST_STYLE_H__ -#define __ST_STYLE_H__ - -#include -#include - -G_BEGIN_DECLS - -#define ST_TYPE_STYLE (st_style_get_type ()) -#define ST_STYLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_STYLE, StStyle)) -#define ST_IS_STYLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_STYLE)) -#define ST_STYLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ST_TYPE_STYLE, StStyleClass)) -#define ST_IS_STYLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ST_TYPE_STYLE)) -#define ST_STYLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ST_TYPE_STYLE, StStyleClass)) - -typedef struct _StStyle StStyle; -typedef struct _StStylePrivate StStylePrivate; -typedef struct _StStyleClass StStyleClass; - -/* forward declaration */ -typedef struct _StStylable StStylable; /* dummy typedef */ -typedef struct _StStylableIface StStylableIface; - -typedef enum { /*< prefix=ST_STYLE_ERROR >*/ - ST_STYLE_ERROR_INVALID_FILE -} StStyleError; - -/** - * StStyle: - * - * The contents of this structure is private and should only be accessed using - * the provided API. - */ -struct _StStyle -{ - /*< private >*/ - GObject parent_instance; - - StStylePrivate *priv; -}; - -struct _StStyleClass -{ - GObjectClass parent_class; - - void (* changed) (StStyle *style); -}; - -GType st_style_get_type (void) G_GNUC_CONST; - -StStyle *st_style_get_default (void); -StStyle *st_style_new (void); - -gboolean st_style_load_from_file (StStyle *style, - const gchar *filename, - GError **error); -void st_style_get_property (StStyle *style, - StStylable *stylable, - GParamSpec *pspec, - GValue *value); -void st_style_get (StStyle *style, - StStylable *stylable, - const gchar *first_property_name, - ...) G_GNUC_NULL_TERMINATED; -void st_style_get_valist (StStyle *style, - StStylable *stylable, - const gchar *first_property_name, - va_list va_args); - -G_END_DECLS - -#endif /* __ST_STYLE_H__ */ diff --git a/src/st/st-tooltip.c b/src/st/st-tooltip.c index 2ba9b414c..bdbef3a2b 100644 --- a/src/st/st-tooltip.c +++ b/src/st/st-tooltip.c @@ -45,7 +45,6 @@ #include "st-tooltip.h" #include "st-widget.h" -#include "st-stylable.h" #include "st-private.h" enum @@ -121,44 +120,24 @@ st_tooltip_get_property (GObject *gobject, static void st_tooltip_style_changed (StWidget *self) { - ClutterColor *color = NULL; StTooltipPrivate *priv; - gchar *font_name; + StThemeNode *theme_node; + ClutterColor color; + const PangoFontDescription *font; gchar *font_string; - gint font_size; priv = ST_TOOLTIP (self)->priv; + theme_node = st_widget_get_theme_node (self); - st_stylable_get (ST_STYLABLE (self), - "color", &color, - "font-family", &font_name, - "font-size", &font_size, - NULL); + st_theme_node_get_foreground_color (theme_node, &color); + clutter_text_set_color (CLUTTER_TEXT (priv->label), &color); - 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); - } + font = st_theme_node_get_font (theme_node); + font_string = pango_font_description_to_string (font); + clutter_text_set_font_name (CLUTTER_TEXT (priv->label), font_string); + g_free (font_string); + ST_WIDGET_CLASS (st_tooltip_parent_class)->style_changed (self); } static void @@ -406,6 +385,7 @@ st_tooltip_class_init (StTooltipClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); + StWidgetClass *widget_class = ST_WIDGET_CLASS (klass); GParamSpec *pspec; g_type_class_add_private (klass, sizeof (StTooltipPrivate)); @@ -420,6 +400,8 @@ st_tooltip_class_init (StTooltipClass *klass) actor_class->map = st_tooltip_map; actor_class->unmap = st_tooltip_unmap; + widget_class->style_changed = st_tooltip_style_changed; + pspec = g_param_spec_string ("label", "Label", "Label of the tooltip", @@ -453,9 +435,6 @@ st_tooltip_init (StTooltip *tooltip) g_object_set (tooltip, "show-on-set-parent", FALSE, NULL); clutter_actor_set_reactive (CLUTTER_ACTOR (tooltip), FALSE); - - g_signal_connect (tooltip, "style-changed", - G_CALLBACK (st_tooltip_style_changed), NULL); } static void diff --git a/src/st/st-types.h b/src/st/st-types.h index ab775ed09..c434125e6 100644 --- a/src/st/st-types.h +++ b/src/st/st-types.h @@ -37,13 +37,10 @@ G_BEGIN_DECLS -#define ST_TYPE_BORDER_IMAGE (st_border_image_get_type ()) #define ST_TYPE_PADDING (st_padding_get_type ()) typedef struct _StPadding StPadding; -GType st_border_image_get_type (void) G_GNUC_CONST; - /** * StPadding: * @top: padding from the top diff --git a/src/st/st-widget.c b/src/st/st-widget.c index eb7a08059..29cdb0531 100644 --- a/src/st/st-widget.c +++ b/src/st/st-widget.c @@ -32,19 +32,16 @@ #include #include -#include #include "st-widget.h" #include "st-marshal.h" #include "st-private.h" -#include "st-stylable.h" #include "st-texture-cache.h" #include "st-texture-frame.h" +#include "st-theme-context.h" #include "st-tooltip.h" -typedef ccss_border_image_t StBorderImage; - /* * Forward declaration for sake of StWidgetChild */ @@ -53,13 +50,14 @@ struct _StWidgetPrivate StPadding border; StPadding padding; - StStyle *style; + StTheme *theme; + StThemeNode *theme_node; gchar *pseudo_class; gchar *style_class; ClutterActor *border_image; ClutterActor *background_image; - ClutterColor *bg_color; + ClutterColor bg_color; gboolean is_stylable : 1; gboolean has_tooltip : 1; @@ -83,7 +81,7 @@ enum { PROP_0, - PROP_STYLE, + PROP_THEME, PROP_PSEUDO_CLASS, PROP_STYLE_CLASS, @@ -93,12 +91,16 @@ enum PROP_TOOLTIP_TEXT }; -static void st_stylable_iface_init (StStylableIface *iface); +enum +{ + STYLE_CHANGED, + LAST_SIGNAL +}; -G_DEFINE_ABSTRACT_TYPE_WITH_CODE (StWidget, st_widget, CLUTTER_TYPE_ACTOR, - G_IMPLEMENT_INTERFACE (ST_TYPE_STYLABLE, - st_stylable_iface_init)); +static guint signals[LAST_SIGNAL] = { 0, }; + +G_DEFINE_ABSTRACT_TYPE (StWidget, st_widget, CLUTTER_TYPE_ACTOR); #define ST_WIDGET_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ST_TYPE_WIDGET, StWidgetPrivate)) @@ -112,9 +114,8 @@ st_widget_set_property (GObject *gobject, switch (prop_id) { - case PROP_STYLE: - st_stylable_set_style (ST_STYLABLE (actor), - g_value_get_object (value)); + case PROP_THEME: + st_widget_set_theme (actor, g_value_get_object (value)); break; case PROP_PSEUDO_CLASS: @@ -158,8 +159,8 @@ st_widget_get_property (GObject *gobject, switch (prop_id) { - case PROP_STYLE: - g_value_set_object (value, priv->style); + case PROP_THEME: + g_value_set_object (value, priv->theme); break; case PROP_PSEUDO_CLASS: @@ -194,10 +195,10 @@ st_widget_dispose (GObject *gobject) StWidget *actor = ST_WIDGET (gobject); StWidgetPrivate *priv = ST_WIDGET (actor)->priv; - if (priv->style) + if (priv->theme) { - g_object_unref (priv->style); - priv->style = NULL; + g_object_unref (priv->theme); + priv->theme = NULL; } if (priv->border_image) @@ -206,12 +207,6 @@ st_widget_dispose (GObject *gobject) priv->border_image = NULL; } - if (priv->bg_color) - { - clutter_color_free (priv->bg_color); - priv->bg_color = NULL; - } - if (priv->tooltip) { ClutterContainer *parent; @@ -387,7 +382,7 @@ st_widget_paint (ClutterActor *self) klass->draw_background (ST_WIDGET (self), priv->border_image, - priv->bg_color); + &priv->bg_color); if (priv->background_image != NULL) clutter_actor_paint (priv->background_image); @@ -408,7 +403,7 @@ st_widget_parent_set (ClutterActor *widget, /* don't send the style changed signal if we no longer have a parent actor */ if (new_parent) - st_stylable_changed ((StStylable*) widget); + st_widget_style_changed (ST_WIDGET (widget)); } static void @@ -447,69 +442,67 @@ st_widget_unmap (ClutterActor *actor) clutter_actor_unmap ((ClutterActor *) priv->tooltip); } +static void notify_children_of_style_change (ClutterContainer *container); + static void -st_widget_style_changed (StStylable *self) +notify_children_of_style_change_foreach (ClutterActor *actor, + gpointer user_data) +{ + if (ST_IS_WIDGET (actor)) + st_widget_style_changed (ST_WIDGET (actor)); + else if (CLUTTER_IS_CONTAINER (actor)) + notify_children_of_style_change ((ClutterContainer *)actor); +} + +static void +notify_children_of_style_change (ClutterContainer *container) +{ + /* notify our children that their parent stylable has changed */ + clutter_container_foreach (container, + notify_children_of_style_change_foreach, + NULL); +} + +static void +st_widget_real_style_changed (StWidget *self) { StWidgetPrivate *priv = ST_WIDGET (self)->priv; - StBorderImage *border_image = NULL; + StThemeNode *theme_node; + StThemeImage *theme_image; StTextureCache *texture_cache; ClutterTexture *texture; - gchar *bg_file = NULL; - StPadding *padding = NULL; + const char *bg_file = NULL; gboolean relayout_needed = FALSE; gboolean has_changed = FALSE; - ClutterColor *color; + StPadding padding; + ClutterColor color; /* application has request this widget is not stylable */ if (!priv->is_stylable) return; - /* cache these values for use in the paint function */ - st_stylable_get (self, - "background-color", &color, - "background-image", &bg_file, - "border-image", &border_image, - "padding", &padding, - NULL); + theme_node = st_widget_get_theme_node (self); - if (color) + st_theme_node_get_background_color (theme_node, &color); + if (!clutter_color_equal (&color, &priv->bg_color)) { - if (priv->bg_color && clutter_color_equal (color, priv->bg_color)) - { - /* color is the same ... */ - clutter_color_free (color); - } - else - { - clutter_color_free (priv->bg_color); - priv->bg_color = color; - has_changed = TRUE; - } - } - else - if (priv->bg_color) - { - clutter_color_free (priv->bg_color); - priv->bg_color = NULL; + priv->bg_color = color; has_changed = TRUE; } + padding.top = st_theme_node_get_padding (theme_node, ST_SIDE_TOP); + padding.right = st_theme_node_get_padding (theme_node, ST_SIDE_RIGHT); + padding.bottom = st_theme_node_get_padding (theme_node, ST_SIDE_BOTTOM); + padding.left = st_theme_node_get_padding (theme_node, ST_SIDE_LEFT); - - if (padding) + if (priv->padding.top != padding.top || + priv->padding.left != padding.left || + priv->padding.right != padding.right || + priv->padding.bottom != padding.bottom) { - if (priv->padding.top != padding->top || - priv->padding.left != padding->left || - priv->padding.right != padding->right || - priv->padding.bottom != padding->bottom) - { - /* Padding changed. Need to relayout. */ - has_changed = TRUE; - relayout_needed = TRUE; - } - - priv->padding = *padding; - g_boxed_free (ST_TYPE_PADDING, padding); + priv->padding = padding; + has_changed = TRUE; + relayout_needed = TRUE; } if (priv->border_image) @@ -526,25 +519,26 @@ st_widget_style_changed (StStylable *self) texture_cache = st_texture_cache_get_default (); - /* Check if the URL is actually present, not garbage in the property */ - if (border_image && border_image->uri) + theme_image = st_theme_node_get_background_theme_image (theme_node); + if (theme_image) { + const char *filename; gint border_left, border_right, border_top, border_bottom; gint width, height; + filename = st_theme_image_get_filename (theme_image); + /* `border-image' takes precedence over `background-image'. * Firefox lets the background-image shine thru when border-image has * alpha an channel, maybe that would be an option for the future. */ texture = st_texture_cache_get_texture (texture_cache, - border_image->uri); + filename); clutter_texture_get_base_size (CLUTTER_TEXTURE (texture), &width, &height); - border_left = ccss_position_get_size (&border_image->left, width); - border_top = ccss_position_get_size (&border_image->top, height); - border_right = ccss_position_get_size (&border_image->right, width); - border_bottom = ccss_position_get_size (&border_image->bottom, height); + st_theme_image_get_borders (theme_image, + &border_left, &border_right, &border_top, &border_bottom); priv->border_image = st_texture_frame_new (texture, border_top, @@ -552,14 +546,13 @@ st_widget_style_changed (StStylable *self) border_bottom, border_left); clutter_actor_set_parent (priv->border_image, CLUTTER_ACTOR (self)); - g_boxed_free (ST_TYPE_BORDER_IMAGE, border_image); has_changed = TRUE; relayout_needed = TRUE; } - if (bg_file != NULL && - strcmp (bg_file, "none")) + bg_file = st_theme_node_get_background_image (theme_node); + if (bg_file != NULL) { texture = st_texture_cache_get_texture (texture_cache, bg_file); priv->background_image = (ClutterActor*) texture; @@ -575,7 +568,6 @@ st_widget_style_changed (StStylable *self) has_changed = TRUE; relayout_needed = TRUE; } - g_free (bg_file); /* If there are any properties above that need to cause a relayout thay * should set this flag. @@ -588,37 +580,89 @@ st_widget_style_changed (StStylable *self) clutter_actor_queue_redraw ((ClutterActor *) self); } - priv->is_style_dirty = FALSE; + if (CLUTTER_IS_CONTAINER (self)) + notify_children_of_style_change ((ClutterContainer *)self); } -static void -st_widget_stylable_child_notify (ClutterActor *actor, - gpointer user_data) +void +st_widget_style_changed (StWidget *widget) { - if (ST_IS_STYLABLE (actor)) - st_stylable_changed ((StStylable*) actor); -} - -static void -st_widget_stylable_changed (StStylable *stylable) -{ - - ST_WIDGET (stylable)->priv->is_style_dirty = TRUE; + widget->priv->is_style_dirty = TRUE; + if (widget->priv->theme_node) + { + g_object_unref (widget->priv->theme_node); + widget->priv->theme_node = NULL; + } /* update the style only if we are mapped */ - if (!CLUTTER_ACTOR_IS_MAPPED ((ClutterActor *) stylable)) + if (!CLUTTER_ACTOR_IS_MAPPED (CLUTTER_ACTOR (widget))) return; - g_signal_emit_by_name (stylable, "style-changed", 0); + st_widget_ensure_style (widget); +} +static void +on_theme_context_changed (StThemeContext *context, + ClutterStage *stage) +{ + notify_children_of_style_change (CLUTTER_CONTAINER (stage)); +} - if (CLUTTER_IS_CONTAINER (stylable)) +static StThemeNode * +get_root_theme_node (ClutterStage *stage) +{ + StThemeContext *context = st_theme_context_get_for_stage (stage); + + if (!g_object_get_data (G_OBJECT (context), "st-theme-initialized")) { - /* notify our children that their parent stylable has changed */ - clutter_container_foreach ((ClutterContainer *) stylable, - st_widget_stylable_child_notify, - NULL); + g_object_set_data (G_OBJECT (context), "st-theme-initialized", GUINT_TO_POINTER (1)); + g_signal_connect (G_OBJECT (context), "changed", + G_CALLBACK (on_theme_context_changed), stage); } + + return st_theme_context_get_root_node (context); +} + +StThemeNode * +st_widget_get_theme_node (StWidget *widget) +{ + StWidgetPrivate *priv = widget->priv; + + if (priv->theme_node == NULL) + { + StThemeNode *parent_node = NULL; + ClutterStage *stage = NULL; + ClutterActor *parent; + + parent = clutter_actor_get_parent (CLUTTER_ACTOR (widget)); + while (parent != NULL) + { + if (parent_node == NULL && ST_IS_WIDGET (parent)) + parent_node = st_widget_get_theme_node (ST_WIDGET (parent)); + else if (CLUTTER_IS_STAGE (parent)) + stage = CLUTTER_STAGE (parent); + + parent = clutter_actor_get_parent (parent); + } + + if (stage == NULL) + { + g_warning ("st_widget_get_theme_node called on a widget not in a stage"); + stage = CLUTTER_STAGE (clutter_stage_get_default ()); + } + + if (parent_node == NULL) + parent_node = get_root_theme_node (CLUTTER_STAGE (stage)); + + priv->theme_node = st_theme_node_new (st_theme_context_get_for_stage (stage), + parent_node, priv->theme, + G_OBJECT_TYPE (widget), + clutter_actor_get_name (CLUTTER_ACTOR (widget)), + priv->style_class, + priv->pseudo_class); + } + + return priv->theme_node; } static gboolean @@ -691,6 +735,7 @@ st_widget_class_init (StWidgetClass *klass) actor_class->hide = st_widget_hide; klass->draw_background = st_widget_real_draw_background; + klass->style_changed = st_widget_real_style_changed; /** * StWidget:pseudo-class: @@ -718,7 +763,19 @@ st_widget_class_init (StWidgetClass *klass) "", ST_PARAM_READWRITE)); - g_object_class_override_property (gobject_class, PROP_STYLE, "style"); + /** + * StWidget:theme + * + * A theme set on this actor overriding the global theming for this actor + * and its descendants + */ + g_object_class_install_property (gobject_class, + PROP_THEME, + g_param_spec_object ("theme", + "Theme", + "Theme override", + ST_TYPE_THEME, + ST_PARAM_READWRITE)); /** * StWidget:stylable: @@ -762,108 +819,66 @@ st_widget_class_init (StWidgetClass *klass) ST_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_TOOLTIP_TEXT, pspec); + /** + * StWidget::style-changed: + * + * Emitted when the style information that the widget derives from the + * theme changes + */ + signals[STYLE_CHANGED] = + g_signal_new ("style-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (StWidgetClass, style_changed), + NULL, NULL, + _st_marshal_VOID__VOID, + G_TYPE_NONE, 0); } -static StStyle * -st_widget_get_style (StStylable *stylable) +/** + * st_widget_set_theme: + * @actor: a #StWidget + * @theme: a new style class string + * + * Overrides the theme that would be inherited from the actor's parent + * or the stage with an entirely new theme (set of stylesheets). + */ +void +st_widget_set_theme (StWidget *actor, + StTheme *theme) { - StWidgetPrivate *priv = ST_WIDGET (stylable)->priv; + StWidgetPrivate *priv = actor->priv; - return priv->style; + g_return_if_fail (ST_IS_WIDGET (actor)); + + priv = actor->priv; + + if (theme !=priv->theme) + { + if (priv->theme) + g_object_unref (priv->theme); + priv->theme = g_object_ref (priv->theme); + + st_widget_style_changed (actor); + + g_object_notify (G_OBJECT (actor), "theme"); + } } -static void -st_style_changed_cb (StStyle *style, - StStylable *stylable) +/** + * st_widget_get_theme: + * @actor: a #StWidget + * + * Gets the overriding theme set on the actor. See st_widget_set_theme() + * + * Return value: (transfer none): the overriding theme, or %NULL + */ +StTheme * +st_widget_get_theme (StWidget *actor) { - st_stylable_changed (stylable); -} + g_return_val_if_fail (ST_IS_WIDGET (actor), NULL); - -static void -st_widget_set_style (StStylable *stylable, - StStyle *style) -{ - StWidgetPrivate *priv = ST_WIDGET (stylable)->priv; - - if (priv->style) - g_object_unref (priv->style); - - priv->style = g_object_ref_sink (style); - - g_signal_connect (priv->style, - "changed", - G_CALLBACK (st_style_changed_cb), - stylable); -} - -static StStylable* -st_widget_get_container (StStylable *stylable) -{ - ClutterActor *parent; - - g_return_val_if_fail (ST_IS_WIDGET (stylable), NULL); - - parent = clutter_actor_get_parent (CLUTTER_ACTOR (stylable)); - - if (ST_IS_STYLABLE (parent)) - return ST_STYLABLE (parent); - else - return NULL; -} - -static StStylable* -st_widget_get_base_style (StStylable *stylable) -{ - return NULL; -} - -static const gchar* -st_widget_get_style_id (StStylable *stylable) -{ - g_return_val_if_fail (ST_IS_WIDGET (stylable), NULL); - - return clutter_actor_get_name (CLUTTER_ACTOR (stylable)); -} - -static const gchar* -st_widget_get_style_type (StStylable *stylable) -{ - return G_OBJECT_TYPE_NAME (stylable); -} - -static const gchar* -st_widget_get_style_class (StStylable *stylable) -{ - g_return_val_if_fail (ST_IS_WIDGET (stylable), NULL); - - return ST_WIDGET (stylable)->priv->style_class; -} - -static const gchar* -st_widget_get_pseudo_class (StStylable *stylable) -{ - g_return_val_if_fail (ST_IS_WIDGET (stylable), NULL); - - return ST_WIDGET (stylable)->priv->pseudo_class; -} - -static gboolean -st_widget_get_viewport (StStylable *stylable, - gint *x, - gint *y, - gint *width, - gint *height) -{ - g_return_val_if_fail (ST_IS_WIDGET (stylable), FALSE); - - *x = 0; - *y = 0; - - *width = clutter_actor_get_width (CLUTTER_ACTOR (stylable)); - *height = clutter_actor_get_height (CLUTTER_ACTOR (stylable)); - - return TRUE; + return actor->priv->theme; } /** @@ -879,7 +894,7 @@ st_widget_set_style_class_name (StWidget *actor, { StWidgetPrivate *priv = actor->priv; - g_return_if_fail (ST_WIDGET (actor)); + g_return_if_fail (ST_IS_WIDGET (actor)); priv = actor->priv; @@ -888,7 +903,7 @@ st_widget_set_style_class_name (StWidget *actor, g_free (priv->style_class); priv->style_class = g_strdup (style_class); - st_stylable_changed ((StStylable*) actor); + st_widget_style_changed (actor); g_object_notify (G_OBJECT (actor), "style-class"); } @@ -907,7 +922,7 @@ st_widget_set_style_class_name (StWidget *actor, const gchar* st_widget_get_style_class_name (StWidget *actor) { - g_return_val_if_fail (ST_WIDGET (actor), NULL); + g_return_val_if_fail (ST_IS_WIDGET (actor), NULL); return actor->priv->style_class; } @@ -924,7 +939,7 @@ st_widget_get_style_class_name (StWidget *actor) const gchar* st_widget_get_style_pseudo_class (StWidget *actor) { - g_return_val_if_fail (ST_WIDGET (actor), NULL); + g_return_val_if_fail (ST_IS_WIDGET (actor), NULL); return actor->priv->pseudo_class; } @@ -942,7 +957,7 @@ st_widget_set_style_pseudo_class (StWidget *actor, { StWidgetPrivate *priv; - g_return_if_fail (ST_WIDGET (actor)); + g_return_if_fail (ST_IS_WIDGET (actor)); priv = actor->priv; @@ -951,99 +966,18 @@ st_widget_set_style_pseudo_class (StWidget *actor, g_free (priv->pseudo_class); priv->pseudo_class = g_strdup (pseudo_class); - st_stylable_changed ((StStylable*) actor); + st_widget_style_changed (actor); g_object_notify (G_OBJECT (actor), "pseudo-class"); } } - -static void -st_stylable_iface_init (StStylableIface *iface) -{ - static gboolean is_initialized = FALSE; - - if (!is_initialized) - { - GParamSpec *pspec; - ClutterColor color = { 0x00, 0x00, 0x00, 0xff }; - ClutterColor bg_color = { 0xff, 0xff, 0xff, 0x00 }; - - is_initialized = TRUE; - - pspec = clutter_param_spec_color ("background-color", - "Background Color", - "The background color of an actor", - &bg_color, - G_PARAM_READWRITE); - st_stylable_iface_install_property (iface, ST_TYPE_WIDGET, pspec); - - pspec = clutter_param_spec_color ("color", - "Text Color", - "The color of the text of an actor", - &color, - G_PARAM_READWRITE); - st_stylable_iface_install_property (iface, ST_TYPE_WIDGET, pspec); - - pspec = g_param_spec_string ("background-image", - "Background Image", - "Background image filename", - NULL, - G_PARAM_READWRITE); - st_stylable_iface_install_property (iface, ST_TYPE_WIDGET, pspec); - - pspec = g_param_spec_string ("font-family", - "Font Family", - "Name of the font to use", - "Sans", - G_PARAM_READWRITE); - st_stylable_iface_install_property (iface, ST_TYPE_WIDGET, pspec); - - pspec = g_param_spec_int ("font-size", - "Font Size", - "Size of the font to use in pixels", - 0, G_MAXINT, 12, - G_PARAM_READWRITE); - st_stylable_iface_install_property (iface, ST_TYPE_WIDGET, pspec); - - pspec = g_param_spec_boxed ("border-image", - "Border image", - "9-slice image to use for drawing borders and background", - ST_TYPE_BORDER_IMAGE, - G_PARAM_READWRITE); - st_stylable_iface_install_property (iface, ST_TYPE_WIDGET, pspec); - - pspec = g_param_spec_boxed ("padding", - "Padding", - "Padding between the widget's borders " - "and its content", - ST_TYPE_PADDING, - G_PARAM_READWRITE); - st_stylable_iface_install_property (iface, ST_TYPE_WIDGET, pspec); - - iface->style_changed = st_widget_style_changed; - iface->stylable_changed = st_widget_stylable_changed; - - iface->get_style = st_widget_get_style; - iface->set_style = st_widget_set_style; - iface->get_base_style = st_widget_get_base_style; - iface->get_container = st_widget_get_container; - iface->get_style_id = st_widget_get_style_id; - iface->get_style_type = st_widget_get_style_type; - iface->get_style_class = st_widget_get_style_class; - iface->get_pseudo_class = st_widget_get_pseudo_class; - /* iface->get_attribute = st_widget_get_attribute; */ - iface->get_viewport = st_widget_get_viewport; - } -} - - static void st_widget_name_notify (StWidget *widget, GParamSpec *pspec, gpointer data) { - st_stylable_changed ((StStylable*) widget); + st_widget_style_changed (widget); } static void @@ -1056,44 +990,6 @@ st_widget_init (StWidget *actor) /* connect style changed */ g_signal_connect (actor, "notify::name", G_CALLBACK (st_widget_name_notify), NULL); - - /* set the default style */ - st_widget_set_style (ST_STYLABLE (actor), st_style_get_default ()); - -} - -static StBorderImage * -st_border_image_copy (const StBorderImage *border_image) -{ - StBorderImage *copy; - - g_return_val_if_fail (border_image != NULL, NULL); - - copy = g_slice_new (StBorderImage); - *copy = *border_image; - - return copy; -} - -static void -st_border_image_free (StBorderImage *border_image) -{ - if (G_LIKELY (border_image)) - g_slice_free (StBorderImage, border_image); -} - -GType -st_border_image_get_type (void) -{ - static GType our_type = 0; - - if (G_UNLIKELY (our_type == 0)) - our_type = - g_boxed_type_register_static (I_("StBorderImage"), - (GBoxedCopyFunc) st_border_image_copy, - (GBoxedFreeFunc) st_border_image_free); - - return our_type; } /** @@ -1110,11 +1006,11 @@ st_widget_ensure_style (StWidget *widget) if (widget->priv->is_style_dirty) { - g_signal_emit_by_name (widget, "style-changed", 0); + g_signal_emit (widget, signals[STYLE_CHANGED], 0); + widget->priv->is_style_dirty = FALSE; } } - /** * st_widget_get_border_image: * @actor: A #StWidget @@ -1353,6 +1249,5 @@ st_widget_draw_background (StWidget *self) klass = ST_WIDGET_GET_CLASS (self); klass->draw_background (ST_WIDGET (self), priv->border_image, - priv->bg_color); - + &priv->bg_color); } diff --git a/src/st/st-widget.h b/src/st/st-widget.h index c06cc4f8c..2c636c902 100644 --- a/src/st/st-widget.h +++ b/src/st/st-widget.h @@ -30,6 +30,8 @@ #include #include +#include +#include G_BEGIN_DECLS @@ -73,6 +75,7 @@ struct _StWidgetClass void (* draw_background) (StWidget *self, ClutterActor *background, const ClutterColor *color); + void (* style_changed) (StWidget *self); }; GType st_widget_get_type (void) G_GNUC_CONST; @@ -83,6 +86,9 @@ G_CONST_RETURN gchar *st_widget_get_style_pseudo_class (StWidget *actor); void st_widget_set_style_class_name (StWidget *actor, const gchar *style_class); G_CONST_RETURN gchar *st_widget_get_style_class_name (StWidget *actor); +void st_widget_set_theme (StWidget *actor, + StTheme *theme); +StTheme * st_widget_get_theme (StWidget *actor); void st_widget_set_has_tooltip (StWidget *widget, gboolean has_tooltip); @@ -98,6 +104,9 @@ void st_widget_ensure_style (StWidget *widget); /* Only to be used by sub-classes of StWidget */ +void st_widget_style_changed (StWidget *widget); +StThemeNode *st_widget_get_theme_node (StWidget *widget); + ClutterActor *st_widget_get_background_image (StWidget *actor); ClutterActor *st_widget_get_border_image (StWidget *actor); void st_widget_get_padding (StWidget *widget, diff --git a/tests/Makefile.am b/tests/Makefile.am index 885804241..43bfbb522 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -14,5 +14,6 @@ run-test.sh: run-test.sh.in $(AM_V_GEN) sed \ -e "s|@GJS_JS_DIR[@]|$(GJS_JS_DIR)|" \ -e "s|@GJS_JS_NATIVE_DIR[@]|$(GJS_JS_NATIVE_DIR)|" \ + -e "s|@MUTTER_LIB_DIR[@]|$(MUTTER_LIB_DIR)|" \ -e "s|@srcdir[@]|$(srcdir)|" \ $< > $@ && chmod a+x $@ diff --git a/tests/interactive/css-fonts.js b/tests/interactive/css-fonts.js new file mode 100644 index 000000000..273177646 --- /dev/null +++ b/tests/interactive/css-fonts.js @@ -0,0 +1,39 @@ +/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ + +const Clutter = imports.gi.Clutter; +const St = imports.gi.St; + +const UI = imports.testcommon.ui; + +UI.init(); +let stage = Clutter.Stage.get_default(); + +let b = new St.BoxLayout({ vertical: true, + width: stage.width, + height: stage.height }); +stage.add_actor(b); + +let t; + +t = new St.Label({ "text": "Bold", style_class: "bold" }); +b.add(t); +t = new St.Label({ "text": "Monospace", style_class: "monospace" }); +b.add(t); +t = new St.Label({ "text": "Italic", style_class: "italic" }); +b.add(t); +t = new St.Label({ "text": "Bold Italic", style_class: "bold italic" }); +b.add(t); +t = new St.Label({ "text": "Big Italic", style_class: "big italic" }); +b.add(t); +t = new St.Label({ "text": "Big Bold", style_class: "big bold" }); +b.add(t); + +let b2 = new St.BoxLayout({ vertical: true, style_class: "monospace" }); +b.add(b2); +t = new St.Label({ "text": "Big Monospace", style_class: "big" }); +b2.add(t); +t = new St.Label({ "text": "Italic Monospace", style_class: "italic" }); +b2.add(t); + +stage.show(); +Clutter.main(); diff --git a/tests/interactive/scrolling.js b/tests/interactive/scrolling.js new file mode 100644 index 000000000..15f985cee --- /dev/null +++ b/tests/interactive/scrolling.js @@ -0,0 +1,28 @@ +/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ + +const Clutter = imports.gi.Clutter; +const St = imports.gi.St; + +const UI = imports.testcommon.ui; + +UI.init(); +let stage = Clutter.Stage.get_default(); + +let v = new St.ScrollView({}); +stage.add_actor(v); +let b = new St.BoxLayout({ vertical: true, + width: stage.width, + height: stage.height }); +v.add_actor(b); + +let cc_a = "a".charCodeAt(0); +let s = ""; +for (let i = 0; i < 26 * 3; i++) { + s += String.fromCharCode(cc_a + i % 26); + + let t = new St.Label({ "text": s}); + b.add(t); +} + +stage.show(); +Clutter.main(); diff --git a/tests/run-test.sh.in b/tests/run-test.sh.in index ce1ce3e3b..4436187d8 100644 --- a/tests/run-test.sh.in +++ b/tests/run-test.sh.in @@ -26,7 +26,7 @@ builddir=`cd $builddir && pwd` srcdir=$builddir/@srcdir@ srcdir=`cd $srcdir && pwd` -GI_TYPELIB_PATH="$builddir/../src" +GI_TYPELIB_PATH="@MUTTER_LIB_DIR@/mutter:$builddir/../src" GJS_DEBUG_OUTPUT=stderr $verbose || GJS_DEBUG_TOPICS="JS ERROR;JS LOG" GNOME_SHELL_TESTSDIR="$srcdir/" diff --git a/tests/testcommon/test.css b/tests/testcommon/test.css index 0e1b3ace7..6ce3d5dc0 100644 --- a/tests/testcommon/test.css +++ b/tests/testcommon/test.css @@ -1,13 +1,33 @@ @import "../../data/theme/gnome-shell.css"; -*.red { +stage { + font: 16pt serif; +} + +.red { background-color: red; } -*.green { +.green { background-color: green; } -*.blue { +.blue { background-color: blue; } + +.bold { + font-weight: bold; +} + +.italic { + font-style: italic; +} + +.big { + font-size: 150%; +} + +.monospace { + font-family: monospace; +} diff --git a/tests/testcommon/ui.js b/tests/testcommon/ui.js index 219bf4782..7110c65a1 100644 --- a/tests/testcommon/ui.js +++ b/tests/testcommon/ui.js @@ -3,6 +3,7 @@ const Clutter = imports.gi.Clutter; const GLib = imports.gi.GLib; const St = imports.gi.St; +const Shell = imports.gi.Shell; const Environment = imports.ui.environment; @@ -10,7 +11,9 @@ function init() { Clutter.init(null, null); Environment.init(); - let style = St.Style.get_default(); + let stage = Clutter.Stage.get_default(); + let context = St.ThemeContext.get_for_stage (stage); let stylesheetPath = GLib.getenv("GNOME_SHELL_TESTSDIR") + "/testcommon/test.css"; - style.load_from_file(stylesheetPath); + let theme = new St.Theme ({ application_stylesheet: stylesheetPath }); + context.set_theme (theme); }