1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ |
---|
2 | /* |
---|
3 | * bonobo-listener.c: Generic listener interface for callbacks. |
---|
4 | * |
---|
5 | * Authors: |
---|
6 | * Alex Graveley (alex@helixcode.com) |
---|
7 | * Mike Kestner (mkestner@ameritech.net) |
---|
8 | * |
---|
9 | * Copyright (C) 2000, Helix Code, Inc. |
---|
10 | */ |
---|
11 | #include <config.h> |
---|
12 | #include <gtk/gtksignal.h> |
---|
13 | |
---|
14 | #include <bonobo/bonobo-exception.h> |
---|
15 | #include <bonobo/bonobo-listener.h> |
---|
16 | |
---|
17 | #define PARENT_TYPE BONOBO_X_OBJECT_TYPE |
---|
18 | |
---|
19 | static GtkObjectClass *bonobo_listener_parent_class; |
---|
20 | |
---|
21 | struct _BonoboListenerPrivate { |
---|
22 | BonoboListenerCallbackFn event_callback; |
---|
23 | gpointer user_data; |
---|
24 | }; |
---|
25 | |
---|
26 | enum SIGNALS { |
---|
27 | EVENT_NOTIFY, |
---|
28 | LAST_SIGNAL |
---|
29 | }; |
---|
30 | static guint signals [LAST_SIGNAL] = { 0 }; |
---|
31 | |
---|
32 | static void |
---|
33 | impl_Bonobo_Listener_event (PortableServer_Servant servant, |
---|
34 | const CORBA_char *event_name, |
---|
35 | const CORBA_any *args, |
---|
36 | CORBA_Environment *ev) |
---|
37 | { |
---|
38 | BonoboListener *listener; |
---|
39 | |
---|
40 | listener = BONOBO_LISTENER (bonobo_object_from_servant (servant)); |
---|
41 | |
---|
42 | bonobo_object_ref (BONOBO_OBJECT (listener)); |
---|
43 | if (listener->priv->event_callback) |
---|
44 | listener->priv->event_callback ( |
---|
45 | listener, (CORBA_char *) event_name, |
---|
46 | (CORBA_any *) args, ev, |
---|
47 | listener->priv->user_data); |
---|
48 | |
---|
49 | gtk_signal_emit (GTK_OBJECT (listener), |
---|
50 | signals [EVENT_NOTIFY], |
---|
51 | event_name, args, ev); |
---|
52 | bonobo_object_unref (BONOBO_OBJECT (listener)); |
---|
53 | } |
---|
54 | |
---|
55 | static void |
---|
56 | bonobo_listener_finalize (GtkObject *object) |
---|
57 | { |
---|
58 | BonoboListener *listener; |
---|
59 | |
---|
60 | listener = BONOBO_LISTENER (object); |
---|
61 | g_free (listener->priv); |
---|
62 | |
---|
63 | bonobo_listener_parent_class->finalize (object); |
---|
64 | } |
---|
65 | |
---|
66 | static void |
---|
67 | bonobo_listener_class_init (BonoboListenerClass *klass) |
---|
68 | { |
---|
69 | GtkObjectClass *oclass = (GtkObjectClass *)klass; |
---|
70 | POA_Bonobo_Listener__epv *epv = &klass->epv; |
---|
71 | |
---|
72 | bonobo_listener_parent_class = gtk_type_class (PARENT_TYPE); |
---|
73 | |
---|
74 | oclass->finalize = bonobo_listener_finalize; |
---|
75 | |
---|
76 | signals [EVENT_NOTIFY] = gtk_signal_new ( |
---|
77 | "event_notify", GTK_RUN_LAST, oclass->type, |
---|
78 | GTK_SIGNAL_OFFSET (BonoboListenerClass, event_notify), |
---|
79 | gtk_marshal_NONE__POINTER_POINTER_POINTER, GTK_TYPE_NONE, 3, |
---|
80 | GTK_TYPE_POINTER, GTK_TYPE_POINTER, GTK_TYPE_POINTER); |
---|
81 | |
---|
82 | gtk_object_class_add_signals (oclass, signals, LAST_SIGNAL); |
---|
83 | |
---|
84 | epv->event = impl_Bonobo_Listener_event; |
---|
85 | } |
---|
86 | |
---|
87 | static void |
---|
88 | bonobo_listener_init (GtkObject *object) |
---|
89 | { |
---|
90 | BonoboListener *listener; |
---|
91 | |
---|
92 | listener = BONOBO_LISTENER(object); |
---|
93 | listener->priv = g_new (BonoboListenerPrivate, 1); |
---|
94 | listener->priv->event_callback = NULL; |
---|
95 | listener->priv->user_data = NULL; |
---|
96 | } |
---|
97 | |
---|
98 | BONOBO_X_TYPE_FUNC_FULL (BonoboListener, |
---|
99 | Bonobo_Listener, |
---|
100 | PARENT_TYPE, |
---|
101 | bonobo_listener); |
---|
102 | |
---|
103 | /** |
---|
104 | * bonobo_listener_new: |
---|
105 | * @event_callback: function to be invoked when an event is emitted by the EventSource. |
---|
106 | * @user_data: data passed to the functioned pointed by @event_call. |
---|
107 | * |
---|
108 | * Creates a generic event listener. The listener calls the @event_callback |
---|
109 | * function and emits an "event_notify" signal when notified of an event. |
---|
110 | * The signal callback should be of the form: |
---|
111 | * |
---|
112 | * <informalexample> |
---|
113 | * <programlisting> |
---|
114 | * void some_callback (BonoboListener *listener, |
---|
115 | * char *event_name, |
---|
116 | * CORBA_any *any, |
---|
117 | * CORBA_Environment *ev, |
---|
118 | * gpointer user_data); |
---|
119 | * </programlisting> |
---|
120 | * </informalexample> |
---|
121 | * |
---|
122 | * You will typically pass the CORBA_Object reference in the return value |
---|
123 | * to an EventSource (by invoking EventSource::addListener). |
---|
124 | * |
---|
125 | * Returns: A BonoboListener object. |
---|
126 | */ |
---|
127 | BonoboListener* |
---|
128 | bonobo_listener_new (BonoboListenerCallbackFn event_callback, |
---|
129 | gpointer user_data) |
---|
130 | { |
---|
131 | BonoboListener *listener; |
---|
132 | |
---|
133 | listener = gtk_type_new (BONOBO_LISTENER_TYPE); |
---|
134 | |
---|
135 | listener->priv->event_callback = event_callback; |
---|
136 | listener->priv->user_data = user_data; |
---|
137 | |
---|
138 | return listener; |
---|
139 | } |
---|
140 | |
---|
141 | |
---|
142 | /** |
---|
143 | * bonobo_event_make_name: |
---|
144 | * @idl_path: the IDL part of the event name. |
---|
145 | * @kind: the kind of the event |
---|
146 | * @subtype: an optional subtype |
---|
147 | * |
---|
148 | * Creates an event name. Event names consist of three parts. The @idl_path is |
---|
149 | * mainly to create a unique namespace, and should identify the interface |
---|
150 | * which triggered the event, for example "Bonobo/Property". The @kind denotes |
---|
151 | * what happened, for example "change". Finally you can use the optional |
---|
152 | * @subtype to make events more specific. All three parts of the name are |
---|
153 | * joined together separated by colons. "Bonobo/Property:change" or |
---|
154 | * "Bonobo/Property:change:autosave" are examples of valid event names. |
---|
155 | * |
---|
156 | * Returns: A valid event_name, or NULL on error. |
---|
157 | */ |
---|
158 | char * |
---|
159 | bonobo_event_make_name (const char *idl_path, |
---|
160 | const char *kind, |
---|
161 | const char *subtype) |
---|
162 | { |
---|
163 | g_return_val_if_fail (idl_path != NULL, NULL); |
---|
164 | g_return_val_if_fail (kind != NULL, NULL); |
---|
165 | g_return_val_if_fail (!strchr (idl_path, ':'), NULL); |
---|
166 | g_return_val_if_fail (!strchr (kind, ':'), NULL); |
---|
167 | g_return_val_if_fail (!subtype || !strchr (subtype, ':'), NULL); |
---|
168 | g_return_val_if_fail (strlen (idl_path), NULL); |
---|
169 | g_return_val_if_fail (strlen (kind), NULL); |
---|
170 | |
---|
171 | if (subtype) |
---|
172 | return g_strconcat (idl_path, ":", kind, ":", |
---|
173 | subtype, NULL); |
---|
174 | else |
---|
175 | return g_strconcat (idl_path, ":", kind, NULL); |
---|
176 | } |
---|
177 | |
---|
178 | static gboolean |
---|
179 | bonobo_event_name_valid (const char *event_name) |
---|
180 | { |
---|
181 | gint i = 0, c = 0, l = -1; |
---|
182 | |
---|
183 | g_return_val_if_fail (event_name != NULL, FALSE); |
---|
184 | g_return_val_if_fail (strlen (event_name), FALSE); |
---|
185 | |
---|
186 | if (event_name [0] == ':') |
---|
187 | return FALSE; |
---|
188 | |
---|
189 | if (event_name [strlen (event_name) - 1] == ':') |
---|
190 | return FALSE; |
---|
191 | |
---|
192 | while (event_name [i]) { |
---|
193 | if (event_name [i] == ':') { |
---|
194 | if (l == (i -1)) |
---|
195 | return FALSE; |
---|
196 | l = i; |
---|
197 | c++; |
---|
198 | } |
---|
199 | i++; |
---|
200 | } |
---|
201 | |
---|
202 | if ((c == 1) || (c == 2)) |
---|
203 | return TRUE; |
---|
204 | |
---|
205 | return FALSE; |
---|
206 | } |
---|
207 | |
---|
208 | static char * |
---|
209 | bonobo_event_token (const char *event_name, gint pos) |
---|
210 | { |
---|
211 | char **str_array, *res; |
---|
212 | |
---|
213 | if (!bonobo_event_name_valid (event_name)) |
---|
214 | return NULL; |
---|
215 | |
---|
216 | str_array = g_strsplit (event_name, ":", 3); |
---|
217 | |
---|
218 | res = g_strdup (str_array [pos]); |
---|
219 | |
---|
220 | g_strfreev (str_array); |
---|
221 | |
---|
222 | return res; |
---|
223 | } |
---|
224 | |
---|
225 | /** |
---|
226 | * bonobo_event_type: |
---|
227 | * @event_name: the event name |
---|
228 | * |
---|
229 | * The event type consists of the first two parts of the event name, the idl_path |
---|
230 | * combined with the kind. |
---|
231 | * |
---|
232 | * Returns: The event type, or NULL on error. |
---|
233 | */ |
---|
234 | char * |
---|
235 | bonobo_event_type (const char *event_name) |
---|
236 | { |
---|
237 | gint i = 0, c = 0; |
---|
238 | |
---|
239 | if (!bonobo_event_name_valid (event_name)) |
---|
240 | return NULL; |
---|
241 | |
---|
242 | while (event_name [i]) { |
---|
243 | if (event_name [i] == ':') |
---|
244 | c++; |
---|
245 | if (c == 2) |
---|
246 | break; |
---|
247 | i++; |
---|
248 | } |
---|
249 | |
---|
250 | return g_strndup (event_name, i); |
---|
251 | } |
---|
252 | |
---|
253 | /** |
---|
254 | * bonobo_event_type: |
---|
255 | * @event_name: the event name |
---|
256 | * |
---|
257 | * Returns: The event subtype, or NULL on error. |
---|
258 | */ |
---|
259 | char * |
---|
260 | bonobo_event_subtype (const char *event_name) |
---|
261 | { |
---|
262 | return bonobo_event_token (event_name, 2); |
---|
263 | } |
---|
264 | |
---|
265 | /** |
---|
266 | * bonobo_event_kind: |
---|
267 | * @event_name: the event name |
---|
268 | * |
---|
269 | * Returns: The event kind, or NULL on error. |
---|
270 | */ |
---|
271 | char * |
---|
272 | bonobo_event_kind (const char *event_name) |
---|
273 | { |
---|
274 | return bonobo_event_token (event_name, 1); |
---|
275 | } |
---|
276 | |
---|
277 | /** |
---|
278 | * bonobo_event_idl_path: |
---|
279 | * @event_name: the event name |
---|
280 | * |
---|
281 | * Returns: The event idl path, or NULL on error. |
---|
282 | */ |
---|
283 | char * |
---|
284 | bonobo_event_idl_path (const char *event_name) |
---|
285 | { |
---|
286 | return bonobo_event_token (event_name, 0); |
---|
287 | } |
---|