View-Specific Data

Sometimes it's useful to store some data that is connected to a view. Every CcItem stores its bounding box in a view-dependent way because different resolutions might result in different bounding box sizes. CCC contains an API that makes using such data as easy as using private data with GObject.

In this example we're creating an item that counts the number of clicks that have happened per view. We're creating a type called SliffSloff and the macro returning the GType will be SLIFF_TYPE_SLOFF.

Specifying View-Specific Data

To store some view-specific data, you have to specify a structure that will be created for each view:

typedef struct {
        gint click_counter;
} SliffSloffViewData;

Now we need to instruct libccc that we want this struct to contain our view-specific data:

static void
sliff_sloff_class_init (SliffSloffClass* self_class)
{
        CcItemClass* item_class = CC_ITEM_CLASS (self_class);

	/* Implement our own handlers for view (un)registration. More details later */
	item_class->view_register   = sliff_sloff_view_register;
	item_class->view_unregister = sliff_sloff_view_unregister;

	/* Require the size of a SliffSloffViewData for the view data */
	cc_item_class_add_view_data (self_class, sizeof (SliffSloffViewData));
}

Accessing View-Specific Data

CCC makes it very easy to access the view-specific data of an item. Calling cc_item_get_view_data will return a pointer to the memory chunk that stores the view-specific data for a certain view of a certain item.

But to make accessing this piece of memory easier, you can define a macro that helps you to get the data:

#define GET_VIEW_DATA(item,view) (CC_ITEM_GET_VIEW_DATA ((item), (view), SLIFF_TYPE_SLOFF, SliffSloffViewData))

Then you can easily access the view-data for a certain item by calling GET_VIEW_DATA(item, view):

/* sliff_sloff_frobnicate:
 * @item: a #CcItem
 * @view: a #CcView
 *
 * Frobnicate the #SliffSloff. This function gets called from
 * the CcItem::button_press event handlers.
 */
static void
sliff_sloff_frobnicate (CcItem* item,
                        CcView* view)
{
        SliffSloffViewData* view_data = GET_VIEW_DATA (item, view);

	view_data->click_counter++;
}

Memory Management

This section explains the details of the memory management that's implemented in CCC. It's useful to read this section at least once to understand the lifecycle of view-specific data.

Allocate and Initialize the Memory

The memory allocation happens as early as possible. The memory for the view-data gets allocated within the default implementation of the CcItem::view-register signal.

This means that custom implementations of CcItem::view-register absolutely need to chain up before executing custom statements.

After chaining up, you can initialize the data. It will be pre-initialized with 0 so you don't have to initialize integers or pointers to be 0 or NULL.

static void
sliff_sloff_view_register (CcItem* item,
                           CcView* view)
{
        SliffSloffViewData* view_data;

	/* call view_register from the parent class => allocate the memory */
        CC_ITEM_CLASS (sliff_sloff_parent_class)->view_register (item, view);

	view_data = GET_VIEW_DATA (item, view);

	/* your custom code (not necessary in this case) */
	view_data->click_counter = 0;
}

Clear and Free the Memory

Removing the view-specific data works exactly the other way round. First you clean up the memory and then you chain up into the CcItem::view-unregister handler of the parent class to free the memory.

static void
sliff_sloff_view_unregister (CcItem* item,
                             CcView* view)
{
        SliffSloffViewData* view_data;

	view_data = GET_VIEW_DATA (item, view_data);

	g_print ("SliffSloff %p received %d clicks on view %s (%p)",
	         item, view_data->click_counter,
		 G_OBJECT_TYPE_NAME (view), view);

	/* here you can unref objects that you created per view */
	view_data->click_counter = 0;

	/* call view_unregister from the parent class => free the memory */
	CC_ITEM_CLASS (sliff_sloff_parent_class)->view_unregister (item, view);
}