/* Dump actors */ static void _xfdashboard_dump_actor_print(ClutterActor *inActor, gint inLevel) { XfdashboardStylable *stylable; ClutterActorBox allocation; gint i; g_return_if_fail(CLUTTER_IS_ACTOR(inActor)); g_return_if_fail(inLevel>=0); /* Check if actor is stylable to retrieve style configuration */ stylable=NULL; if(XFDASHBOARD_IS_STYLABLE(inActor)) stylable=XFDASHBOARD_STYLABLE(inActor); /* Dump actor */ for(i=0; i<inLevel; i++) g_print(" "); clutter_actor_get_allocation_box(inActor, &allocation); g_print("+- %s@%p [%s%s%s%s%s%s] - geometry: %.2f,%.2f [%.2fx%.2f], mapped: %s, visible: %s, layout: %s, children: %d\n", G_OBJECT_TYPE_NAME(inActor), inActor, clutter_actor_get_name(inActor) ? " #" : "", clutter_actor_get_name(inActor) ? clutter_actor_get_name(inActor) : "", stylable && xfdashboard_stylable_get_classes(stylable) ? "." : "", stylable && xfdashboard_stylable_get_classes(stylable) ? xfdashboard_stylable_get_classes(stylable) : "", stylable && xfdashboard_stylable_get_pseudo_classes(stylable) ? ":" : "", stylable && xfdashboard_stylable_get_pseudo_classes(stylable) ? xfdashboard_stylable_get_pseudo_classes(stylable) : "", allocation.x1, allocation.y1, allocation.x2-allocation.x1, allocation.y2-allocation.y1, clutter_actor_is_mapped(inActor) ? "yes" : "no", clutter_actor_is_visible(inActor) ? "yes" : "no", clutter_actor_get_layout_manager(inActor) ? G_OBJECT_TYPE_NAME(clutter_actor_get_layout_manager(inActor)) : "none", clutter_actor_get_n_children(inActor)); }
/* Adds a pseudo-class to existing pseudo-classes of an object */ void xfdashboard_stylable_add_pseudo_class(XfdashboardStylable *self, const gchar *inClass) { const gchar *classes; g_return_if_fail(XFDASHBOARD_IS_STYLABLE(self)); g_return_if_fail(inClass && inClass[0]); /* If pesudo-class is already in list of pseudo-classes do nothing * otherwise set new value. */ classes=xfdashboard_stylable_get_pseudo_classes(self); if(!classes || !_xfdashboard_stylable_list_contains(inClass, -1, classes, ':')) { gchar *newClasses; /* Create new temporary string by concatenating current pseudo-classes * and new psuedo-class with colon separator. Set this new string * representing list of pseudo-classes. */ if(classes) newClasses=g_strconcat(classes, ":", inClass, NULL); else newClasses=g_strdup(inClass); xfdashboard_stylable_set_pseudo_classes(self, newClasses); g_free(newClasses); } }
/* Removed a pseudo-class to existing classes of an object */ void xfdashboard_stylable_remove_pseudo_class(XfdashboardStylable *self, const gchar *inClass) { const gchar *classes; g_return_if_fail(XFDASHBOARD_IS_STYLABLE(self)); g_return_if_fail(inClass && inClass[0]); /* If pseudo-class is not in list of pseudo-classes do nothing * otherwise set new value. */ classes=xfdashboard_stylable_get_pseudo_classes(self); if(classes && _xfdashboard_stylable_list_contains(inClass, -1, classes, ':')) { gchar **oldClasses, **entry; gchar *newClasses, *newClassesTemp; /* Create new temporary string with all current pseudo-classes * separated by colon not matching pseudo-class to remove. * Set this new string representing list of pseudo-classes. */ entry=oldClasses=g_strsplit(classes, ":", -1); newClasses=NULL; while(*entry) { if(!strcmp(*entry, inClass)) { entry++; continue; } if(newClasses) { newClassesTemp=g_strconcat(newClasses, ":", *entry, NULL); g_free(newClasses); newClasses=newClassesTemp; } else newClasses=g_strdup(*entry); entry++; } xfdashboard_stylable_set_pseudo_classes(self, newClasses); g_strfreev(oldClasses); g_free(newClasses); } }
/* Determine if a specific pseudo-class is being set at object */ gboolean xfdashboard_stylable_has_pseudo_class(XfdashboardStylable *self, const gchar *inClass) { const gchar *classes; gboolean result; g_return_val_if_fail(XFDASHBOARD_IS_STYLABLE(self), FALSE); g_return_val_if_fail(inClass && inClass[0], FALSE); result=FALSE; /* Get classes set at object and check if it has the expected one */ classes=xfdashboard_stylable_get_pseudo_classes(self); if(classes && _xfdashboard_stylable_list_contains(inClass, -1, classes, ':')) { result=TRUE; } /* Return result */ return(result); }
/* Check and score this selector against stylable node. * A score below 0 means that they did not match. */ static gint _xfdashboard_css_selector_score_matching_node(XfdashboardCssSelectorRule *inRule, XfdashboardStylable *inStylable) { gint score; gint a, b, c; const gchar *classes; const gchar *pseudoClasses; const gchar *id; g_return_val_if_fail(inRule, -1); g_return_val_if_fail(XFDASHBOARD_IS_STYLABLE(inStylable), -1); /* For information about how the scoring is done, see documentation * "Cascading Style Sheets, level 1" of W3C, section "3.2 Cascading order" * URL: http://www.w3.org/TR/2008/REC-CSS1-20080411/#cascading-order * * 1. Find all declarations that apply to the element/property in question. * Declarations apply if the selector matches the element in question. * If no declarations apply, the inherited value is used. If there is * no inherited value (this is the case for the 'HTML' element and * for properties that do not inherit), the initial value is used. * 2. Sort the declarations by explicit weight: declarations marked * '!important' carry more weight than unmarked (normal) declarations. * 3. Sort by origin: the author's style sheets override the reader's * style sheet which override the UA's default values. An imported * style sheet has the same origin as the style sheet from which it * is imported. * 4. Sort by specificity of selector: more specific selectors will * override more general ones. To find the specificity, count the * number of ID attributes in the selector (a), the number of CLASS * attributes in the selector (b), and the number of tag names in * the selector (c). Concatenating the three numbers (in a number * system with a large base) gives the specificity. * Pseudo-elements and pseudo-classes are counted as normal elements * and classes, respectively. * 5. Sort by order specified: if two rules have the same weight, the * latter specified wins. Rules in imported style sheets are considered * to be before any rules in the style sheet itself. * * NOTE: Keyword '!important' is not supported. */ a=b=c=0; /* Get properties for given stylable */ id=xfdashboard_stylable_get_name(XFDASHBOARD_STYLABLE(inStylable)); classes=xfdashboard_stylable_get_classes(XFDASHBOARD_STYLABLE(inStylable)); pseudoClasses=xfdashboard_stylable_get_pseudo_classes(XFDASHBOARD_STYLABLE(inStylable)); /* Check and score type of selectors but ignore NULL or universal selectors */ if(inRule->type && inRule->type[0]!='*') { GType ruleTypeID; GType nodeTypeID; /* Get type of this rule */ ruleTypeID=g_type_from_name(inRule->type); if(!ruleTypeID) return(-1); /* Get type of other rule to check against and score it */ nodeTypeID=G_OBJECT_TYPE(inStylable); if(!nodeTypeID) return(-1); /* Check if type of this rule matches type of other rule */ if(!g_type_is_a(nodeTypeID, ruleTypeID)) return(-1); /* Determine depth difference between both types * which is the score of this test with a maximum of 99 */ c=g_type_depth(ruleTypeID)-g_type_depth(nodeTypeID); c=MAX(ABS(c), 99); } /* Check and score ID */ if(inRule->id) { /* If node has no ID return immediately */ if(!id || strcmp(inRule->id, id)) return(-1); /* Score ID */ a+=10; } /* Check and score classes */ if(inRule->classes) { gchar *needle; gint numberMatches; /* If node has no pseudo class return immediately */ if(!classes) return(-1); /* Check that each class from the selector's rule appears in the * list of classes from the node, i.e. the selector's rule class list * is a subset of the node's class list */ numberMatches=0; for(needle=inRule->classes; needle; needle=strchr(needle, '.')) { gint needleLength; gchar *nextNeedle; /* Move pointer of needle beyond class seperator '.' */ if(needle[0]=='.') needle++; /* Get length of needle */ nextNeedle=strchr(needle, '.'); if(nextNeedle) needleLength=nextNeedle-needle; else needleLength=strlen(needle); /* If pseudo-class from the selector does not appear in the * list of pseudo-classes from the node, then this is not a * match */ if(!_xfdashboard_css_selector_list_contains(needle, needleLength, classes, '.')) return(-1); numberMatches++; } /* Score matching class */ b=b+(10*numberMatches); } /* Check and score pseudo classes */ if(inRule->pseudoClasses) { gchar *needle; gint numberMatches; /* If node has no pseudo class return immediately */ if(!pseudoClasses) return(-1); /* Check that each pseudo-class from the selector appears in the * pseudo-classes from the node, i.e. the selector pseudo-class list * is a subset of the node's pseudo-class list */ numberMatches=0; for(needle=inRule->pseudoClasses; needle; needle=strchr(needle, ':')) { gint needleLength; gchar *nextNeedle; /* Move pointer of needle beyond pseudo-class seperator ':' */ if(needle[0]==':') needle++; /* Get length of needle */ nextNeedle=strchr(needle, ':'); if(nextNeedle) needleLength=nextNeedle-needle; else needleLength=strlen(needle); /* If pseudo-class from the selector does not appear in the * list of pseudo-classes from the node, then this is not a * match */ if(!_xfdashboard_css_selector_list_contains(needle, needleLength, pseudoClasses, ':')) return(-1); numberMatches++; } /* Score matching pseudo-class */ b=b+(10*numberMatches); } /* Check and score parent */ if(inRule->parentRule && inRule->parentRuleMode==XFDASHBOARD_CSS_SELECTOR_RULE_MODE_PARENT) { gint parentScore; XfdashboardStylable *parent; /* If node has no parent, no parent can match ;) so return immediately */ parent=xfdashboard_stylable_get_parent(inStylable); if(!parent || !XFDASHBOARD_IS_STYLABLE(parent)) return(-1); /* Check if there are matching parents. If not return immediately. */ parentScore=_xfdashboard_css_selector_score_matching_node(inRule->parentRule, parent); if(parentScore<0) return(-1); /* Score matching parents */ c+=parentScore; } /* Check and score ancestor */ if(inRule->parentRule && inRule->parentRuleMode==XFDASHBOARD_CSS_SELECTOR_RULE_MODE_ANCESTOR) { gint ancestorScore; XfdashboardStylable *ancestor; ancestor=inStylable; /* If node has no parents, no ancestor can match so return immediately */ do { ancestor=xfdashboard_stylable_get_parent(ancestor); } while(ancestor && !XFDASHBOARD_IS_STYLABLE(ancestor)); if(!ancestor || !XFDASHBOARD_IS_STYLABLE(ancestor)) return(-1); /* Iterate through ancestors and check and score them */ while(ancestor) { /* Get number of matches for ancestor and if at least one matches, * stop search and score */ ancestorScore=_xfdashboard_css_selector_score_matching_node(inRule->parentRule, ancestor); if(ancestorScore>=0) { c+=ancestorScore; break; } /* Get next ancestor to check but skip actors not implementing * the XfdashboardStylable interface */ do { ancestor=xfdashboard_stylable_get_parent(ancestor); } while(ancestor && !XFDASHBOARD_IS_STYLABLE(ancestor)); if(!ancestor || !XFDASHBOARD_IS_STYLABLE(ancestor)) return(-1); } } /* Calculate final score */ score=(a*10000)+(b*100)+c; return(score); }