]> git.sesse.net Git - vlc/blobdiff - modules/video_output/directx/events.c
* modules/misc/freetype.c: don't use the pitch of the picture to calculate the text...
[vlc] / modules / video_output / directx / events.c
index 60c08c31cfacdffa9fb9ed277803dc0a2d7d18ea..62d78cc3d463d6422ed0581feddc8c42664110e8 100644 (file)
@@ -2,7 +2,7 @@
  * events.c: Windows DirectX video output events handler
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: events.c,v 1.3 2002/10/06 19:28:28 gbazin Exp $
+ * $Id: events.c,v 1.27 2003/10/29 12:23:51 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  *
  *****************************************************************************/
 #include <errno.h>                                                 /* ENOMEM */
 #include <stdlib.h>                                                /* free() */
+#include <ctype.h>                                              /* tolower() */
 #include <string.h>                                            /* strerror() */
 
 #include <vlc/vlc.h>
 #include <vlc/intf.h>
+#include <vlc/input.h>
 #include <vlc/vout.h>
 
-#include "netutils.h"
-
 #include <windows.h>
 #include <windowsx.h>
 #include <shellapi.h>
 
 #include <ddraw.h>
 
+#include "vlc_keys.h"
 #include "vout.h"
 
 /*****************************************************************************
  *****************************************************************************/
 static int  DirectXCreateWindow( vout_thread_t *p_vout );
 static void DirectXCloseWindow ( vout_thread_t *p_vout );
-static void DirectXUpdateRects( vout_thread_t *p_vout );
 static long FAR PASCAL DirectXEventProc ( HWND hwnd, UINT message,
                                           WPARAM wParam, LPARAM lParam );
 
