📄 st-browser-tab.c
字号:
g_return_if_fail(ST_IS_CATEGORY_BAG(bag)); tab->priv->running_categories = running ? g_slist_append(tab->priv->running_categories, bag) : g_slist_remove(tab->priv->running_categories, bag); st_statusbar_set_active(ST_STATUSBAR(bag->statusbar), running); st_browser_tab_update_running(tab); if (running) st_thread_run(st_category_bag_get_task_thread(bag)); else { st_category_bag_set_task_thread(bag, NULL); gtk_statusbar_pop(GTK_STATUSBAR(bag->statusbar), bag->statusbar_context_task); } if (! tab->priv->running_categories && tab->priv->pending_categories) { STCategoryStore *category_store; /* the last reload has just finished, process the pending categories */ category_store = st_handler_get_categories(tab->handler); st_category_store_merge_node(category_store, tab->priv->pending_categories); g_object_unref(category_store); sg_objects_free_node(tab->priv->pending_categories); tab->priv->pending_categories = NULL; }}static voidst_browser_tab_update_running (STBrowserTab *tab){ gboolean new_running; g_return_if_fail(ST_IS_BROWSER_TAB(tab)); new_running = tab->priv->running_categories != NULL || tab->priv->stream_tasks != NULL; if (new_running != tab->running) { tab->running = new_running; g_object_notify(G_OBJECT(tab), "running"); }}gbooleanst_browser_tab_can_stop (STBrowserTab *tab){ g_return_val_if_fail(ST_IS_BROWSER_TAB(tab), FALSE); return tab->running;}voidst_browser_tab_stop (STBrowserTab *tab){ GSList *list; GSList *l; g_return_if_fail(ST_IS_BROWSER_TAB(tab)); g_return_if_fail(st_browser_tab_can_stop(tab)); /* * We use copies, because the lists will be modified by * st_thread_abort(). */ list = g_slist_copy(tab->priv->running_categories); SG_LIST_FOREACH(l, list) { STCategoryBag *bag = l->data; st_thread_abort(st_category_bag_get_task_thread(bag)); } g_slist_free(list); list = g_slist_copy(tab->priv->stream_tasks); SG_LIST_FOREACH(l, list) { STBrowserTabStreamTask *task = l->data; st_thread_abort(task->thread); } g_slist_free(list);}gbooleanst_browser_tab_can_visit_homepage (STBrowserTab *tab){ g_return_val_if_fail(ST_IS_BROWSER_TAB(tab), FALSE); return st_handler_get_home(tab->handler) != NULL;}voidst_browser_tab_visit_homepage (STBrowserTab *tab){ g_return_if_fail(ST_IS_BROWSER_TAB(tab)); g_return_if_fail(st_browser_tab_can_visit_homepage(tab)); st_visit_homepage(st_handler_get_home(tab->handler));}gbooleanst_browser_tab_can_present_preferences (STBrowserTab *tab){ g_return_val_if_fail(ST_IS_BROWSER_TAB(tab), FALSE); return st_handler_event_is_bound(tab->handler, ST_HANDLER_EVENT_PREFERENCES_WIDGET_NEW);}voidst_browser_tab_present_preferences (STBrowserTab *tab){ g_return_if_fail(ST_IS_BROWSER_TAB(tab)); g_return_if_fail(st_browser_tab_can_present_preferences(tab)); st_shell_present_handler_preferences(st_shell, tab->handler);}voidst_browser_tab_update (STBrowserTab *tab){ STCategoryBag *category_bag; STStreamStore *streams; g_return_if_fail(ST_IS_BROWSER_TAB(tab)); category_bag = st_handler_get_selected_category(tab->handler); g_return_if_fail(category_bag != NULL); streams = st_handler_get_streams(tab->handler, ST_CATEGORY(category_bag)->name); st_browser_tab_set_streams(tab, category_bag, streams); if (! st_category_bag_get_task_thread(category_bag)) { if (ST_HANDLER_EVENT_HAS_RELOAD(tab->handler) && st_settings.always_reload) st_browser_tab_reload(tab); else if (! streams) { if (st_cache_has_streams(tab->handler, ST_CATEGORY(category_bag)->name)) st_browser_tab_run_category_task(tab, category_bag, st_browser_tab_cache_load_streams_thread); else if (ST_HANDLER_EVENT_HAS_RELOAD(tab->handler)) st_browser_tab_reload(tab); } } g_object_unref(category_bag); if (streams) g_object_unref(streams);}static voidst_browser_tab_cache_load_streams_thread (gpointer data){ CategoryTask *task = data; STStreamStore *stream_store; GError *err = NULL; GDK_THREADS_ENTER(); st_statusbar_print(ST_STATUSBAR(task->category_bag->statusbar), task->category_bag->statusbar_context_task, _("Loading streams from cache...")); gdk_flush(); GDK_THREADS_LEAVE(); stream_store = st_cache_load_streams(task->tab->handler, ST_CATEGORY(task->category_bag)->name, st_browser_tab_cache_load_streams_progress_cb, task, &err); GDK_THREADS_ENTER(); if (stream_store) { st_handler_set_streams(task->tab->handler, ST_CATEGORY(task->category_bag)->name, stream_store); st_browser_tab_set_streams(task->tab, task->category_bag, stream_store); g_object_unref(stream_store); } st_thread_cleanup(task->thread); gdk_flush(); GDK_THREADS_LEAVE(); if (! stream_store && err) { char *normalized; normalized = st_dialog_normalize(err->message); st_error_dialog(_("Unable to load streams from cache"), "%s", normalized); g_free(normalized); g_error_free(err); }}static gbooleanst_browser_tab_cache_load_streams_progress_cb (int n, int total, gpointer data){ CategoryTask *task = data; if (st_thread_is_aborted(task->thread)) return TRUE; /* abort */ GDK_THREADS_ENTER(); st_thread_printf(task->thread, FALSE, ngettext("Loading streams from cache (%i stream out of %i)...", "Loading streams from cache (%i streams out of %i)...", n), n, total); st_thread_set_progress(task->thread, FALSE, (double) n / total); gdk_flush(); GDK_THREADS_LEAVE(); return FALSE; /* continue */}static voidst_browser_tab_update_counters (STBrowserTab *tab){ GtkTreeModel *model; GString *string; int n_streams; STCategoryBag *category_bag; g_return_if_fail(ST_IS_BROWSER_TAB(tab)); string = g_string_new(NULL); if (tab->category_view) { int n_categories; model = gtk_tree_view_get_model(GTK_TREE_VIEW(tab->category_view)); n_categories = model ? sgtk_tree_model_get_count(model) : 0; g_string_append_printf(string, ngettext("%i category", "%i categories", n_categories), n_categories); } if (*string->str) g_string_append(string, ", "); model = gtk_tree_view_get_model(GTK_TREE_VIEW(tab->stream_view)); n_streams = model ? sgtk_tree_model_get_count(model) : 0; g_string_append_printf(string, ngettext("%i stream", "%i streams", n_streams), n_streams); category_bag = st_handler_get_selected_category(tab->handler); g_return_if_fail(category_bag != NULL); st_statusbar_print(ST_STATUSBAR(category_bag->statusbar), category_bag->statusbar_context_count, string->str); g_string_free(string, TRUE);}static voidst_browser_tab_category_selection_changed_h (STCategoryView *view, gpointer user_data){ STBrowserTab *tab = user_data; st_browser_tab_update(tab);}static voidst_browser_tab_set_streams (STBrowserTab *tab, STCategoryBag *category_bag, STStreamStore *streams){ GtkTreeModel *model; STCategoryBag *selected_category; g_return_if_fail(ST_IS_BROWSER_TAB(tab)); g_return_if_fail(ST_IS_CATEGORY_BAG(category_bag)); selected_category = st_handler_get_selected_category(tab->handler); g_return_if_fail(selected_category != NULL); if (category_bag == selected_category) { model = gtk_tree_view_get_model(GTK_TREE_VIEW(tab->stream_view)); if (model) g_signal_handlers_disconnect_by_func(model, st_browser_tab_update_counters, tab); st_stream_view_set_store(tab->stream_view, streams); if (streams) g_object_connect(streams, "swapped-signal::row-deleted", st_browser_tab_update_counters, tab, "swapped-signal::row-inserted", st_browser_tab_update_counters, tab, NULL); st_browser_tab_update_counters(tab); }}static voidst_browser_tab_paned_notify_position_h (GObject *object, GParamSpec *pspec, gpointer user_data){ st_handler_set_paned_position(ST_BROWSER_TAB(object)->handler, gtk_paned_get_position(GTK_PANED(object)));}gbooleanst_browser_tab_can_run_stream_task (STBrowserTab *tab, STBrowserTabStreamTaskType type){ g_return_val_if_fail(ST_IS_BROWSER_TAB(tab), FALSE); switch (type) { case ST_BROWSER_TAB_STREAM_TASK_TUNE_IN: return ST_HANDLER_EVENT_HAS_TUNE_IN(tab->handler) && st_stream_view_has_selected_streams(tab->stream_view); case ST_BROWSER_TAB_STREAM_TASK_RECORD: return st_handler_event_is_bound(tab->handler, ST_HANDLER_EVENT_STREAM_RECORD) && st_stream_view_has_selected_streams(tab->stream_view); case ST_BROWSER_TAB_STREAM_TASK_BROWSE: return st_handler_event_is_bound(tab->handler, ST_HANDLER_EVENT_STREAM_BROWSE) && st_stream_view_has_selected_streams(tab->stream_view); case ST_BROWSER_TAB_STREAM_TASK_ADD_BOOKMARKS: return tab->handler != st_bookmarks_handler && st_stream_view_has_selected_streams(tab->stream_view); default: g_return_val_if_reached(FALSE); }}voidst_browser_tab_run_stream_task (STBrowserTab *tab, STBrowserTabStreamTaskType type){ STBrowserTabStreamTask *task; g_return_if_fail(ST_IS_BROWSER_TAB(tab)); g_return_if_fail(st_browser_tab_can_run_stream_task(tab, type)); task = g_new0(STBrowserTabStreamTask, 1); task->tab = tab; task->type = type; task->streams = st_stream_view_get_selected_streams(tab->stream_view); task->thread = st_thread_new(tab->handler); task->thread->thread = type == ST_BROWSER_TAB_STREAM_TASK_ADD_BOOKMARKS ? st_browser_tab_stream_task_add_bookmarks_thread : st_browser_tab_stream_task_thread; task->thread->cleanup = st_browser_tab_stream_task_cleanup_cb; task->thread->data = task; task->thread->data_destroy = st_browser_tab_stream_task_data_destroy_cb; tab->priv->stream_tasks = g_slist_append(tab->priv->stream_tasks, task); st_browser_tab_update_running(tab); g_signal_emit(tab, browser_tab_signals[STREAM_TASK_ADDED], 0, task); st_thread_run(task->thread);}static voidst_browser_tab_stream_task_thread (gpointer data){ STBrowserTabStreamTask *task = data; gboolean status; GError *err = NULL; /* if there's no multiple callback, only keep the first stream */ if (task->type != ST_BROWSER_TAB_STREAM_TASK_TUNE_IN || ! st_handler_event_is_bound(task->tab->handler, ST_HANDLER_EVENT_STREAM_TUNE_IN_MULTIPLE)) { sg_objects_free(task->streams->next); task->streams->next = NULL; } /* set running */ GDK_THREADS_ENTER(); g_slist_foreach(task->streams, (GFunc) st_stream_bag_running_ref, NULL); task->running_reffed_streams = g_slist_copy(task->streams); gdk_flush(); GDK_THREADS_LEAVE(); /* run the appropriate callback */ if (task->type == ST_BROWSER_TAB_STREAM_TASK_TUNE_IN) { if (st_handler_event_is_bound(task->tab->handler, ST_HANDLER_EVENT_STREAM_TUNE_IN_MULTIPLE)) status = st_stream_bag_tune_in_multiple(task->streams, &err); else status = st_stream_bag_tune_in(task->streams->data, &err); } else if (task->type == ST_BROWSER_TAB_STREAM_TASK_RECORD) status = st_stream_bag_record(task->streams->data, &err); else if (task->type == ST_BROWSER_TAB_STREAM_TASK_BROWSE) status = st_stream_bag_browse(task->streams->data, &err); else g_return_if_reached(); /* finish */ GDK_THREADS_ENTER(); st_thread_cleanup(task->thread); gdk_flush(); GDK_THREADS_LEAVE(); st_thread_validate_callback_return(task->thread, status, err); if (err) { const char *primary[] = { N_("Unable to tune in"), N_("Unable to record"), N_("Unable to browse") }; char *normalized; normalized = st_dialog_normalize(err->message); st_error_dialog(_(primary[task->type]), "%s", normalized); g_free(normalized); g_error_free(err); }}static voidst_browser_tab_stream_task_add_bookmarks_thread (gpointer data){ STBrowserTabStreamTask *task = data; GSList *l; SG_LIST_FOREACH(l, task->streams) { STStreamBag *bag = l->data; GDK_THREADS_ENTER(); st_stream_bag_running_ref(bag); task->running_reffed_streams = g_slist_append(task->running_reffed_streams, bag); gdk_flush(); GDK_THREADS_LEAVE(); if (st_handler_event_is_bound(task->tab->handler, ST_HANDLER_EVENT_STREAM_RESOLVE)) { gboolean status; GError *err = NULL; status = st_stream_bag_resolve(bag, &err); st_thread_validate_callback_return(task->thread, status, err); if (err) { char *normalized; normalized = st_dialog_normalize(err->message); st_error_dialog(_("Unable to resolve stream"), "%s", normalized); g_free(normalized); g_error_free(err); } } GDK_THREADS_ENTER(); st_stream_bag_running_unref(bag); st_bookmarks_add(bag); task->running_reffed_streams = g_slist_remove(task->running_reffed_streams, bag); gdk_flush(); GDK_THREADS_LEAVE(); }}static voidst_browser_tab_stream_task_cleanup_cb (gpointer data){ STBrowserTabStreamTask *task = data; g_slist_foreach(task->running_reffed_streams, (GFunc) st_stream_bag_running_unref, NULL); task->tab->priv->stream_tasks = g_slist_remove(task->tab->priv->stream_tasks, task); st_browser_tab_update_running(task->tab); g_signal_emit(task->tab, browser_tab_signals[STREAM_TASK_REMOVED], 0, task);}static voidst_browser_tab_stream_task_data_destroy_cb (gpointer data){ STBrowserTabStreamTask *task = data; sg_objects_free(task->streams); g_slist_free(task->running_reffed_streams); g_free(task);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -