/* Object initialization * Create private structure and set up default values */ static void xfdashboard_text_box_init(XfdashboardTextBox *self) { XfdashboardTextBoxPrivate *priv; priv=self->priv=XFDASHBOARD_TEXT_BOX_GET_PRIVATE(self); /* This actor is react on events */ clutter_actor_set_reactive(CLUTTER_ACTOR(self), TRUE); /* Set up default values */ priv->padding=0.0f; priv->spacing=0.0f; priv->isEditable=FALSE; priv->primaryIconName=NULL; priv->secondaryIconName=NULL; priv->textFont=NULL; priv->textColor=NULL; priv->selectionTextColor=NULL; priv->selectionBackgroundColor=NULL; priv->hintTextFont=NULL; priv->hintTextColor=NULL; priv->showPrimaryIcon=FALSE; priv->showSecondaryIcon=FALSE; priv->selectionColorSet=FALSE; priv->hintTextSet=FALSE; /* Create actors */ g_signal_connect(self, "key-press-event", G_CALLBACK(_xfdashboard_text_box_on_key_press_event), NULL); g_signal_connect(self, "key-release-event", G_CALLBACK(_xfdashboard_text_box_on_key_release_event), NULL); priv->actorPrimaryIcon=xfdashboard_button_new(); xfdashboard_stylable_add_class(XFDASHBOARD_STYLABLE(priv->actorPrimaryIcon), "primary-icon"); clutter_actor_set_reactive(priv->actorPrimaryIcon, TRUE); clutter_actor_hide(priv->actorPrimaryIcon); clutter_actor_add_child(CLUTTER_ACTOR(self), priv->actorPrimaryIcon); g_signal_connect_swapped(priv->actorPrimaryIcon, "clicked", G_CALLBACK(_xfdashboard_text_box_on_primary_icon_clicked), self); priv->actorSecondaryIcon=xfdashboard_button_new(); xfdashboard_stylable_add_class(XFDASHBOARD_STYLABLE(priv->actorSecondaryIcon), "secondary-icon"); clutter_actor_set_reactive(priv->actorSecondaryIcon, TRUE); clutter_actor_hide(priv->actorSecondaryIcon); clutter_actor_add_child(CLUTTER_ACTOR(self), priv->actorSecondaryIcon); g_signal_connect_swapped(priv->actorSecondaryIcon, "clicked", G_CALLBACK(_xfdashboard_text_box_on_secondary_icon_clicked), self); priv->actorTextBox=clutter_text_new(); clutter_actor_add_child(CLUTTER_ACTOR(self), priv->actorTextBox); clutter_actor_set_reactive(priv->actorTextBox, TRUE); clutter_text_set_selectable(CLUTTER_TEXT(priv->actorTextBox), FALSE); clutter_text_set_editable(CLUTTER_TEXT(priv->actorTextBox), FALSE); clutter_text_set_single_line_mode(CLUTTER_TEXT(priv->actorTextBox), TRUE); g_signal_connect_swapped(priv->actorTextBox, "text-changed", G_CALLBACK(_xfdashboard_text_box_on_text_changed), self); priv->actorHintLabel=clutter_text_new(); clutter_actor_add_child(CLUTTER_ACTOR(self), priv->actorHintLabel); clutter_actor_set_reactive(priv->actorHintLabel, FALSE); clutter_text_set_selectable(CLUTTER_TEXT(priv->actorHintLabel), FALSE); clutter_text_set_editable(CLUTTER_TEXT(priv->actorHintLabel), FALSE); clutter_text_set_single_line_mode(CLUTTER_TEXT(priv->actorHintLabel), TRUE); clutter_actor_hide(priv->actorHintLabel); }
/* Set/get properties */ static void _xfdashboard_actor_set_property(GObject *inObject, guint inPropID, const GValue *inValue, GParamSpec *inSpec) { XfdashboardActor *self=XFDASHBOARD_ACTOR(inObject); switch(inPropID) { case PROP_CAN_FOCUS: xfdashboard_actor_set_can_focus(self, g_value_get_boolean(inValue)); break; case PROP_EFFECTS: xfdashboard_actor_set_effects(self, g_value_get_string(inValue)); break; case PROP_STYLE_CLASSES: _xfdashboard_actor_stylable_set_classes(XFDASHBOARD_STYLABLE(self), g_value_get_string(inValue)); break; case PROP_STYLE_PSEUDO_CLASSES: _xfdashboard_actor_stylable_set_pseudo_classes(XFDASHBOARD_STYLABLE(self), g_value_get_string(inValue)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec); break; } }
/* The active workspace has changed */ static void _xfdashboard_workspace_selector_on_active_workspace_changed(XfdashboardWorkspaceSelector *self, XfdashboardWindowTrackerWorkspace *inPrevWorkspace, gpointer inUserData) { XfdashboardWorkspaceSelectorPrivate *priv; XfdashboardLiveWorkspace *liveWorkspace; XfdashboardWindowTrackerWorkspace *workspace; g_return_if_fail(XFDASHBOARD_IS_WORKSPACE_SELECTOR(self)); priv=self->priv; /* Unmark previous workspace */ if(inPrevWorkspace) { liveWorkspace=_xfdashboard_workspace_selector_find_actor_for_workspace(self, inPrevWorkspace); if(liveWorkspace) xfdashboard_stylable_remove_pseudo_class(XFDASHBOARD_STYLABLE(liveWorkspace), "active"); priv->activeWorkspace=NULL; } /* Mark new active workspace */ workspace=xfdashboard_window_tracker_get_active_workspace(priv->windowTracker); if(workspace) { priv->activeWorkspace=workspace; liveWorkspace=_xfdashboard_workspace_selector_find_actor_for_workspace(self, priv->activeWorkspace); if(liveWorkspace) xfdashboard_stylable_add_pseudo_class(XFDASHBOARD_STYLABLE(liveWorkspace), "active"); } }
/* Actor's reactive state changed */ static void _xfdashboard_actor_on_reactive_changed(GObject *inObject, GParamSpec *inSpec, gpointer inUserData) { XfdashboardActor *self; g_return_if_fail(XFDASHBOARD_IS_ACTOR(inObject)); self=XFDASHBOARD_ACTOR(inObject); /* Add pseudo-class ':insensitive' if actor is now not reactive * and remove this pseudo-class if actor is now reactive. */ if(clutter_actor_get_reactive(CLUTTER_ACTOR(self))) { xfdashboard_stylable_remove_pseudo_class(XFDASHBOARD_STYLABLE(self), "insensitive"); } else { xfdashboard_stylable_add_pseudo_class(XFDASHBOARD_STYLABLE(self), "insensitive"); } /* Invalide styling to get it recomputed */ _xfdashboard_actor_invalidate_recursive(CLUTTER_ACTOR(self)); }
/* Set press state */ static void _xfdashboard_click_action_set_pressed(XfdashboardClickAction *self, gboolean isPressed) { XfdashboardClickActionPrivate *priv; ClutterActor *actor; g_return_if_fail(XFDASHBOARD_IS_CLICK_ACTION(self)); priv=self->priv; /* Set value if changed */ isPressed=!!isPressed; if(priv->isPressed!=isPressed) { /* Set value */ priv->isPressed=isPressed; /* Style state */ actor=clutter_actor_meta_get_actor(CLUTTER_ACTOR_META(self)); if(XFDASHBOARD_IS_ACTOR(actor)) { if(priv->isPressed) xfdashboard_stylable_add_pseudo_class(XFDASHBOARD_STYLABLE(actor), "pressed"); else xfdashboard_stylable_remove_pseudo_class(XFDASHBOARD_STYLABLE(actor), "pressed"); } /* Notify about property change */ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardClickActionProperties[PROP_PRESSED]); } }
/* 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)); }
/* 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); }
/* Set source actor */ static void _xfdashboard_drag_action_set_source(XfdashboardDragAction *self, ClutterActor *inSource) { XfdashboardDragActionPrivate *priv; g_return_if_fail(XFDASHBOARD_IS_DRAG_ACTION(self)); g_return_if_fail(inSource==NULL || CLUTTER_IS_ACTOR(inSource)); priv=self->priv; /* Release old source actor */ if(priv->source) { /* Unset style */ if(XFDASHBOARD_IS_ACTOR(priv->source)) { xfdashboard_stylable_remove_pseudo_class(XFDASHBOARD_STYLABLE(priv->source), "current-drag-source"); } /* Release actor */ g_object_unref(priv->source); priv->source=NULL; } /* Set new source actor */ if(inSource) { /* Set actor */ priv->source=CLUTTER_ACTOR(g_object_ref(inSource)); } }
/* 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); } }
/* 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); }
/* 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)); }
/* 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)); }
/* Monitor changed primary state */ static void _xfdashboard_stage_interface_on_primary_changed(XfdashboardStageInterface *self, gpointer inUserData) { XfdashboardStageInterfacePrivate *priv; gboolean isPrimary; g_return_if_fail(XFDASHBOARD_IS_STAGE_INTERFACE(self)); priv=self->priv; /* Get new primary state of monitor */ isPrimary=xfdashboard_window_tracker_monitor_is_primary(priv->monitor); /* Depending on primary state set CSS class */ if(isPrimary) xfdashboard_stylable_add_class(XFDASHBOARD_STYLABLE(self), "primary-monitor"); else xfdashboard_stylable_remove_class(XFDASHBOARD_STYLABLE(self), "primary-monitor"); XFDASHBOARD_DEBUG(self, ACTOR, "Stage interface changed primary state to %s because of monitor %d", xfdashboard_window_tracker_monitor_is_primary(priv->monitor) ? "primary" : "non-primary", xfdashboard_window_tracker_monitor_get_number(priv->monitor)); }
/* Unset focus from actor */ static void _xfdashboard_actor_focusable_unset_focus(XfdashboardFocusable *self) { XfdashboardActor *actor; g_return_if_fail(XFDASHBOARD_IS_FOCUSABLE(self)); g_return_if_fail(XFDASHBOARD_IS_ACTOR(self)); actor=XFDASHBOARD_ACTOR(self); /* Set focus and style for focus */ xfdashboard_stylable_remove_class(XFDASHBOARD_STYLABLE(actor), "focus"); }
/* Actor was mapped or unmapped */ static void _xfdashboard_actor_on_mapped_changed(GObject *inObject, GParamSpec *inSpec, gpointer inUserData) { XfdashboardActor *self; g_return_if_fail(XFDASHBOARD_IS_ACTOR(inObject)); self=XFDASHBOARD_ACTOR(inObject); /* Invalide styling to get it recomputed */ xfdashboard_stylable_invalidate(XFDASHBOARD_STYLABLE(self)); }
void xfdashboard_text_box_set_editable(XfdashboardTextBox *self, gboolean isEditable) { XfdashboardTextBoxPrivate *priv; const gchar *text; g_return_if_fail(XFDASHBOARD_IS_TEXT_BOX(self)); priv=self->priv; /* Set value if changed */ if(priv->isEditable!=isEditable) { priv->isEditable=isEditable; if(priv->isEditable) xfdashboard_stylable_add_pseudo_class(XFDASHBOARD_STYLABLE(self), "editable"); else xfdashboard_stylable_remove_pseudo_class(XFDASHBOARD_STYLABLE(self), "editable"); /* Set up actors */ clutter_text_set_selectable(CLUTTER_TEXT(priv->actorTextBox), priv->isEditable); clutter_text_set_editable(CLUTTER_TEXT(priv->actorTextBox), priv->isEditable); text=clutter_text_get_text(CLUTTER_TEXT(priv->actorTextBox)); if((text==NULL || *text==0) && priv->isEditable) { clutter_actor_show(priv->actorHintLabel); } else { clutter_actor_hide(priv->actorHintLabel); } clutter_actor_queue_relayout(CLUTTER_ACTOR(self)); /* Notify about property change */ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardTextBoxProperties[PROP_EDITABLE]); } }
/* Called when attaching and detaching a ClutterActorMeta instance to a ClutterActor */ static void _xfdashboard_drop_action_set_actor(ClutterActorMeta *inActorMeta, ClutterActor *inActor) { XfdashboardDropAction *self; XfdashboardDropActionPrivate *priv; g_return_if_fail(XFDASHBOARD_IS_DROP_ACTION(inActorMeta)); g_return_if_fail(inActor==NULL || CLUTTER_IS_ACTOR(inActor)); self=XFDASHBOARD_DROP_ACTION(inActorMeta); priv=self->priv; /* Unregister current drop target */ if(priv->actor) { /* Disconnect signals */ if(priv->destroySignalID) g_signal_handler_disconnect(priv->actor, priv->destroySignalID); /* Unset style */ if(XFDASHBOARD_IS_ACTOR(priv->actor)) { xfdashboard_stylable_remove_pseudo_class(XFDASHBOARD_STYLABLE(priv->actor), "drop-target"); } /* Unregister drop target */ _xfdashboard_drop_action_unregister_target(self); priv->destroySignalID=0; priv->actor=NULL; } /* Register new drop target */ if(inActor) { priv->actor=inActor; /* Register drop target */ _xfdashboard_drop_action_register_target(self); /* Connect signals */ priv->destroySignalID=g_signal_connect_swapped(priv->actor, "destroy", G_CALLBACK(_xfdashboard_drop_action_on_target_actor_destroy), self); } /* Call parent's class method */ CLUTTER_ACTOR_META_CLASS(xfdashboard_drop_action_parent_class)->set_actor(inActorMeta, inActor); }
/* 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)); }
/* Default signal handler for "drag-leave" */ static void _xfdashboard_drop_action_class_real_drag_leave(XfdashboardDropAction *self, XfdashboardDragAction *inDragAction) { XfdashboardDropActionPrivate *priv; g_return_if_fail(XFDASHBOARD_IS_DROP_ACTION(self)); priv=self->priv; /* Unset style */ if(priv->actor && XFDASHBOARD_IS_ACTOR(priv->actor)) { xfdashboard_stylable_remove_pseudo_class(XFDASHBOARD_STYLABLE(priv->actor), "drop-target"); } }
/* Drag handle has changed so unset styles on old handle and set style on new one */ static void _xfdashboard_drag_action_on_drag_handle_changed(XfdashboardDragAction *self, GParamSpec *inSpec, gpointer inUserData) { XfdashboardDragActionPrivate *priv; gchar *styleClass; g_return_if_fail(XFDASHBOARD_IS_DRAG_ACTION(self)); priv=self->priv; /* Unset styles on current drag handle */ if(priv->dragHandle && XFDASHBOARD_IS_ACTOR(priv->dragHandle)) { /* Unset style */ if(priv->source) { styleClass=g_strdup_printf("drag-source-%s", G_OBJECT_TYPE_NAME(priv->source)); xfdashboard_stylable_remove_class(XFDASHBOARD_STYLABLE(priv->dragHandle), styleClass); g_free(styleClass); } styleClass=g_strdup_printf("drag-actor-%s", G_OBJECT_TYPE_NAME(priv->actor)); xfdashboard_stylable_remove_class(XFDASHBOARD_STYLABLE(priv->dragHandle), styleClass); g_free(styleClass); xfdashboard_stylable_remove_pseudo_class(XFDASHBOARD_STYLABLE(priv->dragHandle), "drag-handle"); /* Forget drag handle */ priv->dragHandle=NULL; } /* Remember new drag handle and set styles */ priv->dragHandle=clutter_drag_action_get_drag_handle(CLUTTER_DRAG_ACTION(self)); if(priv->dragHandle && XFDASHBOARD_IS_ACTOR(priv->dragHandle)) { /* Set style */ if(priv->source) { styleClass=g_strdup_printf("drag-source-%s", G_OBJECT_TYPE_NAME(priv->source)); xfdashboard_stylable_add_class(XFDASHBOARD_STYLABLE(priv->dragHandle), styleClass); g_free(styleClass); } styleClass=g_strdup_printf("drag-actor-%s", G_OBJECT_TYPE_NAME(priv->actor)); xfdashboard_stylable_add_class(XFDASHBOARD_STYLABLE(priv->dragHandle), styleClass); g_free(styleClass); xfdashboard_stylable_add_pseudo_class(XFDASHBOARD_STYLABLE(priv->dragHandle), "drag-handle"); } }
/* 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 "get_parent" */ XfdashboardStylable* xfdashboard_stylable_get_parent(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_parent) { return(XFDASHBOARD_STYLABLE(iface->get_parent(self))); } /* If we get here the virtual function was not overridden */ XFDASHBOARD_STYLABLE_WARN_NOT_IMPLEMENTED(self, "get_parent"); return(NULL); }
/* Unregister a drop target */ static void _xfdashboard_drop_action_unregister_target(XfdashboardDropAction *self) { XfdashboardDropActionPrivate *priv; g_return_if_fail(XFDASHBOARD_IS_DROP_ACTION(self)); priv=self->priv; /* Unset style */ if(priv->actor && XFDASHBOARD_IS_ACTOR(priv->actor)) { xfdashboard_stylable_remove_pseudo_class(XFDASHBOARD_STYLABLE(priv->actor), "drop-target"); } /* Remove target from list of dropable targets */ _xfdashboard_drop_action_targets=g_slist_remove(_xfdashboard_drop_action_targets, self); }
/* 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]); } }
/* Pointer entered actor */ static gboolean _xfdashboard_actor_enter_event(ClutterActor *inActor, ClutterCrossingEvent *inEvent) { XfdashboardActor *self; ClutterActorClass *parentClass; g_return_val_if_fail(XFDASHBOARD_IS_ACTOR(inActor), CLUTTER_EVENT_PROPAGATE); self=XFDASHBOARD_ACTOR(inActor); /* Call parent's virtual function */ parentClass=CLUTTER_ACTOR_CLASS(xfdashboard_actor_parent_class); if(parentClass->enter_event) { parentClass->enter_event(inActor, inEvent); } /* Add pseudo-class ":hover" because pointer entered actor */ xfdashboard_stylable_add_pseudo_class(XFDASHBOARD_STYLABLE(self), "hover"); return(CLUTTER_EVENT_PROPAGATE); }
/* Actor is hidden */ static void _xfdashboard_actor_hide(ClutterActor *inActor) { XfdashboardActor *self; ClutterActorClass *parentClass; g_return_if_fail(XFDASHBOARD_IS_ACTOR(inActor)); self=XFDASHBOARD_ACTOR(inActor); /* Call parent's virtual function */ parentClass=CLUTTER_ACTOR_CLASS(xfdashboard_actor_parent_class); if(parentClass->hide) { parentClass->hide(inActor); } /* Actor is hidden now so remove pseudo-class ":hover" because pointer cannot * be in an actor hidden. */ xfdashboard_stylable_remove_pseudo_class(XFDASHBOARD_STYLABLE(self), "hover"); }
/* 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); }
/* Actor is shown */ static void _xfdashboard_actor_show(ClutterActor *inActor) { XfdashboardActor *self; ClutterActorClass *parentClass; g_return_if_fail(XFDASHBOARD_IS_ACTOR(inActor)); self=XFDASHBOARD_ACTOR(inActor); /* Call parent's virtual function */ parentClass=CLUTTER_ACTOR_CLASS(xfdashboard_actor_parent_class); if(parentClass->show) { parentClass->show(inActor); } /* If actor is visible now check if pointer is inside this actor * then add pseudo-class ":hover" to it */ if(clutter_actor_has_pointer(inActor)) { xfdashboard_stylable_add_pseudo_class(XFDASHBOARD_STYLABLE(self), "hover"); } }
/* 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)); }
/* 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); }