>From d5324148e2c2a92fd2badfda857510b3b3793652 Mon Sep 17 00:00:00 2001
From: Erwan Tulou <erwan10@videolan.org>
Date: Sun, 13 Jun 2010 15:50:19 +0200
Subject: [PATCH] msw: remove the msw thread.

The EventThread is replaced by WindowSetup and WindowCleanup, meant to be 
executed by the vout provider thread (via calls to vout_windowSendEventSetup/Cleanup)

The message processing is moved into the Window Procedure.

---
 modules/video_output/msw/common.c |   60 ++--
 modules/video_output/msw/events.c |  829 +++++++++++++++++--------------------
 modules/video_output/msw/events.h |    2 +-
 3 files changed, 418 insertions(+), 473 deletions(-)

diff --git a/modules/video_output/msw/common.c b/modules/video_output/msw/common.c
index fc11a16..266b434 100644
--- a/modules/video_output/msw/common.c
+++ b/modules/video_output/msw/common.c
@@ -108,7 +108,11 @@ int CommonInit(vout_display_t *vd)
 
     event_hwnd_t hwnd;
     if (EventThreadStart(sys->event, &hwnd, &cfg))
+    {
+        msg_Err( vd, "failed to start event thread" );
+        EventThreadDestroy(sys->event);
         return VLC_EGENERIC;
+    }
 
     sys->parent_window = hwnd.parent_window;
     sys->hparent       = hwnd.hparent;
@@ -150,13 +154,15 @@ void CommonManage(vout_display_t *vd)
 {
     vout_display_sys_t *sys = vd->sys;
 
-    /* We used to call the Win32 PeekMessage function here to read the window
-     * messages. But since window can stay blocked into this function for a
-     * long time (for example when you move your window on the screen), I
-     * decided to isolate PeekMessage in another thread. */
 
-    /* If we do not control our window, we check for geometry changes
-     * ourselves because the parent might not send us its events. */
+#ifdef MODULE_NAME_IS_directx
+
+    /* hack for directx : when moving a top level window, child windows are
+     * usually automatically moved without any notification. Yet, in the case
+     * of directx, the video surface is not moved alongside its window. So
+     * let's check regularly that we haven't moved, and update the video window
+     * if we did */
+
     if (sys->hparent) {
         RECT rect_parent;
         POINT point;
@@ -169,32 +175,12 @@ void CommonManage(vout_display_t *vd)
         if (!EqualRect(&rect_parent, &sys->rect_parent)) {
             sys->rect_parent = rect_parent;
 
-            /* FIXME I find such #ifdef quite weirds. Are they really needed ? */
-
-#if defined(MODULE_NAME_IS_direct3d) || defined(MODULE_NAME_IS_wingdi) || defined(MODULE_NAME_IS_wingapi)
-            SetWindowPos(sys->hwnd, 0, 0, 0,
-                         rect_parent.right - rect_parent.left,
-                         rect_parent.bottom - rect_parent.top,
-                         SWP_NOZORDER);
             UpdateRects(vd, NULL, NULL, true);
-#else
-            /* This one is to force the update even if only
-             * the position has changed */
-            SetWindowPos(sys->hwnd, 0, 1, 1,
-                         rect_parent.right - rect_parent.left,
-                         rect_parent.bottom - rect_parent.top, 0);
-
-            SetWindowPos(sys->hwnd, 0, 0, 0,
-                         rect_parent.right - rect_parent.left,
-                         rect_parent.bottom - rect_parent.top, 0);
-
-#endif
+            // EventThreadAskUpdateRect(sys->event);
         }
     }
 
-    /* */
-    if (EventThreadGetAndResetHasMoved(sys->event))
-        UpdateRects(vd, NULL, NULL, false);
+#endif
 
     /* Pointer change */
     EventThreadMouseAutoHide(sys->event);
@@ -221,6 +207,7 @@ void CommonDisplay(vout_display_t *vd)
                  SWP_NOMOVE|
                  SWP_NOSIZE|
                  SWP_NOZORDER);
+
     sys->is_first_display = false;
 }
 
