/** * g_dbus_object_skeleton_set_object_path: * @object: A #GDBusObjectSkeleton. * @object_path: A valid D-Bus object path. * * Sets the object path for @object. * * Since: 2.30 */ void g_dbus_object_skeleton_set_object_path (GDBusObjectSkeleton *object, const gchar *object_path) { g_return_if_fail (G_IS_DBUS_OBJECT_SKELETON (object)); g_return_if_fail (object_path == NULL || g_variant_is_object_path (object_path)); g_mutex_lock (object->priv->lock); /* TODO: fail if object is currently exported */ if (g_strcmp0 (object->priv->object_path, object_path) != 0) { g_free (object->priv->object_path); object->priv->object_path = g_strdup (object_path); g_mutex_unlock (object->priv->lock); g_object_notify (G_OBJECT (object), "object-path"); } else { g_mutex_unlock (object->priv->lock); } }
/* < internal > * _g_dbus_method_invocation_new: * @sender: (allow-none): The bus name that invoked the method or %NULL if @connection is not a bus connection. * @object_path: The object path the method was invoked on. * @interface_name: The name of the D-Bus interface the method was invoked on. * @method_name: The name of the method that was invoked. * @method_info: (allow-none): Information about the method call or %NULL. * @property_info: (allow-none): Information about the property or %NULL. * @connection: The #GDBusConnection the method was invoked on. * @message: The D-Bus message as a #GDBusMessage. * @parameters: The parameters as a #GVariant tuple. * @user_data: The @user_data #gpointer passed to g_dbus_connection_register_object(). * * Creates a new #GDBusMethodInvocation object. * * Returns: A #GDBusMethodInvocation. Free with g_object_unref(). * * Since: 2.26 */ GDBusMethodInvocation * _g_dbus_method_invocation_new (const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, const GDBusMethodInfo *method_info, const GDBusPropertyInfo *property_info, GDBusConnection *connection, GDBusMessage *message, GVariant *parameters, gpointer user_data) { GDBusMethodInvocation *invocation; g_return_val_if_fail (sender == NULL || g_dbus_is_name (sender), NULL); g_return_val_if_fail (g_variant_is_object_path (object_path), NULL); g_return_val_if_fail (interface_name == NULL || g_dbus_is_interface_name (interface_name), NULL); g_return_val_if_fail (g_dbus_is_member_name (method_name), NULL); g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL); g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL); g_return_val_if_fail (g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE), NULL); invocation = G_DBUS_METHOD_INVOCATION (g_object_new (G_TYPE_DBUS_METHOD_INVOCATION, NULL)); invocation->sender = g_strdup (sender); invocation->object_path = g_strdup (object_path); invocation->interface_name = g_strdup (interface_name); invocation->method_name = g_strdup (method_name); if (method_info) invocation->method_info = g_dbus_method_info_ref ((GDBusMethodInfo *)method_info); if (property_info) invocation->property_info = g_dbus_property_info_ref ((GDBusPropertyInfo *)property_info); invocation->connection = g_object_ref (connection); invocation->message = g_object_ref (message); invocation->parameters = g_variant_ref (parameters); invocation->user_data = user_data; return invocation; }
static gboolean terminal_factory_impl_create_instance (TerminalFactory *factory, GDBusMethodInvocation *invocation, GVariant *options) { TerminalApp *app = terminal_app_get (); TerminalSettingsList *profiles_list; GDBusObjectManagerServer *object_manager; TerminalWindow *window; TerminalScreen *screen; TerminalReceiverImpl *impl; TerminalObjectSkeleton *skeleton; char *object_path; GSettings *profile = NULL; const char *profile_uuid, *title, *encoding; gboolean zoom_set = FALSE; gdouble zoom = 1.0; guint window_id; gboolean show_menubar; gboolean active; gboolean have_new_window, present_window, present_window_set; GError *err = NULL; /* Look up the profile */ if (!g_variant_lookup (options, "profile", "&s", &profile_uuid)) profile_uuid = NULL; if (!g_variant_lookup (options, "encoding", "&s", &encoding)) encoding = NULL; /* use profile encoding */ profiles_list = terminal_app_get_profiles_list (app); profile = terminal_profiles_list_ref_profile_by_uuid (profiles_list, profile_uuid, &err); if (profile == NULL) { g_dbus_method_invocation_return_gerror (invocation, err); g_error_free (err); goto out; } if (g_variant_lookup (options, "window-id", "u", &window_id)) { GtkWindow *win; win = gtk_application_get_window_by_id (GTK_APPLICATION (app), window_id); if (!TERMINAL_IS_WINDOW (win)) { g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Nonexisting window %u referenced", window_id); goto out; } window = TERMINAL_WINDOW (win); have_new_window = FALSE; } else { const char *startup_id, *display_name, *role; gboolean start_maximized, start_fullscreen; int screen_number; GdkScreen *gdk_screen; /* Create a new window */ if (!g_variant_lookup (options, "display", "^&ay", &display_name)) { g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "No display specified"); goto out; } screen_number = 0; gdk_screen = terminal_util_get_screen_by_display_name (display_name, screen_number); if (gdk_screen == NULL) { g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "No screen %d on display \"%s\"", screen_number, display_name); goto out; } window = terminal_app_new_window (app, gdk_screen); if (g_variant_lookup (options, "desktop-startup-id", "^&ay", &startup_id)) gtk_window_set_startup_id (GTK_WINDOW (window), startup_id); /* Overwrite the default, unique window role set in terminal_window_init */ if (g_variant_lookup (options, "role", "&s", &role)) gtk_window_set_role (GTK_WINDOW (window), role); if (g_variant_lookup (options, "show-menubar", "b", &show_menubar)) terminal_window_set_menubar_visible (window, show_menubar); if (g_variant_lookup (options, "fullscreen-window", "b", &start_fullscreen) && start_fullscreen) { gtk_window_fullscreen (GTK_WINDOW (window)); } if (g_variant_lookup (options, "maximize-window", "b", &start_maximized) && start_maximized) { gtk_window_maximize (GTK_WINDOW (window)); } have_new_window = TRUE; } g_assert (window != NULL); if (!g_variant_lookup (options, "title", "&s", &title)) title = NULL; if (g_variant_lookup (options, "zoom", "d", &zoom)) zoom_set = TRUE; screen = terminal_screen_new (profile, encoding, NULL, title, NULL, NULL, zoom_set ? zoom : 1.0); terminal_window_add_screen (window, screen, -1); object_path = get_object_path_for_screen (window, screen); g_assert (g_variant_is_object_path (object_path)); skeleton = terminal_object_skeleton_new (object_path); impl = terminal_receiver_impl_new (screen); terminal_object_skeleton_set_receiver (skeleton, TERMINAL_RECEIVER (impl)); g_object_unref (impl); object_manager = terminal_app_get_object_manager (app); g_dbus_object_manager_server_export (object_manager, G_DBUS_OBJECT_SKELETON (skeleton)); g_object_set_data_full (G_OBJECT (screen), RECEIVER_IMPL_SKELETON_DATA_KEY, skeleton, (GDestroyNotify) g_object_unref); g_signal_connect (screen, "destroy", G_CALLBACK (screen_destroy_cb), app); if (g_variant_lookup (options, "active", "b", &active) && active) { terminal_window_switch_screen (window, screen); gtk_widget_grab_focus (GTK_WIDGET (screen)); } if (g_variant_lookup (options, "present-window", "b", &present_window)) present_window_set = TRUE; else present_window_set = FALSE; if (have_new_window) { const char *geometry; if (g_variant_lookup (options, "geometry", "&s", &geometry) && !terminal_window_parse_geometry (window, geometry)) _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, "Invalid geometry string \"%s\"", geometry); } if (have_new_window || (present_window_set && present_window)) gtk_window_present (GTK_WINDOW (window)); terminal_factory_complete_create_instance (factory, invocation, object_path); g_free (object_path); out: if (profile) g_object_unref (profile); return TRUE; /* handled */ }
/** * Initialize GATT descriptor fields. * * This function initializes the @c CAGattDescriptor object fields. * * @param[out] c Information about GATT characteristic * to which the descriptor belongs. * @param[in] connection D-Bus connection to the bus on which * the descriptor will be exported. * @param[in] s Information about GATT service * information to which the descriptor * belongs. * @param[in] descriptor_path @c GattDescriptor1 object path for the * user description descriptor. * @param[in] value User description descriptor value, * e.g. @c "OIC Node Request" or * @c "OIC Node Response". * * @note This function does not allocate the @a descriptor object * itself. The caller is responsible for allocating that * memory. * * @todo Too many parameters. Perhaps pass in a pointer to a struct * instead. */ static bool CAGattDescriptorInitialize(CAGattCharacteristic * c, GDBusConnection * connection, CAGattService * s, char const * descriptor_path, char const * value) { (void)s; CAGattDescriptor * const d = &c->descriptor; // Path of the form /org/iotivity/gatt/hci0/service0/char0/desc0. d->object_path = g_strdup_printf("%s/%s", c->object_path, descriptor_path); assert(g_variant_is_object_path(d->object_path)); d->descriptor = gatt_descriptor1_skeleton_new(); gatt_descriptor1_set_uuid( d->descriptor, CA_GATT_CHRC_USER_DESCRIPTION_DESC_UUID); gatt_descriptor1_set_characteristic(d->descriptor, c->object_path); gatt_descriptor1_set_value (d->descriptor, g_variant_new_bytestring(value)); // Readable, no encryption, no authorization. static char const * const flags[] = { "read", NULL }; gatt_descriptor1_set_flags(d->descriptor, flags); /* Connect the signal handler that implements the orb.bluez.GattDescriptor1.ReadValue() method. */ g_signal_connect(d->descriptor, "handle-read-value", G_CALLBACK(CAGattDescriptorReadValue), NULL); // Export the descriptor interface on the bus. GError * error = NULL; if (!g_dbus_interface_skeleton_export( G_DBUS_INTERFACE_SKELETON(d->descriptor), connection, d->object_path, &error)) { CAGattDescriptorDestroy(d); OIC_LOG_V(ERROR, TAG, "Unable to export D-Bus GATT descriptor " "interface: %s", error->message); g_error_free(error); return false; } return true; }
// ret: // 0: change to another session // 1: stay current session int switch_to_greeter(gchar *seat_path, struct user_session_dbus *usd) { int ret = 1; char **sessions = NULL; char *seat = NULL; char *display = NULL; char *cur_seat = NULL; gchar **strlist = NULL; char *new_user_session = NULL; GDBusProxy *seat_proxy = NULL; GDBusProxy *login1_proxy = NULL; GError *error = NULL; if (!g_variant_is_object_path(seat_path)) { g_warning("switchtogreeter:invalid object path\n"); return 1; } seat_proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.freedesktop.DisplayManager", seat_path, "org.freedesktop.DisplayManager.Seat", NULL, &error); if (error != NULL) { g_warning("switchtogreeter:seat proxy %s\n", error->message); g_error_free(error); return 1; } error = NULL; printf("current seat path: %s\n", seat_path); strlist = g_strsplit(seat_path, "/", -1); while (*strlist) { cur_seat = *strlist; strlist++; } printf("current seat: %s\n", cur_seat); printf("usd->session_path: %s\n", usd->session_path); printf("usd->username: %s\n", usd->username); if (usd->session_path != NULL && usd->username != NULL) { sd_uid_get_sessions(name_to_uid(usd->username), 0, &sessions); while (*sessions) { sd_session_get_display(*sessions, &display); if (NULL == display){ sessions++; continue; } sd_session_get_seat(*sessions, &seat); printf("session display %s %s\n", *sessions, display); if (seat != NULL && (0 == g_ascii_strcasecmp(seat, cur_seat))) { new_user_session = *sessions; printf("switchtogreeter: find sessions path %s %s \n", new_user_session, seat); break; } sessions++; } if (NULL == new_user_session) { g_error("switchtogreeter: can not find user sessions %s \n", usd->username); return 1; } printf("find user session: %s\n", new_user_session); login1_proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", NULL, &error); g_dbus_proxy_call_sync(login1_proxy, "ActivateSession", g_variant_new("(s)", new_user_session), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); ret = 0; } else if (usd->username != NULL) { printf("SwitchToUser\n"); usd->session_path = ""; g_dbus_proxy_call_sync(seat_proxy, "SwitchToUser", g_variant_new("(ss)", usd->username, usd->session_path), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); ret = 1; } else { g_dbus_proxy_call_sync(seat_proxy, "SwitchToGreeter", g_variant_new("()"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); ret = 1; } if (error != NULL) { g_warning("switchtogreeter:seat switchtogreeter %s\n", error->message); g_error_free(error); } error = NULL; g_object_unref(seat_proxy); return ret; }
static void process_config_entries (GoaDaemon *daemon, GHashTable *group_name_to_key_file_data) { GHashTableIter iter; const gchar *id; KeyFileData *key_file_data; GList *existing_object_paths; GList *config_object_paths; GList *added; GList *removed; GList *unchanged; GList *l; existing_object_paths = NULL; { GList *existing_objects; existing_objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (daemon->object_manager)); for (l = existing_objects; l != NULL; l = l->next) { GoaObject *object = GOA_OBJECT (l->data); const gchar *object_path; object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object)); if (g_str_has_prefix (object_path, "/org/gnome/OnlineAccounts/Accounts/")) existing_object_paths = g_list_prepend (existing_object_paths, g_strdup (object_path)); } g_list_foreach (existing_objects, (GFunc) g_object_unref, NULL); g_list_free (existing_objects); } config_object_paths = NULL; g_hash_table_iter_init (&iter, group_name_to_key_file_data); while (g_hash_table_iter_next (&iter, (gpointer*) &id, (gpointer*) &key_file_data)) { gchar *object_path; /* create and validate object path */ object_path = g_strdup_printf ("/org/gnome/OnlineAccounts/Accounts/%s", id + sizeof "Account " - 1); if (strstr (id + sizeof "Account " - 1, "/") != NULL || !g_variant_is_object_path (object_path)) { g_warning ("`%s' is not a valid account identifier", id); g_free (object_path); continue; } /* steals object_path variable */ config_object_paths = g_list_prepend (config_object_paths, object_path); } existing_object_paths = g_list_sort (existing_object_paths, (GCompareFunc) g_strcmp0); config_object_paths = g_list_sort (config_object_paths, (GCompareFunc) g_strcmp0); diff_sorted_lists (existing_object_paths, config_object_paths, (GCompareFunc) g_strcmp0, &added, &removed, &unchanged); for (l = removed; l != NULL; l = l->next) { const gchar *object_path = l->data; GoaObject *object; object = GOA_OBJECT (g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (daemon->object_manager), object_path)); g_warn_if_fail (object != NULL); g_signal_handlers_disconnect_by_func (goa_object_peek_account (object), G_CALLBACK (on_account_handle_remove), daemon); g_debug ("removing %s", object_path); g_warn_if_fail (g_dbus_object_manager_server_unexport (daemon->object_manager, object_path)); } for (l = added; l != NULL; l = l->next) { const gchar *object_path = l->data; GoaObjectSkeleton *object; gchar *group; g_debug ("adding %s", object_path); group = object_path_to_group (object_path); key_file_data = g_hash_table_lookup (group_name_to_key_file_data, group); g_warn_if_fail (key_file_data != NULL); object = goa_object_skeleton_new (object_path); if (update_account_object (daemon, object, key_file_data->path, group, key_file_data->key_file, TRUE)) { g_dbus_object_manager_server_export (daemon->object_manager, G_DBUS_OBJECT_SKELETON (object)); g_signal_connect (goa_object_peek_account (GOA_OBJECT (object)), "handle-remove", G_CALLBACK (on_account_handle_remove), daemon); g_signal_connect (goa_object_peek_account (GOA_OBJECT (object)), "handle-ensure-credentials", G_CALLBACK (on_account_handle_ensure_credentials), daemon); } g_object_unref (object); g_free (group); } for (l = unchanged; l != NULL; l = l->next) { const gchar *object_path = l->data; GoaObject *object; gchar *group; g_debug ("unchanged %s", object_path); group = object_path_to_group (object_path); key_file_data = g_hash_table_lookup (group_name_to_key_file_data, group); g_warn_if_fail (key_file_data != NULL); object = GOA_OBJECT (g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (daemon->object_manager), object_path)); g_warn_if_fail (object != NULL); if (!update_account_object (daemon, GOA_OBJECT_SKELETON (object), key_file_data->path, group, key_file_data->key_file, FALSE)) { g_signal_handlers_disconnect_by_func (goa_object_peek_account (object), G_CALLBACK (on_account_handle_remove), daemon); g_signal_handlers_disconnect_by_func (goa_object_peek_account (object), G_CALLBACK (on_account_handle_ensure_credentials), daemon); g_warn_if_fail (g_dbus_object_manager_server_unexport (daemon->object_manager, object_path)); } g_object_unref (object); g_free (group); } g_list_free (removed); g_list_free (added); g_list_free (unchanged); g_list_foreach (existing_object_paths, (GFunc) g_free, NULL); g_list_free (existing_object_paths); g_list_foreach (config_object_paths, (GFunc) g_free, NULL); g_list_free (config_object_paths); }
/** * @brief Create function handler * @param[in] object * @param[in] invocation * @param[in] instance * @param[in] type * @return true if metod handled */ static gboolean handle_create_function(GadgetdGadgetFunctionManager *object, GDBusMethodInvocation *invocation, const gchar *instance, const gchar *type) { gchar _cleanup_g_free_ *function_path = NULL; const gchar *msg = NULL; GadgetFunctionManager *func_manager = GADGET_FUNCTION_MANAGER(object); GadgetdFunctionObject *function_object; GadgetDaemon *daemon; struct gd_gadget *gadget = func_manager->gadget; const gchar *gadget_name = usbg_get_gadget_name(gadget->g); gchar _cleanup_g_free_ *instance_path = NULL; gchar _cleanup_g_free_ *type_path = NULL; struct gd_function *func = NULL; gint ret; daemon = gadget_function_manager_get_daemon(GADGET_FUNCTION_MANAGER(object)); INFO("handled create function"); if (gadget == NULL || gadget_name == NULL) { msg = "Unable to get gadget"; goto err; } ret = make_valid_object_path_part(instance, &instance_path); if (ret != GD_SUCCESS) { msg = "Invalid instance name"; goto err; } ret = make_valid_object_path_part(type, &type_path); if (ret != GD_SUCCESS) { msg = "Invalid type name"; goto err; } function_path = g_strdup_printf("%s/Function/%s/%s", func_manager->gadget_path, type_path, instance_path); if (function_path == NULL || !g_variant_is_object_path(function_path)) { msg = "Invalid function instance or type"; goto err; } ret = gd_create_function(gadget, type, instance, &func, &msg); if (ret != GD_SUCCESS) goto err; function_object = gadgetd_function_object_new(function_path, func); if (function_object == NULL) { msg = "Unable to create function object"; goto err; } g_dbus_object_manager_server_export(gadget_daemon_get_object_manager(daemon), G_DBUS_OBJECT_SKELETON(function_object)); /* send function path*/ g_dbus_method_invocation_return_value(invocation, g_variant_new("(o)", function_path)); return TRUE; err: g_dbus_method_invocation_return_dbus_error(invocation, func_manager_iface, msg); return TRUE; }
static GVariant * parse_json (JsonNode *node, const GVariantType *type, GError **error) { const GVariantType *element_type; const gchar *str; if (!g_variant_type_is_definite (type)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Indefinite type '%.*s' is not supported", (int)g_variant_type_get_string_length (type), g_variant_type_peek_string (type)); return NULL; } if (g_variant_type_is_basic (type)) { if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN)) { if (check_type (node, JSON_NODE_VALUE, G_TYPE_BOOLEAN, error)) return g_variant_new_boolean (json_node_get_boolean (node)); } else if (g_variant_type_equal (type, G_VARIANT_TYPE_BYTE)) { if (check_type (node, JSON_NODE_VALUE, G_TYPE_INT64, error)) return g_variant_new_byte (json_node_get_int (node)); } else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16)) { if (check_type (node, JSON_NODE_VALUE, G_TYPE_INT64, error)) return g_variant_new_int16 (json_node_get_int (node)); } else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT16)) { if (check_type (node, JSON_NODE_VALUE, G_TYPE_INT64, error)) return g_variant_new_uint16 (json_node_get_int (node)); } else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32)) { if (check_type (node, JSON_NODE_VALUE, G_TYPE_INT64, error)) return g_variant_new_int32 (json_node_get_int (node)); } else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32)) { if (check_type (node, JSON_NODE_VALUE, G_TYPE_INT64, error)) return g_variant_new_uint32 (json_node_get_int (node)); } else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64)) { if (check_type (node, JSON_NODE_VALUE, G_TYPE_INT64, error)) return g_variant_new_int64 (json_node_get_int (node)); } else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT64)) { if (check_type (node, JSON_NODE_VALUE, G_TYPE_INT64, error)) return g_variant_new_uint64 (json_node_get_int (node)); } else if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE)) { if (check_type (node, JSON_NODE_VALUE, G_TYPE_INT64, NULL)) return g_variant_new_double (json_node_get_int (node)); else if (check_type (node, JSON_NODE_VALUE, G_TYPE_DOUBLE, error)) return g_variant_new_double (json_node_get_double (node)); } else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING)) { if (check_type (node, JSON_NODE_VALUE, G_TYPE_STRING, error)) return g_variant_new_string (json_node_get_string (node)); } else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH)) { if (check_type (node, JSON_NODE_VALUE, G_TYPE_STRING, error)) { str = json_node_get_string (node); if (g_variant_is_object_path (str)) return g_variant_new_object_path (str); else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Invalid object path '%s'", str); return NULL; } } } else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE)) { if (check_type (node, JSON_NODE_VALUE, G_TYPE_STRING, error)) { str = json_node_get_string (node); if (g_variant_is_signature (str)) return g_variant_new_signature (str); else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Invalid signature '%s'", str); return NULL; } } } else { parse_not_supported (type, error); } } else if (g_variant_type_is_variant (type)) { return parse_json_variant (node, error); } else if (g_variant_type_is_array (type)) { element_type = g_variant_type_element (type); if (g_variant_type_is_dict_entry (element_type)) return parse_json_dictionary (node, element_type, error); else return parse_json_array (node, element_type, error); } else if (g_variant_type_is_tuple (type)) { return parse_json_tuple (node, g_variant_type_first (type), error); } else { parse_not_supported (type, error); } return NULL; }