+static void DirectXPopupMenu( event_thread_t *p_event, vlc_bool_t b_open )
+{
+    playlist_t *p_playlist =
+        vlc_object_find( p_event, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
+    if( p_playlist != NULL )
+    {
+        vlc_value_t val;
+        val.b_bool = b_open;
+        var_Set( p_playlist, "intf-popupmenu", val );
+        vlc_object_release( p_playlist );
+    }
+}
+
+static int DirectXConvertKey( int i_key );
+
 /*****************************************************************************
  * DirectXEventThread: Create video window & handle its messages
  *****************************************************************************
@@ -64,17 +79,19 @@ static long FAR PASCAL DirectXEventProc ( HWND hwnd, UINT message,
 void DirectXEventThread( event_thread_t *p_event )
 {
     MSG msg;
-    POINT old_mouse_pos;
+    POINT old_mouse_pos = {0,0};
+    vlc_value_t val;
+    int i_width, i_height, i_x, i_y;
 
     /* Initialisation */
 
     /* Create a window for the video */
     /* Creating a window under Windows also initializes the thread's event
-     * message qeue */
+     * message queue */
     if( DirectXCreateWindow( p_event->p_vout ) )
     {
         msg_Err( p_event, "out of memory" );
-        p_event->b_dead = 1;
+        p_event->b_dead = VLC_TRUE;
     }
 
     /* signal the creation of the window */
@@ -82,18 +99,35 @@ void DirectXEventThread( event_thread_t *p_event )
 
     /* Main loop */
     /* GetMessage will sleep if there's no message in the queue */
-    while( !p_event->b_die
-           && GetMessage( &msg, p_event->p_vout->p_sys->hwnd, 0, 0 ) )
+    while( !p_event->b_die && ( p_event->p_vout->p_sys->hparent ||
+           GetMessage( &msg, p_event->p_vout->p_sys->hwnd, 0, 0 ) ) )
     {
         /* Check if we are asked to exit */
         if( p_event->b_die )
             break;
 
+        if( p_event->p_vout->p_sys->hparent ) msleep( INTF_IDLE_SLEEP );
+
         switch( msg.message )
         {
 
         case WM_NCMOUSEMOVE:
         case WM_MOUSEMOVE:
+            vout_PlacePicture( p_event->p_vout,
+                               p_event->p_vout->p_sys->i_window_width,
+                               p_event->p_vout->p_sys->i_window_height,
+                               &i_x, &i_y, &i_width, &i_height );
+
+            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( (abs(GET_X_LPARAM(msg.lParam) - old_mouse_pos.x) > 2 ||
                 (abs(GET_Y_LPARAM(msg.lParam) - old_mouse_pos.y)) > 2 ) )
             {
@@ -113,94 +147,82 @@ void DirectXEventThread( event_thread_t *p_event )
             ShowCursor( FALSE );
             break;
 
-        case WM_RBUTTONUP:
-            {
-                intf_thread_t *p_intf;
-                p_intf = vlc_object_find( p_event, VLC_OBJECT_INTF,
-                                                   FIND_ANYWHERE );
-                if( p_intf )
-                {
-                    p_intf->b_menu_change = 1;
-                    vlc_object_release( p_intf );
-                }
-            }
+        case WM_LBUTTONDOWN:
+            var_Get( p_event->p_vout, "mouse-button-down", &val );
+            val.i_int |= 1;
+            var_Set( p_event->p_vout, "mouse-button-down", val );
+            DirectXPopupMenu( p_event, VLC_FALSE );
             break;
 
-        case WM_LBUTTONDOWN:
+        case WM_LBUTTONUP:
+            var_Get( p_event->p_vout, "mouse-button-down", &val );
+            val.i_int &= ~1;
+            var_Set( p_event->p_vout, "mouse-button-down", val );
+
+            val.b_bool = VLC_TRUE;
+            var_Set( p_event->p_vout, "mouse-clicked", val );
             break;
 
         case WM_LBUTTONDBLCLK:
             p_event->p_vout->p_sys->i_changes |= VOUT_FULLSCREEN_CHANGE;
             break;
 
-        case WM_KEYDOWN:
-            /* the key events are first processed here. The next
-             * message processed by this main message loop will be the
-             * char translation of the key event */
-            msg_Dbg( p_event, "WM_KEYDOWN" );
-            switch( msg.wParam )
-            {
-            case VK_ESCAPE:
-                /* exit application */
-                p_event->p_vlc->b_die = 1;
-                break;
-
-            case VK_F1: network_ChannelJoin( p_event, 1 ); break;
-            case VK_F2: network_ChannelJoin( p_event, 2 ); break;
-            case VK_F3: network_ChannelJoin( p_event, 3 ); break;
-            case VK_F4: network_ChannelJoin( p_event, 4 ); break;
-            case VK_F5: network_ChannelJoin( p_event, 5 ); break;
-            case VK_F6: network_ChannelJoin( p_event, 6 ); break;
-            case VK_F7: network_ChannelJoin( p_event, 7 ); break;
-            case VK_F8: network_ChannelJoin( p_event, 8 ); break;
-            case VK_F9: network_ChannelJoin( p_event, 9 ); break;
-            case VK_F10: network_ChannelJoin( p_event, 10 ); break;
-            case VK_F11: network_ChannelJoin( p_event, 11 ); break;
-            case VK_F12: network_ChannelJoin( p_event, 12 ); break;
-            }
-            TranslateMessage(&msg);
+        case WM_MBUTTONDOWN:
+            var_Get( p_event->p_vout, "mouse-button-down", &val );
+            val.i_int |= 2;
+            var_Set( p_event->p_vout, "mouse-button-down", val );
+            DirectXPopupMenu( p_event, VLC_FALSE );
             break;
 
-        case WM_CHAR:
-            switch( msg.wParam )
-            {
-            case 'q':
-            case 'Q':
-                /* exit application */
-                p_event->p_vlc->b_die = 1;
-                break;
-
-            case 'f':                            /* switch to fullscreen */
-            case 'F':
-                p_event->p_vout->p_sys->i_changes |= VOUT_FULLSCREEN_CHANGE;
-                break;
+        case WM_MBUTTONUP:
+            var_Get( p_event->p_vout, "mouse-button-down", &val );
+            val.i_int &= ~2;
+            var_Set( p_event->p_vout, "mouse-button-down", val );
+            break;
 
-            case 'c':                                /* toggle grayscale */
-            case 'C':
-                p_event->p_vout->b_grayscale = ! p_event->p_vout->b_grayscale;
-                p_event->p_vout->p_sys->i_changes |= VOUT_GRAYSCALE_CHANGE;
-                break;
+        case WM_RBUTTONDOWN:
+            var_Get( p_event->p_vout, "mouse-button-down", &val );
+            val.i_int |= 4;
+            var_Set( p_event->p_vout, "mouse-button-down", val );
+            DirectXPopupMenu( p_event, VLC_FALSE );
+            break;
 
-            case 'i':                                     /* toggle info */
-            case 'I':
-                p_event->p_vout->b_info = ! p_event->p_vout->b_info;
-                p_event->p_vout->p_sys->i_changes |= VOUT_INFO_CHANGE;
-                break;
+        case WM_RBUTTONUP:
+            var_Get( p_event->p_vout, "mouse-button-down", &val );
+            val.i_int &= ~4;
+            var_Set( p_event->p_vout, "mouse-button-down", val );
+            DirectXPopupMenu( p_event, VLC_TRUE );
+            break;
 
-            case 's':                                  /* toggle scaling */
-            case 'S':
-                p_event->p_vout->b_scale = ! p_event->p_vout->b_scale;
-                p_event->p_vout->p_sys->i_changes |= VOUT_SCALE_CHANGE;
-                break;
+        case WM_KEYDOWN:
+            /* The key events are first processed here and not translated
+             * into WM_CHAR events because we need to know the status of the
+             * modifier keys. */
+            val.i_int = DirectXConvertKey( msg.wParam );
+            if( !val.i_int )
+            {
+                /* This appears to be a "normal" (ascii) key */
+                val.i_int = tolower( MapVirtualKey( msg.wParam, 2 ) );
+            }
 
-            case ' ':                                /* toggle interface */
-                p_event->p_vout->b_interface = ! p_event->p_vout->b_interface;
-                p_event->p_vout->p_sys->i_changes |= VOUT_INTF_CHANGE;
-                break;
+            if( val.i_int )
+            {
+                if( GetKeyState(VK_CONTROL) & 0x8000 )
+                {
+                    val.i_int |= KEY_MODIFIER_CTRL;
+                }
+                else if( GetKeyState(VK_SHIFT) & 0x8000 )
+                {
+                    val.i_int |= KEY_MODIFIER_SHIFT;
+                }
+                else if( GetKeyState(VK_MENU) & 0x8000 )
+                {
+                    val.i_int |= KEY_MODIFIER_ALT;
+                }
 
-            default:
-                break;
+                var_Set( p_event->p_vlc, "key-pressed", val );
             }
+            break;
 
         default:
             /* Messages we don't handle directly are dispatched to the
@@ -219,7 +241,7 @@ void DirectXEventThread( event_thread_t *p_event )
         p_event->p_vout->p_sys->hwnd = NULL; /* Window already destroyed */
     }
 
-    msg_Dbg( p_event, "DirectXEventThread Terminating" );
+    msg_Dbg( p_event, "DirectXEventThread terminating" );
 
     /* clear the changes formerly signaled */
     p_event->p_vout->p_sys->i_changes = 0;
@@ -240,17 +262,16 @@ void DirectXEventThread( event_thread_t *p_event )
 static int DirectXCreateWindow( vout_thread_t *p_vout )
 {
     HINSTANCE  hInstance;
-    WNDCLASSEX wc;                                /* window class components */
-    RECT       rect_window;
-    COLORREF   colorkey; 
+    COLORREF   colorkey;
     HDC        hdc;
     HMENU      hMenu;
-    HICON      vlc_icon = NULL;
-    char       vlc_path[MAX_PATH+1];
+    RECT       rect_window;
+
+    vlc_value_t val;
 
     msg_Dbg( p_vout, "DirectXCreateWindow" );
 
-    /* get this module's instance */
+    /* Get this module's instance */
     hInstance = GetModuleHandle(NULL);
 
     /* Create a BRUSH that will be used by Windows to paint the window
@@ -266,14 +287,16 @@ static int DirectXCreateWindow( vout_thread_t *p_vout )
      * comes from the potential dithering (depends on the display depth)
      * because we need to know the real RGB value of the chosen colorkey */
     hdc = GetDC( NULL );
-    for( colorkey = 5; colorkey < 0xFF /*all shades of red*/; colorkey++ )
+    for( colorkey = 0x0a; colorkey < 0xff /* all shades of red */; colorkey++ )
     {
         if( colorkey == GetNearestColor( hdc, colorkey ) )
-          break;
+        {
+            break;
+        }
     }
     msg_Dbg( p_vout, "background color: %i", colorkey );
 
-    /* create the actual brush */  
+    /* Create the actual brush */
     p_vout->p_sys->hbrush = CreateSolidBrush(colorkey);
     p_vout->p_sys->i_rgb_colorkey = (int)colorkey;
 
@@ -288,66 +311,103 @@ static int DirectXCreateWindow( vout_thread_t *p_vout )
 
     ReleaseDC( NULL, hdc );
 
-    /* Get the Icon from the main app */
-    vlc_icon = NULL;
-    if( GetModuleFileName( NULL, vlc_path, MAX_PATH ) )
+    /* 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 )
     {
-        vlc_icon = ExtractIcon( hInstance, vlc_path, 0 );
+        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)p_vout->p_sys->hbrush );
+        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. */
+        RedrawWindow( p_vout->p_sys->hwnd, NULL, NULL,
+                      RDW_INVALIDATE | RDW_ERASE );
     }
-
-
-    /* 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 icon */
-    wc.hCursor       = LoadCursor(NULL, IDC_ARROW); /* load a default cursor */
-    wc.hbrBackground = p_vout->p_sys->hbrush;            /* background color */
-    wc.lpszMenuName  = NULL;                                      /* no menu */
-    wc.lpszClassName = "VLC DirectX";                 /* use a special class */
-    wc.hIconSm       = vlc_icon;                        /* load the vlc icon */
-
-    /* register the window class */
-    if (!RegisterClassEx(&wc))
+    else
     {
-        WNDCLASS wndclass;
+        WNDCLASSEX wc;                            /* window class components */
+        HICON      vlc_icon = NULL;
+        char       vlc_path[MAX_PATH+1];
 
-        /* free window background brush */
-        if( p_vout->p_sys->hbrush )
+        /* Get the Icon from the main app */
+        vlc_icon = NULL;
+        if( GetModuleFileName( NULL, vlc_path, MAX_PATH ) )
         {
-            DeleteObject( p_vout->p_sys->hbrush );
-            p_vout->p_sys->hbrush = NULL;
+            vlc_icon = ExtractIcon( hInstance, vlc_path, 0 );
         }
 
-        if( vlc_icon )
-            DestroyIcon( vlc_icon );
-
-        /* Check why it failed. If it's because one already exists then fine */
-        if( !GetClassInfo( hInstance, "VLC DirectX", &wndclass ) )
+        /* 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 = p_vout->p_sys->hbrush;        /* 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) )
         {
-            msg_Err( p_vout, "DirectXCreateWindow RegisterClass FAILED" );
-            return (1);
+            WNDCLASS wndclass;
+
+            /* Free window background brush */
+            if( p_vout->p_sys->hbrush )
+            {
+                DeleteObject( p_vout->p_sys->hbrush );
+                p_vout->p_sys->hbrush = NULL;
+            }
+
+            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, "VLC DirectX", &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 title bar.
-     * 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;
-    AdjustWindowRect( &rect_window, WS_OVERLAPPEDWINDOW|WS_SIZEBOX, 0 );
-
-    /* create the window */
-    p_vout->p_sys->hwnd = CreateWindow("VLC DirectX",/* name of window class */
+        /* 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;
+        AdjustWindowRect( &rect_window, WS_OVERLAPPEDWINDOW|WS_SIZEBOX, 0 );
+
+        /* 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,               /* window style */
+                    WS_OVERLAPPEDWINDOW | WS_SIZEBOX,        /* window style */
                     CW_USEDEFAULT,                   /* default X coordinate */
                     0,                               /* default Y coordinate */
                     rect_window.right - rect_window.left,    /* window width */
@@ -355,27 +415,25 @@ static int DirectXCreateWindow( vout_thread_t *p_vout )
                     NULL,                                /* no parent window */
                     NULL,                          /* no menu in this window */
                     hInstance,            /* handle of this program instance */
-                    NULL);                        /* no additional arguments */
+                    (LPVOID)p_vout );            /* send p_vout to WM_CREATE */
 
-    if (p_vout->p_sys->hwnd == NULL) {
-        msg_Warn( p_vout, "DirectXCreateWindow create window FAILED" );
-        return (1);
+        if( !p_vout->p_sys->hwnd )
+        {
+            msg_Warn( p_vout, "DirectXCreateWindow create window FAILED" );
+            return VLC_EGENERIC;
+        }
     }
 
-    /* store a p_vout pointer into the window local storage (for later use
-     * in DirectXEventProc).
-     * We need to use SetWindowLongPtr when it is available in mingw */
-    SetWindowLong( p_vout->p_sys->hwnd, GWL_USERDATA, (LONG)p_vout );
-
-    /* append a "Always On Top" entry in the system menu */
+    /* 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");
+    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);
+    /* Now display the window */
+    ShowWindow( p_vout->p_sys->hwnd, SW_SHOW );
 
-    return ( 0 );
+    return VLC_SUCCESS;
 }
 
 /*****************************************************************************
@@ -387,50 +445,86 @@ static void DirectXCloseWindow( vout_thread_t *p_vout )
 {
     msg_Dbg( p_vout, "DirectXCloseWindow" );
 
-    if( p_vout->p_sys->hwnd != NULL )
+    if( p_vout->p_sys->hwnd && !p_vout->p_sys->hparent )
     {
         DestroyWindow( p_vout->p_sys->hwnd );
-        p_vout->p_sys->hwnd = NULL;
+    }
+    else if( p_vout->p_sys->hparent )
+    {
+        /* 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 );
+
+        /* Blam! Erase everything that might have been there. */
+        InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE );
     }
 
+    p_vout->p_sys->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 */
 }
 
 /*****************************************************************************
- * DirectXUpdateRects: 
+ * DirectXUpdateRects: update clipping rectangles
  *****************************************************************************
- * This function is called when the window position and size is changed, and
+ * This function is called when the window position or size are changed, and
  * its job is to update the source and destination RECTs used to display the
  * picture.
  *****************************************************************************/
