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; }
/** * 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_aggregate_model_clear_model (MexAggregateModel *self, MexModel *model) { gint i; GList *c, *remove; MexContent *content; MexAggregateModelPrivate *priv = self->priv; i = 0; remove = NULL; while ((content = mex_model_get_content (MEX_MODEL (self), i++))) { MexModel *parent = g_hash_table_lookup (priv->content_to_model, content); if (parent == model) { g_hash_table_remove (priv->content_to_model, content); remove = g_list_prepend (remove, content); } } /* Remove the contents after the loop, to avoid modifying what we're * iterating over. */ for (c = remove; c; c = c->next) mex_model_remove_content (MEX_MODEL (self), MEX_CONTENT (c->data)); g_list_free (remove); }
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); }
/** * mex_column_populate: * * Add an item to the column for each item in the current model */ static void mex_column_populate (MexColumn *column) { MexContent *content; gint i = 0; g_return_if_fail (column->priv->model != NULL); while ((content = mex_model_get_content (column->priv->model, i))) mex_column_add_content (column, content, i++); }
static void mex_search_plugin_model_changed_cb (GController *controller, GControllerAction action, GControllerReference *ref, MexModel *model) { gint i; gint n_indices = g_controller_reference_get_n_indices (ref); /* If the MIME type is unset, set one so that it's still playable in the * main UI. This plugin will only use white-listed Grilo plugins that we * know return playable media, so this is OK. */ switch (action) { case G_CONTROLLER_ADD: for (i = 0; i < n_indices; i++) { gchar *notify; MexContent *content; const gchar *property_name; gint content_index = g_controller_reference_get_index_uint (ref, i); content = mex_model_get_content (model, content_index); /* Make sure the mime-type remains useful */ property_name = mex_content_get_property_name (content, MEX_CONTENT_METADATA_MIMETYPE); if (property_name) { notify = g_strconcat ("notify::", property_name, NULL); g_signal_connect (content, notify, G_CALLBACK (mex_search_plugin_mimetype_set_cb), NULL); g_free (notify); } mex_search_plugin_mimetype_set_cb (content); } break; default: break; } }
void mex_aggregate_model_add_model (MexAggregateModel *aggregate, MexModel *model) { gint i; MexContent *content; GController *controller; MexAggregateModelPrivate *priv; g_return_if_fail (MEX_IS_AGGREGATE_MODEL (aggregate)); g_return_if_fail (MEX_IS_MODEL (model)); priv = aggregate->priv; if (g_list_find (priv->models, model)) return; /* Add a link back to the model from the controller */ controller = mex_model_get_controller (model); g_hash_table_insert (priv->controller_to_model, controller, model); /* Add model to list */ priv->models = g_list_insert_sorted (priv->models, model, (GCompareFunc) mex_aggregate_model_sort_func); /* Add existing items */ i = 0; while ((content = mex_model_get_content (model, i))) { g_hash_table_insert (priv->content_to_model, content, model); mex_model_add_content (MEX_MODEL (aggregate), content); i++; } /* Connect to the controller changed signal */ g_signal_connect (controller, "changed", G_CALLBACK (mex_aggregate_model_controller_changed_cb), aggregate); /* Emit added signal */ g_signal_emit (aggregate, signals[MODEL_ADDED], 0, model); }
static void mex_music_player_set_context (MexContentView *player, MexModel *model) { MexMusicPlayerPrivate *priv = MEX_MUSIC_PLAYER (player)->priv; ClutterActor *box, *button; MexContent *content; gint i; if (priv->model) g_object_unref (priv->model); priv->model = model; if (model) g_object_ref (model); box = mex_script_get_actor (priv->script, "tracks"); clutter_actor_remove_all_children (box); for (i = 0; (content = mex_model_get_content (model, i)); i++) { const gchar *title; title = mex_content_get_metadata (content, MEX_CONTENT_METADATA_TITLE); button = mx_button_new_with_label (title); mx_stylable_set_style_class (MX_STYLABLE (button), "Track"); mx_button_set_is_toggle (MX_BUTTON (button), TRUE); g_object_set_data (G_OBJECT (button), "content", content); g_signal_connect (button, "clicked", G_CALLBACK (mex_music_player_item_clicked), player); mx_button_set_icon_position (MX_BUTTON (button), MX_POSITION_RIGHT); clutter_actor_add_child (box, button); } }
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); }
/** * mex_column_controller_changed: * * Callback for when the current model controller's "changed" signal is emitted */ static void mex_column_controller_changed (GController *controller, GControllerAction action, GControllerReference *ref, MexColumn *column) { MexColumnPrivate *priv = column->priv; gint i, n_indices; MexContent *content; 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_column_add_content (column, content, content_index); } break; case G_CONTROLLER_REMOVE: for (i = 0; i < n_indices; i++) { GList *lnk; gint content_index = g_controller_reference_get_index_uint (ref, i); lnk = g_list_nth (priv->children, content_index); if (lnk->data == priv->current_focus) priv->current_focus = NULL; clutter_actor_destroy (lnk->data); priv->children = g_list_delete_link (priv->children, lnk); } break; case G_CONTROLLER_UPDATE: break; case G_CONTROLLER_CLEAR: mex_column_clear (column); break; case G_CONTROLLER_REPLACE: mex_column_clear (column); mex_column_populate (column); break; case G_CONTROLLER_INVALID_ACTION: g_warning (G_STRLOC ": Controller has issued an error"); break; default: g_warning (G_STRLOC ": Unhandled action"); break; } clutter_actor_queue_relayout (CLUTTER_ACTOR (column)); }
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_aggregate_model_controller_changed_cb (GController *controller, GControllerAction action, GControllerReference *ref, MexAggregateModel *self) { gint i; gint n_indices = 0; MexAggregateModelPrivate *priv = self->priv; MexModel *model = g_hash_table_lookup (priv->controller_to_model, controller); if (!model) { g_warning (G_STRLOC ": Signal from unknown controller"); return; } if (ref) n_indices = g_controller_reference_get_n_indices (ref); switch (action) { case G_CONTROLLER_ADD: for (i = 0; i < n_indices; i++) { MexContent *content; gint content_index = g_controller_reference_get_index_uint (ref, i); content = mex_model_get_content (model, content_index); g_hash_table_insert (priv->content_to_model, content, model); mex_model_add_content (MEX_MODEL (self), content); } break; case G_CONTROLLER_REMOVE: for (i = 0; i < n_indices; i++) { MexContent *content; gint content_index = g_controller_reference_get_index_uint (ref, i); content = mex_model_get_content (model, content_index); g_hash_table_remove (priv->content_to_model, content); mex_model_remove_content (MEX_MODEL (self), content); } break; case G_CONTROLLER_UPDATE: break; case G_CONTROLLER_CLEAR: mex_aggregate_model_clear_model (self, model); break; case G_CONTROLLER_REPLACE: { MexContent *content; mex_aggregate_model_clear_model (self, model); i = 0; while ((content = mex_model_get_content (model, i++))) { g_hash_table_insert (priv->content_to_model, content, model); mex_model_add_content (MEX_MODEL (self), content); } } break; case G_CONTROLLER_INVALID_ACTION: g_warning (G_STRLOC ": Proxy controller has issued an error"); break; default: break; } }
/** * mex_proxy_start_at: * @proxy: Proxy to add content to * @start_at_content: First content item in the model to add to * the proxy * @loop: Whether to loop back to the beginning of the * associated #MexModel's content items once the last item is reached; * if %TRUE, content items before the @start_at_content will be * added once the last of the model's content items is reached; * if %FALSE, only content items from @start_at_content to the last of * the model's content items are added * * Add content from a model to a proxy. */ void mex_proxy_start_at (MexProxy *proxy, MexContent *start_at_content, gboolean loop) { gint i; MexContent *content; MexProxyPrivate *priv; GController *controller; g_return_if_fail (MEX_IS_PROXY (proxy)); priv = proxy->priv; if (priv->started) { g_warning (G_STRLOC ": Trying to start an already started proxy"); return; } mex_proxy_clear (proxy); priv->started = TRUE; if (!priv->model) return; if (!G_TYPE_IS_OBJECT (priv->object_type)) { g_warning (G_STRLOC ": Proxy type is not an object type"); return; } /* Iterate over existing objects */ if (!start_at_content) { i = 0; while ((content = mex_model_get_content (priv->model, i++))) mex_proxy_add_content (proxy, content); } else { gint start_at; gboolean looped = FALSE; start_at = mex_model_index (priv->model, start_at_content); if (start_at == -1) { g_critical (G_STRLOC ": Content %p not found in %p model", start_at_content, priv->model); return; } for (i = start_at; TRUE; i++) { /* break out if looped and back around to start_at */ if (loop && looped && i == start_at) break; if ((content = mex_model_get_content (priv->model, i))) { mex_proxy_add_content (proxy, content); } else { if (loop) { looped = TRUE; i = -1; } else break; } } } controller = mex_model_get_controller (priv->model); g_signal_connect_after (controller, "changed", G_CALLBACK (mex_proxy_controller_changed_cb), proxy); }
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); }