summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/en/options.rst5
-rw-r--r--common/msg.c92
-rw-r--r--common/msg.h2
-rw-r--r--options/options.c2
-rw-r--r--options/options.h1
-rw-r--r--osdep/terminal-unix.c15
-rw-r--r--osdep/terminal-win.c5
-rw-r--r--osdep/terminal.h4
-rw-r--r--player/command.c2
-rw-r--r--player/core.h5
-rw-r--r--player/main.c2
-rw-r--r--player/misc.c6
-rw-r--r--player/osd.c104
-rw-r--r--player/playloop.c6
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);