-static void DirectXUpdateRects( vout_thread_t *p_vout )
+void DirectXUpdateRects( vout_thread_t *p_vout, vlc_bool_t b_force )
 {
-    int i_width, i_height, i_x, i_y;
-
 #define rect_src p_vout->p_sys->rect_src
 #define rect_src_clipped p_vout->p_sys->rect_src_clipped
 #define rect_dest p_vout->p_sys->rect_dest
 #define rect_dest_clipped p_vout->p_sys->rect_dest_clipped
-#define rect_display p_vout->p_sys->rect_display
 
-    vout_PlacePicture( p_vout, p_vout->p_sys->i_window_width,
-                       p_vout->p_sys->i_window_height,
+    int i_width, i_height, i_x, i_y;
+
+    RECT  rect;
+    POINT point;
+
+    /* Retrieve the window size */
+    GetClientRect( p_vout->p_sys->hwnd, &rect );
+
+    /* Retrieve the window position */
+    point.x = point.y = 0;
+    ClientToScreen( p_vout->p_sys->hwnd, &point );
+
+    /* If nothing changed, we can return */
+    if( !b_force
+         && p_vout->p_sys->i_window_width == rect.right
+         && p_vout->p_sys->i_window_height == rect.bottom
+         && p_vout->p_sys->i_window_x == point.x
+         && p_vout->p_sys->i_window_y == point.y )
+    {
+        return;
+    }
+
+    /* Update the window position and size */
+    p_vout->p_sys->i_window_x = point.x;
+    p_vout->p_sys->i_window_y = point.y;
+    p_vout->p_sys->i_window_width = rect.right;
+    p_vout->p_sys->i_window_height = rect.bottom;
+
+    vout_PlacePicture( p_vout, rect.right, rect.bottom,
                        &i_x, &i_y, &i_width, &i_height );
 
     /* Destination image position and dimensions */
-    rect_dest.left = i_x + p_vout->p_sys->i_window_x;
-    rect_dest.top = i_y + p_vout->p_sys->i_window_y;
+    rect_dest.left = point.x + i_x;
     rect_dest.right = rect_dest.left + i_width;
+    rect_dest.top = point.y + i_y;
     rect_dest.bottom = rect_dest.top + i_height;
 
 
     /* UpdateOverlay directdraw function doesn't automatically clip to the
-     * display size so we need to do it otherwise it will fails */
+     * display size so we need to do it otherwise it will fail */
 
     /* Clip the destination window */
-    IntersectRect( &rect_dest_clipped, &rect_dest, &rect_display );
+    IntersectRect( &rect_dest_clipped,
+                   &rect_dest,
+                   &p_vout->p_sys->rect_display );
 
 #if 0
     msg_Dbg( p_vout, "DirectXUpdateRects image_dst_clipped coords:"
@@ -456,7 +550,7 @@ static void DirectXUpdateRects( vout_thread_t *p_vout )
     /* 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_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) *
@@ -472,11 +566,23 @@ static void DirectXUpdateRects( vout_thread_t *p_vout )
                      rect_src_clipped.right, rect_src_clipped.bottom );
 #endif
 
+    /* Signal the size change */
+    if( !p_vout->p_sys->p_event->b_die )
+    {
+        if( p_vout->p_sys->b_using_overlay )
+        {
+            DirectXUpdateOverlay( p_vout );
+        }
+        else
+        {
+            p_vout->p_sys->i_changes |= VOUT_SIZE_CHANGE;
+        }
+    }
+
 #undef rect_src
 #undef rect_src_clipped
 #undef rect_dest
 #undef rect_dest_clipped
-#undef rect_display
 }
 
 /*****************************************************************************
@@ -493,50 +599,41 @@ static void DirectXUpdateRects( vout_thread_t *p_vout )
 static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
                                          WPARAM wParam, LPARAM lParam )
 {
-    vout_thread_t *p_vout =
-            (vout_thread_t *)GetWindowLong( hwnd, GWL_USERDATA );
+    vout_thread_t *p_vout;
+
+    if( message == WM_CREATE )
+    {
+        /* Store p_vout for future use */
+        p_vout = (vout_thread_t *)((CREATESTRUCT *)lParam)->lpCreateParams;
+        SetWindowLong( hwnd, GWL_USERDATA, (LONG)p_vout );
+    }
+    else
+    {
+        p_vout = (vout_thread_t *)GetWindowLong( hwnd, GWL_USERDATA );
+    }
 
     switch( message )
     {
 
     case WM_WINDOWPOSCHANGED:
-        {
-        RECT     rect_window;
-        POINT    point_window;
-
-        /* update the window position */
-        point_window.x = 0;
-        point_window.y = 0;
-        ClientToScreen( hwnd, &point_window );
-        p_vout->p_sys->i_window_x = point_window.x;
-        p_vout->p_sys->i_window_y = point_window.y;
-
-        /* update the window size */
-        GetClientRect( hwnd, &rect_window );
-        p_vout->p_sys->i_window_width = rect_window.right;
-        p_vout->p_sys->i_window_height = rect_window.bottom;
-
-        DirectXUpdateRects( p_vout );
-        if( p_vout->p_sys->b_using_overlay &&
-            !p_vout->p_sys->p_event->b_die )
-            DirectXUpdateOverlay( p_vout );
-
-        /* signal the size change */
-        if( !p_vout->p_sys->b_using_overlay &&
-            !p_vout->p_sys->p_event->b_die )
-            p_vout->p_sys->i_changes |= VOUT_SIZE_CHANGE;
-
+        DirectXUpdateRects( p_vout, VLC_TRUE );
         return 0;
-        }
-        break;
 
     /* the user wants to close the window */
     case WM_CLOSE:
-        msg_Dbg( p_vout, "WinProc WM_CLOSE" );
-        /* exit application */
-        p_vout->p_vlc->b_die = 1;
+    {
+        playlist_t * p_playlist =
+            (playlist_t *)vlc_object_find( p_vout, VLC_OBJECT_PLAYLIST,
+                                           FIND_ANYWHERE );
+        if( p_playlist == NULL )
+        {
+            return 0;
+        }
+
+        playlist_Stop( p_playlist );
+        vlc_object_release( p_playlist );
         return 0;
-        break;
+    }
 
     /* the window has been closed so shut down everything now */
     case WM_DESTROY:
@@ -544,7 +641,6 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
         /* just destroy the window */
         PostQuitMessage( 0 );
         return 0;
-        break;
 
     case WM_SYSCOMMAND:
         switch (wParam)
@@ -555,27 +651,15 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
                 return 0;                  /* this stops them from happening */
             case IDM_TOGGLE_ON_TOP:            /* toggle the "on top" status */
             {
-                HMENU hMenu = GetSystemMenu( hwnd , FALSE );
-
+                vlc_value_t val;
                 msg_Dbg( p_vout, "WinProc WM_SYSCOMMAND: IDM_TOGGLE_ON_TOP");
 
-                // Check if the window is already on top
-                if( GetWindowLong( hwnd, GWL_EXSTYLE ) & WS_EX_TOPMOST )
-                {
-                    CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
-                                   MF_BYCOMMAND | MFS_UNCHECKED );
-                    SetWindowPos( hwnd, HWND_NOTOPMOST,
-                                  0, 0, 0, 0,
-                                  SWP_NOSIZE | SWP_NOMOVE );
-                }
-                else
-                {
-                    CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
-                                   MF_BYCOMMAND | MFS_CHECKED );
-                    SetWindowPos( hwnd, HWND_TOPMOST,
-                                  0, 0, 0, 0,
-                                  SWP_NOSIZE | SWP_NOMOVE );
-                }
+                /* Get the current value... */
+                if( var_Get( p_vout, "directx-on-top", &val ) < 0 )
+                    return 0;
+                /* ...and change it */
+                val.b_bool = !val.b_bool;
+                var_Set( p_vout, "directx-on-top", val );
                 return 0;
                 break;
             }
@@ -610,3 +694,47 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
 
     return DefWindowProc(hwnd, message, wParam, lParam);
 }
+
+static struct
+{
+    int i_dxkey;
+    int i_vlckey;
+
+} dxkeys_to_vlckeys[] =
+{
+    { VK_F1, KEY_F1 }, { VK_F2, KEY_F2 }, { VK_F3, KEY_F3 }, { VK_F4, KEY_F4 },
+    { VK_F5, KEY_F5 }, { VK_F6, KEY_F6 }, { VK_F7, KEY_F7 }, { VK_F8, KEY_F8 },
+    { VK_F9, KEY_F9 }, { VK_F10, KEY_F10 }, { VK_F11, KEY_F11 },
+    { VK_F12, KEY_F12 },
+
+    { VK_RETURN, KEY_ENTER },
+    { VK_SPACE, KEY_SPACE },
+    { VK_ESCAPE, KEY_ESC },
+
+    { VK_MENU, KEY_MENU },
+    { VK_LEFT, KEY_LEFT },
+    { VK_RIGHT, KEY_RIGHT },
+    { VK_UP, KEY_UP },
+    { VK_DOWN, KEY_DOWN },
+
+    { VK_HOME, KEY_HOME },
+    { VK_END, KEY_END },
+    { VK_PRIOR, KEY_PAGEUP },
+    { VK_NEXT, KEY_PAGEDOWN },
+    { 0, 0 }
+};
+
+static int DirectXConvertKey( int i_key )
+{
+    int i;
+
+    for( i = 0; dxkeys_to_vlckeys[i].i_dxkey != 0; i++ )
+    {
+        if( dxkeys_to_vlckeys[i].i_dxkey == i_key )
+        {
+            return dxkeys_to_vlckeys[i].i_vlckey;
+        }
+    }
+
+    return 0;
+}