Commit e54cc504 authored by Damien Fouilleul's avatar Damien Fouilleul

vout: merged all Microsoft Windows specific vouts under msw directory in order...

vout: merged all Microsoft Windows specific vouts under msw directory in order to leverage common event handling
parent dde6aaf8
......@@ -5916,7 +5916,7 @@ AC_CONFIG_FILES([
modules/video_chroma/Makefile
modules/video_filter/Makefile
modules/video_output/Makefile
modules/video_output/directx/Makefile
modules/video_output/msw/Makefile
modules/video_output/qte/Makefile
modules/video_output/x11/Makefile
modules/visualization/Makefile
......
......@@ -5,8 +5,6 @@ SOURCES_ggi = ggi.c
SOURCES_glide = glide.c
SOURCES_vout_sdl = sdl.c
SOURCES_svgalib = svgalib.c
SOURCES_wingdi = wingdi.c
SOURCES_wingapi = wingdi.c
SOURCES_mga = mga.c
SOURCES_hd1000v = hd1000v.cpp
SOURCES_snapshot = snapshot.c
......
......@@ -15,3 +15,15 @@ SOURCES_glwin32 = \
vout.h \
events.c \
$(NULL)
SOURCES_wingdi = \
wingdi.c \
vout.h \
events.c \
$(NULL)
SOURCES_wingapi = \
windi.c \
vout.h \
events.c \
$(NULL)
......@@ -138,7 +138,7 @@ typedef struct
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
/*****************************************************************************
* OpenVideo: allocate DirectX video thread output method
* OpenVideo: allocate Vout video thread output method
*****************************************************************************
* This function allocates and initialize the Direct3D vout method.
*****************************************************************************/
......@@ -172,15 +172,12 @@ static int OpenVideo( vlc_object_t *p_this )
p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL;
p_vout->p_sys->hparent = p_vout->p_sys->hfswnd = NULL;
p_vout->p_sys->i_changes = 0;
p_vout->p_sys->b_wallpaper = 0;
vlc_mutex_init( p_vout, &p_vout->p_sys->lock );
SetRectEmpty( &p_vout->p_sys->rect_display );
SetRectEmpty( &p_vout->p_sys->rect_parent );
var_Create( p_vout, "directx-hw-yuv", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
var_Create( p_vout, "directx-device", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
var_Create( p_vout, "disable-screensaver", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
p_vout->p_sys->b_cursor_hidden = 0;
p_vout->p_sys->i_lastmoved = mdate();
......@@ -192,21 +189,21 @@ static int OpenVideo( vlc_object_t *p_this )
p_vout->p_sys->i_window_width = p_vout->i_window_width;
p_vout->p_sys->i_window_height = p_vout->i_window_height;
/* Create the DirectXEventThread, this thread is created by us to isolate
/* Create the Vout EventThread, this thread is created by us to isolate
* the Win32 PeekMessage function calls. We want to do this because
* Windows can stay blocked inside this call for a long time, and when
* this happens it thus blocks vlc's video_output thread.
* DirectXEventThread will take care of the creation of the video
* Vout EventThread will take care of the creation of the video
* window (because PeekMessage has to be called from the same thread which
* created the window). */
msg_Dbg( p_vout, "creating DirectXEventThread" );
msg_Dbg( p_vout, "creating Vout EventThread" );
p_vout->p_sys->p_event =
vlc_object_create( p_vout, sizeof(event_thread_t) );
p_vout->p_sys->p_event->p_vout = p_vout;
if( vlc_thread_create( p_vout->p_sys->p_event, "DirectX Events Thread",
E_(DirectXEventThread), 0, 1 ) )
if( vlc_thread_create( p_vout->p_sys->p_event, "Vout Events Thread",
E_(EventThread), 0, 1 ) )
{
msg_Err( p_vout, "cannot create DirectXEventThread" );
msg_Err( p_vout, "cannot create Vout EventThread" );
vlc_object_destroy( p_vout->p_sys->p_event );
p_vout->p_sys->p_event = NULL;
goto error;
......@@ -214,13 +211,13 @@ static int OpenVideo( vlc_object_t *p_this )
if( p_vout->p_sys->p_event->b_error )
{
msg_Err( p_vout, "DirectXEventThread failed" );
msg_Err( p_vout, "Vout EventThread failed" );
goto error;
}
vlc_object_attach( p_vout->p_sys->p_event, p_vout );
msg_Dbg( p_vout, "DirectXEventThread running" );
msg_Dbg( p_vout, "Vout EventThread running" );
/* Variable to indicate if the window should be on top of others */
/* Trigger a callback right now */
......@@ -272,10 +269,10 @@ static void CloseVideo( vlc_object_t *p_this )
{
vlc_object_detach( p_vout->p_sys->p_event );
/* Kill DirectXEventThread */
/* Kill Vout EventThread */
p_vout->p_sys->p_event->b_die = VLC_TRUE;
/* we need to be sure DirectXEventThread won't stay stuck in
/* we need to be sure Vout EventThread won't stay stuck in
* GetMessage, so we send a fake message */
if( p_vout->p_sys->hwnd )
{
......@@ -334,7 +331,7 @@ static int Init( vout_thread_t *p_vout )
p_vout->output.i_height = p_vout->render.i_height;
p_vout->output.i_aspect = p_vout->render.i_aspect;
p_vout->fmt_out = p_vout->fmt_in;
E_(DirectXUpdateRects)( p_vout, VLC_TRUE );
E_(UpdateRects)( p_vout, VLC_TRUE );
/* create picture pool */
i_ret = Direct3DVoutCreatePictures(p_vout, 1);
......@@ -451,7 +448,7 @@ static int Manage( vout_thread_t *p_vout )
p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
E_(DirectXUpdateRects)( p_vout, VLC_TRUE );
E_(UpdateRects)( p_vout, VLC_TRUE );
}
/* We used to call the Win32 PeekMessage function here to read the window
......@@ -708,7 +705,8 @@ static int Direct3DVoutOpen( vout_thread_t *p_vout )
// Create the D3DDevice
hr = IDirect3D9_CreateDevice(p_d3dobj, D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL, p_vout->p_sys->hvideownd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
D3DCREATE_SOFTWARE_VERTEXPROCESSING|
D3DCREATE_MULTITHREADED,
&d3dpp, &p_d3ddev );
if( FAILED(hr) )
{
......
......@@ -264,7 +264,7 @@ static int OpenVideo( vlc_object_t *p_this )
p_vout->p_sys->i_window_width = p_vout->i_window_width;
p_vout->p_sys->i_window_height = p_vout->i_window_height;
/* Create the DirectXEventThread, this thread is created by us to isolate
/* Create the Vout EventThread, this thread is created by us to isolate
* the Win32 PeekMessage function calls. We want to do this because
* Windows can stay blocked inside this call for a long time, and when
* this happens it thus blocks vlc's video_output thread.
......@@ -275,10 +275,10 @@ static int OpenVideo( vlc_object_t *p_this )
p_vout->p_sys->p_event =
vlc_object_create( p_vout, sizeof(event_thread_t) );
p_vout->p_sys->p_event->p_vout = p_vout;
if( vlc_thread_create( p_vout->p_sys->p_event, "DirectX Events Thread",
E_(DirectXEventThread), 0, 1 ) )
if( vlc_thread_create( p_vout->p_sys->p_event, "Vout Events Thread",
E_(EventThread), 0, 1 ) )
{
msg_Err( p_vout, "cannot create DirectXEventThread" );
msg_Err( p_vout, "cannot create Vout EventThread" );
vlc_object_destroy( p_vout->p_sys->p_event );
p_vout->p_sys->p_event = NULL;
goto error;
......@@ -286,25 +286,25 @@ static int OpenVideo( vlc_object_t *p_this )
if( p_vout->p_sys->p_event->b_error )
{
msg_Err( p_vout, "DirectXEventThread failed" );
msg_Err( p_vout, "Vout EventThread failed" );
goto error;
}
vlc_object_attach( p_vout->p_sys->p_event, p_vout );
msg_Dbg( p_vout, "DirectXEventThread running" );
msg_Dbg( p_vout, "Vout EventThread running" );
/* Initialise DirectDraw */
if( DirectXInitDDraw( p_vout ) )
{
msg_Err( p_vout, "cannot initialize DirectDraw" );
msg_Err( p_vout, "cannot initialize DirectX DirectDraw" );
goto error;
}
/* Create the directx display */
if( DirectXCreateDisplay( p_vout ) )
{
msg_Err( p_vout, "cannot initialize DirectDraw" );
msg_Err( p_vout, "cannot initialize DirectX DirectDraw" );
goto error;
}
......@@ -399,7 +399,7 @@ static int Init( vout_thread_t *p_vout )
p_vout->output.i_height = p_vout->render.i_height;
p_vout->output.i_aspect = p_vout->render.i_aspect;
p_vout->fmt_out = p_vout->fmt_in;
E_(DirectXUpdateRects)( p_vout, VLC_TRUE );
E_(UpdateRects)( p_vout, VLC_TRUE );
#define MAX_DIRECTBUFFERS 1
/* Right now we use only 1 directbuffer because we don't want the
......@@ -492,10 +492,10 @@ static void CloseVideo( vlc_object_t *p_this )
{
vlc_object_detach( p_vout->p_sys->p_event );
/* Kill DirectXEventThread */
/* Kill Vout EventThread */
p_vout->p_sys->p_event->b_die = VLC_TRUE;
/* we need to be sure DirectXEventThread won't stay stuck in
/* we need to be sure Vout EventThread won't stay stuck in
* GetMessage, so we send a fake message */
if( p_vout->p_sys->hwnd )
{
......@@ -608,7 +608,7 @@ static int Manage( vout_thread_t *p_vout )
p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
E_(DirectXUpdateRects)( p_vout, VLC_TRUE );
E_(UpdateRects)( p_vout, VLC_TRUE );
}
/* We used to call the Win32 PeekMessage function here to read the window
......@@ -620,7 +620,7 @@ static int Manage( vout_thread_t *p_vout )
{
SwitchWallpaperMode( p_vout, !p_vout->p_sys->b_wallpaper );
p_vout->p_sys->i_changes &= ~DX_WALLPAPER_CHANGE;
E_(DirectXUpdateOverlay)( p_vout );
DirectDrawUpdateOverlay( p_vout );
}
/*
......@@ -722,7 +722,7 @@ static void Display( vout_thread_t *p_vout, picture_t *p_pic )
{
if( IDirectDrawSurface2_Restore( p_vout->p_sys->p_display ) == DD_OK &&
p_vout->p_sys->b_using_overlay )
E_(DirectXUpdateOverlay)( p_vout );
DirectDrawUpdateOverlay( p_vout );
}
if( !p_vout->p_sys->b_using_overlay )
......@@ -1056,7 +1056,7 @@ static int DirectXCreateDisplay( vout_thread_t *p_vout )
p_vout->p_sys->i_rgb_colorkey =
DirectXFindColorkey( p_vout, &p_vout->p_sys->i_colorkey );
E_(DirectXUpdateRects)( p_vout, VLC_TRUE );
E_(UpdateRects)( p_vout, VLC_TRUE );
return VLC_SUCCESS;
}
......@@ -1224,7 +1224,7 @@ static int DirectXCreateSurface( vout_thread_t *p_vout,
/* Check the overlay is useable as some graphics cards allow creating
* several overlays but only one can be used at one time. */
p_vout->p_sys->p_current_surface = *pp_surface_final;
if( E_(DirectXUpdateOverlay)( p_vout ) != VLC_SUCCESS )
if( DirectDrawUpdateOverlay( p_vout ) != VLC_SUCCESS )
{
IDirectDrawSurface2_Release( *pp_surface_final );
*pp_surface_final = NULL;
......@@ -1237,13 +1237,13 @@ static int DirectXCreateSurface( vout_thread_t *p_vout,
}
/*****************************************************************************
* DirectXUpdateOverlay: Move or resize overlay surface on video display.
* DirectDrawUpdateOverlay: Move or resize overlay surface on video display.
*****************************************************************************
* This function is used to move or resize an overlay surface on the screen.
* Ususally the overlay is moved by the user and thus, by a move or resize
* event (in Manage).
*****************************************************************************/
int E_(DirectXUpdateOverlay)( vout_thread_t *p_vout )
int DirectDrawUpdateOverlay( vout_thread_t *p_vout )
{
DDOVERLAYFX ddofx;
DWORD dwFlags;
......@@ -1299,7 +1299,7 @@ int E_(DirectXUpdateOverlay)( vout_thread_t *p_vout )
if(dxresult != DD_OK)
{
msg_Warn( p_vout, "DirectXUpdateOverlay cannot move/resize overlay" );
msg_Warn( p_vout, "DirectDrawUpdateOverlay cannot move/resize overlay" );
return VLC_EGENERIC;
}
......@@ -1465,7 +1465,7 @@ static int NewPictureVec( vout_thread_t *p_vout, picture_t *p_pic,
DirectXUnlockSurface( p_vout, &front_pic );
}
E_(DirectXUpdateOverlay)( p_vout );
DirectDrawUpdateOverlay( p_vout );
I_OUTPUTPICTURES = 1;
msg_Dbg( p_vout, "YUV overlay created successfully" );
}
......
......@@ -57,6 +57,13 @@
#include "vlc_keys.h"
#include "vout.h"
#if defined(UNDER_CE) && !defined(__PLUGIN__) /*FIXME*/
# define SHFS_SHOWSIPBUTTON 0x0004
# define SHFS_HIDESIPBUTTON 0x0008
# define MENU_HEIGHT 26
BOOL SHFullScreen(HWND hwndRequester, DWORD dwState);
#endif
/*****************************************************************************
* Local prototypes.
*****************************************************************************/
......@@ -82,14 +89,14 @@ static void DirectXPopupMenu( event_thread_t *p_event, vlc_bool_t b_open )
static int DirectXConvertKey( int i_key );
/*****************************************************************************
* DirectXEventThread: Create video window & handle its messages
* EventThread: Create video window & handle its messages
*****************************************************************************
* 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.
*****************************************************************************/
void E_(DirectXEventThread)( event_thread_t *p_event )
void E_(EventThread)( event_thread_t *p_event )
{
MSG msg;
POINT old_mouse_pos = {0,0}, mouse_pos;
......@@ -112,6 +119,7 @@ void E_(DirectXEventThread)( event_thread_t *p_event )
/* Signal the creation of the window */
vlc_thread_ready( p_event );
#ifndef UNDER_CE
/* Set power management stuff */
if( (hkernel32 = GetModuleHandle( _T("KERNEL32") ) ) )
{
......@@ -126,6 +134,7 @@ void E_(DirectXEventThread)( event_thread_t *p_event )
else
msg_Dbg( p_event, "no support for SetThreadExecutionState()" );
}
#endif
/* Main loop */
/* GetMessage will sleep if there's no message in the queue */
......@@ -307,6 +316,12 @@ void E_(DirectXEventThread)( event_thread_t *p_event )
{
if( val.psz_string ) free( val.psz_string );
#ifdef MODULE_NAME_IS_wingdi
val.psz_string = strdup( VOUT_TITLE " (WinGDI output)" );
#endif
#ifdef MODULE_NAME_IS_wingapi
val.psz_string = strdup( VOUT_TITLE " (WinGAPI output)" );
#endif
#ifdef MODULE_NAME_IS_glwin32
val.psz_string = strdup( VOUT_TITLE " (OpenGL output)" );
#endif
......@@ -315,11 +330,11 @@ void E_(DirectXEventThread)( event_thread_t *p_event )
#endif
#ifdef MODULE_NAME_IS_vout_directx
if( p_event->p_vout->p_sys->b_using_overlay ) val.psz_string =
strdup( VOUT_TITLE " (hardware YUV overlay DirectX output)" );
strdup( VOUT_TITLE " (hardware YUV overlay DirectX output)" );
else if( p_event->p_vout->p_sys->b_hw_yuv ) val.psz_string =
strdup( VOUT_TITLE " (hardware YUV DirectX output)" );
strdup( VOUT_TITLE " (hardware YUV DirectX output)" );
else val.psz_string =
strdup( VOUT_TITLE " (software RGB DirectX output)" );
strdup( VOUT_TITLE " (software RGB DirectX output)" );
#endif
}
......@@ -585,13 +600,13 @@ static void DirectXCloseWindow( vout_thread_t *p_vout )
}
/*****************************************************************************
* DirectXUpdateRects: update clipping rectangles
* UpdateRects: update clipping rectangles
*****************************************************************************
* 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.
*****************************************************************************/
void E_(DirectXUpdateRects)( vout_thread_t *p_vout, vlc_bool_t b_force )
void E_(UpdateRects)( vout_thread_t *p_vout, vlc_bool_t b_force )
{
#define rect_src p_vout->p_sys->rect_src
#define rect_src_clipped p_vout->p_sys->rect_src_clipped
......@@ -682,7 +697,7 @@ void E_(DirectXUpdateRects)( vout_thread_t *p_vout, vlc_bool_t b_force )
}
#else /* MODULE_NAME_IS_vout_directx */
/* AFAIK, there are no clipping constraints in Direct3D or OpenGL */
/* AFAIK, there are no clipping constraints in Direct3D, OpenGL and GDI */
rect_dest_clipped = rect_dest;
#endif
......@@ -742,7 +757,7 @@ void E_(DirectXUpdateRects)( vout_thread_t *p_vout, vlc_bool_t b_force )
rect_dest_clipped.bottom -= p_vout->p_sys->rect_display.top;
if( p_vout->p_sys->b_using_overlay )
E_(DirectXUpdateOverlay)( p_vout );
DirectDrawUpdateOverlay( p_vout );
#endif
/* Signal the change in size/position */
......@@ -788,6 +803,7 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
}
}
#ifndef UNDER_CE
/* Catch the screensaver and the monitor turn-off */
if( message == WM_SYSCOMMAND &&
( (wParam & 0xFFF0) == SC_SCREENSAVE || (wParam & 0xFFF0) == SC_MONITORPOWER ) )
......@@ -795,6 +811,7 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
//if( p_vout ) msg_Dbg( p_vout, "WinProc WM_SYSCOMMAND screensaver" );
return 0; /* this stops them from happening */
}
#endif
if( hwnd == p_vout->p_sys->hvideownd )
{
......@@ -841,7 +858,7 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
{
case WM_WINDOWPOSCHANGED:
E_(DirectXUpdateRects)( p_vout, VLC_TRUE );
E_(UpdateRects)( p_vout, VLC_TRUE );
return 0;
/* the user wants to close the window */
......@@ -889,6 +906,50 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
case WM_ERASEBKGND:
return DefWindowProc(hwnd, message, wParam, lParam);
case WM_KILLFOCUS:
#ifdef MODULE_NAME_IS_wingapi
p_vout->p_sys->b_focus = VLC_FALSE;
if( !p_vout->p_sys->b_parent_focus ) GXSuspend();
#endif
#ifdef UNDER_CE
if( hWnd == p_vout->p_sys->hfswnd )
{
HWND htbar = FindWindow( _T("HHTaskbar"), NULL );
ShowWindow( htbar, SW_SHOW );
}
if( !p_vout->p_sys->hparent ||
hWnd == p_vout->p_sys->hfswnd )
{
SHFullScreen( hWnd, SHFS_SHOWSIPBUTTON );
}
#endif
return 0;
case WM_SETFOCUS:
#ifdef MODULE_NAME_IS_wingapi
p_vout->p_sys->b_focus = VLC_TRUE;
GXResume();
#endif
#ifdef UNDER_CE
if( p_vout->p_sys->hparent &&
hWnd != p_vout->p_sys->hfswnd && p_vout->b_fullscreen )
p_vout->p_sys->i_changes |= VOUT_FULLSCREEN_CHANGE;
if( hWnd == p_vout->p_sys->hfswnd )
{
HWND htbar = FindWindow( _T("HHTaskbar"), NULL );
ShowWindow( htbar, SW_HIDE );
}
if( !p_vout->p_sys->hparent ||
hWnd == p_vout->p_sys->hfswnd )
{
SHFullScreen( hWnd, SHFS_HIDESIPBUTTON );
}
#endif
return 0;
default:
//msg_Dbg( p_vout, "WinProc WM Default %i", message );
break;
......@@ -1063,6 +1124,15 @@ static int Control( vout_thread_t *p_vout, int i_query, va_list args )
p_vout->p_sys->b_on_top_change = VLC_TRUE;
return VLC_SUCCESS;
#ifdef MODULE_NAME_IS_wingapi
case VOUT_SET_FOCUS:
b_bool = va_arg( args, vlc_bool_t );
p_vout->p_sys->b_parent_focus = b_bool;
if( b_bool ) GXResume();
else if( !p_vout->p_sys->b_focus ) GXSuspend();
return VLC_SUCCESS;
#endif
default:
return vout_vaControlDefault( p_vout, i_query, args );
}
......
......@@ -108,7 +108,6 @@ static int OpenVideo( vlc_object_t *p_this )
p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL;
p_vout->p_sys->hparent = p_vout->p_sys->hfswnd = NULL;
p_vout->p_sys->i_changes = 0;
p_vout->p_sys->b_wallpaper = 0;
vlc_mutex_init( p_vout, &p_vout->p_sys->lock );
SetRectEmpty( &p_vout->p_sys->rect_display );
SetRectEmpty( &p_vout->p_sys->rect_parent );
......@@ -122,21 +121,21 @@ static int OpenVideo( vlc_object_t *p_this )
p_vout->p_sys->i_window_width = p_vout->i_window_width;
p_vout->p_sys->i_window_height = p_vout->i_window_height;
/* Create the DirectXEventThread, this thread is created by us to isolate
/* Create the Vout EventThread, this thread is created by us to isolate
* the Win32 PeekMessage function calls. We want to do this because
* Windows can stay blocked inside this call for a long time, and when
* this happens it thus blocks vlc's video_output thread.
* DirectXEventThread will take care of the creation of the video
* Vout EventThread will take care of the creation of the video
* window (because PeekMessage has to be called from the same thread which
* created the window). */
msg_Dbg( p_vout, "creating DirectXEventThread" );
msg_Dbg( p_vout, "creating Vout EventThread" );
p_vout->p_sys->p_event =
vlc_object_create( p_vout, sizeof(event_thread_t) );
p_vout->p_sys->p_event->p_vout = p_vout;
if( vlc_thread_create( p_vout->p_sys->p_event, "DirectX Events Thread",
E_(DirectXEventThread), 0, 1 ) )
if( vlc_thread_create( p_vout->p_sys->p_event, "Vout Events Thread",
E_(EventThread), 0, 1 ) )
{
msg_Err( p_vout, "cannot create DirectXEventThread" );
msg_Err( p_vout, "cannot create Vout EventThread" );
vlc_object_destroy( p_vout->p_sys->p_event );
p_vout->p_sys->p_event = NULL;
goto error;
......@@ -144,13 +143,13 @@ static int OpenVideo( vlc_object_t *p_this )
if( p_vout->p_sys->p_event->b_error )
{
msg_Err( p_vout, "DirectXEventThread failed" );
msg_Err( p_vout, "Vout EventThread failed" );
goto error;
}
vlc_object_attach( p_vout->p_sys->p_event, p_vout );
msg_Dbg( p_vout, "DirectXEventThread running" );
msg_Dbg( p_vout, "Vout EventThread running" );
/* Variable to indicate if the window should be on top of others */
/* Trigger a callback right now */
......@@ -225,10 +224,10 @@ static void CloseVideo( vlc_object_t *p_this )
{
vlc_object_detach( p_vout->p_sys->p_event );
/* Kill DirectXEventThread */
/* Kill Vout EventThread */
p_vout->p_sys->p_event->b_die = VLC_TRUE;
/* we need to be sure DirectXEventThread won't stay stuck in
/* we need to be sure Vout EventThread won't stay stuck in
* GetMessage, so we send a fake message */
if( p_vout->p_sys->hwnd )
{
......@@ -312,7 +311,7 @@ static int Manage( vout_thread_t *p_vout )
p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
E_(DirectXUpdateRects)( p_vout, VLC_TRUE );
E_(UpdateRects)( p_vout, VLC_TRUE );
}
/* We used to call the Win32 PeekMessage function here to read the window
......
/*****************************************************************************
* vout.h: Windows DirectX video output header file
* vout.h: Windows video output header file
*****************************************************************************
* Copyright (C) 2001-2004 the VideoLAN team
* $Id$
*
* Authors: Gildas Bazin <gbazin@videolan.org>
* Damien Fouilleul <damienf@videolan.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -22,7 +23,7 @@
*****************************************************************************/
/*****************************************************************************
* event_thread_t: DirectX event thread
* event_thread_t: event thread
*****************************************************************************/
typedef struct event_thread_t
{
......@@ -33,10 +34,10 @@ typedef struct event_thread_t
} event_thread_t;
/*****************************************************************************
* vout_sys_t: video output DirectX method descriptor
* vout_sys_t: video output method descriptor
*****************************************************************************
* This structure is part of the video output thread descriptor.
* It describes the DirectX specific properties of an output thread.
* It describes the module specific properties of an output thread.
*****************************************************************************/
struct vout_sys_t
{
......@@ -75,13 +76,15 @@ struct vout_sys_t
/* Misc */
vlc_bool_t b_on_top_change;
vlc_bool_t b_wallpaper;
#ifndef UNDER_CE
/* screensaver system settings to be restored when vout is closed */
UINT i_spi_lowpowertimeout;
UINT i_spi_powerofftimeout;
UINT i_spi_screensavetimeout;
#endif
/* Coordinates of src and dest images (used when blitting to display) */
RECT rect_src;
RECT rect_src_clipped;
......@@ -90,6 +93,7 @@ struct vout_sys_t
vlc_bool_t b_hw_yuv; /* Should we use hardware YUV->RGB conversions */
#ifdef MODULE_NAME_IS_vout_directx
/* Overlay alignment restrictions */
int i_align_src_boundary;
......@@ -97,6 +101,8 @@ struct vout_sys_t
int i_align_dest_boundary;
int i_align_dest_size;
vlc_bool_t b_wallpaper; /* show as desktop wallpaper ? */
vlc_bool_t b_using_overlay; /* Are we using an overlay surface */
vlc_bool_t b_use_sysmem; /* Should we use system memory for surfaces */
vlc_bool_t b_3buf_overlay; /* Should we use triple buffered overlays */
......@@ -133,20 +139,62 @@ struct vout_sys_t
LPDIRECT3DVERTEXBUFFER9 p_d3dvtc;
#endif
#ifdef MODULE_NAME_IS_wingdi
int i_depth;
/* Our offscreen bitmap and its framebuffer */
HDC off_dc;
HBITMAP off_bitmap;
uint8_t * p_pic_buffer;
int i_pic_pitch;
int i_pic_pixel_pitch;
BITMAPINFO bitmapinfo;
RGBQUAD red;
RGBQUAD green;
RGBQUAD blue;
#endif
#ifdef MODULE_NAME_IS_wingapi
int i_depth;
int render_width;
int render_height;
vlc_bool_t b_focus;
vlc_bool_t b_parent_focus;
HINSTANCE gapi_dll; /* handle of the opened gapi dll */
/* GAPI functions */
int (*GXOpenDisplay)( HWND hWnd, DWORD dwFlags );
int (*GXCloseDisplay)();
void *(*GXBeginDraw)();
int (*GXEndDraw)();
GXDisplayProperties (*GXGetDisplayProperties)();
int (*GXSuspend)();
int (*GXResume)();
#endif
#ifndef UNDER_CE
/* suspend display */
vlc_bool_t b_suspend_display;
#endif
event_thread_t *p_event;
vlc_mutex_t lock;
};
/*****************************************************************************
* Prototypes from vout.c
* Prototypes from directx.c
*****************************************************************************/
int E_(DirectXUpdateOverlay)( vout_thread_t *p_vout );
int DirectDrawUpdateOverlay( vout_thread_t *p_vout );
/*****************************************************************************
* Prototypes from events.c
*****************************************************************************/
void E_(DirectXEventThread) ( event_thread_t *p_event );
void E_(DirectXUpdateRects) ( vout_thread_t *p_vout, vlc_bool_t b_force );
void E_(EventThread) ( event_thread_t *p_event );
void E_(UpdateRects) ( vout_thread_t *p_vout, vlc_bool_t b_force );
void Win32ToggleFullscreen ( vout_thread_t *p_vout );
/*****************************************************************************
......
......@@ -2,7 +2,7 @@
* wingdi.c : Win32 / WinCE GDI video output plugin for vlc
*****************************************************************************
* Copyright (C) 2002 the VideoLAN team
* $Id$
* $Id: wingdi.c 18074 2006-11-26 16:26:44Z zorglub $
*
* Authors: Gildas Bazin <gbazin@videolan.org>
* Samuel Hocevar <sam@zoy.org>
......@@ -35,16 +35,7 @@
#include <commctrl.h>
#define SHFS_SHOWSIPBUTTON 0x0004
#define SHFS_HIDESIPBUTTON 0x0008
#if defined(UNDER_CE) && !defined(__PLUGIN__) /*FIXME*/
# define MENU_HEIGHT 26
BOOL SHFullScreen(HWND hwndRequester, DWORD dwState);
#else
# define MENU_HEIGHT 0
# define SHFullScreen(a,b)
#endif
#include "vout.h"
#ifdef MODULE_NAME_IS_wingapi
typedef struct GXDisplayProperties {
......@@ -111,101 +102,26 @@ static void End ( vout_thread_t * );
static int Manage ( vout_thread_t * );
static void Render ( vout_thread_t *, picture_t * );
#ifdef MODULE_NAME_IS_wingapi
static void FirstDisplayGAPI( vout_thread_t *, picture_t * );
static void DisplayGAPI( vout_thread_t *, picture_t * );
static int GAPILockSurface( vout_thread_t *, picture_t * );
static int GAPIUnlockSurface( vout_thread_t *, picture_t * );
#else
static void FirstDisplayGDI( vout_thread_t *, picture_t * );
static void DisplayGDI( vout_thread_t *, picture_t * );
#endif
static void SetPalette( vout_thread_t *, uint16_t *, uint16_t *, uint16_t * );
static void EventThread ( vlc_object_t * );
static long FAR PASCAL WndProc ( HWND, UINT, WPARAM, LPARAM );
static void InitBuffers ( vout_thread_t * );
static void UpdateRects ( vout_thread_t *, vlc_bool_t );
static int Control( vout_thread_t *p_vout, int i_query, va_list args );
/*****************************************************************************
* Private structure
*****************************************************************************/
struct vout_sys_t
{
/* The event thread */
vlc_object_t * p_event;
/* Our video output window */
HWND hwnd;
HWND hvideownd;
HWND hfswnd;
int i_depth;
HWND hparent; /* Handle of the parent window */
WNDPROC pf_wndproc; /* Window handling callback */
volatile uint16_t i_changes; /* changes made to the video display */
RECT window_placement;
/* Window position and size */
int i_window_x;
int i_window_y;
int i_window_width;
int i_window_height;
int i_window_style;
int render_width;
int render_height;
/* Coordinates of src and dest images (used when blitting to display) */
RECT rect_src;
RECT rect_src_clipped;
RECT rect_dest;
RECT rect_dest_clipped;
RECT rect_parent;
RECT rect_display;
/* Our offscreen bitmap and its framebuffer */
HDC off_dc;
HBITMAP off_bitmap;
uint8_t * p_pic_buffer;
int i_pic_pitch;
int i_pic_pixel_pitch;
BITMAPINFO bitmapinfo;
RGBQUAD red;
RGBQUAD green;
RGBQUAD blue;
/* WINCE stuff */
vlc_bool_t b_video_display;
/* Window focus states */
vlc_bool_t b_focus;
vlc_bool_t b_parent_focus;
#ifdef MODULE_NAME_IS_wingapi
HINSTANCE gapi_dll; /* handle of the opened gapi dll */
/* GAPI functions */
int (*GXOpenDisplay)( HWND hWnd, DWORD dwFlags );
int (*GXCloseDisplay)();
void *(*GXBeginDraw)();
int (*GXEndDraw)();
GXDisplayProperties (*GXGetDisplayProperties)();
int (*GXSuspend)();
int (*GXResume)();
#endif
};
#define GXOpenDisplay p_vout->p_sys->GXOpenDisplay
#define GXCloseDisplay p_vout->p_sys->GXCloseDisplay
#define GXBeginDraw p_vout->p_sys->GXBeginDraw
#define GXEndDraw p_vout->p_sys->GXEndDraw
#define GXGetDisplayProperties p_vout->p_sys->GXGetDisplayProperties
#ifdef MODULE_NAME_IS_wingapi
# define GXOpenDisplay p_vout->p_sys->GXOpenDisplay
# define GXCloseDisplay p_vout->p_sys->GXCloseDisplay
# define GXBeginDraw p_vout->p_sys->GXBeginDraw
# define GXEndDraw p_vout->p_sys->GXEndDraw
# define GXGetDisplayProperties p_vout->p_sys->GXGetDisplayProperties
# define GXSuspend p_vout->p_sys->GXSuspend
# define GXResume p_vout->p_sys->GXResume
#else
# define GXSuspend()
# define GXResume()
#endif
#define DX_POSITION_CHANGE 0x1000
......@@ -238,6 +154,7 @@ static int OpenVideo ( vlc_object_t *p_this )
p_vout->p_sys = (vout_sys_t *)malloc( sizeof(vout_sys_t) );
if( !p_vout->p_sys ) return VLC_ENOMEM;
memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
#ifdef MODULE_NAME_IS_wingapi
/* Load GAPI */
......@@ -286,35 +203,102 @@ static int OpenVideo ( vlc_object_t *p_this )
return VLC_ENOMEM;
}
var_Create( p_vout->p_sys->p_event, "p_vout", VLC_VAR_ADDRESS );
val.p_address = (void *)p_vout;
var_Set( p_vout->p_sys->p_event, "p_vout", val );
SetRectEmpty( &p_vout->p_sys->rect_display );
SetRectEmpty( &p_vout->p_sys->rect_parent );
if( vlc_thread_create( p_vout->p_sys->p_event, "GDI Event Thread",
EventThread, 0, 1 ) )
{
msg_Err( p_vout, "cannot spawn EventThread" );
return VLC_ETHREAD;
}
p_vout->pf_init = Init;
p_vout->pf_end = End;
p_vout->pf_manage = Manage;
p_vout->pf_render = Render;
#ifdef MODULE_NAME_IS_wingapi
p_vout->pf_display = DisplayGAPI;
p_vout->pf_display = FirstDisplayGAPI;
p_vout->p_sys->b_focus = 0;
p_vout->p_sys->b_parent_focus = 0;
#else
p_vout->pf_display = DisplayGDI;
p_vout->pf_display = FirstDisplayGDI;
#endif
p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL;
p_vout->p_sys->hparent = p_vout->p_sys->hfswnd = NULL;
p_vout->p_sys->i_changes = 0;
vlc_mutex_init( p_vout, &p_vout->p_sys->lock );
SetRectEmpty( &p_vout->p_sys->rect_display );
SetRectEmpty( &p_vout->p_sys->rect_parent );
p_vout->p_sys->b_focus = 0;
p_vout->p_sys->b_parent_focus = 0;
var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
var_Create( p_vout, "disable-screensaver", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
p_vout->p_sys->b_cursor_hidden = 0;
p_vout->p_sys->i_lastmoved = mdate();
/* Set main window's size */
p_vout->p_sys->i_window_width = p_vout->i_window_width;
p_vout->p_sys->i_window_height = p_vout->i_window_height;
/* Create the EventThread, this thread is created by us to isolate
* the Win32 PeekMessage function calls. We want to do this because
* Windows can stay blocked inside this call for a long time, and when
* this happens it thus blocks vlc's video_output thread.
* Vout EventThread will take care of the creation of the video
* window (because PeekMessage has to be called from the same thread which
* created the window). */
msg_Dbg( p_vout, "creating Vout EventThread" );
p_vout->p_sys->p_event =
vlc_object_create( p_vout, sizeof(event_thread_t) );
p_vout->p_sys->p_event->p_vout = p_vout;
if( vlc_thread_create( p_vout->p_sys->p_event, "VLC Vout Events Thread",
E_(EventThread), 0, 1 ) )
{
msg_Err( p_vout, "cannot create Vout EventThread" );
vlc_object_destroy( p_vout->p_sys->p_event );
p_vout->p_sys->p_event = NULL;
goto error;
}
if( p_vout->p_sys->p_event->b_error )
{
msg_Err( p_vout, "Vout EventThread failed" );
goto error;
}
vlc_object_attach( p_vout->p_sys->p_event, p_vout );
msg_Dbg( p_vout, "Vout EventThread running" );
#ifndef UNDER_CE
/* Variable to indicate if the window should be on top of others */
/* Trigger a callback right now */
var_Get( p_vout, "video-on-top", &val );
var_Set( p_vout, "video-on-top", val );
/* disable screensaver by temporarily changing system settings */
p_vout->p_sys->i_spi_lowpowertimeout = 0;
p_vout->p_sys->i_spi_powerofftimeout = 0;
p_vout->p_sys->i_spi_screensavetimeout = 0;
var_Get( p_vout, "disable-screensaver", &val);
if( val.b_bool ) {
msg_Dbg(p_vout, "disabling screen saver");
SystemParametersInfo(SPI_GETLOWPOWERTIMEOUT,
0, &(p_vout->p_sys->i_spi_lowpowertimeout), 0);
if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) {
SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT, 0, NULL, 0);
}
SystemParametersInfo(SPI_GETPOWEROFFTIMEOUT, 0,
&(p_vout->p_sys->i_spi_powerofftimeout), 0);
if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) {
SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT, 0, NULL, 0);
}
SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0,
&(p_vout->p_sys->i_spi_screensavetimeout), 0);
if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) {
SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, 0, NULL, 0);
}
}
#endif
return VLC_SUCCESS;
error:
CloseVideo( VLC_OBJECT(p_vout) );
return VLC_EGENERIC;
}
/*****************************************************************************
......@@ -324,17 +308,50 @@ static void CloseVideo ( vlc_object_t *p_this )
{
vout_thread_t * p_vout = (vout_thread_t *)p_this;
p_vout->p_sys->p_event->b_die = VLC_TRUE;
PostMessage( p_vout->p_sys->hwnd, WM_NULL, 0, 0 );
vlc_thread_join( p_vout->p_sys->p_event );
if( p_vout->p_sys->p_event )
{
vlc_object_detach( p_vout->p_sys->p_event );
/* Kill Vout EventThread */
p_vout->p_sys->p_event->b_die = VLC_TRUE;
/* we need to be sure Vout EventThread won't stay stuck in
* GetMessage, so we send a fake message */
if( p_vout->p_sys->hwnd )
{
PostMessage( p_vout->p_sys->hwnd, WM_NULL, 0, 0);
}
vlc_thread_join( p_vout->p_sys->p_event );
vlc_object_destroy( p_vout->p_sys->p_event );
}
vlc_mutex_destroy( &p_vout->p_sys->lock );
#ifndef UNDER_CE
/* restore screensaver system settings */
if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) {
SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT,
p_vout->p_sys->i_spi_lowpowertimeout, NULL, 0);
}
if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) {
SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT,
p_vout->p_sys->i_spi_powerofftimeout, NULL, 0);
}
if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) {
SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT,
p_vout->p_sys->i_spi_screensavetimeout, NULL, 0);
}
#endif
#ifdef MODULE_NAME_IS_wingapi
FreeLibrary( p_vout->p_sys->gapi_dll );
#endif
var_Destroy( p_vout->p_sys->p_event, "p_vout" );
vlc_object_destroy( p_vout->p_sys->p_event );
free( p_vout->p_sys );
if( p_vout->p_sys )
{
free( p_vout->p_sys );
p_vout->p_sys = NULL;
}
}
/*****************************************************************************
......@@ -344,14 +361,14 @@ static int Init( vout_thread_t *p_vout )
{
picture_t *p_pic;
/* Initialize offscreen buffer */
InitBuffers( p_vout );
p_vout->p_sys->rect_display.left = 0;
p_vout->p_sys->rect_display.top = 0;
p_vout->p_sys->rect_display.right = GetSystemMetrics(SM_CXSCREEN);
p_vout->p_sys->rect_display.bottom = GetSystemMetrics(SM_CYSCREEN);
p_vout->p_sys->b_video_display = VLC_TRUE;
p_vout->p_sys->p_event->b_die = VLC_FALSE;
I_OUTPUTPICTURES = 0;
/* Initialize the output structure */
......@@ -428,6 +445,10 @@ static int Init( vout_thread_t *p_vout )
PP_OUTPUTPICTURE[ I_OUTPUTPICTURES++ ] = p_pic;
/* Change the window title bar text */
PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
E_(UpdateRects)( p_vout, VLC_TRUE );
return VLC_SUCCESS;
}
......@@ -436,6 +457,12 @@ static int Init( vout_thread_t *p_vout )
*****************************************************************************/
static void End( vout_thread_t *p_vout )
{
#ifdef MODULE_NAME_IS_wingapi
GXCloseDisplay();
#else
DeleteDC( p_vout->p_sys->off_dc );
DeleteObject( p_vout->p_sys->off_bitmap );
#endif
}
/*****************************************************************************
......@@ -446,17 +473,16 @@ static void End( vout_thread_t *p_vout )
*****************************************************************************/
static int Manage( vout_thread_t *p_vout )
{
#ifndef UNDER_CE
WINDOWPLACEMENT window_placement;
#endif
/* 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 && !p_vout->b_fullscreen )
{
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 );
......@@ -485,6 +511,36 @@ static int Manage( vout_thread_t *p_vout )
i_x, i_y, i_width, i_height, 0 );
}
}
else
{
vlc_mutex_unlock( &p_vout->p_sys->lock );
}
/* Check for cropping / aspect changes */
if( p_vout->i_changes & VOUT_CROP_CHANGE ||
p_vout->i_changes & VOUT_ASPECT_CHANGE )
{
p_vout->i_changes &= ~VOUT_CROP_CHANGE;
p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset;
p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset;
p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width;
p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height;
p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect;
p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
E_(UpdateRects)( p_vout, VLC_TRUE );
}
/*
* Position Change
*/
if( p_vout->p_sys->i_changes & DX_POSITION_CHANGE )
{
p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE;
}
/* 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
......@@ -497,100 +553,71 @@ 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;
Win32ToggleFullscreen( p_vout );
HWND hwnd = (p_vout->p_sys->hparent && p_vout->p_sys->hfswnd) ?
p_vout->p_sys->hfswnd : p_vout->p_sys->hwnd;
p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
}
p_vout->b_fullscreen = ! p_vout->b_fullscreen;
/*
* Pointer change
*/
if( p_vout->b_fullscreen && !p_vout->p_sys->b_cursor_hidden &&
(mdate() - p_vout->p_sys->i_lastmoved) > 5000000 )
{
POINT point;
HWND hwnd;
/* We need to switch between Maximized and Normal sized window */
#ifndef UNDER_CE
window_placement.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement( hwnd, &window_placement );
#endif
if( p_vout->b_fullscreen )
/* Hide the cursor only if it is inside our window */
GetCursorPos( &point );
hwnd = WindowFromPoint(point);
if( hwnd == p_vout->p_sys->hwnd || hwnd == p_vout->p_sys->hvideownd )
{
#ifndef UNDER_CE
/* Change window style, no borders and no title bar */
int i_style = WS_CLIPCHILDREN | WS_VISIBLE;
SetWindowLong( hwnd, GWL_STYLE, i_style );
if( p_vout->p_sys->hparent )
{
/* Retrieve current window position so fullscreen will happen
* on the right screen */
POINT point = {0,0};
RECT rect;
ClientToScreen( p_vout->p_sys->hwnd, &point );
GetClientRect( p_vout->p_sys->hwnd, &rect );
SetWindowPos( hwnd, 0, point.x, point.y,
rect.right, rect.bottom,
SWP_NOZORDER|SWP_FRAMECHANGED );
GetWindowPlacement( hwnd, &window_placement );
}
/* Maximize window */
window_placement.showCmd = SW_SHOWMAXIMIZED;
SetWindowPlacement( hwnd, &window_placement );
SetWindowPos( hwnd, 0, 0, 0, 0, 0,
SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
#endif
if( p_vout->p_sys->hparent )
{
RECT rect;
GetClientRect( hwnd, &rect );
SetParent( p_vout->p_sys->hwnd, hwnd );
SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
rect.right, rect.bottom,
SWP_NOZORDER|SWP_FRAMECHANGED );
}
ShowWindow( hwnd, SW_SHOW );
SetForegroundWindow( hwnd );
PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
}
else
{
/* Change window style, no borders and no title bar */
//SetWindowLong( hwnd, GWL_STYLE, p_vout->p_sys->i_window_style );
p_vout->p_sys->i_lastmoved = mdate();
}
}
#ifndef UNDER_CE
/* Normal window */
window_placement.showCmd = SW_SHOWNORMAL;
SetWindowPlacement( hwnd, &window_placement );
SetWindowPos( hwnd, 0, 0, 0, 0, 0,
SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
#endif
/*
* "Always on top" status change
*/
if( p_vout->p_sys->b_on_top_change )
{
vlc_value_t val;
HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
if( p_vout->p_sys->hparent )
{
RECT rect;
GetClientRect( p_vout->p_sys->hparent, &rect );
SetParent( p_vout->p_sys->hwnd, p_vout->p_sys->hparent );
SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
rect.right, rect.bottom,
SWP_NOZORDER|SWP_FRAMECHANGED );
ShowWindow( hwnd, SW_HIDE );
SetForegroundWindow( p_vout->p_sys->hparent );
}
/* Make sure the mouse cursor is displayed */
//PostMessage( p_vout->p_sys->hwnd, WM_VLC_SHOW_MOUSE, 0, 0 );
}
var_Get( p_vout, "video-on-top", &val );
/* Change window style, borders and title bar */
ShowWindow( p_vout->p_sys->hwnd, SW_SHOW );
UpdateWindow( p_vout->p_sys->hwnd );
/* Set the window on top if necessary */
if( val.b_bool && !( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
& WS_EX_TOPMOST ) )
{
CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
MF_BYCOMMAND | MFS_CHECKED );
SetWindowPos( p_vout->p_sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE );
}
else
/* The window shouldn't be on top */
if( !val.b_bool && ( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
& WS_EX_TOPMOST ) )
{
CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
MF_BYCOMMAND | MFS_UNCHECKED );
SetWindowPos( p_vout->p_sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE );
}
/* Update the object variable and trigger callback */
val.b_bool = p_vout->b_fullscreen;
var_Set( p_vout, "fullscreen", val );
p_vout->p_sys->b_on_top_change = VLC_FALSE;
}
p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
/* Check if the event thread is still running */
if( p_vout->p_sys->p_event->b_die )
{
return VLC_EGENERIC; /* exit */
}
return VLC_SUCCESS;
......@@ -640,8 +667,30 @@ static void DisplayGDI( vout_thread_t *p_vout, picture_t *p_pic )
rect_src_clipped.top, SRCCOPY );
}
ReleaseDC( p_sys->hwnd, hdc );
ReleaseDC( p_sys->hvideownd, hdc );
}
static void FirstDisplayGDI( vout_thread_t *p_vout, picture_t *p_pic )
{
/*
** Video window is initially hidden, show it now since we got a
** picture to show.
*/
SetWindowPos( p_vout->p_sys->hvideownd, 0, 0, 0, 0, 0,
SWP_ASYNCWINDOWPOS|
SWP_FRAMECHANGED|
SWP_SHOWWINDOW|
SWP_NOMOVE|
SWP_NOSIZE|
SWP_NOZORDER );
/* get initial picture presented */
DisplayGDI(p_vout, p_pic);
/* use and restores proper display function for further pictures */
p_vout->pf_display = DisplayGDI;
}
#else
static int GAPILockSurface( vout_thread_t *p_vout, picture_t *p_pic )
......@@ -651,13 +700,6 @@ static int GAPILockSurface( vout_thread_t *p_vout, picture_t *p_pic )
RECT video_rect;
POINT point;
/* Undo the display */
if( ( GetForegroundWindow() != GetParent(p_sys->hwnd) ) ||
( p_sys->b_video_display == VLC_FALSE ) )
{
//return VLC_EGENERIC;
}
GetClientRect( p_sys->hwnd, &video_rect);
vout_PlacePicture( p_vout, video_rect.right - video_rect.left,
video_rect.bottom - video_rect.top,
......@@ -745,444 +787,41 @@ static int GAPIUnlockSurface( vout_thread_t *p_vout, picture_t *p_pic )
static void DisplayGAPI( vout_thread_t *p_vout, picture_t *p_pic )
{
}
#endif
#undef rect_src
#undef rect_src_clipped
#undef rect_dest
#undef rect_dest_clipped
/*****************************************************************************
* SetPalette: sets an 8 bpp palette
*****************************************************************************/
static void SetPalette( vout_thread_t *p_vout,
uint16_t *red, uint16_t *green, uint16_t *blue )
{
msg_Err( p_vout, "FIXME: SetPalette unimplemented" );
}
/*****************************************************************************
* EventThread: Event handling thread
*****************************************************************************/
static void EventThread ( vlc_object_t *p_event )
static void FirstDisplayGAPI( vout_thread_t *p_vout, picture_t *p_pic )
{
vout_thread_t *p_vout;
vlc_value_t val;
int i_style;
WNDCLASS wc;
MSG msg;
/* Initialisations */
var_Get( p_event, "p_vout", &val );
p_vout = (vout_thread_t *)val.p_address;
/* Register window class */
memset( &wc, 0, sizeof(wc) );
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = GetModuleHandle(NULL);
wc.hIcon = 0;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
wc.lpszMenuName = 0;
wc.lpszClassName = _T("VLC WinGDI");
RegisterClass( &wc );
/* Register the video sub-window class */
wc.lpszClassName = _T("VLC WinGDI video"); wc.hIcon = 0;
RegisterClass(&wc);
/* Create output window */
p_vout->p_sys->hparent = (HWND)
vout_RequestWindow( p_vout, &p_vout->p_sys->i_window_x,
&p_vout->p_sys->i_window_y,
(unsigned int *)&p_vout->p_sys->i_window_width,
(unsigned int *)&p_vout->p_sys->i_window_height );
if( p_vout->p_sys->hparent )
ShowWindow( p_vout->p_sys->hparent, SW_SHOW );
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;
p_vout->p_sys->i_window_style = i_style;
p_vout->p_sys->hwnd =
CreateWindow( _T("VLC WinGDI"), _T(VOUT_TITLE), i_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 */
p_vout->p_sys->i_window_width,
p_vout->p_sys->i_window_height + 10,
p_vout->p_sys->hparent, NULL,
GetModuleHandle(NULL), (LPVOID)p_vout );
if( !p_vout->p_sys->hwnd )
{
msg_Warn( p_vout, "couldn't create window" );
return;
}
msg_Warn( p_vout, "Created WinGDI window" );
/* get initial picture presented through D3D */
DisplayGAPI(p_vout, p_pic);
if( p_vout->p_sys->hparent )
{
LONG i_style;
/* We don't want the window owner to overwrite our client area */
i_style = GetWindowLong( p_vout->p_sys->hparent, GWL_STYLE );
if( !(i_style & WS_CLIPCHILDREN) )
/* Hmmm, apparently this is a blocking call... */
SetWindowLong( p_vout->p_sys->hparent, GWL_STYLE,
i_style | WS_CLIPCHILDREN );
/* Create our fullscreen window */
p_vout->p_sys->hfswnd =
CreateWindowEx( WS_EX_APPWINDOW, _T("VLC WinGDI"),
_T(VOUT_TITLE),
WS_NONAVDONEBUTTON|WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, GetModuleHandle(NULL), (LPVOID)p_vout);
}
/* Display our window */
ShowWindow( p_vout->p_sys->hwnd, SW_SHOW );
UpdateWindow( p_vout->p_sys->hwnd );
/* Create video sub-window */
p_vout->p_sys->hvideownd =
CreateWindow( _T("VLC WinGDI video"), _T(""), /* window class */
WS_CHILD | WS_VISIBLE, /* window style */
CW_USEDEFAULT, CW_USEDEFAULT, /* default coordinates */
CW_USEDEFAULT, CW_USEDEFAULT,
p_vout->p_sys->hwnd, /* parent window */
NULL, GetModuleHandle(NULL),
(LPVOID)p_vout ); /* send p_vout to WM_CREATE */
/* Initialize offscreen buffer */
InitBuffers( p_vout );
p_vout->pf_control = Control;
/* Tell the video output we're ready to receive data */
vlc_thread_ready( p_event );
while( !p_event->b_die && GetMessage( &msg, 0, 0, 0 ) )
{
/* Check if we are asked to exit */
if( p_event->b_die ) break;
switch( msg.message )
{
case WM_KEYDOWN:
switch( msg.wParam )
{
case VK_ESCAPE:
p_event->p_libvlc->b_die = VLC_TRUE;
break;
}
TranslateMessage( &msg );
break;
case WM_CHAR:
switch( msg.wParam )
{
case 'q':
case 'Q':
p_event->p_libvlc->b_die = VLC_TRUE;
break;
}
break;
default:
TranslateMessage( &msg );
DispatchMessage( &msg );
break;
}
}
msg_Dbg( p_vout, "CloseWindow" );
#ifdef MODULE_NAME_IS_wingapi
GXCloseDisplay();
#else
DeleteDC( p_vout->p_sys->off_dc );
DeleteObject( p_vout->p_sys->off_bitmap );
#endif
DestroyWindow( p_vout->p_sys->hwnd );
if( p_vout->p_sys->hfswnd ) DestroyWindow( p_vout->p_sys->hfswnd );
if( p_vout->p_sys->hparent )
vout_ReleaseWindow( p_vout, (void *)p_vout->p_sys->hparent );
/*
** Video window is initially hidden, show it now since we got a
** picture to show.
*/
SetWindowPos( p_vout->p_sys->hvideownd, 0, 0, 0, 0, 0,
SWP_ASYNCWINDOWPOS|
SWP_FRAMECHANGED|
SWP_SHOWWINDOW|
SWP_NOMOVE|
SWP_NOSIZE|
SWP_NOZORDER );
/* use and restores proper display function for further pictures */
p_vout->pf_display = DisplayGAPI;
}
/*****************************************************************************
* UpdateRects: update clipping rectangles
*****************************************************************************
* 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 UpdateRects( vout_thread_t *p_vout, vlc_bool_t b_force )
{
#define rect_src p_vout->p_sys->rect_src
#define rect_src_clipped p_vout->p_sys->rect_src_clipped
#define rect_dest p_vout->p_sys->rect_dest
#define rect_dest_clipped p_vout->p_sys->rect_dest_clipped
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 );
if( p_vout->p_sys->hvideownd )
SetWindowPos( p_vout->p_sys->hvideownd, HWND_TOP,
i_x, i_y, i_width, i_height, 0 );
/* Destination image position and dimensions */
rect_dest.left = point.x + i_x;
rect_dest.right = rect_dest.left + i_width;
rect_dest.top = point.y + i_y;
rect_dest.bottom = rect_dest.top + i_height;
/* Clip the destination window */
if( !IntersectRect( &rect_dest_clipped, &rect_dest,
&p_vout->p_sys->rect_display ) )
{
SetRectEmpty( &rect_src_clipped );
return;
}
#if 0
msg_Dbg( p_vout, "image_dst_clipped coords: %i,%i,%i,%i",
rect_dest_clipped.left, rect_dest_clipped.top,
rect_dest_clipped.right, rect_dest_clipped.bottom );
#endif
/* 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 )
{
SetRectEmpty( &rect_src_clipped );
return;
}
/* src image dimensions */
rect_src.left = 0;
rect_src.top = 0;
rect_src.right = p_vout->output.i_width;
rect_src.bottom = p_vout->output.i_height;
/* Clip the source image */
rect_src_clipped.left = (rect_dest_clipped.left - rect_dest.left) *
p_vout->output.i_width / (rect_dest.right - rect_dest.left);
rect_src_clipped.right = p_vout->output.i_width -
(rect_dest.right - rect_dest_clipped.right) * p_vout->output.i_width /
(rect_dest.right - rect_dest.left);
rect_src_clipped.top = (rect_dest_clipped.top - rect_dest.top) *
p_vout->output.i_height / (rect_dest.bottom - rect_dest.top);
rect_src_clipped.bottom = p_vout->output.i_height -
(rect_dest.bottom - rect_dest_clipped.bottom) * p_vout->output.i_height /
(rect_dest.bottom - rect_dest.top);
#if 0
msg_Dbg( p_vout, "image_src_clipped coords: %i,%i,%i,%i",
rect_src_clipped.left, rect_src_clipped.top,
rect_src_clipped.right, rect_src_clipped.bottom );
#endif
/* The destination coordinates need to be relative to the current
* directdraw primary surface (display) */
rect_dest_clipped.left -= p_vout->p_sys->rect_display.left;
rect_dest_clipped.right -= p_vout->p_sys->rect_display.left;
rect_dest_clipped.top -= p_vout->p_sys->rect_display.top;
rect_dest_clipped.bottom -= p_vout->p_sys->rect_display.top;
/* Signal the change in size/position */
p_vout->p_sys->i_changes |= DX_POSITION_CHANGE;
#undef rect_src
#undef rect_src_clipped
#undef rect_dest
#undef rect_dest_clipped
}
/*****************************************************************************
* Message handler for the main window
* SetPalette: sets an 8 bpp palette
*****************************************************************************/
static long FAR PASCAL WndProc( HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam )
static void SetPalette( vout_thread_t *p_vout,
uint16_t *red, uint16_t *green, uint16_t *blue )
{
vout_thread_t *p_vout;
if( message == WM_CREATE )
{
/* Store p_vout for future use */
p_vout = (vout_thread_t *)((CREATESTRUCT *)lParam)->lpCreateParams;
SetWindowLongPtr( hWnd, GWLP_USERDATA, (LONG_PTR)p_vout );
if( p_vout ) msg_Dbg( p_vout, "create: %p", hWnd );
}
else
{
p_vout = (vout_thread_t *)GetWindowLongPtr( hWnd, GWLP_USERDATA );
}
#ifndef UNDER_CE
/* Catch the screensaver and the monitor turn-off */
if( message == WM_SYSCOMMAND &&
( (wParam & 0xFFF0) == SC_SCREENSAVE || (wParam & 0xFFF0) == SC_MONITORPOWER ) )
{
//if( p_vout ) msg_Dbg( p_vout, "WinProc WM_SYSCOMMAND screensaver" );
return 0; /* this stops them from happening */
}
#endif
if( !p_vout )
{
/* Hmmm mozilla does manage somehow to save the pointer to our
* windowproc and still calls it after the vout has been closed. */
return DefWindowProc(hWnd, message, wParam, lParam);
}
if( hWnd != p_vout->p_sys->hwnd &&
hWnd != p_vout->p_sys->hfswnd &&
hWnd != p_vout->p_sys->hvideownd )
return DefWindowProc(hWnd, message, wParam, lParam);
switch( message )
{
case WM_WINDOWPOSCHANGED:
if( hWnd == p_vout->p_sys->hwnd )
UpdateRects( p_vout, VLC_TRUE );
break;
#if 0
case WM_ACTIVATE:
msg_Err( p_vout, "WM_ACTIVATE: %i", wParam );
if( wParam == WA_ACTIVE || wParam == WA_CLICKACTIVE )
GXResume();
else if( wParam == WA_INACTIVE )
GXSuspend();
break;
#endif
case WM_KILLFOCUS:
p_vout->p_sys->b_focus = VLC_FALSE;
if( !p_vout->p_sys->b_parent_focus ) GXSuspend();
if( hWnd == p_vout->p_sys->hfswnd )
{
#ifdef UNDER_CE
HWND htbar = FindWindow( _T("HHTaskbar"), NULL );
ShowWindow( htbar, SW_SHOW );
#endif
}
if( !p_vout->p_sys->hparent ||
hWnd == p_vout->p_sys->hfswnd )
{
SHFullScreen( hWnd, SHFS_SHOWSIPBUTTON );
}
break;
case WM_SETFOCUS:
p_vout->p_sys->b_focus = VLC_TRUE;
GXResume();
if( p_vout->p_sys->hparent &&
hWnd != p_vout->p_sys->hfswnd && p_vout->b_fullscreen )
p_vout->p_sys->i_changes |= VOUT_FULLSCREEN_CHANGE;
if( hWnd == p_vout->p_sys->hfswnd )
{
#ifdef UNDER_CE
HWND htbar = FindWindow( _T("HHTaskbar"), NULL );
ShowWindow( htbar, SW_HIDE );
#endif
}
if( !p_vout->p_sys->hparent ||
hWnd == p_vout->p_sys->hfswnd )
{
SHFullScreen( hWnd, SHFS_HIDESIPBUTTON );
}
break;
case WM_LBUTTONDOWN:
p_vout->p_sys->i_changes |= VOUT_FULLSCREEN_CHANGE;
break;
case WM_MOUSEMOVE:
break;
case WM_LBUTTONUP:
break;
case WM_INITMENUPOPUP:
p_vout->p_sys->b_video_display = VLC_FALSE;
break;
case WM_NOTIFY:
// Redo the video display because menu can be closed
// FIXME verify if p_child_window exits
if( (((NMHDR *)lParam)->code) == NM_CUSTOMDRAW )
p_vout->p_sys->b_video_display = VLC_TRUE;
break;
/* the user wants to close the window */
case WM_CLOSE:
{
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;
}
case WM_DESTROY:
msg_Dbg( p_vout, "WinProc WM_DESTROY" );
PostQuitMessage( 0 );
break;
default:
return DefWindowProc( hWnd, message, wParam, lParam );
}
return 0;
msg_Err( p_vout, "FIXME: SetPalette unimplemented" );
}
/*****************************************************************************
......@@ -1274,89 +913,7 @@ static void InitBuffers( vout_thread_t *p_vout )
p_vout->p_sys->off_dc = CreateCompatibleDC( window_dc );
SelectObject( p_vout->p_sys->off_dc, p_vout->p_sys->off_bitmap );
ReleaseDC( 0, window_dc );
ReleaseDC( p_vout->p_sys->hvideownd, window_dc );
#endif
}
/*****************************************************************************
* Control: control facility for the vout
*****************************************************************************/
static int Control( vout_thread_t *p_vout, int i_query, va_list args )
{
unsigned int *pi_width, *pi_height;
vlc_bool_t b_bool;
RECT rect_window;
POINT point;
switch( i_query )
{
case VOUT_GET_SIZE:
if( p_vout->p_sys->hparent )
return vout_ControlWindow( p_vout,
(void *)p_vout->p_sys->hparent, i_query, args );
pi_width = va_arg( args, unsigned int * );
pi_height = va_arg( args, unsigned int * );
GetClientRect( p_vout->p_sys->hwnd, &rect_window );
*pi_width = rect_window.right - rect_window.left;
*pi_height = rect_window.bottom - rect_window.top;
return VLC_SUCCESS;
case VOUT_SET_SIZE:
if( p_vout->p_sys->hparent )
return vout_ControlWindow( p_vout,
(void *)p_vout->p_sys->hparent, i_query, args );
/* Update dimensions */
rect_window.top = rect_window.left = 0;
rect_window.right = va_arg( args, unsigned int );
rect_window.bottom = va_arg( args, unsigned int );
if( !rect_window.right ) rect_window.right = p_vout->i_window_width;
if( !rect_window.bottom ) rect_window.bottom = p_vout->i_window_height;
AdjustWindowRect( &rect_window, p_vout->p_sys->i_window_style, 0 );
SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
rect_window.right - rect_window.left,
rect_window.bottom - rect_window.top, SWP_NOMOVE );
return VLC_SUCCESS;
case VOUT_CLOSE:
ShowWindow( p_vout->p_sys->hwnd, SW_HIDE );
case VOUT_REPARENT:
/* Change window style, borders and title bar */
//vlc_mutex_lock( &p_vout->p_sys->lock );
p_vout->p_sys->hparent = 0;
//vlc_mutex_unlock( &p_vout->p_sys->lock );
/* Retrieve the window position */
point.x = point.y = 0;
ClientToScreen( p_vout->p_sys->hwnd, &point );
SetParent( p_vout->p_sys->hwnd, 0 );
p_vout->p_sys->i_window_style =
WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW | WS_SIZEBOX;
SetWindowLong( p_vout->p_sys->hwnd, GWL_STYLE,
p_vout->p_sys->i_window_style |
(i_query == VOUT_CLOSE ? 0 : WS_VISIBLE) );
SetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE, WS_EX_APPWINDOW );
SetWindowPos( p_vout->p_sys->hwnd, 0, point.x, point.y, 0, 0,
SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED );
return vout_vaControlDefault( p_vout, i_query, args );
case VOUT_SET_FOCUS:
b_bool = va_arg( args, vlc_bool_t );
p_vout->p_sys->b_parent_focus = b_bool;
if( b_bool ) GXResume();
else if( !p_vout->p_sys->b_focus ) GXSuspend();
return VLC_SUCCESS;
default:
return vout_vaControlDefault( p_vout, i_query, args );
}
}
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