@@ -296,6 +283,11 @@ void UpdateRects(vout_display_t *vd,
     RECT  rect;
     POINT point;
 
+    if( !sys->hwnd )
+        return;
+
+    msg_Err( vd," Calling UpdateRects");
+
     /* */
     if (!cfg)
         cfg = vd->cfg;
@@ -315,8 +307,6 @@ void UpdateRects(vout_display_t *vd,
     EventThreadUpdateWindowPosition(sys->event, &has_moved, &is_resized,
                                     point.x, point.y,
                                     rect.right, rect.bottom);
-    if (is_resized)
-        vout_display_SendEventDisplaySize(vd, rect.right, rect.bottom, cfg->is_fullscreen);
     if (!is_forced && !has_moved && !is_resized )
         return;
 
@@ -359,6 +349,7 @@ void UpdateRects(vout_display_t *vd,
 
 #endif
 
+#if 0
 #if defined(MODULE_NAME_IS_directx) || defined(MODULE_NAME_IS_direct3d)
     /* UpdateOverlay directdraw function doesn't automatically clip to the
      * display size so we need to do it otherwise it will fail
@@ -385,6 +376,11 @@ void UpdateRects(vout_display_t *vd,
 
 #endif
 
+#endif
+
+    /* FORCE NO CLIPPING WHATEVER THE SITUATION */
+    rect_dest_clipped = rect_dest;
+
     /* the 2 following lines are to fix a bug when clicking on the desktop */
     if ((rect_dest_clipped.right - rect_dest_clipped.left) == 0 ||
         (rect_dest_clipped.bottom - rect_dest_clipped.top) == 0) {
@@ -587,8 +583,9 @@ int CommonControl(vout_display_t *vd, int query, va_list args)
         }
         if (query == VOUT_DISPLAY_CHANGE_DISPLAY_SIZE && is_forced) {
             /* Update dimensions */
+            int ret = VLC_SUCCESS;
             if (sys->parent_window) {
-                vout_window_SetSize(sys->parent_window, cfg->display.width, cfg->display.height);
+                ret = vout_window_SetSize(sys->parent_window, cfg->display.width, cfg->display.height);
             } else {
                 RECT rect_window;
                 rect_window.top    = 0;
@@ -601,6 +598,7 @@ int CommonControl(vout_display_t *vd, int query, va_list args)
                              rect_window.right - rect_window.left,
                              rect_window.bottom - rect_window.top, SWP_NOMOVE);
             }
+            return ret;
         }
         UpdateRects(vd, cfg, source, is_forced);
         return VLC_SUCCESS;
diff --git a/modules/video_output/msw/events.c b/modules/video_output/msw/events.c
index 1945b12..af450e0 100644
--- a/modules/video_output/msw/events.c
+++ b/modules/video_output/msw/events.c
@@ -83,6 +83,7 @@ UINT GetMenuState(HMENU hMenu, UINT id, UINT flags)
 #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_UPDATE_RECT  (WM_APP + 3)
 
 struct event_thread_t
 {
@@ -97,35 +98,39 @@ struct event_thread_t
     bool         b_error;
 
     /* */
-    bool use_desktop;
     bool use_overlay;
 
+    /* */
+    bool b_mouse_support;
+    bool b_key_support;
+
     /* Mouse */
     volatile bool    b_cursor_hidden;
     volatile mtime_t i_lastmoved;
     mtime_t          i_mouse_hide_timeout;
 
-    /* Title */
-    char *psz_title;
-
-    int               i_window_style;
     vout_window_cfg_t wnd_cfg;
 
     /* */
+    int i_window_style;
+
+    RECT rect_parent;
+
     vout_window_t *parent_window;
     HWND hparent;
     HWND hwnd;
     HWND hvideownd;
     HWND hfswnd;
+    WNDPROC fWndProc;
     video_format_t       source;
     vout_display_place_t place;
-
-    bool has_moved;
 };
 
+static void WindowSetup( void *p_data, void* hwnd );
+static void WindowCleanup( void *p_data );
+
 static int  DirectXCreateWindow( event_thread_t * );
-static void DirectXCloseWindow ( event_thread_t * );
-static long FAR PASCAL DirectXEventProc( HWND, UINT, WPARAM, LPARAM );
+static LRESULT CALLBACK DirectXEventProc( HWND, UINT, WPARAM, LPARAM );
 
 static int DirectXConvertKey( int i_key );
 
@@ -142,43 +147,33 @@ static inline bool isKeyEvent( WPARAM type )
 }
 
 /*****************************************************************************
- * EventThread: Create video window & handle its messages
+ * WindowSetup: create windows resources
  *****************************************************************************
- * This function creates a video window and then enters an infinite loop
- * that handles the messages sent to that window.
- * The main goal of this thread is to isolate the Win32 PeekMessage function
- * because this one can block for a long time.
+ * This function returns all resources
  *****************************************************************************/
-static void *EventThread( void *p_this )
+static void WindowSetup( void *p_data, void* hwnd )
 {
-    event_thread_t *p_event = (event_thread_t *)p_this;
+    event_thread_t *p_event = (event_thread_t *)p_data;
     vout_display_t *vd = p_event->vd;
-    MSG msg;
-    POINT old_mouse_pos = {0,0}, mouse_pos;
     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
-     * message queue */
-    if( DirectXCreateWindow( p_event ) )
-        p_event->b_error = true;
+    if( !hwnd )
+    {
+        msg_Err( p_event->vd, "hwnd is null" );
+        return;
+    }
 
-    p_event->b_ready = true;
-    vlc_cond_signal( &p_event->wait );
+    p_event->hparent = hwnd;
 
-    const bool b_error = p_event->b_error;
-    vlc_mutex_unlock( &p_event->lock );
+    /* subclass the hparent window to be notified of resizing events */
+    SetWindowLongPtr( p_event->hparent, GWLP_USERDATA, (LONG_PTR)p_event );
+    LONG_PTR ret = SetWindowLongPtr( p_event->hparent,
+                      GWLP_WNDPROC, (LONG_PTR)(WNDPROC)DirectXEventProc);
+    p_event->fWndProc = (WNDPROC)ret;
 
-    if( b_error )
-    {
-        vlc_restorecancel( canc );
-        return NULL;
-    }
+    /* Create subwindows for the video */
+    if( DirectXCreateWindow( p_event ) )
+        p_event->b_error = true;
 
 #ifndef UNDER_CE
     /* Set power management stuff */
@@ -197,230 +192,37 @@ static void *EventThread( void *p_this )
     }
 #endif
 
-    /* Main loop */
-    /* GetMessage will sleep if there's no message in the queue */
-    for( ;; )
-    {
-        vout_display_place_t place;
-        video_format_t       source;
-
-        if( !GetMessage( &msg, 0, 0, 0 ) )
-        {
-            vlc_mutex_lock( &p_event->lock );
-            p_event->b_done = true;
-            vlc_mutex_unlock( &p_event->lock );
-            break;
-        }
-
-        /* Check if we are asked to exit */
-        vlc_mutex_lock( &p_event->lock );
-        const bool b_done = p_event->b_done;
-        vlc_mutex_unlock( &p_event->lock );
-        if( b_done )
-            break;
-
-        if( !b_mouse_support && isMouseEvent( msg.message ) )
-            continue;
-
-        if( !b_key_support && isKeyEvent( msg.message ) )
-            continue;
-
-        /* */
-        switch( msg.message )
-        {
-        case WM_MOUSEMOVE:
-            vlc_mutex_lock( &p_event->lock );
-            place  = p_event->place;
-            source = p_event->source;
-            vlc_mutex_unlock( &p_event->lock );
-
-            if( place.width > 0 && place.height > 0 )
-            {
-                if( msg.hwnd == p_event->hvideownd )
-                {
-                    /* Child window */
-                    place.x = 0;
-                    place.y = 0;
-                }
-                const int x = source.i_x_offset +
-                    (int64_t)(GET_X_LPARAM(msg.lParam) - place.x) * source.i_width  / place.width;
-                const int y = source.i_y_offset +
-                    (int64_t)(GET_Y_LPARAM(msg.lParam) - place.y) * source.i_height / place.height;
-                vout_display_SendEventMouseMoved(vd, x, y);
-            }
-            /* Fall through */
-        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);
-            break;
-        case WM_LBUTTONUP:
-            vout_display_SendEventMouseReleased(vd, MOUSE_BUTTON_LEFT);
-            break;
-        case WM_LBUTTONDBLCLK:
-            vout_display_SendEventMouseDoubleClick(vd);
-            break;
-
-        case WM_MBUTTONDOWN:
-            vout_display_SendEventMousePressed(vd, MOUSE_BUTTON_CENTER);
-            break;
-        case WM_MBUTTONUP:
-            vout_display_SendEventMouseReleased(vd, MOUSE_BUTTON_CENTER);
-            break;
-
-        case WM_RBUTTONDOWN:
-            vout_display_SendEventMousePressed(vd, MOUSE_BUTTON_RIGHT);
-            break;
-        case WM_RBUTTONUP:
-            vout_display_SendEventMouseReleased(vd, MOUSE_BUTTON_RIGHT);
-            break;
-
-        case WM_KEYDOWN:
-        case WM_SYSKEYDOWN:
-        {
-            /* 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. */
-            int i_key = DirectXConvertKey( msg.wParam );
-            if( !i_key )
-            {
-                /* This appears to be a "normal" (ascii) key */
-                i_key = tolower( MapVirtualKey( msg.wParam, 2 ) );
-            }
-
-            if( i_key )
-            {
-                if( GetKeyState(VK_CONTROL) & 0x8000 )
-                {
-                    i_key |= KEY_MODIFIER_CTRL;
-                }
-                if( GetKeyState(VK_SHIFT) & 0x8000 )
-                {
-                    i_key |= KEY_MODIFIER_SHIFT;
-                }
-                if( GetKeyState(VK_MENU) & 0x8000 )
-                {
-                    i_key |= KEY_MODIFIER_ALT;
-                }
-
-                vout_display_SendEventKey(vd, i_key);
-            }
-            break;
-        }
-
-        case WM_MOUSEWHEEL:
-        {
-            int i_key;
-            if( GET_WHEEL_DELTA_WPARAM( msg.wParam ) > 0 )
-            {
-                i_key = KEY_MOUSEWHEELUP;
-            }
-            else
-            {
-                i_key = KEY_MOUSEWHEELDOWN;
-            }
-            if( i_key )
-            {
-                if( GetKeyState(VK_CONTROL) & 0x8000 )
-                {
-                    i_key |= KEY_MODIFIER_CTRL;
-                }
-                if( GetKeyState(VK_SHIFT) & 0x8000 )
-                {
-                    i_key |= KEY_MODIFIER_SHIFT;
-                }
-                if( GetKeyState(VK_MENU) & 0x8000 )
-                {
-                    i_key |= KEY_MODIFIER_ALT;
-                }
-                vout_display_SendEventKey(vd, i_key);
-            }
-            break;
-        }
-
-        case WM_VLC_CHANGE_TEXT:
-        {
-            vlc_mutex_lock( &p_event->lock );
-            wchar_t *pwz_title = NULL;
-            if( p_event->psz_title )
-            {
-                const size_t i_length = strlen(p_event->psz_title);
-                pwz_title = malloc( 2 * (i_length + 1) );
-                if( pwz_title )
-                {
-                    mbstowcs( pwz_title, p_event->psz_title, 2 * i_length );
-                    pwz_title[i_length] = 0;
-                }
-            }
-            vlc_mutex_unlock( &p_event->lock );
-
-            if( pwz_title )
-            {
-                SetWindowTextW( p_event->hwnd, (LPCTSTR)pwz_title );
-                if( p_event->hfswnd )
-                    SetWindowTextW( p_event->hfswnd, (LPCTSTR)pwz_title );
-                free( pwz_title );
-            }
-            break;
-        }
-
-        default:
-            /* Messages we don't handle directly are dispatched to the
-             * window procedure */
-            TranslateMessage(&msg);
-            DispatchMessage(&msg);
-            break;
+}
 
-        } /* End Switch */
+/*****************************************************************************
+ * WindowCleanup: close the window created by WindowSetup
+ *****************************************************************************
+ * This function returns all resources allocated by WindowSetup.
+ *****************************************************************************/
+static void WindowCleanup( void* p_data )
+{
+    event_thread_t *p_event = (event_thread_t *)p_data;
+    vout_display_t *vd = p_event->vd;
+    msg_Dbg( vd, "WindowCleanup" );
 
-    } /* End Main loop */
+    /* restore cursor before deallocation */
+    SendMessage( p_event->hwnd, WM_VLC_SHOW_MOUSE, 0, 0 );
 
