1 /*
2 * Copyright (C) 2016 Red Hat, Inc. (www.redhat.com)
3 *
4 * This library is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
7 *
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
11 * for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 #include "evolution-data-server-config.h"
18
19 #include <gio/gio.h>
20
21 #include "e-network-monitor.h"
22
23 struct _ENetworkMonitorPrivate {
24 GMutex property_lock;
25 gchar *gio_name;
26 GNetworkMonitor *gio_monitor;
27 gulong network_available_notify_id;
28 gulong network_metered_notify_id;
29 gulong network_connectivity_notify_id;
30 gulong network_changed_id;
31 GSource *network_changed_source;
32 };
33
34 enum {
35 PROP_0,
36 PROP_GIO_NAME,
37 PROP_CONNECTIVITY,
38 PROP_NETWORK_METERED,
39 PROP_NETWORK_AVAILABLE
40 };
41
42 static guint network_changed_signal = 0;
43
44 static void e_network_monitor_initable_iface_init (GInitableIface *iface);
45 static void e_network_monitor_gio_iface_init (GNetworkMonitorInterface *iface);
46
G_DEFINE_TYPE_WITH_CODE(ENetworkMonitor,e_network_monitor,G_TYPE_OBJECT,G_ADD_PRIVATE (ENetworkMonitor)G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,e_network_monitor_initable_iface_init)G_IMPLEMENT_INTERFACE (G_TYPE_NETWORK_MONITOR,e_network_monitor_gio_iface_init))47 G_DEFINE_TYPE_WITH_CODE (ENetworkMonitor, e_network_monitor, G_TYPE_OBJECT,
48 G_ADD_PRIVATE (ENetworkMonitor)
49 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, e_network_monitor_initable_iface_init)
50 G_IMPLEMENT_INTERFACE (G_TYPE_NETWORK_MONITOR, e_network_monitor_gio_iface_init))
51
52 static GNetworkConnectivity
53 e_network_monitor_get_connectivity (ENetworkMonitor *network_monitor)
54 {
55 GNetworkConnectivity connectivity;
56
57 g_return_val_if_fail (E_IS_NETWORK_MONITOR (network_monitor), G_NETWORK_CONNECTIVITY_LOCAL);
58
59 g_mutex_lock (&network_monitor->priv->property_lock);
60
61 if (network_monitor->priv->gio_monitor)
62 connectivity = g_network_monitor_get_connectivity (network_monitor->priv->gio_monitor);
63 else
64 connectivity = G_NETWORK_CONNECTIVITY_FULL;
65
66 g_mutex_unlock (&network_monitor->priv->property_lock);
67
68 return connectivity;
69 }
70
71 static gboolean
e_network_monitor_get_network_available(ENetworkMonitor * network_monitor)72 e_network_monitor_get_network_available (ENetworkMonitor *network_monitor)
73 {
74 gboolean network_available;
75
76 g_return_val_if_fail (E_IS_NETWORK_MONITOR (network_monitor), FALSE);
77
78 g_mutex_lock (&network_monitor->priv->property_lock);
79
80 if (network_monitor->priv->gio_monitor)
81 network_available = g_network_monitor_get_network_available (network_monitor->priv->gio_monitor);
82 else
83 network_available = TRUE;
84
85 g_mutex_unlock (&network_monitor->priv->property_lock);
86
87 return network_available;
88 }
89
90 static gboolean
e_network_monitor_get_network_metered(ENetworkMonitor * network_monitor)91 e_network_monitor_get_network_metered (ENetworkMonitor *network_monitor)
92 {
93 gboolean network_metered;
94
95 g_return_val_if_fail (E_IS_NETWORK_MONITOR (network_monitor), FALSE);
96
97 g_mutex_lock (&network_monitor->priv->property_lock);
98
99 if (network_monitor->priv->gio_monitor)
100 network_metered = g_network_monitor_get_network_metered (network_monitor->priv->gio_monitor);
101 else
102 network_metered = FALSE;
103
104 g_mutex_unlock (&network_monitor->priv->property_lock);
105
106 return network_metered;
107 }
108
109 static gboolean
e_network_monitor_emit_network_changed_idle_cb(gpointer user_data)110 e_network_monitor_emit_network_changed_idle_cb (gpointer user_data)
111 {
112 ENetworkMonitor *network_monitor = user_data;
113 gboolean is_available;
114
115 g_return_val_if_fail (E_IS_NETWORK_MONITOR (network_monitor), FALSE);
116
117 g_object_ref (network_monitor);
118
119 is_available = e_network_monitor_get_network_available (network_monitor);
120 g_signal_emit (network_monitor, network_changed_signal, 0, is_available);
121
122 g_source_unref (network_monitor->priv->network_changed_source);
123 network_monitor->priv->network_changed_source = NULL;
124
125 g_object_unref (network_monitor);
126
127 return FALSE;
128 }
129
130 static void
e_network_monitor_schedule_network_changed_emit(ENetworkMonitor * network_monitor)131 e_network_monitor_schedule_network_changed_emit (ENetworkMonitor *network_monitor)
132 {
133 g_mutex_lock (&network_monitor->priv->property_lock);
134
135 if (!network_monitor->priv->network_changed_source) {
136 network_monitor->priv->network_changed_source = g_idle_source_new ();
137 /* Use G_PRIORITY_HIGH_IDLE priority so that multiple
138 * network-change-related notifications coming in at
139 * G_PRIORITY_DEFAULT will get coalesced into one signal
140 * emission.
141 */
142 g_source_set_priority (network_monitor->priv->network_changed_source, G_PRIORITY_HIGH_IDLE);
143 g_source_set_callback (network_monitor->priv->network_changed_source,
144 e_network_monitor_emit_network_changed_idle_cb, network_monitor, NULL);
145 g_source_attach (network_monitor->priv->network_changed_source, NULL);
146 }
147
148 g_mutex_unlock (&network_monitor->priv->property_lock);
149 }
150
151 static void
e_network_monitor_notify_cb(GNetworkMonitor * gio_monitor,GParamSpec * param,ENetworkMonitor * network_monitor)152 e_network_monitor_notify_cb (GNetworkMonitor *gio_monitor,
153 GParamSpec *param,
154 ENetworkMonitor *network_monitor)
155 {
156 g_return_if_fail (G_IS_NETWORK_MONITOR (gio_monitor));
157 g_return_if_fail (param && param->name);
158 g_return_if_fail (E_IS_NETWORK_MONITOR (network_monitor));
159
160 g_object_notify (G_OBJECT (network_monitor), param->name);
161 }
162
163 static void
e_network_monitor_network_changed_cb(GNetworkMonitor * gio_monitor,gboolean is_available,ENetworkMonitor * network_monitor)164 e_network_monitor_network_changed_cb (GNetworkMonitor *gio_monitor,
165 gboolean is_available,
166 ENetworkMonitor *network_monitor)
167 {
168 g_return_if_fail (G_IS_NETWORK_MONITOR (gio_monitor));
169 g_return_if_fail (E_IS_NETWORK_MONITOR (network_monitor));
170
171 e_network_monitor_schedule_network_changed_emit (network_monitor);
172 }
173
174 static void
e_network_monitor_disconnect_gio_monitor_locked(ENetworkMonitor * network_monitor)175 e_network_monitor_disconnect_gio_monitor_locked (ENetworkMonitor *network_monitor)
176 {
177 if (!network_monitor->priv->gio_monitor)
178 return;
179
180 #define disconnect_signal(x) G_STMT_START { \
181 if (network_monitor->priv->x) { \
182 g_signal_handler_disconnect (network_monitor->priv->gio_monitor, network_monitor->priv->x); \
183 network_monitor->priv->x = 0; \
184 } \
185 } G_STMT_END
186
187 disconnect_signal (network_available_notify_id);
188 disconnect_signal (network_metered_notify_id);
189 disconnect_signal (network_connectivity_notify_id);
190 disconnect_signal (network_changed_id);
191
192 #undef disconnect_signal
193 }
194
195 static void
e_network_monitor_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)196 e_network_monitor_set_property (GObject *object,
197 guint property_id,
198 const GValue *value,
199 GParamSpec *pspec)
200 {
201 switch (property_id) {
202 case PROP_GIO_NAME:
203 e_network_monitor_set_gio_name (
204 E_NETWORK_MONITOR (object),
205 g_value_get_string (value));
206 return;
207 }
208
209 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
210 }
211
212 static void
e_network_monitor_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)213 e_network_monitor_get_property (GObject *object,
214 guint property_id,
215 GValue *value,
216 GParamSpec *pspec)
217 {
218 switch (property_id) {
219 case PROP_GIO_NAME:
220 g_value_take_string (
221 value,
222 e_network_monitor_dup_gio_name (
223 E_NETWORK_MONITOR (object)));
224 return;
225
226 case PROP_CONNECTIVITY:
227 g_value_set_enum (
228 value,
229 e_network_monitor_get_connectivity (
230 E_NETWORK_MONITOR (object)));
231 return;
232
233 case PROP_NETWORK_METERED:
234 g_value_set_boolean (
235 value,
236 e_network_monitor_get_network_metered (
237 E_NETWORK_MONITOR (object)));
238 return;
239
240 case PROP_NETWORK_AVAILABLE:
241 g_value_set_boolean (
242 value,
243 e_network_monitor_get_network_available (
244 E_NETWORK_MONITOR (object)));
245 return;
246 }
247
248 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
249 }
250
251 static void
e_network_monitor_constructed(GObject * object)252 e_network_monitor_constructed (GObject *object)
253 {
254 GSettings *settings;
255
256 /* Chain up to parent's method. */
257 G_OBJECT_CLASS (e_network_monitor_parent_class)->constructed (object);
258
259 settings = g_settings_new ("org.gnome.evolution-data-server");
260 g_settings_bind (
261 settings, "network-monitor-gio-name",
262 object, "gio-name",
263 G_SETTINGS_BIND_DEFAULT);
264 g_object_unref (settings);
265 }
266
267 static void
e_network_monitor_finalize(GObject * object)268 e_network_monitor_finalize (GObject *object)
269 {
270 ENetworkMonitor *network_monitor = E_NETWORK_MONITOR (object);
271
272 if (network_monitor->priv->network_changed_source) {
273 g_source_destroy (network_monitor->priv->network_changed_source);
274 g_source_unref (network_monitor->priv->network_changed_source);
275 network_monitor->priv->network_changed_source = NULL;
276 }
277
278 g_mutex_lock (&network_monitor->priv->property_lock);
279 e_network_monitor_disconnect_gio_monitor_locked (network_monitor);
280 g_mutex_unlock (&network_monitor->priv->property_lock);
281
282 g_mutex_clear (&network_monitor->priv->property_lock);
283 g_clear_object (&network_monitor->priv->gio_monitor);
284 g_free (network_monitor->priv->gio_name);
285
286 /* Chain up to parent's method. */
287 G_OBJECT_CLASS (e_network_monitor_parent_class)->finalize (object);
288 }
289
290 static void
e_network_monitor_class_init(ENetworkMonitorClass * class)291 e_network_monitor_class_init (ENetworkMonitorClass *class)
292 {
293 GObjectClass *object_class;
294
295 object_class = G_OBJECT_CLASS (class);
296 object_class->set_property = e_network_monitor_set_property;
297 object_class->get_property = e_network_monitor_get_property;
298 object_class->constructed = e_network_monitor_constructed;
299 object_class->finalize = e_network_monitor_finalize;
300
301 /**
302 * ENetworkMonitor:gio-name:
303 *
304 * The GIO name of the underlying #GNetworkMonitor to use.
305 **/
306 g_object_class_install_property (
307 object_class,
308 PROP_GIO_NAME,
309 g_param_spec_string (
310 "gio-name",
311 "GIO name",
312 NULL,
313 NULL,
314 G_PARAM_READWRITE |
315 G_PARAM_EXPLICIT_NOTIFY |
316 G_PARAM_STATIC_STRINGS));
317
318 g_object_class_override_property (object_class, PROP_NETWORK_AVAILABLE, "network-available");
319 g_object_class_override_property (object_class, PROP_NETWORK_METERED, "network-metered");
320 g_object_class_override_property (object_class, PROP_CONNECTIVITY, "connectivity");
321 }
322
323 static void
e_network_monitor_init(ENetworkMonitor * network_monitor)324 e_network_monitor_init (ENetworkMonitor *network_monitor)
325 {
326 network_monitor->priv = e_network_monitor_get_instance_private (network_monitor);
327
328 g_mutex_init (&network_monitor->priv->property_lock);
329 }
330
331 static gboolean
e_network_monitor_initable_init(GInitable * initable,GCancellable * cancellable,GError ** error)332 e_network_monitor_initable_init (GInitable *initable,
333 GCancellable *cancellable,
334 GError **error)
335 {
336 return TRUE;
337 }
338
339 static void
e_network_monitor_initable_iface_init(GInitableIface * iface)340 e_network_monitor_initable_iface_init (GInitableIface *iface)
341 {
342 iface->init = e_network_monitor_initable_init;
343 }
344
345 static gboolean
e_network_monitor_can_reach(GNetworkMonitor * monitor,GSocketConnectable * connectable,GCancellable * cancellable,GError ** error)346 e_network_monitor_can_reach (GNetworkMonitor *monitor,
347 GSocketConnectable *connectable,
348 GCancellable *cancellable,
349 GError **error)
350 {
351 ENetworkMonitor *network_monitor;
352 GNetworkMonitor *use_gio_monitor = NULL;
353 gboolean can_reach;
354
355 g_return_val_if_fail (E_IS_NETWORK_MONITOR (monitor), FALSE);
356
357 network_monitor = E_NETWORK_MONITOR (monitor);
358
359 g_mutex_lock (&network_monitor->priv->property_lock);
360
361 if (network_monitor->priv->gio_monitor)
362 use_gio_monitor = g_object_ref (network_monitor->priv->gio_monitor);
363
364 g_mutex_unlock (&network_monitor->priv->property_lock);
365
366 if (use_gio_monitor)
367 can_reach = g_network_monitor_can_reach (use_gio_monitor, connectable, cancellable, error);
368 else
369 can_reach = TRUE;
370
371 g_clear_object (&use_gio_monitor);
372
373 return can_reach;
374 }
375
376 static void
e_network_monitor_can_reach_async_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)377 e_network_monitor_can_reach_async_thread (GTask *task,
378 gpointer source_object,
379 gpointer task_data,
380 GCancellable *cancellable)
381 {
382 gboolean success;
383 GError *local_error = NULL;
384
385 success = e_network_monitor_can_reach (source_object, task_data, cancellable, &local_error);
386
387 if (local_error)
388 g_task_return_error (task, local_error);
389 else
390 g_task_return_boolean (task, success);
391 }
392
393 static void
e_network_monitor_can_reach_async(GNetworkMonitor * monitor,GSocketConnectable * connectable,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)394 e_network_monitor_can_reach_async (GNetworkMonitor *monitor,
395 GSocketConnectable *connectable,
396 GCancellable *cancellable,
397 GAsyncReadyCallback callback,
398 gpointer user_data)
399 {
400 GTask *task;
401
402 g_return_if_fail (E_IS_NETWORK_MONITOR (monitor));
403 g_return_if_fail (G_IS_SOCKET_CONNECTABLE (connectable));
404
405 task = g_task_new (monitor, cancellable, callback, user_data);
406 g_task_set_source_tag (task, e_network_monitor_can_reach_async);
407 g_task_set_task_data (task, g_object_ref (connectable), g_object_unref);
408
409 g_task_run_in_thread (task, e_network_monitor_can_reach_async_thread);
410
411 g_object_unref (task);
412 }
413
414 static gboolean
e_network_monitor_can_reach_finish(GNetworkMonitor * monitor,GAsyncResult * result,GError ** error)415 e_network_monitor_can_reach_finish (GNetworkMonitor *monitor,
416 GAsyncResult *result,
417 GError **error)
418 {
419 g_return_val_if_fail (E_IS_NETWORK_MONITOR (monitor), FALSE);
420 g_return_val_if_fail (g_task_is_valid (result, monitor), FALSE);
421
422 g_return_val_if_fail (
423 g_async_result_is_tagged (
424 result, e_network_monitor_can_reach_async), FALSE);
425
426 return g_task_propagate_boolean (G_TASK (result), error);
427 }
428
429 static void
e_network_monitor_gio_iface_init(GNetworkMonitorInterface * iface)430 e_network_monitor_gio_iface_init (GNetworkMonitorInterface *iface)
431 {
432 iface->can_reach = e_network_monitor_can_reach;
433 iface->can_reach_async = e_network_monitor_can_reach_async;
434 iface->can_reach_finish = e_network_monitor_can_reach_finish;
435
436 if (!network_changed_signal)
437 network_changed_signal = g_signal_lookup ("network-changed", G_TYPE_NETWORK_MONITOR);
438 }
439
440 static GNetworkMonitor *
e_network_monitor_create_instance_for_gio_name(const gchar * gio_name)441 e_network_monitor_create_instance_for_gio_name (const gchar *gio_name)
442 {
443 GIOExtensionPoint *pnt;
444 GList *extensions, *link;
445
446 if (!gio_name || !*gio_name)
447 return NULL;
448
449 /* To initialize the GIO extension point for the GNetworkMonitor */
450 g_network_monitor_get_default ();
451
452 pnt = g_io_extension_point_lookup (G_NETWORK_MONITOR_EXTENSION_POINT_NAME);
453 if (!pnt)
454 return NULL;
455
456 extensions = g_io_extension_point_get_extensions (pnt);
457
458 for (link = extensions; link; link = g_list_next (link)) {
459 GIOExtension *ext = link->data;
460
461 if (g_strcmp0 (g_io_extension_get_name (ext), gio_name) == 0)
462 return g_initable_new (g_io_extension_get_type (ext), NULL, NULL, NULL);
463 }
464
465 return NULL;
466 }
467
468 /**
469 * e_network_monitor_get_default:
470 *
471 * Gets the default #ENetworkMonitor. The caller should not unref the returned instance.
472 * The #ENetworkMonitor implements the #GNetworkMonitor iterface.
473 *
474 * Returns: (transfer none): The default #ENetworkMonitor instance.
475 *
476 * Since: 3.22
477 **/
478 GNetworkMonitor *
e_network_monitor_get_default(void)479 e_network_monitor_get_default (void)
480 {
481 static GNetworkMonitor *network_monitor = NULL;
482 G_LOCK_DEFINE_STATIC (network_monitor);
483
484 G_LOCK (network_monitor);
485 if (!network_monitor)
486 network_monitor = g_initable_new (E_TYPE_NETWORK_MONITOR, NULL, NULL, NULL);
487 G_UNLOCK (network_monitor);
488
489 return network_monitor;
490 }
491
492 /**
493 * e_network_monitor_list_gio_names:
494 * @network_monitor: an #ENetworkMonitor
495 *
496 * Get a list of available GIO names for the #GNetworkMonitor implementations.
497 * The strings can be used in e_network_monitor_set_gio_name().
498 *
499 * Returns: (transfer full) (element-type utf8): A newly allocated #GSList,
500 * with newly allocated strings, the GIO names. The #GSList should be freed
501 * with g_slist_free_full (gio_names, g_free); when no longer needed.
502 *
503 * Since: 3.22
504 **/
505 GSList *
e_network_monitor_list_gio_names(ENetworkMonitor * network_monitor)506 e_network_monitor_list_gio_names (ENetworkMonitor *network_monitor)
507 {
508 GIOExtensionPoint *pnt;
509 GList *extensions, *link;
510 GSList *gio_names = NULL;
511
512 g_return_val_if_fail (E_IS_NETWORK_MONITOR (network_monitor), NULL);
513
514 /* To initialize the GIO extension point for the GNetworkMonitor */
515 g_network_monitor_get_default ();
516
517 pnt = g_io_extension_point_lookup (G_NETWORK_MONITOR_EXTENSION_POINT_NAME);
518 if (!pnt)
519 return NULL;
520
521 extensions = g_io_extension_point_get_extensions (pnt);
522
523 for (link = extensions; link; link = g_list_next (link)) {
524 GIOExtension *ext = link->data;
525
526 gio_names = g_slist_prepend (gio_names, g_strdup (g_io_extension_get_name (ext)));
527 }
528
529 return g_slist_reverse (gio_names);
530 }
531
532 /**
533 * e_network_monitor_dup_gio_name:
534 * @network_monitor: an #ENetworkMonitor
535 *
536 * Get currently set GIO name for the network availability checks.
537 * See e_network_monitor_set_gio_name() for more details.
538 *
539 * Returns: (transfer full): A newly allocated string, a GIO name
540 * of the underlying GNetworkMonitor which is set to be used.
541 * The returned string should be freed with g_free(), when
542 * no longer needed.
543 *
544 * Since: 3.22
545 **/
546 gchar *
e_network_monitor_dup_gio_name(ENetworkMonitor * network_monitor)547 e_network_monitor_dup_gio_name (ENetworkMonitor *network_monitor)
548 {
549 gchar *gio_name;
550
551 g_return_val_if_fail (E_IS_NETWORK_MONITOR (network_monitor), NULL);
552
553 g_mutex_lock (&network_monitor->priv->property_lock);
554 gio_name = g_strdup (network_monitor->priv->gio_name);
555 g_mutex_unlock (&network_monitor->priv->property_lock);
556
557 return gio_name;
558 }
559
560 /**
561 * e_network_monitor_set_gio_name:
562 * @network_monitor: an #ENetworkMonitor
563 * @gio_name: (nullable): a GIO name of a #GNetworkMonitor implementation to use, or %NULL
564 *
565 * Set a @gio_name of the #GNetworkMonitor implementation to use, can be %NULL.
566 * Use e_network_monitor_list_gio_names() for a list of available
567 * implementations. A special value, %E_NETWORK_MONITOR_ALWAYS_ONLINE_NAME, can
568 * be used to report the network as always reachable. When an unknown GIO
569 * name is used the default #GNetworkMonitor implementation, as returned
570 * by the g_network_monitor_get_default(), will be used.
571 *
572 * Since: 3.22
573 **/
574 void
e_network_monitor_set_gio_name(ENetworkMonitor * network_monitor,const gchar * gio_name)575 e_network_monitor_set_gio_name (ENetworkMonitor *network_monitor,
576 const gchar *gio_name)
577 {
578 GObject *object;
579
580 g_return_if_fail (E_IS_NETWORK_MONITOR (network_monitor));
581
582 g_mutex_lock (&network_monitor->priv->property_lock);
583
584 if (g_strcmp0 (gio_name, network_monitor->priv->gio_name) == 0) {
585 g_mutex_unlock (&network_monitor->priv->property_lock);
586 return;
587 }
588
589 g_free (network_monitor->priv->gio_name);
590 network_monitor->priv->gio_name = g_strdup (gio_name);
591
592 if (network_monitor->priv->gio_monitor)
593 e_network_monitor_disconnect_gio_monitor_locked (network_monitor);
594
595 g_clear_object (&network_monitor->priv->gio_monitor);
596
597 if (g_strcmp0 (network_monitor->priv->gio_name, E_NETWORK_MONITOR_ALWAYS_ONLINE_NAME) != 0) {
598 GNetworkMonitor *gio_monitor;
599
600 gio_monitor = e_network_monitor_create_instance_for_gio_name (network_monitor->priv->gio_name);
601 if (!gio_monitor)
602 gio_monitor = g_object_ref (g_network_monitor_get_default ());
603
604 network_monitor->priv->gio_monitor = gio_monitor;
605
606 if (gio_monitor) {
607 network_monitor->priv->network_available_notify_id =
608 g_signal_connect (network_monitor->priv->gio_monitor, "notify::network-available",
609 G_CALLBACK (e_network_monitor_notify_cb), network_monitor);
610
611 network_monitor->priv->network_metered_notify_id =
612 g_signal_connect (network_monitor->priv->gio_monitor, "notify::network-metered",
613 G_CALLBACK (e_network_monitor_notify_cb), network_monitor);
614
615 network_monitor->priv->network_connectivity_notify_id =
616 g_signal_connect (network_monitor->priv->gio_monitor, "notify::connectivity",
617 G_CALLBACK (e_network_monitor_notify_cb), network_monitor);
618
619 network_monitor->priv->network_changed_id =
620 g_signal_connect (network_monitor->priv->gio_monitor, "network-changed",
621 G_CALLBACK (e_network_monitor_network_changed_cb), network_monitor);
622 }
623 }
624
625 g_mutex_unlock (&network_monitor->priv->property_lock);
626
627 object = G_OBJECT (network_monitor);
628
629 g_object_freeze_notify (object);
630 g_object_notify (object, "gio-name");
631 g_object_notify (object, "network-available");
632 g_object_notify (object, "network-metered");
633 g_object_notify (object, "connectivity");
634 g_object_thaw_notify (object);
635
636 e_network_monitor_schedule_network_changed_emit (network_monitor);
637 }
638