/* Invalidate style to recompute styles */ static void _xfdashboard_actor_stylable_invalidate(XfdashboardStylable *inStylable) { XfdashboardActor *self; XfdashboardActorPrivate *priv; XfdashboardActorClass *klass; XfdashboardTheme *theme; XfdashboardThemeCSS *themeCSS; GHashTable *possibleStyleSet; GParamSpec *paramSpec; GHashTableIter hashIter; GHashTable *themeStyleSet; gchar *styleName; XfdashboardThemeCSSValue *styleValue; gboolean didChange; #ifdef DEBUG gboolean doDebug=FALSE; #endif g_return_if_fail(XFDASHBOARD_IS_ACTOR(inStylable)); self=XFDASHBOARD_ACTOR(inStylable); priv=self->priv; klass=XFDASHBOARD_ACTOR_GET_CLASS(self); didChange=FALSE; /* Only recompute style for mapped actors or if revalidation was forced */ if(!priv->forceStyleRevalidation && !clutter_actor_is_mapped(CLUTTER_ACTOR(self))) return; /* Get theme CSS */ theme=xfdashboard_application_get_theme(NULL); themeCSS=xfdashboard_theme_get_css(theme); /* First get list of all stylable properties of this and parent classes. * It is used to determine if key in theme style sets are valid. */ possibleStyleSet=xfdashboard_actor_get_stylable_properties_full(klass); #ifdef DEBUG if(doDebug) { gint i=0; gchar *defaultsKey; GValue defaultsVal=G_VALUE_INIT; gchar *defaultsValStr; GParamSpec *realParamSpec; XFDASHBOARD_DEBUG(self, STYLE, "Got param specs for %p (%s) with class '%s' and pseudo-class '%s'", self, G_OBJECT_TYPE_NAME(self), priv->styleClasses, priv->stylePseudoClasses); g_hash_table_iter_init(&hashIter, possibleStyleSet); while(g_hash_table_iter_next(&hashIter, (gpointer*)&defaultsKey, (gpointer*)¶mSpec)) { realParamSpec=(GParamSpec*)g_param_spec_get_qdata(paramSpec, XFDASHBOARD_ACTOR_PARAM_SPEC_REF); g_value_init(&defaultsVal, G_PARAM_SPEC_VALUE_TYPE(realParamSpec)); g_param_value_set_default(realParamSpec, &defaultsVal); defaultsValStr=g_strdup_value_contents(&defaultsVal); XFDASHBOARD_DEBUG(self, STYLE, "%d: param spec [%s] %s=%s\n", ++i, G_OBJECT_CLASS_NAME(klass), defaultsKey, defaultsValStr); g_free(defaultsValStr); g_value_unset(&defaultsVal); } XFDASHBOARD_DEBUG(self, STYLE, "End of param specs"); } #endif /* Get style information from theme */ themeStyleSet=xfdashboard_theme_css_get_properties(themeCSS, XFDASHBOARD_STYLABLE(self)); #ifdef DEBUG if(doDebug) { gint i=0; XFDASHBOARD_DEBUG(self, STYLE, "Got styles from theme for %p (%s) with class '%s' and pseudo-class '%s'", self, G_OBJECT_TYPE_NAME(self), priv->styleClasses, priv->stylePseudoClasses); g_hash_table_iter_init(&hashIter, themeStyleSet); while(g_hash_table_iter_next(&hashIter, (gpointer*)&styleName, (gpointer*)&styleValue)) { XFDASHBOARD_DEBUG(self, STYLE, "%d: [%s] %s=%s\n", ++i, styleValue->source, (gchar*)styleName, styleValue->string); } XFDASHBOARD_DEBUG(self, STYLE, "End of styles from theme"); } #endif /* The 'property-changed' notification will be freezed and thawed * (fired at once) after all stylable properties of this instance are set. */ g_object_freeze_notify(G_OBJECT(self)); /* Iterate through style information retrieved from theme and * set the corresponding property in object instance if key * is valid. */ g_hash_table_iter_init(&hashIter, themeStyleSet); while(g_hash_table_iter_next(&hashIter, (gpointer*)&styleName, (gpointer*)&styleValue)) { GValue cssValue=G_VALUE_INIT; GValue propertyValue=G_VALUE_INIT; GParamSpec *realParamSpec; /* Check if key is a valid object property name */ if(!g_hash_table_lookup_extended(possibleStyleSet, styleName, NULL, (gpointer*)¶mSpec)) continue; /* Get original referenced parameter specification. It does not need * to be referenced while converting because it is valid as this * value is stored in hashtable. */ realParamSpec=(GParamSpec*)g_param_spec_get_qdata(paramSpec, XFDASHBOARD_ACTOR_PARAM_SPEC_REF); /* Convert style value to type of object property and set value * if conversion was successful. Otherwise do nothing. */ g_value_init(&cssValue, G_TYPE_STRING); g_value_set_string(&cssValue, styleValue->string); g_value_init(&propertyValue, G_PARAM_SPEC_VALUE_TYPE(realParamSpec)); if(g_param_value_convert(realParamSpec, &cssValue, &propertyValue, FALSE)) { g_object_set_property(G_OBJECT(self), styleName, &propertyValue); didChange=TRUE; #ifdef DEBUG if(doDebug) { gchar *valstr; valstr=g_strdup_value_contents(&propertyValue); XFDASHBOARD_DEBUG(self, STYLE, "Setting theme value of style property [%s] %s=%s\n", G_OBJECT_CLASS_NAME(klass), styleName, valstr); g_free(valstr); } #endif } else { g_warning(_("Could not transform CSS string value for property '%s' to type %s of class %s"), styleName, g_type_name(G_PARAM_SPEC_VALUE_TYPE(realParamSpec)), G_OBJECT_CLASS_NAME(klass)); } /* Release allocated resources */ g_value_unset(&propertyValue); g_value_unset(&cssValue); } /* Now remove all duplicate keys in set of properties changed we set the last * time. The remaining keys determine the properties which were set the last * time but not this time and should be restored to their default values. */ if(priv->lastThemeStyleSet) { /* Remove duplicate keys from set of last changed properties */ g_hash_table_foreach_remove(priv->lastThemeStyleSet, (GHRFunc)_xfdashboard_actor_hashtable_is_duplicate_key, themeStyleSet); /* Iterate through remaining key and restore corresponding object properties * to their default values. */ g_hash_table_iter_init(&hashIter, priv->lastThemeStyleSet); while(g_hash_table_iter_next(&hashIter, (gpointer*)&styleName, (gpointer*)¶mSpec)) { GValue propertyValue=G_VALUE_INIT; GParamSpec *realParamSpec; /* Check if key is a valid object property name */ if(!g_hash_table_lookup_extended(possibleStyleSet, styleName, NULL, (gpointer*)¶mSpec)) continue; /* Get original referenced parameter specification. It does not need * to be referenced while converting because it is valid as this * value is stored in hashtable. */ realParamSpec=(GParamSpec*)g_param_spec_get_qdata(paramSpec, XFDASHBOARD_ACTOR_PARAM_SPEC_REF); /* Initialize property value to its type and default value */ g_value_init(&propertyValue, G_PARAM_SPEC_VALUE_TYPE(realParamSpec)); g_param_value_set_default(realParamSpec, &propertyValue); /* Set value at object property */ g_object_set_property(G_OBJECT(self), styleName, &propertyValue); didChange=TRUE; #ifdef DEBUG if(doDebug) { gchar *valstr; valstr=g_strdup_value_contents(&propertyValue); XFDASHBOARD_DEBUG(self, STYLE, "Restoring default value of style property [%s] %s=%s\n", G_OBJECT_CLASS_NAME(klass), styleName, valstr); g_free(valstr); } #endif /* Release allocated resources */ g_value_unset(&propertyValue); } /* Release resources of set of last changed properties as we do not need * it anymore. */ g_hash_table_destroy(priv->lastThemeStyleSet); priv->lastThemeStyleSet=NULL; } /* Remember this set of changed properties for next time to determine properties * which need to be restored to their default value. */ priv->lastThemeStyleSet=themeStyleSet; /* Release allocated resources */ g_hash_table_destroy(possibleStyleSet); /* Force a redraw if any change was made at this actor */ if(didChange) clutter_actor_queue_redraw(CLUTTER_ACTOR(self)); /* Reset force style revalidation flag because it's done now */ priv->forceStyleRevalidation=FALSE; /* All stylable properties are set now. So thaw 'property-changed' * notification now and fire all notifications at once. */ g_object_thaw_notify(G_OBJECT(self)); }
/* Default implementation of virtual function "invalidate" */ static void _xfdashboard_stylable_real_invalidate(XfdashboardStylable *self) { XfdashboardTheme *theme; XfdashboardThemeCSS *themeCSS; GHashTable *stylableProperties; GHashTable *themeStyleSet; GHashTableIter hashIter; gchar *propertyName; GParamSpec *propertyValueParamSpec; XfdashboardThemeCSSValue *styleValue; g_return_if_fail(XFDASHBOARD_IS_STYLABLE(self)); /* Get hashtable with all stylable properties and their parameter * specification for default values. */ stylableProperties=xfdashboard_stylable_get_stylable_properties(self); if(!stylableProperties) return; /* Get theme CSS */ theme=xfdashboard_application_get_theme(); themeCSS=xfdashboard_theme_get_css(theme); /* Get styled properties from theme CSS */ themeStyleSet=xfdashboard_theme_css_get_properties(themeCSS, self); /* The 'property-changed' notification will be freezed and thawed * (fired at once) after all stylable properties of this instance are set. */ g_object_freeze_notify(G_OBJECT(self)); /* Iterate through stylable properties and check if we got a style of * that name from theme CSS. If we find such a style set the corresponding * property in object otherwise set default value to override any * previous value set by theme CSS to reset it. */ g_hash_table_iter_init(&hashIter, stylableProperties); while(g_hash_table_iter_next(&hashIter, (gpointer*)&propertyName, (gpointer*)&propertyValueParamSpec)) { /* Check if we got a style with this name from theme CSS and * set style's value if found ... */ if(g_hash_table_lookup_extended(themeStyleSet, propertyName, NULL, (gpointer*)&styleValue)) { GValue cssValue=G_VALUE_INIT; GValue propertyValue=G_VALUE_INIT; /* Convert style value to type of object property and set value * if conversion was successful. Otherwise do nothing. */ g_value_init(&cssValue, G_TYPE_STRING); g_value_set_string(&cssValue, styleValue->string); g_value_init(&propertyValue, G_PARAM_SPEC_VALUE_TYPE(propertyValueParamSpec)); if(g_param_value_convert(propertyValueParamSpec, &cssValue, &propertyValue, FALSE)) { g_object_set_property(G_OBJECT(self), propertyName, &propertyValue); } else { g_warning(_("Could not transform CSS string value for property '%s' to type %s of class %s"), propertyName, g_type_name(G_PARAM_SPEC_VALUE_TYPE(propertyValueParamSpec)), G_OBJECT_TYPE_NAME(self)); } /* Release allocated resources */ g_value_unset(&propertyValue); g_value_unset(&cssValue); } /* ... otherwise set property's default value we got from * stylable interface of object. */ else { GValue propertyValue=G_VALUE_INIT; /* Initialize property value to its type and default value */ g_value_init(&propertyValue, G_PARAM_SPEC_VALUE_TYPE(propertyValueParamSpec)); g_param_value_set_default(propertyValueParamSpec, &propertyValue); /* Set value at object property */ g_object_set_property(G_OBJECT(self), propertyName, &propertyValue); /* Release allocated resources */ g_value_unset(&propertyValue); } } /* All stylable properties are set now. So thaw 'property-changed' * notification now and fire all notifications at once. */ g_object_thaw_notify(G_OBJECT(self)); /* Release allocated resources */ g_hash_table_destroy(themeStyleSet); g_hash_table_destroy(stylableProperties); }