diff options
-rw-r--r-- | DOCS/man/osc.rst | 16 | ||||
-rw-r--r-- | player/lua/osc.lua | 152 |
2 files changed, 161 insertions, 7 deletions
diff --git a/DOCS/man/osc.rst b/DOCS/man/osc.rst index d9c3b3fe96..c0b3760a2e 100644 --- a/DOCS/man/osc.rst +++ b/DOCS/man/osc.rst @@ -341,6 +341,22 @@ Configurable Options ``--sub-use-margins`` option is set to ``yes``, the default). This may be fixed later. +``windowcontrols`` + Default: no (Do not show window controls) + + Whether to show window management controls over the video, and if so, + which side of the window to place them. This may be desirable when the + window has no decorations, either because they have been explicitly + disabled (``border=no``) or because the current platform doesn't support + them (eg: gnome-shell with wayland). + + The set of window controls is fixed, offering ``minimze``, ``maximize``, + and ``quit``. Not all platforms implement ``minimize`` and ``maximize``, + but ``quit`` will always work. + + Supports ``left`` and ``right`` which will place the controls on those + respective sides. + Script Commands ~~~~~~~~~~~~~~~ diff --git a/player/lua/osc.lua b/player/lua/osc.lua index 35abf20ae2..46819858a5 100644 --- a/player/lua/osc.lua +++ b/player/lua/osc.lua @@ -45,6 +45,7 @@ local user_opts = { visibility = "auto", -- only used at init to set visibility_mode(...) boxmaxchars = 80, -- title crop threshold for box layout boxvideo = false, -- apply osc_param.video_margins to video + windowcontrols = "no", -- where to show window controls (or not at all) } -- read_options may modify hidetimeout, so save the original default value in @@ -85,6 +86,9 @@ local osc_styles = { timecodesBar = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs27}", timePosBar = "{\\blur0\\bord".. user_opts.tooltipborder .."\\1c&HFFFFFF\\3c&H000000\\fs30}", vidtitleBar = "{\\blur0\\bord0\\1c&HFFFFFF\\3c&HFFFFFF\\fs18\\q2}", + + wcButtons = "{\\1c&HFFFFFF\\fs24\\fnmpv-osd-symbols}", + wcBar = "{\\1c&H000000}", } -- internal states, do not touch @@ -115,7 +119,7 @@ local state = { using_video_margins = false, } - +local window_control_box_width = 80 -- @@ -961,6 +965,104 @@ function add_layout(name) end end +-- Window Controls +function window_controls(alignment, topbar) + local wc_geo = { + x = 0, + y = 30, + an = 1, + w = osc_param.playresx, + h = 30, + } + + local controlbox_w = window_control_box_width + local titlebox_w = wc_geo.w - controlbox_w + + -- Default alignment is "right" + local controlbox_left = wc_geo.w - controlbox_w + local titlebox_left = wc_geo.x + 5 + + if alignment == "left" then + controlbox_left = wc_geo.x + titlebox_left = wc_geo.x + controlbox_w + 5 + elseif alignment == "right" then + -- Already default + else + msg.error("Invalid setting \""..alignment.."\" for windowcontrols") + -- Falls back to "right" + end + + add_area("window-controls", + get_hitbox_coords(controlbox_left, wc_geo.y, wc_geo.an, + controlbox_w, wc_geo.h)) + + local lo + + -- Background Bar + new_element("wcbar", "box") + lo = add_layout("wcbar") + lo.geometry = wc_geo + lo.layer = 10 + lo.style = osc_styles.wcBar + lo.alpha[1] = user_opts.boxalpha + + local first_geo = + {x = controlbox_left + 5, y = 15, an = 4, w = 25, h = 25} + local second_geo = + {x = controlbox_left + 30, y = 15, an = 4, w = 25, h = 25} + local third_geo = + {x = controlbox_left + 55, y = 15, an = 4, w = 25, h = 25} + + -- Close + ne = new_element("close", "button") + ne.content = "\226\152\146" + ne.eventresponder["mbtn_left_up"] = + function () mp.commandv("quit") end + lo = add_layout("close") + lo.geometry = alignment == "left" and first_geo or third_geo + lo.style = osc_styles.wcButtons + + -- Minimize + ne = new_element("minimize", "button") + ne.content = "\226\154\128" + ne.eventresponder["mbtn_left_up"] = + function () mp.commandv("cycle", "window-minimized") end + lo = add_layout("minimize") + lo.geometry = alignment == "left" and second_geo or first_geo + lo.style = osc_styles.wcButtons + + -- Maximize + ne = new_element("maximize", "button") + ne.content = "\226\150\163" + ne.eventresponder["mbtn_left_up"] = + function () mp.commandv("cycle", "window-maximized") end + lo = add_layout("maximize") + lo.geometry = alignment == "left" and third_geo or second_geo + -- At least with default Ubuntu fonts, this symbol is differently aligned + lo.geometry.y = 13 + lo.style = osc_styles.wcButtons + + if topbar then + -- The title is already there as part of the top bar + return + end + + -- Window Title + ne = new_element("wctitle", "button") + ne.content = function () + local title = mp.command_native({"expand-text", user_opts.title}) + -- escape ASS, and strip newlines and trailing slashes + title = title:gsub("\\n", " "):gsub("\\$", ""):gsub("{","\\{") + return not (title == "") and title or "mpv" + end + lo = add_layout("wctitle") + lo.geometry = + { x = titlebox_left, y = wc_geo.y - 3, an = 1, w = titlebox_w, h = wc_geo.h } + lo.style = string.format("%s{\\clip(%f,%f,%f,%f)}", + osc_styles.wcButtons, + titlebox_left, wc_geo.y - wc_geo.h, titlebox_w, wc_geo.y + wc_geo.h) +end + -- -- Layouts -- @@ -1252,7 +1354,7 @@ layouts["slimbox"] = function () end -function bar_layout(direction) +function bar_layout(direction, windowcontrols) local osc_geo = { x = -2, y, @@ -1268,6 +1370,20 @@ function bar_layout(direction) local tsW = 90 local minW = (buttonW + padX)*5 + (tcW + padX)*4 + (tsW + padX)*2 + -- Special topbar handling when window controls are present + local padwc_l + local padwc_r + if direction < 0 or windowcontrols == "no" then + padwc_l = 0 + padwc_r = 0 + elseif windowcontrols == "left" then + padwc_l = window_control_box_width + padwc_r = 0 + else + padwc_l = 0 + padwc_r = window_control_box_width + end + if ((osc_param.display_aspect > 0) and (osc_param.playresx < minW)) then osc_param.playresy = minW / osc_param.display_aspect osc_param.playresx = osc_param.playresy * osc_param.display_aspect @@ -1348,7 +1464,7 @@ function bar_layout(direction) -- Playback control buttons - geo = { x = osc_geo.x + padX, y = line2, an = 4, + geo = { x = osc_geo.x + padX + padwc_l, y = line2, an = 4, w = buttonW, h = 36 - padY*2} lo = add_layout("playpause") lo.geometry = geo @@ -1374,7 +1490,7 @@ function bar_layout(direction) local sb_l = geo.x + padX -- Fullscreen button - geo = { x = osc_geo.x + osc_geo.w - buttonW - padX, y = geo.y, an = 4, + geo = { x = osc_geo.x + osc_geo.w - buttonW - padX - padwc_r, y = geo.y, an = 4, w = buttonW, h = geo.h } lo = add_layout("tog_fs") lo.geometry = geo @@ -1442,11 +1558,11 @@ function bar_layout(direction) end layouts["bottombar"] = function() - bar_layout(-1) + bar_layout(-1, false) end layouts["topbar"] = function() - bar_layout(1) + bar_layout(1, user_opts.windowcontrols) end -- Validate string type user options @@ -1704,7 +1820,6 @@ function osc_init() ne.eventresponder["mbtn_left_up"] = function () mp.commandv("cycle", "fullscreen") end - --seekbar ne = new_element("seekbar", "slider") @@ -1863,6 +1978,12 @@ function osc_init() -- load layout layouts[user_opts.layout]() + -- load window controls + if user_opts.windowcontrols ~= "no" then + window_controls(user_opts.windowcontrols, + user_opts.layout == "topbar") + end + --do something with the elements prepare_elements() @@ -2103,6 +2224,18 @@ function render() end end + if user_opts.windowcontrols ~= "no" then + for _,cords in ipairs(osc_param.areas["window-controls"]) do + if state.osc_visible then -- activate only when OSC is actually visible + set_virt_mouse_area(cords.x1, cords.y1, cords.x2, cords.y2, "window-controls") + end + + if (mouse_hit_coords(cords.x1, cords.y1, cords.x2, cords.y2)) then + mouse_over_osc = true + end + end + end + -- autohide if not (state.showtime == nil) and (user_opts.hidetimeout >= 0) and (state.showtime + (user_opts.hidetimeout/1000) < now) @@ -2353,6 +2486,11 @@ mp.set_key_bindings({ }, "input", "force") mp.enable_key_bindings("input") +mp.set_key_bindings({ + {"mbtn_left", function(e) process_event("mbtn_left", "up") end, + function(e) process_event("mbtn_left", "down") end}, +}, "window-controls", "force") +mp.enable_key_bindings("window-controls") user_opts.hidetimeout_orig = user_opts.hidetimeout |