summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/osc.rst16
-rw-r--r--player/lua/osc.lua152
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