Commit 92be1f61 authored by gbazin's avatar gbazin

* modules/video_output/directx/*:

  - Major changes to way the embedded vout is handled.
    + the vout windows are created in our event thread so we do receive the events now.
    + we do not use the external window directly (as for normal vout we create our vout window + video sub-window).
    + Create a WS_EX_NOPARENTNOTIFY vout window to make mozilla happy.
  - Improved the mouse auto-hide feature.
  - Do the DirectXUpdateOverlay() in the events thread. This should make S3 graphics cards happy again.
parent 10a593e4
......@@ -160,7 +160,7 @@ vlc_module_end();
static int OpenVideo( vlc_object_t *p_this )
{
vout_thread_t * p_vout = (vout_thread_t *)p_this;
vlc_value_t val, text;
vlc_value_t val;
HMODULE huser32;
/* Allocate structure */
......@@ -186,7 +186,9 @@ static int OpenVideo( vlc_object_t *p_this )
p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL;
p_vout->p_sys->hparent = NULL;
p_vout->p_sys->i_changes = 0;
SetRectEmpty( &p_vout->p_sys->rect_display );
vlc_mutex_init( p_vout, &p_vout->p_sys->lock );
SetRectEmpty( &p_vout->p_sys->rect_display );
SetRectEmpty( &p_vout->p_sys->rect_parent );
/* Multimonitor stuff */
p_vout->p_sys->hmonitor = NULL;
......@@ -371,8 +373,7 @@ static int Init( vout_thread_t *p_vout )
}
/* Change the window title bar text */
if( p_vout->p_sys->hparent ) ; /* Do nothing */
else PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
return VLC_SUCCESS;
}
......@@ -422,6 +423,8 @@ static void CloseVideo( vlc_object_t *p_this )
vlc_object_destroy( p_vout->p_sys->p_event );
}
vlc_mutex_destroy( &p_vout->p_sys->lock );
if( p_vout->p_sys )
{
free( p_vout->p_sys );
......@@ -441,9 +444,37 @@ static int Manage( vout_thread_t *p_vout )
/* If we do not control our window, we check for geometry changes
* ourselves because the parent might not send us its events. */
vlc_mutex_lock( &p_vout->p_sys->lock );
if( p_vout->p_sys->hparent )
{
DirectXUpdateRects( p_vout, VLC_FALSE );
RECT rect_parent;
POINT point;
vlc_mutex_unlock( &p_vout->p_sys->lock );
GetClientRect( p_vout->p_sys->hparent, &rect_parent );
point.x = point.y = 0;
ClientToScreen( p_vout->p_sys->hparent, &point );
OffsetRect( &rect_parent, point.x, point.y );
if( !EqualRect( &rect_parent, &p_vout->p_sys->rect_parent ) )
{
p_vout->p_sys->rect_parent = rect_parent;
/* This one is to force the update even if only
* the position has changed */
SetWindowPos( p_vout->p_sys->hwnd, 0, 1, 1,
rect_parent.right - rect_parent.left,
rect_parent.bottom - rect_parent.top, 0 );
SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
rect_parent.right - rect_parent.left,
rect_parent.bottom - rect_parent.top, 0 );
}
}
else
{
vlc_mutex_unlock( &p_vout->p_sys->lock );
}
/*
......@@ -453,9 +484,6 @@ static int Manage( vout_thread_t *p_vout )
{
p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE;
if( p_vout->p_sys->b_using_overlay )
DirectXUpdateOverlay( p_vout );
/* Check if we are still on the same monitor */
if( p_vout->p_sys->MonitorFromWindow &&
p_vout->p_sys->hmonitor !=
......@@ -478,6 +506,7 @@ static int Manage( vout_thread_t *p_vout )
if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
|| p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
{
int i_style = 0;
vlc_value_t val;
p_vout->b_fullscreen = ! p_vout->b_fullscreen;
......@@ -487,21 +516,33 @@ static int Manage( vout_thread_t *p_vout )
GetWindowPlacement( p_vout->p_sys->hwnd, &window_placement );
if( p_vout->b_fullscreen )
{
if( p_vout->p_sys->hparent )
SetParent( p_vout->p_sys->hwnd, GetDesktopWindow() );
/* Maximized window */
window_placement.showCmd = SW_SHOWMAXIMIZED;
/* Change window style, no borders and no title bar */
SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE, WS_CLIPCHILDREN );
i_style = WS_CLIPCHILDREN;
}
else
{
if( p_vout->p_sys->hparent )
{
SetParent( p_vout->p_sys->hwnd, p_vout->p_sys->hparent );
i_style = WS_CLIPCHILDREN | WS_VISIBLE | WS_CHILD;
}
else
{
i_style = WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW |
WS_SIZEBOX | WS_VISIBLE;
}
/* Normal window */
window_placement.showCmd = SW_SHOWNORMAL;
/* Change window style, borders and title bar */
SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE, WS_CLIPCHILDREN |
WS_OVERLAPPEDWINDOW | WS_SIZEBOX | WS_VISIBLE );
}
/* Change window style, borders and title bar */
SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE, i_style );
SetWindowPlacement( p_vout->p_sys->hwnd, &window_placement );
/* Update the object variable and trigger callback */
......@@ -518,12 +559,24 @@ static int Manage( vout_thread_t *p_vout )
if( (!p_vout->p_sys->b_cursor_hidden) &&
( (mdate() - p_vout->p_sys->i_lastmoved) > 5000000 ) )
{
/* Hide the mouse automatically */
if( p_vout->p_sys->hwnd != p_vout->p_sys->hparent )
POINT point;
RECT rect;
/* Hide the cursor only if it is inside our window */
GetClientRect( p_vout->p_sys->hwnd, &rect );
point.x = point.y = 0;
ClientToScreen( p_vout->p_sys->hwnd, &point );
OffsetRect( &rect, point.x, point.y );
GetCursorPos( &point );
if( PtInRect( &rect, point ) )
{
p_vout->p_sys->b_cursor_hidden = VLC_TRUE;
PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
}
else
{
p_vout->p_sys->i_lastmoved = mdate();
}
}
/*
......@@ -1084,9 +1137,14 @@ int DirectXUpdateOverlay( vout_thread_t *p_vout )
RECT rect_src = p_vout->p_sys->rect_src_clipped;
RECT rect_dest = p_vout->p_sys->rect_dest_clipped;
if( p_vout->p_sys->p_current_surface == NULL ||
!p_vout->p_sys->b_using_overlay )
if( !p_vout->p_sys->b_using_overlay ) return VLC_EGENERIC;
vlc_mutex_lock( &p_vout->p_sys->lock );
if( p_vout->p_sys->p_current_surface == NULL )
{
vlc_mutex_unlock( &p_vout->p_sys->lock );
return VLC_EGENERIC;
}
/* The new window dimensions should already have been computed by the
* caller of this function */
......@@ -1103,6 +1161,9 @@ int DirectXUpdateOverlay( vout_thread_t *p_vout )
p_vout->p_sys->p_current_surface,
&rect_src, p_vout->p_sys->p_display, &rect_dest,
dwFlags, &ddofx );
vlc_mutex_unlock( &p_vout->p_sys->lock );
if(dxresult != DD_OK)
{
msg_Warn( p_vout, "DirectXUpdateOverlay cannot move/resize overlay" );
......@@ -1435,6 +1496,10 @@ static void FreePictureVec( vout_thread_t *p_vout, picture_t *p_pic,
{
int i;
vlc_mutex_lock( &p_vout->p_sys->lock );
p_vout->p_sys->p_current_surface = 0;
vlc_mutex_unlock( &p_vout->p_sys->lock );
for( i = 0; i < i_num_pics; i++ )
{
DirectXCloseSurface( p_vout, p_pic[i].p_sys->p_front_surface );
......@@ -1444,8 +1509,6 @@ static void FreePictureVec( vout_thread_t *p_vout, picture_t *p_pic,
free( p_pic[i].p_sys );
}
}
p_vout->p_sys->p_current_surface = 0;
}
/*****************************************************************************
......
......@@ -81,7 +81,7 @@ static int DirectXConvertKey( int i_key );
void 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;
......@@ -118,21 +118,13 @@ 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 && ( 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, 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 )
{
/* Parent window was created in another thread so we can't
* access the window messages. */
msleep( INTF_IDLE_SLEEP );
continue;
}
switch( msg.message )
{
......@@ -162,8 +154,9 @@ void DirectXEventThread( event_thread_t *p_event )
}
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();
......@@ -348,6 +341,10 @@ static int DirectXCreateWindow( vout_thread_t *p_vout )
HINSTANCE hInstance;
HMENU hMenu;
RECT rect_window;
WNDCLASSEX wc; /* window class components */
HICON vlc_icon = NULL;
char vlc_path[MAX_PATH+1];
int i_style;
msg_Dbg( p_vout, "DirectXCreateWindow" );
......@@ -355,116 +352,99 @@ static int DirectXCreateWindow( vout_thread_t *p_vout )
hInstance = GetModuleHandle(NULL);
/* If an external window was specified, we'll draw in it. */
p_vout->p_sys->hparent = p_vout->p_sys->hwnd =
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 );
if( p_vout->p_sys->hparent )
/* 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;
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). */
SetWindowLongPtr( p_vout->p_sys->hwnd, GWLP_USERDATA, (LONG_PTR)p_vout );
p_vout->p_sys->pf_wndproc =
(WNDPROC)SetWindowLong( p_vout->p_sys->hwnd, GWLP_WNDPROC,
(LONG_PTR)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
/* 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) )
{
WNDCLASSEX wc; /* window class components */
HICON vlc_icon = NULL;
char vlc_path[MAX_PATH+1];
WNDCLASS wndclass;
/* We create the window ourself, there is no previous window proc. */
p_vout->p_sys->pf_wndproc = NULL;
if( vlc_icon ) DestroyIcon( vlc_icon );
/* Get the Icon from the main app */
vlc_icon = NULL;
if( GetModuleFileName( NULL, vlc_path, MAX_PATH ) )
/* Check why it failed. If it's because one already exists
* then fine, otherwise return with an error. */
if( !GetClassInfo( hInstance, "VLC DirectX", &wndclass ) )
{
vlc_icon = ExtractIcon( hInstance, vlc_path, 0 );
msg_Err( p_vout, "DirectXCreateWindow RegisterClass FAILED" );
return VLC_EGENERIC;
}
}
/* 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) )
{
WNDCLASS wndclass;
/* 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 );
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
* 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 );
if( p_vout->p_sys->hparent )
i_style = WS_VISIBLE|WS_CLIPCHILDREN|WS_CHILD;
else
i_style = WS_OVERLAPPEDWINDOW|WS_SIZEBOX|WS_VISIBLE|WS_CLIPCHILDREN;
/* Create the window */
p_vout->p_sys->hwnd =
CreateWindow( "VLC DirectX", /* name of window class */
/* Create the window */
p_vout->p_sys->hwnd =
CreateWindowEx( WS_EX_NOPARENTNOTIFY,
"VLC DirectX", /* name of window class */
VOUT_TITLE " (DirectX Output)", /* window title bar text */
WS_OVERLAPPEDWINDOW | WS_SIZEBOX | WS_VISIBLE |
WS_CLIPCHILDREN, /* window style */
i_style, /* window style */
(p_vout->p_sys->i_window_x < 0) ? CW_USEDEFAULT :
p_vout->p_sys->i_window_x, /* default X coordinate */
(p_vout->p_sys->i_window_y < 0) ? CW_USEDEFAULT :
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;
}
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 );
SetWindowLong( p_vout->p_sys->hparent, GWL_STYLE,
i_style | WS_CLIPCHILDREN );
}
/* Now display the window */
......@@ -493,25 +473,10 @@ 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 */
SetWindowLongPtr( p_vout->p_sys->hwnd,
GWLP_WNDPROC, (LONG_PTR)p_vout->p_sys->pf_wndproc );
SetWindowLongPtr( p_vout->p_sys->hwnd, GWLP_USERDATA, 0 );
/* Blam! Erase everything that might have been there. */
InvalidateRect( p_vout->p_sys->hwnd, NULL, TRUE );
DestroyWindow( p_vout->p_sys->hwnd );
if( p_vout->p_sys->hparent )
vout_ReleaseWindow( p_vout, (void *)p_vout->p_sys->hparent );
}
p_vout->p_sys->hwnd = NULL;
......@@ -662,6 +627,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( p_vout->p_sys->b_using_overlay )
DirectXUpdateOverlay( p_vout );
/* Signal the change in size/position */
p_vout->p_sys->i_changes |= DX_POSITION_CHANGE;
......@@ -799,31 +767,8 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
break;
}
if( p_vout->p_sys->pf_wndproc )
{
LRESULT i_ret;
/* Hmmm mozilla does manage somehow to save the pointer to our
* windowproc and will call us again whereby creating an
* infinite loop.
* We can detect this by resetting GWL_USERDATA before calling
* the parent's windowproc. */
SetWindowLongPtr( p_vout->p_sys->hwnd, GWLP_USERDATA, 0 );
/* Call next window proc in chain */
i_ret = CallWindowProc( p_vout->p_sys->pf_wndproc, hwnd, message,
wParam, lParam );
SetWindowLongPtr( p_vout->p_sys->hwnd, GWLP_USERDATA,
(LONG_PTR)p_vout );
return i_ret;
}
else
{
/* Let windows handle the message */
return DefWindowProc(hwnd, message, wParam, lParam);
}
/* Let windows handle the message */
return DefWindowProc(hwnd, message, wParam, lParam);
}
static long FAR PASCAL DirectXVideoEventProc( HWND hwnd, UINT message,
......@@ -834,10 +779,6 @@ static long FAR PASCAL DirectXVideoEventProc( HWND hwnd, UINT message,
switch( message )
{
case WM_VLC_DESTROY_VIDEO_WIN:
/* Destroy video sub-window */
DestroyWindow( hwnd );
break;
case WM_MOUSEMOVE:
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
......@@ -961,6 +902,21 @@ static int Control( vout_thread_t *p_vout, int i_query, va_list args )
return VLC_SUCCESS;
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 );
SetParent( p_vout->p_sys->hwnd, GetDesktopWindow() );
SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE,
WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW |
WS_SIZEBOX | WS_VISIBLE );
SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0, 0, 0,
SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED );
return VLC_SUCCESS;
case VOUT_CLOSE:
return VLC_SUCCESS;
......
......@@ -77,6 +77,7 @@ struct vout_sys_t
RECT rect_src_clipped;
RECT rect_dest;
RECT rect_dest_clipped;
RECT rect_parent;
/* Overlay alignment restrictions */
int i_align_src_boundary;
......@@ -97,9 +98,10 @@ struct vout_sys_t
volatile mtime_t i_lastmoved;
/* Misc */
vlc_bool_t b_on_top_change;
vlc_bool_t b_on_top_change;
event_thread_t * p_event;
event_thread_t *p_event;
vlc_mutex_t lock;
};
/*****************************************************************************
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment