Merge lp:~gordallott/unity/unity-ubus into lp:unity
- unity-ubus
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Neil J. Patel |
Approved revision: | no longer in the source branch. |
Merged at revision: | 629 |
Proposed branch: | lp:~gordallott/unity/unity-ubus |
Merge into: | lp:unity |
Diff against target: |
786 lines (+611/-15) 7 files modified
libunity/CMakeLists.txt (+1/-1) libunity/ubus-server.c (+361/-0) libunity/ubus-server.h (+74/-0) services/panel-service.c (+16/-12) tests/CMakeLists.txt (+4/-1) tests/unit/TestMain.cpp (+3/-1) tests/unit/TestUBus.cpp (+152/-0) |
To merge this branch: | bzr merge lp:~gordallott/unity/unity-ubus |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Neil J. Patel (community) | Approve | ||
Review via email: mp+41856@code.launchpad.net |
Commit message
Description of the change
adds UBus Support into unity, a simple message broadcasting service to allow for simple inter component communication without introducing dependencies.
Comes with tests because tests are awesome
Gord Allott (gordallott) wrote : | # |
fixed the hash tab indenting
regarding the reference counting, I think its best to just hold on to our own reference and own it completely, no real reason to start increasing/
Neil J. Patel (njpatel) : | # |
Mikkel Kamstrup Erlandsen (kamstrup) wrote : | # |
+UBusMessageInfo *
+ubus_message_
+{
+ UBusMessageInfo *info = g_new (UBusMessageInfo, 1);
+ info->message = g_strdup (message);
+ info->data = data;
+
+ if (data != NULL)
+ g_variant_ref (data);
+ return info;
+}
You probably want to g_variant_
floating ref to send() without leaking.
+ if (info->data != NULL)
+ g_variant_unref (info->data);
+ g_free (info);
You're leaking the message string. Why not use the
ubus_message_
Static modifiers are missing on all private functions in the .c files.
Right now you exporting all the unnamespaced utility functions.
If we expect the message names to not contain variations like
"unity_msg_N" for random 0 < N < 9999999999 then, ie. constant string
like "Unity.ShowDash", then it's a big waste go g_strdup() the message
in the UBusMessageInfo constructor. Just use a GStringChunk and save
all the reallocations.
Other than that nice work :-)
Preview Diff
1 | === modified file 'libunity/CMakeLists.txt' |
2 | --- libunity/CMakeLists.txt 2010-11-19 12:06:29 +0000 |
3 | +++ libunity/CMakeLists.txt 2010-11-25 14:26:39 +0000 |
4 | @@ -56,7 +56,7 @@ |
5 | GENERATE_VAPI unity |
6 | ) |
7 | |
8 | -add_library (${PKGNAME} SHARED ${VALA_C}) |
9 | +add_library (${PKGNAME} SHARED ${VALA_C} ubus-server.c) |
10 | set_target_properties (${PKGNAME} PROPERTIES |
11 | VERSION ${libunity_VERSION} |
12 | SOVERSION ${libunity_SOVERSION} |
13 | |
14 | === added file 'libunity/ubus-server.c' |
15 | --- libunity/ubus-server.c 1970-01-01 00:00:00 +0000 |
16 | +++ libunity/ubus-server.c 2010-11-25 14:26:39 +0000 |
17 | @@ -0,0 +1,361 @@ |
18 | +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ |
19 | +/* |
20 | + * u-bus-server.c |
21 | + * Copyright (C) 2010 Canonical, Ltd. |
22 | + * |
23 | + * This library is free software; you can redistribute it and/or modify |
24 | + * it under the terms of the GNU Lesser General Public License |
25 | + * version 3.0 as published by the Free Software Foundation. |
26 | + * |
27 | + * This library is distributed in the hope that it will be useful, |
28 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
29 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
30 | + * GNU Lesser General Public License version 3.0 for more details. |
31 | + * |
32 | + * You should have received a copy of the GNU Lesser General Public |
33 | + * License along with this library. If not, see |
34 | + * <http://www.gnu.org/licenses/>. |
35 | + * |
36 | + * Authored by Gordon Allott <gord.allott@canonical.com> |
37 | + */ |
38 | + |
39 | +#include "ubus-server.h" |
40 | +#include <string.h> |
41 | +#include <stdlib.h> |
42 | +#include <glib.h> |
43 | + |
44 | +#define UBUS_SERVER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\ |
45 | + UBUS_TYPE_SERVER, \ |
46 | + UBusServerPrivate)) |
47 | + |
48 | +struct _UBusServerPrivate |
49 | +{ |
50 | + GHashTable *message_interest_table; |
51 | + GHashTable *dispatch_table; |
52 | + |
53 | + GQueue *message_queue; |
54 | + |
55 | + gulong id_sequencial_number; |
56 | + gboolean message_pump_queued; |
57 | +}; |
58 | + |
59 | + |
60 | +G_DEFINE_TYPE (UBusServer, ubus_server, G_TYPE_INITIALLY_UNOWNED); |
61 | + |
62 | +struct _UBusDispatchInfo |
63 | +{ |
64 | + gulong id; |
65 | + UBusCallback callback; |
66 | + gchar *message; |
67 | + gpointer *user_data; |
68 | +}; |
69 | +typedef struct _UBusDispatchInfo UBusDispatchInfo; |
70 | + |
71 | +UBusDispatchInfo * |
72 | +ubus_dispatch_info_new (UBusServer* server, const gchar *message, |
73 | + UBusCallback callback, gpointer user_data) |
74 | +{ |
75 | + g_return_val_if_fail (UBUS_IS_SERVER (server), NULL); |
76 | + UBusServerPrivate *priv = server->priv; |
77 | + UBusDispatchInfo *info; |
78 | + |
79 | + if (priv->id_sequencial_number < 1) |
80 | + { |
81 | + g_critical (G_STRLOC ": ID's are overflowing"); |
82 | + } |
83 | + |
84 | + info = g_new (UBusDispatchInfo, 1); |
85 | + info->id = priv->id_sequencial_number++; |
86 | + info->callback = callback; |
87 | + info->message = g_strdup (message); |
88 | + info->user_data = user_data; |
89 | + |
90 | + return info; |
91 | +} |
92 | + |
93 | +void |
94 | +ubus_dispatch_info_free (UBusDispatchInfo *info) |
95 | +{ |
96 | + g_free (info->message); |
97 | + g_free (info); |
98 | +} |
99 | + |
100 | +struct _UBusMessageInfo |
101 | +{ |
102 | + gchar *message; |
103 | + GVariant *data; |
104 | +}; |
105 | + |
106 | +typedef struct _UBusMessageInfo UBusMessageInfo; |
107 | + |
108 | +UBusMessageInfo * |
109 | +ubus_message_info_new (const gchar *message, GVariant *data) |
110 | +{ |
111 | + UBusMessageInfo *info = g_new (UBusMessageInfo, 1); |
112 | + info->message = g_strdup (message); |
113 | + info->data = data; |
114 | + |
115 | + if (data != NULL) |
116 | + g_variant_ref (data); |
117 | + return info; |
118 | +} |
119 | + |
120 | +void |
121 | +ubus_message_info_free (UBusMessageInfo *info) |
122 | +{ |
123 | + g_variant_unref (info->data); |
124 | + g_free (info->message); |
125 | + g_free (info); |
126 | +} |
127 | + |
128 | +gboolean |
129 | +ulong_equal (gconstpointer v1, |
130 | + gconstpointer v2) |
131 | +{ |
132 | + return *((const gulong*) v1) == *((const gulong*) v2); |
133 | +} |
134 | + |
135 | +guint |
136 | +ulong_hash (gconstpointer v) |
137 | +{ |
138 | + return (guint) *(const gulong*) v; |
139 | +} |
140 | + |
141 | +static void |
142 | +ubus_server_init (UBusServer *server) |
143 | +{ |
144 | + UBusServerPrivate *priv; |
145 | + priv = server->priv = UBUS_SERVER_GET_PRIVATE (server); |
146 | + |
147 | + // message_interest_table holds the message/DispatchInfo relationship |
148 | + priv->message_interest_table = g_hash_table_new_full (g_str_hash, g_str_equal, |
149 | + g_free, |
150 | + (GDestroyNotify)g_sequence_free); |
151 | + // dispatch table holds the individial id/DispatchInfo pairs |
152 | + priv->dispatch_table = g_hash_table_new_full (ulong_hash, ulong_equal, |
153 | + g_free, |
154 | + (GDestroyNotify)ubus_dispatch_info_free); |
155 | + |
156 | + // for anyone thats wondering (hi kamstrup!), there are two hash tables so |
157 | + // that lookups are fast when sending messages and removing handlers |
158 | + |
159 | + priv->message_queue = g_queue_new (); |
160 | + priv->id_sequencial_number = 1; |
161 | +} |
162 | + |
163 | +static void |
164 | +ubus_server_finalize (GObject *object) |
165 | +{ |
166 | + UBusServer *server = UBUS_SERVER (object); |
167 | + UBusServerPrivate *priv = server->priv; |
168 | + g_hash_table_destroy (priv->message_interest_table); |
169 | + g_hash_table_destroy (priv->dispatch_table); |
170 | + |
171 | + UBusMessageInfo *info = g_queue_pop_tail (priv->message_queue); |
172 | + for (; info != NULL; info = g_queue_pop_tail (priv->message_queue)) |
173 | + { |
174 | + if (info->data != NULL) |
175 | + g_variant_unref (info->data); |
176 | + g_free (info); |
177 | + } |
178 | + |
179 | + g_queue_free (priv->message_queue); |
180 | + |
181 | + G_OBJECT_CLASS (ubus_server_parent_class)->finalize (object); |
182 | +} |
183 | + |
184 | +static void |
185 | +ubus_server_class_init (UBusServerClass *klass) |
186 | +{ |
187 | + GObjectClass* object_class = G_OBJECT_CLASS (klass); |
188 | + g_type_class_add_private (klass, sizeof (UBusServerPrivate)); |
189 | + object_class->finalize = ubus_server_finalize; |
190 | +} |
191 | + |
192 | +UBusServer * |
193 | +ubus_server_get_default () |
194 | +{ |
195 | + static gsize singleton; |
196 | + if (g_once_init_enter (&singleton)) |
197 | + { |
198 | + UBusServer *server; |
199 | + server = g_object_new (UBUS_TYPE_SERVER, NULL); |
200 | + g_object_ref_sink (server); |
201 | + g_once_init_leave (&singleton, (gsize) server); |
202 | + } |
203 | + |
204 | + // we actually just want to hold our own reference and not let anything |
205 | + // else reference us, because we never want to lose that reference, we are |
206 | + // only allowed to initalise once |
207 | + return (UBusServer *)singleton; |
208 | +} |
209 | + |
210 | +gulong |
211 | +ubus_server_register_interest (UBusServer* server, const gchar *message, |
212 | + UBusCallback callback, gpointer user_data) |
213 | +{ |
214 | + g_return_val_if_fail (UBUS_IS_SERVER (server), 0); |
215 | + g_return_val_if_fail (message != NULL, 0); |
216 | + |
217 | + UBusServerPrivate *priv = server->priv; |
218 | + GSequence *dispatch_list = g_hash_table_lookup (priv->message_interest_table, |
219 | + message); |
220 | + UBusDispatchInfo *info; |
221 | + |
222 | + if (dispatch_list == NULL) |
223 | + { |
224 | + // not had this message before so add a new entry to the message_interest table |
225 | + gchar *key = g_strdup (message); |
226 | + dispatch_list = g_sequence_new (NULL); // we use a sequence because its a stable pointer |
227 | + g_hash_table_insert (priv->message_interest_table, key, dispatch_list); |
228 | + } |
229 | + |
230 | + // add the callback to the dispatch table |
231 | + info = ubus_dispatch_info_new (server, message, callback, user_data); |
232 | + gulong *id = g_malloc (sizeof (gulong)); |
233 | + *id = info->id; |
234 | + g_hash_table_insert (priv->dispatch_table, id, info); |
235 | + |
236 | + // add the dispatch info to the dispatch list in the message interest table |
237 | + g_sequence_append (dispatch_list, info); |
238 | + |
239 | + return info->id; |
240 | +} |
241 | + |
242 | +gboolean |
243 | +ubus_server_pump_message_queue (UBusServer *server) |
244 | +{ |
245 | + g_return_val_if_fail (UBUS_IS_SERVER (server), FALSE); |
246 | + UBusServerPrivate *priv = server->priv; |
247 | + UBusMessageInfo *info; |
248 | + |
249 | + priv->message_pump_queued = TRUE; |
250 | + |
251 | + // loop through each message queued and call the dispatch functions associated |
252 | + // with it. something in the back of my mind says it would be quicker in some |
253 | + // situations to sort the queue first so that duplicate messages can re-use |
254 | + // the same dispatch_list lookups.. but thats a specific case. |
255 | + |
256 | + |
257 | + info = g_queue_pop_tail (priv->message_queue); |
258 | + for (; info != NULL; info = g_queue_pop_tail (priv->message_queue)) |
259 | + { |
260 | + GSequence *dispatch_list; |
261 | + dispatch_list = g_hash_table_lookup (priv->message_interest_table, |
262 | + info->message); |
263 | + |
264 | + if (dispatch_list == NULL) |
265 | + continue; // no handlers for this message |
266 | + |
267 | + GSequenceIter *iter = g_sequence_get_begin_iter (dispatch_list); |
268 | + GSequenceIter *end = g_sequence_get_end_iter (dispatch_list); |
269 | + |
270 | + while (iter != end) |
271 | + { |
272 | + GSequenceIter *next = g_sequence_iter_next (iter); |
273 | + UBusDispatchInfo *dispatch_info = g_sequence_get (iter); |
274 | + UBusCallback callback = dispatch_info->callback; |
275 | + |
276 | + (*callback) (info->data, dispatch_info->user_data); |
277 | + |
278 | + iter = next; |
279 | + } |
280 | + |
281 | + if (info->data != NULL) |
282 | + g_variant_unref (info->data); |
283 | + g_free (info); |
284 | + } |
285 | + |
286 | + return FALSE; |
287 | +} |
288 | + |
289 | +void |
290 | +ubus_server_queue_message_pump (UBusServer *server) |
291 | +{ |
292 | + g_return_if_fail (UBUS_IS_SERVER (server)); |
293 | + UBusServerPrivate *priv = server->priv; |
294 | + |
295 | + if (priv->message_pump_queued) |
296 | + return; |
297 | + |
298 | + g_idle_add ((GSourceFunc)ubus_server_pump_message_queue, server); |
299 | + priv->message_pump_queued = TRUE; |
300 | +} |
301 | + |
302 | +void |
303 | +ubus_server_send_message (UBusServer *server, const gchar *message, |
304 | + GVariant *data) |
305 | +{ |
306 | + g_return_if_fail (UBUS_IS_SERVER (server)); |
307 | + g_return_if_fail (message != NULL); |
308 | + UBusServerPrivate *priv = server->priv; |
309 | + |
310 | + UBusMessageInfo *message_info = ubus_message_info_new (message, data); |
311 | + g_queue_push_head (priv->message_queue, message_info); |
312 | + |
313 | + ubus_server_queue_message_pump (server); |
314 | +} |
315 | + |
316 | +void |
317 | +ubus_server_unregister_interest (UBusServer* server, gulong handle) |
318 | +{ |
319 | + g_return_if_fail (UBUS_IS_SERVER (server)); |
320 | + g_return_if_fail (handle > 0); |
321 | + UBusServerPrivate *priv = server->priv; |
322 | + UBusDispatchInfo *info; |
323 | + GSequence *dispatch_list; |
324 | + |
325 | + // get our info |
326 | + info = g_hash_table_lookup (priv->dispatch_table, &handle); |
327 | + |
328 | + if (info == NULL) |
329 | + { |
330 | + g_warning (G_STRLOC ": Handle %lu does not exist", handle); |
331 | + return; |
332 | + } |
333 | + |
334 | + // now the slightly sucky bit, we have to remove from our message-interest |
335 | + // table, but we can only find it by itterating through a sequence |
336 | + // but this is not so bad because we know *which* sequence its in |
337 | + |
338 | + dispatch_list = g_hash_table_lookup (priv->message_interest_table, |
339 | + info->message); |
340 | + |
341 | + if (dispatch_list == NULL) |
342 | + { |
343 | + g_critical (G_STRLOC ": Handle exists but not dispatch list, ubus has "\ |
344 | + "become unstable"); |
345 | + return; |
346 | + } |
347 | + |
348 | + GSequenceIter *iter = g_sequence_get_begin_iter (dispatch_list); |
349 | + GSequenceIter *end = g_sequence_get_end_iter (dispatch_list); |
350 | + while (iter != end) |
351 | + { |
352 | + GSequenceIter *next = g_sequence_iter_next (iter); |
353 | + UBusDispatchInfo *info_test = g_sequence_get (iter); |
354 | + |
355 | + if (info_test->id == handle) |
356 | + { |
357 | + g_sequence_remove (iter); |
358 | + } |
359 | + |
360 | + iter = next; |
361 | + } |
362 | + |
363 | + if (g_sequence_get_length (dispatch_list) == 0) |
364 | + { |
365 | + // free the key/value pair |
366 | + g_hash_table_remove (priv->message_interest_table, info->message); |
367 | + } |
368 | + |
369 | + // finally remove the dispatch_table hash table. |
370 | + g_hash_table_remove (priv->dispatch_table, &handle); |
371 | + |
372 | +} |
373 | + |
374 | +void |
375 | +ubus_server_force_message_pump (UBusServer* server) |
376 | +{ |
377 | + ubus_server_pump_message_queue (server); |
378 | +} |
379 | |
380 | === added file 'libunity/ubus-server.h' |
381 | --- libunity/ubus-server.h 1970-01-01 00:00:00 +0000 |
382 | +++ libunity/ubus-server.h 2010-11-25 14:26:39 +0000 |
383 | @@ -0,0 +1,74 @@ |
384 | +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ |
385 | +/* |
386 | + * u-bus-server.h |
387 | + * Copyright (C) 2010 Canonical, Ltd. |
388 | + * |
389 | + * This library is free software; you can redistribute it and/or modify |
390 | + * it under the terms of the GNU Lesser General Public License |
391 | + * version 3.0 as published by the Free Software Foundation. |
392 | + * |
393 | + * This library is distributed in the hope that it will be useful, |
394 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
395 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
396 | + * GNU Lesser General Public License version 3.0 for more details. |
397 | + * |
398 | + * You should have received a copy of the GNU Lesser General Public |
399 | + * License along with this library. If not, see |
400 | + * <http://www.gnu.org/licenses/>. |
401 | + * |
402 | + * Authored by Gordon Allott <gord.allott@canonical.com> |
403 | + */ |
404 | + |
405 | +#ifndef _U_BUS_SERVER_H_ |
406 | +#define _U_BUS_SERVER_H_ |
407 | + |
408 | +#include <glib-object.h> |
409 | +#include <glib.h> |
410 | +G_BEGIN_DECLS |
411 | + |
412 | +#define UBUS_TYPE_SERVER (ubus_server_get_type ()) |
413 | +#define UBUS_SERVER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UBUS_TYPE_SERVER, UBusServer)) |
414 | +#define UBUS_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UBUS_TYPE_SERVER, UBusServerClass)) |
415 | +#define UBUS_IS_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UBUS_TYPE_SERVER)) |
416 | +#define UBUS_IS_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UBUS_TYPE_SERVER)) |
417 | +#define UBUS_SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UBUS_TYPE_SERVER, UBusServerClass)) |
418 | + |
419 | +typedef struct _UBusServerClass UBusServerClass; |
420 | +typedef struct _UBusServer UBusServer; |
421 | +typedef struct _UBusServerPrivate UBusServerPrivate; |
422 | + |
423 | +struct _UBusServerClass |
424 | +{ |
425 | + GObjectClass parent_class; |
426 | + |
427 | + /* padding */ |
428 | + void (*_unity_padding1) (void); |
429 | + void (*_unity_padding2) (void); |
430 | + void (*_unity_padding3) (void); |
431 | + void (*_unity_padding4) (void); |
432 | + void (*_unity_padding5) (void); |
433 | + void (*_unity_padding6) (void); |
434 | +}; |
435 | + |
436 | +struct _UBusServer |
437 | +{ |
438 | + GObject parent_instance; |
439 | + |
440 | + UBusServerPrivate *priv; |
441 | +}; |
442 | + |
443 | +typedef void (*UBusCallback) (GVariant *data, gpointer *user_data); |
444 | + |
445 | +GType ubus_server_get_type (void) G_GNUC_CONST; |
446 | +UBusServer *ubus_server_get_default (); |
447 | +void ubus_server_prime_context (UBusServer* server, GMainContext *context); |
448 | +gulong ubus_server_register_interest (UBusServer* server, const gchar *message, |
449 | + UBusCallback callback, gpointer user_data); |
450 | +void ubus_server_send_message (UBusServer* server, const gchar *message, |
451 | + GVariant *data); |
452 | +void ubus_server_unregister_interest (UBusServer* server, gulong handle); |
453 | +void ubus_server_force_message_pump (UBusServer* server); |
454 | + |
455 | +G_END_DECLS |
456 | + |
457 | +#endif /* _U_BUS_SERVER_H_ */ |
458 | |
459 | === modified file 'services/panel-service.c' |
460 | --- services/panel-service.c 2010-11-17 23:53:21 +0000 |
461 | +++ services/panel-service.c 2010-11-25 14:26:39 +0000 |
462 | @@ -158,7 +158,7 @@ |
463 | GdkWindow *window = gtk_widget_get_window (GTK_WIDGET (self->priv->last_menu)); |
464 | if (window == NULL) |
465 | return GDK_FILTER_CONTINUE; |
466 | - |
467 | + |
468 | Window xwindow = gdk_x11_drawable_get_xid (GDK_DRAWABLE (window)); |
469 | |
470 | if (xwindow == 0) |
471 | @@ -236,7 +236,10 @@ |
472 | static gboolean |
473 | initial_resync (PanelService *self) |
474 | { |
475 | - g_signal_emit (self, _service_signals[RE_SYNC], 0, ""); |
476 | + if (PANEL_IS_SERVICE (self)) |
477 | + g_signal_emit (self, _service_signals[RE_SYNC], 0, ""); |
478 | + |
479 | + |
480 | return FALSE; |
481 | } |
482 | |
483 | @@ -264,7 +267,7 @@ |
484 | panel_service_get_default () |
485 | { |
486 | static PanelService *service = NULL; |
487 | - |
488 | + |
489 | if (service == NULL || !PANEL_IS_SERVICE (service)) |
490 | service = g_object_new (PANEL_TYPE_SERVICE, NULL); |
491 | |
492 | @@ -293,13 +296,14 @@ |
493 | |
494 | return g_slist_length (self->priv->indicators); |
495 | } |
496 | - |
497 | + |
498 | /* |
499 | * Private Methods |
500 | */ |
501 | static gboolean |
502 | actually_notify_object (IndicatorObject *object) |
503 | { |
504 | + if (!INDICATOR_IS_OBJECT (object)) return; |
505 | PanelService *self; |
506 | PanelServicePrivate *priv; |
507 | gint position; |
508 | @@ -310,7 +314,7 @@ |
509 | position = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (object), "position")); |
510 | priv->timeouts[position] = SYNC_WAITING; |
511 | |
512 | - if (!suppress_signals); |
513 | + if (!suppress_signals) |
514 | g_signal_emit (self, _service_signals[RE_SYNC], |
515 | 0, g_object_get_data (G_OBJECT (object), "id")); |
516 | |
517 | @@ -392,7 +396,7 @@ |
518 | G_CALLBACK (on_entry_changed), object); |
519 | g_signal_connect (entry->label, "hide", |
520 | G_CALLBACK (on_entry_changed), object); |
521 | - |
522 | + |
523 | } |
524 | if (GTK_IS_IMAGE (entry->image)) |
525 | { |
526 | @@ -452,7 +456,7 @@ |
527 | priv->indicators = g_slist_append (priv->indicators, object); |
528 | |
529 | g_object_set_data_full (G_OBJECT (object), "id", g_strdup (name), g_free); |
530 | - |
531 | + |
532 | g_signal_connect (object, INDICATOR_OBJECT_SIGNAL_ENTRY_ADDED, |
533 | G_CALLBACK (on_entry_added), self); |
534 | g_signal_connect (object, INDICATOR_OBJECT_SIGNAL_ENTRY_REMOVED, |
535 | @@ -535,7 +539,7 @@ |
536 | |
537 | s1 = g_object_get_data (G_OBJECT (o1), "id"); |
538 | s2 = g_object_get_data (G_OBJECT (o2), "id"); |
539 | - |
540 | + |
541 | i1 = name2order (s1); |
542 | i2 = name2order (s2); |
543 | |
544 | @@ -573,7 +577,7 @@ |
545 | GError *error = NULL; |
546 | |
547 | pixbuf = gtk_image_get_pixbuf (image); |
548 | - |
549 | + |
550 | if (gdk_pixbuf_save_to_buffer (pixbuf, &buffer, &buffer_size, "png", &error, NULL)) |
551 | { |
552 | ret = g_base64_encode ((const guchar *)buffer, buffer_size); |
553 | @@ -623,7 +627,7 @@ |
554 | gboolean is_label = GTK_IS_LABEL (entry->label); |
555 | gboolean is_image = GTK_IS_IMAGE (entry->image); |
556 | gchar *image_data = NULL; |
557 | - |
558 | + |
559 | g_variant_builder_add (b, "(sssbbusbb)", |
560 | indicator_id, |
561 | id, |
562 | @@ -729,7 +733,7 @@ |
563 | /* Set the sync back to neutral */ |
564 | position = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (i->data), "position")); |
565 | self->priv->timeouts[position] = SYNC_NEUTRAL; |
566 | - |
567 | + |
568 | indicator_object_to_variant (i->data, indicator_id, &b); |
569 | } |
570 | |
571 | @@ -776,7 +780,7 @@ |
572 | { |
573 | PanelServicePrivate *priv = self->priv; |
574 | IndicatorObjectEntry *entry = g_hash_table_lookup (priv->id2entry_hash, entry_id); |
575 | - |
576 | + |
577 | if (GTK_IS_MENU (priv->last_menu)) |
578 | { |
579 | priv->last_x = 0; |
580 | |
581 | === modified file 'tests/CMakeLists.txt' |
582 | --- tests/CMakeLists.txt 2010-11-24 16:36:23 +0000 |
583 | +++ tests/CMakeLists.txt 2010-11-25 14:26:39 +0000 |
584 | @@ -16,7 +16,7 @@ |
585 | ${TEST_UNIT_DEPS_CFLAGS_OTHER} |
586 | "-DGETTEXT_PACKAGE=\"unity\"" |
587 | "-DINDICATORDIR=\"${CMAKE_BINARY_DIR}/tests\"" |
588 | - "-DINDICATORICONDIR=\"${CMAKE_BINARY_DIR}/tests\"" |
589 | + "-DINDICATORICONDIR=\"${CMAKE_BINARY_DIR}/tests\"" |
590 | ) |
591 | add_definitions (${CFLAGS}) |
592 | |
593 | @@ -35,6 +35,9 @@ |
594 | unit/TestFavoriteStoreGSettings.cpp |
595 | unit/TestPanelService.cpp |
596 | unit/TestMain.cpp |
597 | + unit/TestUBus.cpp |
598 | + ../libunity/ubus-server.c |
599 | + ../libunity/ubus-server.h |
600 | ../services/panel-service.c |
601 | ../services/panel-service.h |
602 | ../src/FavoriteStore.cpp |
603 | |
604 | === modified file 'tests/unit/TestMain.cpp' |
605 | --- tests/unit/TestMain.cpp 2010-11-17 21:38:57 +0000 |
606 | +++ tests/unit/TestMain.cpp 2010-11-25 14:26:39 +0000 |
607 | @@ -24,6 +24,7 @@ |
608 | |
609 | void TestFavoriteStoreGSettingsCreateSuite (void); |
610 | void TestPanelServiceCreateSuite (void); |
611 | +void TestUBusCreateSuite (void); |
612 | |
613 | int |
614 | main (int argc, char **argv) |
615 | @@ -32,12 +33,13 @@ |
616 | |
617 | g_type_init (); |
618 | g_thread_init (NULL); |
619 | - |
620 | + |
621 | g_test_init (&argc, &argv, NULL); |
622 | |
623 | //Keep alphabetical please |
624 | TestFavoriteStoreGSettingsCreateSuite (); |
625 | TestPanelServiceCreateSuite (); |
626 | + TestUBusCreateSuite (); |
627 | |
628 | return g_test_run (); |
629 | } |
630 | |
631 | === added file 'tests/unit/TestUBus.cpp' |
632 | --- tests/unit/TestUBus.cpp 1970-01-01 00:00:00 +0000 |
633 | +++ tests/unit/TestUBus.cpp 2010-11-25 14:26:39 +0000 |
634 | @@ -0,0 +1,152 @@ |
635 | +/* |
636 | + * Copyright 2010 Canonical Ltd. |
637 | + * |
638 | + * This program is free software: you can redistribute it and/or modify it |
639 | + * under the terms of the GNU General Public License version 3, as published |
640 | + * by the Free Software Foundation. |
641 | + * |
642 | + * This program is distributed in the hope that it will be useful, but |
643 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
644 | + * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR |
645 | + * PURPOSE. See the GNU General Public License for more details. |
646 | + * |
647 | + * You should have received a copy of the GNU General Public License |
648 | + * version 3 along with this program. If not, see |
649 | + * <http://www.gnu.org/licenses/> |
650 | + * |
651 | + * Authored by: Gordon Allott <gord.allott@canonical.com> |
652 | + * |
653 | + */ |
654 | + |
655 | + |
656 | +#include "config.h" |
657 | +#include "libunity/ubus-server.h" |
658 | + |
659 | +#define MESSAGE1 "TEST MESSAGE ONE" |
660 | +#define MESSAGE2 "ՄᕅᏆⲤꙨႧΈ Ϊટ ಗשׁຣ໐ɱË‼‼❢" |
661 | + |
662 | +static void TestAllocation (void); |
663 | +static void TestMainLoop (void); |
664 | +static void TestPropagation (void); |
665 | + |
666 | +void |
667 | +TestUBusCreateSuite () |
668 | +{ |
669 | +#define _DOMAIN "/Unit/UBus" |
670 | + g_test_add_func (_DOMAIN"/Allocation", TestAllocation); |
671 | + g_test_add_func (_DOMAIN"/Propagation", TestPropagation); |
672 | + g_test_add_func (_DOMAIN"/MainLoop", TestMainLoop); |
673 | +} |
674 | + |
675 | +static void |
676 | +TestAllocation () |
677 | +{ |
678 | + UBusServer *serv_1 = ubus_server_get_default (); |
679 | + UBusServer *serv_2 = ubus_server_get_default (); |
680 | + |
681 | + g_assert (serv_1 != NULL); |
682 | + g_assert (serv_2 != NULL); |
683 | + |
684 | + // i used a different way of making a singleton than i am used to |
685 | + // so i'm not 100% confident in it yet |
686 | + g_assert (serv_1 == serv_2); |
687 | +} |
688 | + |
689 | +void |
690 | +test_handler_inc_counter (GVariant *data, gpointer *val) |
691 | +{ |
692 | + // inc a counter when we get called |
693 | + gint *counter = (gint*)val; |
694 | + *counter = *counter + 1; |
695 | +} |
696 | + |
697 | +void |
698 | +test_handler_inc_counter_2 (GVariant *data, gpointer *val) |
699 | +{ |
700 | + // inc a counter by two when called |
701 | + gint *counter = (gint*)val; |
702 | + *counter = *counter + 2; |
703 | +} |
704 | + |
705 | +static void |
706 | +TestPropagation () |
707 | +{ |
708 | + UBusServer *ubus = ubus_server_get_default (); |
709 | + gint counter = 0; |
710 | + gulong handler1 = ubus_server_register_interest (ubus, MESSAGE1, |
711 | + test_handler_inc_counter, |
712 | + &counter); |
713 | + |
714 | + gulong handler2 = ubus_server_register_interest (ubus, MESSAGE2, // tests UNICODE |
715 | + test_handler_inc_counter_2, |
716 | + &counter); |
717 | + |
718 | + gint i; |
719 | + for (i=0; i<1000; i++) |
720 | + { |
721 | + ubus_server_send_message (ubus, MESSAGE1, NULL); |
722 | + } |
723 | + |
724 | + ubus_server_force_message_pump (ubus); |
725 | + |
726 | + counter = 0; |
727 | + for (i=0; i<1000; i++) |
728 | + { |
729 | + ubus_server_send_message (ubus, MESSAGE1, NULL); |
730 | + ubus_server_send_message (ubus, MESSAGE2, NULL); |
731 | + } |
732 | + ubus_server_force_message_pump (ubus); |
733 | + |
734 | + g_assert (counter == 3000); |
735 | + |
736 | + ubus_server_unregister_interest (ubus, handler1); |
737 | + ubus_server_unregister_interest (ubus, handler2); |
738 | + |
739 | + counter = 0; |
740 | + ubus_server_send_message (ubus, MESSAGE1, NULL); |
741 | + ubus_server_send_message (ubus, MESSAGE2, NULL); |
742 | + |
743 | + ubus_server_force_message_pump (ubus); |
744 | + |
745 | + g_assert (counter == 0); |
746 | +} |
747 | + |
748 | +gboolean |
749 | +main_loop_bailout (gpointer data) |
750 | +{ |
751 | + GMainLoop *mainloop = (GMainLoop*)data; |
752 | + g_main_quit (mainloop); |
753 | + return FALSE; |
754 | +} |
755 | + |
756 | +void |
757 | +test_handler_mainloop (GVariant *data, gpointer *val) |
758 | +{ |
759 | + // inc a counter when we get called |
760 | + gint *counter = (gint*)val; |
761 | + *counter = *counter + 1; |
762 | + |
763 | +} |
764 | + |
765 | +static void |
766 | +TestMainLoop () |
767 | +{ |
768 | + GMainLoop *mainloop; |
769 | + UBusServer *ubus = ubus_server_get_default (); |
770 | + gint counter = 0; |
771 | + |
772 | + mainloop = g_main_loop_new (NULL, TRUE); |
773 | + g_timeout_add_seconds (1, main_loop_bailout, mainloop); |
774 | + |
775 | + ubus_server_register_interest (ubus, MESSAGE1, |
776 | + test_handler_mainloop, |
777 | + &counter); |
778 | + |
779 | + ubus_server_send_message (ubus, MESSAGE1, NULL); |
780 | + g_main_loop_run (mainloop); |
781 | + |
782 | + g_assert (counter == 1); |
783 | + |
784 | +} |
785 | + |
786 | + |
- g_hash_ table_destroy does what you want it to and won't break if they use g_slice to allocate hashtable struct in the future
- Tab indenting in a bunch of places
- The first server you create has a ref count of 2 because it's not initially unowned (hence returns from g_object_new with ref_count = 1) and then your ref it again before retuning; Maybe make it derive from GInitiallyUnowned and return g_object_ref_sink (service)
- Like the singleton approach, haven't seen that in a while ;)