1 /*
2  * viewpad: A viewpad managing views
3  *
4  * Copyright 2012-2020 Stephan Haller <nomad@froevel.de>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  * MA 02110-1301, USA.
20  *
21  *
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 
28 #include <libxfdashboard/viewpad.h>
29 
30 #include <glib/gi18n-lib.h>
31 #include <gtk/gtk.h>
32 #include <math.h>
33 
34 #include <libxfdashboard/view-manager.h>
35 #include <libxfdashboard/scrollbar.h>
36 #include <libxfdashboard/enums.h>
37 #include <libxfdashboard/utils.h>
38 #include <libxfdashboard/focusable.h>
39 #include <libxfdashboard/focus-manager.h>
40 #include <libxfdashboard/compat.h>
41 #include <libxfdashboard/debug.h>
42 
43 
44 /* Define this class in GObject system */
45 static void _xfdashboard_viewpad_focusable_iface_init(XfdashboardFocusableInterface *iface);
46 
47 struct _XfdashboardViewpadPrivate
48 {
49 	/* Properties related */
50 	gfloat							spacing;
51 	XfdashboardView					*activeView;
52 	XfdashboardVisibilityPolicy		hScrollbarPolicy;
53 	gboolean						hScrollbarVisible;
54 	XfdashboardVisibilityPolicy		vScrollbarPolicy;
55 	gboolean						vScrollbarVisible;
56 
57 	/* Instance related */
58 	XfdashboardViewManager			*viewManager;
59 
60 	ClutterLayoutManager			*layout;
61 	ClutterActor					*container;
62 	ClutterActor					*hScrollbar;
63 	ClutterActor					*vScrollbar;
64 
65 	guint							scrollbarUpdateID;
66 
67 	gboolean						doRegisterFocusableViews;
68 
69 	ClutterActorBox					*lastAllocation;
70 };
71 
72 G_DEFINE_TYPE_WITH_CODE(XfdashboardViewpad,
73 						xfdashboard_viewpad,
74 						XFDASHBOARD_TYPE_BACKGROUND,
75 						G_ADD_PRIVATE(XfdashboardViewpad)
76 						G_IMPLEMENT_INTERFACE(XFDASHBOARD_TYPE_FOCUSABLE, _xfdashboard_viewpad_focusable_iface_init))
77 
78 /* Properties */
79 enum
80 {
81 	PROP_0,
82 
83 	PROP_SPACING,
84 	PROP_ACTIVE_VIEW,
85 	PROP_HSCROLLBAR_POLICY,
86 	PROP_HSCROLLBAR_VISIBLE,
87 	PROP_VSCROLLBAR_POLICY,
88 	PROP_VSCROLLBAR_VISIBLE,
89 
90 	PROP_LAST
91 };
92 
93 static GParamSpec* XfdashboardViewpadProperties[PROP_LAST]={ 0, };
94 
95 /* Signals */
96 enum
97 {
98 	SIGNAL_VIEW_ADDED,
99 	SIGNAL_VIEW_REMOVED,
100 
101 	SIGNAL_VIEW_ACTIVATING,
102 	SIGNAL_VIEW_ACTIVATED,
103 	SIGNAL_VIEW_DEACTIVATING,
104 	SIGNAL_VIEW_DEACTIVATED,
105 
106 	SIGNAL_LAST
107 };
108 
109 static guint XfdashboardViewpadSignals[SIGNAL_LAST]={ 0, };
110 
111 /* Forward declaration */
112 static void _xfdashboard_viewpad_allocate(ClutterActor *self, const ClutterActorBox *inBox, ClutterAllocationFlags inFlags);
113 
114 /* IMPLEMENTATION: Private variables and methods */
115 
116 /* Update view depending on scrollbar values */
_xfdashboard_viewpad_update_view_viewport(XfdashboardViewpad * self)117 static void _xfdashboard_viewpad_update_view_viewport(XfdashboardViewpad *self)
118 {
119 	XfdashboardViewpadPrivate	*priv;
120 	ClutterMatrix				transform;
121 	gfloat						x, y, w, h;
122 
123 	g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self));
124 
125 	priv=self->priv;
126 
127 	/* Check for active view */
128 	if(priv->activeView==NULL)
129 	{
130 		g_warning("Cannot update viewport of view because no one is active");
131 		return;
132 	}
133 
134 	/* Get offset from scrollbars and view size from clipping */
135 	if(clutter_actor_has_clip(CLUTTER_ACTOR(priv->activeView)))
136 	{
137 		clutter_actor_get_clip(CLUTTER_ACTOR(priv->activeView), &x, &y, &w, &h);
138 	}
139 		else
140 		{
141  			x=y=0.0f;
142 			clutter_actor_get_size(CLUTTER_ACTOR(priv->activeView), &w, &h);
143 		}
144 
145 	/* To avoid blur convert float to ints (virtually) */
146 	x=ceil(x);
147 	y=ceil(y);
148 	w=ceil(w);
149 	h=ceil(h);
150 
151 	/* Set transformation (offset) */
152 	cogl_matrix_init_identity(&transform);
153 	cogl_matrix_translate(&transform, -x, -y, 0.0f);
154 	clutter_actor_set_transform(CLUTTER_ACTOR(priv->activeView), &transform);
155 
156 	/* Set new clipping */
157 	clutter_actor_set_clip(CLUTTER_ACTOR(priv->activeView), x, y, w, h);
158 }
159 
160 /* The value of a scrollbar has changed */
_xfdashboard_viewpad_on_scrollbar_value_changed(XfdashboardViewpad * self,gfloat inValue,gpointer inUserData)161 static void _xfdashboard_viewpad_on_scrollbar_value_changed(XfdashboardViewpad *self,
162 															gfloat inValue,
163 															gpointer inUserData)
164 {
165 	XfdashboardViewpadPrivate	*priv;
166 	ClutterActor				*scrollbar;
167 	gfloat						x, y, w, h;
168 
169 	g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self));
170 	g_return_if_fail(XFDASHBOARD_IS_SCROLLBAR(inUserData));
171 
172 	priv=self->priv;
173 	scrollbar=CLUTTER_ACTOR(inUserData);
174 
175 	/* Update clipping */
176 	if(clutter_actor_has_clip(CLUTTER_ACTOR(priv->activeView)))
177 	{
178 		clutter_actor_get_clip(CLUTTER_ACTOR(priv->activeView), &x, &y, &w, &h);
179 		if(scrollbar==priv->hScrollbar) x=inValue;
180 			else if(scrollbar==priv->vScrollbar) y=inValue;
181 	}
182 		else
183 		{
184 			x=y=0.0f;
185 			clutter_actor_get_size(CLUTTER_ACTOR(priv->activeView), &w, &h);
186 		}
187 	clutter_actor_set_clip(CLUTTER_ACTOR(priv->activeView), x, y, w, h);
188 
189 	/* Update viewport */
190 	_xfdashboard_viewpad_update_view_viewport(self);
191 }
192 
193 /* Allocation of a view changed */
_xfdashboard_viewpad_update_scrollbars(XfdashboardViewpad * self)194 static void _xfdashboard_viewpad_update_scrollbars(XfdashboardViewpad *self)
195 {
196 	XfdashboardViewpadPrivate	*priv;
197 	gfloat						w, h;
198 
199 	g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self));
200 
201 	priv=self->priv;
202 
203 	/* Set range of scroll bar to width and height of active view
204 	 * But we need to check for nan-values here - I do not get rid of it :(
205 	 */
206 	if(priv->activeView) clutter_actor_get_size(CLUTTER_ACTOR(priv->activeView), &w, &h);
207 		else w=h=1.0f;
208 
209 	xfdashboard_scrollbar_set_range(XFDASHBOARD_SCROLLBAR(priv->vScrollbar), isnan(h)==0 ? h : 0.0f);
210 
211 	/* If any scroll bar policy is automatic then reallocate the
212 	 * same allocation again in an unkindly way to force a recalculation
213 	 * if scroll bars needed to shown (or hidden what is unlikely)
214 	 */
215 	if(clutter_actor_is_visible(CLUTTER_ACTOR(self)) &&
216 		(priv->hScrollbarPolicy==XFDASHBOARD_VISIBILITY_POLICY_AUTOMATIC ||
217 			priv->vScrollbarPolicy==XFDASHBOARD_VISIBILITY_POLICY_AUTOMATIC))
218 	{
219 		ClutterActorBox			box;
220 
221 		clutter_actor_get_allocation_box(CLUTTER_ACTOR(self), &box);
222 		_xfdashboard_viewpad_allocate(CLUTTER_ACTOR(self), &box, CLUTTER_DELEGATE_LAYOUT);
223 	}
224 }
225 
226 /* Set new active view and deactive current one */
_xfdashboard_viewpad_activate_view(XfdashboardViewpad * self,XfdashboardView * inView)227 static void _xfdashboard_viewpad_activate_view(XfdashboardViewpad *self, XfdashboardView *inView)
228 {
229 	XfdashboardViewpadPrivate	*priv;
230 	gfloat						x, y;
231 	XfdashboardFocusManager		*focusManager;
232 	gboolean					hasFocus;
233 
234 	g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self));
235 	g_return_if_fail(inView==NULL || XFDASHBOARD_IS_VIEW(inView));
236 
237 	priv=self->priv;
238 	hasFocus=FALSE;
239 
240 	/* Only set value if it changes */
241 	if(inView==priv->activeView) return;
242 
243 	/* Check if view is a child of this actor */
244 	if(inView && clutter_actor_contains(CLUTTER_ACTOR(self), CLUTTER_ACTOR(inView))==FALSE)
245 	{
246 		g_warning("View %s is not a child of %s and cannot be activated",
247 					G_OBJECT_TYPE_NAME(inView), G_OBJECT_TYPE_NAME(self));
248 		return;
249 	}
250 
251 	/* Only allow enabled views to be activated */
252 	if(inView && !xfdashboard_view_get_enabled(inView))
253 	{
254 		g_warning("Cannot activate disabled view %s at %s",
255 					G_OBJECT_TYPE_NAME(inView), G_OBJECT_TYPE_NAME(self));
256 		return;
257 	}
258 
259 	/* Determine if this viewpad has the focus because we have to move focus in this case */
260 	focusManager=xfdashboard_focus_manager_get_default();
261 
262 	/* Deactivate current view */
263 	if(priv->activeView)
264 	{
265 		/* Unset focus at current active view if this view has the focus */
266 		hasFocus=xfdashboard_focus_manager_has_focus(focusManager, XFDASHBOARD_FOCUSABLE(priv->activeView));
267 		if(hasFocus)
268 		{
269 			xfdashboard_focusable_unset_focus(XFDASHBOARD_FOCUSABLE(priv->activeView));
270 			XFDASHBOARD_DEBUG(self, ACTOR,
271 								"Unset focus from view '%s' because it is the active view at viewpad",
272 								xfdashboard_view_get_name(priv->activeView));
273 		}
274 
275 		/* Hide current view and emit signal before and after deactivation */
276 		g_signal_emit(self, XfdashboardViewpadSignals[SIGNAL_VIEW_DEACTIVATING], 0, priv->activeView);
277 		g_signal_emit_by_name(priv->activeView, "deactivating");
278 
279 		clutter_actor_hide(CLUTTER_ACTOR(priv->activeView));
280 		XFDASHBOARD_DEBUG(self, ACTOR,
281 							"Deactivated view %s",
282 							G_OBJECT_TYPE_NAME(priv->activeView));
283 
284 		g_signal_emit_by_name(priv->activeView, "deactivated");
285 		g_signal_emit(self, XfdashboardViewpadSignals[SIGNAL_VIEW_DEACTIVATED], 0, priv->activeView);
286 
287 		g_object_unref(priv->activeView);
288 		priv->activeView=NULL;
289 	}
290 
291 	/* Activate new view (if available) by showing new view, setting up
292 	 * scrollbars and emitting signal before and after activation.
293 	 * Prevent signal handling for scrollbars' "value-changed" as it will
294 	 * mess up with clipping and viewport. We only need to set value of
295 	 * scrollbars but we do not need to handle the changed value.
296 	 */
297 	if(inView)
298 	{
299 		priv->activeView=g_object_ref(inView);
300 
301 		g_signal_emit(self, XfdashboardViewpadSignals[SIGNAL_VIEW_ACTIVATING], 0, priv->activeView);
302 		g_signal_emit_by_name(priv->activeView, "activating");
303 
304 		g_signal_handlers_block_by_func(priv->hScrollbar, _xfdashboard_viewpad_on_scrollbar_value_changed, self);
305 		g_signal_handlers_block_by_func(priv->vScrollbar, _xfdashboard_viewpad_on_scrollbar_value_changed, self);
306 
307 		x=y=0.0f;
308 		clutter_actor_get_clip(CLUTTER_ACTOR(priv->activeView), &x, &y, NULL, NULL);
309 		_xfdashboard_viewpad_update_scrollbars(self);
310 		xfdashboard_scrollbar_set_value(XFDASHBOARD_SCROLLBAR(priv->hScrollbar), x);
311 		xfdashboard_scrollbar_set_value(XFDASHBOARD_SCROLLBAR(priv->vScrollbar), y);
312 		_xfdashboard_viewpad_update_view_viewport(self);
313 		clutter_actor_show(CLUTTER_ACTOR(priv->activeView));
314 		XFDASHBOARD_DEBUG(self, ACTOR,
315 							"Activated view %s",
316 							G_OBJECT_TYPE_NAME(priv->activeView));
317 
318 		g_signal_handlers_unblock_by_func(priv->hScrollbar, _xfdashboard_viewpad_on_scrollbar_value_changed, self);
319 		g_signal_handlers_unblock_by_func(priv->vScrollbar, _xfdashboard_viewpad_on_scrollbar_value_changed, self);
320 
321 		g_signal_emit_by_name(priv->activeView, "activated");
322 		g_signal_emit(self, XfdashboardViewpadSignals[SIGNAL_VIEW_ACTIVATED], 0, priv->activeView);
323 
324 		/* Set focus to new active view if this viewpad has the focus */
325 		if(hasFocus)
326 		{
327 			xfdashboard_focus_manager_set_focus(focusManager, XFDASHBOARD_FOCUSABLE(priv->activeView));
328 			XFDASHBOARD_DEBUG(self, ACTOR,
329 								"The previous active view at viewpad had focus so set focus to new active view '%s'",
330 								xfdashboard_view_get_name(priv->activeView));
331 		}
332 	}
333 
334 	/* If no view is active at this time move focus to next focusable actor
335 	 * if this viewpad has the focus.
336 	 */
337 	if(hasFocus && !priv->activeView)
338 	{
339 		XfdashboardFocusable	*newFocusable;
340 
341 		newFocusable=xfdashboard_focus_manager_get_next_focusable(focusManager, XFDASHBOARD_FOCUSABLE(self));
342 		if(newFocusable)
343 		{
344 			xfdashboard_focus_manager_set_focus(focusManager, newFocusable);
345 			XFDASHBOARD_DEBUG(self, ACTOR,
346 								"Viewpad has focus but no view is active so move focus to next focusable actor of type '%s'",
347 								G_OBJECT_TYPE_NAME(newFocusable));
348 		}
349 	}
350 
351 	/* Release allocated resources */
352 	if(focusManager) g_object_unref(focusManager);
353 
354 	/* Notify about property change */
355 	g_object_notify_by_pspec(G_OBJECT(self), XfdashboardViewpadProperties[PROP_ACTIVE_VIEW]);
356 }
357 
358 /* A view was disabled */
_xfdashboard_viewpad_on_view_disabled(XfdashboardViewpad * self,XfdashboardView * inView)359 static void _xfdashboard_viewpad_on_view_disabled(XfdashboardViewpad *self, XfdashboardView *inView)
360 {
361 	XfdashboardViewpadPrivate	*priv;
362 	ClutterActorIter			iter;
363 	ClutterActor				*child;
364 	XfdashboardView				*firstActivatableView;
365 
366 	g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self));
367 	g_return_if_fail(XFDASHBOARD_IS_VIEW(inView));
368 
369 	priv=self->priv;
370 	firstActivatableView=NULL;
371 
372 	/* If the currently disabled view is the active one, activate a next available view */
373 	if(inView==priv->activeView)
374 	{
375 		/* Iterate through create views and lookup view of given type */
376 		clutter_actor_iter_init(&iter, CLUTTER_ACTOR(self));
377 		while(clutter_actor_iter_next(&iter, &child))
378 		{
379 			/* Check if child is a view otherwise continue iterating */
380 			if(XFDASHBOARD_IS_VIEW(child)!=TRUE) continue;
381 
382 			/* If child is not the view being disabled check if it could
383 			 * become the next activatable view
384 			 * the first activatable view after we destroyed all views found.
385 			 */
386 			if(XFDASHBOARD_VIEW(child)!=inView &&
387 				xfdashboard_view_get_enabled(XFDASHBOARD_VIEW(child)))
388 			{
389 				firstActivatableView=XFDASHBOARD_VIEW(child);
390 			}
391 		}
392 
393 		/* Now activate the first activatable view we found during iteration.
394 		 * It can also be no view (NULL pointer).
395 		 */
396 		XFDASHBOARD_DEBUG(self, ACTOR,
397 							"Disabled view %s was the active view in %s - will activate %s",
398 							G_OBJECT_TYPE_NAME(inView),
399 							G_OBJECT_TYPE_NAME(self),
400 							firstActivatableView ? G_OBJECT_TYPE_NAME(firstActivatableView) : "no other view");
401 		_xfdashboard_viewpad_activate_view(self, firstActivatableView);
402 	}
403 }
404 
405 /* A view was enabled */
_xfdashboard_viewpad_on_view_enabled(XfdashboardViewpad * self,XfdashboardView * inView)406 static void _xfdashboard_viewpad_on_view_enabled(XfdashboardViewpad *self, XfdashboardView *inView)
407 {
408 	XfdashboardViewpadPrivate	*priv;
409 
410 	g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self));
411 	g_return_if_fail(XFDASHBOARD_IS_VIEW(inView));
412 
413 	priv=self->priv;
414 
415 	/* If no view is active this new enabled view will be activated  */
416 	if(!priv->activeView) _xfdashboard_viewpad_activate_view(self, inView);
417 }
418 
419 /* Allocation of a view changed */
_xfdashboard_viewpad_on_allocation_changed_repaint_callback(gpointer inUserData)420 static gboolean _xfdashboard_viewpad_on_allocation_changed_repaint_callback(gpointer inUserData)
421 {
422 	XfdashboardViewpad			*self;
423 	XfdashboardViewpadPrivate	*priv;
424 
425 	g_return_val_if_fail(XFDASHBOARD_IS_VIEWPAD(inUserData), G_SOURCE_REMOVE);
426 
427 	self=XFDASHBOARD_VIEWPAD(inUserData);
428 	priv=self->priv;
429 
430 	/* Update scrollbars */
431 	_xfdashboard_viewpad_update_scrollbars(self);
432 
433 	/* Ensure view is visible */
434 	_xfdashboard_viewpad_on_scrollbar_value_changed(self,
435 													xfdashboard_scrollbar_get_value(XFDASHBOARD_SCROLLBAR(priv->hScrollbar)),
436 													priv->hScrollbar);
437 	_xfdashboard_viewpad_on_scrollbar_value_changed(self,
438 													xfdashboard_scrollbar_get_value(XFDASHBOARD_SCROLLBAR(priv->vScrollbar)),
439 													priv->vScrollbar);
440 
441 	/* Do not call this callback again */
442 	priv->scrollbarUpdateID=0;
443 	return(G_SOURCE_REMOVE);
444 }
445 
_xfdashboard_viewpad_on_allocation_changed(ClutterActor * inActor,ClutterActorBox * inBox,ClutterAllocationFlags inFlags,gpointer inUserData)446 static void _xfdashboard_viewpad_on_allocation_changed(ClutterActor *inActor,
447 														ClutterActorBox *inBox,
448 														ClutterAllocationFlags inFlags,
449 														gpointer inUserData)
450 {
451 	XfdashboardViewpad			*self;
452 	XfdashboardViewpadPrivate	*priv;
453 	XfdashboardView				*view G_GNUC_UNUSED;
454 
455 	g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(inActor));
456 	g_return_if_fail(XFDASHBOARD_IS_VIEW(inUserData));
457 
458 	self=XFDASHBOARD_VIEWPAD(inActor);
459 	priv=self->priv;
460 	view=XFDASHBOARD_VIEW(inUserData);
461 
462 	/* Defer updating scrollbars but only if view whose allocation
463 	 * has changed is the active one
464 	 */
465 	if(priv->scrollbarUpdateID==0)
466 	{
467 		priv->scrollbarUpdateID=
468 			clutter_threads_add_repaint_func_full(CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD | CLUTTER_REPAINT_FLAGS_POST_PAINT,
469 													_xfdashboard_viewpad_on_allocation_changed_repaint_callback,
470 													self,
471 													NULL);
472 	}
473 }
474 
475 /* Scroll to requested position in view */
_xfdashboard_viewpad_on_view_scroll_to(XfdashboardViewpad * self,gfloat inX,gfloat inY,gpointer inUserData)476 static void _xfdashboard_viewpad_on_view_scroll_to(XfdashboardViewpad *self,
477 													gfloat inX,
478 													gfloat inY,
479 													gpointer inUserData)
480 {
481 	XfdashboardViewpadPrivate	*priv;
482 	XfdashboardView				*view;
483 	gfloat						x, y, w, h;
484 
485 	g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self));
486 	g_return_if_fail(XFDASHBOARD_IS_VIEW(inUserData));
487 
488 	priv=self->priv;
489 	view=XFDASHBOARD_VIEW(inUserData);
490 
491 	/* If to-scroll view is the active view in viewpad
492 	 * just set scrollbar value to the new ones
493 	 */
494 	if(view==priv->activeView)
495 	{
496 		if(inX>=0.0f) xfdashboard_scrollbar_set_value(XFDASHBOARD_SCROLLBAR(priv->hScrollbar), inX);
497 		if(inY>=0.0f) xfdashboard_scrollbar_set_value(XFDASHBOARD_SCROLLBAR(priv->vScrollbar), inY);
498 	}
499 		/* If to-scroll view is not the active one update its clipping */
500 		else
501 		{
502 			if(clutter_actor_has_clip(CLUTTER_ACTOR(view)))
503 			{
504 				clutter_actor_get_clip(CLUTTER_ACTOR(view), &x, &y, &w, &h);
505 				if(inX>=0.0f) x=inX;
506 				if(inY>=0.0f) y=inY;
507 			}
508 				else
509 				{
510 					x=y=0.0f;
511 					clutter_actor_get_size(CLUTTER_ACTOR(view), &w, &h);
512 				}
513 			clutter_actor_set_clip(CLUTTER_ACTOR(view), x, y, w, h);
514 		}
515 }
516 
517 /* Determine if scrolling is needed to get requested actor visible in viewpad and
518  * return the distance in x and y direction if scrolling is needed.
519  */
_xfdashboard_viewpad_view_needs_scrolling_for_child(XfdashboardViewpad * self,XfdashboardView * inView,ClutterActor * inViewChild,gfloat * outScrollX,gfloat * outScrollY)520 static gboolean _xfdashboard_viewpad_view_needs_scrolling_for_child(XfdashboardViewpad *self,
521 																	XfdashboardView *inView,
522 																	ClutterActor *inViewChild,
523 																	gfloat *outScrollX,
524 																	gfloat *outScrollY)
525 {
526 	XfdashboardViewpadPrivate	*priv;
527 	ClutterVertex				origin;
528 	ClutterVertex				transformedUpperLeft;
529 	ClutterVertex				transformedLowerRight;
530 	gfloat						x, y, w, h;
531 	gboolean					viewFitsIntoViewpad;
532 	gboolean					needScrolling;
533 	gfloat						scrollX, scrollY;
534 	gfloat						viewpadWidth, viewpadHeight;
535 
536 	g_return_val_if_fail(XFDASHBOARD_IS_VIEWPAD(self), FALSE);
537 	g_return_val_if_fail(XFDASHBOARD_IS_VIEW(inView), FALSE);
538 	g_return_val_if_fail(CLUTTER_IS_ACTOR(inViewChild), FALSE);
539 
540 	priv=self->priv;
541 	viewFitsIntoViewpad=FALSE;
542 	needScrolling=FALSE;
543 	scrollX=scrollY=0.0f;
544 
545 	/* Check if view would fit into this viewpad completely */
546 	if(priv->lastAllocation)
547 	{
548 		viewpadWidth=clutter_actor_box_get_width(priv->lastAllocation);
549 		viewpadHeight=clutter_actor_box_get_height(priv->lastAllocation);
550 
551 		clutter_actor_get_size(CLUTTER_ACTOR(inView), &w, &h);
552 		if(w<=viewpadWidth && h<=viewpadHeight) viewFitsIntoViewpad=TRUE;
553 	}
554 		else
555 		{
556 			clutter_actor_get_size(CLUTTER_ACTOR(self), &viewpadWidth, &viewpadHeight);
557 		}
558 
559 	/* Get position and size of view but respect scrolled position */
560 	if(inView==priv->activeView)
561 	{
562 		x=xfdashboard_scrollbar_get_value(XFDASHBOARD_SCROLLBAR(priv->hScrollbar));
563 		y=xfdashboard_scrollbar_get_value(XFDASHBOARD_SCROLLBAR(priv->vScrollbar));
564 		w=viewpadWidth;
565 		h=viewpadHeight;
566 	}
567 		else
568 		{
569 			if(clutter_actor_has_clip(CLUTTER_ACTOR(inView)))
570 			{
571 				clutter_actor_get_clip(CLUTTER_ACTOR(inView), &x, &y, &w, &h);
572 			}
573 				else
574 				{
575 					x=y=0.0f;
576 					clutter_actor_get_size(CLUTTER_ACTOR(inView), &w, &h);
577 				}
578 		}
579 
580 	/* Check that upper left point of actor is visible otherwise set flag for scrolling */
581 	if(!viewFitsIntoViewpad)
582 	{
583 		origin.x=origin.y=origin.z=0.0f;
584 		clutter_actor_apply_relative_transform_to_point(inViewChild, CLUTTER_ACTOR(inView), &origin, &transformedUpperLeft);
585 	}
586 		else
587 		{
588 			origin.x=origin.y=origin.z=0.0f;
589 			clutter_actor_apply_relative_transform_to_point(CLUTTER_ACTOR(inView), CLUTTER_ACTOR(self), &origin, &transformedUpperLeft);
590 		}
591 
592 	if(transformedUpperLeft.x<x ||
593 		transformedUpperLeft.x>(x+w) ||
594 		transformedUpperLeft.y<y ||
595 		transformedUpperLeft.y>(y+h))
596 	{
597 		needScrolling=TRUE;
598 	}
599 
600 	/* Check that lower right point of actor is visible otherwise set flag for scrolling */
601 	if(!viewFitsIntoViewpad)
602 	{
603 		origin.z=0.0f;
604 		clutter_actor_get_size(inViewChild, &origin.x, &origin.y);
605 		clutter_actor_apply_relative_transform_to_point(inViewChild, CLUTTER_ACTOR(inView), &origin, &transformedLowerRight);
606 	}
607 		else
608 		{
609 			origin.x=clutter_actor_box_get_width(priv->lastAllocation);
610 			origin.y=clutter_actor_box_get_height(priv->lastAllocation);
611 			origin.z=0.0f;
612 			clutter_actor_apply_relative_transform_to_point(CLUTTER_ACTOR(inView), CLUTTER_ACTOR(self), &origin, &transformedLowerRight);
613 		}
614 
615 	if(transformedLowerRight.x<x ||
616 		transformedLowerRight.x>(x+w) ||
617 		transformedLowerRight.y<y ||
618 		transformedLowerRight.y>(y+h))
619 	{
620 		needScrolling=TRUE;
621 	}
622 
623 	/* Check if we need to scroll */
624 	if(needScrolling)
625 	{
626 		gfloat					distanceUpperLeft;
627 		gfloat					distanceLowerRight;
628 
629 		/* Find shortest way to scroll and then scroll */
630 		distanceUpperLeft=sqrtf(powf(transformedUpperLeft.x-x, 2.0f)+powf(transformedUpperLeft.y-y, 2.0f));
631 		distanceLowerRight=sqrtf(powf(transformedLowerRight.x-(x+w), 2.0f)+powf(transformedLowerRight.y-(y+h), 2.0f));
632 
633 		if(distanceUpperLeft<=distanceLowerRight)
634 		{
635 			scrollX=transformedUpperLeft.x;
636 			scrollY=transformedUpperLeft.y;
637 		}
638 			else
639 			{
640 				scrollX=transformedUpperLeft.x;
641 				scrollY=transformedLowerRight.y-h;
642 			}
643 	}
644 
645 	/* Store values computed */
646 	if(outScrollX) *outScrollX=scrollX;
647 	if(outScrollY) *outScrollY=scrollY;
648 
649 	/* Return TRUE if scrolling is needed otherwise FALSE */
650 	return(needScrolling);
651 }
652 
653 /* Determine if scrolling is needed to get requested actor visible in viewpad */
_xfdashboard_viewpad_on_view_child_needs_scroll(XfdashboardViewpad * self,ClutterActor * inActor,gpointer inUserData)654 static gboolean _xfdashboard_viewpad_on_view_child_needs_scroll(XfdashboardViewpad *self,
655 																ClutterActor *inActor,
656 																gpointer inUserData)
657 {
658 	XfdashboardView				*view;
659 
660 	g_return_val_if_fail(XFDASHBOARD_IS_VIEWPAD(self), FALSE);
661 	g_return_val_if_fail(CLUTTER_IS_ACTOR(inActor), FALSE);
662 	g_return_val_if_fail(XFDASHBOARD_IS_VIEW(inUserData), FALSE);
663 
664 	view=XFDASHBOARD_VIEW(inUserData);
665 
666 	/* Determine if scrolling is needed and return result */
667 	return(_xfdashboard_viewpad_view_needs_scrolling_for_child(self, view, inActor, NULL, NULL));
668 }
669 
670 /* Ensure that a child of a view is visible by scrolling if needed */
_xfdashboard_viewpad_on_view_child_ensure_visible(XfdashboardViewpad * self,ClutterActor * inActor,gpointer inUserData)671 static void _xfdashboard_viewpad_on_view_child_ensure_visible(XfdashboardViewpad *self,
672 														ClutterActor *inActor,
673 														gpointer inUserData)
674 {
675 	XfdashboardView				*view;
676 	gfloat						scrollX, scrollY;
677 
678 	g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self));
679 	g_return_if_fail(CLUTTER_IS_ACTOR(inActor));
680 	g_return_if_fail(XFDASHBOARD_IS_VIEW(inUserData));
681 
682 	view=XFDASHBOARD_VIEW(inUserData);
683 
684 	/* Check if scrolling is needed to scroll in direction and amount determined */
685 	if(_xfdashboard_viewpad_view_needs_scrolling_for_child(self, view, inActor, &scrollX, &scrollY))
686 	{
687 		_xfdashboard_viewpad_on_view_scroll_to(self, scrollX, scrollY, view);
688 	}
689 }
690 
691 /* Create view of given type and add to this actor */
_xfdashboard_viewpad_add_view(XfdashboardViewpad * self,const gchar * inID)692 static void _xfdashboard_viewpad_add_view(XfdashboardViewpad *self, const gchar *inID)
693 {
694 	XfdashboardViewpadPrivate	*priv;
695 	GObject						*view;
696 
697 	g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self));
698 	g_return_if_fail(inID && *inID);
699 
700 	priv=self->priv;
701 
702 	/* Create instance and check if it is a view */
703 	XFDASHBOARD_DEBUG(self, ACTOR,
704 						"Creating view %s for viewpad",
705 						inID);
706 
707 	view=xfdashboard_view_manager_create_view(priv->viewManager, inID);
708 	if(view==NULL)
709 	{
710 		g_critical("Failed to create view %s for viewpad", inID);
711 		return;
712 	}
713 
714 	if(XFDASHBOARD_IS_VIEW(view)!=TRUE)
715 	{
716 		g_critical("View %s of type %s is not a %s and cannot be added to %s",
717 					inID,
718 					G_OBJECT_TYPE_NAME(view),
719 					g_type_name(XFDASHBOARD_TYPE_VIEW),
720 					G_OBJECT_TYPE_NAME(self));
721 		return;
722 	}
723 
724 	/* Add new view instance to this actor but hidden */
725 	clutter_actor_hide(CLUTTER_ACTOR(view));
726 	clutter_actor_add_child(CLUTTER_ACTOR(self), CLUTTER_ACTOR(view));
727 	g_signal_connect_swapped(view, "allocation-changed", G_CALLBACK(_xfdashboard_viewpad_on_allocation_changed), self);
728 	g_signal_connect_swapped(view, "scroll-to", G_CALLBACK(_xfdashboard_viewpad_on_view_scroll_to), self);
729 	g_signal_connect_swapped(view, "child-needs-scroll", G_CALLBACK(_xfdashboard_viewpad_on_view_child_needs_scroll), self);
730 	g_signal_connect_swapped(view, "child-ensure-visible", G_CALLBACK(_xfdashboard_viewpad_on_view_child_ensure_visible), self);
731 	g_signal_connect_swapped(view, "disabled", G_CALLBACK(_xfdashboard_viewpad_on_view_disabled), self);
732 	g_signal_connect_swapped(view, "enabled", G_CALLBACK(_xfdashboard_viewpad_on_view_enabled), self);
733 	g_signal_emit(self, XfdashboardViewpadSignals[SIGNAL_VIEW_ADDED], 0, view);
734 
735 	/* Set active view if none active (usually it is the first view created) */
736 	if(priv->activeView==NULL &&
737 		xfdashboard_view_get_enabled(XFDASHBOARD_VIEW(view)))
738 	{
739 		_xfdashboard_viewpad_activate_view(self, XFDASHBOARD_VIEW(view));
740 	}
741 
742 	/* If newly added view is focusable register it to focus manager */
743 	if(priv->doRegisterFocusableViews &&
744 		XFDASHBOARD_IS_FOCUSABLE(view))
745 	{
746 		XfdashboardFocusManager	*focusManager;
747 
748 		focusManager=xfdashboard_focus_manager_get_default();
749 		xfdashboard_focus_manager_register_after(focusManager,
750 													XFDASHBOARD_FOCUSABLE(view),
751 													XFDASHBOARD_FOCUSABLE(self));
752 		g_object_unref(focusManager);
753 	}
754 }
755 
756 /* Called when a new view type was registered */
_xfdashboard_viewpad_on_view_registered(XfdashboardViewpad * self,const gchar * inID,gpointer inUserData)757 static void _xfdashboard_viewpad_on_view_registered(XfdashboardViewpad *self,
758 													const gchar *inID,
759 													gpointer inUserData)
760 {
761 	g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self));
762 	g_return_if_fail(inID && *inID);
763 
764 	_xfdashboard_viewpad_add_view(self, inID);
765 }
766 
767 /* Called when a view type was unregistered */
_xfdashboard_viewpad_on_view_unregistered(XfdashboardViewpad * self,const gchar * inID,gpointer inUserData)768 static void _xfdashboard_viewpad_on_view_unregistered(XfdashboardViewpad *self,
769 														const gchar *inID,
770 														gpointer inUserData)
771 {
772 	XfdashboardViewpadPrivate	*priv;
773 	ClutterActorIter			iter;
774 	ClutterActor				*child;
775 	ClutterActor				*firstActivatableView;
776 
777 	g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self));
778 	g_return_if_fail(inID && *inID);
779 
780 	priv=self->priv;
781 	firstActivatableView=NULL;
782 
783 	/* Iterate through create views and lookup view of given type */
784 	clutter_actor_iter_init(&iter, CLUTTER_ACTOR(self));
785 	while(clutter_actor_iter_next(&iter, &child))
786 	{
787 		/* Check if child is a view otherwise continue iterating */
788 		if(XFDASHBOARD_IS_VIEW(child)!=TRUE) continue;
789 
790 		/* If this child is not the one being unregistered and is not
791 		 * disabled then it will get the first activatable view after
792 		 * we destroyed all views found.
793 		 */
794 		if(!xfdashboard_view_has_id(XFDASHBOARD_VIEW(child), inID))
795 		{
796 			if(xfdashboard_view_get_enabled(XFDASHBOARD_VIEW(child))) firstActivatableView=child;
797 		}
798 			else
799 			{
800 				if(G_OBJECT(child)==G_OBJECT(priv->activeView)) _xfdashboard_viewpad_activate_view(self, NULL);
801 				g_signal_emit(self, XfdashboardViewpadSignals[SIGNAL_VIEW_REMOVED], 0, child);
802 				clutter_actor_destroy(child);
803 			}
804 	}
805 
806 	/* Now activate the first activatable view we found during iteration */
807 	if(firstActivatableView) _xfdashboard_viewpad_activate_view(self, XFDASHBOARD_VIEW(firstActivatableView));
808 }
809 
810 /* Scroll event happened at this actor because it was not handled
811  * with any child actor
812  */
_xfdashboard_viewpad_on_scroll_event(ClutterActor * inActor,ClutterEvent * inEvent,gpointer inUserData)813 static gboolean _xfdashboard_viewpad_on_scroll_event(ClutterActor *inActor,
814 														ClutterEvent *inEvent,
815 														gpointer inUserData)
816 {
817 	XfdashboardViewpad				*self;
818 	XfdashboardViewpadPrivate		*priv;
819 	gboolean						result;
820 
821 	g_return_val_if_fail(XFDASHBOARD_IS_VIEWPAD(inActor), FALSE);
822 	g_return_val_if_fail(inEvent, FALSE);
823 
824 	self=XFDASHBOARD_VIEWPAD(inActor);
825 	priv=self->priv;
826 	result=CLUTTER_EVENT_PROPAGATE;
827 
828 	/* If vertical scroll bar is visible emit scroll event there */
829 	if(priv->vScrollbarVisible)
830 	{
831 		result=clutter_actor_event(priv->vScrollbar, inEvent, FALSE);
832 	}
833 		/* Otherwise try horizontal scroll bar if visible */
834 		else if(priv->hScrollbarVisible)
835 		{
836 			result=clutter_actor_event(priv->hScrollbar, inEvent, FALSE);
837 		}
838 
839 	return(result);
840 }
841 
842 /* IMPLEMENTATION: ClutterActor */
843 
844 /* Show this actor and the current active view */
_xfdashboard_viewpad_show(ClutterActor * self)845 static void _xfdashboard_viewpad_show(ClutterActor *self)
846 {
847 	XfdashboardViewpadPrivate	*priv=XFDASHBOARD_VIEWPAD(self)->priv;
848 	ClutterActorClass			*actorClass=CLUTTER_ACTOR_CLASS(xfdashboard_viewpad_parent_class);
849 
850 	/* Only show active view again */
851 	if(priv->activeView) clutter_actor_show(CLUTTER_ACTOR(priv->activeView));
852 
853 	/* Call parent's class show method */
854 	if(actorClass->show) actorClass->show(self);
855 }
856 
857 /* Get preferred width/height */
_xfdashboard_viewpad_get_preferred_height(ClutterActor * self,gfloat inForWidth,gfloat * outMinHeight,gfloat * outNaturalHeight)858 static void _xfdashboard_viewpad_get_preferred_height(ClutterActor *self,
859 														gfloat inForWidth,
860 														gfloat *outMinHeight,
861 														gfloat *outNaturalHeight)
862 {
863 	gfloat							minHeight, naturalHeight;
864 
865 	/* Do not set any minimum or natural sizes. The parent actor is responsible
866 	 * to set this actor's sizes as viewport.
867 	 */
868 	minHeight=naturalHeight=0.0f;
869 
870 	/* Store sizes computed */
871 	if(outMinHeight) *outMinHeight=minHeight;
872 	if(outNaturalHeight) *outNaturalHeight=naturalHeight;
873 }
874 
_xfdashboard_viewpad_get_preferred_width(ClutterActor * self,gfloat inForHeight,gfloat * outMinWidth,gfloat * outNaturalWidth)875 static void _xfdashboard_viewpad_get_preferred_width(ClutterActor *self,
876 														gfloat inForHeight,
877 														gfloat *outMinWidth,
878 														gfloat *outNaturalWidth)
879 {
880 	gfloat							minWidth, naturalWidth;
881 
882 	/* Do not set any minimum or natural sizes. The parent actor is responsible
883 	 * to set this actor's sizes as viewport.
884 	 */
885 	minWidth=naturalWidth=0.0f;
886 
887 	/* Store sizes computed */
888 	if(outMinWidth) *outMinWidth=minWidth;
889 	if(outNaturalWidth) *outNaturalWidth=naturalWidth;
890 }
891 
892 /* Allocate position and size of actor and its children */
_xfdashboard_viewpad_allocate(ClutterActor * self,const ClutterActorBox * inBox,ClutterAllocationFlags inFlags)893 static void _xfdashboard_viewpad_allocate(ClutterActor *self,
894 											const ClutterActorBox *inBox,
895 											ClutterAllocationFlags inFlags)
896 {
897 	XfdashboardViewpadPrivate	*priv=XFDASHBOARD_VIEWPAD(self)->priv;
898 	ClutterActorClass			*actorClass=CLUTTER_ACTOR_CLASS(xfdashboard_viewpad_parent_class);
899 	gfloat						viewWidth, viewHeight;
900 	gfloat						vScrollbarWidth, vScrollbarHeight;
901 	gfloat						hScrollbarWidth, hScrollbarHeight;
902 	gboolean					hScrollbarVisible, vScrollbarVisible;
903 	ClutterActorBox				*box;
904 	gfloat						x, y, w, h;
905 
906 	/* Chain up to store the allocation of the actor */
907 	if(actorClass->allocate) actorClass->allocate(self, inBox, inFlags);
908 
909 	/* Initialize largest possible allocation for view and determine
910 	 * real size of view to show. The real size is used to determine
911 	 * scroll bar visibility if policy is automatic */
912 	viewWidth=clutter_actor_box_get_width(inBox);
913 	viewHeight=clutter_actor_box_get_height(inBox);
914 
915 	/* Determine visibility of scroll bars */
916 	hScrollbarVisible=FALSE;
917 	if(priv->hScrollbarPolicy==XFDASHBOARD_VISIBILITY_POLICY_ALWAYS ||
918 		(priv->hScrollbarPolicy==XFDASHBOARD_VISIBILITY_POLICY_AUTOMATIC &&
919 			xfdashboard_scrollbar_get_range(XFDASHBOARD_SCROLLBAR(priv->hScrollbar))>viewWidth))
920 	{
921 		hScrollbarVisible=TRUE;
922 	}
923 	if(xfdashboard_view_get_view_fit_mode(XFDASHBOARD_VIEW(priv->activeView))==XFDASHBOARD_VIEW_FIT_MODE_HORIZONTAL ||
924 		xfdashboard_view_get_view_fit_mode(XFDASHBOARD_VIEW(priv->activeView))==XFDASHBOARD_VIEW_FIT_MODE_BOTH)
925 	{
926 		hScrollbarVisible=FALSE;
927 	}
928 
929 	vScrollbarVisible=FALSE;
930 	if(priv->vScrollbarPolicy==XFDASHBOARD_VISIBILITY_POLICY_ALWAYS ||
931 		(priv->vScrollbarPolicy==XFDASHBOARD_VISIBILITY_POLICY_AUTOMATIC &&
932 			xfdashboard_scrollbar_get_range(XFDASHBOARD_SCROLLBAR(priv->vScrollbar))>viewHeight))
933 	{
934 		vScrollbarVisible=TRUE;
935 	}
936 	if(xfdashboard_view_get_view_fit_mode(XFDASHBOARD_VIEW(priv->activeView))==XFDASHBOARD_VIEW_FIT_MODE_VERTICAL ||
937 		xfdashboard_view_get_view_fit_mode(XFDASHBOARD_VIEW(priv->activeView))==XFDASHBOARD_VIEW_FIT_MODE_BOTH)
938 	{
939 		vScrollbarVisible=FALSE;
940 	}
941 
942 	/* Set allocation for visible scroll bars */
943 	vScrollbarWidth=0.0f;
944 	vScrollbarHeight=viewHeight;
945 	clutter_actor_get_preferred_width(priv->vScrollbar, -1, NULL, &vScrollbarWidth);
946 
947 	hScrollbarWidth=viewWidth;
948 	hScrollbarHeight=0.0f;
949 	clutter_actor_get_preferred_height(priv->hScrollbar, -1, NULL, &hScrollbarHeight);
950 
951 	if(hScrollbarVisible && vScrollbarVisible)
952 	{
953 		vScrollbarHeight-=hScrollbarHeight;
954 		hScrollbarWidth-=vScrollbarWidth;
955 	}
956 
957 	if(vScrollbarVisible==FALSE) box=clutter_actor_box_new(0, 0, 0, 0);
958 		else box=clutter_actor_box_new(viewWidth-vScrollbarWidth, 0, viewWidth, vScrollbarHeight);
959 	clutter_actor_allocate(priv->vScrollbar, box, inFlags);
960 	clutter_actor_box_free(box);
961 
962 	if(hScrollbarVisible==FALSE) box=clutter_actor_box_new(0, 0, 0, 0);
963 		else box=clutter_actor_box_new(0, viewHeight-hScrollbarHeight, hScrollbarWidth, viewHeight);
964 	clutter_actor_allocate(priv->hScrollbar, box, inFlags);
965 	clutter_actor_box_free(box);
966 
967 	/* Reduce allocation for view by any visible scroll bar
968 	 * and set allocation and clipping of view
969 	 */
970 	if(priv->activeView)
971 	{
972 		/* Set allocation */
973 		if(vScrollbarVisible) viewWidth-=vScrollbarWidth;
974 		if(hScrollbarVisible) viewHeight-=hScrollbarHeight;
975 
976 		x=y=0.0f;
977 		if(clutter_actor_has_clip(CLUTTER_ACTOR(priv->activeView)))
978 		{
979 			clutter_actor_get_clip(CLUTTER_ACTOR(priv->activeView), &x, &y, NULL, NULL);
980 		}
981 
982 		switch(xfdashboard_view_get_view_fit_mode(XFDASHBOARD_VIEW(priv->activeView)))
983 		{
984 			case XFDASHBOARD_VIEW_FIT_MODE_BOTH:
985 				w=viewWidth;
986 				h=viewHeight;
987 				break;
988 
989 			case XFDASHBOARD_VIEW_FIT_MODE_HORIZONTAL:
990 				w=viewWidth;
991 				clutter_actor_get_preferred_height(CLUTTER_ACTOR(priv->activeView), w, NULL, &h);
992 				break;
993 
994 			case XFDASHBOARD_VIEW_FIT_MODE_VERTICAL:
995 				h=viewHeight;
996 				clutter_actor_get_preferred_width(CLUTTER_ACTOR(priv->activeView), h, NULL, &w);
997 				break;
998 
999 			default:
1000 				clutter_actor_get_preferred_size(CLUTTER_ACTOR(priv->activeView), NULL, NULL, &w, &h);
1001 				break;
1002 		}
1003 
1004 		box=clutter_actor_box_new(0, 0, w, h);
1005 		clutter_actor_allocate(CLUTTER_ACTOR(priv->activeView), box, inFlags);
1006 		clutter_actor_box_free(box);
1007 
1008 		clutter_actor_set_clip(CLUTTER_ACTOR(priv->activeView), x, y, viewWidth, viewHeight);
1009 	}
1010 
1011 	/* Only set value if it changes */
1012 	if(priv->hScrollbarVisible!=hScrollbarVisible)
1013 	{
1014 		/* Set new value */
1015 		priv->hScrollbarVisible=hScrollbarVisible;
1016 
1017 		/* Notify about property change */
1018 		g_object_notify_by_pspec(G_OBJECT(self), XfdashboardViewpadProperties[PROP_HSCROLLBAR_VISIBLE]);
1019 	}
1020 
1021 	if(priv->vScrollbarVisible!=vScrollbarVisible)
1022 	{
1023 		/* Set new value */
1024 		priv->vScrollbarVisible=vScrollbarVisible;
1025 
1026 		/* Notify about property change */
1027 		g_object_notify_by_pspec(G_OBJECT(self), XfdashboardViewpadProperties[PROP_VSCROLLBAR_VISIBLE]);
1028 	}
1029 
1030 	/* Remember this allocation as last one set */
1031 	if(priv->lastAllocation)
1032 	{
1033 		clutter_actor_box_free(priv->lastAllocation);
1034 		priv->lastAllocation=NULL;
1035 	}
1036 
1037 	priv->lastAllocation=clutter_actor_box_copy(inBox);
1038 }
1039 
1040 /* IMPLEMENTATION: Interface XfdashboardFocusable */
1041 
1042 /* Determine if actor can get the focus */
_xfdashboard_viewpad_focusable_can_focus(XfdashboardFocusable * inFocusable)1043 static gboolean _xfdashboard_viewpad_focusable_can_focus(XfdashboardFocusable *inFocusable)
1044 {
1045 	XfdashboardViewpad			*self;
1046 	XfdashboardViewpadPrivate	*priv;
1047 
1048 	g_return_val_if_fail(XFDASHBOARD_IS_FOCUSABLE(inFocusable), FALSE);
1049 	g_return_val_if_fail(XFDASHBOARD_IS_VIEWPAD(inFocusable), FALSE);
1050 
1051 	self=XFDASHBOARD_VIEWPAD(inFocusable);
1052 	priv=self->priv;
1053 
1054 	/* If it is the first time this viewpad is checked if it is focusable register
1055 	 * all registered and focusable views at focus manager and set flag that newly
1056 	 * added views should be registered to focus manager also because now the insert
1057 	 * position at focus manager for this viewpad is known and we can keep the focus
1058 	 * order for the views.
1059 	 * We determine if this is the first time this viewpad is check for its focusability
1060 	 * by checking if the "do-register-view" flag is still not set.
1061 	 */
1062 	if(!priv->doRegisterFocusableViews)
1063 	{
1064 		XfdashboardFocusManager		*focusManager;
1065 		ClutterActorIter			iter;
1066 		ClutterActor				*child;
1067 
1068 		/* Get focus manager */
1069 		focusManager=xfdashboard_focus_manager_get_default();
1070 
1071 		/* Iterate through children of this viewpad and register each focusable view found */
1072 		clutter_actor_iter_init(&iter, CLUTTER_ACTOR(self));
1073 		while(clutter_actor_iter_next(&iter, &child))
1074 		{
1075 			/* Check if child is a view otherwise continue iterating */
1076 			if(XFDASHBOARD_IS_VIEW(child)!=TRUE) continue;
1077 
1078 			/* If view is focusable register it to focus manager */
1079 			if(XFDASHBOARD_IS_FOCUSABLE(child))
1080 			{
1081 				xfdashboard_focus_manager_register_after(focusManager,
1082 															XFDASHBOARD_FOCUSABLE(child),
1083 															XFDASHBOARD_FOCUSABLE(self));
1084 			}
1085 		}
1086 
1087 		/* Release allocated resources */
1088 		if(focusManager) g_object_unref(focusManager);
1089 
1090 		/* Set flag that from now on each newly added view should be added to focus manager */
1091 		priv->doRegisterFocusableViews=TRUE;
1092 	}
1093 
1094 	/* This viewpad cannot be focused. It is only registered at focus manager as
1095 	 * a placeholder to register focusable views just after this viewpad to keep
1096 	 * order of focusable actors.
1097 	 */
1098 	return(FALSE);
1099 }
1100 
1101 /* Interface initialization
1102  * Set up default functions
1103  */
_xfdashboard_viewpad_focusable_iface_init(XfdashboardFocusableInterface * iface)1104 void _xfdashboard_viewpad_focusable_iface_init(XfdashboardFocusableInterface *iface)
1105 {
1106 	iface->can_focus=_xfdashboard_viewpad_focusable_can_focus;
1107 }
1108 
1109 /* IMPLEMENTATION: GObject */
1110 
1111 /* Dispose this object */
_xfdashboard_viewpad_dispose(GObject * inObject)1112 static void _xfdashboard_viewpad_dispose(GObject *inObject)
1113 {
1114 	XfdashboardViewpad			*self=XFDASHBOARD_VIEWPAD(inObject);
1115 	XfdashboardViewpadPrivate	*priv=self->priv;
1116 
1117 	/* Prevent further registers of views */
1118 	priv->doRegisterFocusableViews=FALSE;
1119 
1120 	/* Deactivate current view */
1121 	if(priv->activeView) _xfdashboard_viewpad_activate_view(self, NULL);
1122 
1123 	/* Disconnect signals handlers */
1124 	if(priv->viewManager)
1125 	{
1126 		g_signal_handlers_disconnect_by_data(priv->viewManager, self);
1127 		g_object_unref(priv->viewManager);
1128 		priv->viewManager=NULL;
1129 	}
1130 
1131 	/* Release allocated resources */
1132 	if(priv->lastAllocation)
1133 	{
1134 		clutter_actor_box_free(priv->lastAllocation);
1135 		priv->lastAllocation=NULL;
1136 	}
1137 
1138 	/* Call parent's class dispose method */
1139 	G_OBJECT_CLASS(xfdashboard_viewpad_parent_class)->dispose(inObject);
1140 }
1141 
1142 /* Set/get properties */
_xfdashboard_viewpad_set_property(GObject * inObject,guint inPropID,const GValue * inValue,GParamSpec * inSpec)1143 static void _xfdashboard_viewpad_set_property(GObject *inObject,
1144 												guint inPropID,
1145 												const GValue *inValue,
1146 												GParamSpec *inSpec)
1147 {
1148 	XfdashboardViewpad		*self=XFDASHBOARD_VIEWPAD(inObject);
1149 
1150 	switch(inPropID)
1151 	{
1152 		case PROP_SPACING:
1153 			xfdashboard_viewpad_set_spacing(self, g_value_get_float(inValue));
1154 			break;
1155 
1156 		case PROP_HSCROLLBAR_POLICY:
1157 			xfdashboard_viewpad_set_horizontal_scrollbar_policy(self, (XfdashboardVisibilityPolicy)g_value_get_enum(inValue));
1158 			break;
1159 
1160 		case PROP_VSCROLLBAR_POLICY:
1161 			xfdashboard_viewpad_set_vertical_scrollbar_policy(self, (XfdashboardVisibilityPolicy)g_value_get_enum(inValue));
1162 			break;
1163 
1164 		default:
1165 			G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
1166 			break;
1167 	}
1168 }
1169 
_xfdashboard_viewpad_get_property(GObject * inObject,guint inPropID,GValue * outValue,GParamSpec * inSpec)1170 static void _xfdashboard_viewpad_get_property(GObject *inObject,
1171 												guint inPropID,
1172 												GValue *outValue,
1173 												GParamSpec *inSpec)
1174 {
1175 	XfdashboardViewpad		*self=XFDASHBOARD_VIEWPAD(inObject);
1176 
1177 	switch(inPropID)
1178 	{
1179 		case PROP_SPACING:
1180 			g_value_set_float(outValue, self->priv->spacing);
1181 			break;
1182 
1183 		case PROP_ACTIVE_VIEW:
1184 			g_value_set_object(outValue, self->priv->activeView);
1185 			break;
1186 
1187 		case PROP_HSCROLLBAR_POLICY:
1188 			g_value_set_enum(outValue, self->priv->hScrollbarPolicy);
1189 			break;
1190 
1191 		case PROP_HSCROLLBAR_VISIBLE:
1192 			g_value_set_boolean(outValue, self->priv->hScrollbarVisible);
1193 			break;
1194 
1195 		case PROP_VSCROLLBAR_POLICY:
1196 			g_value_set_enum(outValue, self->priv->vScrollbarPolicy);
1197 			break;
1198 
1199 		case PROP_VSCROLLBAR_VISIBLE:
1200 			g_value_set_boolean(outValue, self->priv->vScrollbarVisible);
1201 			break;
1202 
1203 		default:
1204 			G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
1205 			break;
1206 	}
1207 }
1208 
1209 /* Class initialization
1210  * Override functions in parent classes and define properties
1211  * and signals
1212  */
xfdashboard_viewpad_class_init(XfdashboardViewpadClass * klass)1213 static void xfdashboard_viewpad_class_init(XfdashboardViewpadClass *klass)
1214 {
1215 	XfdashboardActorClass	*actorClass=XFDASHBOARD_ACTOR_CLASS(klass);
1216 	ClutterActorClass		*clutterActorClass=CLUTTER_ACTOR_CLASS(klass);
1217 	GObjectClass			*gobjectClass=G_OBJECT_CLASS(klass);
1218 
1219 	/* Override functions */
1220 	gobjectClass->set_property=_xfdashboard_viewpad_set_property;
1221 	gobjectClass->get_property=_xfdashboard_viewpad_get_property;
1222 	gobjectClass->dispose=_xfdashboard_viewpad_dispose;
1223 
1224 	clutterActorClass->show=_xfdashboard_viewpad_show;
1225 	clutterActorClass->get_preferred_width=_xfdashboard_viewpad_get_preferred_width;
1226 	clutterActorClass->get_preferred_height=_xfdashboard_viewpad_get_preferred_height;
1227 	clutterActorClass->allocate=_xfdashboard_viewpad_allocate;
1228 
1229 	/* Define properties */
1230 	XfdashboardViewpadProperties[PROP_SPACING]=
1231 		g_param_spec_float("spacing",
1232 							"Spacing",
1233 							"The spacing between views and scrollbars",
1234 							0.0f, G_MAXFLOAT,
1235 							0.0f,
1236 							G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1237 
1238 	XfdashboardViewpadProperties[PROP_ACTIVE_VIEW]=
1239 		g_param_spec_object("active-view",
1240 								"Active view",
1241 								"The current active view in viewpad",
1242 								XFDASHBOARD_TYPE_VIEW,
1243 								G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
1244 
1245 	XfdashboardViewpadProperties[PROP_HSCROLLBAR_VISIBLE]=
1246 		g_param_spec_boolean("horizontal-scrollbar-visible",
1247 								"Horizontal scrollbar visibility",
1248 								"This flag indicates if horizontal scrollbar is visible",
1249 								FALSE,
1250 								G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
1251 
1252 	XfdashboardViewpadProperties[PROP_HSCROLLBAR_POLICY]=
1253 		g_param_spec_enum("horizontal-scrollbar-policy",
1254 							"Horizontal scrollbar policy",
1255 							"The policy for horizontal scrollbar controlling when it is displayed",
1256 							XFDASHBOARD_TYPE_VISIBILITY_POLICY,
1257 							XFDASHBOARD_VISIBILITY_POLICY_AUTOMATIC,
1258 							G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1259 
1260 	XfdashboardViewpadProperties[PROP_VSCROLLBAR_VISIBLE]=
1261 		g_param_spec_boolean("vertical-scrollbar-visible",
1262 								"Vertical scrollbar visibility",
1263 								"This flag indicates if vertical scrollbar is visible",
1264 								FALSE,
1265 								G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
1266 
1267 	XfdashboardViewpadProperties[PROP_VSCROLLBAR_POLICY]=
1268 		g_param_spec_enum("vertical-scrollbar-policy",
1269 							"Vertical scrollbar policy",
1270 							"The policy for vertical scrollbar controlling when it is displayed",
1271 							XFDASHBOARD_TYPE_VISIBILITY_POLICY,
1272 							XFDASHBOARD_VISIBILITY_POLICY_AUTOMATIC,
1273 							G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1274 
1275 	g_object_class_install_properties(gobjectClass, PROP_LAST, XfdashboardViewpadProperties);
1276 
1277 	/* Define stylable properties */
1278 	xfdashboard_actor_install_stylable_property(actorClass, XfdashboardViewpadProperties[PROP_SPACING]);
1279 	xfdashboard_actor_install_stylable_property(actorClass, XfdashboardViewpadProperties[PROP_HSCROLLBAR_POLICY]);
1280 	xfdashboard_actor_install_stylable_property(actorClass, XfdashboardViewpadProperties[PROP_VSCROLLBAR_POLICY]);
1281 
1282 	/* Define signals */
1283 	XfdashboardViewpadSignals[SIGNAL_VIEW_ADDED]=
1284 		g_signal_new("view-added",
1285 						G_TYPE_FROM_CLASS(klass),
1286 						G_SIGNAL_RUN_LAST,
1287 						G_STRUCT_OFFSET(XfdashboardViewpadClass, view_added),
1288 						NULL,
1289 						NULL,
1290 						g_cclosure_marshal_VOID__OBJECT,
1291 						G_TYPE_NONE,
1292 						1,
1293 						XFDASHBOARD_TYPE_VIEW);
1294 
1295 	XfdashboardViewpadSignals[SIGNAL_VIEW_REMOVED]=
1296 		g_signal_new("view-removed",
1297 						G_TYPE_FROM_CLASS(klass),
1298 						G_SIGNAL_RUN_LAST,
1299 						G_STRUCT_OFFSET(XfdashboardViewpadClass, view_removed),
1300 						NULL,
1301 						NULL,
1302 						g_cclosure_marshal_VOID__OBJECT,
1303 						G_TYPE_NONE,
1304 						1,
1305 						XFDASHBOARD_TYPE_VIEW);
1306 
1307 	XfdashboardViewpadSignals[SIGNAL_VIEW_ACTIVATING]=
1308 		g_signal_new("view-activating",
1309 						G_TYPE_FROM_CLASS(klass),
1310 						G_SIGNAL_RUN_LAST,
1311 						G_STRUCT_OFFSET(XfdashboardViewpadClass, view_activating),
1312 						NULL,
1313 						NULL,
1314 						g_cclosure_marshal_VOID__OBJECT,
1315 						G_TYPE_NONE,
1316 						1,
1317 						XFDASHBOARD_TYPE_VIEW);
1318 
1319 	XfdashboardViewpadSignals[SIGNAL_VIEW_ACTIVATED]=
1320 		g_signal_new("view-activated",
1321 						G_TYPE_FROM_CLASS(klass),
1322 						G_SIGNAL_RUN_LAST,
1323 						G_STRUCT_OFFSET(XfdashboardViewpadClass, view_activated),
1324 						NULL,
1325 						NULL,
1326 						g_cclosure_marshal_VOID__OBJECT,
1327 						G_TYPE_NONE,
1328 						1,
1329 						XFDASHBOARD_TYPE_VIEW);
1330 
1331 	XfdashboardViewpadSignals[SIGNAL_VIEW_DEACTIVATING]=
1332 		g_signal_new("view-deactivating",
1333 						G_TYPE_FROM_CLASS(klass),
1334 						G_SIGNAL_RUN_LAST,
1335 						G_STRUCT_OFFSET(XfdashboardViewpadClass, view_deactivating),
1336 						NULL,
1337 						NULL,
1338 						g_cclosure_marshal_VOID__OBJECT,
1339 						G_TYPE_NONE,
1340 						1,
1341 						XFDASHBOARD_TYPE_VIEW);
1342 
1343 	XfdashboardViewpadSignals[SIGNAL_VIEW_DEACTIVATED]=
1344 		g_signal_new("view-deactivated",
1345 						G_TYPE_FROM_CLASS(klass),
1346 						G_SIGNAL_RUN_LAST,
1347 						G_STRUCT_OFFSET(XfdashboardViewpadClass, view_deactivated),
1348 						NULL,
1349 						NULL,
1350 						g_cclosure_marshal_VOID__OBJECT,
1351 						G_TYPE_NONE,
1352 						1,
1353 						XFDASHBOARD_TYPE_VIEW);
1354 }
1355 
1356 /* Object initialization
1357  * Create private structure and set up default values
1358  */
xfdashboard_viewpad_init(XfdashboardViewpad * self)1359 static void xfdashboard_viewpad_init(XfdashboardViewpad *self)
1360 {
1361 	XfdashboardViewpadPrivate	*priv;
1362 	GList						*views, *viewEntry;
1363 
1364 	priv=self->priv=xfdashboard_viewpad_get_instance_private(self);
1365 
1366 	/* Set up default values */
1367 	priv->viewManager=xfdashboard_view_manager_get_default();
1368 	priv->activeView=NULL;
1369 	priv->spacing=0.0f;
1370 	priv->hScrollbarVisible=FALSE;
1371 	priv->hScrollbarPolicy=XFDASHBOARD_VISIBILITY_POLICY_AUTOMATIC;
1372 	priv->vScrollbarVisible=FALSE;
1373 	priv->vScrollbarPolicy=XFDASHBOARD_VISIBILITY_POLICY_AUTOMATIC;
1374 	priv->scrollbarUpdateID=0;
1375 	priv->doRegisterFocusableViews=FALSE;
1376 	priv->lastAllocation=NULL;
1377 
1378 	/* Set up this actor */
1379 	clutter_actor_set_reactive(CLUTTER_ACTOR(self), TRUE);
1380 	g_signal_connect(self, "scroll-event", G_CALLBACK(_xfdashboard_viewpad_on_scroll_event), NULL);
1381 
1382 	/* Set up child actors */
1383 	priv->hScrollbar=xfdashboard_scrollbar_new(CLUTTER_ORIENTATION_HORIZONTAL);
1384 	clutter_actor_add_child(CLUTTER_ACTOR(self), priv->hScrollbar);
1385 	g_signal_connect_swapped(priv->hScrollbar, "value-changed", G_CALLBACK(_xfdashboard_viewpad_on_scrollbar_value_changed), self);
1386 
1387 	priv->vScrollbar=xfdashboard_scrollbar_new(CLUTTER_ORIENTATION_VERTICAL);
1388 	clutter_actor_add_child(CLUTTER_ACTOR(self), priv->vScrollbar);
1389 	g_signal_connect_swapped(priv->vScrollbar, "value-changed", G_CALLBACK(_xfdashboard_viewpad_on_scrollbar_value_changed), self);
1390 
1391 	/* Create instance of each registered view type and add it to this actor
1392 	 * and connect signals
1393 	 */
1394 	views=viewEntry=xfdashboard_view_manager_get_registered(priv->viewManager);
1395 	for(; viewEntry; viewEntry=g_list_next(viewEntry))
1396 	{
1397 		const gchar				*viewID;
1398 
1399 		viewID=(const gchar*)viewEntry->data;
1400 		_xfdashboard_viewpad_add_view(self, viewID);
1401 	}
1402 	g_list_free_full(views, g_free);
1403 
1404 	g_signal_connect_swapped(priv->viewManager, "registered", G_CALLBACK(_xfdashboard_viewpad_on_view_registered), self);
1405 	g_signal_connect_swapped(priv->viewManager, "unregistered", G_CALLBACK(_xfdashboard_viewpad_on_view_unregistered), self);
1406 }
1407 
1408 /* IMPLEMENTATION: Public API */
1409 
1410 /* Create new instance */
xfdashboard_viewpad_new(void)1411 ClutterActor* xfdashboard_viewpad_new(void)
1412 {
1413 	return(CLUTTER_ACTOR(g_object_new(XFDASHBOARD_TYPE_VIEWPAD, NULL)));
1414 }
1415 
1416 /* Get/set spacing */
xfdashboard_viewpad_get_spacing(XfdashboardViewpad * self)1417 gfloat xfdashboard_viewpad_get_spacing(XfdashboardViewpad *self)
1418 {
1419 	g_return_val_if_fail(XFDASHBOARD_IS_VIEWPAD(self), 0.0f);
1420 
1421 	return(self->priv->spacing);
1422 }
1423 
xfdashboard_viewpad_set_spacing(XfdashboardViewpad * self,gfloat inSpacing)1424 void xfdashboard_viewpad_set_spacing(XfdashboardViewpad *self, gfloat inSpacing)
1425 {
1426 	XfdashboardViewpadPrivate	*priv;
1427 
1428 	g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self));
1429 	g_return_if_fail(inSpacing>=0.0f);
1430 
1431 	priv=self->priv;
1432 
1433 	/* Only set value if it changes */
1434 	if(inSpacing==priv->spacing) return;
1435 
1436 	/* Set new value */
1437 	priv->spacing=inSpacing;
1438 	if(priv->layout)
1439 	{
1440 		clutter_grid_layout_set_column_spacing(CLUTTER_GRID_LAYOUT(priv->layout), priv->spacing);
1441 		clutter_grid_layout_set_row_spacing(CLUTTER_GRID_LAYOUT(priv->layout), priv->spacing);
1442 	}
1443 	clutter_actor_queue_relayout(CLUTTER_ACTOR(self));
1444 
1445 	/* Notify about property change */
1446 	g_object_notify_by_pspec(G_OBJECT(self), XfdashboardViewpadProperties[PROP_SPACING]);
1447 }
1448 
1449 /* Get list of views */
xfdashboard_viewpad_get_views(XfdashboardViewpad * self)1450 GList* xfdashboard_viewpad_get_views(XfdashboardViewpad *self)
1451 {
1452 	ClutterActorIter			iter;
1453 	ClutterActor				*child;
1454 	GList						*list;
1455 
1456 	g_return_val_if_fail(XFDASHBOARD_IS_VIEWPAD(self), NULL);
1457 
1458 	list=NULL;
1459 
1460 	/* Iterate through children and create list of views */
1461 	clutter_actor_iter_init(&iter, CLUTTER_ACTOR(self));
1462 	while(clutter_actor_iter_next(&iter, &child))
1463 	{
1464 		/* Check if child is a view and add to list */
1465 		if(XFDASHBOARD_IS_VIEW(child)==TRUE) list=g_list_prepend(list, child);
1466 	}
1467 	list=g_list_reverse(list);
1468 
1469 	return(list);
1470 }
1471 
1472 /* Determine if viewpad contains requested view */
xfdashboard_viewpad_has_view(XfdashboardViewpad * self,XfdashboardView * inView)1473 gboolean xfdashboard_viewpad_has_view(XfdashboardViewpad *self, XfdashboardView *inView)
1474 {
1475 	ClutterActorIter			iter;
1476 	ClutterActor				*child;
1477 
1478 	g_return_val_if_fail(XFDASHBOARD_IS_VIEWPAD(self), FALSE);
1479 	g_return_val_if_fail(XFDASHBOARD_IS_VIEW(inView), FALSE);
1480 
1481 	/* Iterate through children and check if child is requested view */
1482 	clutter_actor_iter_init(&iter, CLUTTER_ACTOR(self));
1483 	while(clutter_actor_iter_next(&iter, &child))
1484 	{
1485 		if(XFDASHBOARD_IS_VIEW(child) &&
1486 			XFDASHBOARD_VIEW(child)==inView)
1487 		{
1488 			return(TRUE);
1489 		}
1490 	}
1491 
1492 	/* If we get here the requested view could not be found
1493 	 * so return FALSE.
1494 	 */
1495 	return(FALSE);
1496 }
1497 
1498 /* Find view by type */
xfdashboard_viewpad_find_view_by_type(XfdashboardViewpad * self,GType inType)1499 XfdashboardView* xfdashboard_viewpad_find_view_by_type(XfdashboardViewpad *self, GType inType)
1500 {
1501 	ClutterActorIter			iter;
1502 	ClutterActor				*child;
1503 	XfdashboardView				*view;
1504 
1505 	g_return_val_if_fail(XFDASHBOARD_IS_VIEWPAD(self), NULL);
1506 
1507 	view=NULL;
1508 
1509 	/* Iterate through children and create list of views */
1510 	clutter_actor_iter_init(&iter, CLUTTER_ACTOR(self));
1511 	while(!view && clutter_actor_iter_next(&iter, &child))
1512 	{
1513 		/* Check if child is a view and of type looking for */
1514 		if(XFDASHBOARD_IS_VIEW(child)==TRUE &&
1515 			G_OBJECT_TYPE(child)==inType)
1516 		{
1517 			view=XFDASHBOARD_VIEW(child);
1518 		}
1519 	}
1520 
1521 	/* Return view found which may be NULL if no view of requested type was found */
1522 	return(view);
1523 }
1524 
1525 /* Find view by ID */
xfdashboard_viewpad_find_view_by_id(XfdashboardViewpad * self,const gchar * inID)1526 XfdashboardView* xfdashboard_viewpad_find_view_by_id(XfdashboardViewpad *self, const gchar *inID)
1527 {
1528 	ClutterActorIter			iter;
1529 	ClutterActor				*child;
1530 	XfdashboardView				*view;
1531 
1532 	g_return_val_if_fail(XFDASHBOARD_IS_VIEWPAD(self), NULL);
1533 	g_return_val_if_fail(inID && *inID, NULL);
1534 
1535 	view=NULL;
1536 
1537 	/* Iterate through children and lookup view matching requested name */
1538 	clutter_actor_iter_init(&iter, CLUTTER_ACTOR(self));
1539 	while(!view && clutter_actor_iter_next(&iter, &child))
1540 	{
1541 		/* Check if child is a view and its internal name matches requested name */
1542 		if(XFDASHBOARD_IS_VIEW(child)==TRUE &&
1543 			xfdashboard_view_has_id(XFDASHBOARD_VIEW(child), inID))
1544 		{
1545 			view=XFDASHBOARD_VIEW(child);
1546 		}
1547 	}
1548 
1549 	/* Return view found which may be NULL if no view of requested type was found */
1550 	return(view);
1551 }
1552 
1553 /* Get/set active view */
xfdashboard_viewpad_get_active_view(XfdashboardViewpad * self)1554 XfdashboardView* xfdashboard_viewpad_get_active_view(XfdashboardViewpad *self)
1555 {
1556 	g_return_val_if_fail(XFDASHBOARD_IS_VIEWPAD(self), NULL);
1557 
1558 	return(self->priv->activeView);
1559 }
1560 
xfdashboard_viewpad_set_active_view(XfdashboardViewpad * self,XfdashboardView * inView)1561 void xfdashboard_viewpad_set_active_view(XfdashboardViewpad *self, XfdashboardView *inView)
1562 {
1563 	XfdashboardViewpadPrivate	*priv;
1564 
1565 	g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self));
1566 	g_return_if_fail(XFDASHBOARD_IS_VIEW(inView));
1567 
1568 	priv=self->priv;
1569 
1570 	/* Only activate view if it changes */
1571 	if(priv->activeView!=inView) _xfdashboard_viewpad_activate_view(self, inView);
1572 }
1573 
1574 /* Get/set scroll bar visibility */
xfdashboard_viewpad_get_horizontal_scrollbar_visible(XfdashboardViewpad * self)1575 gboolean xfdashboard_viewpad_get_horizontal_scrollbar_visible(XfdashboardViewpad *self)
1576 {
1577 	g_return_val_if_fail(XFDASHBOARD_IS_VIEWPAD(self), FALSE);
1578 
1579 	return(self->priv->hScrollbarVisible);
1580 }
1581 
xfdashboard_viewpad_get_vertical_scrollbar_visible(XfdashboardViewpad * self)1582 gboolean xfdashboard_viewpad_get_vertical_scrollbar_visible(XfdashboardViewpad *self)
1583 {
1584 	g_return_val_if_fail(XFDASHBOARD_IS_VIEWPAD(self), FALSE);
1585 
1586 	return(self->priv->vScrollbarVisible);
1587 }
1588 
1589 /* Get/set scroll bar policy */
xfdashboard_viewpad_get_horizontal_scrollbar_policy(XfdashboardViewpad * self)1590 XfdashboardVisibilityPolicy xfdashboard_viewpad_get_horizontal_scrollbar_policy(XfdashboardViewpad *self)
1591 {
1592 	g_return_val_if_fail(XFDASHBOARD_IS_VIEWPAD(self), XFDASHBOARD_VISIBILITY_POLICY_AUTOMATIC);
1593 
1594 	return(self->priv->hScrollbarPolicy);
1595 }
1596 
xfdashboard_viewpad_set_horizontal_scrollbar_policy(XfdashboardViewpad * self,XfdashboardVisibilityPolicy inPolicy)1597 void xfdashboard_viewpad_set_horizontal_scrollbar_policy(XfdashboardViewpad *self, XfdashboardVisibilityPolicy inPolicy)
1598 {
1599 	XfdashboardViewpadPrivate	*priv;
1600 
1601 	g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self));
1602 
1603 	priv=self->priv;
1604 
1605 	/* Only set new value if it differs from current value */
1606 	if(priv->hScrollbarPolicy==inPolicy) return;
1607 
1608 	/* Set new value */
1609 	priv->hScrollbarPolicy=inPolicy;
1610 	clutter_actor_queue_relayout(CLUTTER_ACTOR(self));
1611 
1612 	/* Notify about property change */
1613 	g_object_notify_by_pspec(G_OBJECT(self), XfdashboardViewpadProperties[PROP_HSCROLLBAR_POLICY]);
1614 }
1615 
xfdashboard_viewpad_get_vertical_scrollbar_policy(XfdashboardViewpad * self)1616 XfdashboardVisibilityPolicy xfdashboard_viewpad_get_vertical_scrollbar_policy(XfdashboardViewpad *self)
1617 {
1618 	g_return_val_if_fail(XFDASHBOARD_IS_VIEWPAD(self), XFDASHBOARD_VISIBILITY_POLICY_AUTOMATIC);
1619 
1620 	return(self->priv->vScrollbarPolicy);
1621 }
1622 
xfdashboard_viewpad_set_vertical_scrollbar_policy(XfdashboardViewpad * self,XfdashboardVisibilityPolicy inPolicy)1623 void xfdashboard_viewpad_set_vertical_scrollbar_policy(XfdashboardViewpad *self, XfdashboardVisibilityPolicy inPolicy)
1624 {
1625 	XfdashboardViewpadPrivate	*priv;
1626 
1627 	g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self));
1628 
1629 	priv=self->priv;
1630 
1631 	/* Only set new value if it differs from current value */
1632 	if(priv->vScrollbarPolicy==inPolicy) return;
1633 
1634 	/* Set new value */
1635 	priv->vScrollbarPolicy=inPolicy;
1636 	clutter_actor_queue_relayout(CLUTTER_ACTOR(self));
1637 
1638 	/* Notify about property change */
1639 	g_object_notify_by_pspec(G_OBJECT(self), XfdashboardViewpadProperties[PROP_VSCROLLBAR_POLICY]);
1640 }
1641