diff options
author | Dan Winship <danw@src.gnome.org> | 2003-01-20 22:18:38 +0800 |
---|---|---|
committer | Dan Winship <danw@src.gnome.org> | 2003-01-20 22:18:38 +0800 |
commit | 6974f9169918ed0145d93f276a6165e0189daec4 (patch) | |
tree | 1b6861d739f03629e42b867ba2dd5b6e2286c7a8 /calendar/pcs/cal-backend.c | |
parent | dd5c34148a1d8f8170c0ba5b2033cbfd67e78a5c (diff) | |
download | gsoc2013-evolution-6974f9169918ed0145d93f276a6165e0189daec4.tar.gz gsoc2013-evolution-6974f9169918ed0145d93f276a6165e0189daec4.tar.zst gsoc2013-evolution-6974f9169918ed0145d93f276a6165e0189daec4.zip |
Move some non-file-backend-specific stuff from cal-backend-file here so it
* pcs/cal-backend.c: Move some non-file-backend-specific stuff
from cal-backend-file here so it can be shared with other
backends.
(CalBackendPrivate): add this, containing the categories hashes
and the (formerly public) clients list.
(cal_backend_init, cal_backend_finalize): Handle backend->priv.
(cal_destroy_cb): Simplify this (and redo it as a weak notify
func)
(cal_backend_add_cal): Keep a weak ref on the cal rather than
connecting to its "destroy" signal. Call notify_categories_changed
to let the new cal know about them.
(get_object): Default implementation of cal_backend_get_object.
that calls cal_component_get_as_string on the return value of
cal_backend_get_object_component.
(cal_backend_notify_mode, cal_backend_notify_update,
cal_backend_notify_remove, cal_backend_notify_error): Notify each
Cal about something.
(cal_backend_ref_categories, cal_backend_unref_categories):
Maintain a list of categories that are used by components in the
backend, and trigger categories_changed notifications as needed.
* pcs/cal-backend-file.c: Remove stuff that was moved to
CalBackend (notify funcs, category handling, get_object
implementation)
svn path=/trunk/; revision=19524
Diffstat (limited to 'calendar/pcs/cal-backend.c')
-rw-r--r-- | calendar/pcs/cal-backend.c | 373 |
1 files changed, 336 insertions, 37 deletions
diff --git a/calendar/pcs/cal-backend.c b/calendar/pcs/cal-backend.c index 876ef0d5ec..f797f3f67d 100644 --- a/calendar/pcs/cal-backend.c +++ b/calendar/pcs/cal-backend.c @@ -32,6 +32,29 @@ +/* A category that exists in some of the objects of the calendar */ +typedef struct { + /* Category name, also used as the key in the categories hash table */ + char *name; + + /* Number of objects that have this category */ + int refcount; +} CalBackendCategory; + +/* Private part of the CalBackend structure */ +struct _CalBackendPrivate { + /* List of Cal objects with their listeners */ + GList *clients; + + /* Hash table of live categories, temporary hash of + * added/removed categories, and idle handler for sending + * category_changed. + */ + GHashTable *categories; + GHashTable *changed_categories; + guint category_idle_id; +}; + /* Signal IDs */ enum { LAST_CLIENT_GONE, @@ -41,13 +64,20 @@ enum { OBJ_REMOVED, LAST_SIGNAL }; +static guint cal_backend_signals[LAST_SIGNAL]; static void cal_backend_class_init (CalBackendClass *class); +static void cal_backend_init (CalBackend *backend); +static void cal_backend_finalize (GObject *object); -static guint cal_backend_signals[LAST_SIGNAL]; +static char *get_object (CalBackend *backend, const char *uid); + +static void notify_categories_changed (CalBackend *backend); #define CLASS(backend) (CAL_BACKEND_CLASS (G_OBJECT_GET_CLASS (backend))) +static GObjectClass *parent_class; + /** @@ -73,7 +103,7 @@ cal_backend_get_type (void) NULL, NULL, sizeof (CalBackend), 0, - (GInstanceInitFunc) NULL + (GInstanceInitFunc) cal_backend_init, }; cal_backend_type = g_type_register_static (G_TYPE_OBJECT, "CalBackend", &info, 0); } @@ -87,6 +117,8 @@ cal_backend_class_init (CalBackendClass *class) { GObjectClass *object_class; + parent_class = (GObjectClass *) g_type_class_peek_parent (class); + object_class = (GObjectClass *) class; cal_backend_signals[LAST_CLIENT_GONE] = @@ -134,6 +166,8 @@ cal_backend_class_init (CalBackendClass *class) G_TYPE_NONE, 1, G_TYPE_STRING); + object_class->finalize = cal_backend_finalize; + class->last_client_gone = NULL; class->opened = NULL; class->obj_updated = NULL; @@ -148,7 +182,7 @@ cal_backend_class_init (CalBackendClass *class) class->get_mode = NULL; class->set_mode = NULL; class->get_n_objects = NULL; - class->get_object = NULL; + class->get_object = get_object; class->get_object_component = NULL; class->get_timezone_object = NULL; class->get_uids = NULL; @@ -162,6 +196,51 @@ cal_backend_class_init (CalBackendClass *class) class->send_object = NULL; } +/* Object initialization func for the calendar backend */ +void +cal_backend_init (CalBackend *backend) +{ + CalBackendPrivate *priv; + + priv = g_new0 (CalBackendPrivate, 1); + backend->priv = priv; + + priv->categories = g_hash_table_new (g_str_hash, g_str_equal); + priv->changed_categories = g_hash_table_new (g_str_hash, g_str_equal); +} + +/* Used from g_hash_table_foreach(), frees a CalBackendCategory structure */ +static void +free_category_cb (gpointer key, gpointer value, gpointer data) +{ + CalBackendCategory *c = value; + + g_free (c->name); + g_free (c); +} + +void +cal_backend_finalize (GObject *object) +{ + CalBackend *backend = (CalBackend *)object; + CalBackendPrivate *priv; + + priv = backend->priv; + + g_assert (priv->clients == NULL); + + g_hash_table_foreach (priv->categories, free_category_cb, NULL); + g_hash_table_destroy (priv->categories); + + g_hash_table_foreach (priv->changed_categories, free_category_cb, NULL); + g_hash_table_destroy (priv->changed_categories); + + if (priv->category_idle_id) + g_source_remove (priv->category_idle_id); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + /** @@ -204,37 +283,17 @@ cal_backend_get_email_address (CalBackend *backend) /* Callback used when a Cal is destroyed */ static void -cal_destroy_cb (GObject *object, gpointer data) +cal_destroy_cb (gpointer data, GObject *where_cal_was) { - Cal *cal; - Cal *lcal; - CalBackend *backend; - GList *l; - - cal = CAL (object); + CalBackend *backend = CAL_BACKEND (data); + CalBackendPrivate *priv = backend->priv; - backend = CAL_BACKEND (data); - - /* Find the cal in the list of clients */ - - for (l = backend->clients; l; l = l->next) { - lcal = CAL (l->data); - - if (lcal == cal) - break; - } - - g_assert (l != NULL); - - /* Disconnect */ - - backend->clients = g_list_remove_link (backend->clients, l); - g_list_free_1 (l); + priv->clients = g_list_remove (priv->clients, where_cal_was); /* When all clients go away, notify the parent factory about it so that * it may decide whether to kill the backend or not. */ - if (!backend->clients) + if (!priv->clients) cal_backend_last_client_gone (backend); } @@ -249,22 +308,25 @@ cal_destroy_cb (GObject *object, gpointer data) void cal_backend_add_cal (CalBackend *backend, Cal *cal) { + CalBackendPrivate *priv = backend->priv; + g_return_if_fail (backend != NULL); g_return_if_fail (IS_CAL_BACKEND (backend)); g_return_if_fail (IS_CAL (cal)); - /* we do not keep a reference to the Cal since the Calendar - * user agent owns it */ - g_signal_connect (G_OBJECT (cal), "destroy", - G_CALLBACK (cal_destroy_cb), - backend); + /* we do not keep a (strong) reference to the Cal since the + * Calendar user agent owns it */ + g_object_weak_ref (G_OBJECT (cal), cal_destroy_cb, backend); - backend->clients = g_list_prepend (backend->clients, cal); + priv->clients = g_list_prepend (priv->clients, cal); + + /* Tell the new client about the list of categories. + * (Ends up telling all the other clients too, but *shrug*.) + */ + notify_categories_changed (backend); /* notify backend that a new Cal has been added */ - g_signal_emit (G_OBJECT (backend), - cal_backend_signals[CAL_ADDED], - 0, cal); + g_signal_emit (backend, cal_backend_signals[CAL_ADDED], 0, cal); } /** @@ -426,6 +488,19 @@ cal_backend_get_n_objects (CalBackend *backend, CalObjType type) return (* CLASS (backend)->get_n_objects) (backend, type); } +/* Default cal_backend_get_object implementation */ +static char * +get_object (CalBackend *backend, const char *uid) +{ + CalComponent *comp; + + comp = cal_backend_get_object_component (backend, uid); + if (!comp) + return NULL; + + return cal_component_get_as_string (comp); +} + /** * cal_backend_get_object: * @backend: A calendar backend. @@ -902,3 +977,227 @@ cal_backend_set_default_timezone (CalBackend *backend, const char *tzid) return (* CLASS (backend)->set_default_timezone) (backend, tzid); } + +/** + * cal_backend_notify_mode: + * @backend: A calendar backend. + * @status: Status of the mode set + * @mode: the current mode + * + * Notifies each of the backend's listeners about the results of a + * setMode call. + **/ +void +cal_backend_notify_mode (CalBackend *backend, + GNOME_Evolution_Calendar_Listener_SetModeStatus status, + GNOME_Evolution_Calendar_CalMode mode) +{ + CalBackendPrivate *priv = backend->priv; + GList *l; + + for (l = priv->clients; l; l = l->next) + cal_notify_mode (l->data, status, mode); +} + +/** + * cal_backend_notify_update: + * @backend: A calendar backend. + * @uid: UID of object that was updated. + * + * Notifies each of the backend's listeners about an update to a + * calendar object. + **/ +void +cal_backend_notify_update (CalBackend *backend, const char *uid) +{ + CalBackendPrivate *priv = backend->priv; + GList *l; + + cal_backend_obj_updated (backend, uid); + for (l = priv->clients; l; l = l->next) + cal_notify_update (l->data, uid); +} + +/** + * cal_backend_notify_remove: + * @backend: A calendar backend. + * @uid: UID of object that was removed. + * + * Notifies each of the backend's listeners about a calendar object + * that was removed. + **/ +void +cal_backend_notify_remove (CalBackend *backend, const char *uid) +{ + CalBackendPrivate *priv = backend->priv; + GList *l; + + cal_backend_obj_removed (backend, uid); + for (l = priv->clients; l; l = l->next) + cal_notify_remove (l->data, uid); +} + +/** + * cal_backend_notify_error: + * @backend: A calendar backend. + * @message: Error message + * + * Notifies each of the backend's listeners about an error + **/ +void +cal_backend_notify_error (CalBackend *backend, const char *message) +{ + CalBackendPrivate *priv = backend->priv; + GList *l; + + for (l = priv->clients; l; l = l->next) + cal_notify_error (l->data, message); +} + +static void +add_category_cb (gpointer name, gpointer category, gpointer data) +{ + GNOME_Evolution_Calendar_StringSeq *seq = data; + + seq->_buffer[seq->_length++] = CORBA_string_dup (name); +} + +static void +notify_categories_changed (CalBackend *backend) +{ + CalBackendPrivate *priv = backend->priv; + GNOME_Evolution_Calendar_StringSeq *seq; + GList *l; + + /* Build the sequence of category names */ + seq = GNOME_Evolution_Calendar_StringSeq__alloc (); + seq->_length = 0; + seq->_maximum = g_hash_table_size (priv->categories); + seq->_buffer = CORBA_sequence_CORBA_string_allocbuf (seq->_maximum); + CORBA_sequence_set_release (seq, TRUE); + + g_hash_table_foreach (priv->categories, add_category_cb, seq); + + /* Notify the clients */ + for (l = priv->clients; l; l = l->next) + cal_notify_categories_changed (l->data, seq); + + CORBA_free (seq); +} + +static gboolean +prune_changed_categories (gpointer key, gpointer value, gpointer data) +{ + CalBackendCategory *category = value; + + if (!category->refcount) { + g_free (category->name); + g_free (category); + } + return TRUE; +} + +static gboolean +idle_notify_categories_changed (gpointer data) +{ + CalBackend *backend = CAL_BACKEND (data); + CalBackendPrivate *priv = backend->priv; + + if (g_hash_table_size (priv->changed_categories)) { + notify_categories_changed (backend); + g_hash_table_foreach_remove (priv->changed_categories, prune_changed_categories, NULL); + } + return FALSE; +} + +/** + * cal_backend_ref_categories: + * @backend: A calendar backend + * @categories: a list of categories + * + * Adds 1 to the refcount of each of the named categories. If any of + * the categories are new, clients will be notified of the updated + * category list at idle time. + **/ +void +cal_backend_ref_categories (CalBackend *backend, GSList *categories) +{ + CalBackendPrivate *priv; + CalBackendCategory *c; + const char *name; + + priv = backend->priv; + + while (categories) { + name = categories->data; + c = g_hash_table_lookup (priv->categories, name); + + if (c) + c->refcount++; + else { + /* See if it was recently removed */ + + c = g_hash_table_lookup (priv->changed_categories, name); + if (c && c->refcount == 0) { + /* Move it back to the set of live categories */ + g_hash_table_remove (priv->changed_categories, c->name); + + c->refcount = 1; + g_hash_table_insert (priv->categories, c->name, c); + } else { + /* Create a new category */ + c = g_new (CalBackendCategory, 1); + c->name = g_strdup (name); + c->refcount = 1; + g_hash_table_insert (priv->categories, c->name, c); + g_hash_table_insert (priv->changed_categories, c->name, c); + } + } + + categories = categories->next; + } + + if (g_hash_table_size (priv->changed_categories) && + !priv->category_idle_id) + priv->category_idle_id = g_idle_add (idle_notify_categories_changed, backend); +} + +/** + * cal_backend_unref_categories: + * @backend: A calendar backend + * @categories: a list of categories + * + * Subtracts 1 from the refcount of each of the named categories. If + * any of the refcounts go down to 0, clients will be notified of the + * updated category list at idle time. + **/ +void +cal_backend_unref_categories (CalBackend *backend, GSList *categories) +{ + CalBackendPrivate *priv; + CalBackendCategory *c; + const char *name; + + priv = backend->priv; + + while (categories) { + name = categories->data; + c = g_hash_table_lookup (priv->categories, name); + + if (c) { + g_assert (c != NULL); + g_assert (c->refcount > 0); + + c->refcount--; + + if (c->refcount == 0) { + g_hash_table_remove (priv->categories, c->name); + g_hash_table_insert (priv->changed_categories, c->name, c); + } + } + } + + if (g_hash_table_size (priv->changed_categories) && + !priv->category_idle_id) + priv->category_idle_id = g_idle_add (idle_notify_categories_changed, backend); +} |