1 /* ide-device-manager.c
2 *
3 * Copyright 2015-2019 Christian Hergert <christian@hergert.me>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: GPL-3.0-or-later
19 */
20
21 #define G_LOG_DOMAIN "ide-device-manager"
22
23 #include "config.h"
24
25 #include <glib/gi18n.h>
26 #include <libide-plugins.h>
27 #include <libide-threading.h>
28 #include <libpeas/peas.h>
29
30 #include "ide-build-manager.h"
31 #include "ide-pipeline.h"
32 #include "ide-deploy-strategy.h"
33 #include "ide-device-manager.h"
34 #include "ide-device-private.h"
35 #include "ide-device-provider.h"
36 #include "ide-device.h"
37 #include "ide-foundry-compat.h"
38 #include "ide-local-device.h"
39
40 struct _IdeDeviceManager
41 {
42 IdeObject parent_instance;
43
44 /*
45 * The currently selected device. Various subsystems will track this
46 * to update necessary changes for the device type. For example, the
47 * build pipeline will need to adjust things based on the current
48 * device to ensure we are building for the right architecture.
49 */
50 IdeDevice *device;
51
52 /*
53 * The devices that have been registered by IdeDeviceProvier plugins.
54 * It always has at least one device, the "local" device (IdeLocalDevice).
55 */
56 GPtrArray *devices;
57
58 /* Providers that are registered in plugins supporting IdeDeviceProvider. */
59 IdeExtensionSetAdapter *providers;
60
61 /*
62 * Our menu that contains our list of devices for the user to select. This
63 * is "per-IdeContext" so that it is not global to the system (which would
64 * result in duplicates for each workbench opened).
65 */
66 GMenu *menu;
67 GMenu *menu_section;
68
69 /*
70 * Our progress in a deployment. Simplifies binding to the progress bar
71 * in the omnibar.
72 */
73 gdouble progress;
74
75 guint loading : 1;
76 };
77
78 typedef struct
79 {
80 IdeObjectArray *strategies;
81 IdePipeline *pipeline;
82 } DeployState;
83
84 typedef struct
85 {
86 gint n_active;
87 } InitState;
88
89 static void list_model_init_interface (GListModelInterface *iface);
90 static void async_initable_init_iface (GAsyncInitableIface *iface);
91 static void ide_device_manager_action_device (IdeDeviceManager *self,
92 GVariant *param);
93 static void ide_device_manager_action_deploy (IdeDeviceManager *self,
94 GVariant *param);
95 static void ide_device_manager_deploy_tick (IdeTask *task);
96
97 DZL_DEFINE_ACTION_GROUP (IdeDeviceManager, ide_device_manager, {
98 { "device", ide_device_manager_action_device, "s", "'local'" },
99 { "deploy", ide_device_manager_action_deploy },
100 })
101
102 G_DEFINE_FINAL_TYPE_WITH_CODE (IdeDeviceManager, ide_device_manager, IDE_TYPE_OBJECT,
103 G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP,
104 ide_device_manager_init_action_group)
105 G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_init_iface)
106 G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, list_model_init_interface))
107
108 enum {
109 PROP_0,
110 PROP_DEVICE,
111 PROP_PROGRESS,
112 N_PROPS
113 };
114
115 enum {
116 DEPLOY_STARTED,
117 DEPLOY_FINISHED,
118 N_SIGNALS
119 };
120
121 static GParamSpec *properties [N_PROPS];
122 static guint signals [N_SIGNALS];
123
124 static void
deploy_state_free(DeployState * state)125 deploy_state_free (DeployState *state)
126 {
127 g_clear_object (&state->pipeline);
128 g_clear_pointer (&state->strategies, ide_object_array_unref);
129 g_slice_free (DeployState, state);
130 }
131
132 static void
ide_device_manager_provider_device_added_cb(IdeDeviceManager * self,IdeDevice * device,IdeDeviceProvider * provider)133 ide_device_manager_provider_device_added_cb (IdeDeviceManager *self,
134 IdeDevice *device,
135 IdeDeviceProvider *provider)
136 {
137 g_autoptr(GMenuItem) menu_item = NULL;
138 const gchar *display_name;
139 const gchar *icon_name;
140 const gchar *device_id;
141 guint position;
142
143 IDE_ENTRY;
144
145 g_assert (IDE_IS_DEVICE_MANAGER (self));
146 g_assert (IDE_IS_DEVICE (device));
147 g_assert (!provider || IDE_IS_DEVICE_PROVIDER (provider));
148
149 device_id = ide_device_get_id (device);
150 icon_name = ide_device_get_icon_name (device);
151 display_name = ide_device_get_display_name (device);
152
153 IDE_TRACE_MSG ("Discovered device %s", device_id);
154
155 /* Notify user of new device if this is after initial loading */
156 if (!self->loading)
157 {
158 g_autoptr(IdeNotification) notif = NULL;
159 g_autofree gchar *title = NULL;
160
161 /* translators: %s is replaced with the external device name */
162 title = g_strdup_printf (_("Discovered device “%s”"), display_name);
163 notif = g_object_new (IDE_TYPE_NOTIFICATION,
164 "id", "org.gnome.builder.device-manager.added",
165 "title", title,
166 "icon-name", icon_name,
167 NULL);
168
169 ide_notification_attach (notif, IDE_OBJECT (self));
170 ide_notification_withdraw_in_seconds (notif, -1);
171 }
172
173 /* First add the device to the array, we'll notify observers later */
174 position = self->devices->len;
175 g_ptr_array_add (self->devices, g_object_ref (device));
176
177 /* Now add a new menu item to our selection model */
178 menu_item = g_menu_item_new (display_name, NULL);
179 g_menu_item_set_attribute (menu_item, "id", "s", device_id);
180 g_menu_item_set_attribute (menu_item, "verb-icon-name", "s", icon_name ?: "computer-symbolic");
181 g_menu_item_set_action_and_target_value (menu_item,
182 "device-manager.device",
183 g_variant_new_string (device_id));
184 g_menu_append_item (self->menu_section, menu_item);
185
186 /* Now notify about the new device */
187 g_list_model_items_changed (G_LIST_MODEL (self), position, 0, 1);
188
189 IDE_EXIT;
190 }
191
192 static void
ide_device_manager_provider_device_removed_cb(IdeDeviceManager * self,IdeDevice * device,IdeDeviceProvider * provider)193 ide_device_manager_provider_device_removed_cb (IdeDeviceManager *self,
194 IdeDevice *device,
195 IdeDeviceProvider *provider)
196 {
197 const gchar *device_id;
198 GMenu *menu;
199 guint n_items;
200
201 IDE_ENTRY;
202
203 g_assert (IDE_IS_DEVICE_MANAGER (self));
204 g_assert (IDE_IS_DEVICE (device));
205 g_assert (IDE_IS_DEVICE_PROVIDER (provider));
206
207 device_id = ide_device_get_id (device);
208
209 menu = self->menu_section;
210 n_items = g_menu_model_get_n_items (G_MENU_MODEL (menu));
211
212 for (guint i = 0; i < n_items; i++)
213 {
214 g_autofree gchar *id = NULL;
215
216 if (g_menu_model_get_item_attribute (G_MENU_MODEL (menu), i, "id", "s", &id) &&
217 g_strcmp0 (id, device_id) == 0)
218 {
219 g_menu_remove (menu, i);
220 break;
221 }
222 }
223
224 for (guint i = 0; i < self->devices->len; i++)
225 {
226 IdeDevice *element = g_ptr_array_index (self->devices, i);
227
228 if (element == device)
229 {
230 g_ptr_array_remove_index (self->devices, i);
231 g_list_model_items_changed (G_LIST_MODEL (self), i, 1, 0);
232 break;
233 }
234 }
235
236 IDE_EXIT;
237 }
238
239 static void
ide_device_manager_provider_load_cb(GObject * object,GAsyncResult * result,gpointer user_data)240 ide_device_manager_provider_load_cb (GObject *object,
241 GAsyncResult *result,
242 gpointer user_data)
243 {
244 IdeDeviceProvider *provider = (IdeDeviceProvider *)object;
245 g_autoptr(IdeDeviceManager) self = user_data;
246 g_autoptr(GError) error = NULL;
247
248 IDE_ENTRY;
249
250 g_assert (IDE_IS_DEVICE_PROVIDER (provider));
251 g_assert (G_IS_ASYNC_RESULT (result));
252 g_assert (IDE_IS_DEVICE_MANAGER (self));
253
254 if (!ide_device_provider_load_finish (provider, result, &error))
255 g_warning ("%s failed to load: %s",
256 G_OBJECT_TYPE_NAME (provider),
257 error->message);
258
259 IDE_EXIT;
260 }
261
262 static void
ide_device_manager_provider_added_cb(IdeExtensionSetAdapter * set,PeasPluginInfo * plugin_info,PeasExtension * exten,gpointer user_data)263 ide_device_manager_provider_added_cb (IdeExtensionSetAdapter *set,
264 PeasPluginInfo *plugin_info,
265 PeasExtension *exten,
266 gpointer user_data)
267 {
268 IdeDeviceManager *self = user_data;
269 IdeDeviceProvider *provider = (IdeDeviceProvider *)exten;
270 g_autoptr(GPtrArray) devices = NULL;
271
272 IDE_ENTRY;
273
274 g_assert (IDE_IS_EXTENSION_SET_ADAPTER (set));
275 g_assert (IDE_IS_DEVICE_MANAGER (self));
276 g_assert (plugin_info != NULL);
277 g_assert (IDE_IS_DEVICE_PROVIDER (provider));
278
279 ide_object_append (IDE_OBJECT (self), IDE_OBJECT (provider));
280
281 g_signal_connect_object (provider,
282 "device-added",
283 G_CALLBACK (ide_device_manager_provider_device_added_cb),
284 self,
285 G_CONNECT_SWAPPED);
286
287 g_signal_connect_object (provider,
288 "device-removed",
289 G_CALLBACK (ide_device_manager_provider_device_removed_cb),
290 self,
291 G_CONNECT_SWAPPED);
292
293 devices = ide_device_provider_get_devices (provider);
294 IDE_PTR_ARRAY_SET_FREE_FUNC (devices, g_object_unref);
295
296 for (guint i = 0; i < devices->len; i++)
297 {
298 IdeDevice *device = g_ptr_array_index (devices, i);
299
300 g_assert (IDE_IS_DEVICE (device));
301
302 ide_device_manager_provider_device_added_cb (self, device, provider);
303 }
304
305 ide_device_provider_load_async (provider,
306 NULL,
307 ide_device_manager_provider_load_cb,
308 g_object_ref (self));
309
310 IDE_EXIT;
311 }
312
313 static void
ide_device_manager_provider_removed_cb(IdeExtensionSetAdapter * set,PeasPluginInfo * plugin_info,PeasExtension * exten,gpointer user_data)314 ide_device_manager_provider_removed_cb (IdeExtensionSetAdapter *set,
315 PeasPluginInfo *plugin_info,
316 PeasExtension *exten,
317 gpointer user_data)
318 {
319 IdeDeviceManager *self = user_data;
320 IdeDeviceProvider *provider = (IdeDeviceProvider *)exten;
321 g_autoptr(GPtrArray) devices = NULL;
322
323 IDE_ENTRY;
324
325 g_assert (IDE_IS_EXTENSION_SET_ADAPTER (set));
326 g_assert (IDE_IS_DEVICE_MANAGER (self));
327 g_assert (plugin_info != NULL);
328 g_assert (IDE_IS_DEVICE_PROVIDER (provider));
329
330 devices = ide_device_provider_get_devices (provider);
331 IDE_PTR_ARRAY_SET_FREE_FUNC (devices, g_object_unref);
332
333 for (guint i = 0; i < devices->len; i++)
334 {
335 IdeDevice *removed_device = g_ptr_array_index (devices, i);
336
337 for (guint j = 0; j < self->devices->len; j++)
338 {
339 IdeDevice *device = g_ptr_array_index (self->devices, j);
340
341 if (device == removed_device)
342 {
343 g_ptr_array_remove_index (self->devices, j);
344 g_list_model_items_changed (G_LIST_MODEL (self), j, 1, 0);
345 break;
346 }
347 }
348 }
349
350 g_signal_handlers_disconnect_by_func (provider,
351 G_CALLBACK (ide_device_manager_provider_device_added_cb),
352 self);
353
354 g_signal_handlers_disconnect_by_func (provider,
355 G_CALLBACK (ide_device_manager_provider_device_removed_cb),
356 self);
357
358 ide_object_destroy (IDE_OBJECT (provider));
359
360 IDE_EXIT;
361 }
362
363 static void
ide_device_manager_add_local(IdeDeviceManager * self)364 ide_device_manager_add_local (IdeDeviceManager *self)
365 {
366 g_autoptr(IdeDevice) device = NULL;
367 g_autoptr(IdeTriplet) triplet = NULL;
368 g_autofree gchar *arch = NULL;
369
370 g_return_if_fail (IDE_IS_DEVICE_MANAGER (self));
371
372 triplet = ide_triplet_new_from_system ();
373 device = g_object_new (IDE_TYPE_LOCAL_DEVICE,
374 "triplet", triplet,
375 NULL);
376 ide_object_append (IDE_OBJECT (self), IDE_OBJECT (device));
377 ide_device_manager_provider_device_added_cb (self, device, NULL);
378 }
379
380 static GType
ide_device_manager_get_item_type(GListModel * list_model)381 ide_device_manager_get_item_type (GListModel *list_model)
382 {
383 return IDE_TYPE_DEVICE;
384 }
385
386 static guint
ide_device_manager_get_n_items(GListModel * list_model)387 ide_device_manager_get_n_items (GListModel *list_model)
388 {
389 IdeDeviceManager *self = (IdeDeviceManager *)list_model;
390
391 g_assert (IDE_IS_DEVICE_MANAGER (self));
392
393 return self->devices->len;
394 }
395
396 static gpointer
ide_device_manager_get_item(GListModel * list_model,guint position)397 ide_device_manager_get_item (GListModel *list_model,
398 guint position)
399 {
400 IdeDeviceManager *self = (IdeDeviceManager *)list_model;
401
402 g_assert (IDE_IS_DEVICE_MANAGER (self));
403 g_assert (position < self->devices->len);
404
405 return g_object_ref (g_ptr_array_index (self->devices, position));
406 }
407
408 static void
ide_device_manager_destroy(IdeObject * object)409 ide_device_manager_destroy (IdeObject *object)
410 {
411 IdeDeviceManager *self = (IdeDeviceManager *)object;
412
413 g_assert (IDE_IS_OBJECT (object));
414 g_assert (IDE_IS_MAIN_THREAD ());
415
416 ide_clear_and_destroy_object (&self->providers);
417
418 IDE_OBJECT_CLASS (ide_device_manager_parent_class)->destroy (object);
419
420 if (self->devices->len > 0)
421 g_ptr_array_remove_range (self->devices, 0, self->devices->len);
422
423 g_clear_object (&self->device);
424 }
425
426 static void
ide_device_manager_finalize(GObject * object)427 ide_device_manager_finalize (GObject *object)
428 {
429 IdeDeviceManager *self = (IdeDeviceManager *)object;
430
431 g_clear_pointer (&self->devices, g_ptr_array_unref);
432 g_clear_object (&self->menu);
433 g_clear_object (&self->menu_section);
434
435 G_OBJECT_CLASS (ide_device_manager_parent_class)->finalize (object);
436 }
437
438 static void
ide_device_manager_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)439 ide_device_manager_get_property (GObject *object,
440 guint prop_id,
441 GValue *value,
442 GParamSpec *pspec)
443 {
444 IdeDeviceManager *self = IDE_DEVICE_MANAGER (object);
445
446 switch (prop_id)
447 {
448 case PROP_DEVICE:
449 g_value_set_object (value, ide_device_manager_get_device (self));
450 break;
451
452 case PROP_PROGRESS:
453 g_value_set_double (value, ide_device_manager_get_progress (self));
454 break;
455
456 default:
457 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
458 }
459 }
460
461 static void
ide_device_manager_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)462 ide_device_manager_set_property (GObject *object,
463 guint prop_id,
464 const GValue *value,
465 GParamSpec *pspec)
466 {
467 IdeDeviceManager *self = IDE_DEVICE_MANAGER (object);
468
469 switch (prop_id)
470 {
471 case PROP_DEVICE:
472 ide_device_manager_set_device (self, g_value_get_object (value));
473 break;
474
475 default:
476 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
477 }
478 }
479
480 static void
ide_device_manager_class_init(IdeDeviceManagerClass * klass)481 ide_device_manager_class_init (IdeDeviceManagerClass *klass)
482 {
483 GObjectClass *object_class = G_OBJECT_CLASS (klass);
484 IdeObjectClass *i_object_class = IDE_OBJECT_CLASS (klass);
485
486 object_class->finalize = ide_device_manager_finalize;
487 object_class->get_property = ide_device_manager_get_property;
488 object_class->set_property = ide_device_manager_set_property;
489
490 i_object_class->destroy = ide_device_manager_destroy;
491
492 /**
493 * IdeDeviceManager:device:
494 *
495 * The "device" property indicates the currently selected device by the
496 * user. This is the device we will try to deploy to when running, and
497 * execute the application on.
498 *
499 * Since: 3.32
500 */
501 properties [PROP_DEVICE] =
502 g_param_spec_object ("device",
503 "Device",
504 "The currently selected device to build for",
505 IDE_TYPE_DEVICE,
506 G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
507
508 /**
509 * IdeDeviceManager:progress:
510 *
511 * The "progress" property is updated with a value between 0.0 and 1.0 while
512 * the deployment is in progress.
513 *
514 * Since: 3.32
515 */
516 properties [PROP_PROGRESS] =
517 g_param_spec_double ("progress",
518 "Progress",
519 "Deployment progress",
520 0.0, 1.0, 0.0,
521 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
522
523 g_object_class_install_properties (object_class, N_PROPS, properties);
524
525 signals [DEPLOY_STARTED] =
526 g_signal_new ("deploy-started",
527 G_TYPE_FROM_CLASS (klass),
528 G_SIGNAL_RUN_LAST,
529 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
530
531 signals [DEPLOY_FINISHED] =
532 g_signal_new ("deploy-finished",
533 G_TYPE_FROM_CLASS (klass),
534 G_SIGNAL_RUN_LAST,
535 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
536 }
537
538 static void
list_model_init_interface(GListModelInterface * iface)539 list_model_init_interface (GListModelInterface *iface)
540 {
541 iface->get_item_type = ide_device_manager_get_item_type;
542 iface->get_n_items = ide_device_manager_get_n_items;
543 iface->get_item = ide_device_manager_get_item;
544 }
545
546 static void
ide_device_manager_init(IdeDeviceManager * self)547 ide_device_manager_init (IdeDeviceManager *self)
548 {
549 self->devices = g_ptr_array_new_with_free_func (g_object_unref);
550
551 self->menu = g_menu_new ();
552 self->menu_section = g_menu_new ();
553 g_menu_append_section (self->menu, _("Devices"), G_MENU_MODEL (self->menu_section));
554 }
555
556 /**
557 * ide_device_manager_get_device_by_id:
558 * @self: an #IdeDeviceManager
559 * @device_id: The device identifier string.
560 *
561 * Fetches the first device that matches the device identifier @device_id.
562 *
563 * Returns: (transfer none): An #IdeDevice or %NULL.
564 *
565 * Since: 3.32
566 */
567 IdeDevice *
ide_device_manager_get_device_by_id(IdeDeviceManager * self,const gchar * device_id)568 ide_device_manager_get_device_by_id (IdeDeviceManager *self,
569 const gchar *device_id)
570 {
571 g_return_val_if_fail (IDE_IS_DEVICE_MANAGER (self), NULL);
572
573 for (guint i = 0; i < self->devices->len; i++)
574 {
575 IdeDevice *device;
576 const gchar *id;
577
578 device = g_ptr_array_index (self->devices, i);
579 id = ide_device_get_id (device);
580
581 if (0 == g_strcmp0 (id, device_id))
582 return device;
583 }
584
585 return NULL;
586 }
587
588 /**
589 * ide_device_manager_get_device:
590 * @self: a #IdeDeviceManager
591 *
592 * Gets the currently selected device.
593 * Usually, this is an #IdeLocalDevice.
594 *
595 * Returns: (transfer none) (not nullable): an #IdeDevice
596 *
597 * Since: 3.32
598 */
599 IdeDevice *
ide_device_manager_get_device(IdeDeviceManager * self)600 ide_device_manager_get_device (IdeDeviceManager *self)
601 {
602 g_return_val_if_fail (IDE_IS_DEVICE_MANAGER (self), NULL);
603 g_return_val_if_fail (self->devices->len > 0, NULL);
604
605 if (self->device == NULL)
606 {
607 for (guint i = 0; i < self->devices->len; i++)
608 {
609 IdeDevice *device = g_ptr_array_index (self->devices, i);
610
611 if (IDE_IS_LOCAL_DEVICE (device))
612 return device;
613 }
614
615 g_assert_not_reached ();
616 }
617
618 return self->device;
619 }
620
621 /**
622 * ide_device_manager_set_device:
623 * @self: an #IdeDeviceManager
624 * @device: (nullable): an #IdeDevice or %NULL
625 *
626 * Sets the #IdeDeviceManager:device property, which is the currently selected
627 * device. Builder uses this to determine how to build the current project for
628 * the devices architecture and operating system.
629 *
630 * If @device is %NULL, the local device will be used.
631 *
632 * Since: 3.32
633 */
634 void
ide_device_manager_set_device(IdeDeviceManager * self,IdeDevice * device)635 ide_device_manager_set_device (IdeDeviceManager *self,
636 IdeDevice *device)
637 {
638 IDE_ENTRY;
639
640 g_return_if_fail (IDE_IS_DEVICE_MANAGER (self));
641 g_return_if_fail (!device || IDE_IS_DEVICE (device));
642
643 /* Short-circuit if we're setting to local and the current
644 * device is already local (null).
645 */
646 if (self->device == NULL &&
647 device != NULL &&
648 ide_str_equal0 ("local", ide_device_get_id (device)))
649 return;
650
651 if (g_set_object (&self->device, device))
652 {
653 const gchar *device_id = NULL;
654 IdeBuildManager *build_manager;
655 IdeContext *context;
656
657 context = ide_object_get_context (IDE_OBJECT (self));
658 build_manager = ide_build_manager_from_context (context);
659
660 if (device != NULL)
661 device_id = ide_device_get_id (device);
662
663 if (device_id == NULL)
664 device_id = "local";
665
666 IDE_TRACE_MSG ("Device set to %s", device_id);
667
668 ide_device_manager_set_action_state (self, "device", g_variant_new_string (device_id));
669 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DEVICE]);
670
671 ide_build_manager_invalidate (build_manager);
672 }
673
674 IDE_EXIT;
675 }
676
677 static void
ide_device_manager_action_device(IdeDeviceManager * self,GVariant * param)678 ide_device_manager_action_device (IdeDeviceManager *self,
679 GVariant *param)
680 {
681 const gchar *device_id;
682 IdeDevice *device;
683
684 IDE_ENTRY;
685
686 g_assert (IDE_IS_DEVICE_MANAGER (self));
687 g_assert (param != NULL);
688 g_assert (g_variant_is_of_type (param, G_VARIANT_TYPE_STRING));
689
690 if (!(device_id = g_variant_get_string (param, NULL)))
691 device_id = "local";
692
693 IDE_TRACE_MSG ("Setting device to \"%s\"", device_id);
694
695 if (!(device = ide_device_manager_get_device_by_id (self, device_id)))
696 {
697 g_debug ("No such device \"%s\"", device_id);
698 IDE_EXIT;
699 }
700
701 ide_device_manager_set_device (self, device);
702 }
703
704 static void
log_deploy_error(GObject * object,GAsyncResult * result,gpointer user_data)705 log_deploy_error (GObject *object,
706 GAsyncResult *result,
707 gpointer user_data)
708 {
709 g_autoptr(GError) error = NULL;
710
711 g_assert (IDE_IS_DEVICE_MANAGER (object));
712 g_assert (G_IS_ASYNC_RESULT (result));
713
714 if (!ide_device_manager_deploy_finish (IDE_DEVICE_MANAGER (object), result, &error))
715 ide_object_warning (object, "%s", error->message);
716 }
717
718 static void
ide_device_manager_action_deploy(IdeDeviceManager * self,GVariant * param)719 ide_device_manager_action_deploy (IdeDeviceManager *self,
720 GVariant *param)
721 {
722 IdePipeline *pipeline;
723 IdeBuildManager *build_manager;
724 IdeContext *context;
725
726 g_assert (IDE_IS_DEVICE_MANAGER (self));
727
728 context = ide_object_get_context (IDE_OBJECT (self));
729 build_manager = ide_build_manager_from_context (context);
730 pipeline = ide_build_manager_get_pipeline (build_manager);
731
732 if (!ide_pipeline_is_ready (pipeline))
733 ide_context_warning (context, _("Cannot deploy to device, build pipeline is not initialized"));
734 else
735 ide_device_manager_deploy_async (self, pipeline, NULL, log_deploy_error, NULL);
736 }
737
738 static void
deploy_progress_cb(goffset current_num_bytes,goffset total_num_bytes,gpointer user_data)739 deploy_progress_cb (goffset current_num_bytes,
740 goffset total_num_bytes,
741 gpointer user_data)
742 {
743 IdeDeviceManager *self = user_data;
744 gdouble progress = 0.0;
745
746 g_assert (IDE_IS_DEVICE_MANAGER (self));
747
748 if (total_num_bytes > 0)
749 progress = current_num_bytes / total_num_bytes;
750
751 self->progress = CLAMP (progress, 0.0, 1.0);
752 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PROGRESS]);
753 }
754
755 static void
collect_strategies(PeasExtensionSet * set,PeasPluginInfo * plugin_info,PeasExtension * exten,gpointer user_data)756 collect_strategies (PeasExtensionSet *set,
757 PeasPluginInfo *plugin_info,
758 PeasExtension *exten,
759 gpointer user_data)
760 {
761 IdeObjectArray *strategies = user_data;
762 IdeDeployStrategy *strategy = (IdeDeployStrategy *)exten;
763
764 g_assert (PEAS_IS_EXTENSION_SET (set));
765 g_assert (plugin_info != NULL);
766 g_assert (IDE_IS_DEPLOY_STRATEGY (strategy));
767 g_assert (strategies != NULL);
768
769 ide_object_array_add (strategies, strategy);
770 }
771
772 static void
ide_device_manager_deploy_cb(GObject * object,GAsyncResult * result,gpointer user_data)773 ide_device_manager_deploy_cb (GObject *object,
774 GAsyncResult *result,
775 gpointer user_data)
776 {
777 IdeDeployStrategy *strategy = (IdeDeployStrategy *)object;
778 g_autoptr(GError) error = NULL;
779 g_autoptr(IdeTask) task = user_data;
780
781 IDE_ENTRY;
782
783 g_assert (IDE_IS_DEPLOY_STRATEGY (strategy));
784 g_assert (G_IS_ASYNC_RESULT (result));
785 g_assert (IDE_IS_TASK (task));
786
787 if (!ide_deploy_strategy_deploy_finish (strategy, result, &error))
788 ide_task_return_error (task, g_steal_pointer (&error));
789 else
790 ide_task_return_boolean (task, TRUE);
791
792 IDE_EXIT;
793 }
794
795 static void
ide_device_manager_deploy_load_cb(GObject * object,GAsyncResult * result,gpointer user_data)796 ide_device_manager_deploy_load_cb (GObject *object,
797 GAsyncResult *result,
798 gpointer user_data)
799 {
800 IdeDeployStrategy *strategy = (IdeDeployStrategy *)object;
801 g_autoptr(GError) error = NULL;
802 g_autoptr(IdeTask) task = user_data;
803 IdeDeviceManager *self;
804 DeployState *state;
805
806 IDE_ENTRY;
807
808 g_assert (IDE_IS_DEPLOY_STRATEGY (strategy));
809 g_assert (G_IS_ASYNC_RESULT (result));
810 g_assert (IDE_IS_TASK (task));
811
812 if (!ide_deploy_strategy_load_finish (strategy, result, &error))
813 {
814 g_debug ("Deploy strategy failed to load: %s", error->message);
815 ide_object_destroy (IDE_OBJECT (strategy));
816 ide_device_manager_deploy_tick (task);
817 IDE_EXIT;
818 }
819
820 /* Okay, we found a match. Now deploy to the device. */
821
822 self = ide_task_get_source_object (task);
823 state = ide_task_get_task_data (task);
824
825 g_assert (IDE_IS_DEVICE_MANAGER (self));
826 g_assert (state != NULL);
827 g_assert (state->strategies != NULL);
828 g_assert (IDE_IS_PIPELINE (state->pipeline));
829
830 ide_deploy_strategy_deploy_async (strategy,
831 state->pipeline,
832 deploy_progress_cb,
833 g_object_ref (self),
834 g_object_unref,
835 ide_task_get_cancellable (task),
836 ide_device_manager_deploy_cb,
837 g_object_ref (task));
838
839 IDE_EXIT;
840 }
841
842 static void
ide_device_manager_deploy_tick(IdeTask * task)843 ide_device_manager_deploy_tick (IdeTask *task)
844 {
845 g_autoptr(IdeDeployStrategy) strategy = NULL;
846 DeployState *state;
847
848 IDE_ENTRY;
849
850 g_assert (IDE_IS_TASK (task));
851
852 state = ide_task_get_task_data (task);
853
854 g_assert (state != NULL);
855 g_assert (state->strategies != NULL);
856 g_assert (IDE_IS_PIPELINE (state->pipeline));
857
858 if (state->strategies->len == 0)
859 {
860 ide_task_return_new_error (task,
861 G_IO_ERROR,
862 G_IO_ERROR_NOT_SUPPORTED,
863 "Failed to locate deployment strategy for device");
864 IDE_EXIT;
865 }
866
867 strategy = ide_object_array_steal_index (state->strategies, 0);
868
869 ide_deploy_strategy_load_async (strategy,
870 state->pipeline,
871 ide_task_get_cancellable (task),
872 ide_device_manager_deploy_load_cb,
873 g_object_ref (task));
874
875 IDE_EXIT;
876 }
877
878 static void
ide_device_manager_deploy_completed(IdeDeviceManager * self,GParamSpec * pspec,IdeTask * task)879 ide_device_manager_deploy_completed (IdeDeviceManager *self,
880 GParamSpec *pspec,
881 IdeTask *task)
882 {
883 g_assert (IDE_IS_DEVICE_MANAGER (self));
884 g_assert (IDE_IS_TASK (task));
885
886 if (self->progress < 1.0)
887 {
888 self->progress = 1.0;
889 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PROGRESS]);
890 }
891
892 g_signal_emit (self, signals [DEPLOY_FINISHED], 0);
893 }
894
895 /**
896 * ide_device_manager_deploy_async:
897 * @self: a #IdeDeviceManager
898 * @pipeline: an #IdePipeline
899 * @cancellable: a #GCancellable, or %NULL
900 * @callback: a #GAsyncReadyCallback
901 * @user_data: closure data for @callback
902 *
903 * Requests that the application be deployed to the device. This may need to
904 * be done before running the application so that the device has the most
905 * up to date build.
906 *
907 * Since: 3.32
908 */
909 void
ide_device_manager_deploy_async(IdeDeviceManager * self,IdePipeline * pipeline,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)910 ide_device_manager_deploy_async (IdeDeviceManager *self,
911 IdePipeline *pipeline,
912 GCancellable *cancellable,
913 GAsyncReadyCallback callback,
914 gpointer user_data)
915 {
916 g_autoptr(PeasExtensionSet) set = NULL;
917 g_autoptr(IdeTask) task = NULL;
918 DeployState *state;
919 IdeDevice *device;
920
921 IDE_ENTRY;
922
923 g_return_if_fail (IDE_IS_DEVICE_MANAGER (self));
924 g_return_if_fail (IDE_IS_PIPELINE (pipeline));
925 g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
926
927 self->progress = 0.0;
928 g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PROGRESS]);
929
930 g_signal_emit (self, signals [DEPLOY_STARTED], 0);
931
932 task = ide_task_new (self, cancellable, callback, user_data);
933 ide_task_set_source_tag (task, ide_device_manager_deploy_async);
934
935 g_signal_connect_object (task,
936 "notify::completed",
937 G_CALLBACK (ide_device_manager_deploy_completed),
938 self,
939 G_CONNECT_SWAPPED);
940
941 if (!(device = ide_pipeline_get_device (pipeline)))
942 {
943 ide_task_return_new_error (task,
944 G_IO_ERROR,
945 G_IO_ERROR_FAILED,
946 "Missing device in pipeline");
947 IDE_EXIT;
948 }
949
950 if (IDE_IS_LOCAL_DEVICE (device))
951 {
952 ide_task_return_boolean (task, TRUE);
953 IDE_EXIT;
954 }
955
956 state = g_slice_new0 (DeployState);
957 state->pipeline = g_object_ref (pipeline);
958 state->strategies = ide_object_array_new ();
959 ide_task_set_task_data (task, state, deploy_state_free);
960
961 set = peas_extension_set_new (peas_engine_get_default (),
962 IDE_TYPE_DEPLOY_STRATEGY,
963 NULL);
964 peas_extension_set_foreach (set, collect_strategies, state->strategies);
965
966 /* Root the addins as children of us so that they get context access */
967 for (guint i = 0; i < state->strategies->len; i++)
968 ide_object_append (IDE_OBJECT (self),
969 ide_object_array_index (state->strategies, i));
970
971 ide_device_manager_deploy_tick (task);
972
973 IDE_EXIT;
974 }
975
976 /**
977 * ide_device_manager_deploy_finish:
978 * @self: a #IdeDeviceManager
979 * @result: a #GAsyncResult provided to callback
980 * @error: a location for a #GError, or %NULL
981 *
982 * Completes a request to deploy the application to the device.
983 *
984 * Returns: %TRUE if successful; otherwise %FALSE and @error is set
985 *
986 * Since: 3.32
987 */
988 gboolean
ide_device_manager_deploy_finish(IdeDeviceManager * self,GAsyncResult * result,GError ** error)989 ide_device_manager_deploy_finish (IdeDeviceManager *self,
990 GAsyncResult *result,
991 GError **error)
992 {
993 gboolean ret;
994
995 IDE_ENTRY;
996
997 g_return_val_if_fail (IDE_IS_DEVICE_MANAGER (self), FALSE);
998 g_return_val_if_fail (IDE_IS_TASK (result), FALSE);
999 g_return_val_if_fail (ide_task_is_valid (IDE_TASK (result), self), FALSE);
1000
1001 ret = ide_task_propagate_boolean (IDE_TASK (result), error);
1002
1003 IDE_RETURN (ret);
1004 }
1005
1006 static void
ide_device_manager_create_runner_cb(GObject * object,GAsyncResult * result,gpointer user_data)1007 ide_device_manager_create_runner_cb (GObject *object,
1008 GAsyncResult *result,
1009 gpointer user_data)
1010 {
1011 IdeDeployStrategy *strategy = (IdeDeployStrategy *)object;
1012 g_autoptr(GError) error = NULL;
1013 g_autoptr(IdeTask) task = user_data;
1014 IdeRunner *runner;
1015
1016 IDE_ENTRY;
1017
1018 g_assert (IDE_IS_DEPLOY_STRATEGY (strategy));
1019 g_assert (G_IS_ASYNC_RESULT (result));
1020 g_assert (IDE_IS_TASK (task));
1021
1022 runner = ide_deploy_strategy_create_runner_finish (strategy, result, &error);
1023
1024 if (error)
1025 ide_task_return_error (task, g_steal_pointer (&error));
1026 else
1027 ide_task_return_pointer (task, runner, g_object_unref);
1028
1029 ide_object_destroy (IDE_OBJECT (strategy));
1030
1031 IDE_EXIT;
1032 }
1033
1034 static void
ide_device_manager_create_runner_load_cb(GObject * object,GAsyncResult * result,gpointer user_data)1035 ide_device_manager_create_runner_load_cb (GObject *object,
1036 GAsyncResult *result,
1037 gpointer user_data)
1038 {
1039 IdeDeployStrategy *strategy = (IdeDeployStrategy *)object;
1040 g_autoptr(GError) error = NULL;
1041 g_autoptr(IdeTask) task = user_data;
1042 IdeDeviceManager *self;
1043 DeployState *state;
1044
1045 IDE_ENTRY;
1046
1047 g_assert (IDE_IS_DEPLOY_STRATEGY (strategy));
1048 g_assert (G_IS_ASYNC_RESULT (result));
1049 g_assert (IDE_IS_TASK (task));
1050
1051 if (!ide_deploy_strategy_load_finish (strategy, result, &error))
1052 {
1053 g_debug ("Deploy strategy failed to load: %s", error->message);
1054 ide_object_destroy (IDE_OBJECT (strategy));
1055 ide_device_manager_deploy_tick (task);
1056 IDE_EXIT;
1057 }
1058
1059 /* Okay, we found a match. Now run on the device. */
1060
1061 self = ide_task_get_source_object (task);
1062 state = ide_task_get_task_data (task);
1063
1064 g_assert (IDE_IS_DEVICE_MANAGER (self));
1065 g_assert (state != NULL);
1066 g_assert (state->strategies != NULL);
1067 g_assert (IDE_IS_PIPELINE (state->pipeline));
1068
1069 ide_deploy_strategy_create_runner_async (strategy,
1070 state->pipeline,
1071 ide_task_get_cancellable (task),
1072 ide_device_manager_create_runner_cb,
1073 g_object_ref (task));
1074
1075 IDE_EXIT;
1076 }
1077
1078 static void
ide_device_manager_create_runner_tick(IdeTask * task)1079 ide_device_manager_create_runner_tick (IdeTask *task)
1080 {
1081 g_autoptr(IdeDeployStrategy) strategy = NULL;
1082 DeployState *state;
1083
1084 IDE_ENTRY;
1085
1086 g_assert (IDE_IS_TASK (task));
1087
1088 state = ide_task_get_task_data (task);
1089
1090 g_assert (state != NULL);
1091 g_assert (state->strategies != NULL);
1092 g_assert (IDE_IS_PIPELINE (state->pipeline));
1093
1094 if (state->strategies->len == 0)
1095 {
1096 ide_task_return_new_error (task,
1097 G_IO_ERROR,
1098 G_IO_ERROR_NOT_SUPPORTED,
1099 "Failed to locate deployment strategy for device");
1100 IDE_EXIT;
1101 }
1102
1103 strategy = ide_object_array_steal_index (state->strategies, 0);
1104
1105 ide_deploy_strategy_load_async (strategy,
1106 state->pipeline,
1107 ide_task_get_cancellable (task),
1108 ide_device_manager_create_runner_load_cb,
1109 g_object_ref (task));
1110
1111 IDE_EXIT;
1112 }
1113
1114 /**
1115 * ide_device_manager_create_runner_async:
1116 * @self: a #IdeDeviceManager
1117 * @pipeline: an #IdePipeline
1118 * @cancellable: a #GCancellable, or %NULL
1119 * @callback: a #GAsyncReadyCallback
1120 * @user_data: closure data for @callback
1121 *
1122 * Requests an #IdeRunner that runs on the current device, if a runner
1123 * other than the default is required.
1124 *
1125 * Since: 41
1126 */
1127 void
ide_device_manager_create_runner_async(IdeDeviceManager * self,IdePipeline * pipeline,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1128 ide_device_manager_create_runner_async (IdeDeviceManager *self,
1129 IdePipeline *pipeline,
1130 GCancellable *cancellable,
1131 GAsyncReadyCallback callback,
1132 gpointer user_data)
1133 {
1134 g_autoptr(PeasExtensionSet) set = NULL;
1135 g_autoptr(IdeTask) task = NULL;
1136 DeployState *state;
1137 IdeDevice *device;
1138
1139 IDE_ENTRY;
1140
1141 g_return_if_fail (IDE_IS_DEVICE_MANAGER (self));
1142 g_return_if_fail (IDE_IS_PIPELINE (pipeline));
1143 g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
1144
1145 task = ide_task_new (self, cancellable, callback, user_data);
1146 ide_task_set_source_tag (task, ide_device_manager_create_runner_async);
1147
1148 if (!(device = ide_pipeline_get_device (pipeline)))
1149 {
1150 ide_task_return_new_error (task,
1151 G_IO_ERROR,
1152 G_IO_ERROR_FAILED,
1153 "Missing device in pipeline");
1154 IDE_EXIT;
1155 }
1156
1157 if (IDE_IS_LOCAL_DEVICE (device))
1158 {
1159 (ide_task_return_pointer) (task, NULL, NULL);
1160 IDE_EXIT;
1161 }
1162
1163 state = g_slice_new0 (DeployState);
1164 state->pipeline = g_object_ref (pipeline);
1165 state->strategies = ide_object_array_new ();
1166 ide_task_set_task_data (task, state, deploy_state_free);
1167
1168 set = peas_extension_set_new (peas_engine_get_default (),
1169 IDE_TYPE_DEPLOY_STRATEGY,
1170 NULL);
1171 peas_extension_set_foreach (set, collect_strategies, state->strategies);
1172
1173 /* Root the addins as children of us so that they get context access */
1174 for (guint i = 0; i < state->strategies->len; i++)
1175 ide_object_append (IDE_OBJECT (self),
1176 ide_object_array_index (state->strategies, i));
1177
1178 ide_device_manager_create_runner_tick (task);
1179
1180 IDE_EXIT;
1181 }
1182
1183 /**
1184 * ide_device_manager_create_runner_finish:
1185 * @self: a #IdeDeviceManager
1186 * @result: a #GAsyncResult provided to callback
1187 * @error: a location for a #GError, or %NULL
1188 *
1189 * Completes a request to create an #IdeRunner to run on the device.
1190 *
1191 * Returns: (transfer full): An #IdeRunner or %NULL.
1192 *
1193 * Since: 41
1194 */
1195 IdeRunner *
ide_device_manager_create_runner_finish(IdeDeviceManager * self,GAsyncResult * result,GError ** error)1196 ide_device_manager_create_runner_finish (IdeDeviceManager *self,
1197 GAsyncResult *result,
1198 GError **error)
1199 {
1200 IdeRunner *ret;
1201
1202 IDE_ENTRY;
1203
1204 g_return_val_if_fail (IDE_IS_DEVICE_MANAGER (self), FALSE);
1205 g_return_val_if_fail (IDE_IS_TASK (result), FALSE);
1206 g_return_val_if_fail (ide_task_is_valid (IDE_TASK (result), self), FALSE);
1207
1208 ret = ide_task_propagate_pointer (IDE_TASK (result), error);
1209
1210 IDE_RETURN (ret);
1211 }
1212
1213 gdouble
ide_device_manager_get_progress(IdeDeviceManager * self)1214 ide_device_manager_get_progress (IdeDeviceManager *self)
1215 {
1216 g_return_val_if_fail (IDE_IS_DEVICE_MANAGER (self), 0.0);
1217
1218 return self->progress;
1219 }
1220
1221 GMenu *
_ide_device_manager_get_menu(IdeDeviceManager * self)1222 _ide_device_manager_get_menu (IdeDeviceManager *self)
1223 {
1224 g_return_val_if_fail (IDE_IS_DEVICE_MANAGER (self), NULL);
1225
1226 return self->menu;
1227 }
1228
1229 static void
ide_device_manager_init_provider_load_cb(GObject * object,GAsyncResult * result,gpointer user_data)1230 ide_device_manager_init_provider_load_cb (GObject *object,
1231 GAsyncResult *result,
1232 gpointer user_data)
1233 {
1234 IdeDeviceProvider *provider = (IdeDeviceProvider *)object;
1235 g_autoptr(IdeTask) task = user_data;
1236 g_autoptr(GError) error = NULL;
1237 InitState *state;
1238
1239 g_assert (IDE_IS_MAIN_THREAD ());
1240 g_assert (IDE_IS_DEVICE_PROVIDER (provider));
1241 g_assert (G_IS_ASYNC_RESULT (result));
1242 g_assert (IDE_IS_TASK (task));
1243
1244 if (!ide_device_provider_load_finish (provider, result, &error))
1245 g_warning ("%s: %s", G_OBJECT_TYPE_NAME (provider), error->message);
1246
1247 state = ide_task_get_task_data (task);
1248 state->n_active--;
1249
1250 if (state->n_active == 0)
1251 ide_task_return_boolean (task, TRUE);
1252 }
1253
1254 static void
ide_device_manager_init_provider_cb(IdeExtensionSetAdapter * set,PeasPluginInfo * plugin_info,PeasExtension * exten,gpointer user_data)1255 ide_device_manager_init_provider_cb (IdeExtensionSetAdapter *set,
1256 PeasPluginInfo *plugin_info,
1257 PeasExtension *exten,
1258 gpointer user_data)
1259 {
1260 IdeDeviceProvider *provider = (IdeDeviceProvider *)exten;
1261 IdeDeviceManager *self;
1262 IdeTask *task = user_data;
1263 InitState *state;
1264
1265 g_assert (IDE_IS_MAIN_THREAD ());
1266 g_assert (IDE_IS_EXTENSION_SET_ADAPTER (set));
1267 g_assert (plugin_info != NULL);
1268 g_assert (IDE_IS_DEVICE_PROVIDER (provider));
1269 g_assert (IDE_IS_TASK (task));
1270
1271 self = ide_task_get_source_object (task);
1272 state = ide_task_get_task_data (task);
1273 state->n_active++;
1274
1275 g_signal_connect_object (provider,
1276 "device-added",
1277 G_CALLBACK (ide_device_manager_provider_device_added_cb),
1278 self,
1279 G_CONNECT_SWAPPED);
1280
1281 g_signal_connect_object (provider,
1282 "device-removed",
1283 G_CALLBACK (ide_device_manager_provider_device_removed_cb),
1284 self,
1285 G_CONNECT_SWAPPED);
1286
1287 ide_device_provider_load_async (provider,
1288 ide_task_get_cancellable (task),
1289 ide_device_manager_init_provider_load_cb,
1290 g_object_ref (task));
1291 }
1292
1293 static void
ide_device_manager_init_async(GAsyncInitable * initable,gint io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1294 ide_device_manager_init_async (GAsyncInitable *initable,
1295 gint io_priority,
1296 GCancellable *cancellable,
1297 GAsyncReadyCallback callback,
1298 gpointer user_data)
1299 {
1300 IdeDeviceManager *self = (IdeDeviceManager *)initable;
1301 g_autoptr(IdeTask) task = NULL;
1302 InitState *state;
1303
1304 IDE_ENTRY;
1305
1306 g_assert (IDE_IS_MAIN_THREAD ());
1307 g_assert (IDE_IS_DEVICE_MANAGER (self));
1308 g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
1309
1310 task = ide_task_new (self, cancellable, callback, user_data);
1311 ide_task_set_source_tag (task, ide_device_manager_init_async);
1312 ide_task_set_priority (task, io_priority);
1313
1314 self->loading = TRUE;
1315
1316 state = g_new0 (InitState, 1);
1317 ide_task_set_task_data (task, state, g_free);
1318
1319 ide_device_manager_add_local (self);
1320
1321 self->providers = ide_extension_set_adapter_new (IDE_OBJECT (self),
1322 peas_engine_get_default (),
1323 IDE_TYPE_DEVICE_PROVIDER,
1324 NULL, NULL);
1325
1326 g_signal_connect (self->providers,
1327 "extension-added",
1328 G_CALLBACK (ide_device_manager_provider_added_cb),
1329 self);
1330
1331 g_signal_connect (self->providers,
1332 "extension-removed",
1333 G_CALLBACK (ide_device_manager_provider_removed_cb),
1334 self);
1335
1336 ide_extension_set_adapter_foreach (self->providers,
1337 ide_device_manager_init_provider_cb,
1338 task);
1339
1340 if (state->n_active == 0)
1341 ide_task_return_boolean (task, TRUE);
1342
1343 IDE_EXIT;
1344 }
1345
1346 static gboolean
ide_device_manager_init_finish(GAsyncInitable * initable,GAsyncResult * result,GError ** error)1347 ide_device_manager_init_finish (GAsyncInitable *initable,
1348 GAsyncResult *result,
1349 GError **error)
1350 {
1351 IdeDeviceManager *self = (IdeDeviceManager *)initable;
1352 gboolean ret;
1353
1354 IDE_ENTRY;
1355
1356 g_assert (IDE_IS_MAIN_THREAD ());
1357 g_assert (IDE_IS_DEVICE_MANAGER (initable));
1358 g_assert (IDE_IS_TASK (result));
1359
1360 self->loading = FALSE;
1361
1362 ret = ide_task_propagate_boolean (IDE_TASK (result), error);
1363
1364 IDE_RETURN (ret);
1365 }
1366
1367 static void
async_initable_init_iface(GAsyncInitableIface * iface)1368 async_initable_init_iface (GAsyncInitableIface *iface)
1369 {
1370 iface->init_async = ide_device_manager_init_async;
1371 iface->init_finish = ide_device_manager_init_finish;
1372 }
1373