diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index f5a5711b9df70..b44b452b94071 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -87,6 +87,8 @@ Interface changes - remove deprecated `--vf-defaults` and `--af-defaults` options - `--drm-connector` no longer allows selecting the card number (use `--drm-device` instead) + - add `--title-bar` option + - add `--window-corners` option --- mpv 0.36.0 --- - add `--target-contrast` - Target luminance value is now also applied when ICC profile is used. diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 2cae12e5f26ff..20ba4f8552685 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -3131,10 +3131,25 @@ Window Focus the video window on creation and makes it the front most window. This is on by default. +``--window-corners=`` + (Windows only) + Set the preference for window corner rounding. + + :default: Let the system decide whether or not to round window corners + :donotround: Never round window corners + :round: Round the corners if appropriate + :roundsmall: Round the corners if appropriate, with a small radius + ``--border``, ``--no-border`` Play video with window border and decorations. Since this is on by default, use ``--no-border`` to disable the standard window decorations. +``--title-bar``, ``--no-title-bar`` + (Windows only) + Play video with the window title bar. Since this is on by default, + use --no-title-bar to hide the title bar. The --no-border option takes + precedence. + ``--on-all-workspaces`` (X11 and macOS only) Show the video window on all virtual desktops. diff --git a/options/options.c b/options/options.c index c53183a6ecaae..40f1f6ff83f2d 100644 --- a/options/options.c +++ b/options/options.c @@ -32,6 +32,7 @@ #ifdef _WIN32 #include +#include #endif #include "options.h" @@ -114,6 +115,7 @@ static const m_option_t mp_vo_opt_list[] = { {"ontop-level", OPT_CHOICE(ontop_level, {"window", -1}, {"system", -2}, {"desktop", -3}), M_RANGE(0, INT_MAX)}, {"border", OPT_BOOL(border)}, + {"title-bar", OPT_BOOL(title_bar)}, {"on-all-workspaces", OPT_BOOL(all_workspaces)}, {"geometry", OPT_GEOMETRY(geometry)}, {"autofit", OPT_SIZE_BOX(autofit)}, @@ -189,6 +191,16 @@ static const m_option_t mp_vo_opt_list[] = { {"window-affinity", OPT_CHOICE(window_affinity, {"default", WDA_NONE}, {"excludefromcapture", WDA_EXCLUDEFROMCAPTURE}, {"monitor", WDA_MONITOR})}, {"vo-mmcss-profile", OPT_STRING(mmcss_profile)}, +// For old MinGW-w64 compatibility +#define DWMWCP_DEFAULT 0 +#define DWMWCP_DONOTROUND 1 +#define DWMWCP_ROUND 2 +#define DWMWCP_ROUNDSMALL 3 + {"window-corners", OPT_CHOICE(window_corners, + {"default", DWMWCP_DEFAULT}, + {"donotround", DWMWCP_DONOTROUND}, + {"round", DWMWCP_ROUND}, + {"roundsmall", DWMWCP_ROUNDSMALL})}, #endif #if HAVE_EGL_ANDROID {"android-surface-size", OPT_SIZE_BOX(android_surface_size)}, @@ -216,6 +228,7 @@ const struct m_sub_options vo_sub_opts = { .native_fs = true, .taskbar_progress = true, .border = true, + .title_bar = true, .appid = "mpv", .content_type = -1, .WinID = -1, diff --git a/options/options.h b/options/options.h index a272f46916692..339acda38c1a2 100644 --- a/options/options.h +++ b/options/options.h @@ -16,6 +16,7 @@ typedef struct mp_vo_opts { int ontop_level; bool fullscreen; bool border; + bool title_bar; bool all_workspaces; bool window_minimized; bool window_maximized; @@ -65,6 +66,7 @@ typedef struct mp_vo_opts { int window_affinity; char *mmcss_profile; + int window_corners; double override_display_fps; double timing_offset; diff --git a/video/out/w32_common.c b/video/out/w32_common.c index 4861d97cc00cc..b97d001791b78 100644 --- a/video/out/w32_common.c +++ b/video/out/w32_common.c @@ -58,6 +58,8 @@ EXTERN_C IMAGE_DOS_HEADER __ImageBase; #define DWMWA_USE_IMMERSIVE_DARK_MODE 20 #endif +#define DWMWA_WINDOW_CORNER_PREFERENCE 33 + #ifndef DPI_ENUMS_DECLARED typedef enum MONITOR_DPI_TYPE { MDT_EFFECTIVE_DPI = 0, @@ -167,7 +169,7 @@ struct vo_w32_state { HANDLE avrt_handle; }; -static void add_window_borders(struct vo_w32_state *w32, HWND hwnd, RECT *rc) +static void adjust_window_rect(struct vo_w32_state *w32, HWND hwnd, RECT *rc) { if (w32->api.pAdjustWindowRectExForDpi) { w32->api.pAdjustWindowRectExForDpi(rc, @@ -178,6 +180,15 @@ static void add_window_borders(struct vo_w32_state *w32, HWND hwnd, RECT *rc) } } +static void add_window_borders(struct vo_w32_state *w32, HWND hwnd, RECT *rc) +{ + RECT win = *rc; + adjust_window_rect(w32, hwnd, rc); + // Adjust for title bar height that will be hidden in WM_NCCALCSIZE + if (w32->opts->border && !w32->opts->title_bar && !w32->current_fs) + rc->top -= rc->top - win.top; +} + // basically a reverse AdjustWindowRect (win32 doesn't appear to have this) static void subtract_window_borders(struct vo_w32_state *w32, HWND hwnd, RECT *rc) { @@ -809,6 +820,13 @@ static DWORD update_style(struct vo_w32_state *w32, DWORD style) return style; } +static LONG get_title_bar_height(struct vo_w32_state *w32) +{ + RECT rc = {0}; + adjust_window_rect(w32, w32->window, &rc); + return -rc.top; +} + static void update_window_style(struct vo_w32_state *w32) { if (w32->parent) @@ -855,6 +873,18 @@ static void fit_window_on_screen(struct vo_w32_state *w32) if (w32->opts->border) subtract_window_borders(w32, w32->window, &screen); + // Check for invisible borders and adjust the work area size + RECT frame, window; + if (GetWindowRect(w32->window, &window) && + SUCCEEDED(DwmGetWindowAttribute(w32->window, DWMWA_EXTENDED_FRAME_BOUNDS, + &frame, sizeof(RECT)))) + { + screen.left -= frame.left - window.left; + screen.top -= frame.top - window.top; + screen.right += window.right - frame.right; + screen.bottom += window.bottom - frame.bottom; + } + bool adjusted = fit_rect_size(&w32->windowrc, rect_w(screen), rect_h(screen)); if (w32->windowrc.top < screen.top) { @@ -1007,6 +1037,15 @@ static void update_window_state(struct vo_w32_state *w32) signal_events(w32, VO_EVENT_RESIZE); } +static void update_corners_pref(const struct vo_w32_state *w32) { + if (w32->parent) + return; + + int pref = w32->current_fs ? 0 : w32->opts->window_corners; + DwmSetWindowAttribute(w32->window, DWMWA_WINDOW_CORNER_PREFERENCE, + &pref, sizeof(pref)); +} + static void reinit_window_state(struct vo_w32_state *w32) { if (w32->parent) @@ -1014,6 +1053,7 @@ static void reinit_window_state(struct vo_w32_state *w32) // The order matters: fs state should be updated prior to changing styles update_fullscreen_state(w32); + update_corners_pref(w32); update_window_style(w32); // fit_on_screen is applied at most once when/if applicable (normal win). @@ -1230,7 +1270,7 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, break; case WM_NCHITTEST: // Provide sizing handles for borderless windows - if (!w32->opts->border && !w32->current_fs) { + if ((!w32->opts->border || !w32->opts->title_bar) && !w32->current_fs) { return borderless_nchittest(w32, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); } @@ -1351,6 +1391,15 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, case WM_SETTINGCHANGE: update_dark_mode(w32); break; + case WM_NCCALCSIZE: + // Apparently removing WS_CAPTION disables some window animation, instead + // just reduce non-client size to remove title bar. + if (wParam && lParam && w32->opts->border && !w32->opts->title_bar && + !w32->current_fs && !w32->parent) + { + ((LPNCCALCSIZE_PARAMS) lParam)->rgrc[0].top -= get_title_bar_height(w32); + } + break; } if (message == w32->tbtnCreatedMsg) { @@ -1622,6 +1671,7 @@ static void *gui_thread(void *ptr) } update_dark_mode(w32); + update_corners_pref(w32); if (w32->opts->window_affinity) update_affinity(w32); @@ -1802,13 +1852,17 @@ static int gui_thread_control(struct vo_w32_state *w32, int request, void *arg) update_affinity(w32); } else if (changed_option == &vo_opts->ontop) { update_window_state(w32); - } else if (changed_option == &vo_opts->border) { + } else if (changed_option == &vo_opts->border || + changed_option == &vo_opts->title_bar) + { update_window_style(w32); update_window_state(w32); } else if (changed_option == &vo_opts->window_minimized) { update_minimized_state(w32); } else if (changed_option == &vo_opts->window_maximized) { update_maximized_state(w32); + } else if (changed_option == &vo_opts->window_corners) { + update_corners_pref(w32); } }