-    /* Check for WM_QUIT if we created the window */
-    if( !p_event->hparent && msg.message == WM_QUIT )
-    {
-        msg_Warn( vd, "WM_QUIT... should not happen!!" );
-        p_event->hwnd = NULL; /* Window already destroyed */
-    }
+    /* restore default proc for hparent */
+    SetWindowLongPtr( p_event->hparent, GWLP_USERDATA, (LONG_PTR)NULL );
+    SetWindowLongPtr( p_event->hparent, GWL_WNDPROC,
+                      (LONG_PTR)p_event->fWndProc);
 
-    msg_Dbg( vd, "DirectXEventThread terminating" );
+    /* destroy owned windows */
+    DestroyWindow( p_event->hwnd );
+    if( p_event->hfswnd )
+        DestroyWindow( p_event->hfswnd );
 
-    DirectXCloseWindow( p_event );
-    vlc_restorecancel(canc);
-    return 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 */
 }
 
-
 /* following functions are local */
 
 /*****************************************************************************
@@ -434,59 +236,20 @@ static int DirectXCreateWindow( event_thread_t *p_event )
 {
     vout_display_t *vd = p_event->vd;
     HINSTANCE  hInstance;
-    HMENU      hMenu;
-    RECT       rect_window;
     WNDCLASS   wc;                            /* window class components */
