Skip to content

Commit b844c51

Browse files
committed
vo: add win32 context menu support
1 parent 9cee441 commit b844c51

File tree

9 files changed

+384
-1
lines changed

9 files changed

+384
-1
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
add `context-menu` command
2+
add `menu-data` property

DOCS/man/input.rst

Lines changed: 43 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+
``context-menu``
931+
Show context menu on video window, see `Context Menu`_ section.
932+
930933

931934
Input Commands that are Possibly Subject to Change
932935
--------------------------------------------------
@@ -3454,6 +3457,46 @@ Property list
34543457
and not using raw mode, the underlying content will be given (e.g. strings will be
34553458
printed directly, rather than quoted and JSON-escaped).
34563459

3460+
``menu-data`` (RW)
3461+
This property stores the raw menu definition, see `Context Menu`_ section.
3462+
3463+
``type``
3464+
Menu item type, can be: ``separator``, ``submenu``, or empty.
3465+
3466+
``title``
3467+
Menu item title, required if type is not ``separator``.
3468+
3469+
``cmd``
3470+
Command to execute when the menu item is clicked.
3471+
3472+
``shortcut``
3473+
Menu item shortcut key, appears to the right of the menu item.
3474+
A shortcut key does not have to be functional, it's just a visual hint.
3475+
3476+
``state``
3477+
Menu item state, can be: ``checked``, ``disabled``, ``hidden``, or empty.
3478+
3479+
``submenu``
3480+
Submenu items, required if type is ``submenu``.
3481+
3482+
When querying the property with the client API using ``MPV_FORMAT_NODE``, or with
3483+
Lua ``mp.get_property_native``, this will return a mpv_node with the following
3484+
contents:
3485+
3486+
::
3487+
3488+
MPV_FORMAT_NODE_ARRAY
3489+
MPV_FORMAT_NODE_MAP (menu item)
3490+
"type" MPV_FORMAT_STRING
3491+
"title" MPV_FORMAT_STRING
3492+
"cmd" MPV_FORMAT_STRING
3493+
"shortcut" MPV_FORMAT_STRING
3494+
"state" MPV_FORMAT_NODE_ARRAY[MPV_FORMAT_STRING]
3495+
"submenu" MPV_FORMAT_NODE_ARRAY[menu item]
3496+
3497+
Writing to this property with the client API using ``MPV_FORMAT_NODE`` or with
3498+
Lua ``mp.set_property_native`` will trigger an immediate update of the menu.
3499+
34573500
``working-directory``
34583501
The working directory of the mpv process. Can be useful for JSON IPC users,
34593502
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
@@ -310,6 +310,21 @@ Wheel left/right
310310
Ctrl+Wheel up/down
311311
Change video zoom.
312312

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

meson.build

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,8 @@ if features['win32-desktop']
510510
'osdep/terminal-win.c',
511511
'video/out/w32_common.c',
512512
'video/out/win32/displayconfig.c',
513-
'video/out/win32/droptarget.c')
513+
'video/out/win32/droptarget.c',
514+
'video/out/win32/menu.c')
514515
main_fn_source = files('osdep/main-fn-win.c')
515516
endif
516517

player/command.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ struct command_ctx {
114114

115115
char **script_props;
116116
mpv_node udata;
117+
mpv_node mdata;
117118

118119
double cached_window_scale;
119120
};
@@ -126,6 +127,10 @@ static const struct m_option udata_type = {
126127
.type = CONF_TYPE_NODE
127128
};
128129

130+
static const struct m_option mdata_type = {
131+
.type = CONF_TYPE_NODE
132+
};
133+
129134
struct overlay {
130135
struct mp_image *source;
131136
int x, y;
@@ -3730,6 +3735,35 @@ static int mp_property_bindings(void *ctx, struct m_property *prop,
37303735
return M_PROPERTY_NOT_IMPLEMENTED;
37313736
}
37323737

3738+
static int mp_property_mdata(void *ctx, struct m_property *prop,
3739+
int action, void *arg)
3740+
{
3741+
MPContext *mpctx = ctx;
3742+
mpv_node *node = &mpctx->command_ctx->mdata;
3743+
3744+
switch (action) {
3745+
case M_PROPERTY_GET_TYPE:
3746+
*(struct m_option *)arg = (struct m_option){.type = CONF_TYPE_NODE};
3747+
return M_PROPERTY_OK;
3748+
case M_PROPERTY_GET:
3749+
case M_PROPERTY_GET_NODE:
3750+
m_option_copy(&mdata_type, arg, node);
3751+
return M_PROPERTY_OK;
3752+
case M_PROPERTY_SET:
3753+
case M_PROPERTY_SET_NODE: {
3754+
m_option_copy(&mdata_type, node, arg);
3755+
talloc_steal(mpctx->command_ctx, node_get_alloc(node));
3756+
mp_notify_property(mpctx, prop->name);
3757+
3758+
struct vo *vo = mpctx->video_out;
3759+
if (vo)
3760+
vo_control(vo, VOCTRL_UPDATE_MENU, arg);
3761+
return M_PROPERTY_OK;
3762+
}
3763+
}
3764+
return M_PROPERTY_NOT_IMPLEMENTED;
3765+
}
3766+
37333767
static int do_list_udata(int item, int action, void *arg, void *ctx);
37343768

37353769
struct udata_ctx {
@@ -4109,6 +4143,8 @@ static const struct m_property mp_properties_base[] = {
41094143
{"command-list", mp_property_commands},
41104144
{"input-bindings", mp_property_bindings},
41114145

4146+
{"menu-data", mp_property_mdata},
4147+
41124148
{"user-data", mp_property_udata},
41134149
{"term-size", mp_property_term_size},
41144150

@@ -6567,6 +6603,16 @@ static void cmd_begin_vo_dragging(void *p)
65676603
vo_control(vo, VOCTRL_BEGIN_DRAGGING, NULL);
65686604
}
65696605

6606+
static void cmd_context_menu(void *p)
6607+
{
6608+
struct mp_cmd_ctx *cmd = p;
6609+
struct MPContext *mpctx = cmd->mpctx;
6610+
struct vo *vo = mpctx->video_out;
6611+
6612+
if (vo)
6613+
vo_control(vo, VOCTRL_SHOW_MENU, NULL);
6614+
}
6615+
65706616
/* This array defines all known commands.
65716617
* The first field the command name used in libmpv and input.conf.
65726618
* The second field is the handler function (see mp_cmd_def.handler and
@@ -7039,6 +7085,8 @@ const struct mp_cmd_def mp_cmds[] = {
70397085

70407086
{ "begin-vo-dragging", cmd_begin_vo_dragging },
70417087

7088+
{ "context-menu", cmd_context_menu },
7089+
70427090
{0}
70437091
};
70447092

@@ -7113,6 +7161,9 @@ void command_init(struct MPContext *mpctx)
71137161
ctx->properties[count++] = prop;
71147162
}
71157163

7164+
node_init(&ctx->mdata, MPV_FORMAT_NODE_ARRAY, NULL);
7165+
talloc_steal(ctx, ctx->mdata.u.list);
7166+
71167167
node_init(&ctx->udata, MPV_FORMAT_NODE_MAP, NULL);
71177168
talloc_steal(ctx, ctx->udata.u.list);
71187169
}

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"
@@ -82,6 +83,8 @@ typedef enum MONITOR_DPI_TYPE {
8283
#define rect_w(r) ((r).right - (r).left)
8384
#define rect_h(r) ((r).bottom - (r).top)
8485

86+
#define WM_SHOWMENU (WM_USER + 1)
87+
8588
struct w32_api {
8689
HRESULT (WINAPI *pGetDpiForMonitor)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*);
8790
BOOL (WINAPI *pAdjustWindowRectExForDpi)(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle, UINT dpi);
@@ -109,6 +112,9 @@ struct vo_w32_state {
109112
HHOOK parent_win_hook;
110113
HWINEVENTHOOK parent_evt_hook;
111114

115+
HMENU menu;
116+
void *menu_ctx; // talloc context for MENUITEMINFOW.dwItemData
117+
112118
HMONITOR monitor; // Handle of the current screen
113119
char *color_profile; // Path of the current screen's color profile
114120

@@ -1485,10 +1491,19 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
14851491
if (!w32->terminate)
14861492
mp_input_put_key(w32->input_ctx, MP_KEY_CLOSE_WIN);
14871493
RevokeDragDrop(w32->window);
1494+
DestroyMenu(w32->menu);
14881495
w32->destroyed = true;
14891496
w32->window = NULL;
14901497
PostQuitMessage(0);
14911498
break;
1499+
case WM_COMMAND: {
1500+
const char *cmd = mp_win32_get_menu_cmd(w32->menu, LOWORD(wParam));
1501+
if (cmd) {
1502+
mp_cmd_t *cmdt = mp_input_parse_cmd(w32->input_ctx, bstr0(cmd), "");
1503+
mp_input_queue_cmd(w32->input_ctx, cmdt);
1504+
}
1505+
break;
1506+
}
14921507
case WM_SYSCOMMAND:
14931508
switch (wParam & 0xFFF0) {
14941509
case SC_SCREENSAVE:
@@ -1682,6 +1697,8 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
16821697
// the window is created. Otherwise, fallback to setting alphanumeric mode on
16831698
// the first keypress.
16841699
SetTimer(w32->window, (UINT_PTR)WM_CREATE, 250, NULL);
1700+
w32->menu = CreatePopupMenu();
1701+
w32->menu_ctx = talloc_new(w32);
16851702
break;
16861703
case WM_TIMER:
16871704
if (wParam == WM_CREATE) {
@@ -1690,6 +1707,9 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
16901707
return 0;
16911708
}
16921709
break;
1710+
case WM_SHOWMENU:
1711+
mp_win32_show_menu(w32->menu, w32->window);
1712+
break;
16931713
}
16941714

16951715
if (message == w32->tbtn_created_msg) {
@@ -2275,6 +2295,12 @@ static int gui_thread_control(struct vo_w32_state *w32, int request, void *arg)
22752295
case VOCTRL_BEGIN_DRAGGING:
22762296
w32->start_dragging = true;
22772297
return VO_TRUE;
2298+
case VOCTRL_SHOW_MENU:
2299+
PostMessageW(w32->window, WM_SHOWMENU, 0, 0);
2300+
return VO_TRUE;
2301+
case VOCTRL_UPDATE_MENU:
2302+
mp_win32_update_menu(w32->menu_ctx, w32->menu, (struct mpv_node *)arg);
2303+
return VO_TRUE;
22782304
}
22792305
return VO_NOTIMPL;
22802306
}

0 commit comments

Comments
 (0)