[vlc-devel] [PATCH v3 5/5] vout: win32: drawable: use an internal HWND to detect size changes

Rémi Denis-Courmont remi at remlab.net
Thu May 7 16:56:45 CEST 2020


Le torstaina 7. toukokuuta 2020, 17.45.08 EEST Steve Lhomme a écrit :
> In the past the display module was checking if the size of the host HWND
> changed via the Manage callback. Now this callback doesn't exist anymore and
> the window module is responsible for reporting its size.
> 
> In the case of embedded-window we need to read the size of the parent as we
> don't get any events telling us it's resized, nor that we should be resized
> (since apps using set_hwnd have no way to know the HWND we use internally to
> resize it).
> ---
>  modules/video_output/drawable.c | 174 +++++++++++++++++++++++++++++++-
>  1 file changed, 170 insertions(+), 4 deletions(-)
> 
> diff --git a/modules/video_output/drawable.c
> b/modules/video_output/drawable.c index ad82afadd9e9..901065588488 100644
> --- a/modules/video_output/drawable.c
> +++ b/modules/video_output/drawable.c
> @@ -64,6 +64,121 @@ static const struct vout_window_operations ops = {
>      .destroy = Close,
>  };
> 
> +#define RECTWidth(r)   (LONG)((r).right - (r).left)
> +#define RECTHeight(r)  (LONG)((r).bottom - (r).top)
> +
> +static const TCHAR *EMBED_HWND_CLASS = TEXT("VLC embeded HWND");
> +
> +struct drawable_sys
> +{
> +    vlc_sem_t hwnd_set;
> +
> +    vout_window_t *wnd;
> +    HWND hWnd;
> +    HWND embed_hwnd;
> +    RECT rect_parent;
> +};
> +
> +static LRESULT CALLBACK WinVoutEventProc(HWND hwnd, UINT message,
> +                                         WPARAM wParam, LPARAM lParam )
> +{
> +    if( message == WM_CREATE /*WM_NCCREATE*/ )
> +    {
> +        /* Store our internal structure for future use */
> +        CREATESTRUCT *c = (CREATESTRUCT *)lParam;
> +        SetWindowLongPtr( hwnd, GWLP_USERDATA, (LONG_PTR)c->lpCreateParams
> ); +        return 0;
> +    }
> +
> +    LONG_PTR p_user_data = GetWindowLongPtr( hwnd, GWLP_USERDATA );
> +    if( unlikely(p_user_data == 0) )
> +        return DefWindowProc(hwnd, message, wParam, lParam);
> +    struct drawable_sys *sys = (struct drawable_sys *)p_user_data;
> +
> +    vout_window_t *wnd = sys->wnd;
> +
> +    RECT clientRect;
> +    GetClientRect(sys->embed_hwnd, &clientRect);
> +    if (RECTWidth(sys->rect_parent)  != RECTWidth(clientRect) ||
> +        RECTHeight(sys->rect_parent) != RECTHeight(clientRect)) {
> +        sys->rect_parent = clientRect;
> +
> +        SetWindowPos(hwnd, 0, 0, 0,
> +                     RECTWidth(sys->rect_parent),
> +                     RECTHeight(sys->rect_parent),
> +                     SWP_NOZORDER|SWP_NOMOVE|SWP_NOACTIVATE);
> +    }
> +
> +    switch( message )
> +    {
> +    case WM_ERASEBKGND:
> +        /* nothing to erase */
> +        return 1;
> +
> +    case WM_PAINT:
> +        /* nothing to repaint */
> +        ValidateRect(hwnd, NULL);
> +        break;
> +
> +    case WM_CLOSE:
> +        vout_window_ReportClose(wnd);
> +        return 0;
> +
> +    /* the window has been closed so shut down everything now */
> +    case WM_DESTROY:
> +        /* just destroy the window */
> +        PostQuitMessage( 0 );
> +        return 0;
> +
> +    case WM_SIZE:
> +        vout_window_ReportSize(wnd, LOWORD(lParam), HIWORD(lParam));
> +        return 0;
> +
> +    default:
> +        break;
> +    }
> +
> +    /* Let windows handle the message */
> +    return DefWindowProc(hwnd, message, wParam, lParam);
> +}
> +
> +static DWORD WINAPI WindowLoopThread(LPVOID lpParameter)
> +{
> +    struct drawable_sys *sys = lpParameter;
> +
> +    /* Get this module's instance */
> +    HMODULE hInstance = GetModuleHandle(NULL);
> +
> +    sys->hWnd =
> +        CreateWindowEx( 0,
> +                    EMBED_HWND_CLASS,              /* name of window class
> */ +                    TEXT("Embedded HWND"),                 /* window
> title */ +                    WS_CHILD|WS_VISIBLE|WS_DISABLED,       /*
> window style */ +                    0,                             /*
> default X coordinate */ +                    0,                            
> /* default Y coordinate */ +                   
> RECTWidth(sys->rect_parent),           /* window width */ +                
>    RECTHeight(sys->rect_parent),         /* window height */ +             
>       sys->embed_hwnd,                      /* parent window */ +          
>          NULL,                        /* no menu in this window */ +       
>             hInstance,          /* handle of this program instance */ +    
>                sys );                            /* send to WM_CREATE */ +
> +    vlc_sem_post(&sys->hwnd_set);
> +
> +    if (sys->hWnd == NULL)
> +        return 1;
> +
> +    /* Main loop */
> +    /* GetMessage will sleep if there's no message in the queue */
> +    MSG msg;
> +    while( GetMessage( &msg, 0, 0, 0 ) )
> +    {
> +        TranslateMessage(&msg);
> +        DispatchMessage(&msg);
> +    }
> +    return 0;
> +}
> +
>  static void RemoveDrawable(HWND val)
>  {
>      size_t n = 0;
> @@ -84,6 +199,9 @@ static void RemoveDrawable(HWND val)
>      {
>          free (used);
>          used = NULL;
> +
> +        HINSTANCE hInstance = GetModuleHandle(NULL);
> +        UnregisterClass( EMBED_HWND_CLASS, hInstance );
>      }
>      vlc_mutex_unlock (&serializer);
>  }
> @@ -102,6 +220,7 @@ static int Open(vout_window_t *wnd)
>      size_t n = 0;
> 
>      vlc_mutex_lock (&serializer);
> +    bool first_hwnd = used == NULL;
>      if (used != NULL)
>          for (/*n = 0*/; used[n]; n++)
>              if (used[n] == val)
> @@ -122,11 +241,58 @@ static int Open(vout_window_t *wnd)
> 
>      vlc_mutex_unlock (&serializer);
> 
> +    struct drawable_sys *sys = vlc_obj_calloc(VLC_OBJECT(wnd), 1,
> sizeof(*sys));
> +    if (unlikely(sys == NULL)) {
> +        RemoveDrawable(val);
> +        return VLC_ENOMEM;
> +    }
> +
> +    sys->embed_hwnd = (HWND)val;
> +    sys->wnd = wnd;
> +    GetClientRect(sys->embed_hwnd, &sys->rect_parent);
> +    vlc_sem_init(&sys->hwnd_set, 0);
> +
> +    if (first_hwnd)
> +    {
> +        /* Get this module's instance */
> +        HMODULE hInstance = GetModuleHandle(NULL);
> +
> +        WNDCLASS wc = { 0 };                      /* window class
> components */ +        wc.lpfnWndProc   = WinVoutEventProc;               
> /* event handler */ +        wc.hInstance     = hInstance;                 
>           /* instance */ +        wc.lpszClassName = EMBED_HWND_CLASS;
> +        if( !RegisterClass(&wc) )
> +        {
> +            msg_Err( sys->wnd, "RegisterClass failed (err=%lu)",
> GetLastError() );

IIRC, Windows errors are conventionally printed in hex format?

> +            goto error;
> +        }
> +    }
> +
> +    // Create a Thread for the window event loop
> +    if (CreateThread(NULL, 0, WindowLoopThread, sys, 0, NULL) == NULL)
> +    {
> +        msg_Err( sys->wnd, "CreateThread failed (err=%lu)", GetLastError()
> ); +        goto error;
> +    }
> +
> +    vlc_sem_wait(&sys->hwnd_set);
> +
> +    if (sys->hWnd == NULL)
> +    {
> +        msg_Err( sys->wnd, "Failed to create a window (err=%lu)",
> GetLastError() );
> +        goto error;
> +    }
> +
>      wnd->type = VOUT_WINDOW_TYPE_HWND;
> -    wnd->handle.hwnd = (void *)val;
> +    wnd->handle.hwnd = (void *)sys->hWnd;
>      wnd->ops = &ops;
> -    wnd->sys = (void *)val;
> +    wnd->sys = (void *)sys;

Seemingly useless cast.

>      return VLC_SUCCESS;
> +
> +error:
> +    RemoveDrawable(sys->embed_hwnd);
> +
> +    return VLC_EGENERIC;
>  }
> 
>  /**
> @@ -134,7 +300,7 @@ static int Open(vout_window_t *wnd)
>   */
>  static void Close (vout_window_t *wnd)
>  {
> -    HWND val = (HWND) wnd->handle.hwnd;
> +    struct drawable_sys *sys = wnd->sys;
> 
> -    RemoveDrawable(val);
> +    RemoveDrawable(sys->embed_hwnd);
>  }


-- 
雷米‧德尼-库尔蒙
http://www.remlab.net/





More information about the vlc-devel mailing list