summaryrefslogtreecommitdiff
path: root/src/fruits
diff options
context:
space:
mode:
Diffstat (limited to 'src/fruits')
-rw-r--r--src/fruits/cmc/ui/widgets/now_playing.c21
-rw-r--r--src/fruits/cmsrv/cmsrv.c76
-rw-r--r--src/fruits/cmv/cmv.c22
-rwxr-xr-xsrc/fruits/cmv/create_icon.sh4
-rw-r--r--src/fruits/cmv/meson.build10
5 files changed, 96 insertions, 37 deletions
diff --git a/src/fruits/cmc/ui/widgets/now_playing.c b/src/fruits/cmc/ui/widgets/now_playing.c
index 56405b3..1a4303d 100644
--- a/src/fruits/cmc/ui/widgets/now_playing.c
+++ b/src/fruits/cmc/ui/widgets/now_playing.c
@@ -162,23 +162,28 @@ void cmc_now_playing_render(struct cmc_now_playing *np, struct cmc_list_entry *e
ncplane_putstr_yx(np->n, 1, x1 + 2, timestr);
if (entry) {
- u32 rslash = al_str_rfind(&entry->brief, '/');
str part;
+ u32 rslash = al_str_rfind(&entry->brief, '/');
if (rslash != AL_STR_NO_POS) {
part = al_str_substr(&entry->brief, rslash + 1, entry->brief.length);
} else {
part = entry->brief;
}
- char *c_str = al_str_to_c_str(&part);
+ // x1 = Position of right side "|".
+ // x2 = First character of entry brief.
s32 x2 = 6 + width1;
- // @TODO: Can mid be negative.
s32 mid = x1 - x2;
- ncplane_putnstr_yx(np->n, 1, x2, MIN(al_strlen(c_str), (size_t)mid), c_str);
- if (part.length >= mid) {
- ncplane_putnstr_yx(np->n, 1, x2 + mid - 1, 1, ".");
- ncplane_putnstr_yx(np->n, 1, x2 + mid - 2, 1, ".");
+ if (mid >= 1) {
+ char *c_str = al_str_to_c_str(&part);
+ ncplane_putnstr_yx(np->n, 1, x2, MIN(al_strlen(c_str), (size_t)mid), c_str);
+ if (part.length >= (u32)mid) {
+ ncplane_putnstr_yx(np->n, 1, x2 + mid - 1, 1, ".");
+ if (mid >= 2) {
+ ncplane_putnstr_yx(np->n, 1, x2 + mid - 2, 1, ".");
+ }
+ }
+ al_free(c_str);
}
- al_free(c_str);
bool visual_cached = false;
struct cmc_now_playing_visual *visual;
diff --git a/src/fruits/cmsrv/cmsrv.c b/src/fruits/cmsrv/cmsrv.c
index b0793d1..452254b 100644
--- a/src/fruits/cmsrv/cmsrv.c
+++ b/src/fruits/cmsrv/cmsrv.c
@@ -30,6 +30,7 @@ struct cmsrv {
struct nn_line_processor cli;
} local;
#endif
+ bool use_ui;
#ifdef CMSRV_USE_UI
struct cmsrv_ui ui;
struct nn_poll input_poll;
@@ -43,14 +44,27 @@ static void close_cmsrv(struct cmsrv *s)
nn_line_processor_stop(&s->local.cli);
#endif
#ifdef CMSRV_USE_UI
- nn_poll_stop(&s->input_poll);
- nn_timer_stop(&s->render_timer);
+ if (s->use_ui) {
+ nn_poll_stop(&s->input_poll);
+ nn_timer_stop(&s->render_timer);
+ }
#endif
camu_server_close(&s->server);
nn_signal_stop(&s->quit_signal);
}
#ifdef CMSRV_LOCAL_SOCKET
+static inline void try_parse_arg_from_line(str *line, u32 offset, s32 *n)
+{
+ str arg = al_str_substr(line, offset, line->length);
+ bool error;
+ s64 i = al_str_to_long(&arg, 10, &error);
+ if (!error) {
+ if (*n < 0) i = -i;
+ *n = CLAMP(i, (s64)INT32_MIN, (s64)INT32_MAX);
+ }
+}
+
static u8 server_line_callback(void *userdata, str *line)
{
struct cmsrv *s = (struct cmsrv *)userdata;
@@ -60,19 +74,13 @@ static u8 server_line_callback(void *userdata, str *line)
} else if (al_str_cmp(line, &al_str_c(";NEXT"), 0, 5) == 0) {
s32 n = 1;
if (line->length > 6) {
- str arg = al_str_substr(line, 6, line->length);
- bool error;
- s64 i = al_str_to_long(&arg, 10, &error);
- if (!error) n = CLAMP(i, (s64)INT32_MIN, (s64)INT32_MAX);
+ try_parse_arg_from_line(line, 6, &n);
}
lia_list_skip(list, LIANA_SEQUENCE_ANY, n);
} else if (al_str_cmp(line, &al_str_c(";PREV"), 0, 5) == 0) {
s32 n = -1;
if (line->length > 6) {
- str arg = al_str_substr(line, 6, line->length);
- bool error;
- s64 i = -al_str_to_long(&arg, 10, &error);
- if (!error) n = CLAMP(i, (s64)INT32_MIN, (s64)INT32_MAX);
+ try_parse_arg_from_line(line, 6, &n);
}
lia_list_skip(list, LIANA_SEQUENCE_ANY, n);
} else if (al_str_cmp(line, &al_str_c(";SEEK"), 0, 5) == 0) {
@@ -93,8 +101,18 @@ static u8 server_line_callback(void *userdata, str *line)
lia_list_reverse(list);
} else if (al_str_eq(line, &al_str_c(";CLEAR"))) {
lia_list_clear(list);
+ } else if (al_str_cmp(line, &al_str_c(";START_AT"), 0, 9) == 0) {
+ if (line->length > 6) {
+ s32 n = 0;
+ try_parse_arg_from_line(line, 10, &n);
+ if (n > 0) {
+ camu_server_local_start_at(&s->server, n);
+ }
+ }
} else if (al_str_eq(line, &al_str_c(";DISCONNECT"))) {
lia_server_force_disconnect_nodes(&s->server.data.server);
+ } else if (al_str_eq(line, &al_str_c(";QUIT"))) {
+ close_cmsrv(s);
} else {
struct nn_packet *packet = nn_packet_create();
nn_packet_write_str(packet, line);
@@ -156,10 +174,17 @@ static void quit_signal_callback(void *userdata)
static struct cmsrv s = { 0 };
+static bool sigint_force = false;
static void sigint_handler(s32 signum)
{
(void)signum;
- nn_signal_send(&s.quit_signal);
+ if (sigint_force) {
+ exit(128 + SIGINT);
+ } else {
+ nn_signal_send(&s.quit_signal);
+ log_warn("Attempting graceful exit. ^C again to force exit.");
+ sigint_force = true;
+ }
}
#ifdef NAUNET_ON_WINDOWS
@@ -172,11 +197,16 @@ s32 main(s32 argc, char *argv[])
return EXIT_FAILURE;
}
+ s.use_ui = false;
#ifdef CMSRV_USE_UI
- if (!cmsrv_ui_init(&s.ui, &s.server)) {
- return EXIT_FAILURE;
+ char *CMSRV_UI = getenv("CMSRV_UI");
+ if (CMSRV_UI) s.use_ui = al_strscmp(CMSRV_UI, "1") == 0;
+ if (s.use_ui) {
+ if (!cmsrv_ui_init(&s.ui, &s.server)) {
+ return EXIT_FAILURE;
+ }
+ al_set_print(log_callback, &s);
}
- al_set_print(log_callback, &s);
#endif
#ifdef CAMU_HAVE_FFMPEG
@@ -194,7 +224,7 @@ s32 main(s32 argc, char *argv[])
if (CMSRV_IP) addr = al_str_cr(CMSRV_IP);
log_info("Serving from %.*s.", al_str_x(&addr));
- camu_server_init(&s.server, &s.loop);
+ camu_server_init(&s.server, &s.loop, false);
if (!camu_server_listen(&s.server, NNWT_SOCKET_TCP, &addr, CAMU_PORT)) {
return EXIT_FAILURE;
}
@@ -212,12 +242,14 @@ s32 main(s32 argc, char *argv[])
#endif
#ifdef CMSRV_USE_UI
- nn_poll_init(&s.input_poll, input_poll_callback, &s);
- nn_poll_set(&s.input_poll, cmsrv_ui_get_input_fd(&s.ui), NNWT_POLL_READ);
- nn_poll_start(&s.input_poll, &s.loop);
- nn_timer_init(&s.render_timer, &s.loop, render_timer_callback, &s);
- nn_timer_set_repeat(&s.render_timer, NNWT_TS_FROM_USEC(100000));
- nn_timer_again(&s.render_timer);
+ if (s.use_ui) {
+ nn_poll_init(&s.input_poll, input_poll_callback, &s);
+ nn_poll_set(&s.input_poll, cmsrv_ui_get_input_fd(&s.ui), NNWT_POLL_READ);
+ nn_poll_start(&s.input_poll, &s.loop);
+ nn_timer_init(&s.render_timer, &s.loop, render_timer_callback, &s);
+ nn_timer_set_repeat(&s.render_timer, NNWT_TS_FROM_USEC(100000));
+ nn_timer_again(&s.render_timer);
+ }
#endif
nn_event_loop_run(&s.loop);
@@ -226,7 +258,7 @@ s32 main(s32 argc, char *argv[])
nn_socket_close(&s.local.sock);
#endif
#ifdef CMSRV_USE_UI
- cmsrv_ui_close(&s.ui);
+ if (s.use_ui) cmsrv_ui_close(&s.ui);
#endif
camu_server_free(&s.server);
nn_event_loop_destroy(&s.loop);
diff --git a/src/fruits/cmv/cmv.c b/src/fruits/cmv/cmv.c
index 74e3555..333588e 100644
--- a/src/fruits/cmv/cmv.c
+++ b/src/fruits/cmv/cmv.c
@@ -18,7 +18,7 @@
#include "icon.h"
#endif
-#ifndef NAUNET_ON_WINDOWS
+#if !defined NAUNET_ON_WINDOWS && !defined NAUNET_ON_ANDROID
// https://unix.stackexchange.com/a/16884
#define PID_MAX_STR 7 // 0x400000 (2^22).
static str CMV_UNIX_PATH = al_str_c("/tmp/cmv_sock_");
@@ -45,6 +45,7 @@ static void exit_callback(void *userdata, struct camu_desktop *desktop)
static nn_thread_result NNWT_THREADCALL event_loop_thread(void *userdata)
{
+ nn_thread_set_priority(NNWT_THREAD_SCHED_FIFO, 40);
struct cmv *c = (struct cmv *)userdata;
nn_thread_set_name("event_loop");
nn_event_loop_run(&c->loop);
@@ -174,9 +175,16 @@ s32 window_system_main(u32 argc, str *argv, void *extra)
prefs->language.audio = CAMU_LANG_JAPANESE;
prefs->language.subtitles = CAMU_LANG_ENGLISH;
+#ifdef CAMU_DIRECT_MODE
+#ifdef CAMU_SINK_ONLY
+#error "Sink-only and DIRECT_MODE are incompatible"
+#endif
+ if (!local) al_assert("Cannot connect to a server in DIRECT_MODE" && false);
+#endif
+
#ifndef CAMU_SINK_ONLY
if (local) {
- camu_server_init(&c.server, &c.loop);
+ camu_server_init(&c.server, &c.loop, local);
#ifdef CAMU_DIRECT_MODE
camu_server_bind_direct(&c.server);
#else
@@ -212,8 +220,8 @@ s32 window_system_main(u32 argc, str *argv, void *extra)
c.desktop.userdata = &c;
}
char *SINK_FORCE_LOCAL = getenv("SINK_FORCE_LOCAL");
- if (SINK_FORCE_LOCAL && al_strscmp(SINK_FORCE_LOCAL, "1") == 0) {
- c.desktop.sink.local = true;
+ if (SINK_FORCE_LOCAL) {
+ c.desktop.sink.local = al_strscmp(SINK_FORCE_LOCAL, "1") == 0;
} else {
c.desktop.sink.local = local;
}
@@ -232,9 +240,9 @@ s32 window_system_main(u32 argc, str *argv, void *extra)
nn_packet_free(packet);
}
if (extra) {
- u32 start_index = *(u32 *)extra;
+ s32 start_index = *(s32 *)extra;
if (start_index != 0) {
- camu_server_local_set_index(&c.server, start_index);
+ camu_server_local_start_at(&c.server, start_index);
}
}
}
@@ -306,7 +314,7 @@ s32 main(s32 argc, char *argv[])
for (s32 i = 0; i < argc; i++) {
str arg;
#ifdef NAUNET_ON_WINDOWS
- if (!al_str_from_wstr(&arg, &al_wstr_cr(argv[i]))) { // This is so broken.
+ if (!al_str_from_wstr(&arg, &al_wstr_cr(argv[i]))) {
log_error("Failed to convert argument #%i from a wide string.", i);
continue;
}
diff --git a/src/fruits/cmv/create_icon.sh b/src/fruits/cmv/create_icon.sh
new file mode 100755
index 0000000..08aa8eb
--- /dev/null
+++ b/src/fruits/cmv/create_icon.sh
@@ -0,0 +1,4 @@
+#! /usr/bin/env sh
+for size in {16,32,64,128}; do
+ magick sink.png -resize $sizex$size -set filename:f "%[t]-%[w]x%[h]" "%[filename:f].png"
+done
diff --git a/src/fruits/cmv/meson.build b/src/fruits/cmv/meson.build
index 301fa58..a9eda61 100644
--- a/src/fruits/cmv/meson.build
+++ b/src/fruits/cmv/meson.build
@@ -21,10 +21,20 @@ elif is_windows
windows = import('windows')
cmv_src += [windows.compile_resources('icon.rc')]
if not is_msvc
+ cmv_args += ['-mwindows', '-municode']
cmv_link_args += ['-mwindows', '-municode', '-static', '-static-libgcc', '-static-libstdc++']
endif
endif
+install_data(join_paths(meson.source_root(), 'package/sink.desktop'), install_tag: 'xdg',
+ install_dir: join_paths(get_option('datadir'), 'applications'))
+
+foreach size: ['16x16', '32x32', '64x64', '128x128', '256x256']
+ icon_dir = join_paths(get_option('datadir'), 'icons', 'hicolor', size, 'apps')
+ install_data('sink-' + size + '.png', install_tag: 'xdg',
+ install_dir: icon_dir, rename: 'sink.png')
+endforeach
+
if is_android
cmv_args += ['-DAPPLICATION_NAME="CTV"']
shared_library('ctv', cmv_src, dependencies: cmv_deps, c_args: cmv_args, link_args: cmv_link_args)