/* The value of a scrollbar has changed */ static void _xfdashboard_viewpad_on_scrollbar_value_changed(XfdashboardViewpad *self, gfloat inValue, gpointer inUserData) { XfdashboardViewpadPrivate *priv; ClutterActor *scrollbar; gfloat x, y, w, h; g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self)); g_return_if_fail(XFDASHBOARD_IS_SCROLLBAR(inUserData)); priv=self->priv; scrollbar=CLUTTER_ACTOR(inUserData); /* Update clipping */ if(clutter_actor_has_clip(CLUTTER_ACTOR(priv->activeView))) { clutter_actor_get_clip(CLUTTER_ACTOR(priv->activeView), &x, &y, &w, &h); if(scrollbar==priv->hScrollbar) x=inValue; else if(scrollbar==priv->vScrollbar) y=inValue; } else { x=y=0.0f; clutter_actor_get_size(CLUTTER_ACTOR(priv->activeView), &w, &h); } clutter_actor_set_clip(CLUTTER_ACTOR(priv->activeView), x, y, w, h); /* Update viewport */ _xfdashboard_viewpad_update_view_viewport(self); }
static void clip_notify_cb (ClutterActor *actor, GParamSpec *pspec, ChamplainViewport *self) { gfloat width, height; ChamplainViewportPrivate *priv = self->priv; if (!priv->sync_adjustments) return; if (!clutter_actor_has_clip (actor)) { if (priv->hadjustment) g_object_set (priv->hadjustment, "page-size", (gdouble) 1.0, NULL); if (priv->vadjustment) g_object_set (priv->vadjustment, "page-size", (gdouble) 1.0, NULL); return; } clutter_actor_get_clip (actor, NULL, NULL, &width, &height); if (priv->hadjustment) g_object_set (priv->hadjustment, "page-size", (gdouble) width, NULL); if (priv->vadjustment) g_object_set (priv->vadjustment, "page-size", (gdouble) height, NULL); }
IO_METHOD(IoClutterActor, getClip) { float xoff = 0, yoff = 0, width = 0, height = 0; IoObject *result = IoObject_new(IOSTATE); clutter_actor_get_clip(IOCACTOR(self), &xoff, &yoff, &width, &height); IoObject_setSlot_to_(result, IOSYMBOL("xOff"), IONUMBER(xoff)); IoObject_setSlot_to_(result, IOSYMBOL("yOff"), IONUMBER(yoff)); IoObject_setSlot_to_(result, IOSYMBOL("width"), IONUMBER(width)); IoObject_setSlot_to_(result, IOSYMBOL("height"), IONUMBER(height)); return result; }
/* Update view depending on scrollbar values */ static void _xfdashboard_viewpad_update_view_viewport(XfdashboardViewpad *self) { XfdashboardViewpadPrivate *priv; ClutterMatrix transform; gfloat x, y, w, h; g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self)); priv=self->priv; /* Check for active view */ if(priv->activeView==NULL) { g_warning(_("Cannot update viewport of view because no one is active")); return; } /* Get offset from scrollbars and view size from clipping */ if(clutter_actor_has_clip(CLUTTER_ACTOR(priv->activeView))) { clutter_actor_get_clip(CLUTTER_ACTOR(priv->activeView), &x, &y, &w, &h); } else { x=y=0.0f; clutter_actor_get_size(CLUTTER_ACTOR(priv->activeView), &w, &h); } /* To avoid blur convert float to ints (virtually) */ x=ceil(x); y=ceil(y); w=ceil(w); h=ceil(h); /* Set transformation (offset) */ cogl_matrix_init_identity(&transform); cogl_matrix_translate(&transform, -x, -y, 0.0f); clutter_actor_set_transform(CLUTTER_ACTOR(priv->activeView), &transform); /* Set new clipping */ clutter_actor_set_clip(CLUTTER_ACTOR(priv->activeView), x, y, w, h); }
/* 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); } }
static void rc_area_clip_add(RendererClutter *rc, gfloat x, gfloat y, gfloat w, gfloat h) { gfloat x2, y2; gfloat clip_x, clip_y, clip_w, clip_h, clip_x2, clip_y2; x2 = x + w; y2 = y + h; clutter_actor_get_clip(rc->texture, &clip_x, &clip_y, &clip_w, &clip_h); clip_x2 = clip_x + clip_w; clip_y2 = clip_y + clip_h; if (clip_x > x) clip_x = x; if (clip_x2 < x2) clip_x2 = x2; if (clip_y > y) clip_y = y; if (clip_y2 < y2) clip_y2 = y2; clip_w = clip_x2 - clip_x; clip_h = clip_y2 - clip_y; clutter_actor_set_clip(rc->texture, clip_x, clip_y, clip_w, clip_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); } } }
/* Set new active view and deactive current one */ static void _xfdashboard_viewpad_activate_view(XfdashboardViewpad *self, XfdashboardView *inView) { XfdashboardViewpadPrivate *priv; gfloat x, y; g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self)); g_return_if_fail(inView==NULL || XFDASHBOARD_IS_VIEW(inView)); priv=self->priv; /* Only set value if it changes */ if(inView==priv->activeView) return; /* Check if view is a child of this actor */ if(inView && clutter_actor_contains(CLUTTER_ACTOR(self), CLUTTER_ACTOR(inView))==FALSE) { g_warning(_("View %s is not a child of %s and cannot be activated"), G_OBJECT_TYPE_NAME(inView), G_OBJECT_TYPE_NAME(self)); return; } /* Only allow enabled views to be activated */ if(inView && !xfdashboard_view_get_enabled(inView)) { g_warning(_("Cannot activate disabled view %s at %s"), G_OBJECT_TYPE_NAME(inView), G_OBJECT_TYPE_NAME(self)); return; } /* Deactivate current view */ if(priv->activeView) { /* Hide current view and emit signal before and after deactivation */ g_signal_emit(self, XfdashboardViewpadSignals[SIGNAL_VIEW_DEACTIVATING], 0, priv->activeView); g_signal_emit_by_name(priv->activeView, "deactivating"); clutter_actor_hide(CLUTTER_ACTOR(priv->activeView)); g_debug("Deactivated view %s", G_OBJECT_TYPE_NAME(priv->activeView)); g_signal_emit_by_name(priv->activeView, "deactivated"); g_signal_emit(self, XfdashboardViewpadSignals[SIGNAL_VIEW_DEACTIVATED], 0, priv->activeView); g_object_unref(priv->activeView); priv->activeView=NULL; } /* Activate new view (if available) by showing new view, setting up * scrollbars and emitting signal before and after activation. * Prevent signal handling for scrollbars' "value-changed" as it will * mess up with clipping and viewport. We only need to set value of * scrollbars but we do not need to handle the changed value. */ if(inView) { priv->activeView=g_object_ref(inView); g_signal_emit(self, XfdashboardViewpadSignals[SIGNAL_VIEW_ACTIVATING], 0, priv->activeView); g_signal_emit_by_name(priv->activeView, "activating"); g_signal_handlers_block_by_func(priv->hScrollbar, _xfdashboard_viewpad_on_scrollbar_value_changed, self); g_signal_handlers_block_by_func(priv->vScrollbar, _xfdashboard_viewpad_on_scrollbar_value_changed, self); x=y=0.0f; clutter_actor_get_clip(CLUTTER_ACTOR(priv->activeView), &x, &y, NULL, NULL); _xfdashboard_viewpad_update_scrollbars(self); xfdashboard_scrollbar_set_value(XFDASHBOARD_SCROLLBAR(priv->hScrollbar), x); xfdashboard_scrollbar_set_value(XFDASHBOARD_SCROLLBAR(priv->vScrollbar), y); _xfdashboard_viewpad_update_view_viewport(self); clutter_actor_show(CLUTTER_ACTOR(priv->activeView)); g_debug("Activated view %s", G_OBJECT_TYPE_NAME(priv->activeView)); g_signal_handlers_unblock_by_func(priv->hScrollbar, _xfdashboard_viewpad_on_scrollbar_value_changed, self); g_signal_handlers_unblock_by_func(priv->vScrollbar, _xfdashboard_viewpad_on_scrollbar_value_changed, self); g_signal_emit_by_name(priv->activeView, "activated"); g_signal_emit(self, XfdashboardViewpadSignals[SIGNAL_VIEW_ACTIVATED], 0, priv->activeView); } /* Notify about property change */ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardViewpadProperties[PROP_ACTIVE_VIEW]); }