mpv-player / mpv

🎥 Command line video player
https://mpv.io
Other
26.75k stars 2.84k forks source link

Allow libmpv frontends for better window-dragging implementation #12782

Open stax76 opened 8 months ago

stax76 commented 8 months ago

For a libmpv frontend to fully support 3rd party OSCs like uosc and support window-dragging, it's necessary to know if the mouse is inside an OSC menu, in this case dragging is undesired.

I couldn't find a way to get this information, so I use a workaround, I simply do no dragging when the mouse is near a window border because OSC menus are usually found near window borders.

If the menu is in the middle, like the context menu of uosc, dragging is still performed. I didn't know uosc is very popular and doesn't fully work in mpv.net until a recent bug report, it works now after delaying the start of the drag operation for a few pixels.

So currently there are two minor defects in my frontend, dragging works only in the middle of the window, not near borders, and if there is a menu in the middle of the window dragging is still performed.

I looked at the mpv code today and what I found is that it appears to hit test here:

static bool test_mouse(struct input_ctx *ictx, int x, int y, int rej_flags)
{
    input_lock(ictx);
    bool res = false;
    for (int i = 0; i < ictx->num_active_sections; i++) {
        struct active_section *as = &ictx->active_sections[i];
        if (as->flags & rej_flags)
            continue;
        struct cmd_bind_section *s = get_bind_section(ictx, bstr0(as->name));
        if (s->mouse_area_set && test_rect(&s->mouse_area, x, y)) {
            res = true;
            break;
        }
    }
    input_unlock(ictx);
    return res;
}

Now if there was a hit test function either in client.h or as input command, it would solve my problem, or maybe there is already something I could use, or something simpler.

stax76 commented 8 months ago

Overall, there are 3 features in mpv.net that need to know if the mouse is in inside an OSC menu:

  1. window-dragging
  2. Cursor hiding
  3. Showing the context menu
stax76 commented 8 months ago

I added a description of the issue to the mpv.net manual:

For mpv.net it's currently not possible to find out where OSC menus are located, but there are 3 features that require this information, therefore mpv.net makes the assumption that near the window borders might be OSC menus. As a result the following three features, work only when invokes from the center of the window:

  1. Window dragging (moving the window with the mouse).
  2. Showing the context menu.
  3. Auto hiding the mouse cursor.

When the mouse is near a window border, these 3 features are not available.

Dudemanguy commented 8 months ago

Would it suffice to simply add a user-data property boolean to osc.lua that tells you if the mouse is over the osc menus or not? It sounds like that's all you really need from us.

stax76 commented 8 months ago

In this case, all OSC scripts would have to do the same, there are about ten OSC scripts available.

I don't know if it would be as fast and reliable as a client.h function.

Dudemanguy commented 8 months ago

I think currently this works via input sections which I'm truthfully not familiar with. I'm not sure why libmpv behavior would be any different though. It should be the same (in theory anyway).

stax76 commented 8 months ago

Frontends always implement their own main window, so they need their own window dragging code, and code to show a context menu and code to auto hide the cursor, but it's not possible to do exactly without a hit test function. The only thing that can be done is creating permanent dead zones near the window borders. It can be perceived as bug or limitation. mpv.net currently uses:

    bool IsMouseInOsc()
    {
        Point pos = PointToClient(MousePosition);
        float top = 0;

        if (!Player.Border)
            top = ClientSize.Height * 0.1f;

        return pos.X < ClientSize.Width * 0.1 ||
               pos.X > ClientSize.Width * 0.9 ||
               pos.Y < top ||
               pos.Y > ClientSize.Height * 0.78;
    }

So the dead zones are:

Left: 10% Top: 10%, but only if border=no Right: 10% Bottom: 22%

na-na-hi commented 1 month ago

In general, all libmpv clients are on equal grounds and compete for shared resources. I think it's up to the clients to resolve any outstanding conflicts, so user-data is a suitable solution.

Also note that currently some OSC implementations (including the built-in OSC and uosc) use the internal allow-hide-cursor+allow-vo-dragging input section flags to control the hide cursor and window dragging behavior. These scripts eventually need to stop using this mechanism, since input section is deprecated and may be removed in the future. Once input section is removed, there is no way for mpv to know the region which has these properties, so providing such feature is impossible.