-    HICON      vlc_icon;
-    char       vlc_path[MAX_PATH+1];
-    int        i_style, i_stylex;
 
     msg_Dbg( vd, "DirectXCreateWindow" );
 
     /* Get this module's instance */
     hInstance = GetModuleHandle(NULL);
 
-    #ifdef MODULE_NAME_IS_direct3d
-    if( !p_event->use_desktop )
-    {
-    #endif
-        /* 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->handle.hwnd;
-        else
-            p_event->hparent = NULL;
-    #ifdef MODULE_NAME_IS_direct3d
-    }
-    else
-    {
-        /* Find Program Manager */
-        HWND hwnd = FindWindow( _T("Progman"), NULL );
-        if( hwnd ) hwnd = FindWindowEx( hwnd, NULL, _T("SHELLDLL_DefView"), NULL );
-        if( hwnd ) hwnd = FindWindowEx( hwnd, NULL, _T("SysListView32"), NULL );
-        if( !hwnd )
-            msg_Err( vd, "Couldn't find desktop icon window. Desktop mode can't be established." );
-        p_event->parent_window = NULL;
-        p_event->hparent = hwnd;
-    }
-    #endif
-
-    /* Get the Icon from the main app */
-    vlc_icon = NULL;
-#ifndef UNDER_CE
-    if( GetModuleFileName( NULL, vlc_path, MAX_PATH ) )
-    {
-        vlc_icon = ExtractIcon( hInstance, vlc_path, 0 );
-    }
-#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.hIcon         = 0;                                     /* no icon */
     wc.hCursor       = LoadCursor(NULL, IDC_ARROW);    /* default cursor */
     wc.hbrBackground = GetStockObject(BLACK_BRUSH);  /* background color */
     wc.lpszMenuName  = NULL;                                  /* no menu */
@@ -497,8 +260,6 @@ static int DirectXCreateWindow( event_thread_t *p_event )
     {
         WNDCLASS wndclass;
 
-        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 ) )
@@ -524,51 +285,23 @@ static int DirectXCreateWindow( event_thread_t *p_event )
         }
     }
 
-    /* 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.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;
+    LONG i_style = WS_VISIBLE|WS_CLIPCHILDREN|WS_CHILD;
 
-    if( var_GetBool( vd, "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.
-    }
-
-    if( p_event->hparent )
-    {
-        i_style = WS_VISIBLE|WS_CLIPCHILDREN|WS_CHILD;
-        i_stylex = 0;
-    }
-
-    p_event->i_window_style = i_style;
+    RECT rect_parent;
+    GetClientRect(p_event->hparent, &rect_parent);
+    int width = rect_parent.right - rect_parent.left;
+    int height = rect_parent.bottom - rect_parent.top;
 
     /* Create the window */
     p_event->hwnd =
