/* Find view by internal name */ XfdashboardView* xfdashboard_viewpad_find_view_by_name(XfdashboardViewpad *self, const gchar *inInternalName) { ClutterActorIter iter; ClutterActor *child; XfdashboardView *view; g_return_val_if_fail(XFDASHBOARD_IS_VIEWPAD(self), NULL); view=NULL; /* Iterate through children and lookup view matching requested name */ clutter_actor_iter_init(&iter, CLUTTER_ACTOR(self)); while(!view && clutter_actor_iter_next(&iter, &child)) { /* Check if child is a view and its internal name matches requested name */ if(XFDASHBOARD_IS_VIEW(child)==TRUE && g_strcmp0(xfdashboard_view_get_internal_name(XFDASHBOARD_VIEW(child)), inInternalName)==0) { view=XFDASHBOARD_VIEW(child); } } /* Return view found which may be NULL if no view of requested type was found */ return(view); }
static void _xfdashboard_viewpad_on_allocation_changed(ClutterActor *inActor, ClutterActorBox *inBox, ClutterAllocationFlags inFlags, gpointer inUserData) { XfdashboardViewpad *self; XfdashboardViewpadPrivate *priv; XfdashboardView *view G_GNUC_UNUSED; g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(inActor)); g_return_if_fail(XFDASHBOARD_IS_VIEW(inUserData)); self=XFDASHBOARD_VIEWPAD(inActor); priv=self->priv; view=XFDASHBOARD_VIEW(inUserData); /* Defer updating scrollbars but only if view whose allocation * has changed is the active one */ if(priv->scrollbarUpdateID==0) { priv->scrollbarUpdateID= clutter_threads_add_repaint_func_full(CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD | CLUTTER_REPAINT_FLAGS_POST_PAINT, _xfdashboard_viewpad_on_allocation_changed_repaint_callback, self, NULL); } }
static void _xfdashboard_view_get_property(GObject *inObject, guint inPropID, GValue *outValue, GParamSpec *inSpec) { XfdashboardView *self=XFDASHBOARD_VIEW(inObject); switch(inPropID) { case PROP_VIEW_INTERNAL_NAME: g_value_set_string(outValue, self->priv->viewInternalName); break; case PROP_VIEW_NAME: g_value_set_string(outValue, self->priv->viewName); break; case PROP_VIEW_ICON: g_value_set_string(outValue, self->priv->viewIcon); break; case PROP_FIT_MODE: g_value_set_enum(outValue, self->priv->fitMode); break; case PROP_ENABLED: g_value_set_boolean(outValue, self->priv->isEnabled); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec); break; } }
/* Find view by type */ XfdashboardView* xfdashboard_viewpad_find_view_by_type(XfdashboardViewpad *self, GType inType) { ClutterActorIter iter; ClutterActor *child; XfdashboardView *view; g_return_val_if_fail(XFDASHBOARD_IS_VIEWPAD(self), NULL); view=NULL; /* Iterate through children and create list of views */ clutter_actor_iter_init(&iter, CLUTTER_ACTOR(self)); while(!view && clutter_actor_iter_next(&iter, &child)) { /* Check if child is a view and of type looking for */ if(XFDASHBOARD_IS_VIEW(child)==TRUE && G_OBJECT_TYPE(child)==inType) { view=XFDASHBOARD_VIEW(child); } } /* Return view found which may be NULL if no view of requested type was found */ return(view); }
/* Set/get properties */ static void _xfdashboard_view_set_property(GObject *inObject, guint inPropID, const GValue *inValue, GParamSpec *inSpec) { XfdashboardView *self=XFDASHBOARD_VIEW(inObject); switch(inPropID) { case PROP_VIEW_INTERNAL_NAME: xfdashboard_view_set_internal_name(self, g_value_get_string(inValue)); break; case PROP_VIEW_NAME: xfdashboard_view_set_name(self, g_value_get_string(inValue)); break; case PROP_VIEW_ICON: xfdashboard_view_set_icon(self, g_value_get_string(inValue)); break; case PROP_FIT_MODE: xfdashboard_view_set_fit_mode(self, (XfdashboardFitMode)g_value_get_enum(inValue)); break; case PROP_ENABLED: xfdashboard_view_set_enabled(self, g_value_get_boolean(inValue)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec); break; } }
/* Dispose this object */ static void _xfdashboard_view_dispose(GObject *inObject) { XfdashboardView *self=XFDASHBOARD_VIEW(inObject); XfdashboardViewPrivate *priv=self->priv; /* Release allocated resources */ if(priv->viewInternalName) { g_free(priv->viewInternalName); priv->viewInternalName=NULL; } if(priv->viewName) { g_free(priv->viewName); priv->viewName=NULL; } if(priv->viewIcon) { g_free(priv->viewIcon); priv->viewIcon=NULL; } if(priv->viewIconImage) { g_object_unref(priv->viewIconImage); priv->viewIconImage=NULL; } /* Call parent's class dispose method */ G_OBJECT_CLASS(xfdashboard_view_parent_class)->dispose(inObject); }
/* Called when a view was removed to viewpad */ static void _xfdashboard_view_selector_on_view_removed(XfdashboardViewSelector *self, XfdashboardView *inView, gpointer inUserData) { ClutterActorIter iter; ClutterActor *child; gpointer view; g_return_if_fail(XFDASHBOARD_IS_VIEW_SELECTOR(self)); /* Iterate through create views and lookup view of given type */ clutter_actor_iter_init(&iter, CLUTTER_ACTOR(self)); while(clutter_actor_iter_next(&iter, &child)) { /* Check if child is a button otherwise continue iterating */ if(!XFDASHBOARD_IS_TOGGLE_BUTTON(child)) continue; /* If button has reference to view destroy it */ view=g_object_get_data(G_OBJECT(child), "view"); if(XFDASHBOARD_IS_VIEW(view) && XFDASHBOARD_VIEW(view)==inView) { clutter_actor_destroy(child); } } }
/* A view was disabled */ static void _xfdashboard_viewpad_on_view_disabled(XfdashboardViewpad *self, XfdashboardView *inView) { XfdashboardViewpadPrivate *priv; ClutterActorIter iter; ClutterActor *child; XfdashboardView *firstActivatableView; g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self)); g_return_if_fail(XFDASHBOARD_IS_VIEW(inView)); priv=self->priv; firstActivatableView=NULL; /* If the currently disabled view is the active one, activate a next available view */ if(inView==priv->activeView) { /* Iterate through create views and lookup view of given type */ clutter_actor_iter_init(&iter, CLUTTER_ACTOR(self)); while(clutter_actor_iter_next(&iter, &child)) { /* Check if child is a view otherwise continue iterating */ if(XFDASHBOARD_IS_VIEW(child)!=TRUE) continue; /* If child is not the view being disabled check if it could * become the next activatable view * the first activatable view after we destroyed all views found. */ if(XFDASHBOARD_VIEW(child)!=inView && xfdashboard_view_get_enabled(XFDASHBOARD_VIEW(child))) { firstActivatableView=XFDASHBOARD_VIEW(child); } } /* Now activate the first activatable view we found during iteration. * It can also be no view (NULL pointer). */ g_debug("Disabled view %s was the active view in %s - will activate %s", G_OBJECT_TYPE_NAME(inView), G_OBJECT_TYPE_NAME(self), firstActivatableView ? G_OBJECT_TYPE_NAME(firstActivatableView) : "no other view"); _xfdashboard_viewpad_activate_view(self, firstActivatableView); } }
/* Create view of given type and add to this actor */ static void _xfdashboard_viewpad_add_view(XfdashboardViewpad *self, GType inViewType) { XfdashboardViewpadPrivate *priv; GObject *view; g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self)); priv=self->priv; /* Create instance and check if it is a view */ g_debug("Creating view %s for viewpad", g_type_name(inViewType)); view=g_object_new(inViewType, NULL); if(view==NULL) { g_critical(_("Failed to create view instance of %s"), g_type_name(inViewType)); return; } if(XFDASHBOARD_IS_VIEW(view)!=TRUE) { g_critical(_("Instance %s is not a %s and cannot be added to %s"), g_type_name(inViewType), g_type_name(XFDASHBOARD_TYPE_VIEW), G_OBJECT_TYPE_NAME(self)); return; } /* Add new view instance to this actor but hidden */ clutter_actor_hide(CLUTTER_ACTOR(view)); clutter_actor_add_child(CLUTTER_ACTOR(self), CLUTTER_ACTOR(view)); g_signal_connect_swapped(view, "allocation-changed", G_CALLBACK(_xfdashboard_viewpad_on_allocation_changed), self); g_signal_connect_swapped(view, "scroll-to", G_CALLBACK(_xfdashboard_viewpad_on_view_scroll_to), self); g_signal_connect_swapped(view, "ensure-visible", G_CALLBACK(_xfdashboard_viewpad_on_view_ensure_visible), self); g_signal_connect_swapped(view, "disabled", G_CALLBACK(_xfdashboard_viewpad_on_view_disabled), self); g_signal_connect_swapped(view, "enabled", G_CALLBACK(_xfdashboard_viewpad_on_view_enabled), self); g_signal_emit(self, XfdashboardViewpadSignals[SIGNAL_VIEW_ADDED], 0, view); /* Set active view if none active (usually it is the first view created) */ if(priv->activeView==NULL && xfdashboard_view_get_enabled(XFDASHBOARD_VIEW(view))) { _xfdashboard_viewpad_activate_view(self, XFDASHBOARD_VIEW(view)); } }
/* Called when a view type was unregistered */ static void _xfdashboard_viewpad_on_view_unregistered(XfdashboardViewpad *self, GType inViewType, gpointer inUserData) { XfdashboardViewpadPrivate *priv; ClutterActorIter iter; ClutterActor *child; ClutterActor *firstActivatableView; g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self)); priv=self->priv; firstActivatableView=NULL; /* Iterate through create views and lookup view of given type */ clutter_actor_iter_init(&iter, CLUTTER_ACTOR(self)); while(clutter_actor_iter_next(&iter, &child)) { /* Check if child is a view otherwise continue iterating */ if(XFDASHBOARD_IS_VIEW(child)!=TRUE) continue; /* If child is not of type being unregistered it will get * the first activatable view after we destroyed all views found. */ if(G_OBJECT_TYPE(child)!=inViewType) { if(xfdashboard_view_get_enabled(XFDASHBOARD_VIEW(child))) firstActivatableView=child; } else { if(G_OBJECT(child)==G_OBJECT(priv->activeView)) _xfdashboard_viewpad_activate_view(self, NULL); g_signal_emit(self, XfdashboardViewpadSignals[SIGNAL_VIEW_REMOVED], 0, child); clutter_actor_destroy(child); } } /* Now activate the first activatable view we found during iteration */ if(firstActivatableView) _xfdashboard_viewpad_activate_view(self, XFDASHBOARD_VIEW(firstActivatableView)); }
/* A view button was clicked to activate it */ static void _xfdashboard_view_selector_on_view_button_clicked(XfdashboardViewSelector *self, gpointer inUserData) { XfdashboardViewSelectorPrivate *priv; XfdashboardToggleButton *button; XfdashboardView *view; g_return_if_fail(XFDASHBOARD_IS_VIEW_SELECTOR(self)); g_return_if_fail(XFDASHBOARD_IS_BUTTON(inUserData)); priv=self->priv; button=XFDASHBOARD_TOGGLE_BUTTON(inUserData); view=XFDASHBOARD_VIEW(g_object_get_data(G_OBJECT(button), "view")); xfdashboard_viewpad_set_active_view(priv->viewpad, view); }
/** * xfdashboard_view_selector_set_viewpad: * @self: A #XfdashboardViewSelector * @inViewpad: The #XfdashboardViewpad whose views to show at this actor * * Sets the #XfdashboardViewpad whose views to show as a choice of views * at @self. */ void xfdashboard_view_selector_set_viewpad(XfdashboardViewSelector *self, XfdashboardViewpad *inViewpad) { XfdashboardViewSelectorPrivate *priv; GList *views, *entry; g_return_if_fail(XFDASHBOARD_IS_VIEW_SELECTOR(self)); g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(inViewpad)); priv=self->priv; /* Only set new value if it differs from current value */ if(priv->viewpad==inViewpad) return; /* Release old viewpad if available */ if(priv->viewpad) { /* Destroy all children */ clutter_actor_destroy_all_children(CLUTTER_ACTOR(self)); /* Release old viewpad */ g_signal_handlers_disconnect_by_data(priv->viewpad, self); g_object_unref(priv->viewpad); priv->viewpad=NULL; } /* Set new value */ priv->viewpad=XFDASHBOARD_VIEWPAD(g_object_ref(inViewpad)); g_signal_connect_swapped(priv->viewpad, "view-added", G_CALLBACK(_xfdashboard_view_selector_on_view_added), self); g_signal_connect_swapped(priv->viewpad, "view-removed", G_CALLBACK(_xfdashboard_view_selector_on_view_removed), self); /* Create instance of each registered view type and add it to this actor * and connect signals */ views=xfdashboard_viewpad_get_views(priv->viewpad); for(entry=views; entry; entry=g_list_next(entry)) { _xfdashboard_view_selector_on_view_added(self, XFDASHBOARD_VIEW(entry->data), NULL); } g_list_free(views); /* Notify about property change */ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardViewSelectorProperties[PROP_VIEWPAD]); }
/* Scroll to requested position in view */ static void _xfdashboard_viewpad_on_view_scroll_to(XfdashboardViewpad *self, gfloat inX, gfloat inY, gpointer inUserData) { XfdashboardViewpadPrivate *priv; XfdashboardView *view; gfloat x, y, w, h; g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self)); g_return_if_fail(XFDASHBOARD_IS_VIEW(inUserData)); priv=self->priv; view=XFDASHBOARD_VIEW(inUserData); /* If to-scroll view is the active view in viewpad * just set scrollbar value to the new ones */ if(view==priv->activeView) { if(inX>=0.0f) xfdashboard_scrollbar_set_value(XFDASHBOARD_SCROLLBAR(priv->hScrollbar), inX); if(inY>=0.0f) xfdashboard_scrollbar_set_value(XFDASHBOARD_SCROLLBAR(priv->vScrollbar), inY); } /* If to-scroll view is not the active one update its clipping */ else { if(clutter_actor_has_clip(CLUTTER_ACTOR(view))) { clutter_actor_get_clip(CLUTTER_ACTOR(view), &x, &y, &w, &h); if(inX>=0.0f) x=inX; if(inY>=0.0f) y=inY; } else { x=y=0.0f; clutter_actor_get_size(CLUTTER_ACTOR(view), &w, &h); } clutter_actor_set_clip(CLUTTER_ACTOR(view), x, y, w, h); } }
/* Allocate position and size of actor and its children */ static void _xfdashboard_viewpad_allocate(ClutterActor *self, const ClutterActorBox *inBox, ClutterAllocationFlags inFlags) { XfdashboardViewpadPrivate *priv=XFDASHBOARD_VIEWPAD(self)->priv; ClutterActorClass *actorClass=CLUTTER_ACTOR_CLASS(xfdashboard_viewpad_parent_class); gfloat viewWidth, viewHeight; gfloat vScrollbarWidth, vScrollbarHeight; gfloat hScrollbarWidth, hScrollbarHeight; gboolean hScrollbarVisible, vScrollbarVisible; ClutterActorBox *box; gfloat x, y, w, h; /* Chain up to store the allocation of the actor */ if(actorClass->allocate) actorClass->allocate(self, inBox, inFlags); /* Initialize largest possible allocation for view and determine * real size of view to show. The real size is used to determine * scroll bar visibility if policy is automatic */ viewWidth=clutter_actor_box_get_width(inBox); viewHeight=clutter_actor_box_get_height(inBox); /* Determine visibility of scroll bars */ hScrollbarVisible=FALSE; if(priv->hScrollbarPolicy==XFDASHBOARD_POLICY_ALWAYS || (priv->hScrollbarPolicy==XFDASHBOARD_POLICY_AUTOMATIC && xfdashboard_scrollbar_get_range(XFDASHBOARD_SCROLLBAR(priv->hScrollbar))>viewWidth)) { hScrollbarVisible=TRUE; } if(xfdashboard_view_get_fit_mode(XFDASHBOARD_VIEW(priv->activeView))==XFDASHBOARD_FIT_MODE_HORIZONTAL || xfdashboard_view_get_fit_mode(XFDASHBOARD_VIEW(priv->activeView))==XFDASHBOARD_FIT_MODE_BOTH) { hScrollbarVisible=FALSE; } vScrollbarVisible=FALSE; if(priv->vScrollbarPolicy==XFDASHBOARD_POLICY_ALWAYS || (priv->vScrollbarPolicy==XFDASHBOARD_POLICY_AUTOMATIC && xfdashboard_scrollbar_get_range(XFDASHBOARD_SCROLLBAR(priv->vScrollbar))>viewHeight)) { vScrollbarVisible=TRUE; } if(xfdashboard_view_get_fit_mode(XFDASHBOARD_VIEW(priv->activeView))==XFDASHBOARD_FIT_MODE_VERTICAL || xfdashboard_view_get_fit_mode(XFDASHBOARD_VIEW(priv->activeView))==XFDASHBOARD_FIT_MODE_BOTH) { vScrollbarVisible=FALSE; } /* Set allocation for visible scroll bars */ vScrollbarWidth=0.0f; vScrollbarHeight=viewHeight; clutter_actor_get_preferred_width(priv->vScrollbar, -1, NULL, &vScrollbarWidth); hScrollbarWidth=viewWidth; hScrollbarHeight=0.0f; clutter_actor_get_preferred_height(priv->hScrollbar, -1, NULL, &hScrollbarHeight); if(hScrollbarVisible && vScrollbarVisible) { vScrollbarHeight-=hScrollbarHeight; hScrollbarWidth-=vScrollbarWidth; } if(vScrollbarVisible==FALSE) box=clutter_actor_box_new(0, 0, 0, 0); else box=clutter_actor_box_new(viewWidth-vScrollbarWidth, 0, viewWidth, vScrollbarHeight); clutter_actor_allocate(priv->vScrollbar, box, inFlags); clutter_actor_box_free(box); if(hScrollbarVisible==FALSE) box=clutter_actor_box_new(0, 0, 0, 0); else box=clutter_actor_box_new(0, viewHeight-hScrollbarHeight, hScrollbarWidth, viewHeight); clutter_actor_allocate(priv->hScrollbar, box, inFlags); clutter_actor_box_free(box); /* Reduce allocation for view by any visible scroll bar * and set allocation and clipping of view */ if(priv->activeView) { /* Set allocation */ if(vScrollbarVisible) viewWidth-=vScrollbarWidth; if(hScrollbarVisible) viewHeight-=hScrollbarHeight; x=y=0.0f; if(clutter_actor_has_clip(CLUTTER_ACTOR(priv->activeView))) { clutter_actor_get_clip(CLUTTER_ACTOR(priv->activeView), &x, &y, NULL, NULL); } switch(xfdashboard_view_get_fit_mode(XFDASHBOARD_VIEW(priv->activeView))) { case XFDASHBOARD_FIT_MODE_BOTH: w=viewWidth; h=viewHeight; break; case XFDASHBOARD_FIT_MODE_HORIZONTAL: w=viewWidth; clutter_actor_get_preferred_height(CLUTTER_ACTOR(priv->activeView), w, NULL, &h); break; case XFDASHBOARD_FIT_MODE_VERTICAL: h=viewHeight; clutter_actor_get_preferred_width(CLUTTER_ACTOR(priv->activeView), h, NULL, &w); break; default: clutter_actor_get_preferred_size(CLUTTER_ACTOR(priv->activeView), NULL, NULL, &w, &h); break; } box=clutter_actor_box_new(0, 0, w, h); clutter_actor_allocate(CLUTTER_ACTOR(priv->activeView), box, inFlags); clutter_actor_box_free(box); clutter_actor_set_clip(CLUTTER_ACTOR(priv->activeView), x, y, viewWidth, viewHeight); } /* Only set value if it changes */ if(priv->hScrollbarVisible!=hScrollbarVisible) { /* Set new value */ priv->hScrollbarVisible=hScrollbarVisible; /* Notify about property change */ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardViewpadProperties[PROP_HSCROLLBAR_VISIBLE]); } if(priv->vScrollbarVisible!=vScrollbarVisible) { /* Set new value */ priv->vScrollbarVisible=vScrollbarVisible; /* Notify about property change */ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardViewpadProperties[PROP_VSCROLLBAR_VISIBLE]); } }
/* Ensure that a child of a view is visible by scrolling if needed */ static void _xfdashboard_viewpad_on_view_ensure_visible(XfdashboardViewpad *self, ClutterActor *inActor, gpointer inUserData) { XfdashboardViewpadPrivate *priv; XfdashboardView *view; ClutterVertex origin; ClutterVertex transformedUpperLeft; ClutterVertex transformedLowerRight; gfloat x, y, w, h; gboolean needScrolling; g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self)); g_return_if_fail(CLUTTER_IS_ACTOR(inActor)); g_return_if_fail(XFDASHBOARD_IS_VIEW(inUserData)); priv=self->priv; view=XFDASHBOARD_VIEW(inUserData); needScrolling=FALSE; origin.z=0.0f; /* Get position and size of view but respect scrolled position */ if(view==priv->activeView) { x=xfdashboard_scrollbar_get_value(XFDASHBOARD_SCROLLBAR(priv->hScrollbar)); y=xfdashboard_scrollbar_get_value(XFDASHBOARD_SCROLLBAR(priv->vScrollbar)); clutter_actor_get_size(CLUTTER_ACTOR(self), &w, &h); } else { if(clutter_actor_has_clip(CLUTTER_ACTOR(view))) { clutter_actor_get_clip(CLUTTER_ACTOR(view), &x, &y, &w, &h); } else { x=y=0.0f; clutter_actor_get_size(CLUTTER_ACTOR(view), &w, &h); } } /* Check that upper left point of actor is visible otherwise set flag for scrolling */ origin.x=origin.y=0.0f; clutter_actor_apply_relative_transform_to_point(inActor, CLUTTER_ACTOR(view), &origin, &transformedUpperLeft); if(transformedUpperLeft.x<x || transformedUpperLeft.x>(x+w) || transformedUpperLeft.y<y || transformedUpperLeft.y>(y+h)) { needScrolling=TRUE; } /* Check that lower right point of actor is visible otherwise set flag for scrolling */ clutter_actor_get_size(inActor, &origin.x, &origin.y); clutter_actor_apply_relative_transform_to_point(inActor, CLUTTER_ACTOR(view), &origin, &transformedLowerRight); if(transformedLowerRight.x<x || transformedLowerRight.x>(x+w) || transformedLowerRight.y<y || transformedLowerRight.y>(y+h)) { needScrolling=TRUE; } /* Check if we need to scroll */ if(needScrolling) { gfloat distanceUpperLeft; gfloat distanceLowerRight; /* Find shortest way to scroll and then scroll */ distanceUpperLeft=sqrtf(powf(transformedUpperLeft.x-x, 2.0f)+powf(transformedUpperLeft.y-y, 2.0f)); distanceLowerRight=sqrtf(powf(transformedLowerRight.x-(x+w), 2.0f)+powf(transformedLowerRight.y-(y+h), 2.0f)); if(distanceUpperLeft<=distanceLowerRight) { _xfdashboard_viewpad_on_view_scroll_to(self, transformedUpperLeft.x, transformedUpperLeft.y, view); } else { _xfdashboard_viewpad_on_view_scroll_to(self, transformedUpperLeft.x, transformedLowerRight.y-h, view); } } }