]> git.sesse.net Git - vlc/blobdiff - modules/video_output/directx/events.c
For consistency, remove references to vlc from libvlc
[vlc] / modules / video_output / directx / events.c
index 53579d69cd6a61dc6647ba60c8a051c499f466fe..4122baa1833e59aaa770c03caf01f846271653c2 100644 (file)
@@ -1,10 +1,10 @@
 /*****************************************************************************
  * events.c: Windows DirectX video output events handler
  *****************************************************************************
- * Copyright (C) 2001 VideoLAN
- * $Id: events.c,v 1.35 2003/12/23 15:27:50 gbazin Exp $
+ * Copyright (C) 2001-2004 the VideoLAN team
+ * $Id$
  *
- * Authors: Gildas Bazin <gbazin@netcourrier.com>
+ * Authors: Gildas Bazin <gbazin@videolan.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
 
 #include <ctype.h>                                              /* tolower() */
 #include <string.h>                                            /* strerror() */
 
+#ifndef _WIN32_WINNT
+#   define _WIN32_WINNT 0x0500
+#endif
+
 #include <vlc/vlc.h>
 #include <vlc/intf.h>
 #include <vlc/input.h>
 #include <windowsx.h>
 #include <shellapi.h>
 
+#ifdef MODULE_NAME_IS_vout_directx
 #include <ddraw.h>
+#endif
+#ifdef MODULE_NAME_IS_direct3d
+#include <d3d9.h>
+#endif
+#ifdef MODULE_NAME_IS_glwin32
+#include <GL/gl.h>
+#endif
 
 #include "vlc_keys.h"
 #include "vout.h"
@@ -51,7 +63,8 @@
 static int  DirectXCreateWindow( vout_thread_t *p_vout );
 static void DirectXCloseWindow ( vout_thread_t *p_vout );
 static long FAR PASCAL DirectXEventProc( HWND, UINT, WPARAM, LPARAM );