-        CreateWindowEx( WS_EX_NOPARENTNOTIFY | i_stylex,
+        CreateWindowEx( WS_EX_NOPARENTNOTIFY,
                     _T("VLC DirectX"),               /* name of window class */
                     _T(VOUT_TITLE) _T(" (DirectX Output)"),  /* window title */
                     i_style,                                 /* window style */
-                    (!p_event->wnd_cfg.x) ? CW_USEDEFAULT :
-                        (UINT)p_event->wnd_cfg.x,   /* default X coordinate */
-                    (!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 */
+                    0,                               /* default X coordinate */
+                    0,                               /* default Y coordinate */
+                    width,                                   /* window width */
+                    height,                                 /* window height */
                     p_event->hparent,                       /* parent window */
                     NULL,                          /* no menu in this window */
                     hInstance,            /* handle of this program instance */
@@ -580,37 +313,21 @@ static int DirectXCreateWindow( event_thread_t *p_event )
         return VLC_EGENERIC;
     }
 
-    if( p_event->hparent )
-    {
-        LONG i_style;
-
-        /* We don't want the window owner to overwrite our client area */
-        i_style = GetWindowLong( p_event->hparent, GWL_STYLE );
-
-        if( !(i_style & WS_CLIPCHILDREN) )
-            /* Hmmm, apparently this is a blocking call... */
-            SetWindowLong( p_event->hparent, GWL_STYLE,
-                           i_style | WS_CLIPCHILDREN );
-
-        /* Create our fullscreen window */
-        p_event->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 );
-    }
-    else
-    {
-        p_event->hfswnd = NULL;
-    }
+    /* We don't want the window owner to overwrite our client area */
+    i_style = GetWindowLongPtr( p_event->hparent, GWL_STYLE );
 
-    /* Append a "Always On Top" entry in the system menu */
-    hMenu = GetSystemMenu( p_event->hwnd, FALSE );
-    AppendMenu( hMenu, MF_SEPARATOR, 0, _T("") );
-    AppendMenu( hMenu, MF_STRING | MF_UNCHECKED,
-                       IDM_TOGGLE_ON_TOP, _T("Always on &Top") );
+    if( !(i_style & WS_CLIPCHILDREN) )
+        SetWindowLong( p_event->hparent, GWL_STYLE,
+                              i_style | WS_CLIPCHILDREN );
+
+    /* Create our fullscreen window */
+    p_event->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 );
 
     /* Create video sub-window. This sub window will always exactly match
      * the size of the video, which allows us to use crazy overlay colorkeys
@@ -631,6 +348,14 @@ static int DirectXCreateWindow( event_thread_t *p_event )
     else
         msg_Dbg( vd, "created video sub-window" );
 
+    /* report back the real size to update the video window accordingly */
+    vout_display_SendEventDisplaySize( vd, width, height,
+                                       vd->cfg->is_fullscreen );
+
+    /* SetFocus on our internal window */
+    if( p_event->b_key_support )
+        SetFocus( p_event->hwnd );
+
     /* Now display the window */
     ShowWindow( p_event->hwnd, SW_SHOW );
 
@@ -638,31 +363,6 @@ static int DirectXCreateWindow( event_thread_t *p_event )
 }
 
 /*****************************************************************************
- * DirectXCloseWindow: close the window created by DirectXCreateWindow
- *****************************************************************************
- * This function returns all resources allocated by DirectXCreateWindow.
- *****************************************************************************/
-static void DirectXCloseWindow( event_thread_t *p_event )
-{
-    vout_display_t *vd = p_event->vd;
-    msg_Dbg( vd, "DirectXCloseWindow" );
-
-    DestroyWindow( p_event->hwnd );
-    if( p_event->hfswnd )
-        DestroyWindow( p_event->hfswnd );
-
-    #ifdef MODULE_NAME_IS_direct3d
-    if( !p_event->use_desktop )
-    #endif
-        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 */
-}
-
-/*****************************************************************************
  * DirectXEventProc: This is the window event processing function.
  *****************************************************************************
  * On Windows, when you create a window you have to attach an event processing
@@ -673,8 +373,8 @@ static void DirectXCloseWindow( event_thread_t *p_event )
  * Nonqueued Messages are those that Windows will send directly to this
  * procedure (like WM_DESTROY, WM_WINDOWPOSCHANGED...)
  *****************************************************************************/
-static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
-                                         WPARAM wParam, LPARAM lParam )
+static LRESULT CALLBACK DirectXEventProc( HWND hwnd, UINT message,
+                                          WPARAM wParam, LPARAM lParam )
 {
     event_thread_t *p_event;
 
@@ -750,7 +450,8 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
             // fall through
 #endif
         default:
-            return DefWindowProc(hwnd, message, wParam, lParam);
+            // return DefWindowProc(hwnd, message, wParam, lParam);
+            break;
         }
     }
 
