📄 st-stream-bag.c
字号:
/* * Copyright (c) 2004 Jean-Yves Lefort * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Jean-Yves Lefort nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */#include <string.h>#include <glib-object.h>#include "sg-util.h"#include "st-stream-bag.h"#include "st-stream-view.h"#include "st-handler.h"#include "st-stock.h"#include "st-stream-store.h"#include "st-handler-field.h"/*** type definitions ********************************************************/enum { CHANGED, STATE_CHANGED, DELETED, LAST_SIGNAL}; struct _STStreamBagPrivate{ int running_count;};/*** variable declarations ***************************************************/static GObjectClass *parent_class = NULL;static unsigned int stream_bag_signals[LAST_SIGNAL] = { 0 };/*** function declarations ***************************************************/static void st_stream_bag_class_init (STStreamBagClass *class);static void st_stream_bag_init (STStreamBag *bag);static void st_stream_bag_finalize (GObject *object);/*** implementation **********************************************************/GTypest_stream_bag_get_type (void){ static GType stream_bag_type = 0; if (! stream_bag_type) { static const GTypeInfo stream_bag_info = { sizeof(STStreamBagClass), NULL, NULL, (GClassInitFunc) st_stream_bag_class_init, NULL, NULL, sizeof(STStreamBag), 0, (GInstanceInitFunc) st_stream_bag_init, }; stream_bag_type = g_type_register_static(G_TYPE_OBJECT, "STStreamBag", &stream_bag_info, 0); } return stream_bag_type;}static voidst_stream_bag_class_init (STStreamBagClass *class){ GObjectClass *object_class = G_OBJECT_CLASS(class); parent_class = g_type_class_peek_parent(class); g_type_class_add_private(class, sizeof(STStreamBagPrivate)); object_class->finalize = st_stream_bag_finalize; stream_bag_signals[CHANGED] = g_signal_new("changed", ST_TYPE_STREAM_BAG, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(STStreamBagClass, changed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); stream_bag_signals[STATE_CHANGED] = g_signal_new("state-changed", ST_TYPE_STREAM_BAG, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(STStreamBagClass, state_changed), NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); stream_bag_signals[DELETED] = g_signal_new("deleted", ST_TYPE_STREAM_BAG, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(STStreamBagClass, deleted), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);}static voidst_stream_bag_init (STStreamBag *bag){ bag->stream = NULL; bag->handler = NULL; memset(&bag->iter, 0, sizeof(bag->iter)); bag->priv = G_TYPE_INSTANCE_GET_PRIVATE(bag, ST_TYPE_STREAM_BAG, STStreamBagPrivate);}static voidst_stream_bag_finalize (GObject *object){ STStreamBag *bag = ST_STREAM_BAG(object); st_handler_event_stream_free(bag->handler, bag->stream); parent_class->finalize(object);}STStreamBag *st_stream_bag_new (STHandler *handler){ g_return_val_if_fail(ST_IS_HANDLER(handler), NULL); return st_stream_bag_new_from_stream(handler, st_handler_event_stream_new(handler));}STStreamBag *st_stream_bag_new_from_stream (STHandler *handler, STStream *stream){ STStreamBag *bag; g_return_val_if_fail(ST_IS_HANDLER(handler), NULL); g_return_val_if_fail(stream != NULL, NULL); bag = g_object_new(ST_TYPE_STREAM_BAG, NULL); bag->stream = stream; bag->handler = handler; return bag;}voidst_stream_bag_running_ref (STStreamBag *bag){ g_return_if_fail(ST_IS_STREAM_BAG(bag)); if (++bag->priv->running_count == 1) g_signal_emit(bag, stream_bag_signals[STATE_CHANGED], 0, TRUE);}voidst_stream_bag_running_unref (STStreamBag *bag){ g_return_if_fail(ST_IS_STREAM_BAG(bag)); g_return_if_fail(bag->priv->running_count > 0); if (--bag->priv->running_count == 0) g_signal_emit(bag, stream_bag_signals[STATE_CHANGED], 0, FALSE);}/*** event wrappers **********************************************************/voidst_stream_bag_get_field (STStreamBag *bag, STHandlerField *field, GValue *value){ g_return_if_fail(ST_IS_STREAM_BAG(bag)); g_return_if_fail(field != NULL); g_return_if_fail(value != NULL); g_value_init(value, st_handler_field_get_type(field)); st_handler_event_stream_field_get(bag->handler, bag->stream, field, value);}voidst_stream_bag_set_field (STStreamBag *bag, STHandlerField *field, const GValue *value){ g_return_if_fail(ST_IS_STREAM_BAG(bag)); g_return_if_fail(field != NULL); g_return_if_fail(G_IS_VALUE(value)); st_handler_event_stream_field_set(bag->handler, bag->stream, field, value);}voidst_stream_bag_get_stock_field (STStreamBag *bag, STHandlerStockField stock_field, GValue *value){ g_return_if_fail(ST_IS_STREAM_BAG(bag)); g_return_if_fail(st_handler_event_is_bound(bag->handler, ST_HANDLER_EVENT_STREAM_STOCK_FIELD_GET)); switch (stock_field) { case ST_HANDLER_STOCK_FIELD_NAME: case ST_HANDLER_STOCK_FIELD_GENRE: case ST_HANDLER_STOCK_FIELD_DESCRIPTION: case ST_HANDLER_STOCK_FIELD_HOMEPAGE: g_value_init(value, G_TYPE_STRING); break; case ST_HANDLER_STOCK_FIELD_URI_LIST: g_value_init(value, G_TYPE_VALUE_ARRAY); break; default: g_return_if_reached(); } st_stream_bag_get_stock_field_initialized(bag, stock_field, value);}voidst_stream_bag_get_stock_field_initialized (STStreamBag *bag, STHandlerStockField stock_field, GValue *value){ g_return_if_fail(ST_IS_STREAM_BAG(bag)); g_return_if_fail(st_handler_event_is_bound(bag->handler, ST_HANDLER_EVENT_STREAM_STOCK_FIELD_GET)); g_return_if_fail(G_IS_VALUE(value)); switch (stock_field) { case ST_HANDLER_STOCK_FIELD_NAME: case ST_HANDLER_STOCK_FIELD_GENRE: case ST_HANDLER_STOCK_FIELD_DESCRIPTION: case ST_HANDLER_STOCK_FIELD_HOMEPAGE: g_return_if_fail(G_VALUE_HOLDS_STRING(value)); break; case ST_HANDLER_STOCK_FIELD_URI_LIST: g_return_if_fail(G_VALUE_HOLDS(value, G_TYPE_VALUE_ARRAY)); break; default: g_return_if_reached(); } st_handler_event_stream_stock_field_get(bag->handler, bag->stream, stock_field, value);}/* * Must be called from a thread. */gbooleanst_stream_bag_resolve (STStreamBag *bag, GError **err){ gboolean status; g_return_val_if_fail(ST_IS_STREAM_BAG(bag), FALSE); g_return_val_if_fail(st_handler_event_is_bound(bag->handler, ST_HANDLER_EVENT_STREAM_RESOLVE), FALSE); status = st_handler_event_stream_resolve(bag->handler, ST_STREAM(bag), err); if (status) { GDK_THREADS_ENTER(); g_signal_emit(bag, stream_bag_signals[CHANGED], 0); gdk_flush(); GDK_THREADS_LEAVE(); } return status;}/* * Must be called from a thread. */gbooleanst_stream_bag_tune_in_multiple (GSList *bags, GError **err){ STHandler *handler; GSList *l; GSList *streams = NULL; gboolean status; /* require at least one stream */ g_return_val_if_fail(bags != NULL, FALSE); handler = ST_STREAM_BAG(bags->data)->handler; g_return_val_if_fail(st_handler_event_is_bound(handler, ST_HANDLER_EVENT_STREAM_TUNE_IN_MULTIPLE), FALSE); SG_LIST_FOREACH(l, bags) { STStreamBag *bag = ST_STREAM_BAG(l->data); streams = g_slist_append(streams, ST_STREAM(bag)); } status = st_handler_event_stream_tune_in_multiple(handler, streams, err); g_slist_free(streams); if (status) { GDK_THREADS_ENTER(); SG_LIST_FOREACH(l, bags) g_signal_emit(l->data, stream_bag_signals[CHANGED], 0); gdk_flush(); GDK_THREADS_LEAVE(); } return status;}/* * Must be called from a thread. */gbooleanst_stream_bag_tune_in (STStreamBag *bag, GError **err){ gboolean status; g_return_val_if_fail(ST_IS_STREAM_BAG(bag), FALSE); g_return_val_if_fail(st_handler_event_is_bound(bag->handler, ST_HANDLER_EVENT_STREAM_TUNE_IN), FALSE); status = st_handler_event_stream_tune_in(bag->handler, ST_STREAM(bag), err); if (status) { GDK_THREADS_ENTER(); g_signal_emit(bag, stream_bag_signals[CHANGED], 0); gdk_flush(); GDK_THREADS_LEAVE(); } return status;}/* * Must be called from a thread. */gbooleanst_stream_bag_record (STStreamBag *bag, GError **err){ gboolean status; g_return_val_if_fail(ST_IS_STREAM_BAG(bag), FALSE); g_return_val_if_fail(st_handler_event_is_bound(bag->handler, ST_HANDLER_EVENT_STREAM_RECORD), FALSE); status = st_handler_event_stream_record(bag->handler, ST_STREAM(bag), err); if (status) { GDK_THREADS_ENTER(); g_signal_emit(bag, stream_bag_signals[CHANGED], 0); gdk_flush(); GDK_THREADS_LEAVE(); } return status;}/* * Must be called from a thread. */gbooleanst_stream_bag_browse (STStreamBag *bag, GError **err){ gboolean status; g_return_val_if_fail(ST_IS_STREAM_BAG(bag), FALSE); g_return_val_if_fail(st_handler_event_is_bound(bag->handler, ST_HANDLER_EVENT_STREAM_BROWSE), FALSE); status = st_handler_event_stream_browse(bag->handler, ST_STREAM(bag), err); if (status) { GDK_THREADS_ENTER(); g_signal_emit(bag, stream_bag_signals[CHANGED], 0); gdk_flush(); GDK_THREADS_LEAVE(); } return status;}gbooleanst_stream_bag_modify (STStreamBag *bag, GSList *fields, GSList *values, GError **err){ gboolean status; g_return_val_if_fail(ST_IS_STREAM_BAG(bag), FALSE); g_return_val_if_fail(st_handler_event_is_bound(bag->handler, ST_HANDLER_EVENT_STREAM_MODIFY), FALSE); status = st_handler_event_stream_modify(bag->handler, bag->stream, fields, values, err); /* the stream might have been modified even if ! status */ g_signal_emit(bag, stream_bag_signals[CHANGED], 0); return status;}gbooleanst_stream_bag_delete (STStreamBag *bag, GError **err){ g_return_val_if_fail(ST_IS_STREAM_BAG(bag), FALSE); g_return_val_if_fail(st_handler_event_is_bound(bag->handler, ST_HANDLER_EVENT_STREAM_DELETE), FALSE); if (st_handler_event_stream_delete(bag->handler, bag->stream, err)) { g_signal_emit(bag, stream_bag_signals[DELETED], 0); return TRUE; } else return FALSE;}gbooleanst_stream_bag_matches (STStreamBag *bag, const char *token, gboolean case_sensitive){ GSList *l; gboolean matches = FALSE; g_return_val_if_fail(ST_IS_STREAM_BAG(bag), FALSE); g_return_val_if_fail(token != NULL, FALSE); SG_LIST_FOREACH(l, st_handler_get_fields(bag->handler)) { STHandlerField *field = l->data; if (ST_HANDLER_FIELD_IS_VISIBLE(field)) { GValue value = { 0, }; GValue transformed = { 0, }; st_stream_bag_get_field(bag, field, &value); g_value_init(&transformed, G_TYPE_STRING); if (g_value_transform(&value, &transformed)) { const char *str = g_value_get_string(&transformed); if (str) matches = case_sensitive ? sg_utf8_strcontains(str, token) : sg_utf8_strcasecontains(str, token); } g_value_unset(&value); g_value_unset(&transformed); if (matches) break; } } return matches;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -