]> git.sesse.net Git - vlc/blobdiff - modules/video_output/msw/events.c
opengl: Supports OpenGL ES.
[vlc] / modules / video_output / msw / events.c
index f93a9210ec1294c55ba50a0ac0e8f3ca497032d8..46c15c4a55fc077ae157e361c59d022af13de06f 100644 (file)
@@ -49,6 +49,9 @@
 #ifdef MODULE_NAME_IS_glwin32
 #include "../opengl.h"
 #endif
+#ifdef MODULE_NAME_IS_direct2d
+#include <d2d1.h>
+#endif
 
 #include <vlc_keys.h>
 #include "common.h"
@@ -60,6 +63,9 @@
 UINT GetMenuState(HMENU hMenu, UINT id, UINT flags)
 {
     MENUITEMINFO info;
+    memset(&info, 0, sizeof(info));
+    info.cbSize = sizeof(info);
+    info.fMask = MIIM_STATE;
     if (!GetMenuItemInfo(hMenu, id, (flags & MF_BYPOSITION) != 0, &info))
         return -1;
     /* XXX Submenu handling is missing... */
@@ -78,8 +84,7 @@ UINT GetMenuState(HMENU hMenu, UINT id, UINT flags)
  * Local prototypes.
  *****************************************************************************/
 #define WM_VLC_HIDE_MOUSE   (WM_APP + 0)
-#define WM_VLC_SHOW_MOUSE   (WM_APP + 1)
-#define WM_VLC_CHANGE_TEXT  (WM_APP + 2)
+#define WM_VLC_CHANGE_TEXT  (WM_APP + 1)
 
 struct event_thread_t
 {
@@ -98,9 +103,10 @@ struct event_thread_t
     bool use_overlay;
 
     /* Mouse */
-    volatile bool    b_cursor_hidden;
-    volatile mtime_t i_lastmoved;
-    mtime_t          i_mouse_hide_timeout;
+    bool is_cursor_hidden;
+    HCURSOR cursor_arrow;
+    HCURSOR cursor_empty;
+    unsigned button_pressed;
 
     /* Title */
     char *psz_title;
@@ -110,6 +116,8 @@ struct event_thread_t
 
     /* */
     vout_window_t *parent_window;
+    TCHAR class_main[256];
+    TCHAR class_video[256];
     HWND hparent;
     HWND hwnd;
     HWND hvideownd;
@@ -126,6 +134,82 @@ static long FAR PASCAL DirectXEventProc( HWND, UINT, WPARAM, LPARAM );
 
 static int DirectXConvertKey( int i_key );
 
+static inline bool isMouseEvent( WPARAM type )
+{
+    return type >= WM_MOUSEFIRST &&
+           type <= WM_MOUSELAST;
+}
+
+static inline bool isKeyEvent( WPARAM type )
+{
+    return type >= WM_KEYFIRST &&
+           type <= WM_KEYLAST;
+}
+
+static void UpdateCursor( event_thread_t *p_event, bool b_show )
+{
+    if( p_event->is_cursor_hidden == !b_show )
+        return;
+    p_event->is_cursor_hidden = !b_show;
+
+#if 1
+    HCURSOR cursor = b_show ? p_event->cursor_arrow : p_event->cursor_empty;
+    if( p_event->hvideownd )
+        SetClassLongPtr( p_event->hvideownd, GCLP_HCURSOR, (LONG_PTR)cursor );
+    if( p_event->hwnd )
+        SetClassLongPtr( p_event->hwnd, GCLP_HCURSOR, (LONG_PTR)cursor );
+#endif
+
+    /* FIXME I failed to find a cleaner way to force a redraw of the cursor */
+    POINT p;
+    GetCursorPos(&p);
+    HWND hwnd = WindowFromPoint(p);
+    if( hwnd == p_event->hvideownd || hwnd == p_event->hwnd )
+    {
+        if( b_show )
+            SetCursor( cursor );
+        else
+            SetCursorPos( p.x, p.y );
+    }
+}
+
+#ifndef UNDER_CE
+static HCURSOR EmptyCursor( HINSTANCE instance )
+{
+    const int cw = GetSystemMetrics(SM_CXCURSOR);
+    const int ch = GetSystemMetrics(SM_CYCURSOR);
+
+    HCURSOR cursor = NULL;
+    uint8_t *and = malloc(cw * ch);
+    uint8_t *xor = malloc(cw * ch);
+    if( and && xor )
+    {
+        memset(and, 0xff, cw * ch );
+        memset(xor, 0x00, cw * ch );
+        cursor = CreateCursor( instance, 0, 0, cw, ch, and, xor);
+    }
+    free( and );
+    free( xor );
+
+    return cursor;
+}
+#endif
+
+static void MousePressed( event_thread_t *p_event, HWND hwnd, unsigned button )
+{
+    if( !p_event->button_pressed )
+        SetCapture( hwnd );
+    p_event->button_pressed |= 1 << button;
+    vout_display_SendEventMousePressed( p_event->vd, button );
+}
+
+static void MouseReleased( event_thread_t *p_event, unsigned button )
+{
+    p_event->button_pressed &= ~(1 << button);
+    if( !p_event->button_pressed )
+        ReleaseCapture();
+    vout_display_SendEventMouseReleased( p_event->vd, button );
+}
 /*****************************************************************************
  * EventThread: Create video window & handle its messages
  *****************************************************************************
@@ -143,6 +227,9 @@ static void *EventThread( void *p_this )
     HMODULE hkernel32;
     int canc = vlc_savecancel ();
 
+    bool b_mouse_support = var_InheritBool( p_event->vd, "mouse-events" );
+    bool b_key_support = var_InheritBool( p_event->vd, "keyboard-events" );
+
     vlc_mutex_lock( &p_event->lock );
     /* Create a window for the video */
     /* Creating a window under Windows also initializes the thread's event
@@ -201,6 +288,34 @@ static void *EventThread( void *p_this )
         if( b_done )
             break;
 
+        if( !b_mouse_support && isMouseEvent( msg.message ) )
+            continue;
+
+        if( !b_key_support && isKeyEvent( msg.message ) )
+            continue;
+
+        /* Handle mouse state */
+        if( msg.message == WM_MOUSEMOVE ||
+            msg.message == WM_NCMOUSEMOVE )
+        {
+            GetCursorPos( &mouse_pos );
+            /* FIXME, why this >2 limits ? */
+            if( (abs(mouse_pos.x - old_mouse_pos.x) > 2 ||
+                (abs(mouse_pos.y - old_mouse_pos.y)) > 2 ) )
+            {
+                old_mouse_pos = mouse_pos;
+                UpdateCursor( p_event, true );
+            }
+        }
+        else if( isMouseEvent( msg.message ) )
+        {
+            UpdateCursor( p_event, true );
+        }
+        else if( msg.message == WM_VLC_HIDE_MOUSE )
+        {
+            UpdateCursor( p_event, false );
+        }
+
         /* */
         switch( msg.message )
         {
@@ -224,62 +339,35 @@ static void *EventThread( void *p_this )
                     (int64_t)(GET_Y_LPARAM(msg.lParam) - place.y) * source.i_height / place.height;
                 vout_display_SendEventMouseMoved(vd, x, y);
             }
-            /* Fall through */
+            break;
         case WM_NCMOUSEMOVE:
-            GetCursorPos( &mouse_pos );
-            /* FIXME, why this >2 limits ? */
-            if( (abs(mouse_pos.x - old_mouse_pos.x) > 2 ||
-                (abs(mouse_pos.y - old_mouse_pos.y)) > 2 ) )
-            {
-                GetCursorPos( &old_mouse_pos );
-                p_event->i_lastmoved = mdate();
-
-                if( p_event->b_cursor_hidden )
-                {
-                    p_event->b_cursor_hidden = false;
-                    ShowCursor( TRUE );
-                }
-            }
             break;
 
         case WM_VLC_HIDE_MOUSE:
-            if( p_event->b_cursor_hidden )
-                break;
-            p_event->b_cursor_hidden = true;
-            GetCursorPos( &old_mouse_pos );
-            ShowCursor( FALSE );
-            break;
-
-        case WM_VLC_SHOW_MOUSE:
-            if( !p_event->b_cursor_hidden )
-                break;
-            p_event->b_cursor_hidden = false;
-            GetCursorPos( &old_mouse_pos );
-            ShowCursor( TRUE );
             break;
 
         case WM_LBUTTONDOWN:
-            vout_display_SendEventMousePressed(vd, MOUSE_BUTTON_LEFT);
+            MousePressed( p_event, msg.hwnd, MOUSE_BUTTON_LEFT );
             break;
         case WM_LBUTTONUP:
-            vout_display_SendEventMouseReleased(vd, MOUSE_BUTTON_LEFT);
+            MouseReleased( p_event, MOUSE_BUTTON_LEFT );
             break;
         case WM_LBUTTONDBLCLK:
             vout_display_SendEventMouseDoubleClick(vd);
             break;
 
         case WM_MBUTTONDOWN:
-            vout_display_SendEventMousePressed(vd, MOUSE_BUTTON_CENTER);
+            MousePressed( p_event, msg.hwnd, MOUSE_BUTTON_CENTER );
             break;
         case WM_MBUTTONUP:
-            vout_display_SendEventMouseReleased(vd, MOUSE_BUTTON_CENTER);
+            MouseReleased( p_event, MOUSE_BUTTON_CENTER );
             break;
 
         case WM_RBUTTONDOWN:
-            vout_display_SendEventMousePressed(vd, MOUSE_BUTTON_RIGHT);
+            MousePressed( p_event, msg.hwnd, MOUSE_BUTTON_RIGHT );
             break;
         case WM_RBUTTONUP:
-            vout_display_SendEventMouseReleased(vd, MOUSE_BUTTON_RIGHT);
+            MouseReleased( p_event, MOUSE_BUTTON_RIGHT );
             break;
 
         case WM_KEYDOWN:
@@ -363,9 +451,9 @@ static void *EventThread( void *p_this )
 
             if( pwz_title )
             {
-                SetWindowTextW( p_event->hwnd, (LPCTSTR)pwz_title );
+                SetWindowTextW( p_event->hwnd, pwz_title );
                 if( p_event->hfswnd )
-                    SetWindowTextW( p_event->hfswnd, (LPCTSTR)pwz_title );
+                    SetWindowTextW( p_event->hfswnd, pwz_title );
                 free( pwz_title );
             }
             break;
@@ -429,7 +517,7 @@ static int DirectXCreateWindow( event_thread_t *p_event )
         /* If an external window was specified, we'll draw in it. */
         p_event->parent_window = vout_display_NewWindow(vd, &p_event->wnd_cfg );
         if( p_event->parent_window )
-            p_event->hparent = p_event->parent_window->hwnd;
+            p_event->hparent = p_event->parent_window->handle.hwnd;
         else
             p_event->hparent = NULL;
     #ifdef MODULE_NAME_IS_direct3d
@@ -446,6 +534,10 @@ static int DirectXCreateWindow( event_thread_t *p_event )
         p_event->hparent = hwnd;
     }
     #endif
+    p_event->cursor_arrow = LoadCursor(NULL, IDC_ARROW);
+#ifndef UNDER_CE
+    p_event->cursor_empty = EmptyCursor(hInstance);
+#endif
 
     /* Get the Icon from the main app */
     vlc_icon = NULL;
@@ -463,49 +555,38 @@ static int DirectXCreateWindow( event_thread_t *p_event )
     wc.cbWndExtra    = 0;                        /* no extra window data */
     wc.hInstance     = hInstance;                            /* instance */
     wc.hIcon         = vlc_icon;                /* load the vlc big icon */
-    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);    /* default cursor */
+    wc.hCursor       = p_event->is_cursor_hidden ? p_event->cursor_empty :
+                                                   p_event->cursor_arrow;
     wc.hbrBackground = GetStockObject(BLACK_BRUSH);  /* background color */
     wc.lpszMenuName  = NULL;                                  /* no menu */
-    wc.lpszClassName = _T("VLC DirectX");         /* use a special class */
+    wc.lpszClassName = p_event->class_main;       /* use a special class */
 
     /* Register the window class */
     if( !RegisterClass(&wc) )
     {
-        WNDCLASS wndclass;
+        if( vlc_icon )
+            DestroyIcon( vlc_icon );
 
-        if( vlc_icon ) DestroyIcon( vlc_icon );
-
-        /* Check why it failed. If it's because one already exists
-         * then fine, otherwise return with an error. */
-        if( !GetClassInfo( hInstance, _T("VLC DirectX"), &wndclass ) )
-        {
-            msg_Err( vd, "DirectXCreateWindow RegisterClass FAILED (err=%lu)", GetLastError() );
-            return VLC_EGENERIC;
-        }
+        msg_Err( vd, "DirectXCreateWindow RegisterClass FAILED (err=%lu)", GetLastError() );
+        return VLC_EGENERIC;
     }
 
     /* Register the video sub-window class */
-    wc.lpszClassName = _T("VLC DirectX video"); wc.hIcon = 0;
+    wc.lpszClassName = p_event->class_video;
+    wc.hIcon = 0;
     wc.hbrBackground = NULL; /* no background color */
     if( !RegisterClass(&wc) )
     {
-        WNDCLASS wndclass;
-
-        /* Check why it failed. If it's because one already exists
-         * then fine, otherwise return with an error. */
-        if( !GetClassInfo( hInstance, _T("VLC DirectX video"), &wndclass ) )
-        {
-            msg_Err( vd, "DirectXCreateWindow RegisterClass FAILED (err=%lu)", GetLastError() );
-            return VLC_EGENERIC;
-        }
+        msg_Err( vd, "DirectXCreateWindow RegisterClass FAILED (err=%lu)", GetLastError() );
+        return VLC_EGENERIC;
     }
 
     /* When you create a window you give the dimensions you wish it to
      * have. Unfortunatly these dimensions will include the borders and
      * titlebar. We use the following function to find out the size of
      * the window corresponding to the useable surface we want */
