~ubuntu-branches/ubuntu/wily/evolution-data-server/wily

« back to all changes in this revision

Viewing changes to libedataserver/e-extensible.c

  • Committer: Package Import Robot
  • Author(s): Iain Lane
  • Date: 2015-07-20 13:34:59 UTC
  • mfrom: (1.1.126) (1.2.48 sid)
  • Revision ID: package-import@ubuntu.com-20150720133459-g6y46hnu5ewtoz08
Tags: 3.16.4-0ubuntu2
debian/patches/0001-Bug-752373-Monthly-events-do-not-recur-correctly.patch:
Cherry-pick patch from upstream to fix events not recurring correctly.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * e-extensible.c
 
3
 *
 
4
 * This library is free software: you can redistribute it and/or modify it
 
5
 * under the terms of the GNU Lesser General Public License as published by
 
6
 * the Free Software Foundation.
 
7
 *
 
8
 * This library is distributed in the hope that it will be useful, but
 
9
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 
10
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 
11
 * for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU Lesser General Public License
 
14
 * along with this library. If not, see <http://www.gnu.org/licenses/>.
 
15
 *
 
16
 */
 
17
 
 
18
/**
 
19
 * SECTION: e-extensible
 
20
 * @include: libedataserver/libedataserver.h
 
21
 * @short_description: An interface for extending objects
 
22
 *
 
23
 * #EExtension objects can be tacked on to any #GObject instance that
 
24
 * implements the #EExtensible interface.  A #GObject type can be made
 
25
 * extensible in two steps:
 
26
 *
 
27
 * 1. Add the #EExtensible interface when registering the #GType.
 
28
 *    There are no methods to implement.
 
29
 *
 
30
 * <informalexample>
 
31
 * <programlisting>
 
32
 * #include <libedataserver/libedataserver.h>
 
33
 *
 
34
 * G_DEFINE_TYPE_WITH_CODE (
 
35
 *         ECustomWidget, e_custom_widget, GTK_TYPE_WIDGET,
 
36
 *         G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE, NULL))
 
37
 * </programlisting>
 
38
 * </informalexample>
 
39
 *
 
40
 * 2. Load extensions for the class at some point during #GObject
 
41
 *    initialization.  Generally this should be done toward the end of
 
42
 *    the initialization code, so extensions get a fully initialized
 
43
 *    object to work with.
 
44
 *
 
45
 * <informalexample>
 
46
 * <programlisting>
 
47
 * static void
 
48
 * e_custom_widget_constructed (ECustomWidget *widget)
 
49
 * {
 
50
 *         Construction code goes here, same as call to parent's 'constructed'...
 
51
 *
 
52
 *         e_extensible_load_extensions (E_EXTENSIBLE (widget));
 
53
 * }
 
54
 * </programlisting>
 
55
 * </informalexample>
 
56
 **/
 
57
 
 
58
#ifdef HAVE_CONFIG_H
 
59
#include <config.h>
 
60
#endif
 
61
 
 
62
#include "e-extension.h"
 
63
#include "e-data-server-util.h"
 
64
 
 
65
#include "e-extensible.h"
 
66
 
 
67
#define IS_AN_EXTENSION_TYPE(type) \
 
68
        (g_type_is_a ((type), E_TYPE_EXTENSION))
 
69
 
 
70
static GQuark extensible_quark;
 
71
 
 
72
G_DEFINE_INTERFACE (
 
73
        EExtensible,
 
74
        e_extensible,
 
75
        G_TYPE_OBJECT)
 
76
 
 
77
static GPtrArray *
 
78
extensible_get_extensions (EExtensible *extensible)
 
79
{
 
80
        return g_object_get_qdata (G_OBJECT (extensible), extensible_quark);
 
81
}
 
82
 
 
83
static void
 
84
extensible_load_extension (GType extension_type,
 
85
                           EExtensible *extensible)
 
86
{
 
87
        EExtensionClass *extension_class;
 
88
        GType extensible_type;
 
89
        GPtrArray *extensions;
 
90
        EExtension *extension;
 
91
 
 
92
        extensible_type = G_OBJECT_TYPE (extensible);
 
93
        extension_class = g_type_class_ref (extension_type);
 
94
 
 
95
        /* Only load extensions that extend the given extensible object. */
 
96
        if (!g_type_is_a (extensible_type, extension_class->extensible_type))
 
97
                goto exit;
 
98
 
 
99
        extension = g_object_new (
 
100
                extension_type, "extensible", extensible, NULL);
 
101
 
 
102
        extensions = extensible_get_extensions (extensible);
 
103
        g_ptr_array_add (extensions, extension);
 
104
 
 
105
exit:
 
106
        g_type_class_unref (extension_class);
 
107
}
 
108
 
 
109
static void
 
110
e_extensible_default_init (EExtensibleInterface *iface)
 
111
{
 
112
        extensible_quark = g_quark_from_static_string ("e-extensible-quark");
 
113
}
 
114
 
 
115
/**
 
116
 * e_extensible_load_extensions:
 
117
 * @extensible: an #EExtensible
 
118
 *
 
119
 * Creates an instance of all instantiable subtypes of #EExtension which
 
120
 * target the class of @extensible.  The lifetimes of these newly created
 
121
 * #EExtension objects are bound to @extensible such that they are finalized
 
122
 * when @extensible is finalized.
 
123
 *
 
124
 * Since: 3.4
 
125
 **/
 
126
void
 
127
e_extensible_load_extensions (EExtensible *extensible)
 
128
{
 
129
        GPtrArray *extensions;
 
130
 
 
131
        g_return_if_fail (E_IS_EXTENSIBLE (extensible));
 
132
 
 
133
        if (extensible_get_extensions (extensible) != NULL)
 
134
                return;
 
135
 
 
136
        extensions = g_ptr_array_new_with_free_func (
 
137
                (GDestroyNotify) g_object_unref);
 
138
 
 
139
        g_object_set_qdata_full (
 
140
                G_OBJECT (extensible), extensible_quark,
 
141
                g_ptr_array_ref (extensions),
 
142
                (GDestroyNotify) g_ptr_array_unref);
 
143
 
 
144
        e_type_traverse (
 
145
                E_TYPE_EXTENSION, (ETypeFunc)
 
146
                extensible_load_extension, extensible);
 
147
 
 
148
        /* If the extension array is still empty, remove it from the
 
149
         * extensible object.  It may be that no extension types have
 
150
         * been registered yet, so this allows for trying again later. */
 
151
        if (extensions->len == 0)
 
152
                g_object_set_qdata (
 
153
                        G_OBJECT (extensible),
 
154
                        extensible_quark, NULL);
 
155
 
 
156
        g_ptr_array_unref (extensions);
 
157
}
 
158
 
 
159
/**
 
160
 * e_extensible_list_extensions:
 
161
 * @extensible: an #EExtensible
 
162
 * @extension_type: the type of extensions to list
 
163
 *
 
164
 * Returns a list of #EExtension objects bound to @extensible whose
 
165
 * types are ancestors of @extension_type.  For a complete list of
 
166
 * extension objects bound to @extensible, pass %E_TYPE_EXTENSION.
 
167
 *
 
168
 * The list itself should be freed with g_list_free().  The extension
 
169
 * objects are owned by @extensible and should not be unreferenced.
 
170
 *
 
171
 * Returns: a list of extension objects derived from @extension_type
 
172
 *
 
173
 * Since: 3.4
 
174
 **/
 
175
GList *
 
176
e_extensible_list_extensions (EExtensible *extensible,
 
177
                              GType extension_type)
 
178
{
 
179
        GPtrArray *extensions;
 
180
        GList *list = NULL;
 
181
        guint ii;
 
182
 
 
183
        g_return_val_if_fail (E_IS_EXTENSIBLE (extensible), NULL);
 
184
        g_return_val_if_fail (IS_AN_EXTENSION_TYPE (extension_type), NULL);
 
185
 
 
186
        e_extensible_load_extensions (extensible);
 
187
 
 
188
        extensions = extensible_get_extensions (extensible);
 
189
 
 
190
        /* This will be NULL if no extensions are present. */
 
191
        if (extensions == NULL)
 
192
                return NULL;
 
193
 
 
194
        for (ii = 0; ii < extensions->len; ii++) {
 
195
                GObject *object;
 
196
 
 
197
                object = g_ptr_array_index (extensions, ii);
 
198
                if (g_type_is_a (G_OBJECT_TYPE (object), extension_type))
 
199
                        list = g_list_prepend (list, object);
 
200
        }
 
201
 
 
202
        return g_list_reverse (list);
 
203
}