prop_t * add_news(const char *message, const char *location, const char *caption) { prop_t *p, *ret = NULL; prop_t *root = prop_create(prop_get_global(), "news"); hts_mutex_lock(&news_mutex); if(dismissed_news_out != NULL) { if(htsmsg_get_u32_or_default(dismissed_news_in, message, 0)) { dismis_news(message); } else { p = prop_create_root(NULL); prop_set_string(prop_create(p, "message"), message); prop_set_string(prop_create(p, "location"), location); prop_set_string(prop_create(p, "caption"), caption); prop_subscribe(PROP_SUB_TRACK_DESTROY, PROP_TAG_CALLBACK, news_sink, prop_ref_inc(p), PROP_TAG_ROOT, prop_create(p, "eventSink"), PROP_TAG_MUTEX, &news_mutex, NULL); ret = prop_ref_inc(p); if(prop_set_parent(p, root)) prop_destroy(p); } } hts_mutex_unlock(&news_mutex); return ret; }
/** * Try to open the given URL with a playqueue context */ static int file_open_audio(prop_t *page, const char *url) { char parent[URL_MAX]; char parent2[URL_MAX]; struct fa_stat fs; prop_t *model; if(fa_parent(parent, sizeof(parent), url)) return 1; if(fa_stat(parent, &fs, NULL, 0)) return 1; model = prop_create(page, "model"); prop_set_string(prop_create(model, "type"), "directory"); /* Find a meaningful page title (last component of URL) */ rstr_t *title = title_from_url(parent); prop_set(model, "metadata", "title", NULL, PROP_SET_RSTRING, title); // Set parent if(!fa_parent(parent2, sizeof(parent2), parent)) prop_set_string(prop_create(page, "parent"), parent2); fa_scanner(parent, fs.fs_mtime, model, url, prop_create(page, "directClose"), title); rstr_release(title); return 0; }
static JSBool js_item_addOptAction(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { js_item_t *ji = JS_GetPrivate(cx, obj); const char *title; const char *action; if (!JS_ConvertArguments(cx, argc, argv, "ss", &title, &action)) return JS_FALSE; prop_t *p = prop_create_root(NULL); prop_set_string(prop_create(p, "type"), "action"); prop_set_string(prop_create(prop_create(p, "metadata"), "title"), title); prop_set_int(prop_create(p, "enabled"), 1); prop_set_string(prop_create(p, "action"), action); prop_t *opts = prop_create_r(ji->ji_root, "options"); if(prop_set_parent(p, opts)) prop_destroy(p); prop_ref_dec(opts); *rval = JSVAL_VOID; return JS_TRUE; }
int search_class_create(prop_t *parent, prop_t **nodesp, prop_t **entriesp, const char *title, const char *icon) { prop_t *p = prop_create_root(NULL); prop_t *m = prop_create(p, "metadata"); prop_t *n, *e; rstr_t *url = backend_prop_make(p, NULL); prop_set_rstring(prop_create(p, "url"), url); rstr_release(url); prop_set_string(prop_create(m, "title"), title); if(icon != NULL) prop_set_string(prop_create(m, "icon"), icon); prop_set_string(prop_create(p, "type"), "directory"); n = prop_create(p, "nodes"); e = prop_create(p, "entries"); prop_set_int(e, 0); *nodesp = prop_ref_inc(n); *entriesp = prop_ref_inc(e); if(prop_set_parent(p, parent)) { prop_destroy(p); return 1; } return 0; }
static void trace_prop(int l, const char *pfx, const char *msg, const char *sev) { trace_entry_t *te = malloc(sizeof(trace_entry_t)); te->p = prop_create_root(NULL); prop_set_string(prop_create(te->p, "prefix"), pfx); prop_set_string(prop_create(te->p, "message"), msg); prop_set_string(prop_create(te->p, "severity"), sev); TAILQ_INSERT_TAIL(&traces, te, link); if(prop_set_parent(te->p, log_root)) abort(); entries++; if(entries > 50) { te = TAILQ_FIRST(&traces); TAILQ_REMOVE(&traces, te, link); prop_destroy(te->p); free(te); entries--; } }
static prop_t * setting_add_cstr(prop_t *parent, const char *title, const char *type, int flags) { prop_t *p = setting_get(parent, flags); prop_set_string(prop_create(prop_create(p, "metadata"), "title"), title); prop_set_string(prop_create(p, "type"), type); return p; }
int nav_open_error(prop_t *root, const char *msg) { prop_t *model = prop_create(root, "model"); prop_set_string(prop_create(model, "type"), "openerror"); prop_set_int(prop_create(model, "loading"), 0); prop_set_string(prop_create(model, "error"), msg); prop_set_int(prop_create(root, "directClose"), 1); return 0; }
static prop_t * setting_add_cstr(prop_t *parent, const char *title, const char *type) { prop_t *p, *model; p = prop_create(parent ? prop_create(parent, "nodes") : settings_nodes, NULL); model = prop_create(p, "model"); prop_set_string(prop_create(prop_create(model, "metadata"), "title"), title); prop_set_string(prop_create(model, "type"), type); return p; }
void settings_create_info(prop_t *parent, const char *image, const char *description) { prop_t *r = prop_create(setting_add(prop_create(parent, "model"), "Info", "info"), "model"); prop_set_string(prop_create(r, "description"), description); if(image != NULL) prop_set_string(prop_create(r, "image"), image); }
static JSBool js_appendItem0(JSContext *cx, js_model_t *model, prop_t *parent, const char *url, const char *type, JSObject *metaobj, jsval *data, jsval *rval, int enabled, const char *metabind) { prop_t *item = prop_create_root(NULL); if(url != NULL) prop_set_string(prop_create(item, "url"), url); if(data != NULL) js_prop_set_from_jsval(cx, prop_create(item, "data"), *data); *rval = JSVAL_VOID; if(metabind != NULL) metadb_bind_url_to_prop(NULL, metabind, item); if(type != NULL) { prop_set_string(prop_create(item, "type"), type); if(metaobj) js_prop_from_object(cx, metaobj, prop_create(item, "metadata")); } else if(url != NULL) { if(backend_resolve_item(url, item)) { prop_destroy(item); return JS_TRUE; } } prop_set_int(prop_create(item, "enabled"), enabled); prop_t *p = prop_ref_inc(item); if(prop_set_parent(item, parent)) { prop_destroy(item); prop_ref_dec(p); } else { JSObject *robj = JS_NewObjectWithGivenProto(cx, &item_class, JSVAL_TO_OBJECT(model->jm_item_proto), NULL); *rval = OBJECT_TO_JSVAL(robj); js_item_t *ji = calloc(1, sizeof(js_item_t)); ji->ji_model = model; ji->ji_root = p; LIST_INSERT_HEAD(&model->jm_items, ji, ji_link); JS_SetPrivate(cx, robj, ji); ji->ji_enable_set_property = 1; } return JS_TRUE; }
int message_popup(const char *message, int flags, const char **extra) { prop_t *p; int rval; p = prop_ref_inc(prop_create_root(NULL)); TRACE(TRACE_DEBUG, "Notification", "%s", message); prop_set_string(prop_create(p, "type"), "message"); prop_set_string_ex(prop_create(p, "message"), NULL, message, flags & MESSAGE_POPUP_RICH_TEXT ? PROP_STR_RICH : PROP_STR_UTF8); if(extra) { int cnt = 1; prop_t *btns = prop_create(p, "buttons"); while(*extra) { prop_t *b = prop_create_root(NULL); prop_set_string(prop_create(b, "title"), *extra); char action[10]; snprintf(action, sizeof(action), "btn%d", cnt); prop_set_string(prop_create(b, "action"), action); if(prop_set_parent(b, btns)) abort(); cnt++; extra++; } } if(flags & MESSAGE_POPUP_CANCEL) prop_set_int(prop_create(p, "cancel"), 1); if(flags & MESSAGE_POPUP_OK) prop_set_int(prop_create(p, "ok"), 1); event_t *e = popup_display(p); prop_destroy(p); prop_ref_dec(p); const event_payload_t *ep = (const event_payload_t *)e; if(event_is_action(e, ACTION_OK)) rval = MESSAGE_POPUP_OK; else if(event_is_action(e, ACTION_CANCEL)) rval = MESSAGE_POPUP_CANCEL; else if(event_is_type(e, EVENT_DYNAMIC_ACTION) && !strncmp(ep->payload, "btn", 3)) rval = atoi(ep->payload + 3); else rval = 0; event_release(e); return rval; }
void settings_init(void) { prop_t *n, *d, *model; prop_t *s1; settings_root = prop_create(prop_get_global(), "settings"); prop_set_string(prop_create(settings_root, "type"), "settings"); set_title(settings_root, _p("Global settings")); settings_nodes = prop_create_root(NULL); s1 = prop_create_root(NULL); prop_nf_create(s1, settings_nodes, NULL, "node.model.metadata.title", PROP_NF_AUTODESTROY); settings_apps = prop_create_root(NULL); settings_sd = prop_create_root(NULL); prop_concat_t *pc; pc = prop_concat_create(prop_create(settings_root, "nodes"), 0); prop_concat_add_source(pc, s1, NULL); // Applications and plugins n = prop_create(prop_create(settings_apps, "model"), "nodes"); d = prop_create_root(NULL); model = prop_create(d, "model"); set_title(model, _p("Applications and installed plugins")); prop_set_string(prop_create(model, "type"), "divider"); prop_concat_add_source(pc, n, d); d = prop_create_root(NULL); model = prop_create(d, "model"); set_title(model, _p("Discovered media sources")); prop_set_string(prop_create(model, "type"), "divider"); n = prop_create(prop_create(settings_sd, "model"), "nodes"); prop_concat_add_source(pc, n, d); // General settings settings_general = settings_add_dir(NULL, _p("General"), NULL, NULL, _p("System related settings")); }
void * notify_add(prop_t *root, notify_type_t type, const char *icon, int delay, rstr_t *fmt, ...) { char msg[256]; prop_t *p; const char *typestr; int tl; va_list ap, apx; switch(type) { case NOTIFY_INFO: typestr = "info"; tl = TRACE_INFO; break; case NOTIFY_WARNING: typestr = "warning"; tl = TRACE_INFO; break; case NOTIFY_ERROR: typestr = "error"; tl = TRACE_ERROR; break; default: return NULL; } va_start(ap, fmt); va_copy(apx, ap); tracev(0, tl, "notify", rstr_get(fmt), ap); vsnprintf(msg, sizeof(msg), rstr_get(fmt), apx); va_end(ap); va_end(apx); rstr_release(fmt); p = prop_create_root(NULL); prop_set_string(prop_create(p, "text"), msg); prop_set_string(prop_create(p, "type"), typestr); if(icon != NULL) prop_set_string(prop_create(p, "icon"), icon); p = prop_ref_inc(p); if(prop_set_parent(p, root ?: notify_prop_entries)) prop_destroy(p); if(delay != 0) { prop_t *r = NULL; if(delay < 0) { r = prop_ref_inc(p); delay = -delay; } callout_arm(NULL, notify_timeout, p, delay); return r; } return p; }
void settings_init(void) { prop_t *n, *d; prop_t *s1; settings_root = prop_create(prop_get_global(), "settings"); prop_set_string(prop_create(settings_root, "type"), "settings"); set_title2(settings_root, _p("Global settings")); settings_nodes = prop_create_root(NULL); s1 = prop_create_root(NULL); struct prop_nf *pnf; pnf = prop_nf_create(s1, settings_nodes, NULL, PROP_NF_AUTODESTROY); prop_nf_sort(pnf, "node.metadata.title", 0, 0, NULL, 1); settings_apps = prop_create_root(NULL); settings_sd = prop_create_root(NULL); prop_concat_t *pc; pc = prop_concat_create(prop_create(settings_root, "nodes"), 0); prop_concat_add_source(pc, s1, NULL); // Applications and plugins n = prop_create(settings_apps, "nodes"); d = prop_create_root(NULL); set_title2(d, _p("Applications and installed plugins")); prop_set_string(prop_create(d, "type"), "separator"); prop_concat_add_source(pc, n, d); d = prop_create_root(NULL); set_title2(d, _p("Discovered media sources")); prop_set_string(prop_create(d, "type"), "separator"); n = prop_create(settings_sd, "nodes"); prop_concat_add_source(pc, n, d); // General settings settings_general = settings_add_dir(NULL, _p("General"), NULL, NULL, _p("System related settings"), "settings:general"); // Developer settings, only available via its URI init_dev_settings(); }
/** * Set some info in the global property tree that might be interesting */ static void init_global_info(void) { prop_t *s = prop_create(prop_get_global(), "showtime"); extern const char *htsversion; extern const char *htsversion_full; prop_set_string(prop_create(s, "version"), htsversion); prop_set_string(prop_create(s, "fullversion"), htsversion_full); prop_set_string(prop_create(s, "copyright"), "© 2006 - 2011 Andreas Öman"); }
static int be_page_open(prop_t *root, const char *url0, int sync) { prop_t *src = prop_create(root, "model"); prop_t *metadata = prop_create(src, "metadata"); char *cap = mystrdupa(url0 + strlen("page:")); prop_set_string(prop_create(src, "type"), cap); cap[0] = toupper((int)cap[0]); prop_set_string(prop_create(metadata, "title"), cap); return 0; }
static void htsp_channelAddUpdate(htsp_connection_t *hc, htsmsg_t *m, int create) { uint32_t id, next; int chnum; char txt[200]; const char *title, *icon; htsp_channel_t *ch; if(htsmsg_get_u32(m, "channelId", &id)) return; title = htsmsg_get_str(m, "channelName"); icon = htsmsg_get_str(m, "channelIcon"); chnum = htsmsg_get_s32_or_default(m, "channelNumber", -1); snprintf(txt, sizeof(txt), "%d", id); hts_mutex_lock(&hc->hc_meta_mutex); if(create) { ch = htsp_channel_get(hc, id, 1); if(prop_set_parent(ch->ch_root, hc->hc_channels_nodes)) abort(); } else { ch = htsp_channel_get(hc, id, 0); if(ch == NULL) { TRACE(TRACE_ERROR, "HTSP", "Got update for unknown channel %d", id); hts_mutex_unlock(&hc->hc_meta_mutex); return; } } hts_mutex_unlock(&hc->hc_meta_mutex); if(icon != NULL) prop_set_string(ch->ch_prop_icon, icon); if(title != NULL) { mystrset(&ch->ch_title, title); prop_set_string(ch->ch_prop_title, title); } if(chnum != -1) prop_set_int(ch->ch_prop_channelNumber, chnum); if(htsmsg_get_u32(m, "eventId", &id)) id = 0; if(htsmsg_get_u32(m, "nextEventId", &next)) next = 0; update_events(hc, ch->ch_prop_events, id, next); }
static void bookmark_add(const char *title, const char *url, const char *type) { bookmark_t *bm = calloc(1, sizeof(bookmark_t)); prop_t *p = prop_create_root(NULL); prop_t *src = prop_create(p, "model"); prop_set_string(prop_create(src, "type"), "bookmark"); bm->bm_title_sub = bookmark_add_prop(src, "title", title, bm, set_title); bm->bm_url_sub = bookmark_add_prop(src, "url", url, bm, set_url); bm->bm_type_sub = bookmark_add_prop(src, "svctype", type, bm, set_type); bm->bm_service = service_create(title, url, type, NULL, 1, 1); prop_link(service_get_status_prop(bm->bm_service), prop_create(src, "status")); prop_link(service_get_statustxt_prop(bm->bm_service), prop_create(src, "statustxt")); prop_subscribe(PROP_SUB_TRACK_DESTROY | PROP_SUB_NO_INITIAL_UPDATE, PROP_TAG_CALLBACK, bookmark_destroyed, bm, PROP_TAG_ROOT, p, PROP_TAG_MUTEX, &bookmark_mutex, NULL); if(prop_set_parent(p, prop_create(bookmarks, "nodes"))) abort(); }
void connman_init(void) { TAILQ_INIT(&connman_services); netconf_model = prop_create_root(NULL); prop_concat_t *pc = prop_concat_create(prop_create(netconf_model, "nodes")); net_state = prop_create(netconf_model, "status"); prop_set(netconf_model, "type", PROP_SET_STRING, "directory"); prop_t *m = prop_create(netconf_model, "metadata"); prop_set(m, "title", PROP_SET_RSTRING, _("Network connections")); // service_nodes contains list of items we receive from connman service_nodes = prop_create_root(NULL); prop_concat_add_source(pc, service_nodes, NULL); // settings connman_settings = prop_create_root(NULL); prop_t *delim = prop_create_root(NULL); prop_set_string(prop_create(delim, "type"), "separator"); prop_concat_add_source(pc, prop_create(connman_settings, "nodes"), delim); settings_add_url(gconf.settings_network, _p("Network connections"), NULL, NULL, NULL, MYURL, SETTINGS_FIRST); hts_thread_create_detached("connman", connman_thread, NULL, THREAD_PRIO_BGTASK); }
static void connman_getpropreties(GDBusProxy *connman) { GError *err = NULL; GVariant *v = g_dbus_proxy_call_sync(connman, "GetProperties", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err); if(v == NULL) { TRACE(TRACE_ERROR, "CONNMAN", "Unable to GetProperties -- %s", err->message); g_error_free(err); return; } GVariant *dict = g_variant_get_child_value(v, 0); if(dict != NULL) { GVariant *state = g_variant_lookup_value(dict, "State", NULL); if(state != NULL) { const gchar *val = g_variant_get_string(state, NULL); prop_set_string(net_state, val); } } g_variant_unref(v); }
static void settings_add_dir_sup(prop_t *root, const char *url, const char *icon, const char *subtype) { rstr_t *url2 = backend_prop_make(root, url); prop_set_rstring(prop_create(root, "url"), url2); rstr_release(url2); prop_t *metadata = prop_create(root, "metadata"); prop_set_string(prop_create(root, "subtype"), subtype); if(icon != NULL) prop_set_string(prop_create(metadata, "icon"), icon); }
int message_popup(const char *message, int flags) { prop_t *p; int rval; p = prop_create_root(NULL); prop_set_string(prop_create(p, "type"), "message"); prop_set_string_ex(prop_create(p, "message"), NULL, message, flags & MESSAGE_POPUP_RICH_TEXT ? PROP_STR_RICH : PROP_STR_UTF8); if(flags & MESSAGE_POPUP_CANCEL) prop_set_int(prop_create(p, "cancel"), 1); if(flags & MESSAGE_POPUP_OK) prop_set_int(prop_create(p, "ok"), 1); event_t *e = popup_display(p); prop_destroy(p); if(event_is_action(e, ACTION_OK)) rval = MESSAGE_POPUP_OK; else if(event_is_action(e, ACTION_CANCEL)) rval = MESSAGE_POPUP_CANCEL; else rval = 0; event_release(e); return rval; }
JSBool js_addsubprovider(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { js_subprovider_t *sp; js_plugin_t *jsp = JS_GetPrivate(cx, obj); if(!JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(argv[0]))) { JS_ReportError(cx, "Argument is not a function"); return JS_FALSE; } sp = calloc(1, sizeof(js_subprovider_t)); sp->super.sp_query = js_sub_query; sp->super.sp_retain = js_sub_retain; sp->sp_title = prop_create_root(NULL); prop_set_string(sp->sp_title, jsp->jsp_id); subtitle_provider_register(&sp->super, jsp->jsp_id, sp->sp_title, 0, "plugin", 1, 1); sp->sp_jsp = jsp; LIST_INSERT_HEAD(&jsp->jsp_subproviders, sp, sp_plugin_link); sp->sp_func = argv[0]; atomic_set(&sp->sp_refcnt, 1); JS_AddNamedRoot(cx, &sp->sp_func, "subprovider"); *rval = JSVAL_VOID; return JS_TRUE; }
static void set_title_from_url(prop_t *metadata, const char *url) { char tmp[1024]; fa_url_get_last_component(tmp, sizeof(tmp), url); prop_set_string(prop_create(metadata, "title"), tmp); }
void mp_set_playstatus_by_hold_locked(media_pipe_t *mp, const char *msg) { int hold = !!mp->mp_hold_flags; if(hold == mp->mp_hold_gate) return; mp->mp_hold_gate = hold; int cmd = hold ? MB_CTRL_PAUSE : MB_CTRL_PLAY; if(mp->mp_flags & MP_VIDEO) mp_send_cmd_locked(mp, &mp->mp_video, cmd); mp_send_cmd_locked(mp, &mp->mp_audio, cmd); if(!hold) prop_set_void(mp->mp_prop_pausereason); else prop_set_string(mp->mp_prop_pausereason, msg ?: "Paused by user"); prop_set_string(mp->mp_prop_playstatus, hold ? "pause" : "play"); mp_event_dispatch(mp, event_create_int(EVENT_HOLD, hold)); if(mp->mp_flags & MP_FLUSH_ON_HOLD) mp_flush_locked(mp, 0); if(mp->mp_hold_changed != NULL) mp->mp_hold_changed(mp); }
static void glw_slideshow_update_playstatus(glw_slideshow_t *s) { s->deadline = s->hold ? INT64_MAX : 0; glw_need_refresh(s->w.glw_root, 0); prop_set_string(s->playstatus, s->hold ? "pause" : "play"); }
static void nav_open0(navigator_t *nav, const char *url, const char *view, prop_t *origin) { nav_page_t *np = calloc(1, sizeof(nav_page_t)); np->np_nav = nav; np->np_url = url ? strdup(url) : NULL; np->np_direct_close = 0; TAILQ_INSERT_TAIL(&nav->nav_pages, np, np_global_link); np->np_prop_root = prop_create_root("page"); if(view != NULL) { np->np_view = strdup(view); prop_set_string(prop_create(np->np_prop_root, "requestedView"), view); } // XXX Change this into event-style subscription np->np_close_sub = prop_subscribe(0, PROP_TAG_ROOT, prop_create(np->np_prop_root, "close"), PROP_TAG_CALLBACK_INT, nav_page_close_set, np, PROP_TAG_COURIER, nav->nav_pc, NULL); if(url != NULL) prop_set_string(prop_create(np->np_prop_root, "url"), url); np->np_url_sub = prop_subscribe(PROP_SUB_NO_INITIAL_UPDATE, PROP_TAG_ROOT, prop_create(np->np_prop_root, "url"), PROP_TAG_CALLBACK_STRING, nav_page_url_set, np, PROP_TAG_COURIER, nav->nav_pc, NULL); np->np_direct_close_sub = prop_subscribe(PROP_SUB_NO_INITIAL_UPDATE, PROP_TAG_ROOT, prop_create(np->np_prop_root, "directClose"), PROP_TAG_CALLBACK_INT, nav_page_direct_close_set, np, PROP_TAG_COURIER, nav->nav_pc, NULL); TRACE(TRACE_INFO, "navigator", "Opening %s", url); if(backend_open(np->np_prop_root, url)) nav_open_errorf(np->np_prop_root, url, "No handler for URL"); nav_insert_page(nav, np, origin); }
int nav_open_errorf(prop_t *root, const char *fmt, ...) { va_list ap; char buf[200]; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); prop_t *src = prop_create(root, "model"); prop_set_string(prop_create(src, "type"), "openerror"); prop_set_int(prop_create(src, "loading"), 0); prop_set_string(prop_create(src, "error"), buf); prop_set_int(prop_create(root, "directClose"), 1); return 0; }
prop_t * settings_multiopt_add_opt_cstr(setting_t *s, const char *id, const char *title, int selected) { prop_t *o = prop_create(s->s_val, id); prop_set_string(prop_create(o, "title"), title); return settings_multiopt_add(s, id, o, selected); }
void mp_set_mq_meta(media_queue_t *mq, const AVCodec *codec, const AVCodecContext *avctx) { char buf[128]; metadata_from_libav(buf, sizeof(buf), codec, avctx); prop_set_string(mq->mq_prop_codec, buf); }