Skip to content

Commit 28e4ffb

Browse files
committed
vo: add win32 context menu support
1 parent 474e213 commit 28e4ffb

File tree

9 files changed

+356
-1
lines changed

9 files changed

+356
-1
lines changed

DOCS/interface-changes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ Interface changes
2727
::
2828

2929
--- mpv 0.38.0 ---
30+
- add `show-menu` command
31+
- add `menu-data` property
3032
- add `begin-vo-dragging` command
3133
- add `--deinterlace-field-parity` option
3234
- add `--volume-gain`, `--volume-gain-min`, and `--volume-gain-max` options

DOCS/man/input.rst

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -927,6 +927,9 @@ Remember to quote string arguments in input.conf (see `Flat command syntax`_).
927927
<keep-selection>
928928
Do not change current track selections.
929929

930+
``show-menu``
931+
Show context menu on video window, see `Context Menu`_ section.
932+
930933

931934
Input Commands that are Possibly Subject to Change
932935
--------------------------------------------------
@@ -3424,6 +3427,41 @@ Property list
34243427
and not using raw mode, the underlying content will be given (e.g. strings will be
34253428
printed directly, rather than quoted and JSON-escaped).
34263429

3430+
``menu-data`` (RW)
3431+
This property stores the raw menu definition, see `Context Menu`_ section.
3432+
3433+
``type``
3434+
Menu item type, can be: ``separator``, ``submenu``, or empty.
3435+
3436+
``title``
3437+
Menu item title, required if type is not ``separator``.
3438+
3439+
``cmd``
3440+
Command to execute when the menu item is clicked.
3441+
3442+
``state``
3443+
Menu item state, can be: ``checked``, ``disabled``, ``hidden``, or empty.
3444+
3445+
``submenu``
3446+
Submenu items, required if type is ``submenu``.
3447+
3448+
When querying the property with the client API using ``MPV_FORMAT_NODE``, or with
3449+
Lua ``mp.get_property_native``, this will return a mpv_node with the following
3450+
contents:
3451+
3452+
::
3453+
3454+
MPV_FORMAT_NODE_ARRAY
3455+
MPV_FORMAT_NODE_MAP (menu item)
3456+
"type" MPV_FORMAT_STRING
3457+
"title" MPV_FORMAT_STRING
3458+
"cmd" MPV_FORMAT_STRING
3459+
"state" MPV_FORMAT_NODE_ARRAY[MPV_FORMAT_STRING]
3460+
"submenu" MPV_FORMAT_NODE_ARRAY[menu item]
3461+
3462+
Writing to this property with the client API using ``MPV_FORMAT_NODE`` or with
3463+
Lua ``mp.set_property_native`` will trigger an immediate update of the menu.
3464+
34273465
``working-directory``
34283466
The working directory of the mpv process. Can be useful for JSON IPC users,
34293467
because the command line player usually works with relative paths.

DOCS/man/mpv.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,21 @@ Wheel left/right
307307
Ctrl+Wheel up/down
308308
Change video zoom.
309309

310+
Context Menu
311+
-------------
312+
313+
.. warning::
314+
315+
This feature is experimental. It may not work with all VOs, a libass based
316+
fallback may be implemented in the future.
317+
318+
Context Menu is a menu that pops up on the video window on user interaction
319+
(mouse right click, etc.).
320+
321+
To use this feature, you need to fill the ``menu-data`` property with menu
322+
definition data, and add a keybinding to run the ``show-menu`` command, this
323+
can be done with a user script.
324+
310325
USAGE
311326
=====
312327

meson.build

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,8 @@ if features['win32-desktop']
505505
'osdep/terminal-win.c',
506506
'video/out/w32_common.c',
507507
'video/out/win32/displayconfig.c',
508-
'video/out/win32/droptarget.c')
508+
'video/out/win32/droptarget.c',
509+
'video/out/win32/menu.c')
509510
main_fn_source = files('osdep/main-fn-win.c')
510511
endif
511512