@@ -758,9 +459,31 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
     {
 
     case WM_WINDOWPOSCHANGED:
-        vlc_mutex_lock( &p_event->lock );
-        p_event->has_moved = true;
-        vlc_mutex_unlock( &p_event->lock );
+    {
+        WINDOWPOS* str = (WINDOWPOS*)lParam;
+        int width = str->cx;
+        int height = str->cy;
+        int x = str->x;
+        int y = str->y;
+
+        if( hwnd == p_event->hparent )
+        {
+            SetWindowPos( p_event->hwnd, 0, 0, 0,
+                          width, height, 0);
+        }
+        else if( hwnd == p_event->hwnd )
+        {
+            msg_Dbg( vd, "video window resized (%ix%i +%i+%i)",
+                         width, height, x, y);
+
+            vout_display_SendEventDisplaySize( vd, width, height,
+                                               vd->cfg->is_fullscreen );
+        }
+        return 0;
+    }
+
+    case WM_VLC_UPDATE_RECT:
+        UpdateRects( p_event->vd, NULL, NULL, true );
         return 0;
 
     /* the user wants to close the window */
@@ -769,11 +492,12 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
         return 0;
 
     /* the window has been closed so shut down everything now */
+    /**
     case WM_DESTROY:
         msg_Dbg( vd, "WinProc WM_DESTROY" );
-        /* just destroy the window */
         PostQuitMessage( 0 );
         return 0;
+    **/
 
     case WM_SYSCOMMAND:
         switch (wParam)
@@ -845,6 +569,247 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
         break;
     }
 
+
+/*toto*/
+    {
+        vout_display_place_t place;
+        video_format_t       source;
+
+        POINT old_mouse_pos = {0,0}, mouse_pos;
+
+        if( !p_event->b_mouse_support && isMouseEvent( message ) )
+            goto fin;
+
+        if( !p_event->b_key_support && isKeyEvent( message ) )
+            goto fin;
+
+        /* */
+        switch( message )
+        {
+        case WM_MOUSEMOVE:
+        {
+            TRACKMOUSEEVENT TrackEvent;
+            TrackEvent.cbSize      = sizeof( TRACKMOUSEEVENT );
+            TrackEvent.dwFlags     = TME_LEAVE;
+            TrackEvent.hwndTrack   = hwnd;
+            TrackEvent.dwHoverTime = 1;
+            TrackMouseEvent( &TrackEvent );
+
+            vlc_mutex_lock( &p_event->lock );
+            place  = p_event->place;
+            source = p_event->source;
+            vlc_mutex_unlock( &p_event->lock );
+
+            if( place.width > 0 && place.height > 0 )
+            {
+                if( hwnd == p_event->hvideownd )
+                {
+                    /* Child window */
+                    place.x = 0;
+                    place.y = 0;
+                }
+                const int x = source.i_x_offset +
+                    (int64_t)(GET_X_LPARAM(lParam) - place.x) * source.i_width  / place.width;
+                const int y = source.i_y_offset +
+                    (int64_t)(GET_Y_LPARAM(lParam) - place.y) * source.i_height / place.height;
+                vout_display_SendEventMouseMoved(vd, x, y);
+            }
+        }
+            /* Fall through */
+        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_MOUSELEAVE:
+        {
+            POINT point;
+            GetCursorPos( &point );
+            HWND hwnd_now = WindowFromPoint(point);
+
+            msg_Err( p_event->vd, "MOUSELEAVE (%s) (%p), win now=(%p)",
+                          hwnd == p_event->hparent ? "hparent" :
+                          hwnd == p_event->hwnd ? "hwnd" :
+                          hwnd == p_event->hvideownd ? "hvideownd" :
+                                                       "other",
+                          hwnd,
+                          hwnd_now );
+
+            // if( hwnd_now != p_event->hwnd && hwnd_now != p_event->hvideownd )
+                EventThreadMouseShow( p_event );
+            break;
+        }
+
+#if 0
+        case WM_CHILDACTIVATE:
+            fprintf(stderr,"\n\n_____________WM_CHILDACTIVATE %s(%p) \n\n",
+                          hwnd == p_event->hparent ? "hparent" :
+                          hwnd == p_event->hwnd ? "hwnd" :
+                          hwnd == p_event->hvideownd ? "hvideownd" :
+                                                       "other",
+                          hwnd );
+            fflush(stderr);
+
+
+#ifdef MODULE_NAME_IS_directx
+
+    /* hack for directx : when moving a top level window, child windows are
+     * usually automatically moved without any notification. Yet, in the case
+     * of directx, the video surface is not moved alongside its window. So
+     * let's check regularly that we haven't moved, and update the video window
+     * if we did */
+
+    if (hwnd == p_event->hparent) {
+        RECT rect_parent;
+        POINT point;
+
+        GetClientRect(p_event->hparent, &rect_parent);
+        point.x = point.y = 0;
+        ClientToScreen(p_event->hparent, &point);
+        OffsetRect(&rect_parent, point.x, point.y);
+
+        if (!EqualRect(&rect_parent, &p_event->rect_parent)) {
+            p_event->rect_parent = rect_parent;
+            UpdateRects( p_event->vd, NULL, NULL, true);
+            // EventThreadAskUpdateRect(sys->event);
+        }
+    }
+
+#endif
+            break;
+
+#endif
+
+        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);
+            break;
+        case WM_LBUTTONUP:
+            vout_display_SendEventMouseReleased(vd, MOUSE_BUTTON_LEFT);
+            break;
+        case WM_LBUTTONDBLCLK:
+            vout_display_SendEventMouseDoubleClick(vd);
+            break;
+
+        case WM_MBUTTONDOWN:
+            vout_display_SendEventMousePressed(vd, MOUSE_BUTTON_CENTER);
+            break;
+        case WM_MBUTTONUP:
+            vout_display_SendEventMouseReleased(vd, MOUSE_BUTTON_CENTER);
+            break;
+
+        case WM_RBUTTONDOWN:
+            vout_display_SendEventMousePressed(vd, MOUSE_BUTTON_RIGHT);
+            break;
+        case WM_RBUTTONUP:
+            vout_display_SendEventMouseReleased(vd, MOUSE_BUTTON_RIGHT);
+            break;
+
+        case WM_KEYDOWN:
+        case WM_SYSKEYDOWN:
+        {
+            /* 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. */
+            int i_key = DirectXConvertKey( wParam );
+            if( !i_key )
+            {
+                /* This appears to be a "normal" (ascii) key */
+                i_key = tolower( MapVirtualKey( wParam, 2 ) );
+            }
+
+            if( i_key )
+            {
+                if( GetKeyState(VK_CONTROL) & 0x8000 )
+                {
+                    i_key |= KEY_MODIFIER_CTRL;
+                }
+                if( GetKeyState(VK_SHIFT) & 0x8000 )
+                {
+                    i_key |= KEY_MODIFIER_SHIFT;
+                }
+                if( GetKeyState(VK_MENU) & 0x8000 )
+                {
+                    i_key |= KEY_MODIFIER_ALT;
+                }
+
+                vout_display_SendEventKey(vd, i_key);
+            }
+            break;
+        }
+
+        case WM_MOUSEWHEEL:
+        {
+            int i_key;
+            if( GET_WHEEL_DELTA_WPARAM( wParam ) > 0 )
+            {
+                i_key = KEY_MOUSEWHEELUP;
+            }
+            else
+            {
+                i_key = KEY_MOUSEWHEELDOWN;
+            }
+            if( i_key )
+            {
+                if( GetKeyState(VK_CONTROL) & 0x8000 )
+                {
+                    i_key |= KEY_MODIFIER_CTRL;
+                }
+                if( GetKeyState(VK_SHIFT) & 0x8000 )
+                {
+                    i_key |= KEY_MODIFIER_SHIFT;
+                }
+                if( GetKeyState(VK_MENU) & 0x8000 )
+                {
+                    i_key |= KEY_MODIFIER_ALT;
+                }
+                vout_display_SendEventKey(vd, i_key);
+            }
+            break;
+        }
+
+        default:
+            break;
+
+        } /* End Switch */
+
+    } /* End Main loop */
+
+fin:
+
+    if(hwnd == p_event->hparent && p_event->fWndProc )
+    {
+        return CallWindowProc( p_event->fWndProc, hwnd, message, wParam, lParam);
+        // return p_event->fWndProc( hwnd, message, wParam, lParam);
+    }
+
     /* Let windows handle the message */
     return DefWindowProc(hwnd, message, wParam, lParam);
 }
