static void _content_notify (MexContent *content, GParamSpec *pspec, MexContentTile *tile) { MexContentTilePrivate *priv = tile->priv; const gchar *still_prop_name, *title_prop_name, *logo_prop_name; still_prop_name = mex_content_get_property_name (MEX_CONTENT (priv->content), MEX_CONTENT_METADATA_STILL); title_prop_name = mex_content_get_property_name (MEX_CONTENT (priv->content), MEX_CONTENT_METADATA_TITLE); logo_prop_name = mex_content_get_property_name (MEX_CONTENT (priv->content), MEX_CONTENT_METADATA_STATION_LOGO); if (!g_strcmp0 (pspec->name, still_prop_name)) { _reset_thumbnail (tile); } else if (!g_strcmp0 (pspec->name, title_prop_name)) { _update_title (tile); } else if (!g_strcmp0 (pspec->name, logo_prop_name)) { _update_logo (tile); } }
int main (int argc, char **argv) { const ClutterColor grey = { 0x40, 0x40, 0x40, 0xff }; ClutterActor *stage, *info_panel, *align; MxApplication *app; MxWindow *window; MexFeed *feed; MexProgram *program; mex_init (&argc, &argv); app = mx_application_new (&argc, &argv, "mex-info-panel-test", 0); mex_style_load_default (); window = mx_application_create_window (app); stage = (ClutterActor *) mx_window_get_clutter_stage (window); clutter_stage_set_color ((ClutterStage *) stage, &grey); align = g_object_new (MX_TYPE_FRAME, "x-align", MX_ALIGN_MIDDLE, "y-align", MX_ALIGN_END, NULL); mx_window_set_child (window, align); info_panel = mex_info_panel_new (MEX_INFO_PANEL_MODE_FULL); mx_bin_set_child (MX_BIN (align), info_panel); mx_window_set_has_toolbar (window, FALSE); clutter_actor_set_size (stage, 1024, 768); feed = mex_feed_new ("source", "title"); program = mex_program_new (feed); mex_content_set_metadata (MEX_CONTENT (program), MEX_CONTENT_METADATA_MIMETYPE, "video/mp4"); mex_content_set_metadata (MEX_CONTENT (program), MEX_CONTENT_METADATA_TITLE, "The cats on the moon"); mex_content_set_metadata (MEX_CONTENT (program), MEX_CONTENT_METADATA_SYNOPSIS, "An original title where cats are sent to the moon to catch all the mice which are naturally attracted there due to the large consistency of cheese, this results in a space race between NASA and CATSA, leading to war on the moon over territory claimed by cats"); mex_content_set_metadata (MEX_CONTENT (program), MEX_CONTENT_METADATA_STILL, "http://farm5.static.flickr.com/4013/4305303148_5cbc986a44_m.jpg"); mex_content_view_set_content (MEX_CONTENT_VIEW (info_panel), MEX_CONTENT (program)); clutter_actor_show (stage); clutter_main (); return 0; }
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); }
void mex_grilo_program_set_grilo_media (MexGriloProgram *program, GrlMedia *media) { MexGriloProgramPrivate *priv; g_return_if_fail (MEX_IS_GRILO_PROGRAM (program)); g_return_if_fail (GRL_IS_MEDIA (media)); priv = program->priv; if (priv->media == media) return; if (priv->media != NULL) g_object_unref (priv->media); priv->media = g_object_ref (media); set_metadatas_from_media (MEX_CONTENT (program), media); /* Unset 'completed' so that the next time completed is called, all data * on this Grilo media is re-resolved. */ priv->completed = FALSE; }
static void mex_grilo_feed_open_default (MexGriloProgram *program, MexGriloFeed *feed) { MexPlayer *player = mex_player_get_default (); mex_content_view_set_context (MEX_CONTENT_VIEW (player), MEX_MODEL (feed)); mex_content_view_set_content (MEX_CONTENT_VIEW (player), MEX_CONTENT (program)); }
static void tile_created_cb (MexProxy *proxy, GObject *content, GObject *object, gpointer controls) { const gchar *mime_type; ClutterEffect *effect; ClutterColor color = { 0, 0, 0, 60 }; /* filter out folders */ mime_type = mex_content_get_metadata (MEX_CONTENT (content), MEX_CONTENT_METADATA_MIMETYPE); if (g_strcmp0 (mime_type, "x-grl/box") == 0) { g_signal_stop_emission_by_name (proxy, "object-created"); return; } mex_tile_set_important (MEX_TILE (object), TRUE); clutter_actor_set_reactive (CLUTTER_ACTOR (object), TRUE); g_object_set (object, "thumb-height", 140, "thumb-width", 250, NULL); g_signal_connect (object, "key-press-event", G_CALLBACK (key_press_event_cb), controls); g_signal_connect (object, "button-release-event", G_CALLBACK (button_release_event_cb), controls); effect = g_object_new (MEX_TYPE_SHADOW, "radius-x", 15, "radius-y", 15, "color", &color, "enabled", FALSE, NULL); clutter_actor_add_effect_with_name (CLUTTER_ACTOR (object), "shadow", effect); effect = g_object_new (MEX_TYPE_SHADOW, "radius-x", 15, "radius-y", 15, "color", &color, NULL); clutter_actor_add_effect_with_name (mx_bin_get_child (MX_BIN (object)), "shadow", effect); g_signal_connect (object, "focus-in", G_CALLBACK (tile_focus_in_cb), NULL); g_signal_connect (object, "focus-out", G_CALLBACK (tile_focus_out_cb), NULL); tile_focus_out_cb (MX_BIN (object)); }
static char * program_get_metadata_fallback (MexGenericContent *gc, MexContentMetadata key) { MexContent *content = MEX_CONTENT (gc); const gchar *showname; gchar *target; switch (key) { case MEX_CONTENT_METADATA_TITLE: showname = mex_content_get_metadata (content, MEX_CONTENT_METADATA_SERIES_NAME); if (!showname) { const gchar *url; gchar *basename; url = mex_content_get_metadata (content, MEX_CONTENT_METADATA_URL); basename = g_path_get_basename (url); target = g_uri_unescape_string (basename, NULL); g_free (basename); } else { const gchar *episode, *season; episode = mex_content_get_metadata (content, MEX_CONTENT_METADATA_EPISODE); season = mex_content_get_metadata (content, MEX_CONTENT_METADATA_SEASON); if (episode && season) { target = g_strdup_printf ("%s: Season %s, Episode %s", showname, season, episode); } else if (episode) { target = g_strdup_printf ("%s: Episode %s", showname, episode); } else if (season) { target = g_strdup_printf ("%s: Season %s", showname, season); } else { target = g_strdup (showname); } } break; default: target = NULL; break; } return target; }
static void program_complete_cb (GrlMediaSource *source, guint operation_id, GrlMedia *media, gpointer userdata, const GError *error) { MexGriloProgram *self = userdata; MexContent *content = MEX_CONTENT (self); set_metadatas_from_media (content, media); mex_grilo_program_thumbnail (content, media); g_object_unref (self); g_object_unref (source); }
static char * _mex_program_get_index_str (MexProgram *program) { GString *str; char *index_str; g_return_val_if_fail (MEX_IS_PROGRAM (program), NULL); str = g_string_new (""); mex_content_foreach_metadata (MEX_CONTENT (program), make_metadata_string, str); index_str = str->str; g_string_free (str, FALSE); return index_str; }
static void _mex_grilo_feed_content_updated (GrlSource *source, GPtrArray *changed_medias, GrlSourceChangeType change_type, gboolean known_location, MexGriloFeed *feed) { gint i; GrlMedia *media; const gchar *id; MexGriloProgram *program; for (i = 0 ; i < changed_medias->len ; i++) { media = g_ptr_array_index (changed_medias, i); id = grl_media_get_id (media); switch (change_type) { case GRL_CONTENT_CHANGED: program = MEX_GRILO_PROGRAM (mex_feed_lookup (MEX_FEED (feed), id)); /* The policy might be slightly different here... */ if (program != NULL) { mex_grilo_program_set_grilo_media (program, media); } break; case GRL_CONTENT_ADDED: program = MEX_GRILO_PROGRAM (mex_feed_lookup (MEX_FEED (feed), id)); if (program != NULL) { mex_grilo_program_set_grilo_media (program, media); } else { emit_media_added (feed, media); } break; case GRL_CONTENT_REMOVED: program = MEX_GRILO_PROGRAM (mex_feed_lookup (MEX_FEED (feed), id)); if (program != NULL) { mex_model_remove_content (MEX_MODEL (feed), MEX_CONTENT (program)); } break; } } }
void mex_program_get_thumbnail (MexProgram *program, MexGetThumbnailReply reply, gpointer userdata) { MexProgramClass *klass; MexProgramPrivate *priv; const char *still; g_return_if_fail (MEX_IS_PROGRAM (program)); priv = program->priv; /* Some backends (eg. Apple trailers) may be able to cache the stream so we can just use the standard metadata method to obtain it */ still = mex_content_get_metadata (MEX_CONTENT (program), MEX_PROGRAM_METADATA_STILL); if (stream != NULL) { struct _GetStreamPayload *payload = g_slice_new (struct _GetStreamPayload); payload->program = g_object_ref (program); payload->reply = reply; payload->userdata = userdata; /* Technically the stream could be freed before the idle is called Great, now I want refcounted strings */ payload->stream = g_strdup (stream); g_idle_add (emit_get_stream_reply, payload); return; } /* Other backends require custom methods to get the stream url */ klass = MEX_PROGRAM_GET_CLASS (program); if (klass->get_stream) { klass->get_stream (program, reply, userdata); } else { struct _GetStreamPayload *payload = g_slice_new (struct _GetStreamPayload); payload->program = g_object_ref (program); payload->reply = reply; payload->userdata = userdata; payload->stream = NULL; g_idle_add (emit_get_stream_reply, payload); } }
/* * Callback from mex_thumbnailer_generate, when a thumbnail has been generated. */ static void thumbnail_cb (const char *uri, gpointer user_data) { MexContent *content; char *thumb_path; content = MEX_CONTENT (user_data); thumb_path = get_thumbnail_path_for_uri (uri); if (g_file_test (thumb_path, G_FILE_TEST_EXISTS)) { gchar *thumb_uri = g_filename_to_uri (thumb_path, NULL, NULL); mex_grilo_program_set_metadata (content, MEX_CONTENT_METADATA_STILL, thumb_uri); g_free (thumb_uri); } g_free (thumb_path); }
static void mex_grilo_program_get_stream_cb (GrlMediaSource *source, guint operation_id, GrlMedia *media, gpointer userdata, const GError *error) { MexGriloProgramClosure *closure = userdata; MexContent *content = MEX_CONTENT (closure->self); const gchar *url = grl_media_get_url (media); MEX_CONTENT_IFACE (mex_grilo_program_parent_class)->set_metadata (content, MEX_CONTENT_METADATA_STREAM, url); closure->reply (MEX_PROGRAM (content), url, error, closure->userdata); g_object_unref (content); g_object_unref (source); g_slice_free (MexGriloProgramClosure, closure); }
static void mex_suggest_complete_cb (MexDownloadQueue *queue, const gchar *uri, const gchar *buffer, gsize count, const GError *error, gpointer userdata) { RestXmlNode *root, *n; RestXmlParser *parser; MexSearchPlugin *self = userdata; MexSearchPluginPrivate *priv = self->priv; priv->suggest_id = NULL; /* hide spinner */ mx_spinner_set_animating (MX_SPINNER (priv->spinner), FALSE); clutter_actor_hide (priv->spinner); if (error) { g_warning ("Error querying Google suggestions: %s", error->message); return; } parser = rest_xml_parser_new (); root = rest_xml_parser_parse_from_data (parser, buffer, count); if (!root) { g_warning ("Unknown error parsing Google suggestions XML"); g_object_unref (parser); return; } /* Clear model */ mex_model_clear (MEX_MODEL (priv->suggest_model)); /* Add new suggestions to model */ n = rest_xml_node_find (root, "CompleteSuggestion"); for (; n; n = n->next) { MexContent *content; const gchar *suggestion; RestXmlNode *node = rest_xml_node_find (n, "suggestion"); if (!node) continue; suggestion = rest_xml_node_get_attr (node, "data"); if (!suggestion) continue; content = MEX_CONTENT (mex_program_new (priv->suggest_model)); mex_content_set_metadata (content, MEX_CONTENT_METADATA_TITLE, suggestion); mex_content_set_metadata (content, MEX_CONTENT_METADATA_MIMETYPE, "x-mex/search"); mex_model_add_content (MEX_MODEL (priv->suggest_model), content); } /* Unref */ rest_xml_node_unref (root); g_object_unref (parser); }
static void mex_search_plugin_update_history (MexSearchPlugin *self, const gchar *term) { gint i; gsize length; gchar *contents, *current; MexSearchPluginPrivate *priv = self->priv; const gchar *base_dir = mex_settings_get_config_dir (mex_settings_get_default ()); gchar *history_file = g_build_filename (base_dir, "search", "history", NULL); /* Read the history file contents */ /* TODO: Make this less rubbish? */ g_file_get_contents (history_file, &contents, &length, NULL); /* Prepend new search-term if appropriate */ if (term) { gint terms; gchar *path; gsize new_length; gsize term_len = strlen (term); gchar *new_contents = g_malloc (length + term_len + 1); memcpy (new_contents, term, term_len); new_contents[term_len] = '\n'; new_length = term_len + 1; /* Truncate list to 10 terms and remove duplicates */ if (contents) { i = 0; terms = 1; do { gint cur_len; char *eos = strchr (contents + i, '\n'); if (!eos) cur_len = strlen (contents + i); else cur_len = eos - (contents + i); if ((cur_len != term_len) || (strncmp (contents + i, term, term_len) != 0)) { memcpy (new_contents + new_length, contents + i, cur_len + 1); new_length += cur_len + 1; if (++terms >= 10) break; } if (!eos) break; i += cur_len + 1; } while (i < length); } new_contents[new_length++] = '\0'; /* Save new list */ path = g_path_get_dirname (history_file); g_mkdir_with_parents (path, 0755); g_free (path); g_file_set_contents (history_file, new_contents, new_length, NULL); /* Replace content with new content */ g_free (contents); contents = new_contents; length = new_length; } /* Empty current list */ mex_model_clear (MEX_MODEL (priv->history_model)); /* Populate with search history */ if (contents) { current = contents; while (current < contents + length) { MexContent *content = MEX_CONTENT (mex_program_new (priv->history_model)); gchar *end = g_utf8_strchr (current, -1, '\n'); if (end) *end = '\0'; if (*current) { mex_content_set_metadata (content, MEX_CONTENT_METADATA_TITLE, current); mex_content_set_metadata (content, MEX_CONTENT_METADATA_MIMETYPE, "x-mex/search"); mex_model_add_content (MEX_MODEL (priv->history_model), content); } if (end) current = end + 1; else break; } g_free (contents); } else { /* Add a default search so the column isn't hidden. * TODO: Have a way of inserting 'stock' content rather than doing * this, I suppose. */ MexContent *content = MEX_CONTENT (mex_program_new (priv->history_model)); mex_content_set_metadata (content, MEX_CONTENT_METADATA_TITLE, "MeeGo"); mex_content_set_metadata (content, MEX_CONTENT_METADATA_MIMETYPE, "x-mex/search"); mex_model_add_content (MEX_MODEL (priv->history_model), content); } }