-static long FAR PASCAL DirectXVideoEventProc( HWND, UINT, WPARAM, LPARAM );
+
+static int Control( vout_thread_t *p_vout, int i_query, va_list args );
 
 static void DirectXPopupMenu( event_thread_t *p_event, vlc_bool_t b_open )
 {
@@ -76,14 +89,16 @@ static int DirectXConvertKey( int i_key );
  * The main goal of this thread is to isolate the Win32 PeekMessage function
  * because this one can block for a long time.
  *****************************************************************************/
-void DirectXEventThread( event_thread_t *p_event )
+void E_(DirectXEventThread)( event_thread_t *p_event )
 {
     MSG msg;
-    POINT old_mouse_pos = {0,0};
+    POINT old_mouse_pos = {0,0}, mouse_pos;
     vlc_value_t val;
     int i_width, i_height, i_x, i_y;
+    HMODULE hkernel32;
 
     /* Initialisation */
+    p_event->p_vout->pf_control = Control;
 
     /* Create a window for the video */
     /* Creating a window under Windows also initializes the thread's event
@@ -97,23 +112,29 @@ void DirectXEventThread( event_thread_t *p_event )
     /* Signal the creation of the window */
     vlc_thread_ready( p_event );
 
+    /* Set power management stuff */
+    if( (hkernel32 = GetModuleHandle( _T("KERNEL32") ) ) )
+    {
+        ULONG (WINAPI* OurSetThreadExecutionState)( ULONG );
+
+        OurSetThreadExecutionState = (ULONG (WINAPI*)( ULONG ))
+            GetProcAddress( hkernel32, _T("SetThreadExecutionState") );
+
+        if( OurSetThreadExecutionState )
+            /* Prevent monitor from powering off */
+            OurSetThreadExecutionState( ES_DISPLAY_REQUIRED | ES_CONTINUOUS );
+        else
+            msg_Dbg( p_event, "no support for SetThreadExecutionState()" );
+    }
+
     /* Main loop */
     /* GetMessage will sleep if there's no message in the queue */
-    while( !p_event->b_die && ( p_event->p_vout->p_sys->hparent ||
-           GetMessage( &msg, p_event->p_vout->p_sys->hwnd, 0, 0 ) ) )
+    while( !p_event->b_die && GetMessage( &msg, 0, 0, 0 ) )
     {
         /* Check if we are asked to exit */
         if( p_event->b_die )
             break;
 
-        if( p_event->p_vout->p_sys->hparent )
-        {
-            /* Parent window was created in another thread so we can't
-             * access the window messages. */
-            msleep( INTF_IDLE_SLEEP );
-            continue;
-        }
-
         switch( msg.message )
         {
 
@@ -123,25 +144,31 @@ void DirectXEventThread( event_thread_t *p_event )
                                p_event->p_vout->p_sys->i_window_height,
                                &i_x, &i_y, &i_width, &i_height );
 
-            if( msg.hwnd != p_event->p_vout->p_sys->hwnd )
+            if( msg.hwnd == p_event->p_vout->p_sys->hvideownd )
             {
                 /* Child window */
                 i_x = i_y = 0;
             }
 
-            val.i_int = ( GET_X_LPARAM(msg.lParam) - i_x )
-                         * p_event->p_vout->render.i_width / i_width;
-            var_Set( p_event->p_vout, "mouse-x", val );
-            val.i_int = ( GET_Y_LPARAM(msg.lParam) - i_y )
-                         * p_event->p_vout->render.i_height / i_height;
-            var_Set( p_event->p_vout, "mouse-y", val );
-
-            val.b_bool = VLC_TRUE;
-            var_Set( p_event->p_vout, "mouse-moved", val );
+            if( i_width && i_height )
+            {
+                val.i_int = ( GET_X_LPARAM(msg.lParam) - i_x ) *
+                    p_event->p_vout->fmt_in.i_visible_width / i_width +
+                    p_event->p_vout->fmt_in.i_x_offset;
+                var_Set( p_event->p_vout, "mouse-x", val );
+                val.i_int = ( GET_Y_LPARAM(msg.lParam) - i_y ) *
+                    p_event->p_vout->fmt_in.i_visible_height / i_height +
+                    p_event->p_vout->fmt_in.i_y_offset;
+                var_Set( p_event->p_vout, "mouse-y", val );
+
+                val.b_bool = VLC_TRUE;
+                var_Set( p_event->p_vout, "mouse-moved", val );
+            }
 
         case WM_NCMOUSEMOVE:
-            if( (abs(GET_X_LPARAM(msg.lParam) - old_mouse_pos.x) > 2 ||
-                (abs(GET_Y_LPARAM(msg.lParam) - old_mouse_pos.y)) > 2 ) )
+            GetCursorPos( &mouse_pos );
+            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->p_vout->p_sys->i_lastmoved = mdate();
@@ -155,10 +182,19 @@ void DirectXEventThread( event_thread_t *p_event )
             break;
 
         case WM_VLC_HIDE_MOUSE:
+            if( p_event->p_vout->p_sys->b_cursor_hidden ) break;
+            p_event->p_vout->p_sys->b_cursor_hidden = VLC_TRUE;
             GetCursorPos( &old_mouse_pos );
             ShowCursor( FALSE );
             break;
 
+        case WM_VLC_SHOW_MOUSE:
+            if( !p_event->p_vout->p_sys->b_cursor_hidden ) break;
+            p_event->p_vout->p_sys->b_cursor_hidden = VLC_FALSE;
+            GetCursorPos( &old_mouse_pos );
+            ShowCursor( TRUE );
+            break;
+
         case WM_LBUTTONDOWN:
             var_Get( p_event->p_vout, "mouse-button-down", &val );
             val.i_int |= 1;
@@ -233,19 +269,75 @@ void DirectXEventThread( event_thread_t *p_event )
                     val.i_int |= KEY_MODIFIER_ALT;
                 }
 
-                var_Set( p_event->p_vlc, "key-pressed", val );
+                var_Set( p_event->p_libvlc, "key-pressed", val );
+            }
+            break;
+
+        case WM_MOUSEWHEEL:
+            if( GET_WHEEL_DELTA_WPARAM( msg.wParam ) > 0 )
+            {
+                val.i_int = KEY_MOUSEWHEELUP;
+            }
+            else
+            {
+                val.i_int = KEY_MOUSEWHEELDOWN;
+            }
+            if( val.i_int )
+            {
+                if( GetKeyState(VK_CONTROL) & 0x8000 )
+                {
+                    val.i_int |= KEY_MODIFIER_CTRL;
+                }
+                if( GetKeyState(VK_SHIFT) & 0x8000 )
+                {
+                    val.i_int |= KEY_MODIFIER_SHIFT;
+                }
+                if( GetKeyState(VK_MENU) & 0x8000 )
+                {
+                    val.i_int |= KEY_MODIFIER_ALT;
+                }
+
+                var_Set( p_event->p_libvlc, "key-pressed", val );
             }
             break;
 
         case WM_VLC_CHANGE_TEXT:
-            if( p_event->p_vout->p_sys->b_using_overlay )
-                SetWindowText( p_event->p_vout->p_sys->hwnd,
-                    VOUT_TITLE " (hardware YUV overlay DirectX output)" );
-            else if( p_event->p_vout->p_sys->b_hw_yuv )
-                SetWindowText( p_event->p_vout->p_sys->hwnd,
-                    VOUT_TITLE " (hardware YUV DirectX output)" );
-            else SetWindowText( p_event->p_vout->p_sys->hwnd,
-                    VOUT_TITLE " (software RGB DirectX output)" );
+            var_Get( p_event->p_vout, "video-title", &val );
+            if( !val.psz_string || !*val.psz_string ) /* Default video title */
+            {
+                if( val.psz_string ) free( val.psz_string );
+
+#ifdef MODULE_NAME_IS_glwin32
+                val.psz_string = strdup( VOUT_TITLE " (OpenGL output)" );
+#endif
+#ifdef MODULE_NAME_IS_direct3d
+                val.psz_string = strdup( VOUT_TITLE " (Direct3D output)" );
+#endif
+#ifdef MODULE_NAME_IS_directx
+                if( p_event->p_vout->p_sys->b_using_overlay ) val.psz_string = 
+                strdup( VOUT_TITLE " (hardware YUV overlay DirectX output)" );
+                else if( p_event->p_vout->p_sys->b_hw_yuv ) val.psz_string = 
+                strdup( VOUT_TITLE " (hardware YUV DirectX output)" );
+                else val.psz_string = 
+                strdup( VOUT_TITLE " (software RGB DirectX output)" );
+#endif
+            }
+
+#ifdef UNICODE
+            {
+                wchar_t *psz_title = malloc( strlen(val.psz_string) * 2 + 2 );
+                mbstowcs( psz_title, val.psz_string, strlen(val.psz_string)*2);
+                psz_title[strlen(val.psz_string)] = 0;
+                free( val.psz_string ); val.psz_string = (char *)psz_title;
+            }
+#endif
+
+            SetWindowText( p_event->p_vout->p_sys->hwnd,
+                           (LPCTSTR)val.psz_string );
+            if( p_event->p_vout->p_sys->hfswnd )
+                SetWindowText( p_event->p_vout->p_sys->hfswnd,
+                               (LPCTSTR)val.psz_string );
+            free( val.psz_string );
             break;
 
         default:
@@ -259,7 +351,8 @@ void DirectXEventThread( event_thread_t *p_event )
 
     } /* End Main loop */
 
-    if( msg.message == WM_QUIT )
+    /* Check for WM_QUIT if we created the window */
+    if( !p_event->p_vout->p_sys->hparent && msg.message == WM_QUIT )
     {
         msg_Warn( p_event, "WM_QUIT... should not happen!!" );
         p_event->p_vout->p_sys->hwnd = NULL; /* Window already destroyed */
@@ -288,8 +381,10 @@ static int DirectXCreateWindow( vout_thread_t *p_vout )
     HINSTANCE  hInstance;
     HMENU      hMenu;
     RECT       rect_window;
-
-    vlc_value_t val;
+    WNDCLASS   wc;                            /* window class components */
+    HICON      vlc_icon = NULL;
+    char       vlc_path[MAX_PATH+1];
+    int        i_style, i_stylex;
 
     msg_Dbg( p_vout, "DirectXCreateWindow" );
 
@@ -297,124 +392,171 @@ static int DirectXCreateWindow( vout_thread_t *p_vout )
     hInstance = GetModuleHandle(NULL);
 
     /* If an external window was specified, we'll draw in it. */
-    var_Get( p_vout->p_vlc, "drawable", &val );
-    p_vout->p_sys->hparent = p_vout->p_sys->hwnd =
-             val.i_int ?  (void*)(ptrdiff_t) val.i_int : NULL;
-
-    if( p_vout->p_sys->hparent )
+    p_vout->p_sys->hparent =
+        vout_RequestWindow( p_vout, &p_vout->p_sys->i_window_x,
+                            &p_vout->p_sys->i_window_y,
+                            &p_vout->p_sys->i_window_width,
+                            &p_vout->p_sys->i_window_height );
+
+    /* We create the window ourself, there is no previous window proc. */
+    p_vout->p_sys->pf_wndproc = NULL;
+
+    /* Get the Icon from the main app */
+    vlc_icon = NULL;
+#ifndef UNDER_CE
+    if( GetModuleFileName( NULL, vlc_path, MAX_PATH ) )
     {
-        msg_Dbg( p_vout, "using external window %p\n", p_vout->p_sys->hwnd );
-
-        /* Set stuff in the window that we can not put directly in
-         * a class (see below). */
-        SetClassLong( p_vout->p_sys->hwnd,
-                      GCL_STYLE, CS_DBLCLKS );
-        SetClassLong( p_vout->p_sys->hwnd,
-                      GCL_HBRBACKGROUND, (LONG)GetStockObject(BLACK_BRUSH) );
-        SetClassLong( p_vout->p_sys->hwnd,
-                      GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_ARROW) );
-        /* Store a p_vout pointer into the window local storage (for later
-         * use in DirectXEventProc). */
-        SetWindowLong( p_vout->p_sys->hwnd, GWL_USERDATA, (LONG)p_vout );
-
-        p_vout->p_sys->pf_wndproc =
-               (WNDPROC)SetWindowLong( p_vout->p_sys->hwnd,
-                                       GWL_WNDPROC, (LONG)DirectXEventProc );
-
-        /* Blam! Erase everything that might have been there. */
-        InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE );
+        vlc_icon = ExtractIcon( hInstance, vlc_path, 0 );
     }