player/command.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ struct command_ctx {
111111

112112
char **script_props;
113113
mpv_node udata;
114+
mpv_node mdata;
114115

115116
double cached_window_scale;
116117
};
@@ -123,6 +124,10 @@ static const struct m_option udata_type = {
123124
.type = CONF_TYPE_NODE
124125
};
125126

127+
static const struct m_option mdata_type = {
128+
.type = CONF_TYPE_NODE
129+
};
130+
126131
struct overlay {
127132
struct mp_image *source;
128133
int x, y;
@@ -3712,6 +3717,32 @@ static int mp_property_bindings(void *ctx, struct m_property *prop,
37123717
return M_PROPERTY_NOT_IMPLEMENTED;
37133718
}
37143719

3720+
static int mp_property_mdata(void *ctx, struct m_property *prop,
3721+
int action, void *arg)
3722+
{
3723+
MPContext *mpctx = ctx;
3724+
switch (action) {
3725+
case M_PROPERTY_GET_TYPE:
3726+
*(struct m_option *)arg = (struct m_option){.type = CONF_TYPE_NODE};
3727+
return M_PROPERTY_OK;
3728+
case M_PROPERTY_GET:
3729+
case M_PROPERTY_GET_NODE:
3730+
m_option_copy(&mdata_type, arg, &mpctx->command_ctx->mdata);
3731+
return M_PROPERTY_OK;
3732+
case M_PROPERTY_SET:
3733+
case M_PROPERTY_SET_NODE: {
3734+
m_option_copy(&mdata_type, &mpctx->command_ctx->mdata, arg);
3735+
mp_notify_property(mpctx, prop->name);
3736+
3737+
struct vo *vo = mpctx->video_out;
3738+
if (vo)
3739+
vo_control(vo, VOCTRL_UPDATE_MENU, arg);
3740+
return M_PROPERTY_OK;
3741+
}
3742+
}
3743+
return M_PROPERTY_NOT_IMPLEMENTED;
3744+
}
3745+
37153746
static int do_list_udata(int item, int action, void *arg, void *ctx);
37163747

37173748
struct udata_ctx {
@@ -4090,6 +4121,8 @@ static const struct m_property mp_properties_base[] = {
40904121
{"command-list", mp_property_commands},
40914122
{"input-bindings", mp_property_bindings},
40924123

4124+
{"menu-data", mp_property_mdata},
4125+
40934126
{"user-data", mp_property_udata},
40944127

40954128
M_PROPERTY_ALIAS("video", "vid"),
@@ -6534,6 +6567,16 @@ static void cmd_begin_vo_dragging(void *p)
65346567
vo_control(vo, VOCTRL_BEGIN_DRAGGING, NULL);
65356568
}
65366569

6570+
static void cmd_show_menu(void *p)
6571+
{
6572+
struct mp_cmd_ctx *cmd = p;
6573+
struct MPContext *mpctx = cmd->mpctx;
6574+
struct vo *vo = mpctx->video_out;
6575+
6576+
if (vo)
6577+
vo_control(vo, VOCTRL_SHOW_MENU, NULL);
6578+
}
6579+
65376580
/* This array defines all known commands.
65386581
* The first field the command name used in libmpv and input.conf.
65396582
* The second field is the handler function (see mp_cmd_def.handler and
@@ -7004,6 +7047,8 @@ const struct mp_cmd_def mp_cmds[] = {
70047047

70057048
{ "begin-vo-dragging", cmd_begin_vo_dragging },
70067049

7050+
{ "show-menu", cmd_show_menu },
7051+
70077052
{0}
70087053
};
70097054

video/out/vo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ enum mp_voctrl {
125125

126126
// Begin VO dragging.
127127
VOCTRL_BEGIN_DRAGGING,
128+
129+
// Native context menu
130+
VOCTRL_SHOW_MENU,
131+
VOCTRL_UPDATE_MENU,
128132
};
129133

130134
// Helper to expose what kind of content is currently playing to the VO.

video/out/w32_common.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "w32_common.h"
4141
#include "win32/displayconfig.h"
4242
#include "win32/droptarget.h"
43+
#include "win32/menu.h"
4344
#include "osdep/io.h"
4445
#include "osdep/threads.h"
4546
#include "osdep/w32_keyboard.h"
@@ -75,6 +76,8 @@ typedef enum MONITOR_DPI_TYPE {
7576
#define rect_w(r) ((r).right - (r).left)
7677
#define rect_h(r) ((r).bottom - (r).top)
7778

79+
#define WM_SHOWMENU (WM_USER + 1)
80+
7881
struct w32_api {
7982
HRESULT (WINAPI *pGetDpiForMonitor)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*);
8083
BOOL (WINAPI *pAdjustWindowRectExForDpi)(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle, UINT dpi);
@@ -101,6 +104,9 @@ struct vo_w32_state {
101104
HHOOK parent_win_hook;
102105
HWINEVENTHOOK parent_evt_hook;
103106

107+
HMENU menu;
108+
void *menu_ctx; // talloc context for MENUITEMINFOW.dwItemData
109+
104110
HMONITOR monitor; // Handle of the current screen
105111
char *color_profile; // Path of the current screen's color profile
106112

@@ -1405,10 +1411,19 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
14051411
if (!w32->terminate)
14061412
mp_input_put_key(w32->input_ctx, MP_KEY_CLOSE_WIN);
14071413
RevokeDragDrop(w32->window);
1414+
DestroyMenu(w32->menu);
14081415
w32->destroyed = true;
14091416
w32->window = NULL;
14101417
PostQuitMessage(0);
14111418
break;
1419+
case WM_COMMAND: {
1420+
const char *cmd = mp_win32_get_menu_cmd(w32->menu, LOWORD(wParam));
1421+
if (cmd) {
1422+
mp_cmd_t *cmdt = mp_input_parse_cmd(w32->input_ctx, bstr0(cmd), "");
1423+
mp_input_queue_cmd(w32->input_ctx, cmdt);
1424+
}
1425+
break;
1426+
}
14121427
case WM_SYSCOMMAND:
14131428
switch (wParam & 0xFFF0) {
14141429
case SC_SCREENSAVE:
@@ -1592,6 +1607,8 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
15921607
// the window is created. Otherwise, fallback to setting alphanumeric mode on
15931608
// the first keypress.
15941609
SetTimer(w32->window, (UINT_PTR)WM_CREATE, 250, NULL);
1610+
w32->menu = CreatePopupMenu();
1611+
w32->menu_ctx = talloc_new(w32);
15951612
break;
15961613
case WM_TIMER:
15971614
if (wParam == WM_CREATE) {
@@ -1600,6 +1617,9 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
16001617
return 0;
16011618
}
16021619
break;
1620+
case WM_SHOWMENU:
1621+
mp_win32_show_menu(w32->menu, w32->window);
1622+
break;
16031623
}
16041624

16051625
if (message == w32->tbtn_created_msg) {
@@ -2174,6 +2194,12 @@ static int gui_thread_control(struct vo_w32_state *w32, int request, void *arg)
21742194
case VOCTRL_BEGIN_DRAGGING:
21752195
w32->start_dragging = true;
21762196
return VO_TRUE;
2197+
case VOCTRL_SHOW_MENU:
2198+
PostMessageW(w32->window, WM_SHOWMENU, 0, 0);
2199+
return VO_TRUE;
2200+
case VOCTRL_UPDATE_MENU:
2201+
mp_win32_update_menu(w32->menu_ctx, w32->menu, (struct mpv_node *)arg);
2202+
return VO_TRUE;
21772203
}
21782204
return VO_NOTIMPL;
21792205
}

0 commit comments

Comments
 (0)