[AdgContext] Got some docs from the wiki
[adg.git] / adg / adg-context.c
blobf3656c6bb8104b7a7bb9a26424e31808bc141317
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009 Nicola Fontana <ntd at entidi.it>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
21 /**
22 * SECTION:adg-context
23 * @short_description: Base class for styling the rendering process
25 * The context is a collection of styles, one for each #AdgStyle derived
26 * class. To achieve this result, there is a common register where all
27 * the style derived class are stored and every #AdgContext instance keeps
28 * its own register of style instances (one instance per class).
30 * Although this could be implemented by accessing the underlying registers
31 * using GType id, to be able to access efficiently, that is O(1) magnitude,
32 * the concept of slot was introduced.
34 * The slot serves the same purpose than a GType, that is identify a type
35 * class, but the slots are a strict sequence starting from 0, useful to be
36 * used as an array index.
37 **/
39 /**
40 * AdgContext:
42 * All fields are private and should not be used directly.
43 * Use its public methods instead.
44 **/
46 /**
47 * AdgContextFiller:
48 * @style_class: the new style class
49 * @user_data: the user provided data
51 * Callback to be used to get the default instance for newly registered
52 * style classes. This is needed to solve the issue rising on #AdgContext
53 * instances when a new style is added.
55 * The arrays that keep track of the style instances inside the contexts
56 * are dynamics (#GPtrArray type): whenever an undefined style instance
57 * is requested, the context object fills the array "holes" using a call
58 * to this callback.
60 * Returns: the instance to use for the passed in style class
61 **/
64 #include "adg-context.h"
65 #include "adg-context-private.h"
66 #include "adg-intl.h"
69 static AdgStyle * context_filler (AdgStyleClass *style_class,
70 gpointer user_data);
71 static void fill_style_slots (AdgContext *context,
72 guint last_slot);
74 static GPtrArray *class_slots = NULL;
77 G_DEFINE_TYPE(AdgContext, adg_context, G_TYPE_OBJECT);
80 static void
81 adg_context_class_init(AdgContextClass *klass)
83 g_type_class_add_private(klass, sizeof(AdgContextPrivate));
86 static void
87 adg_context_init(AdgContext *context)
89 AdgContextPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(context,
90 ADG_TYPE_CONTEXT,
91 AdgContextPrivate);
93 data->style_slots = g_ptr_array_sized_new(class_slots ?
94 class_slots->len : 10);
95 data->context_filler = context_filler;
96 data->user_data = NULL;
98 context->data = data;
103 * adg_context_get_slot:
104 * @type: an #AdgStyle type
106 * Gets the slot associated to @type. If not found, registers a new
107 * style family by assigning a new slot id to it: the internal register
108 * will keep a reference to this style class.
110 * Returns: the requested slot id
112 AdgStyleSlot
113 adg_context_get_slot(GType type)
115 AdgStyleClass *klass = g_type_class_ref(type);
117 g_return_val_if_fail(ADG_IS_STYLE_CLASS(klass), -1);
119 if (G_UNLIKELY(class_slots == NULL)) {
120 class_slots = g_ptr_array_sized_new(10);
121 } else {
122 guint n;
123 for (n = 0; n < class_slots->len; ++n)
124 if (class_slots->pdata[n] == klass)
125 return n;
128 g_ptr_array_add(class_slots, klass);
129 return class_slots->len - 1;
133 * adg_context_new:
134 * @context_filler: callback to use to fill uninitialized styles
135 * @user_data: additional pointer to pass to @context_filler
137 * Constructs a new empty context. If @context_filler is %NULL, the default
138 * filler callback will be used (the new style instances will be %NULL).
140 * Returns: a new context
142 AdgContext *
143 adg_context_new(AdgContextFiller context_filler, gpointer user_data)
145 AdgContext *context = g_object_new(ADG_TYPE_CONTEXT, NULL);
147 if (context_filler) {
148 AdgContextPrivate *data = context->data;
150 data->context_filler = context_filler;
151 data->user_data = user_data;
154 return context;
158 * adg_context_get_style:
159 * @context: an #AdgContext instance
160 * @slot: the style slot where to get the style
162 * Gets a style instance from the specified @slot of @context.
164 * Returns: the style instance
166 AdgStyle *
167 adg_context_get_style(AdgContext *context, AdgStyleSlot slot)
169 AdgContextPrivate *data;
170 GPtrArray *style_slots;
172 g_return_val_if_fail(ADG_IS_CONTEXT(context), NULL);
173 g_return_val_if_fail(slot >= 0 && slot < class_slots->len, NULL);
175 data = context->data;
176 style_slots = data->style_slots;
178 if (G_UNLIKELY(slot >= style_slots->len))
179 fill_style_slots(context, slot);
181 return (AdgStyle *) g_ptr_array_index(style_slots, slot);
185 * adg_context_set_style:
186 * @context: an #AdgContext instance
187 * @style: the new style to include
189 * Sets a new style inside @context. The old style (if any)
190 * will be unreferenced while a new reference will be added to @style.
192 void
193 adg_context_set_style(AdgContext *context, AdgStyle *style)
195 AdgContextPrivate *data;
196 AdgStyleSlot slot;
197 GPtrArray *style_slots;
199 g_return_if_fail(ADG_IS_CONTEXT(context));
200 g_return_if_fail(ADG_IS_STYLE(style));
202 data = context->data;
203 slot = adg_context_get_slot(G_TYPE_FROM_INSTANCE(style));
204 style_slots = data->style_slots;
206 g_object_ref(style);
208 if (G_LIKELY(slot < style_slots->len)) {
209 g_object_unref(style_slots->pdata[slot]);
210 style_slots->pdata[slot] = style;
211 } else {
212 fill_style_slots(context, slot - 1);
213 g_ptr_array_add(style_slots, style);
218 static AdgStyle *
219 context_filler(AdgStyleClass *style_class, gpointer user_data)
221 return NULL;
224 static void
225 fill_style_slots(AdgContext *context, guint last_slot)
227 AdgContextPrivate *data;
228 GPtrArray *style_slots;
229 AdgStyleClass *klass;
230 AdgStyle *style;
231 guint n;
233 data = context->data;
234 style_slots = data->style_slots;
236 for (n = style_slots->len; n <= last_slot; ++n) {
237 klass = (AdgStyleClass *) g_ptr_array_index(class_slots, n);
238 style = data->context_filler(klass, data->user_data);
239 g_object_ref((GObject *) style);
240 g_ptr_array_add(style_slots, style);