-    else
+#endif
+
+    /* Fill in the window class structure */
+    wc.style         = CS_OWNDC|CS_DBLCLKS;          /* style: dbl click */
+    wc.lpfnWndProc   = (WNDPROC)DirectXEventProc;       /* event handler */
+    wc.cbClsExtra    = 0;                         /* no extra class data */
+    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.hbrBackground = GetStockObject(BLACK_BRUSH);  /* background color */
+    wc.lpszMenuName  = NULL;                                  /* no menu */
+    wc.lpszClassName = _T("VLC DirectX");         /* use a special class */
+
+    /* Register the window class */
+    if( !RegisterClass(&wc) )
     {
-        WNDCLASSEX wc;                            /* window class components */
-        HICON      vlc_icon = NULL;
-        char       vlc_path[MAX_PATH+1];
+        WNDCLASS wndclass;
 
-        /* Get the Icon from the main app */
-        vlc_icon = NULL;
-        if( GetModuleFileName( NULL, vlc_path, MAX_PATH ) )
-        {
-            vlc_icon = ExtractIcon( hInstance, vlc_path, 0 );
-        }
+        if( vlc_icon ) DestroyIcon( vlc_icon );
 
-        /* Fill in the window class structure */
-        wc.cbSize        = sizeof(WNDCLASSEX);
-        wc.style         = CS_DBLCLKS;                   /* style: dbl click */
-        wc.lpfnWndProc   = (WNDPROC)DirectXEventProc;       /* event handler */
-        wc.cbClsExtra    = 0;                         /* no extra class data */
-        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.hbrBackground = GetStockObject(BLACK_BRUSH);  /* background color */
-        wc.lpszMenuName  = NULL;                                  /* no menu */
-        wc.lpszClassName = "VLC DirectX";             /* use a special class */
-        wc.hIconSm       = vlc_icon;              /* load the vlc small icon */
-
-        /* Register the window class */
-        if( !RegisterClassEx(&wc) )
+        /* 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 ) )
         {
-            WNDCLASS wndclass;
+            msg_Err( p_vout, "DirectXCreateWindow RegisterClass FAILED" );
+            return VLC_EGENERIC;
+        }
+    }
 
-            if( vlc_icon )
-            {
-                DestroyIcon( vlc_icon );
-            }
+    /* Register the video sub-window class */
+    wc.lpszClassName = _T("VLC DirectX video"); wc.hIcon = 0;
+    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, "VLC DirectX", &wndclass ) )
-            {
-                msg_Err( p_vout, "DirectXCreateWindow RegisterClass FAILED" );
-                return VLC_EGENERIC;
-            }
+        /* 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( p_vout, "DirectXCreateWindow RegisterClass FAILED" );
+            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.right  = rect_window.left + p_vout->p_sys->i_window_width;
+    rect_window.bottom = rect_window.top + p_vout->p_sys->i_window_height;
 
-        /* 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.right  = rect_window.left + p_vout->p_sys->i_window_width;
-        rect_window.bottom = rect_window.top + p_vout->p_sys->i_window_height;
+    if( var_GetBool( p_vout, "video-deco" ) )
+    {
+        /* Open with window decoration */
         AdjustWindowRect( &rect_window, WS_OVERLAPPEDWINDOW|WS_SIZEBOX, 0 );
+        i_style = WS_OVERLAPPEDWINDOW|WS_SIZEBOX|WS_VISIBLE|WS_CLIPCHILDREN;
+        i_stylex = 0;
+    }
+    else
+    {
+        /* No window decoration */
+        AdjustWindowRect( &rect_window, WS_POPUP, 0 );
+        i_style = WS_POPUP|WS_VISIBLE|WS_CLIPCHILDREN;
+        i_stylex = 0; // WS_EX_TOOLWINDOW; Is TOOLWINDOW really needed ?
+                      // It messes up the fullscreen window.
+    }
 
-        /* Create the window */
-        p_vout->p_sys->hwnd =
-            CreateWindow( "VLC DirectX",             /* name of window class */
-                    VOUT_TITLE " (DirectX Output)", /* window title bar text */
-                    WS_OVERLAPPEDWINDOW | WS_SIZEBOX | WS_VISIBLE |
-                    WS_CLIPCHILDREN,                         /* window style */
-                    CW_USEDEFAULT,                   /* default X coordinate */
-                    0,                               /* default Y coordinate */
+    if( p_vout->p_sys->hparent )
+    {
+        i_style = WS_VISIBLE|WS_CLIPCHILDREN|WS_CHILD;
+        i_stylex = 0;
+    }
+
+    p_vout->p_sys->i_window_style = i_style;
+
+    /* Create the window */
+    p_vout->p_sys->hwnd =
+        CreateWindowEx( WS_EX_NOPARENTNOTIFY | i_stylex,
+                    _T("VLC DirectX"),               /* name of window class */
+                    _T(VOUT_TITLE) _T(" (DirectX Output)"),  /* window title */
+                    i_style,                                 /* window style */
+                    (p_vout->p_sys->i_window_x < 0) ? CW_USEDEFAULT :
+                        (UINT)p_vout->p_sys->i_window_x,   /* default X coordinate */
+                    (p_vout->p_sys->i_window_y < 0) ? CW_USEDEFAULT :
+                        (UINT)p_vout->p_sys->i_window_y,   /* default Y coordinate */
                     rect_window.right - rect_window.left,    /* window width */
                     rect_window.bottom - rect_window.top,   /* window height */
-                    NULL,                                /* no parent window */
+                    p_vout->p_sys->hparent,                 /* parent window */
                     NULL,                          /* no menu in this window */
                     hInstance,            /* handle of this program instance */
                     (LPVOID)p_vout );            /* send p_vout to WM_CREATE */
 
-        if( !p_vout->p_sys->hwnd )
-        {
-            msg_Warn( p_vout, "DirectXCreateWindow create window FAILED" );
-            return VLC_EGENERIC;
-        }
+    if( !p_vout->p_sys->hwnd )
+    {
+        msg_Warn( p_vout, "DirectXCreateWindow create window FAILED" );
+        return VLC_EGENERIC;
     }
 
-    /* Now display the window */
-    ShowWindow( p_vout->p_sys->hwnd, SW_SHOW );
+    if( p_vout->p_sys->hparent )
+    {
+        LONG i_style;
+
+        /* We don't want the window owner to overwrite our client area */
+        i_style = GetWindowLong( p_vout->p_sys->hparent, GWL_STYLE );
+
+        if( !(i_style & WS_CLIPCHILDREN) )
+            /* Hmmm, apparently this is a blocking call... */
+            SetWindowLong( p_vout->p_sys->hparent, GWL_STYLE,
+                           i_style | WS_CLIPCHILDREN );
+
+        /* Create our fullscreen window */
+        p_vout->p_sys->hfswnd =
+            CreateWindowEx( WS_EX_APPWINDOW, _T("VLC DirectX"),
+                            _T(VOUT_TITLE) _T(" (DirectX Output)"),
+                            WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_SIZEBOX,
+                            CW_USEDEFAULT, CW_USEDEFAULT,
+                            CW_USEDEFAULT, CW_USEDEFAULT,
+                            NULL, NULL, hInstance, NULL );
+    }
+
+    /* Append a "Always On Top" entry in the system menu */
+    hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
+    AppendMenu( hMenu, MF_SEPARATOR, 0, _T("") );
+    AppendMenu( hMenu, MF_STRING | MF_UNCHECKED,
+                       IDM_TOGGLE_ON_TOP, _T("Always on &Top") );
 
     /* Create video sub-window. This sub window will always exactly match
      * the size of the video, which allows us to use crazy overlay colorkeys
      * without having them shown outside of the video area. */
-    SendMessage( p_vout->p_sys->hwnd, WM_VLC_CREATE_VIDEO_WIN, 0, 0 );
+    p_vout->p_sys->hvideownd =
+       CreateWindow( _T("VLC DirectX video"), _T(""),   /* window class */
+               WS_CHILD | WS_VISIBLE,                   /* window style */
+               0, 0,
+               p_vout->render.i_width,                 /* default width */
+               p_vout->render.i_height,                /* default height */
+               p_vout->p_sys->hwnd,                    /* parent window */
+               NULL, hInstance,
+               (LPVOID)p_vout );            /* send p_vout to WM_CREATE */
+
+    if( !p_vout->p_sys->hvideownd )
+       msg_Warn( p_vout, "can't create video sub-window" );
+    else
+       msg_Dbg( p_vout, "created video sub-window" );
 
-    /* Append a "Always On Top" entry in the system menu */
-    hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
-    AppendMenu( hMenu, MF_SEPARATOR, 0, "" );
-    AppendMenu( hMenu, MF_STRING | MF_UNCHECKED,
-                       IDM_TOGGLE_ON_TOP, "Always on &Top" );
+    /* Now display the window */
+    ShowWindow( p_vout->p_sys->hwnd, SW_SHOW );
 
     return VLC_SUCCESS;
 }
@@ -428,23 +570,11 @@ static void DirectXCloseWindow( vout_thread_t *p_vout )
 {
     msg_Dbg( p_vout, "DirectXCloseWindow" );
 
-    if( p_vout->p_sys->hwnd && !p_vout->p_sys->hparent )
-    {
-        DestroyWindow( p_vout->p_sys->hwnd );
-    }
-    else if( p_vout->p_sys->hparent )
-    {
-        /* Get rid of the video sub-window */
-        PostMessage( p_vout->p_sys->hvideownd, WM_VLC_DESTROY_VIDEO_WIN, 0, 0);
-
-        /* We don't want our windowproc to be called anymore */
-        SetWindowLong( p_vout->p_sys->hwnd,
-                       GWL_WNDPROC, (LONG)p_vout->p_sys->pf_wndproc );
-        SetWindowLong( p_vout->p_sys->hwnd, GWL_USERDATA, (LONG)NULL );
+    DestroyWindow( p_vout->p_sys->hwnd );
+    if( p_vout->p_sys->hfswnd ) DestroyWindow( p_vout->p_sys->hfswnd );
 
-        /* Blam! Erase everything that might have been there. */
-        InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE );
-    }
+    if( p_vout->p_sys->hparent )
+        vout_ReleaseWindow( p_vout, (void *)p_vout->p_sys->hparent );
 
     p_vout->p_sys->hwnd = NULL;
 
@@ -460,7 +590,7 @@ static void DirectXCloseWindow( vout_thread_t *p_vout )
  * its job is to update the source and destination RECTs used to display the
  * picture.
  *****************************************************************************/
-void DirectXUpdateRects( vout_thread_t *p_vout, vlc_bool_t b_force )
+void E_(DirectXUpdateRects)( vout_thread_t *p_vout, vlc_bool_t b_force )
 {
 #define rect_src p_vout->p_sys->rect_src
 #define rect_src_clipped p_vout->p_sys->rect_src_clipped
@@ -498,8 +628,9 @@ void DirectXUpdateRects( vout_thread_t *p_vout, vlc_bool_t b_force )
     vout_PlacePicture( p_vout, rect.right, rect.bottom,
                        &i_x, &i_y, &i_width, &i_height );
 
-    SetWindowPos( p_vout->p_sys->hvideownd, HWND_TOP,
-                  i_x, i_y, i_width, i_height, 0 );
+    if( p_vout->p_sys->hvideownd )
+        SetWindowPos( p_vout->p_sys->hvideownd, HWND_TOP,
+                      i_x, i_y, i_width, i_height, 0 );
 
     /* Destination image position and dimensions */
     rect_dest.left = point.x + i_x;
@@ -507,6 +638,22 @@ void DirectXUpdateRects( vout_thread_t *p_vout, vlc_bool_t b_force )
     rect_dest.top = point.y + i_y;
     rect_dest.bottom = rect_dest.top + i_height;
 
+#ifdef MODULE_NAME_IS_vout_directx
+    /* Apply overlay hardware constraints */
+    if( p_vout->p_sys->b_using_overlay )
+    {
+        if( p_vout->p_sys->i_align_dest_boundary )
+            rect_dest.left = ( rect_dest.left +
+                p_vout->p_sys->i_align_dest_boundary / 2 ) & 
+                ~p_vout->p_sys->i_align_dest_boundary;
+
+        if( p_vout->p_sys->i_align_dest_size )
+            rect_dest.right = (( rect_dest.right - rect_dest.left +
+                p_vout->p_sys->i_align_dest_size / 2 ) & 
+                ~p_vout->p_sys->i_align_dest_size) + rect_dest.left;
+    }
+#endif
+
     /* UpdateOverlay directdraw function doesn't automatically clip to the
      * display size so we need to do it otherwise it will fail */
 
@@ -540,16 +687,44 @@ void DirectXUpdateRects( vout_thread_t *p_vout, vlc_bool_t b_force )
     rect_src.bottom = p_vout->render.i_height;
 
     /* Clip the source image */
-    rect_src_clipped.left = (rect_dest_clipped.left - rect_dest.left) *
-      p_vout->render.i_width / (rect_dest.right - rect_dest.left);
-    rect_src_clipped.right = p_vout->render.i_width -
-      (rect_dest.right - rect_dest_clipped.right) * p_vout->render.i_width /
-      (rect_dest.right - rect_dest.left);
-    rect_src_clipped.top = (rect_dest_clipped.top - rect_dest.top) *
-      p_vout->render.i_height / (rect_dest.bottom - rect_dest.top);
-    rect_src_clipped.bottom = p_vout->render.i_height -
-      (rect_dest.bottom - rect_dest_clipped.bottom) * p_vout->render.i_height /
-      (rect_dest.bottom - rect_dest.top);
+    rect_src_clipped.left = p_vout->fmt_out.i_x_offset +
+      (rect_dest_clipped.left - rect_dest.left) *
+      p_vout->fmt_out.i_visible_width / (rect_dest.right - rect_dest.left);
+    rect_src_clipped.right = p_vout->fmt_out.i_x_offset +
+      p_vout->fmt_out.i_visible_width -
+      (rect_dest.right - rect_dest_clipped.right) *
+      p_vout->fmt_out.i_visible_width / (rect_dest.right - rect_dest.left);
+    rect_src_clipped.top = p_vout->fmt_out.i_y_offset +
+      (rect_dest_clipped.top - rect_dest.top) *
+      p_vout->fmt_out.i_visible_height / (rect_dest.bottom - rect_dest.top);
+    rect_src_clipped.bottom = p_vout->fmt_out.i_y_offset +
+      p_vout->fmt_out.i_visible_height -
+      (rect_dest.bottom - rect_dest_clipped.bottom) *
+      p_vout->fmt_out.i_visible_height / (rect_dest.bottom - rect_dest.top);
+
+#ifdef MODULE_NAME_IS_vout_directx
+    /* Apply overlay hardware constraints */
+    if( p_vout->p_sys->b_using_overlay )
+    {
+        if( p_vout->p_sys->i_align_src_boundary )
+            rect_src_clipped.left = ( rect_src_clipped.left +
+                p_vout->p_sys->i_align_src_boundary / 2 ) & 
+                ~p_vout->p_sys->i_align_src_boundary;
+
+        if( p_vout->p_sys->i_align_src_size )
+            rect_src_clipped.right = (( rect_src_clipped.right -
+                rect_src_clipped.left +
+                p_vout->p_sys->i_align_src_size / 2 ) & 
+                ~p_vout->p_sys->i_align_src_size) + rect_src_clipped.left;
+    }
+#endif
+
+#if 0
+    msg_Dbg( p_vout, "DirectXUpdateRects image_src_clipped"
+                     " coords: %i,%i,%i,%i",
+                     rect_src_clipped.left, rect_src_clipped.top,
+                     rect_src_clipped.right, rect_src_clipped.bottom );
+#endif
 
     /* The destination coordinates need to be relative to the current
      * directdraw primary surface (display) */
@@ -558,11 +733,9 @@ void DirectXUpdateRects( vout_thread_t *p_vout, vlc_bool_t b_force )
     rect_dest_clipped.top -= p_vout->p_sys->rect_display.top;
     rect_dest_clipped.bottom -= p_vout->p_sys->rect_display.top;
 
-#if 0
-    msg_Dbg( p_vout, "DirectXUpdateRects image_src_clipped"
-                     " coords: %i,%i,%i,%i",
-                     rect_src_clipped.left, rect_src_clipped.top,
-                     rect_src_clipped.right, rect_src_clipped.bottom );
+#ifdef MODULE_NAME_IS_vout_directx
+    if( p_vout->p_sys->b_using_overlay )
+        E_(DirectXUpdateOverlay)( p_vout );
 #endif
 
     /* Signal the change in size/position */
@@ -594,11 +767,19 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
     {
         /* Store p_vout for future use */
         p_vout = (vout_thread_t *)((CREATESTRUCT *)lParam)->lpCreateParams;
-        SetWindowLong( hwnd, GWL_USERDATA, (LONG)p_vout );
+        SetWindowLongPtr( hwnd, GWLP_USERDATA, (LONG_PTR)p_vout );
     }
     else
     {
-        p_vout = (vout_thread_t *)GetWindowLong( hwnd, GWL_USERDATA );
+        p_vout = (vout_thread_t *)GetWindowLongPtr( hwnd, GWLP_USERDATA );
+    }
+
+    /* Catch the screensaver and the monitor turn-off */
+    if( message == WM_SYSCOMMAND &&
+        ( (wParam & 0xFFF0) == SC_SCREENSAVE || (wParam & 0xFFF0) == SC_MONITORPOWER ) )
+    {
+        //if( p_vout ) msg_Dbg( p_vout, "WinProc WM_SYSCOMMAND screensaver" );
+        return 0; /* this stops them from happening */
     }
 
     if( !p_vout )
@@ -608,11 +789,14 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
         return DefWindowProc(hwnd, message, wParam, lParam);
     }
 
+    if( hwnd == p_vout->p_sys->hvideownd )
+        return DefWindowProc(hwnd, message, wParam, lParam);
+
     switch( message )
     {
 
     case WM_WINDOWPOSCHANGED:
-        DirectXUpdateRects( p_vout, VLC_TRUE );
+        E_(DirectXUpdateRects)( p_vout, VLC_TRUE );
         return 0;
 
     /* the user wants to close the window */
@@ -641,47 +825,26 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
     case WM_SYSCOMMAND:
         switch (wParam)
         {
-            case SC_SCREENSAVE:                     /* catch the screensaver */
-            case SC_MONITORPOWER:              /* catch the monitor turn-off */
-                msg_Dbg( p_vout, "WinProc WM_SYSCOMMAND" );
-                return 0;                  /* this stops them from happening */
             case IDM_TOGGLE_ON_TOP:            /* toggle the "on top" status */
             {
                 vlc_value_t val;
                 msg_Dbg( p_vout, "WinProc WM_SYSCOMMAND: IDM_TOGGLE_ON_TOP");
 
-                /* Get the current value... */
-                if( var_Get( p_vout, "video-on-top", &val ) < 0 )
-                    return 0;
-                /* ...and change it */
+                /* Change the current value */
+                var_Get( p_vout, "video-on-top", &val );
                 val.b_bool = !val.b_bool;
                 var_Set( p_vout, "video-on-top", val );
                 return 0;
-                break;
             }
         }
         break;
 
-    case WM_VLC_CREATE_VIDEO_WIN:
-        /* Create video sub-window */
-        p_vout->p_sys->hvideownd =
-            CreateWindow( "STATIC", "",   /* window class and title bar text */
-                    WS_CHILD | WS_VISIBLE,                   /* window style */
-                    CW_USEDEFAULT, CW_USEDEFAULT,     /* default coordinates */
-                    CW_USEDEFAULT, CW_USEDEFAULT,
-                    hwnd,                                   /* parent window */
-                    NULL, GetModuleHandle(NULL), NULL );
-
-        if( !p_vout->p_sys->hvideownd )
-        {
-            msg_Warn( p_vout, "Can't create video sub-window" );
-        }
-        else
-        {
-            msg_Warn( p_vout, "Created video sub-window" );
-            SetWindowLong( p_vout->p_sys->hvideownd,
-                           GWL_WNDPROC, (LONG)DirectXVideoEventProc );
-        }
+    case WM_PAINT:
+    case WM_NCPAINT:
+    case WM_ERASEBKGND:
+        /* We do not want to relay these messages to the parent window
+         * because we rely on the background color for the overlay. */
+        return DefWindowProc(hwnd, message, wParam, lParam);
         break;
 
     default:
@@ -689,19 +852,7 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
         break;
     }
 
-    return DefWindowProc(hwnd, message, wParam, lParam);
-}
-static long FAR PASCAL DirectXVideoEventProc( HWND hwnd, UINT message,
-                                              WPARAM wParam, LPARAM lParam )
-{
-    switch( message )
-    {
-    case WM_VLC_DESTROY_VIDEO_WIN:
-        /* Destroy video sub-window */
-        DestroyWindow( hwnd );
-        break;
-    }
-
+    /* Let windows handle the message */
     return DefWindowProc(hwnd, message, wParam, lParam);
 }
 