-    rect_window.top    = 10;
     rect_window.left   = 10;
+    rect_window.top    = 10;
     rect_window.right  = rect_window.left + p_event->wnd_cfg.width;
     rect_window.bottom = rect_window.top  + p_event->wnd_cfg.height;
 
@@ -536,12 +617,12 @@ static int DirectXCreateWindow( event_thread_t *p_event )
     /* Create the window */
     p_event->hwnd =
         CreateWindowEx( WS_EX_NOPARENTNOTIFY | i_stylex,
-                    _T("VLC DirectX"),               /* name of window class */
+                    p_event->class_main,             /* name of window class */
                     _T(VOUT_TITLE) _T(" (DirectX Output)"),  /* window title */
                     i_style,                                 /* window style */
-                    (p_event->wnd_cfg.x < 0) ? CW_USEDEFAULT :
+                    (!p_event->wnd_cfg.x) ? CW_USEDEFAULT :
                         (UINT)p_event->wnd_cfg.x,   /* default X coordinate */
-                    (p_event->wnd_cfg.y < 0) ? CW_USEDEFAULT :
+                    (!p_event->wnd_cfg.y) ? CW_USEDEFAULT :
                         (UINT)p_event->wnd_cfg.y,   /* default Y coordinate */
                     rect_window.right - rect_window.left,    /* window width */
                     rect_window.bottom - rect_window.top,   /* window height */
@@ -570,7 +651,7 @@ static int DirectXCreateWindow( event_thread_t *p_event )
 
         /* Create our fullscreen window */
         p_event->hfswnd =
-            CreateWindowEx( WS_EX_APPWINDOW, _T("VLC DirectX"),
+            CreateWindowEx( WS_EX_APPWINDOW, p_event->class_main,
                             _T(VOUT_TITLE) _T(" (DirectX Output)"),
                             WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_SIZEBOX,
                             CW_USEDEFAULT, CW_USEDEFAULT,
@@ -593,7 +674,7 @@ static int DirectXCreateWindow( event_thread_t *p_event )
      * without having them shown outside of the video area. */
     /* FIXME vd->source.i_width/i_height seems wrong */
     p_event->hvideownd =
-    CreateWindow( _T("VLC DirectX video"), _T(""),   /* window class */
+    CreateWindow( p_event->class_video, _T(""),   /* window class */
         WS_CHILD,                   /* window style, not visible initially */
         0, 0,
         vd->source.i_width,          /* default width */
@@ -633,9 +714,13 @@ static void DirectXCloseWindow( event_thread_t *p_event )
         vout_display_DeleteWindow( vd, p_event->parent_window );
     p_event->hwnd = NULL;
 
-    /* We don't unregister the Window Class because it could lead to race
-     * conditions and it will be done anyway by the system when the app will
-     * exit */
+    HINSTANCE hInstance = GetModuleHandle(NULL);
+    UnregisterClass( p_event->class_video, hInstance );
+    UnregisterClass( p_event->class_main, hInstance );
+
+#ifndef UNDER_CE
+    DestroyCursor( p_event->cursor_empty );
+#endif
 }
 
 /*****************************************************************************
@@ -683,6 +768,26 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
         return 0; /* this stops them from happening */
     }
 #endif
+#if 0
+    if( message == WM_SETCURSOR )
+    {
+        msg_Err(vd, "WM_SETCURSOR: %d (t2)", p_event->is_cursor_hidden);
+        SetCursor( p_event->is_cursor_hidden ? p_event->cursor_empty : p_event->cursor_arrow );
+        return 1;
+    }
+#endif
+    if( message == WM_CAPTURECHANGED )
+    {
+        for( int button = 0; p_event->button_pressed; button++ )
+        {
+            unsigned m = 1 << button;
+            if( p_event->button_pressed & m )
+                vout_display_SendEventMouseReleased( p_event->vd, button );
+            p_event->button_pressed &= ~m;
+        }
+        p_event->button_pressed = 0;
+        return 0;
+    }
 
     if( hwnd == p_event->hvideownd )
     {
@@ -891,30 +996,11 @@ static int DirectXConvertKey( int i_key )
     return 0;
 }
 
-void EventThreadMouseAutoHide( event_thread_t *p_event )
+void EventThreadMouseHide( event_thread_t *p_event )
 {
-    if (!p_event->b_cursor_hidden &&
-        (mdate() - p_event->i_lastmoved) > p_event->i_mouse_hide_timeout )
-    {
-        /* Hide the cursor only if it is inside our window */
-        POINT point;
-        GetCursorPos( &point );
-
-        HWND hwnd = WindowFromPoint(point);
-        if( hwnd == p_event->hwnd || hwnd == p_event->hvideownd )
-        {
-            PostMessage( p_event->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
-        }
-        else
-        {
-            p_event->i_lastmoved = mdate();
-        }
-    }
-}
-void EventThreadMouseShow( event_thread_t *p_event )
-{
-    PostMessage( p_event->hwnd, WM_VLC_SHOW_MOUSE, 0, 0 );
+    PostMessage( p_event->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
 }
+
 void EventThreadUpdateTitle( event_thread_t *p_event, const char *psz_fallback )
 {
     char *psz_title = var_GetNonEmptyString( p_event->vd, "video-title" );
@@ -997,14 +1083,16 @@ event_thread_t *EventThreadCreate( vout_display_t *vd)
     vlc_mutex_init( &p_event->lock );
     vlc_cond_init( &p_event->wait );
 
-    p_event->b_cursor_hidden      = false;
-    p_event->i_lastmoved          = mdate();
-    p_event->i_mouse_hide_timeout =
-        var_GetInteger(vd, "mouse-hide-timeout") * 1000;
+    p_event->is_cursor_hidden = false;
+    p_event->button_pressed = 0;
     p_event->psz_title = NULL;
     p_event->source = vd->source;
-    vout_display_PlacePicture(&p_event->place, &vd->source, vd->cfg, true);
+    vout_display_PlacePicture(&p_event->place, &vd->source, vd->cfg, false);
 
+    _snprintf( p_event->class_main, sizeof(p_event->class_main)/sizeof(*p_event->class_main),
+               _T("VLC MSW %p"), p_event );
+    _snprintf( p_event->class_video, sizeof(p_event->class_video)/sizeof(*p_event->class_video),
+               _T("VLC MSW video %p"), p_event );
     return p_event;
 }