/* Default implementation of virtual function "get_parent" */ static XfdashboardStylable* _xfdashboard_stylable_real_get_parent(XfdashboardStylable *self) { XfdashboardStylable *parent; g_return_val_if_fail(XFDASHBOARD_IS_STYLABLE(self), NULL); parent=NULL; /* If object implementing this interface is derived from ClutterActor * get actor's parent actor. */ if(CLUTTER_IS_ACTOR(self)) { ClutterActor *parentActor; /* Get parent and if parent stylable set parent as result */ parentActor=clutter_actor_get_parent(CLUTTER_ACTOR(self)); if(parentActor && XFDASHBOARD_IS_STYLABLE(parentActor)) { parent=XFDASHBOARD_STYLABLE(parentActor); } } /* Return stylable parent */ return(parent); }
/* Call virtual function "set_focus" */ void xfdashboard_focusable_set_focus(XfdashboardFocusable *self) { XfdashboardFocusableInterface *iface; ClutterActor *selection; g_return_if_fail(XFDASHBOARD_IS_FOCUSABLE(self)); iface=XFDASHBOARD_FOCUSABLE_GET_IFACE(self); /* Call virtual function */ if(iface->set_focus) { iface->set_focus(self); } /* Style newly focused actor */ if(XFDASHBOARD_IS_STYLABLE(self)) { xfdashboard_stylable_add_class(XFDASHBOARD_STYLABLE(self), "focus"); } /* If actor supports selection get current selection and style it */ if(xfdashboard_focusable_supports_selection(self)) { /* Get current selection. If no selection is available then select first item. */ selection=xfdashboard_focusable_get_selection(self); if(!selection) { selection=xfdashboard_focusable_find_selection(self, NULL, XFDASHBOARD_SELECTION_TARGET_FIRST); if(selection) xfdashboard_focusable_set_selection(self, selection); } /* Style selection if available */ if(selection && XFDASHBOARD_IS_STYLABLE(selection)) { xfdashboard_stylable_add_pseudo_class(XFDASHBOARD_STYLABLE(selection), "selected"); } g_debug("Set selection to %s for focused actor %s", G_OBJECT_TYPE_NAME(self), selection ? G_OBJECT_TYPE_NAME(selection) : "<nil>"); } /* Emit signal */ g_signal_emit(self, XfdashboardFocusableSignals[SIGNAL_FOCUS_GAINED], 0, self); g_debug("Emitted signal 'focus-gained' for focused actor %s", G_OBJECT_TYPE_NAME(self)); }
/* 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); } }
/* 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)); }
/* Invalidate all stylable children recursively beginning at given actor */ static void _xfdashboard_actor_invalidate_recursive(ClutterActor *inActor) { ClutterActor *child; ClutterActorIter actorIter; g_return_if_fail(CLUTTER_IS_ACTOR(inActor)); /* If actor is stylable invalidate it to get its style recomputed */ if(XFDASHBOARD_IS_STYLABLE(inActor)) { xfdashboard_stylable_invalidate(XFDASHBOARD_STYLABLE(inActor)); } /* Recompute styles for all children recursively */ clutter_actor_iter_init(&actorIter, inActor); while(clutter_actor_iter_next(&actorIter, &child)) { /* Call ourselve recursive with child as top-level actor. * We return immediately if it has no children but invalidate child * before. If it has children it will first invalidated and will be * iterated over its children then. In both cases the child will * be invalidated. */ _xfdashboard_actor_invalidate_recursive(child); } }
/* Check if this focusable actor has the focus */ static gboolean _xfdashboard_focusable_has_focus(XfdashboardFocusable *self) { XfdashboardFocusManager *focusManager; gboolean hasFocus; g_return_val_if_fail(XFDASHBOARD_IS_FOCUSABLE(self), FALSE); hasFocus=FALSE; /* Ask focus manager which actor has the current focus and * check if it is this focusable actor. */ focusManager=xfdashboard_focus_manager_get_default(); hasFocus=xfdashboard_focus_manager_has_focus(focusManager, self); g_object_unref(focusManager); /* If focus manager says this focusable has not the focus then * it might a proxy who has the focus (as seen by focus manager) * but in real this focusable actor is the destination of the * proxy so check for style class "focus" being set. */ if(!hasFocus && XFDASHBOARD_IS_STYLABLE(self) && xfdashboard_stylable_has_class(XFDASHBOARD_STYLABLE(self), "focus")) { hasFocus=TRUE; } return(hasFocus); }
/* Check and score this selector against a stylable node. * A score below 0 means that they did not match. */ gint xfdashboard_css_selector_score_matching_stylable_node(XfdashboardCssSelector *self, XfdashboardStylable *inStylable) { g_return_val_if_fail(XFDASHBOARD_IS_CSS_SELECTOR(self), -1); g_return_val_if_fail(XFDASHBOARD_IS_STYLABLE(inStylable), -1); /* Check and score rules */ return(_xfdashboard_css_selector_score_matching_node(self->priv->rule, inStylable)); }
/* Call virtual function "unset_focus" */ void xfdashboard_focusable_unset_focus(XfdashboardFocusable *self) { XfdashboardFocusableInterface *iface; ClutterActor *selection; g_return_if_fail(XFDASHBOARD_IS_FOCUSABLE(self)); iface=XFDASHBOARD_FOCUSABLE_GET_IFACE(self); /* Call virtual function */ if(iface->unset_focus) { iface->unset_focus(self); } /* Remove style from unfocused actor */ if(XFDASHBOARD_IS_STYLABLE(self)) { xfdashboard_stylable_remove_class(XFDASHBOARD_STYLABLE(self), "focus"); } /* If actor supports selection get current selection and unstyle it */ if(xfdashboard_focusable_supports_selection(self)) { /* Get current selection */ selection=xfdashboard_focusable_get_selection(self); /* unstyle selection if available */ if(selection && XFDASHBOARD_IS_STYLABLE(selection)) { xfdashboard_stylable_remove_pseudo_class(XFDASHBOARD_STYLABLE(selection), "selected"); } g_debug("Unstyled selection %s for focus loosing actor %s", G_OBJECT_TYPE_NAME(self), selection ? G_OBJECT_TYPE_NAME(selection) : "<nil>"); } /* Emit signal */ g_signal_emit(self, XfdashboardFocusableSignals[SIGNAL_FOCUS_LOST], 0, self); g_debug("Emitted signal 'focus-lost' for focused actor %s", G_OBJECT_TYPE_NAME(self)); }
/* 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); } }
/* Default implementation of virtual function "get_name" */ static const gchar* _xfdashboard_stylable_real_get_name(XfdashboardStylable *self) { const gchar *name; g_return_val_if_fail(XFDASHBOARD_IS_STYLABLE(self), NULL); name=NULL; /* If object implementing this interface is derived from ClutterActor * get actor's name. */ if(CLUTTER_IS_ACTOR(self)) name=clutter_actor_get_name(CLUTTER_ACTOR(self)); /* Return determined name for stylable object */ return(name); }
/* Get stylable parent of actor */ static XfdashboardStylable* _xfdashboard_actor_stylable_get_parent(XfdashboardStylable *inStylable) { ClutterActor *self; ClutterActor *parent; g_return_val_if_fail(CLUTTER_IS_ACTOR(inStylable), NULL); self=CLUTTER_ACTOR(inStylable); /* Get parent and check if stylable. If not return NULL. */ parent=clutter_actor_get_parent(self); if(!XFDASHBOARD_IS_STYLABLE(parent)) return(NULL); /* Return stylable parent */ return(XFDASHBOARD_STYLABLE(parent)); }
/* Dispose this object */ static void _xfdashboard_popup_menu_item_meta_dispose(GObject *inObject) { XfdashboardPopupMenuItemMeta *self=XFDASHBOARD_POPUP_MENU_ITEM_META(inObject); XfdashboardPopupMenuItemMetaPrivate *priv=self->priv; /* Release our allocated variables */ if(priv->popupMenu) { g_object_remove_weak_pointer(G_OBJECT(priv->popupMenu), (gpointer*)&priv->popupMenu); priv->popupMenu=NULL; } if(priv->menuItem) { /* Remove style from menu item if possible */ if(XFDASHBOARD_IS_STYLABLE(priv->menuItem)) { xfdashboard_stylable_remove_class(XFDASHBOARD_STYLABLE(priv->menuItem), "popup-menu-item"); } /* Remove click action from menu item actor */ if(priv->clickAction) { clutter_actor_remove_action(priv->menuItem, priv->clickAction); priv->clickAction=NULL; } /* Release menu item actor */ g_object_remove_weak_pointer(G_OBJECT(priv->menuItem), (gpointer*)&priv->menuItem); priv->menuItem=NULL; } if(priv->callback) { priv->callback=NULL; } if(priv->userData) { priv->userData=NULL; } /* Call parent's class dispose method */ G_OBJECT_CLASS(xfdashboard_popup_menu_item_meta_parent_class)->dispose(inObject); }
/* Call virtual function "set_pseudo_classes" */ void xfdashboard_stylable_set_pseudo_classes(XfdashboardStylable *self, const gchar *inClasses) { XfdashboardStylableInterface *iface; g_return_if_fail(XFDASHBOARD_IS_STYLABLE(self)); iface=XFDASHBOARD_STYLABLE_GET_IFACE(self); /* Call virtual function */ if(iface->set_pseudo_classes) { iface->set_pseudo_classes(self, inClasses); return; } /* If we get here the virtual function was not overridden */ XFDASHBOARD_STYLABLE_WARN_NOT_IMPLEMENTED(self, "set_pseudo_classes"); }
/* Call virtual function "get_classes" */ const gchar* xfdashboard_stylable_get_classes(XfdashboardStylable *self) { XfdashboardStylableInterface *iface; g_return_val_if_fail(XFDASHBOARD_IS_STYLABLE(self), NULL); iface=XFDASHBOARD_STYLABLE_GET_IFACE(self); /* Call virtual function */ if(iface->get_classes) { return(iface->get_classes(self)); } /* If we get here the virtual function was not overridden */ XFDASHBOARD_STYLABLE_WARN_NOT_IMPLEMENTED(self, "get_classes"); return(NULL); }
/* Call virtual function "invalidate" */ void xfdashboard_stylable_invalidate(XfdashboardStylable *self) { XfdashboardStylableInterface *iface; g_return_if_fail(XFDASHBOARD_IS_STYLABLE(self)); iface=XFDASHBOARD_STYLABLE_GET_IFACE(self); /* Call virtual function */ if(iface->invalidate) { iface->invalidate(self); return; } /* If we get here the virtual function was not overridden */ XFDASHBOARD_STYLABLE_WARN_NOT_IMPLEMENTED(self, "invalidate"); }
/* Set menu item actor */ static void _xfdashboard_popup_menu_item_meta_set_menu_item(XfdashboardPopupMenuItemMeta *self, ClutterActor *inMenuItem) { XfdashboardPopupMenuItemMetaPrivate *priv; g_return_if_fail(XFDASHBOARD_IS_POPUP_MENU_ITEM_META(self)); g_return_if_fail(CLUTTER_IS_ACTOR(inMenuItem)); priv=self->priv; /* This function can only be called once so no menu item must be set yet */ if(priv->menuItem || priv->clickAction) { g_critical(_("Attempting to set menu item %s at %s but it is already set."), G_OBJECT_TYPE_NAME(inMenuItem), G_OBJECT_TYPE_NAME(self)); return; } /* Set value if changed */ if(priv->menuItem!=inMenuItem) { /* Set value */ priv->menuItem=inMenuItem; g_object_add_weak_pointer(G_OBJECT(priv->menuItem), (gpointer*)&priv->menuItem); /* Apply style for menu item if possible */ if(XFDASHBOARD_IS_STYLABLE(priv->menuItem)) { xfdashboard_stylable_add_class(XFDASHBOARD_STYLABLE(priv->menuItem), "popup-menu-item"); } /* Create click action and add it to menu item actor */ priv->clickAction=xfdashboard_click_action_new(); g_signal_connect_swapped(priv->clickAction, "clicked", G_CALLBACK(_xfdashboard_popup_menu_item_meta_clicked), self); clutter_actor_add_action(priv->menuItem, priv->clickAction); /* Notify about property change */ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardPopupMenuItemMetaProperties[PROP_MENU_ITEM]); } }
/* 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); }
/* Internal function to traverse an actor which can be call recursively */ static gboolean _xfdashboard_traverse_actor_internal(ClutterActor *inActor, XfdashboardCssSelector *inSelector, XfdashboardTraversalCallback inCallback, gpointer inUserData) { ClutterActorIter iter; ClutterActor *child; gint score; gboolean doContinueTraversal; g_return_val_if_fail(CLUTTER_IS_ACTOR(inActor), XFDASHBOARD_TRAVERSAL_CONTINUE); g_return_val_if_fail(XFDASHBOARD_IS_CSS_SELECTOR(inSelector), XFDASHBOARD_TRAVERSAL_CONTINUE); g_return_val_if_fail(inCallback, XFDASHBOARD_TRAVERSAL_CONTINUE); /* Check if given actor matches selector if a selector is provided * otherwise each child will match. Call callback for matching children. */ if(XFDASHBOARD_IS_STYLABLE(inActor)) { score=xfdashboard_css_selector_score_matching_stylable_node(inSelector, XFDASHBOARD_STYLABLE(inActor)); if(score>=0) { doContinueTraversal=(inCallback)(inActor, inUserData); if(!doContinueTraversal) return(doContinueTraversal); } } /* For each child of actor call ourselve recursive */ clutter_actor_iter_init(&iter, inActor); while(clutter_actor_iter_next(&iter, &child)) { doContinueTraversal=_xfdashboard_traverse_actor_internal(child, inSelector, inCallback, inUserData); if(!doContinueTraversal) return(doContinueTraversal); } /* If we get here return and continue traversal */ return(XFDASHBOARD_TRAVERSAL_CONTINUE); }
/* Find and add parameter specification of a stylable property to hashtable */ gboolean xfdashboard_stylable_add_stylable_property(XfdashboardStylable *self, GHashTable *ioStylableProperties, const gchar *inProperty) { GParamSpec *spec; g_return_val_if_fail(XFDASHBOARD_IS_STYLABLE(self), FALSE); /* Find property in instance */ spec=g_object_class_find_property(G_OBJECT_GET_CLASS(self), inProperty); if(!spec) { g_warning(_("Could not find property '%s' for class %s"), inProperty, G_OBJECT_TYPE_NAME(self)); return(FALSE); } /* Add parameter specification of found property to hashtable */ g_hash_table_insert(ioStylableProperties, g_strdup(inProperty), g_param_spec_ref(spec)); return(TRUE); }
/* Call virtual function "get_stylable_properties" */ GHashTable* xfdashboard_stylable_get_stylable_properties(XfdashboardStylable *self) { XfdashboardStylableInterface *iface; GHashTable *stylableProperties; g_return_val_if_fail(XFDASHBOARD_IS_STYLABLE(self), NULL); iface=XFDASHBOARD_STYLABLE_GET_IFACE(self); /* Call virtual function */ if(iface->get_stylable_properties) { /* Create hashtable to insert stylable properties at */ stylableProperties=g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_param_spec_unref); /* Get stylable properties */ iface->get_stylable_properties(self, stylableProperties); /* If hashtable is empty, destroy it and return NULL */ if(g_hash_table_size(stylableProperties)==0) { g_hash_table_destroy(stylableProperties); stylableProperties=NULL; } /* Return hashtable with stylable properties */ return(stylableProperties); } /* If we get here the virtual function was not overridden */ XFDASHBOARD_STYLABLE_WARN_NOT_IMPLEMENTED(self, "get_stylable_properties"); return(NULL); }
/* Call virtual function "set_selection" */ gboolean xfdashboard_focusable_set_selection(XfdashboardFocusable *self, ClutterActor *inSelection) { XfdashboardFocusableInterface *iface; ClutterActor *oldSelection; gboolean success; g_return_val_if_fail(XFDASHBOARD_IS_FOCUSABLE(self), FALSE); g_return_val_if_fail(!inSelection || CLUTTER_IS_ACTOR(inSelection), FALSE); iface=XFDASHBOARD_FOCUSABLE_GET_IFACE(self); /* If this focusable actor does not support selection we should ask for * the current selection and avoid the warning being printed if this * virtual function was not overridden. */ if(!xfdashboard_focusable_supports_selection(self)) return(FALSE); /* First get current selection */ oldSelection=xfdashboard_focusable_get_selection(self); /* Do nothing if new selection is the same as the current one */ if(inSelection==oldSelection) return(TRUE); /* Call virtual function */ if(iface->set_selection) { /* Call virtual function to set selection */ success=iface->set_selection(self, inSelection); /* If new selection could be set successfully, remove signal handlers * from old selection and set up signal handlers for new selection. */ if(success) { /* Remove signal handlers and styles from old selection */ if(oldSelection) { /* Remove signal handlers at old selection*/ g_signal_handlers_disconnect_by_func(oldSelection, G_CALLBACK(_xfdashboard_focusable_on_selection_unavailable), self); /* Remove style from old selection */ if(XFDASHBOARD_IS_STYLABLE(oldSelection)) { xfdashboard_stylable_remove_pseudo_class(XFDASHBOARD_STYLABLE(oldSelection), "selected"); } } /* Set up signal handlers and styles at new selection */ if(inSelection) { /* Set up signal handlers to get notified if new selection * is going to be unavailable (e.g. hidden or destroyed) */ g_signal_connect_swapped(inSelection, "destroy", G_CALLBACK(_xfdashboard_focusable_on_selection_unavailable), self); g_signal_connect_swapped(inSelection, "hide", G_CALLBACK(_xfdashboard_focusable_on_selection_unavailable), self); /* Style new selection if this focusable actor has the focus */ if(_xfdashboard_focusable_has_focus(self) && XFDASHBOARD_IS_STYLABLE(inSelection)) { xfdashboard_stylable_add_pseudo_class(XFDASHBOARD_STYLABLE(inSelection), "selected"); } } /* Emit signal */ g_signal_emit(self, XfdashboardFocusableSignals[SIGNAL_SELECTION_CHANGED], 0, oldSelection, inSelection); } /* Return result of calling virtual function */ return(success); } /* If we get here the virtual function was not overridden */ XFDASHBOARD_FOCUSABLE_WARN_NOT_IMPLEMENTED(self, "set_selection"); return(FALSE); }
/* 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); }
/* 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); }
void xfdashboard_focus_manager_register_after(XfdashboardFocusManager *self, XfdashboardFocusable *inFocusable, XfdashboardFocusable *inAfterFocusable) { XfdashboardFocusManagerPrivate *priv; g_return_if_fail(XFDASHBOARD_IS_FOCUS_MANAGER(self)); g_return_if_fail(inFocusable); g_return_if_fail(!inAfterFocusable || XFDASHBOARD_IS_FOCUSABLE(inAfterFocusable)); priv=self->priv; /* Check if given focusable actor is really focusable and stylable */ if(!XFDASHBOARD_IS_FOCUSABLE(inFocusable)) { g_warning(_("Object %s does not inherit %s and cannot be registered"), G_OBJECT_TYPE_NAME(inFocusable), g_type_name(XFDASHBOARD_TYPE_FOCUSABLE)); return; } if(!XFDASHBOARD_IS_STYLABLE(inFocusable)) { g_warning(_("Object %s does not inherit %s and cannot be registered"), G_OBJECT_TYPE_NAME(inFocusable), g_type_name(XFDASHBOARD_TYPE_STYLABLE)); return; } /* Register focusable actor if not already registered */ if(g_list_find(priv->registeredFocusables, inFocusable)==NULL) { gint insertPosition; g_debug("Registering focusable %s", G_OBJECT_TYPE_NAME(inFocusable)); /* If requested find position of focusable actor to insert new focusable actor after. * Increase found position by one and add new focusable actor to list of registered * focusable actors at this position. Otherwise add new focusable actor to end of list. */ insertPosition=-1; if(inAfterFocusable) { insertPosition=g_list_index(priv->registeredFocusables, inAfterFocusable); if(insertPosition!=-1) insertPosition++; else { g_warning(_("Could not find registered focusable object %s to register object %s - appending to end of list."), G_OBJECT_TYPE_NAME(inAfterFocusable), G_OBJECT_TYPE_NAME(inFocusable)); } } priv->registeredFocusables=g_list_insert(priv->registeredFocusables, inFocusable, insertPosition); /* Connect to signals to get notified if actor is going to be destroy, * unrealized or hidden to remove it from list of focusable actors. */ g_signal_connect_swapped(inFocusable, "destroy", G_CALLBACK(_xfdashboard_focus_manager_on_focusable_destroy), self); g_signal_connect_swapped(inFocusable, "realize", G_CALLBACK(_xfdashboard_focus_manager_on_focusable_hide), self); g_signal_connect_swapped(inFocusable, "hide", G_CALLBACK(_xfdashboard_focus_manager_on_focusable_hide), self); /* Emit signal */ g_signal_emit(self, XfdashboardFocusManagerSignals[SIGNAL_REGISTERED], 0, inFocusable); } }
/* The current selection of a focusable actor (if focussed or not) is not available anymore * (e.g. hidden or destroyed). So move selection at focusable actor to next available and * selectable item. */ static void _xfdashboard_focusable_on_selection_unavailable(XfdashboardFocusable *self, gpointer inUserData) { XfdashboardFocusableInterface *iface; ClutterActor *oldSelection; ClutterActor *newSelection; gboolean success; XfdashboardApplication *application; g_return_if_fail(XFDASHBOARD_IS_FOCUSABLE(self)); g_return_if_fail(CLUTTER_IS_ACTOR(inUserData)); iface=XFDASHBOARD_FOCUSABLE_GET_IFACE(self); oldSelection=CLUTTER_ACTOR(inUserData); newSelection=NULL; success=FALSE; /* If application is not quitting then call virtual function to set selection * which have to be available because this signal handler was set in * xfdashboard_focusable_set_selection() when this virtual function was available * and successfully called. * If setting new selection was unsuccessful we set selection to nothing (NULL); */ application=xfdashboard_application_get_default(); if(!xfdashboard_application_is_quitting(application)) { /* Get next selection */ newSelection=xfdashboard_focusable_find_selection(self, oldSelection, XFDASHBOARD_SELECTION_TARGET_NEXT); /* Set new selection */ success=iface->set_selection(self, newSelection); if(!success) { success=iface->set_selection(self, newSelection); if(!success) { g_critical(_("Old selection %s at %s is unavailable but setting new selection either to %s or nothing failed!"), G_OBJECT_TYPE_NAME(oldSelection), G_OBJECT_TYPE_NAME(self), newSelection ? G_OBJECT_TYPE_NAME(newSelection) : "<nil>"); } /* Now reset new selection to NULL regardless if setting selection at * focusable actor was successful or not. A critical warning was displayed * if is was unsuccessful because setting nothing (NULL) must succeed usually. */ newSelection=NULL; } } /* Regardless if setting selection was successful, remove signal handlers * and styles from old selection. */ if(oldSelection) { /* Remove signal handlers at old selection*/ g_signal_handlers_disconnect_by_func(oldSelection, G_CALLBACK(_xfdashboard_focusable_on_selection_unavailable), self); /* Remove style from old selection */ if(XFDASHBOARD_IS_STYLABLE(oldSelection)) { xfdashboard_stylable_remove_pseudo_class(XFDASHBOARD_STYLABLE(oldSelection), "selected"); } } /* If setting selection was successful, set up signal handlers and styles at new selection */ if(success && newSelection) { /* Set up signal handlers to get notified if new selection * is going to be unavailable (e.g. hidden or destroyed) */ g_signal_connect_swapped(newSelection, "destroy", G_CALLBACK(_xfdashboard_focusable_on_selection_unavailable), self); g_signal_connect_swapped(newSelection, "hide", G_CALLBACK(_xfdashboard_focusable_on_selection_unavailable), self); /* Check if this focusable actor has the focus because if it has * the have to style new selection. */ if(_xfdashboard_focusable_has_focus(self) && XFDASHBOARD_IS_STYLABLE(newSelection)) { xfdashboard_stylable_add_pseudo_class(XFDASHBOARD_STYLABLE(newSelection), "selected"); } } /* Emit signal because at least old selection has changed */ g_signal_emit(self, XfdashboardFocusableSignals[SIGNAL_SELECTION_CHANGED], 0, oldSelection, newSelection); }