[california/wip/725786-edit-recurring] Better solution to master/generated instance problem



commit e463b92af715c4f78cc5ca38355d3567ad6bebfa
Author: Jim Nelson <jim yorba org>
Date:   Tue Jul 15 16:27:49 2014 -0700

    Better solution to master/generated instance problem
    
    All masters are now loaded in the backing and associated with their
    generated instances before being injected into the system...this
    alleviates I/O and async issues in the UI, who always have access to
    the masters by virtue of having access to their instances.

 .../backing-calendar-source-subscription.vala      |  101 ++++++++++++++++----
 src/backing/backing-calendar-source.vala           |   13 +--
 .../backing-eds-calendar-source-subscription.vala  |  102 +++++++++++---------
 src/backing/eds/backing-eds-calendar-source.vala   |    2 +-
 src/component/component-instance.vala              |   46 ++++++++-
 src/host/host-create-update-event.vala             |    2 +-
 src/host/host-create-update-recurring.vala         |   25 ++----
 src/host/host-show-event.vala                      |    9 +-
 vapi/libecal-1.2.vapi                              |    3 +-
 vapi/libecal-1.2/libecal-1.2.metadata              |    5 +-
 10 files changed, 202 insertions(+), 106 deletions(-)
---
diff --git a/src/backing/backing-calendar-source-subscription.vala 
b/src/backing/backing-calendar-source-subscription.vala
index 12a1342..bf4fbc4 100644
--- a/src/backing/backing-calendar-source-subscription.vala
+++ b/src/backing/backing-calendar-source-subscription.vala
@@ -9,15 +9,13 @@ namespace California.Backing {
 /**
  * A subscription to an active timespan of interest of a calendar.
  *
- * CalendarSourceSubscription generates { link Component.Instance}s of the various events in a
- * window of time in a calendar.  Note that for recurring events, there is no interface to directly
- * edit or remove the "original" iCalendar source.  Rather, the caller should update or remove
- * generated instances of that recurring event with flags to indicate how the original is to be
- * altered to match these changes.  See { link CalendarSource} for the interface to make these
- * alterations.
+ * The subscription notifies of calendar updates via its signals.  It can list complete or partial
+ * collections of { link Component.Instances} it has reported via those signals.
  *
- * The subscription can notify of calendar event updates and list a complete or partial collections
- * of the same.
+ * CalendarSourceSubscription generates { link Component.Instance}s of the various events in a
+ * window of time in a calendar.  Both master instances and generated recurring instances are
+ * reported through the interface.  Operations performed on instances should be done with the
+ * subscription's { link CalendarSource}.
  */
 
 public abstract class CalendarSourceSubscription : BaseObject {
@@ -50,22 +48,63 @@ public abstract class CalendarSourceSubscription : BaseObject {
     /**
      * Fired as existing { link Component.Instance}s are discovered when starting a subscription.
      *
+     * Like { link instance_added}, this is only fired for master Instances which do not
+     * generate recurring instances and generated Instances.  See { link master_discovered} to
+     * be notified of all master Instances.
+     *
      * This is fired while { link start} is working, either in the foreground or in the background.
      * It won't fire until start() is invoked.
+     *
+     * @see master_discovered
      */
     public signal void instance_discovered(Component.Instance instance);
     
     /**
-     * Indicates that an { link Instance} within the { link window} has been added to the calendar.
+     * Fired as existing master { link Component.Instance}s are discovered when starting a
+     * subscription.
+     *
+     * This is fired for all discovered master Instances whether or not they may generate
+     * Instances for this subscription.
+     *
+     * This is fired while { link start} is working, either in the foreground or in the background.
+     * It won't fire until start() is invoked.
+     *
+     * @see instance_discovered
+     */
+    public signal void master_discovered(Component.Instance instance);
+    
+    /**
+     * Fired when a { link Component.Instance} within the { link window} has been added to the
+     * { link CalendarSource}.
+     *
+     * This is fired only for master Instances which do not generate recurring Instances and for
+     * generated Instances.  See { link master_added} to be notified of all master Instances.
      *
      * The signal is fired for both local additions (added through this interface) and remote
      * additions.
      *
      * This signal won't fire until { link start} is called.
+     *
+     * @see master_added
      */
     public signal void instance_added(Component.Instance instance);
     
     /**
+     * Fired as existing master { link Component.Instance}s are added to the { link CalendarSource}.
+     *
+     * This is fired for all discovered master Instances whether or not they may generate
+     * Instances for this subscription.
+     *
+     * The signal is fired for both local additions (added through this interface) and remote
+     * additions.
+     *
+     * This signal won't fire until { link start} is called.
+     *
+     * @see instance_added
+     */
+    public signal void master_added(Component.Instance instance);
+    
+    /**
      * Indicates that an { link Instance} within the { link date_window} has been removed from the
      * calendar.
      *
@@ -143,10 +182,17 @@ public abstract class CalendarSourceSubscription : BaseObject {
      * @see instance_discovered
      */
     protected virtual void notify_instance_discovered(Component.Instance instance) {
-        if (add_instance(instance))
-            instance_discovered(instance);
-        else
+        if (!add_instance(instance)) {
             debug("Cannot add discovered component %s to %s: already known", instance.to_string(), 
to_string());
+            
+            return;
+        }
+        
+        if (instance.is_master_instance)
+            master_discovered(instance);
+        
+        if (!instance.can_generate_instances)
+            instance_discovered(instance);
     }
     
     /**
@@ -156,10 +202,17 @@ public abstract class CalendarSourceSubscription : BaseObject {
      * @see instance_added
      */
     protected virtual void notify_instance_added(Component.Instance instance) {
-        if (add_instance(instance))
-            instance_added(instance);
-        else
+        if (!add_instance(instance)) {
             debug("Cannot add component %s to %s: already known", instance.to_string(), to_string());
+            
+            return;
+        }
+        
+        if (instance.is_master_instance)
+            master_added(instance);
+        
+        if (!instance.can_generate_instances)
+            instance_added(instance);
     }
     
     /**
@@ -195,13 +248,13 @@ public abstract class CalendarSourceSubscription : BaseObject {
      * Notify that the { link Component.Instance}s have been dropped due to the { link Source} going
      * unavailable.
      */
-    protected virtual void notify_instance_dropped(Component.Instance instance) {
+    protected virtual void notify_instance_dropped(Component.UID uid) {
         Gee.Collection<Component.Instance> removed_instances;
-        if (remove_instance(instance.uid, out removed_instances)) {
+        if (remove_instance(uid, out removed_instances)) {
             foreach (Component.Instance removed_instance in removed_instances)
                 instance_dropped(removed_instance);
         } else {
-            debug("Cannot notify dropped component %s in %s: not known", instance.to_string(), to_string());
+            debug("Cannot notify dropped component %s in %s: not known", uid.to_string(), to_string());
         }
     }
     
@@ -264,7 +317,7 @@ public abstract class CalendarSourceSubscription : BaseObject {
         // the multimap
         debug("Dropping %d instances to %s: unavailable", instances.size, calendar.to_string());
         foreach (Component.Instance instance in instances.get_values().to_array())
-            notify_instance_dropped(instance);
+            notify_instance_dropped(instance.uid);
     }
     
     /**
@@ -285,6 +338,16 @@ public abstract class CalendarSourceSubscription : BaseObject {
     }
     
     /**
+     * Returns the master { link Component.Instance} for the { link Component.UID}.
+     *
+     * @returns null if the UID has not been sene.
+     */
+    public Component.Instance? master_for_uid(Component.UID uid) {
+        return traverse<Component.Instance>(instances.get(uid))
+            .first_matching(instance => instance.is_master_instance);
+    }
+    
+    /**
      * Returns the seen { link Component.Instance} matching the supplied (possibly partially
      * filled-out) Instance.
      *
diff --git a/src/backing/backing-calendar-source.vala b/src/backing/backing-calendar-source.vala
index 895f7cf..7b2fac0 100644
--- a/src/backing/backing-calendar-source.vala
+++ b/src/backing/backing-calendar-source.vala
@@ -95,17 +95,14 @@ public abstract class CalendarSource : Source {
         AffectedInstances affected, Cancellable? cancellable = null) throws Error;
     
     /**
-     * Fetches the master component of an { link Component.Instance}.
+     * Fetches the master component of an { link Component.Instance} by its { link Component.UID}.
      *
-     * If an Instance is recurring, { link CalendarSourceSubscription} produces individual instances
-     * of those recurrences (which therefore lack the rules and information that produce them).
-     * This call allows for the original (or master) component to be retrieved.
-     *
-     * If the instance is not recurring, the returned Instance will be identical (or near-identical)
-     * to the one produced by CalendarSourceSubscription.
+     * Unlike master instances generated by a { link CalendarSourceSubscription}, there instance
+     * is not tracked by the { link CalendarSource} and will not be updated as it is update
+     * elsewhere, either locally or remotely.
      *
      * @see Component.Instance.is_recurring_instance
-     * @throws An Error if the { link Component.UID} is unknown to the { link CalendarSource},
+     * @throws An Error if the { link Component.UID} is unknown to the CalendarSource,
      * as well as for the sundry I/O errors and such.
      */
     public abstract async Component.Instance fetch_master_component_async(Component.UID uid,
diff --git a/src/backing/eds/backing-eds-calendar-source-subscription.vala 
b/src/backing/eds/backing-eds-calendar-source-subscription.vala
index b3003a6..30a314f 100644
--- a/src/backing/eds/backing-eds-calendar-source-subscription.vala
+++ b/src/backing/eds/backing-eds-calendar-source-subscription.vala
@@ -11,17 +11,21 @@ namespace California.Backing {
  */
 
 internal class EdsCalendarSourceSubscription : CalendarSourceSubscription {
+    private delegate void InstanceNotifier(Component.Instance instance);
+    
     private E.CalClientView view;
+    private string sexp;
     // this is different than "active", which gets set when start completes
     private bool started = false;
     private Error? start_err = null;
     
     // Called from EdsCalendarSource.subscribe_async().  The CalClientView should not be started
     public EdsCalendarSourceSubscription(EdsCalendarSource eds_calendar, Calendar.ExactTimeSpan window,
-        E.CalClientView view) {
+        E.CalClientView view, string sexp) {
         base (eds_calendar, window);
         
         this.view = view;
+        this.sexp = sexp;
     }
     
     ~EdsCalendarSourceSubscription() {
@@ -82,36 +86,36 @@ internal class EdsCalendarSourceSubscription : CalendarSourceSubscription {
         // next
         view.start();
         
-        // prime with the list of known events
-        view.client.generate_instances(
-            window.start_exact_time.to_time_t(),
-            window.end_exact_time.to_time_t(),
-            cancellable,
-            on_instance_generated,
-            on_generate_finished);
+        discovery_async.begin(cancellable);
     }
     
-    private bool on_instance_generated(E.CalComponent eds_component, time_t instance_start,
-        time_t instance_end) {
+    private async void discovery_async(Cancellable? cancellable) {
+        SList<unowned iCal.icalcomponent> ical_components;
         try {
-            Component.Event? event = Component.Instance.convert(calendar, eds_component.get_icalcomponent())
-                as Component.Event;
-            if (event != null)
-                notify_instance_discovered(event);
+            yield view.client.get_object_list(sexp, cancellable, out ical_components);
         } catch (Error err) {
-            debug("Unable to generate discovered event for %s: %s", to_string(), err.message);
+            start_err = err;
+            
+            start_failed(err);
+            
+            return;
         }
         
-        return true;
-    }
-    
-    private void on_generate_finished() {
+        // process all known objects within the sexp range
+        on_objects_discovered_added(ical_components, notify_instance_discovered);
+        
         // only set when generation (start) is finished
         active = true;
     }
     
-    private void on_objects_added(SList<weak iCal.icalcomponent> objects) {
-        foreach (weak iCal.icalcomponent ical_component in objects) {
+    private void on_objects_added(SList<unowned iCal.icalcomponent> ical_components) {
+        // process all added objects
+        on_objects_discovered_added(ical_components, notify_instance_added);
+    }
+    
+    private void on_objects_discovered_added(SList<unowned iCal.icalcomponent> ical_components,
+        InstanceNotifier notifier) {
+        foreach (unowned iCal.icalcomponent ical_component in ical_components) {
             if (String.is_empty(ical_component.get_uid()))
                 continue;
             
@@ -121,47 +125,53 @@ internal class EdsCalendarSourceSubscription : CalendarSourceSubscription {
             if (has_uid(uid))
                 notify_instance_removed(uid);
             
-            // if no recurrences, add this alone
-            if (!E.Util.component_has_recurrences(ical_component)) {
-                add_instance(ical_component);
-                
+            // add all instances, master and generated
+            Component.Instance? master = add_instance(null, ical_component, notifier);
+            if (master == null)
+                continue;
+            
+            // if no recurrences, done
+            if (!E.Util.component_has_recurrences(ical_component))
                 continue;
-            }
             
             // generate recurring instances
-            view.client.generate_instances_for_object(
+            view.client.generate_instances_for_object_sync(
                 ical_component,
                 window.start_exact_time.to_time_t(),
                 window.end_exact_time.to_time_t(),
-                null,
-                on_instance_added,
-                null);
+                (eds_component, start, end) => {
+                    add_instance(master, eds_component.get_icalcomponent(), notifier);
+                    
+                    return true;
+                }
+            );
         }
     }
     
-    private bool on_instance_added(E.CalComponent eds_component, time_t instance_start,
-        time_t instance_end) {
-        add_instance(eds_component.get_icalcomponent());
-        
-        return true;
-    }
-    
     // Assumes all existing events with UID/RID have been removed already
-    private void add_instance(iCal.icalcomponent ical_component) {
+    private Component.Instance? add_instance(Component.Instance? master, iCal.icalcomponent ical_component,
+        InstanceNotifier notifier) {
         // convert the added component into a new Event
-        Component.Event? added_event;
+        Component.Event? added_event = null;
         try {
             added_event = Component.Instance.convert(calendar, ical_component) as Component.Event;
-            if (added_event != null)
-                notify_instance_added(added_event);
+            if (added_event != null) {
+                // assign the master (if this isn't the master already)
+                added_event.master = master;
+                
+                // notify of didscovery/addition
+                notifier(added_event);
+            }
         } catch (Error err) {
             debug("Unable to process added event: %s", err.message);
         }
+        
+        return added_event;
     }
     
-    private void on_objects_modified(SList<weak iCal.icalcomponent> objects) {
-        SList<weak iCal.icalcomponent> add_list = new SList<weak iCal.icalcomponent>();
-        foreach (weak iCal.icalcomponent ical_component in objects) {
+    private void on_objects_modified(SList<unowned iCal.icalcomponent> ical_components) {
+        SList<unowned iCal.icalcomponent> add_list = new SList<unowned iCal.icalcomponent>();
+        foreach (unowned iCal.icalcomponent ical_component in ical_components) {
             // if not an instance and has recurring, treat as an add (which removes and adds generated
             // instances)
             if (!E.Util.component_is_instance(ical_component) && 
E.Util.component_has_recurrences(ical_component)) {
@@ -207,8 +217,8 @@ internal class EdsCalendarSourceSubscription : CalendarSourceSubscription {
         on_objects_added(add_list);
     }
     
-    private void on_objects_removed(SList<weak E.CalComponentId?> ids) {
-        foreach (weak E.CalComponentId id in ids)
+    private void on_objects_removed(SList<unowned E.CalComponentId?> ids) {
+        foreach (unowned E.CalComponentId id in ids)
             notify_instance_removed(new Component.UID(id.uid));
     }
 }
diff --git a/src/backing/eds/backing-eds-calendar-source.vala 
b/src/backing/eds/backing-eds-calendar-source.vala
index eb1e2a9..92a7b1c 100644
--- a/src/backing/eds/backing-eds-calendar-source.vala
+++ b/src/backing/eds/backing-eds-calendar-source.vala
@@ -135,7 +135,7 @@ internal class EdsCalendarSource : CalendarSource {
         E.CalClientView view;
         yield client.get_view(sexp, cancellable, out view);
         
-        return new EdsCalendarSourceSubscription(this, window, view);
+        return new EdsCalendarSourceSubscription(this, window, view, sexp);
     }
     
     public override async Component.UID? create_component_async(Component.Instance instance,
diff --git a/src/component/component-instance.vala b/src/component/component-instance.vala
index 35e6581..4154669 100644
--- a/src/component/component-instance.vala
+++ b/src/component/component-instance.vala
@@ -32,6 +32,7 @@ public abstract class Instance : BaseObject, Gee.Hashable<Instance> {
     public const string PROP_RRULE = "rrule";
     public const string PROP_RID = "rid";
     public const string PROP_SEQUENCE = "sequence";
+    public const string PROP_MASTER = "master";
     
     protected const string PROP_IN_FULL_UPDATE = "in-full-update";
     
@@ -78,12 +79,49 @@ public abstract class Instance : BaseObject, Gee.Hashable<Instance> {
     public Component.DateTime? rid { get; set; default = null; }
     
     /**
-     * Returns true if the { link Recurrable} is in fact a recurring instance.
+     * Returns true if the { link Instance} is a master instance.
+     *
+     * A master instance is one that has not been generated from another Instance's recurring
+     * rule (RRULE).  In practice, this means the Instance does not have a RECURRENCE-ID.
+     *
+     * @see rid
+     * @see rrule
+     */
+    public bool is_master_instance { get { return rid == null; } }
+    
+    /**
+     * Returns true if the { link Instance} is a generated recurring instance.
+     *
+     * A generated recurring instance is one that has been artificially constructed from another
+     * Instance's recurring rule (RRULE).  In practice, this means the Instance has a
+     * RECURRENCE-ID.
+     *
+     * @see rid
+     * @see Backing.CalendarSource.fetch_master_component_async
+     */
+    public bool is_generated_instance { get { return rid != null; } }
+    
+    /**
+     * Returns true if the master { link Instance} can generate recurring instances.
+     *
+     * This indicates the Instance is a master Instance and can generate recurring instances from
+     * its RRULE.  In practice, this means the Instance has no RECURRENCE-ID but does have an
+     * RRULE.  (Generated instances will have the RRULE that construct them as well as a
+     * RECURRENCE-ID.)
      *
      * @see rid
      * @see Backing.CalendarSource.fetch_master_component_async
      */
-    public bool is_recurring_instance { get { return rid != null; } }
+    public bool can_generate_instances { get { return rid == null && rrule != null; } }
+    
+    /**
+     * If a generated { link Instance}, holds a reference to the master Instance that generated it.
+     *
+     * The { link Backing} should do everything it can to provide a master Instance for all
+     * generated Instances.  However, if this is null it is not a guarantee this is a master
+     * Instance.  Use { link is_master_instance}.
+     */
+    public Instance? master { get; internal set; default = null; }
     
     /**
      * The SEQUENCE of a VEVENT, VTODO, or VJOURNAL.
@@ -421,10 +459,10 @@ public abstract class Instance : BaseObject, Gee.Hashable<Instance> {
         if (this == other)
             return true;
         
-        if (is_recurring_instance != other.is_recurring_instance)
+        if (is_generated_instance != other.is_generated_instance)
             return false;
         
-        if (is_recurring_instance && !rid.equal_to(other.rid))
+        if (is_generated_instance && !rid.equal_to(other.rid))
             return false;
         
         if (sequence != other.sequence)
diff --git a/src/host/host-create-update-event.vala b/src/host/host-create-update-event.vala
index 095e693..2f5d3be 100644
--- a/src/host/host-create-update-event.vala
+++ b/src/host/host-create-update-event.vala
@@ -283,7 +283,7 @@ public class CreateUpdateEvent : Gtk.Grid, Toolkit.Card {
             return;
         
         // if updating a recurring event, need to ask about update scope
-        if (event.is_recurring_instance && is_update) {
+        if (event.is_generated_instance && is_update) {
             rotating_button_box.family = FAMILY_RECURRING;
             
             return;
diff --git a/src/host/host-create-update-recurring.vala b/src/host/host-create-update-recurring.vala
index 7c4ba87..9e42a74 100644
--- a/src/host/host-create-update-recurring.vala
+++ b/src/host/host-create-update-recurring.vala
@@ -160,24 +160,8 @@ public class CreateUpdateRecurring : Gtk.Grid, Toolkit.Card {
         // *must* have an Event by this point, whether from before or due to this jump
         assert(event != null);
         
-        // need to load the master component in order to update the RRULE (which isn't stored in
-        // the generated instances)
-        load_master_async.begin();
-    }
-    
-    private async void load_master_async() {
-        try {
-            Component.Instance master_instance = yield event.calendar_source.fetch_master_component_async(
-                event.uid, null);
-            master = master_instance as Component.Event;
-        } catch (Error err) {
-            debug("Unable to load master from %s: %s", event.calendar_source.to_string(),
-                err.message);
-            
-            master = null;
-        }
-        
-        if (master == null) {
+        // need to use the master component in order to update the master RRULE
+        if (!can_update_recurring(event)) {
             jump_back();
             
             return;
@@ -186,7 +170,12 @@ public class CreateUpdateRecurring : Gtk.Grid, Toolkit.Card {
         update_controls();
     }
     
+    public static bool can_update_recurring(Component.Event event) {
+        return event.is_master_instance || (event.master is Component.Event);
+    }
+    
     private void update_controls() {
+        master = (event.is_master_instance ? event : event.master) as Component.Event;
         assert(master != null);
         
         make_recurring_checkbutton.active = (master.rrule != null);
diff --git a/src/host/host-show-event.vala b/src/host/host-show-event.vala
index c647be4..b20bc33 100644
--- a/src/host/host-show-event.vala
+++ b/src/host/host-show-event.vala
@@ -86,13 +86,10 @@ public class ShowEvent : Gtk.Grid, Toolkit.Card {
         // description
         set_label(null, description_text, Markup.linkify(escape(event.description), linkify_delegate));
         
-        // don't current support updating recurring events properly; see
-        // https://bugzilla.gnome.org/show_bug.cgi?id=725786
         bool read_only = event.calendar_source != null && event.calendar_source.read_only;
         
-        bool updatable = !event.is_recurring_instance && !read_only;
-        update_button.visible = updatable;
-        update_button.no_show_all = updatable;
+        update_button.visible = !read_only;
+        update_button.no_show_all = !read_only;
         
         remove_button.visible = !read_only;
         remove_button.no_show_all = !read_only;
@@ -142,7 +139,7 @@ public class ShowEvent : Gtk.Grid, Toolkit.Card {
         //
         // TODO: Gtk.Stack would be a better widget for this animation, but it's unavailable in
         // Glade as of GTK+ 3.12.
-        if (event.is_recurring_instance) {
+        if (event.is_generated_instance) {
             button_box_revealer.reveal_child = false;
             remove_recurring_revealer.reveal_child = true;
             
diff --git a/vapi/libecal-1.2.vapi b/vapi/libecal-1.2.vapi
index 4d9a21a..d692d2e 100644
--- a/vapi/libecal-1.2.vapi
+++ b/vapi/libecal-1.2.vapi
@@ -53,7 +53,8 @@ namespace E {
                public unowned string get_local_attachment_store ();
                [CCode (finish_name = "e_cal_client_get_object_finish")]
                public async void get_object (string uid, string? rid, GLib.Cancellable? cancellable, out 
iCal.icalcomponent out_icalcomp) throws GLib.Error;
-               public async bool get_object_list (string sexp, GLib.Cancellable? cancellable) throws 
GLib.Error;
+               [CCode (finish_name = "e_cal_client_get_object_list_finish")]
+               public async bool get_object_list (string sexp, GLib.Cancellable? cancellable, out 
GLib.SList<weak iCal.icalcomponent> out_icalcomps) throws GLib.Error;
                public async bool get_object_list_as_comps (string sexp, GLib.Cancellable? cancellable) 
throws GLib.Error;
                public bool get_object_list_as_comps_sync (string sexp, GLib.SList out_ecalcomps, 
GLib.Cancellable? cancellable) throws GLib.Error;
                public bool get_object_list_sync (string sexp, GLib.SList out_icalcomps, GLib.Cancellable? 
cancellable) throws GLib.Error;
diff --git a/vapi/libecal-1.2/libecal-1.2.metadata b/vapi/libecal-1.2/libecal-1.2.metadata
index e93a428..2577912 100644
--- a/vapi/libecal-1.2/libecal-1.2.metadata
+++ b/vapi/libecal-1.2/libecal-1.2.metadata
@@ -89,9 +89,10 @@ e_cal_client_get_object.cancellable nullable="1"
 e_cal_client_get_object_finish type_name="void"
 e_cal_client_get_object_finish.out_icalcomp is_out="1" transfer_ownership="1"
 
-e_cal_client_get_object_list async="1"
+e_cal_client_get_object_list async="1" finish_name="e_cal_client_get_object_list_finish"
 e_cal_client_get_object_list.cancellable nullable="1"
-e_cal_client_get_object_list_finish.icalcomps is_out="1" value_owned="1" type_arguments="iCal.icalcomponent"
+
+e_cal_client_get_object_list_finish.out_icalcomps is_out="1" transfer_ownership="1" type_arguments="unowned 
iCal.icalcomponent"
 
 e_cal_client_get_object_list_as_comps async="1"
 e_cal_client_get_object_list_as_comps.cancellable nullable="1"


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]