static JsonGenerator * _model_to_generator (MexQueueModel *model) { gint i; JsonArray *json_array; JsonNode *root; JsonGenerator *generator; json_array = json_array_sized_new (mex_model_get_length (MEX_MODEL (model))); for (i = 0; i < mex_model_get_length (MEX_MODEL (model)); i++) { MexContent *content; JsonNode *content_node; content = mex_model_get_content (MEX_MODEL (model), i); content_node = json_gobject_serialize (G_OBJECT (content)); json_array_add_element (json_array, content_node); } generator = json_generator_new (); root = json_node_new (JSON_NODE_ARRAY); json_node_set_array (root, json_array); json_generator_set_root (generator, root); json_array_unref (json_array); json_node_free (root); return generator; }
static void mex_music_player_shuffle_toggled (MexMusicPlayer *player, GParamSpec *spec, MxButton *button) { MexMusicPlayerPrivate *priv = player->priv; gint i; if (mx_button_get_toggled (button)) { gint length; length = mex_model_get_length (priv->model); priv->shuffle = g_array_sized_new (FALSE, FALSE, sizeof (gint), length); for (i = 0; i < length; i++) g_array_insert_val (priv->shuffle, i, i); /* shuffle the list */ g_array_sort (priv->shuffle, mex_music_player_random_sort); } else { if (priv->shuffle) { g_array_free (priv->shuffle, TRUE); priv->shuffle = NULL; } } }
/** * mex_media_controls_get_enqueued: * @controls: The MexMediaControls widget * @current_content: MexContent that the player is currently playing * * If the media controls has been given a queue model then return the next * MexContent in the queue model. * * Return value: The next content in the queue or NULL */ MexContent * mex_media_controls_get_enqueued (MexMediaControls *controls, MexContent *current_content) { MexMediaControlsPrivate *priv; MexModel *queue; MexContent *content = NULL; if (!MEX_IS_MEDIA_CONTROLS (controls) || !MEX_IS_CONTENT (current_content)) return NULL; priv = controls->priv; if (priv->is_queue_model == FALSE) return NULL; queue = mex_proxy_get_model (priv->proxy); if (queue) { gint idx, length; idx = mex_model_index (queue, current_content); length = mex_model_get_length (queue); if (idx++ > length) return NULL; content = mex_model_get_content (queue, idx); } return content; }
static void _add_remove_recursive (MexModel *queue_model, MexModel *model, gboolean add) { gint len, i; len = mex_model_get_length (model); for (i=0; i < len; i++) { MexContent *content; const gchar *mimetype; content = mex_model_get_content (model, i); mimetype = mex_content_get_metadata (content, MEX_CONTENT_METADATA_MIMETYPE); /* Don't accidentally add a directory or group to the queue */ if (!g_strcmp0 (mimetype, "x-grl/box") || !g_strcmp0 (mimetype, "x-mex/group")) continue; if (add) mex_model_add_content (queue_model, content); else mex_model_remove_content (queue_model, content); } g_object_unref (model); }
static void mex_view_model_set_model (MexViewModel *self, MexModel *model) { MexViewModelPrivate *priv = self->priv; if (model == priv->model) return; if (model) { MexContent *content; GController *controller; gint i = 0; priv->model = g_object_ref_sink (model); controller = mex_model_get_controller (model); g_signal_connect (controller, "changed", G_CALLBACK (mex_view_model_controller_changed_cb), self); /* copy initial items across */ g_ptr_array_set_size (priv->internal_items, mex_model_get_length (priv->model)); while ((content = mex_model_get_content (priv->model, i))) priv->internal_items->pdata[i++] = content; } mex_view_model_refresh_external_items (self); }
/* This function is asynchronous .. slightly worried about re-entrancy here */ static void mex_queue_model_save (MexQueueModel *model) { GFile *f; gchar *filename; JsonGenerator *generator; gchar *buf; gsize buf_len; filename = _queue_file_name (); f = g_file_new_for_path (filename); if (mex_model_get_length (MEX_MODEL (model)) == 0) { GError *error = NULL; if (!g_file_delete (f, NULL, &error)) { g_warning (G_STRLOC ": Unable to delete file: %s", error->message); g_clear_error (&error); } g_object_unref (f); g_free (filename); return; } generator = _model_to_generator (model); buf = json_generator_to_data (generator, &buf_len); g_file_replace_contents_async (f, buf, buf_len, NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL, (GAsyncReadyCallback)_file_replaced_cb, buf); g_object_unref (f); g_free (filename); g_object_unref (generator); }
static void mex_music_player_update_index (MexMusicPlayer *player, gint new_index) { MexMusicPlayerPrivate *priv = player->priv; gint content_index, length; MexContent *new_content; length = mex_model_get_length (priv->model); if (priv->repeat) { if (new_index >= length) new_index = 0; else if (new_index < 0) new_index = length - 1; } else { if (new_index >= length) new_index = length - 1; else if (new_index < 0) new_index = 0; } priv->current_index = new_index; if (priv->shuffle) content_index = g_array_index (priv->shuffle, gint, priv->current_index); else content_index = priv->current_index; new_content = mex_model_get_content (priv->model, content_index); mex_music_player_set_content (MEX_CONTENT_VIEW (player), new_content); }
static void _controller_changed_cb (GController *controller, GControllerAction action, GControllerReference *ref, MexQueueModel *model) { MexQueueModelPrivate *priv = model->priv; guint index_; MexContent *content; /* * MexGenericContent only does single items at a time so we have an * assumption here that our reference only contains a single item */ if (action == G_CONTROLLER_ADD || action == G_CONTROLLER_REMOVE) { index_ = g_controller_reference_get_index_uint (ref, 0); content = mex_model_get_content (MEX_MODEL (model), index_); } if (action == G_CONTROLLER_ADD) { mex_content_set_metadata (content, MEX_CONTENT_METADATA_QUEUED, "yes"); } else if (action == G_CONTROLLER_REMOVE) { mex_content_set_metadata (content, MEX_CONTENT_METADATA_QUEUED, NULL); } else if (action == G_CONTROLLER_CLEAR) { gint model_length; model_length = mex_model_get_length (MEX_MODEL (model)); for (index_=0; index_ < model_length; index_++) { content = mex_model_get_content (MEX_MODEL (model), index_); mex_content_set_metadata (content, MEX_CONTENT_METADATA_QUEUED, NULL); } } else { GEnumClass *enum_class; enum_class = g_type_class_ref (G_TYPE_CONTROLLER_ACTION); g_critical (G_STRLOC ": Unexpected GController action: %s", (g_enum_get_value (enum_class, action))->value_name); g_type_class_unref (enum_class); } if (priv->serialise_idle_id) return; /* Need to use a high priority idle here since we want to try and write * *after* the content has been removed from the model */ priv->serialise_idle_id = g_idle_add_full (G_PRIORITY_DEFAULT, (GSourceFunc)_serialise_idle_cb, g_object_ref (model), g_object_unref); }
static void mex_proxy_controller_changed_cb (GController *controller, GControllerAction action, GControllerReference *ref, MexProxy *proxy) { gint i, n_indices; MexContent *content; MexProxyPrivate *priv = proxy->priv; n_indices = g_controller_reference_get_n_indices (ref); switch (action) { case G_CONTROLLER_ADD: for (i = 0; i < n_indices; i++) { gint content_index = g_controller_reference_get_index_uint (ref, i); content = mex_model_get_content (priv->model, content_index); mex_proxy_add_content (proxy, content); } break; case G_CONTROLLER_REMOVE: { gint length, fillin = 0, start_fillin; GList *positions = NULL, *position; for (i = 0; i < n_indices; i++) { gint content_index = g_controller_reference_get_index_uint (ref, i); if (content_index >= priv->limit) positions = g_list_insert_sorted_with_data (positions, GINT_TO_POINTER (content_index), _insert_position, NULL); else fillin++; content = mex_model_get_content (priv->model, content_index); mex_proxy_remove_content (proxy, content); } position = positions; length = mex_model_get_length (priv->model); start_fillin = priv->limit; for (i = 0; i < MIN (fillin, (length - (gint) priv->limit)); i++) { if ((position != NULL) && (start_fillin == GPOINTER_TO_INT (position->data))) { while ((position != NULL) && (start_fillin == GPOINTER_TO_INT (position->data))) { start_fillin++; if (start_fillin > GPOINTER_TO_INT (position->data)) position = position->next; } } content = mex_model_get_content (priv->model, start_fillin); mex_proxy_add_content (proxy, content); start_fillin++; } g_list_free (positions); } break; case G_CONTROLLER_UPDATE: /* Should be no need for this, GBinding sorts it out for us :) */ break; case G_CONTROLLER_CLEAR: mex_proxy_clear (proxy); break; case G_CONTROLLER_REPLACE: mex_proxy_clear (proxy); i = 0; while ((content = mex_model_get_content (priv->model, i++))) mex_proxy_add_content (proxy, content); break; case G_CONTROLLER_INVALID_ACTION: g_warning (G_STRLOC ": Proxy controller has issued an error"); break; default: g_warning (G_STRLOC ": Unhandled action"); break; } }
static void mex_view_model_controller_changed_cb (GController *controller, GControllerAction action, GControllerReference *ref, MexViewModel *self) { gint n_indices, i; MexViewModelPrivate *priv = self->priv; n_indices = g_controller_reference_get_n_indices (ref); switch (action) { case G_CONTROLLER_ADD: { guint view_length; /* increase the internal items array by the number of new items */ view_length = mex_model_get_length (MEX_MODEL (self)); g_ptr_array_set_size (priv->internal_items, view_length + n_indices); /* set the new items */ while (n_indices-- > 0) { MexContent *content; guint idx; idx = g_controller_reference_get_index_uint (ref, n_indices); content = mex_model_get_content (priv->model, idx); g_signal_connect (content, "notify", G_CALLBACK (content_notify_cb), self); priv->internal_items->pdata[view_length + n_indices] = content; } } break; case G_CONTROLLER_REMOVE: { while (n_indices-- > 0) { MexContent *content; gint idx; idx = g_controller_reference_get_index_int (ref, n_indices); content = mex_model_get_content (priv->model, idx); g_signal_handlers_disconnect_by_func (content, G_CALLBACK (content_notify_cb), self); g_ptr_array_remove_fast (priv->internal_items, content); } } break; case G_CONTROLLER_UPDATE: /* Should be no need for this, GBinding sorts it out for us :) */ break; case G_CONTROLLER_CLEAR: for (i = 0; i < priv->external_items->len; i++) g_object_unref (g_ptr_array_index (priv->external_items, i)); g_ptr_array_set_size (priv->external_items, 0); for (i = 0; i < priv->external_items->len; i++) g_signal_handlers_disconnect_by_func (g_ptr_array_index (priv->external_items, i), G_CALLBACK (content_notify_cb), self); g_ptr_array_set_size (priv->internal_items, 0); break; case G_CONTROLLER_REPLACE: g_warning (G_STRLOC ": G_CONTROLLER_REPLACE not implemented by MexViewModel"); break; case G_CONTROLLER_INVALID_ACTION: g_warning (G_STRLOC ": View-model controller has issued an error"); break; default: g_warning (G_STRLOC ": Unhandled action"); break; } mex_view_model_refresh_external_items (self); }