@@ -731,10 +882,28 @@ static struct
     { VK_PRIOR, KEY_PAGEUP },
     { VK_NEXT, KEY_PAGEDOWN },
 
+    { VK_INSERT, KEY_INSERT },
+    { VK_DELETE, KEY_DELETE },
+
     { VK_CONTROL, 0 },
     { VK_SHIFT, 0 },
     { VK_MENU, 0 },
 
+    { VK_BROWSER_BACK, KEY_BROWSER_BACK },
+    { VK_BROWSER_FORWARD, KEY_BROWSER_FORWARD },
+    { VK_BROWSER_REFRESH, KEY_BROWSER_REFRESH },
+    { VK_BROWSER_STOP, KEY_BROWSER_STOP },
+    { VK_BROWSER_SEARCH, KEY_BROWSER_SEARCH },
+    { VK_BROWSER_FAVORITES, KEY_BROWSER_FAVORITES },
+    { VK_BROWSER_HOME, KEY_BROWSER_HOME },
+    { VK_VOLUME_MUTE, KEY_VOLUME_MUTE },
+    { VK_VOLUME_DOWN, KEY_VOLUME_DOWN },
+    { VK_VOLUME_UP, KEY_VOLUME_UP },
+    { VK_MEDIA_NEXT_TRACK, KEY_MEDIA_NEXT_TRACK },
+    { VK_MEDIA_PREV_TRACK, KEY_MEDIA_PREV_TRACK },
+    { VK_MEDIA_STOP, KEY_MEDIA_STOP },
+    { VK_MEDIA_PLAY_PAUSE, KEY_MEDIA_PLAY_PAUSE },
+
     { 0, 0 }
 };
 
@@ -752,3 +921,84 @@ static int DirectXConvertKey( int i_key )
 
     return 0;
 }
+
+/*****************************************************************************
+ * Control: control facility for the vout
+ *****************************************************************************/
+static int Control( vout_thread_t *p_vout, int i_query, va_list args )
+{
+    unsigned int *pi_width, *pi_height;
+    RECT rect_window;
+    POINT point;
+
+    switch( i_query )
+    {
+    case VOUT_GET_SIZE:
+        if( p_vout->p_sys->hparent )
+            return vout_ControlWindow( p_vout,
+                    (void *)p_vout->p_sys->hparent, i_query, args );
+
+        pi_width  = va_arg( args, unsigned int * );
+        pi_height = va_arg( args, unsigned int * );
+
+        GetClientRect( p_vout->p_sys->hwnd, &rect_window );
+
+        *pi_width  = rect_window.right - rect_window.left;
+        *pi_height = rect_window.bottom - rect_window.top;
+        return VLC_SUCCESS;
+
+    case VOUT_SET_SIZE:
+        if( p_vout->p_sys->hparent )
+            return vout_ControlWindow( p_vout,
+                    (void *)p_vout->p_sys->hparent, i_query, args );
+
+        /* Update dimensions */
+        rect_window.top = rect_window.left = 0;
+        rect_window.right  = va_arg( args, unsigned int );
+        rect_window.bottom = va_arg( args, unsigned int );
+        if( !rect_window.right ) rect_window.right = p_vout->i_window_width;
+        if( !rect_window.bottom ) rect_window.bottom = p_vout->i_window_height;
+        AdjustWindowRect( &rect_window, p_vout->p_sys->i_window_style, 0 );
+
+        SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
+                      rect_window.right - rect_window.left,
+                      rect_window.bottom - rect_window.top, SWP_NOMOVE );
+
+        return VLC_SUCCESS;
+
+    case VOUT_CLOSE:
+        ShowWindow( p_vout->p_sys->hwnd, SW_HIDE );
+    case VOUT_REPARENT:
+        /* Change window style, borders and title bar */
+        vlc_mutex_lock( &p_vout->p_sys->lock );
+        p_vout->p_sys->hparent = 0;
+        vlc_mutex_unlock( &p_vout->p_sys->lock );
+
+        /* Retrieve the window position */
+        point.x = point.y = 0;
+        ClientToScreen( p_vout->p_sys->hwnd, &point );
+
+        SetParent( p_vout->p_sys->hwnd, 0 );
+        p_vout->p_sys->i_window_style =
+            WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW | WS_SIZEBOX;
+        SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE,
+                       p_vout->p_sys->i_window_style |
+                       (i_query == VOUT_CLOSE ? 0 : WS_VISIBLE) );
+        SetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE, WS_EX_APPWINDOW );
+        SetWindowPos( p_vout->p_sys->hwnd, 0, point.x, point.y, 0, 0,
+                      SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED );
+
+        return vout_vaControlDefault( p_vout, i_query, args );
+
+    case VOUT_SET_STAY_ON_TOP:
+        if( p_vout->p_sys->hparent )
+            return vout_ControlWindow( p_vout,
+                    (void *)p_vout->p_sys->hparent, i_query, args );
+
+        p_vout->p_sys->b_on_top_change = VLC_TRUE;
+        return VLC_SUCCESS;
+
+    default:
+        return vout_vaControlDefault( p_vout, i_query, args );
+    }
+}