diff options
-rw-r--r-- | DOCS/man/en/options.rst | 5 | ||||
-rw-r--r-- | common/msg.c | 92 | ||||
-rw-r--r-- | common/msg.h | 2 | ||||
-rw-r--r-- | options/options.c | 2 | ||||
-rw-r--r-- | options/options.h | 1 | ||||
-rw-r--r-- | osdep/terminal-unix.c | 15 | ||||
-rw-r--r-- | osdep/terminal-win.c | 5 | ||||
-rw-r--r-- | osdep/terminal.h | 4 | ||||
-rw-r--r-- | player/command.c | 2 | ||||
-rw-r--r-- | player/core.h | 5 | ||||
-rw-r--r-- | player/main.c | 2 | ||||
-rw-r--r-- | player/misc.c | 6 | ||||
-rw-r--r-- | player/osd.c | 104 | ||||
-rw-r--r-- | player/playloop.c | 6 |
14 files changed, 159 insertions, 92 deletions
diff --git a/DOCS/man/en/options.rst b/DOCS/man/en/options.rst index 27aa56a7f0..ad5eabd232 100644 --- a/DOCS/man/en/options.rst +++ b/DOCS/man/en/options.rst @@ -2378,11 +2378,6 @@ OPTIONS Display OSD messages on the console when no video output is available. Enabled by default. -``--term-osd-esc=<string>`` - Specify the escape sequence to use before writing an OSD message on the - console. The escape sequence should move the pointer to the beginning of - the line used for the OSD and clear it (default: ``^[[A\r^[[K``). - ``--title=<string>`` Set the window title. Properties are expanded on playback start. (See `Property Expansion`_.) diff --git a/common/msg.c b/common/msg.c index 841fab30c7..2cd2e19b27 100644 --- a/common/msg.c +++ b/common/msg.c @@ -43,8 +43,12 @@ struct mp_log_root { struct mpv_global *global; // --- protected by mp_msg_lock char *msglevels; - bool smode; // slave mode compatibility glue + bool smode; // slave mode compatibility glue bool module; + bool termosd; // use terminal control codes for status line + bool header; // indicate that message header should be printed + int blank_lines; // number of lines useable by status + int status_lines; // number of current status lines // --- semi-atomic access bool color; int verbose; @@ -55,8 +59,6 @@ struct mp_log_root { * (This is perhaps better than maintaining a globally accessible and * synchronized mp_log tree.) */ int64_t reload_counter; - int header; // indicate if last line printed ended with \n or \r - int statusline; // indicates if last line printed was a status line }; struct mp_log { @@ -117,6 +119,61 @@ bool mp_msg_test(struct mp_log *log, int lev) return lev <= log->level || (log->root->smode && lev == MSGL_SMODE); } +// Reposition cursor and clear lines for outputting the status line. In certain +// cases, like term OSD and subtitle display, the status can consist of +// multiple lines. +static void prepare_status_line(struct mp_log_root *root, char *new_status) +{ + FILE *f = stderr; + size_t old_lines = root->blank_lines; + + size_t new_lines = 1; + char *tmp = new_status; + while (1) { + tmp = strchr(tmp, '\n'); + if (!tmp) + break; + new_lines++; + tmp++; + } + + // clear the status line itself + fprintf(f, "\r%s", terminal_erase_to_end_of_line); + // and clear all previous old lines + for (size_t n = 1; n < old_lines; n++) + fprintf(f, "%s\r%s", terminal_cursor_up, terminal_erase_to_end_of_line); + // skip "unused" blank lines, so that status is aligned to term bottom + for (size_t n = new_lines; n < old_lines; n++) + fprintf(f, "\n"); + + root->status_lines = new_lines; + root->blank_lines = MPMAX(root->blank_lines, new_lines); +} + +static void flush_status_line(struct mp_log_root *root) +{ + // If there was a status line, don't overwrite it, but skip it. + if (root->status_lines) + fprintf(stderr, "\n"); + root->status_lines = 0; + root->blank_lines = 0; +} + +void mp_msg_flush_status_line(struct mpv_global *global) +{ + pthread_mutex_lock(&mp_msg_lock); + flush_status_line(global->log->root); + pthread_mutex_unlock(&mp_msg_lock); +} + +bool mp_msg_has_status_line(struct mpv_global *global) +{ + pthread_mutex_lock(&mp_msg_lock); + bool r = global->log->root->status_lines > 0; + pthread_mutex_unlock(&mp_msg_lock); + return r; +} + static void set_msg_color(FILE* stream, int lev) { static const int v_colors[] = {9, 1, 3, -1, -1, 2, 8, 8, -1}; @@ -139,12 +196,21 @@ void mp_msg_va(struct mp_log *log, int lev, const char *format, va_list va) tmp[MSGSIZE_MAX - 2] = '\n'; tmp[MSGSIZE_MAX - 1] = 0; - /* A status line is normally intended to be overwritten by the next - * status line, and does not end with a '\n'. If we're printing a normal - * line instead after the status one print '\n' to change line. */ - if (root->statusline && lev != MSGL_STATUS) - fprintf(stderr, "\n"); - root->statusline = lev == MSGL_STATUS; + char *terminate = ""; + + if (lev == MSGL_STATUS) { + if (root->termosd) { + prepare_status_line(root, tmp); + terminate = "\r"; + } else { + terminate = "\n"; + } + root->header = true; + } else { + flush_status_line(root); + size_t len = strlen(tmp); + root->header = len && tmp[len - 1] == '\n'; + } if (root->color) set_msg_color(stream, lev); @@ -156,10 +222,7 @@ void mp_msg_va(struct mp_log *log, int lev, const char *format, va_list va) } } - size_t len = strlen(tmp); - root->header = len && (tmp[len - 1] == '\n' || tmp[len - 1] == '\r'); - - fprintf(stream, "%s", tmp); + fprintf(stream, "%s%s", tmp, terminate); if (root->color) terminal_set_foreground_color(stream, -1); @@ -211,7 +274,7 @@ void mp_msg_init(struct mpv_global *global) struct mp_log_root *root = talloc_zero(NULL, struct mp_log_root); root->global = global; - root->header = 1; + root->header = true; root->reload_counter = 1; struct mp_log dummy = { .root = root }; @@ -236,6 +299,7 @@ void mp_msg_update_msglevels(struct mpv_global *global) root->module = opts->msg_module; root->smode = opts->msg_identify; root->color = opts->msg_color && isatty(fileno(stdout)); + root->termosd = !opts->slave_mode && isatty(fileno(stdout)); talloc_free(root->msglevels); root->msglevels = talloc_strdup(root, global->opts->msglevels); diff --git a/common/msg.h b/common/msg.h index 561efe5e53..50420c9044 100644 --- a/common/msg.h +++ b/common/msg.h @@ -82,6 +82,8 @@ void mp_msg_uninit(struct mpv_global *global); void mp_msg_update_msglevels(struct mpv_global *global); void mp_msg_mute(struct mpv_global *global, bool mute); void mp_msg_force_stderr(struct mpv_global *global, bool force_stderr); +void mp_msg_flush_status_line(struct mpv_global *global); +bool mp_msg_has_status_line(struct mpv_global *global); struct bstr; int mp_msg_split_msglevel(struct bstr *s, struct bstr *out_mod, int *out_level); diff --git a/options/options.c b/options/options.c index 1fa6a68cfe..dbc06bdf7f 100644 --- a/options/options.c +++ b/options/options.c @@ -597,8 +597,6 @@ const m_option_t mp_opts[] = { {"auto", 2}, {"no", 0})), - OPT_STRING("term-osd-esc", term_osd_esc, M_OPT_PARSE_ESCAPES, - OPTDEF_STR("\x1b[A\r\x1b[K")), OPT_STRING("playing-msg", playing_msg, M_OPT_PARSE_ESCAPES), OPT_STRING("status-msg", status_msg, M_OPT_PARSE_ESCAPES), OPT_STRING("osd-status-msg", osd_status_msg, M_OPT_PARSE_ESCAPES), diff --git a/options/options.h b/options/options.h index 6b5e1c7392..5608392a99 100644 --- a/options/options.h +++ b/options/options.h @@ -124,7 +124,6 @@ typedef struct MPOpts { int softsleep; int frame_dropping; int term_osd; - char *term_osd_esc; char *playing_msg; char *status_msg; char *osd_status_msg; diff --git a/osdep/terminal-unix.c b/osdep/terminal-unix.c index 193cd8557f..de7087b9b8 100644 --- a/osdep/terminal-unix.c +++ b/osdep/terminal-unix.c @@ -56,7 +56,8 @@ static volatile int tio_orig_set; int screen_width = 80; int screen_height = 24; -char * erase_to_end_of_line = NULL; +char *terminal_erase_to_end_of_line = "\033[A"; +char *terminal_cursor_up = "\033[K"; typedef struct { char *cap; @@ -267,10 +268,16 @@ static int load_termcap(char *termtype){ #endif ensure_cap(&termcap_buf, 2048); - static char term_buf[64]; + static char term_buf[128]; char *buf_ptr = &term_buf[0]; - - erase_to_end_of_line = tgetstr("ce", &buf_ptr); + char *tmp; + + tmp = tgetstr("ce", &buf_ptr); + if (tmp) + terminal_erase_to_end_of_line = tmp; + tmp = tgetstr("ku", &buf_ptr); + if (tmp) + terminal_cursor_up = tmp; screen_width = tgetnum("co"); screen_height = tgetnum("li"); diff --git a/osdep/terminal-win.c b/osdep/terminal-win.c index 5186c301f2..1ecb520f94 100644 --- a/osdep/terminal-win.c +++ b/osdep/terminal-win.c @@ -33,9 +33,10 @@ #include "input/input.h" #include "terminal.h" -int screen_width = 80; +int screen_width = 79; int screen_height = 24; -char *erase_to_end_of_line = NULL; +char *terminal_erase_to_end_of_line = ""; +char *terminal_cursor_up = ""; #define hSTDOUT GetStdHandle(STD_OUTPUT_HANDLE) #define hSTDERR GetStdHandle(STD_ERROR_HANDLE) diff --git a/osdep/terminal.h b/osdep/terminal.h index c524adbc2b..651e31ed71 100644 --- a/osdep/terminal.h +++ b/osdep/terminal.h @@ -33,8 +33,8 @@ struct input_ctx; extern int screen_width; extern int screen_height; -/* Termcap code to erase to end of line */ -extern char * erase_to_end_of_line; +extern char *terminal_erase_to_end_of_line; +extern char *terminal_cursor_up; /* Global initialization for terminal output. */ int terminal_init(void); diff --git a/player/command.c b/player/command.c index f6f3e43a63..6ee50dea87 100644 --- a/player/command.c +++ b/player/command.c @@ -3058,7 +3058,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd) case MP_CMD_RUN: { #ifndef __MINGW32__ - mp_msg(mpctx->statusline, MSGL_STATUS, "\n"); + mp_msg_flush_status_line(mpctx->global); char *args[MP_CMD_MAX_ARGS + 1] = {0}; for (int n = 0; n < cmd->nargs; n++) args[n] = cmd->args[n].v.s; diff --git a/player/core.h b/player/core.h index 3285e4848d..271f96595b 100644 --- a/player/core.h +++ b/player/core.h @@ -160,7 +160,9 @@ typedef struct MPContext { struct input_ctx *input; struct osd_state *osd; struct mp_osd_msg *osd_msg_stack; - char *terminal_osd_text; + char *term_osd_text; + char *term_osd_status; + char *term_osd_contents; char *last_window_title; int add_osd_seek_info; // bitfield of enum mp_osd_seek_info @@ -408,7 +410,6 @@ void update_window_title(struct MPContext *mpctx, bool force); void stream_dump(struct MPContext *mpctx); // osd.c -void write_status_line(struct MPContext *mpctx, const char *line); void print_status(struct MPContext *mpctx); void set_osd_bar(struct MPContext *mpctx, int type, const char* name, double min, double max, double val); diff --git a/player/main.c b/player/main.c index afb3db46ea..ff9f7b732a 100644 --- a/player/main.c +++ b/player/main.c @@ -287,7 +287,7 @@ static int mpv_main(int argc, char *argv[]) struct MPContext *mpctx = talloc(NULL, MPContext); *mpctx = (struct MPContext){ .last_dvb_step = 1, - .terminal_osd_text = talloc_strdup(mpctx, ""), + .term_osd_contents = talloc_strdup(mpctx, ""), .playlist = talloc_struct(mpctx, struct playlist, {0}), }; diff --git a/player/misc.c b/player/misc.c index eb8c0c147e..700def3ae4 100644 --- a/player/misc.c +++ b/player/misc.c @@ -170,10 +170,8 @@ void stream_dump(struct MPContext *mpctx) if (!opts->quiet && ((stream->pos / (1024 * 1024)) % 2) == 1) { uint64_t pos = stream->pos - stream->start_pos; uint64_t end = stream->end_pos - stream->start_pos; - char *line = talloc_asprintf(NULL, "Dumping %lld/%lld...", - (long long int)pos, (long long int)end); - write_status_line(mpctx, line); - talloc_free(line); + MP_MSG(mpctx, MSGL_STATUS, "Dumping %lld/%lld...", + (long long int)pos, (long long int)end); } stream_fill_buffer(stream); for (;;) { diff --git a/player/osd.c b/player/osd.c index 93340d78c2..7999847720 100644 --- a/player/osd.c +++ b/player/osd.c @@ -56,44 +56,67 @@ static void sadd_percentage(char **buf, int percent) { *buf = talloc_asprintf_append(*buf, " (%d%%)", percent); } -static int get_term_width(void) +static char *join_lines(void *ta_ctx, char **parts, int num_parts) { - get_screen_size(); - int width = screen_width > 0 ? screen_width : 80; -#if defined(__MINGW32__) || defined(__CYGWIN__) - /* Windows command line is broken (MinGW's rxvt works, but we - * should not depend on that). */ - width--; -#endif - return width; + char *res = talloc_strdup(ta_ctx, ""); + for (int n = 0; n < num_parts; n++) + res = talloc_asprintf_append(res, "%s%s", n ? "\n" : "", parts[n]); + return res; } -void write_status_line(struct MPContext *mpctx, const char *line) +static void term_osd_update(struct MPContext *mpctx) { - struct MPOpts *opts = mpctx->opts; - if (opts->slave_mode) { - mp_msg(mpctx->statusline, MSGL_STATUS, "%s\n", line); - } else if (erase_to_end_of_line) { - mp_msg(mpctx->statusline, MSGL_STATUS, "%s%s\r", line, erase_to_end_of_line); + int num_parts = 0; + char *parts[2] = {0}; + + if (mpctx->term_osd_text && mpctx->term_osd_text[0]) + parts[num_parts++] = mpctx->term_osd_text; + if (mpctx->term_osd_status && mpctx->term_osd_status[0]) + parts[num_parts++] = mpctx->term_osd_status; + + char *s = join_lines(mpctx, parts, num_parts); + + if (strcmp(mpctx->term_osd_contents, s) == 0 && + mp_msg_has_status_line(mpctx->global)) + { + talloc_free(s); } else { - int pos = strlen(line); - int width = get_term_width() - pos; - mp_msg(mpctx->statusline, MSGL_STATUS, "%s%*s\r", line, width, ""); + talloc_free(mpctx->term_osd_contents); + mpctx->term_osd_contents = s; + mp_msg(mpctx->statusline, MSGL_STATUS, "%s", s); } } +static void term_osd_set_text(struct MPContext *mpctx, const char *text) +{ + if (mpctx->video_out && mpctx->opts->term_osd != 1) + text = ""; // disable + talloc_free(mpctx->term_osd_text); + mpctx->term_osd_text = talloc_strdup(mpctx, text); + term_osd_update(mpctx); +} + +static void term_osd_set_status(struct MPContext *mpctx, const char *text) +{ + talloc_free(mpctx->term_osd_status); + mpctx->term_osd_status = talloc_strdup(mpctx, text); + term_osd_update(mpctx); +} + void print_status(struct MPContext *mpctx) { struct MPOpts *opts = mpctx->opts; update_window_title(mpctx, false); - if (opts->quiet) + if (opts->quiet) { + term_osd_set_status(mpctx, ""); return; + } if (opts->status_msg) { char *r = mp_property_expand_string(mpctx, opts->status_msg); - write_status_line(mpctx, r); + term_osd_set_status(mpctx, r); talloc_free(r); return; } @@ -160,7 +183,7 @@ void print_status(struct MPContext *mpctx) saddf(&line, " Cache: %d%%", cache); // end - write_status_line(mpctx, line); + term_osd_set_status(mpctx, line); talloc_free(line); } @@ -477,22 +500,13 @@ void update_osd_msg(struct MPContext *mpctx) double pos = get_current_pos_ratio(mpctx, false); update_osd_bar(mpctx, OSD_BAR_SEEK, 0, 1, MPCLAMP(pos, 0, 1)); + print_status(mpctx); + // Look if we have a msg mp_osd_msg_t *msg = get_osd_msg(mpctx); if (msg && !msg->show_position) { - if (mpctx->video_out && opts->term_osd != 1) { - osd_set_text(osd, msg->msg); - } else if (opts->term_osd) { - if (strcmp(mpctx->terminal_osd_text, msg->msg)) { - talloc_free(mpctx->terminal_osd_text); - mpctx->terminal_osd_text = talloc_strdup(mpctx, msg->msg); - // Multi-line message => clear what will be the second line - write_status_line(mpctx, ""); - mp_msg(mpctx->statusline, MSGL_STATUS, - "%s%s\n", opts->term_osd_esc, mpctx->terminal_osd_text); - print_status(mpctx); - } - } + osd_set_text(osd, msg->msg); + term_osd_set_text(mpctx, msg->msg); return; } @@ -500,21 +514,15 @@ void update_osd_msg(struct MPContext *mpctx) if (msg && msg->show_position) osd_level = 3; - if (mpctx->video_out && opts->term_osd != 1) { - // fallback on the timer - char *text = NULL; + // clear, or if OSD level demands it, show the status + char *text = NULL; - if (osd_level >= 2) - sadd_osd_status(&text, mpctx, osd_level == 3); + if (osd_level >= 2) + sadd_osd_status(&text, mpctx, osd_level == 3); - osd_set_text(osd, text); - talloc_free(text); - return; - } + osd_set_text(osd, text); + talloc_free(text); - // Clear the term osd line - if (opts->term_osd && mpctx->terminal_osd_text[0]) { - mpctx->terminal_osd_text[0] = '\0'; - mp_msg(mpctx->statusline, MSGL_STATUS, "%s\n", opts->term_osd_esc); - } + // always clear (term-osd has separate status line) + term_osd_set_text(mpctx, ""); } diff --git a/player/playloop.c b/player/playloop.c index c61ba419b0..95e9a9c5a4 100644 --- a/player/playloop.c +++ b/player/playloop.c @@ -1164,7 +1164,6 @@ void run_playloop(struct MPContext *mpctx) get_relative_time(mpctx); } update_avsync(mpctx); - print_status(mpctx); screenshot_flip(mpctx); new_frame_shown = true; @@ -1188,10 +1187,6 @@ void run_playloop(struct MPContext *mpctx) update_osd_msg(mpctx); - // The cache status is part of the status line. Possibly update it. - if (mpctx->paused && mp_get_cache_percent(mpctx) >= 0) - print_status(mpctx); - if (!video_left && (!mpctx->paused || was_restart)) { double a_pos = 0; if (mpctx->d_audio) { @@ -1199,7 +1194,6 @@ void run_playloop(struct MPContext *mpctx) mpctx->opts->playback_speed * buffered_audio); } mpctx->playback_pts = a_pos; - print_status(mpctx); } update_subtitles(mpctx); |