@@ -947,12 +912,7 @@ void EventThreadUpdateTitle( event_thread_t *p_event, const char *psz_fallback )
     if( !psz_title )
         return;
 
-    vlc_mutex_lock( &p_event->lock );
-    free( p_event->psz_title );
-    p_event->psz_title = psz_title;
-    vlc_mutex_unlock( &p_event->lock );
-
-    PostMessage( p_event->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
+    PostMessage( p_event->hparent, WM_VLC_CHANGE_TEXT, 0, 0 );
 }
 int EventThreadGetWindowStyle( event_thread_t *p_event )
 {
@@ -967,8 +927,8 @@ void EventThreadUpdateWindowPosition( event_thread_t *p_event,
     vlc_mutex_lock( &p_event->lock );
     *pb_moved   = x != p_event->wnd_cfg.x ||
                   y != p_event->wnd_cfg.y;
-    *pb_resized = w != p_event->wnd_cfg.width ||
-                  h != p_event->wnd_cfg.height;
+    *pb_resized = w != (int)p_event->wnd_cfg.width ||
+                  h != (int)p_event->wnd_cfg.height;
 
     p_event->wnd_cfg.x      = x;
     p_event->wnd_cfg.y      = y;
@@ -993,14 +953,10 @@ void EventThreadUseOverlay( event_thread_t *p_event, bool b_used )
     p_event->use_overlay = b_used;
     vlc_mutex_unlock( &p_event->lock );
 }
-bool EventThreadGetAndResetHasMoved( event_thread_t *p_event )
-{
-    vlc_mutex_lock( &p_event->lock );
-    const bool has_moved = p_event->has_moved;
-    p_event->has_moved = false;
-    vlc_mutex_unlock( &p_event->lock );
 
-    return has_moved;
+void EventThreadAskUpdateRect( event_thread_t *p_event )
+{
+    PostMessage( p_event->hwnd, WM_VLC_UPDATE_RECT, 0, 0 );
 }
 
 event_thread_t *EventThreadCreate( vout_display_t *vd)
@@ -1013,7 +969,7 @@ event_thread_t *EventThreadCreate( vout_display_t *vd)
      * window (because PeekMessage has to be called from the same thread which
      * created the window). */
     msg_Dbg( vd, "creating Vout EventThread" );
-    event_thread_t *p_event = malloc( sizeof(*p_event) );
+    event_thread_t *p_event = calloc( 1, sizeof(*p_event) );
     if( !p_event )
         return NULL;
 
@@ -1021,11 +977,13 @@ event_thread_t *EventThreadCreate( vout_display_t *vd)
     vlc_mutex_init( &p_event->lock );
     vlc_cond_init( &p_event->wait );
 
+    SetRectEmpty(&p_event->rect_parent);
     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->psz_title = NULL;
+    p_event->b_mouse_support = var_InheritBool(vd, "mouse-events");
+    p_event->b_key_support = var_InheritBool(vd, "keyboard-events");
     p_event->source = vd->source;
     vout_display_PlacePicture(&p_event->place, &vd->source, vd->cfg, true);
 
@@ -1034,7 +992,6 @@ event_thread_t *EventThreadCreate( vout_display_t *vd)
 
 void EventThreadDestroy( event_thread_t *p_event )
 {
-    free( p_event->psz_title );
     vlc_cond_destroy( &p_event->wait );
     vlc_mutex_destroy( &p_event->lock );
     free( p_event );
@@ -1042,35 +999,31 @@ void EventThreadDestroy( event_thread_t *p_event )
 
 int EventThreadStart( event_thread_t *p_event, event_hwnd_t *p_hwnd, const event_cfg_t *p_cfg )
 {
-    p_event->use_desktop = p_cfg->use_desktop;
+    vlc_mutex_lock( &p_event->lock );
+
     p_event->use_overlay = p_cfg->use_overlay;
     p_event->wnd_cfg     = p_cfg->win;
 
-    p_event->has_moved = false;
+    p_event->wnd_cfg.setup = WindowSetup;
+    p_event->wnd_cfg.cleanup = WindowCleanup;
+    p_event->wnd_cfg.data = p_event;
 
     p_event->b_ready = false;
     p_event->b_done  = false;
     p_event->b_error = false;
 
-    if( vlc_clone( &p_event->thread, EventThread, p_event,
-                   VLC_THREAD_PRIORITY_LOW ) )
+    p_event->hparent = NULL;
+
+    vout_display_t *vd = p_event->vd;
+    p_event->parent_window = vout_display_NewWindow(vd, &p_event->wnd_cfg);
+    if( !p_event->parent_window )
     {
-        msg_Err( p_event->vd, "cannot create Vout EventThread" );
+        vlc_mutex_unlock( &p_event->lock );
         return VLC_EGENERIC;
     }
 
-    vlc_mutex_lock( &p_event->lock );
-    while( !p_event->b_ready )
-        vlc_cond_wait( &p_event->wait, &p_event->lock );
-    const bool b_error = p_event->b_error;
-    vlc_mutex_unlock( &p_event->lock );
+    p_event->hparent = p_event->parent_window->handle.hwnd;
 
-    if( b_error )
-    {
-        vlc_join( p_event->thread, NULL );
-        p_event->b_ready = false;
-        return VLC_EGENERIC;
-    }
     msg_Dbg( p_event->vd, "Vout EventThread running" );
 
     /* */
@@ -1079,24 +1032,18 @@ int EventThreadStart( event_thread_t *p_event, event_hwnd_t *p_hwnd, const event
     p_hwnd->hwnd          = p_event->hwnd;
     p_hwnd->hvideownd     = p_event->hvideownd;
     p_hwnd->hfswnd        = p_event->hfswnd;
+
+    vlc_mutex_unlock( &p_event->lock );
+
     return VLC_SUCCESS;
 }
 
 void EventThreadStop( event_thread_t *p_event )
 {
-    if( !p_event->b_ready )
-        return;
-
     vlc_mutex_lock( &p_event->lock );
-    p_event->b_done = true;
-    vlc_mutex_unlock( &p_event->lock );
 
-    /* we need to be sure Vout EventThread won't stay stuck in
-     * GetMessage, so we send a fake message */
-    if( p_event->hwnd )
-        PostMessage( p_event->hwnd, WM_NULL, 0, 0);
+    vout_display_DeleteWindow( p_event->vd, p_event->parent_window );
 
-    vlc_join( p_event->thread, NULL );
-    p_event->b_ready = false;
+    vlc_mutex_unlock( &p_event->lock );
 }
 
diff --git a/modules/video_output/msw/events.h b/modules/video_output/msw/events.h
index 43828f4..155a353 100644
--- a/modules/video_output/msw/events.h
+++ b/modules/video_output/msw/events.h
@@ -59,5 +59,5 @@ void            EventThreadUpdateSourceAndPlace( event_thread_t *p_event,
                                                  const video_format_t *p_source,
                                                  const vout_display_place_t *p_place );
 void            EventThreadUseOverlay( event_thread_t *, bool b_used );
-bool            EventThreadGetAndResetHasMoved( event_thread_t * );
+void            EventThreadAskUpdateRect( event_thread_t * );
 
-- 
1.5.6.5


