/* 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); }
/* 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); }