calendar-server: Improve performance by properly using ECalClientView
The previous code always restarted whole ECalClientView when it received any changes in it, which could sometimes lead to constant repeated restarts of the view. https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/1875
This commit is contained in:
parent
30d902f898
commit
c00d79bae2
@ -1,12 +1,19 @@
|
|||||||
<node>
|
<node>
|
||||||
<interface name="org.gnome.Shell.CalendarServer">
|
<interface name="org.gnome.Shell.CalendarServer">
|
||||||
<method name="GetEvents">
|
<method name="SetTimeRange">
|
||||||
<arg type="x" direction="in" />
|
<arg type="x" name="since" direction="in"/>
|
||||||
<arg type="x" direction="in" />
|
<arg type="x" name="until" direction="in"/>
|
||||||
<arg type="b" direction="in" />
|
<arg type="b" name="force_reload" direction="in"/>
|
||||||
<arg type="a(sssbxxa{sv})" direction="out" />
|
|
||||||
</method>
|
</method>
|
||||||
|
<signal name="EventsAddedOrUpdated">
|
||||||
|
<arg type="a(ssbxxa{sv})" name="events" direction="out"/>
|
||||||
|
</signal>
|
||||||
|
<signal name="EventsRemoved">
|
||||||
|
<arg type="as" name="ids" direction="out"/>
|
||||||
|
</signal>
|
||||||
|
<signal name="ClientDisappeared">
|
||||||
|
<arg type="s" name="source_uid" direction="out"/>
|
||||||
|
</signal>
|
||||||
<property name="HasCalendars" type="b" access="read" />
|
<property name="HasCalendars" type="b" access="read" />
|
||||||
<signal name="Changed" />
|
|
||||||
</interface>
|
</interface>
|
||||||
</node>
|
</node>
|
||||||
|
@ -222,7 +222,12 @@ class DBusEventSource extends EventSourceBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._dbusProxy.connectSignal('Changed', this._onChanged.bind(this));
|
this._dbusProxy.connectSignal('EventsAddedOrUpdated',
|
||||||
|
this._onEventsAddedOrUpdated.bind(this));
|
||||||
|
this._dbusProxy.connectSignal('EventsRemoved',
|
||||||
|
this._onEventsRemoved.bind(this));
|
||||||
|
this._dbusProxy.connectSignal('ClientDisappeared',
|
||||||
|
this._onClientDisappeared.bind(this));
|
||||||
|
|
||||||
this._dbusProxy.connect('notify::g-name-owner', () => {
|
this._dbusProxy.connect('notify::g-name-owner', () => {
|
||||||
if (this._dbusProxy.g_name_owner)
|
if (this._dbusProxy.g_name_owner)
|
||||||
@ -258,7 +263,7 @@ class DBusEventSource extends EventSourceBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_resetCache() {
|
_resetCache() {
|
||||||
this._events = [];
|
this._events = new Map();
|
||||||
this._lastRequestBegin = null;
|
this._lastRequestBegin = null;
|
||||||
this._lastRequestEnd = null;
|
this._lastRequestEnd = null;
|
||||||
}
|
}
|
||||||
@ -274,27 +279,46 @@ class DBusEventSource extends EventSourceBase {
|
|||||||
this.emit('changed');
|
this.emit('changed');
|
||||||
}
|
}
|
||||||
|
|
||||||
_onChanged() {
|
_onEventsAddedOrUpdated(dbusProxy, nameOwner, argArray) {
|
||||||
this._loadEvents(false);
|
const [appointments = []] = argArray;
|
||||||
}
|
let changed = false;
|
||||||
|
|
||||||
_onEventsReceived(results, _error) {
|
|
||||||
let newEvents = [];
|
|
||||||
let appointments = results[0] || [];
|
|
||||||
for (let n = 0; n < appointments.length; n++) {
|
for (let n = 0; n < appointments.length; n++) {
|
||||||
let a = appointments[n];
|
const [id, summary, allDay, startTime, endTime] = appointments[n];
|
||||||
let date = new Date(a[4] * 1000);
|
const date = new Date(startTime * 1000);
|
||||||
let end = new Date(a[5] * 1000);
|
const end = new Date(endTime * 1000);
|
||||||
let id = a[0];
|
|
||||||
let summary = a[1];
|
|
||||||
let allDay = a[3];
|
|
||||||
let event = new CalendarEvent(id, date, end, summary, allDay);
|
let event = new CalendarEvent(id, date, end, summary, allDay);
|
||||||
newEvents.push(event);
|
this._events.set(event.id, event);
|
||||||
}
|
|
||||||
newEvents.sort((ev1, ev2) => ev1.date.getTime() - ev2.date.getTime());
|
|
||||||
|
|
||||||
this._events = newEvents;
|
changed = true;
|
||||||
this._isLoading = false;
|
}
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
this.emit('changed');
|
||||||
|
}
|
||||||
|
|
||||||
|
_onEventsRemoved(dbusProxy, nameOwner, argArray) {
|
||||||
|
const [ids = []] = argArray;
|
||||||
|
|
||||||
|
let changed = false;
|
||||||
|
for (const id of ids)
|
||||||
|
changed |= this._events.delete(id);
|
||||||
|
|
||||||
|
if (changed)
|
||||||
|
this.emit('changed');
|
||||||
|
}
|
||||||
|
|
||||||
|
_onClientDisappeared(dbusProxy, nameOwner, argArray) {
|
||||||
|
let [sourceUid = ''] = argArray;
|
||||||
|
sourceUid += '\n';
|
||||||
|
|
||||||
|
let changed = false;
|
||||||
|
for (const id of this._events.keys()) {
|
||||||
|
if (id.startsWith(sourceUid))
|
||||||
|
changed |= this._events.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed)
|
||||||
this.emit('changed');
|
this.emit('changed');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,27 +328,30 @@ class DBusEventSource extends EventSourceBase {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (this._curRequestBegin && this._curRequestEnd) {
|
if (this._curRequestBegin && this._curRequestEnd) {
|
||||||
this._dbusProxy.GetEventsRemote(this._curRequestBegin.getTime() / 1000,
|
if (forceReload) {
|
||||||
|
this._events.clear();
|
||||||
|
this.emit('changed');
|
||||||
|
}
|
||||||
|
this._dbusProxy.SetTimeRangeRemote(
|
||||||
|
this._curRequestBegin.getTime() / 1000,
|
||||||
this._curRequestEnd.getTime() / 1000,
|
this._curRequestEnd.getTime() / 1000,
|
||||||
forceReload,
|
forceReload,
|
||||||
this._onEventsReceived.bind(this),
|
|
||||||
Gio.DBusCallFlags.NONE);
|
Gio.DBusCallFlags.NONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
requestRange(begin, end) {
|
requestRange(begin, end) {
|
||||||
if (!(_datesEqual(begin, this._lastRequestBegin) && _datesEqual(end, this._lastRequestEnd))) {
|
if (!(_datesEqual(begin, this._lastRequestBegin) && _datesEqual(end, this._lastRequestEnd))) {
|
||||||
this._isLoading = true;
|
|
||||||
this._lastRequestBegin = begin;
|
this._lastRequestBegin = begin;
|
||||||
this._lastRequestEnd = end;
|
this._lastRequestEnd = end;
|
||||||
this._curRequestBegin = begin;
|
this._curRequestBegin = begin;
|
||||||
this._curRequestEnd = end;
|
this._curRequestEnd = end;
|
||||||
this._loadEvents(false);
|
this._loadEvents(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*_getFilteredEvents(begin, end) {
|
*_getFilteredEvents(begin, end) {
|
||||||
for (const event of this._events) {
|
for (const event of this._events.values()) {
|
||||||
if (_dateIntervalsOverlap(event.date, event.end, begin, end))
|
if (_dateIntervalsOverlap(event.date, event.end, begin, end))
|
||||||
yield event;
|
yield event;
|
||||||
}
|
}
|
||||||
@ -879,7 +906,7 @@ class EventsSection extends MessageList.MessageListSection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_reloadEvents() {
|
_reloadEvents() {
|
||||||
if (this._eventSource.isLoading)
|
if (this._eventSource.isLoading || this._reloading)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._reloading = true;
|
this._reloading = true;
|
||||||
|
@ -19,7 +19,7 @@ cogl_pango_pc = 'mutter-cogl-pango-' + mutter_api_version
|
|||||||
libmutter_pc = 'libmutter-' + mutter_api_version
|
libmutter_pc = 'libmutter-' + mutter_api_version
|
||||||
|
|
||||||
ecal_req = '>= 3.33.1'
|
ecal_req = '>= 3.33.1'
|
||||||
eds_req = '>= 3.17.2'
|
eds_req = '>= 3.33.1'
|
||||||
gcr_req = '>= 3.7.5'
|
gcr_req = '>= 3.7.5'
|
||||||
gio_req = '>= 2.56.0'
|
gio_req = '>= 2.56.0'
|
||||||
gi_req = '>= 1.49.1'
|
gi_req = '>= 1.49.1'
|
||||||
|
@ -45,137 +45,122 @@ struct _ClientData
|
|||||||
gulong backend_died_id;
|
gulong backend_died_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _CalendarSourceData
|
|
||||||
{
|
|
||||||
ECalClientSourceType source_type;
|
|
||||||
CalendarSources *sources;
|
|
||||||
guint changed_signal;
|
|
||||||
|
|
||||||
/* ESource -> EClient */
|
|
||||||
GHashTable *clients;
|
|
||||||
|
|
||||||
guint timeout_id;
|
|
||||||
|
|
||||||
guint loaded : 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct _CalendarSourcesPrivate CalendarSourcesPrivate;
|
typedef struct _CalendarSourcesPrivate CalendarSourcesPrivate;
|
||||||
|
|
||||||
struct _CalendarSources
|
struct _CalendarSources
|
||||||
{
|
{
|
||||||
GObject parent;
|
GObject parent;
|
||||||
|
|
||||||
ESourceRegistry *registry;
|
ESourceRegistryWatcher *registry_watcher;
|
||||||
gulong source_added_id;
|
gulong filter_id;
|
||||||
gulong source_changed_id;
|
gulong appeared_id;
|
||||||
gulong source_removed_id;
|
gulong disappeared_id;
|
||||||
|
|
||||||
CalendarSourceData appointment_sources;
|
GMutex clients_lock;
|
||||||
CalendarSourceData task_sources;
|
GHashTable *clients; /* ESource -> ClientData */
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE (CalendarSources, calendar_sources, G_TYPE_OBJECT)
|
G_DEFINE_TYPE (CalendarSources, calendar_sources, G_TYPE_OBJECT)
|
||||||
|
|
||||||
static void calendar_sources_finalize (GObject *object);
|
|
||||||
|
|
||||||
static void backend_died_cb (EClient *client, CalendarSourceData *source_data);
|
|
||||||
static void calendar_sources_registry_source_changed_cb (ESourceRegistry *registry,
|
|
||||||
ESource *source,
|
|
||||||
CalendarSources *sources);
|
|
||||||
static void calendar_sources_registry_source_removed_cb (ESourceRegistry *registry,
|
|
||||||
ESource *source,
|
|
||||||
CalendarSources *sources);
|
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
APPOINTMENT_SOURCES_CHANGED,
|
CLIENT_APPEARED,
|
||||||
TASK_SOURCES_CHANGED,
|
CLIENT_DISAPPEARED,
|
||||||
LAST_SIGNAL
|
LAST_SIGNAL
|
||||||
};
|
};
|
||||||
static guint signals [LAST_SIGNAL] = { 0, };
|
static guint signals [LAST_SIGNAL] = { 0, };
|
||||||
|
|
||||||
static GObjectClass *parent_class = NULL;
|
static void
|
||||||
static CalendarSources *calendar_sources_singleton = NULL;
|
calendar_sources_client_connected_cb (GObject *source_object,
|
||||||
|
GAsyncResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
CalendarSources *sources = CALENDAR_SOURCES (source_object);
|
||||||
|
ESource *source = user_data;
|
||||||
|
EClient *client;
|
||||||
|
g_autoptr (GError) error = NULL;
|
||||||
|
|
||||||
|
/* The calendar_sources_connect_client_sync() already stored the 'client'
|
||||||
|
* into the sources->clients */
|
||||||
|
client = calendar_sources_connect_client_finish (sources, result, &error);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
g_warning ("Could not load source '%s': %s",
|
||||||
|
e_source_get_uid (source),
|
||||||
|
error->message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_signal_emit (sources, signals[CLIENT_APPEARED], 0, client, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_clear_object (&client);
|
||||||
|
g_clear_object (&source);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
registry_watcher_filter_cb (ESourceRegistryWatcher *watcher,
|
||||||
|
ESource *source,
|
||||||
|
CalendarSources *sources)
|
||||||
|
{
|
||||||
|
return e_source_has_extension (source, E_SOURCE_EXTENSION_CALENDAR) &&
|
||||||
|
e_source_selectable_get_selected (e_source_get_extension (source, E_SOURCE_EXTENSION_CALENDAR));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
registry_watcher_source_appeared_cb (ESourceRegistryWatcher *watcher,
|
||||||
|
ESource *source,
|
||||||
|
CalendarSources *sources)
|
||||||
|
{
|
||||||
|
ECalClientSourceType source_type;
|
||||||
|
|
||||||
|
if (e_source_has_extension (source, E_SOURCE_EXTENSION_CALENDAR))
|
||||||
|
source_type = E_CAL_CLIENT_SOURCE_TYPE_EVENTS;
|
||||||
|
else if (e_source_has_extension (source, E_SOURCE_EXTENSION_MEMO_LIST))
|
||||||
|
source_type = E_CAL_CLIENT_SOURCE_TYPE_MEMOS;
|
||||||
|
else if (e_source_has_extension (source, E_SOURCE_EXTENSION_TASK_LIST))
|
||||||
|
source_type = E_CAL_CLIENT_SOURCE_TYPE_TASKS;
|
||||||
|
else
|
||||||
|
g_return_if_reached ();
|
||||||
|
|
||||||
|
calendar_sources_connect_client (sources, source, source_type, 30, NULL, calendar_sources_client_connected_cb, g_object_ref (source));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
registry_watcher_source_disappeared_cb (ESourceRegistryWatcher *watcher,
|
||||||
|
ESource *source,
|
||||||
|
CalendarSources *sources)
|
||||||
|
{
|
||||||
|
gboolean emit;
|
||||||
|
|
||||||
|
g_mutex_lock (&sources->clients_lock);
|
||||||
|
|
||||||
|
emit = g_hash_table_remove (sources->clients, source);
|
||||||
|
|
||||||
|
g_mutex_unlock (&sources->clients_lock);
|
||||||
|
|
||||||
|
if (emit)
|
||||||
|
g_signal_emit (sources, signals[CLIENT_DISAPPEARED], 0, e_source_get_uid (source), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
client_data_free (ClientData *data)
|
client_data_free (ClientData *data)
|
||||||
{
|
{
|
||||||
g_clear_signal_handler (&data->backend_died_id, data->client);
|
g_signal_handler_disconnect (data->client, data->backend_died_id);
|
||||||
g_object_unref (data->client);
|
g_object_unref (data->client);
|
||||||
g_slice_free (ClientData, data);
|
g_slice_free (ClientData, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
calendar_sources_class_init (CalendarSourcesClass *klass)
|
calendar_sources_constructed (GObject *object)
|
||||||
{
|
|
||||||
GObjectClass *gobject_class = (GObjectClass *) klass;
|
|
||||||
|
|
||||||
parent_class = g_type_class_peek_parent (klass);
|
|
||||||
|
|
||||||
gobject_class->finalize = calendar_sources_finalize;
|
|
||||||
|
|
||||||
signals [APPOINTMENT_SOURCES_CHANGED] =
|
|
||||||
g_signal_new ("appointment-sources-changed",
|
|
||||||
G_TYPE_FROM_CLASS (gobject_class),
|
|
||||||
G_SIGNAL_RUN_LAST,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
G_TYPE_NONE,
|
|
||||||
0);
|
|
||||||
|
|
||||||
signals [TASK_SOURCES_CHANGED] =
|
|
||||||
g_signal_new ("task-sources-changed",
|
|
||||||
G_TYPE_FROM_CLASS (gobject_class),
|
|
||||||
G_SIGNAL_RUN_LAST,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
G_TYPE_NONE,
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
calendar_sources_init (CalendarSources *sources)
|
|
||||||
{
|
{
|
||||||
|
CalendarSources *sources = CALENDAR_SOURCES (object);
|
||||||
|
ESourceRegistry *registry = NULL;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
GDBusConnection *session_bus;
|
|
||||||
GVariant *result;
|
|
||||||
|
|
||||||
/* WORKAROUND: the hardcoded timeout for e_source_registry_new_sync()
|
G_OBJECT_CLASS (calendar_sources_parent_class)->constructed (object);
|
||||||
(and other library calls that eventually call g_dbus_proxy_new[_sync]())
|
|
||||||
is 25 seconds. This has been shown to be too small for
|
|
||||||
evolution-source-registry in certain cases (slow disk, concurrent IO,
|
|
||||||
many configured sources), so we first ensure that the service
|
|
||||||
starts with a manual call and a higher timeout.
|
|
||||||
|
|
||||||
HACK: every time the DBus API is bumped in e-d-s we need
|
|
||||||
to update this!
|
|
||||||
*/
|
|
||||||
session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
|
|
||||||
if (session_bus == NULL)
|
|
||||||
{
|
|
||||||
g_error ("Failed to connect to the session bus: %s", error->message);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = g_dbus_connection_call_sync (session_bus, "org.freedesktop.DBus",
|
|
||||||
"/", "org.freedesktop.DBus",
|
|
||||||
"StartServiceByName",
|
|
||||||
g_variant_new ("(su)",
|
|
||||||
"org.gnome.evolution.dataserver.Sources5",
|
|
||||||
0),
|
|
||||||
NULL,
|
|
||||||
G_DBUS_CALL_FLAGS_NONE,
|
|
||||||
60 * 1000,
|
|
||||||
NULL, &error);
|
|
||||||
if (result != NULL)
|
|
||||||
{
|
|
||||||
g_variant_unref (result);
|
|
||||||
sources->registry = e_source_registry_new_sync (NULL, &error);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
registry = e_source_registry_new_sync (NULL, &error);
|
||||||
if (error != NULL)
|
if (error != NULL)
|
||||||
{
|
{
|
||||||
/* Any error is fatal, but we don't want to crash gnome-shell-calendar-server
|
/* Any error is fatal, but we don't want to crash gnome-shell-calendar-server
|
||||||
@ -185,53 +170,30 @@ calendar_sources_init (CalendarSources *sources)
|
|||||||
exit (EXIT_FAILURE);
|
exit (EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_object_unref (session_bus);
|
g_return_if_fail (registry != NULL);
|
||||||
|
|
||||||
sources->source_added_id = g_signal_connect (sources->registry,
|
sources->registry_watcher = e_source_registry_watcher_new (registry, NULL);
|
||||||
"source-added",
|
|
||||||
G_CALLBACK (calendar_sources_registry_source_changed_cb),
|
|
||||||
sources);
|
|
||||||
sources->source_changed_id = g_signal_connect (sources->registry,
|
|
||||||
"source-changed",
|
|
||||||
G_CALLBACK (calendar_sources_registry_source_changed_cb),
|
|
||||||
sources);
|
|
||||||
sources->source_removed_id = g_signal_connect (sources->registry,
|
|
||||||
"source-removed",
|
|
||||||
G_CALLBACK (calendar_sources_registry_source_removed_cb),
|
|
||||||
sources);
|
|
||||||
|
|
||||||
sources->appointment_sources.source_type = E_CAL_CLIENT_SOURCE_TYPE_EVENTS;
|
g_clear_object (®istry);
|
||||||
sources->appointment_sources.sources = sources;
|
|
||||||
sources->appointment_sources.changed_signal = signals [APPOINTMENT_SOURCES_CHANGED];
|
sources->clients = g_hash_table_new_full ((GHashFunc) e_source_hash,
|
||||||
sources->appointment_sources.clients = g_hash_table_new_full ((GHashFunc) e_source_hash,
|
|
||||||
(GEqualFunc) e_source_equal,
|
(GEqualFunc) e_source_equal,
|
||||||
(GDestroyNotify) g_object_unref,
|
(GDestroyNotify) g_object_unref,
|
||||||
(GDestroyNotify) client_data_free);
|
(GDestroyNotify) client_data_free);
|
||||||
sources->appointment_sources.timeout_id = 0;
|
sources->filter_id = g_signal_connect (sources->registry_watcher,
|
||||||
|
"filter",
|
||||||
|
G_CALLBACK (registry_watcher_filter_cb),
|
||||||
|
sources);
|
||||||
|
sources->appeared_id = g_signal_connect (sources->registry_watcher,
|
||||||
|
"appeared",
|
||||||
|
G_CALLBACK (registry_watcher_source_appeared_cb),
|
||||||
|
sources);
|
||||||
|
sources->disappeared_id = g_signal_connect (sources->registry_watcher,
|
||||||
|
"disappeared",
|
||||||
|
G_CALLBACK (registry_watcher_source_disappeared_cb),
|
||||||
|
sources);
|
||||||
|
|
||||||
sources->task_sources.source_type = E_CAL_CLIENT_SOURCE_TYPE_TASKS;
|
e_source_registry_watcher_reclaim (sources->registry_watcher);
|
||||||
sources->task_sources.sources = sources;
|
|
||||||
sources->task_sources.changed_signal = signals [TASK_SOURCES_CHANGED];
|
|
||||||
sources->task_sources.clients = g_hash_table_new_full ((GHashFunc) e_source_hash,
|
|
||||||
(GEqualFunc) e_source_equal,
|
|
||||||
(GDestroyNotify) g_object_unref,
|
|
||||||
(GDestroyNotify) client_data_free);
|
|
||||||
sources->task_sources.timeout_id = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
calendar_sources_finalize_source_data (CalendarSources *sources,
|
|
||||||
CalendarSourceData *source_data)
|
|
||||||
{
|
|
||||||
if (source_data->loaded)
|
|
||||||
{
|
|
||||||
g_hash_table_destroy (source_data->clients);
|
|
||||||
source_data->clients = NULL;
|
|
||||||
|
|
||||||
g_clear_handle_id (&source_data->timeout_id, g_source_remove);
|
|
||||||
|
|
||||||
source_data->loaded = FALSE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -239,28 +201,67 @@ calendar_sources_finalize (GObject *object)
|
|||||||
{
|
{
|
||||||
CalendarSources *sources = CALENDAR_SOURCES (object);
|
CalendarSources *sources = CALENDAR_SOURCES (object);
|
||||||
|
|
||||||
if (sources->registry)
|
g_clear_pointer (&sources->clients, g_hash_table_destroy);
|
||||||
|
|
||||||
|
if (sources->registry_watcher)
|
||||||
{
|
{
|
||||||
g_clear_signal_handler (&sources->source_added_id,
|
g_signal_handler_disconnect (sources->registry_watcher,
|
||||||
sources->registry);
|
sources->filter_id);
|
||||||
g_clear_signal_handler (&sources->source_changed_id,
|
g_signal_handler_disconnect (sources->registry_watcher,
|
||||||
sources->registry);
|
sources->appeared_id);
|
||||||
g_clear_signal_handler (&sources->source_removed_id,
|
g_signal_handler_disconnect (sources->registry_watcher,
|
||||||
sources->registry);
|
sources->disappeared_id);
|
||||||
g_object_unref (sources->registry);
|
g_clear_object (&sources->registry_watcher);
|
||||||
}
|
}
|
||||||
sources->registry = NULL;
|
|
||||||
|
|
||||||
calendar_sources_finalize_source_data (sources, &sources->appointment_sources);
|
g_mutex_clear (&sources->clients_lock);
|
||||||
calendar_sources_finalize_source_data (sources, &sources->task_sources);
|
|
||||||
|
|
||||||
if (G_OBJECT_CLASS (parent_class)->finalize)
|
G_OBJECT_CLASS (calendar_sources_parent_class)->finalize (object);
|
||||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
calendar_sources_class_init (CalendarSourcesClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class = (GObjectClass *) klass;
|
||||||
|
|
||||||
|
gobject_class->constructed = calendar_sources_constructed;
|
||||||
|
gobject_class->finalize = calendar_sources_finalize;
|
||||||
|
|
||||||
|
signals [CLIENT_APPEARED] =
|
||||||
|
g_signal_new ("client-appeared",
|
||||||
|
G_TYPE_FROM_CLASS (gobject_class),
|
||||||
|
G_SIGNAL_RUN_LAST,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
G_TYPE_NONE,
|
||||||
|
1,
|
||||||
|
E_TYPE_CAL_CLIENT);
|
||||||
|
|
||||||
|
signals [CLIENT_DISAPPEARED] =
|
||||||
|
g_signal_new ("client-disappeared",
|
||||||
|
G_TYPE_FROM_CLASS (gobject_class),
|
||||||
|
G_SIGNAL_RUN_LAST,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
G_TYPE_NONE,
|
||||||
|
1,
|
||||||
|
G_TYPE_STRING); /* ESource::uid of the disappeared client */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
calendar_sources_init (CalendarSources *sources)
|
||||||
|
{
|
||||||
|
g_mutex_init (&sources->clients_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
CalendarSources *
|
CalendarSources *
|
||||||
calendar_sources_get (void)
|
calendar_sources_get (void)
|
||||||
{
|
{
|
||||||
|
static CalendarSources *calendar_sources_singleton = NULL;
|
||||||
gpointer singleton_location = &calendar_sources_singleton;
|
gpointer singleton_location = &calendar_sources_singleton;
|
||||||
|
|
||||||
if (calendar_sources_singleton)
|
if (calendar_sources_singleton)
|
||||||
@ -273,80 +274,65 @@ calendar_sources_get (void)
|
|||||||
return calendar_sources_singleton;
|
return calendar_sources_singleton;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The clients are just created here but not loaded */
|
ESourceRegistry *
|
||||||
static void
|
calendar_sources_get_registry (CalendarSources *sources)
|
||||||
create_client_for_source (ESource *source,
|
|
||||||
ECalClientSourceType source_type,
|
|
||||||
CalendarSourceData *source_data)
|
|
||||||
{
|
{
|
||||||
ClientData *data;
|
return e_source_registry_watcher_get_registry (sources->registry_watcher);
|
||||||
EClient *client;
|
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
client = g_hash_table_lookup (source_data->clients, source);
|
|
||||||
g_return_if_fail (client == NULL);
|
|
||||||
|
|
||||||
client = e_cal_client_connect_sync (source, source_type, -1, NULL, &error);
|
|
||||||
if (!client)
|
|
||||||
{
|
|
||||||
g_warning ("Could not load source '%s': %s",
|
|
||||||
e_source_get_uid (source),
|
|
||||||
error->message);
|
|
||||||
g_clear_error (&error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = g_slice_new0 (ClientData);
|
|
||||||
data->client = E_CAL_CLIENT (client); /* takes ownership */
|
|
||||||
data->backend_died_id = g_signal_connect (client,
|
|
||||||
"backend-died",
|
|
||||||
G_CALLBACK (backend_died_cb),
|
|
||||||
source_data);
|
|
||||||
|
|
||||||
g_hash_table_insert (source_data->clients, g_object_ref (source), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
debug_dump_ecal_list (GHashTable *clients)
|
|
||||||
{
|
|
||||||
#ifdef CALENDAR_ENABLE_DEBUG
|
|
||||||
GList *list, *link;
|
|
||||||
|
|
||||||
dprintf ("Loaded clients:\n");
|
|
||||||
list = g_hash_table_get_keys (clients);
|
|
||||||
for (link = list; link != NULL; link = g_list_next (link))
|
|
||||||
{
|
|
||||||
ESource *source = E_SOURCE (link->data);
|
|
||||||
|
|
||||||
dprintf (" %s %s\n",
|
|
||||||
e_source_get_uid (source),
|
|
||||||
e_source_get_display_name (source));
|
|
||||||
}
|
|
||||||
g_list_free (list);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
calendar_sources_load_esource_list (ESourceRegistry *registry,
|
gather_event_clients_cb (gpointer key,
|
||||||
CalendarSourceData *source_data);
|
gpointer value,
|
||||||
|
gpointer user_data)
|
||||||
static gboolean
|
|
||||||
backend_restart (gpointer data)
|
|
||||||
{
|
{
|
||||||
CalendarSourceData *source_data = data;
|
GSList **plist = user_data;
|
||||||
ESourceRegistry *registry;
|
ClientData *cd = value;
|
||||||
|
|
||||||
registry = source_data->sources->registry;
|
if (cd)
|
||||||
calendar_sources_load_esource_list (registry, source_data);
|
*plist = g_slist_prepend (*plist, g_object_ref (cd->client));
|
||||||
g_signal_emit (source_data->sources, source_data->changed_signal, 0);
|
}
|
||||||
|
|
||||||
source_data->timeout_id = 0;
|
GSList *
|
||||||
|
calendar_sources_ref_clients (CalendarSources *sources)
|
||||||
|
{
|
||||||
|
GSList *list = NULL;
|
||||||
|
|
||||||
return FALSE;
|
g_return_val_if_fail (CALENDAR_IS_SOURCES (sources), NULL);
|
||||||
|
|
||||||
|
g_mutex_lock (&sources->clients_lock);
|
||||||
|
g_hash_table_foreach (sources->clients, gather_event_clients_cb, &list);
|
||||||
|
g_mutex_unlock (&sources->clients_lock);
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
calendar_sources_has_clients (CalendarSources *sources)
|
||||||
|
{
|
||||||
|
GHashTableIter iter;
|
||||||
|
gpointer value;
|
||||||
|
gboolean has = FALSE;
|
||||||
|
|
||||||
|
g_return_val_if_fail (CALENDAR_IS_SOURCES (sources), FALSE);
|
||||||
|
|
||||||
|
g_mutex_lock (&sources->clients_lock);
|
||||||
|
|
||||||
|
g_hash_table_iter_init (&iter, sources->clients);
|
||||||
|
while (!has && g_hash_table_iter_next (&iter, NULL, &value))
|
||||||
|
{
|
||||||
|
ClientData *cd = value;
|
||||||
|
|
||||||
|
has = cd != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_mutex_unlock (&sources->clients_lock);
|
||||||
|
|
||||||
|
return has;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
backend_died_cb (EClient *client, CalendarSourceData *source_data)
|
backend_died_cb (EClient *client,
|
||||||
|
CalendarSources *sources)
|
||||||
{
|
{
|
||||||
ESource *source;
|
ESource *source;
|
||||||
const char *display_name;
|
const char *display_name;
|
||||||
@ -354,196 +340,167 @@ backend_died_cb (EClient *client, CalendarSourceData *source_data)
|
|||||||
source = e_client_get_source (client);
|
source = e_client_get_source (client);
|
||||||
display_name = e_source_get_display_name (source);
|
display_name = e_source_get_display_name (source);
|
||||||
g_warning ("The calendar backend for '%s' has crashed.", display_name);
|
g_warning ("The calendar backend for '%s' has crashed.", display_name);
|
||||||
g_hash_table_remove (source_data->clients, source);
|
g_mutex_lock (&sources->clients_lock);
|
||||||
|
g_hash_table_remove (sources->clients, source);
|
||||||
g_clear_handle_id (&source_data->timeout_id, g_source_remove);
|
g_mutex_unlock (&sources->clients_lock);
|
||||||
|
|
||||||
source_data->timeout_id = g_timeout_add_seconds (2, backend_restart,
|
|
||||||
source_data);
|
|
||||||
g_source_set_name_by_id (source_data->timeout_id, "[gnome-shell] backend_restart");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static EClient *
|
||||||
calendar_sources_load_esource_list (ESourceRegistry *registry,
|
calendar_sources_connect_client_sync (CalendarSources *sources,
|
||||||
CalendarSourceData *source_data)
|
|
||||||
{
|
|
||||||
GList *list, *link;
|
|
||||||
const gchar *extension_name;
|
|
||||||
|
|
||||||
switch (source_data->source_type)
|
|
||||||
{
|
|
||||||
case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
|
|
||||||
extension_name = E_SOURCE_EXTENSION_CALENDAR;
|
|
||||||
break;
|
|
||||||
case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
|
|
||||||
extension_name = E_SOURCE_EXTENSION_TASK_LIST;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
g_return_if_reached ();
|
|
||||||
}
|
|
||||||
|
|
||||||
list = e_source_registry_list_sources (registry, extension_name);
|
|
||||||
|
|
||||||
for (link = list; link != NULL; link = g_list_next (link))
|
|
||||||
{
|
|
||||||
ESource *source = E_SOURCE (link->data);
|
|
||||||
ESourceSelectable *extension;
|
|
||||||
gboolean show_source;
|
|
||||||
|
|
||||||
extension = e_source_get_extension (source, extension_name);
|
|
||||||
show_source = e_source_get_enabled (source) && e_source_selectable_get_selected (extension);
|
|
||||||
|
|
||||||
if (show_source)
|
|
||||||
create_client_for_source (source, source_data->source_type, source_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
debug_dump_ecal_list (source_data->clients);
|
|
||||||
|
|
||||||
g_list_free_full (list, g_object_unref);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
calendar_sources_registry_source_changed_cb (ESourceRegistry *registry,
|
|
||||||
ESource *source,
|
ESource *source,
|
||||||
CalendarSources *sources)
|
ECalClientSourceType source_type,
|
||||||
|
guint32 wait_for_connected_seconds,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
{
|
{
|
||||||
if (e_source_has_extension (source, E_SOURCE_EXTENSION_CALENDAR))
|
EClient *client = NULL;
|
||||||
{
|
ClientData *client_data;
|
||||||
CalendarSourceData *source_data;
|
|
||||||
ESourceSelectable *extension;
|
|
||||||
gboolean have_client;
|
|
||||||
gboolean show_source;
|
|
||||||
|
|
||||||
source_data = &sources->appointment_sources;
|
g_mutex_lock (&sources->clients_lock);
|
||||||
extension = e_source_get_extension (source, E_SOURCE_EXTENSION_CALENDAR);
|
client_data = g_hash_table_lookup (sources->clients, source);
|
||||||
have_client = (g_hash_table_lookup (source_data->clients, source) != NULL);
|
if (client_data)
|
||||||
show_source = e_source_get_enabled (source) && e_source_selectable_get_selected (extension);
|
client = E_CLIENT (g_object_ref (client_data->client));
|
||||||
|
g_mutex_unlock (&sources->clients_lock);
|
||||||
|
|
||||||
if (!show_source && have_client)
|
if (client)
|
||||||
|
return client;
|
||||||
|
|
||||||
|
client = e_cal_client_connect_sync (source, source_type, wait_for_connected_seconds, cancellable, error);
|
||||||
|
if (!client)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
g_mutex_lock (&sources->clients_lock);
|
||||||
|
client_data = g_hash_table_lookup (sources->clients, source);
|
||||||
|
if (client_data)
|
||||||
{
|
{
|
||||||
g_hash_table_remove (source_data->clients, source);
|
g_clear_object (&client);
|
||||||
g_signal_emit (sources, source_data->changed_signal, 0);
|
client = E_CLIENT (g_object_ref (client_data->client));
|
||||||
}
|
}
|
||||||
if (show_source && !have_client)
|
else
|
||||||
{
|
{
|
||||||
create_client_for_source (source, source_data->source_type, source_data);
|
client_data = g_slice_new0 (ClientData);
|
||||||
g_signal_emit (sources, source_data->changed_signal, 0);
|
client_data->client = E_CAL_CLIENT (g_object_ref (client));
|
||||||
|
client_data->backend_died_id = g_signal_connect (client,
|
||||||
|
"backend-died",
|
||||||
|
G_CALLBACK (backend_died_cb),
|
||||||
|
sources);
|
||||||
|
|
||||||
|
g_hash_table_insert (sources->clients, g_object_ref (source), client_data);
|
||||||
}
|
}
|
||||||
|
g_mutex_unlock (&sources->clients_lock);
|
||||||
|
|
||||||
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e_source_has_extension (source, E_SOURCE_EXTENSION_TASK_LIST))
|
typedef struct _AsyncContext {
|
||||||
{
|
ESource *source;
|
||||||
CalendarSourceData *source_data;
|
ECalClientSourceType source_type;
|
||||||
ESourceSelectable *extension;
|
guint32 wait_for_connected_seconds;
|
||||||
gboolean have_client;
|
} AsyncContext;
|
||||||
gboolean show_source;
|
|
||||||
|
|
||||||
source_data = &sources->task_sources;
|
static void
|
||||||
extension = e_source_get_extension (source, E_SOURCE_EXTENSION_TASK_LIST);
|
async_context_free (gpointer ptr)
|
||||||
have_client = (g_hash_table_lookup (source_data->clients, source) != NULL);
|
{
|
||||||
show_source = e_source_get_enabled (source) && e_source_selectable_get_selected (extension);
|
AsyncContext *ctx = ptr;
|
||||||
|
|
||||||
if (!show_source && have_client)
|
if (ctx)
|
||||||
{
|
{
|
||||||
g_hash_table_remove (source_data->clients, source);
|
g_clear_object (&ctx->source);
|
||||||
g_signal_emit (sources, source_data->changed_signal, 0);
|
g_slice_free (AsyncContext, ctx);
|
||||||
}
|
|
||||||
if (show_source && !have_client)
|
|
||||||
{
|
|
||||||
create_client_for_source (source, source_data->source_type, source_data);
|
|
||||||
g_signal_emit (sources, source_data->changed_signal, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
calendar_sources_registry_source_removed_cb (ESourceRegistry *registry,
|
calendar_sources_connect_client_thread (GTask *task,
|
||||||
|
gpointer source_object,
|
||||||
|
gpointer task_data,
|
||||||
|
GCancellable *cancellable)
|
||||||
|
{
|
||||||
|
CalendarSources *sources = source_object;
|
||||||
|
AsyncContext *ctx = task_data;
|
||||||
|
EClient *client;
|
||||||
|
GError *local_error = NULL;
|
||||||
|
|
||||||
|
client = calendar_sources_connect_client_sync (sources, ctx->source, ctx->source_type,
|
||||||
|
ctx->wait_for_connected_seconds, cancellable, &local_error);
|
||||||
|
if (!client)
|
||||||
|
{
|
||||||
|
if (local_error)
|
||||||
|
g_task_return_error (task, local_error);
|
||||||
|
else
|
||||||
|
g_task_return_pointer (task, NULL, NULL);
|
||||||
|
} else {
|
||||||
|
g_task_return_pointer (task, client, g_object_unref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
calendar_sources_connect_client (CalendarSources *sources,
|
||||||
ESource *source,
|
ESource *source,
|
||||||
CalendarSources *sources)
|
ECalClientSourceType source_type,
|
||||||
|
guint32 wait_for_connected_seconds,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
if (e_source_has_extension (source, E_SOURCE_EXTENSION_CALENDAR))
|
AsyncContext *ctx;
|
||||||
{
|
g_autoptr (GTask) task = NULL;
|
||||||
CalendarSourceData *source_data;
|
|
||||||
|
|
||||||
source_data = &sources->appointment_sources;
|
ctx = g_slice_new0 (AsyncContext);
|
||||||
g_hash_table_remove (source_data->clients, source);
|
ctx->source = g_object_ref (source);
|
||||||
g_signal_emit (sources, source_data->changed_signal, 0);
|
ctx->source_type = source_type;
|
||||||
|
ctx->wait_for_connected_seconds = wait_for_connected_seconds;
|
||||||
|
|
||||||
|
task = g_task_new (sources, cancellable, callback, user_data);
|
||||||
|
g_task_set_source_tag (task, calendar_sources_connect_client);
|
||||||
|
g_task_set_task_data (task, ctx, async_context_free);
|
||||||
|
|
||||||
|
g_task_run_in_thread (task, calendar_sources_connect_client_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e_source_has_extension (source, E_SOURCE_EXTENSION_TASK_LIST))
|
EClient *
|
||||||
|
calendar_sources_connect_client_finish (CalendarSources *sources,
|
||||||
|
GAsyncResult *result,
|
||||||
|
GError **error)
|
||||||
{
|
{
|
||||||
CalendarSourceData *source_data;
|
g_return_val_if_fail (g_task_is_valid (result, sources), NULL);
|
||||||
|
g_return_val_if_fail (g_async_result_is_tagged (result, calendar_sources_connect_client), NULL);
|
||||||
|
|
||||||
source_data = &sources->task_sources;
|
return g_task_propagate_pointer (G_TASK (result), error);
|
||||||
g_hash_table_remove (source_data->clients, source);
|
|
||||||
g_signal_emit (sources, source_data->changed_signal, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
ensure_appointment_sources (CalendarSources *sources)
|
void
|
||||||
|
print_debug (const gchar *format,
|
||||||
|
...)
|
||||||
{
|
{
|
||||||
if (!sources->appointment_sources.loaded)
|
g_autofree char *s = NULL;
|
||||||
|
g_autofree char *timestamp = NULL;
|
||||||
|
va_list ap;
|
||||||
|
g_autoptr (GDateTime) now = NULL;
|
||||||
|
static volatile gsize once_init_value = 0;
|
||||||
|
static gboolean show_debug = FALSE;
|
||||||
|
static guint pid = 0;
|
||||||
|
|
||||||
|
if (g_once_init_enter (&once_init_value))
|
||||||
{
|
{
|
||||||
calendar_sources_load_esource_list (sources->registry,
|
show_debug = (g_getenv ("CALENDAR_SERVER_DEBUG") != NULL);
|
||||||
&sources->appointment_sources);
|
pid = getpid ();
|
||||||
sources->appointment_sources.loaded = TRUE;
|
g_once_init_leave (&once_init_value, 1);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GList *
|
if (!show_debug)
|
||||||
calendar_sources_get_appointment_clients (CalendarSources *sources)
|
goto out;
|
||||||
{
|
|
||||||
GList *list, *link;
|
|
||||||
|
|
||||||
g_return_val_if_fail (CALENDAR_IS_SOURCES (sources), NULL);
|
now = g_date_time_new_now_local ();
|
||||||
|
timestamp = g_date_time_format (now, "%H:%M:%S");
|
||||||
|
|
||||||
ensure_appointment_sources (sources);
|
va_start (ap, format);
|
||||||
|
s = g_strdup_vprintf (format, ap);
|
||||||
|
va_end (ap);
|
||||||
|
|
||||||
list = g_hash_table_get_values (sources->appointment_sources.clients);
|
g_print ("gnome-shell-calendar-server[%d]: %s.%03d: %s\n",
|
||||||
|
pid, timestamp, g_date_time_get_microsecond (now), s);
|
||||||
for (link = list; link != NULL; link = g_list_next (link))
|
out:
|
||||||
link->data = ((ClientData *) link->data)->client;
|
;
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
ensure_task_sources (CalendarSources *sources)
|
|
||||||
{
|
|
||||||
if (!sources->task_sources.loaded)
|
|
||||||
{
|
|
||||||
calendar_sources_load_esource_list (sources->registry,
|
|
||||||
&sources->task_sources);
|
|
||||||
sources->task_sources.loaded = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GList *
|
|
||||||
calendar_sources_get_task_clients (CalendarSources *sources)
|
|
||||||
{
|
|
||||||
GList *list, *link;
|
|
||||||
|
|
||||||
g_return_val_if_fail (CALENDAR_IS_SOURCES (sources), NULL);
|
|
||||||
|
|
||||||
ensure_task_sources (sources);
|
|
||||||
|
|
||||||
list = g_hash_table_get_values (sources->task_sources.clients);
|
|
||||||
|
|
||||||
for (link = list; link != NULL; link = g_list_next (link))
|
|
||||||
link->data = ((ClientData *) link->data)->client;
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
calendar_sources_has_sources (CalendarSources *sources)
|
|
||||||
{
|
|
||||||
g_return_val_if_fail (CALENDAR_IS_SOURCES (sources), FALSE);
|
|
||||||
|
|
||||||
ensure_appointment_sources (sources);
|
|
||||||
ensure_task_sources (sources);
|
|
||||||
|
|
||||||
return g_hash_table_size (sources->appointment_sources.clients) > 0 ||
|
|
||||||
g_hash_table_size (sources->task_sources.clients) > 0;
|
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,12 @@
|
|||||||
|
|
||||||
#include <glib-object.h>
|
#include <glib-object.h>
|
||||||
|
|
||||||
|
#define EDS_DISABLE_DEPRECATED
|
||||||
|
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||||
|
#include <libedataserver/libedataserver.h>
|
||||||
|
#include <libecal/libecal.h>
|
||||||
|
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
#define CALENDAR_TYPE_SOURCES (calendar_sources_get_type ())
|
#define CALENDAR_TYPE_SOURCES (calendar_sources_get_type ())
|
||||||
@ -33,10 +39,25 @@ G_DECLARE_FINAL_TYPE (CalendarSources, calendar_sources,
|
|||||||
CALENDAR, SOURCES, GObject)
|
CALENDAR, SOURCES, GObject)
|
||||||
|
|
||||||
CalendarSources *calendar_sources_get (void);
|
CalendarSources *calendar_sources_get (void);
|
||||||
GList *calendar_sources_get_appointment_clients (CalendarSources *sources);
|
ESourceRegistry *calendar_sources_get_registry (CalendarSources *sources);
|
||||||
GList *calendar_sources_get_task_clients (CalendarSources *sources);
|
GSList *calendar_sources_ref_clients (CalendarSources *sources);
|
||||||
|
gboolean calendar_sources_has_clients (CalendarSources *sources);
|
||||||
|
|
||||||
gboolean calendar_sources_has_sources (CalendarSources *sources);
|
void calendar_sources_connect_client (CalendarSources *sources,
|
||||||
|
ESource *source,
|
||||||
|
ECalClientSourceType source_type,
|
||||||
|
guint32 wait_for_connected_seconds,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
EClient *calendar_sources_connect_client_finish
|
||||||
|
(CalendarSources *sources,
|
||||||
|
GAsyncResult *result,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
/* Set the environment variable CALENDAR_SERVER_DEBUG to show debug */
|
||||||
|
void print_debug (const gchar *str,
|
||||||
|
...) G_GNUC_PRINTF (1, 2);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user