#include <windows.h>
#include <ddraw.h>
+#include <commctrl.h>
#include <multimon.h>
#undef GetSystemMetrics
static DWORD DirectXFindColorkey( vout_thread_t *p_vout, uint32_t i_color );
+void SwitchWallpaperMode( vout_thread_t *, vlc_bool_t );
+
/* Object variables callbacks */
static int FindDevicesCallback( vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void * );
+static int WallpaperCallback( vlc_object_t *, char const *,
+ vlc_value_t, vlc_value_t, void * );
/*****************************************************************************
* Module descriptor
#define TRIPLEBUF_TEXT N_("Use triple buffering for overlays")
#define TRIPLEBUF_LONGTEXT N_( \
- "Try to use triple bufferring when using YUV overlays. That results in " \
+ "Try to use triple buffering when using YUV overlays. That results in " \
"much better video quality (no flickering)." )
#define DEVICE_TEXT N_("Name of desired display device")
-#define DEVICE_LONGTEXT N_("In a multimonitor configuration, you can specify "\
- "the Windows device name of the display that you want the video window " \
- "to open on. For example, \"\\\\.\\DISPLAY1\" or \"\\\\.\\DISPLAY2\"." )
+#define DEVICE_LONGTEXT N_("In a multiple monitor configuration, you can " \
+ "specify the Windows device name of the display that you want the video " \
+ "window to open on. For example, \"\\\\.\\DISPLAY1\" or " \
+ "\"\\\\.\\DISPLAY2\"." )
+
+#define WALLPAPER_TEXT N_("Enable wallpaper mode ")
+#define WALLPAPER_LONGTEXT N_( \
+ "The wallpaper mode allows you to display the video as the desktop " \
+ "background. Note that this feature only works in overlay mode and " \
+ "the desktop must not already have a wallpaper." )
static char *ppsz_dev[] = { "" };
static char *ppsz_dev_text[] = { N_("Default") };
change_string_list( ppsz_dev, ppsz_dev_text, FindDevicesCallback );
change_action_add( FindDevicesCallback, N_("Refresh list") );
+ add_bool( "directx-wallpaper", 0, NULL, WALLPAPER_TEXT, WALLPAPER_LONGTEXT,
+ VLC_TRUE );
+
set_description( _("DirectX video output") );
set_capability( "video output", 100 );
add_shortcut( "directx" );
p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL;
p_vout->p_sys->hparent = 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_Get( p_vout, "video-on-top", &val );
var_Set( p_vout, "video-on-top", val );
+ /* Variable to indicate if the window should be on top of others */
+ /* Trigger a callback right now */
+ var_Create( p_vout, "directx-wallpaper", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
+ val.psz_string = _("Wallpaper");
+ var_Change( p_vout, "directx-wallpaper", VLC_VAR_SETTEXT, &val, NULL );
+ var_AddCallback( p_vout, "directx-wallpaper", WallpaperCallback, NULL );
+ var_Get( p_vout, "directx-wallpaper", &val );
+ var_Set( p_vout, "directx-wallpaper", val );
+
return VLC_SUCCESS;
error:
vlc_mutex_destroy( &p_vout->p_sys->lock );
+ /* Make sure the wallpaper is restored */
+ SwitchWallpaperMode( p_vout, VLC_FALSE );
+
if( p_vout->p_sys )
{
free( p_vout->p_sys );
* Manage: handle Sys events
*****************************************************************************
* This function should be called regularly by the video output thread.
- * It returns a non null value if an error occured.
+ * It returns a non null value if an error occurred.
*****************************************************************************/
static int Manage( vout_thread_t *p_vout )
{
* long time (for example when you move your window on the screen), I
* decided to isolate PeekMessage in another thread. */
+ if( p_vout->p_sys->i_changes & DX_WALLPAPER_CHANGE )
+ {
+ SwitchWallpaperMode( p_vout, !p_vout->p_sys->b_wallpaper );
+ p_vout->p_sys->i_changes &= ~DX_WALLPAPER_CHANGE;
+ DirectXUpdateOverlay( p_vout );
+ }
+
/*
* Fullscreen change
*/
/* We need to switch between Maximized and Normal sized window */
window_placement.length = sizeof(WINDOWPLACEMENT);
- 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() );
- SetForegroundWindow( p_vout->p_sys->hwnd );
- }
+ if( p_vout->p_sys->hparent )
+ {
+ POINT point;
+
+ /* Retrieve the window position */
+ point.x = point.y = 0;
+ ClientToScreen( p_vout->p_sys->hwnd, &point );
+ SetParent( p_vout->p_sys->hwnd, GetDesktopWindow() );
+ SetWindowPos( p_vout->p_sys->hwnd, 0, point.x, point.y, 0, 0,
+ SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED );
+ SetForegroundWindow( p_vout->p_sys->hwnd );
+ }
/* Maximized window */
+ GetWindowPlacement( p_vout->p_sys->hwnd, &window_placement );
window_placement.showCmd = SW_SHOWMAXIMIZED;
/* Change window style, no borders and no title bar */
- i_style = WS_CLIPCHILDREN;
+ i_style = WS_CLIPCHILDREN | WS_VISIBLE | WS_POPUP;
}
else
{
if( p_vout->p_sys->hparent )
{
SetParent( p_vout->p_sys->hwnd, p_vout->p_sys->hparent );
+ SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0, 0, 0,
+ SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED );
i_style = WS_CLIPCHILDREN | WS_VISIBLE | WS_CHILD;
+ SetForegroundWindow( p_vout->p_sys->hparent );
}
else
{
}
/* Normal window */
+ GetWindowPlacement( p_vout->p_sys->hwnd, &window_placement );
window_placement.showCmd = SW_SHOWNORMAL;
/* Make sure the mouse cursor is displayed */
/* 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 );
+ SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0, 0, 0,
+ SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED );
/* Update the object variable and trigger callback */
val.b_bool = p_vout->b_fullscreen;
if( !p_vout->p_sys->b_using_overlay ) return VLC_EGENERIC;
+ if( p_vout->p_sys->b_wallpaper )
+ {
+ int i_x, i_y, i_width, i_height;
+
+ rect_src.left = rect_src.top = 0;
+ rect_src.right = p_vout->render.i_width;
+ rect_src.bottom = p_vout->render.i_height;
+
+ rect_dest = p_vout->p_sys->rect_display;
+ vout_PlacePicture( p_vout, rect_dest.right, rect_dest.bottom,
+ &i_x, &i_y, &i_width, &i_height );
+
+ rect_dest.left += i_x;
+ rect_dest.right = rect_dest.left + i_width;
+ rect_dest.top += i_y;
+ rect_dest.bottom = rect_dest.top + i_height;
+ }
+
vlc_mutex_lock( &p_vout->p_sys->lock );
if( p_vout->p_sys->p_current_surface == NULL )
{
{
int i,j;
for( i = 0; i < front_pic.i_planes; i++ )
- for( j = 0; j < front_pic.p[i].i_lines; j++)
+ for( j = 0; j < front_pic.p[i].i_visible_lines; j++)
memset( front_pic.p[i].p_pixels + j *
front_pic.p[i].i_pitch, 127,
front_pic.p[i].i_visible_pitch );
{
p_pic[i].i_status = DESTROYED_PICTURE;
p_pic[i].i_type = DIRECT_PICTURE;
+ p_pic[i].b_slow = VLC_TRUE;
p_pic[i].pf_lock = DirectXLockSurface;
p_pic[i].pf_unlock = DirectXUnlockSurface;
PP_OUTPUTPICTURE[i] = &p_pic[i];
case VLC_FOURCC('R','V','3','2'):
p_pic->p->p_pixels = p_pic->p_sys->ddsd.lpSurface;
p_pic->p->i_lines = p_vout->output.i_height;
+ p_pic->p->i_visible_lines = p_vout->output.i_height;
p_pic->p->i_pitch = p_pic->p_sys->ddsd.lPitch;
switch( p_vout->output.i_chroma )
{
p_pic->Y_PIXELS = p_pic->p_sys->ddsd.lpSurface;
p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height;
+ p_pic->p[Y_PLANE].i_visible_lines = p_vout->output.i_height;
p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->ddsd.lPitch;
p_pic->p[Y_PLANE].i_pixel_pitch = 1;
p_pic->p[Y_PLANE].i_visible_pitch = p_vout->output.i_width *
p_pic->V_PIXELS = p_pic->Y_PIXELS
+ p_pic->p[Y_PLANE].i_lines * p_pic->p[Y_PLANE].i_pitch;
p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2;
+ p_pic->p[V_PLANE].i_visible_lines = p_vout->output.i_height / 2;
p_pic->p[V_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2;
p_pic->p[V_PLANE].i_pixel_pitch = 1;
p_pic->p[V_PLANE].i_visible_pitch = p_vout->output.i_width / 2 *
p_pic->U_PIXELS = p_pic->V_PIXELS
+ p_pic->p[V_PLANE].i_lines * p_pic->p[V_PLANE].i_pitch;
p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2;
+ p_pic->p[U_PLANE].i_visible_lines = p_vout->output.i_height / 2;
p_pic->p[U_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2;
p_pic->p[U_PLANE].i_pixel_pitch = 1;
p_pic->p[U_PLANE].i_visible_pitch = p_vout->output.i_width / 2 *
p_pic->Y_PIXELS = p_pic->p_sys->ddsd.lpSurface;
p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height;
+ p_pic->p[Y_PLANE].i_visible_lines = p_vout->output.i_height;
p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->ddsd.lPitch;
p_pic->p[Y_PLANE].i_pixel_pitch = 1;
p_pic->p[Y_PLANE].i_visible_pitch = p_vout->output.i_width *
p_pic->U_PIXELS = p_pic->Y_PIXELS
+ p_pic->p[Y_PLANE].i_lines * p_pic->p[Y_PLANE].i_pitch;
p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2;
+ p_pic->p[U_PLANE].i_visible_lines = p_vout->output.i_height / 2;
p_pic->p[U_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2;
p_pic->p[U_PLANE].i_pixel_pitch = 1;
p_pic->p[U_PLANE].i_visible_pitch = p_vout->output.i_width / 2 *
p_pic->V_PIXELS = p_pic->U_PIXELS
+ p_pic->p[U_PLANE].i_lines * p_pic->p[U_PLANE].i_pitch;
p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2;
+ p_pic->p[V_PLANE].i_visible_lines = p_vout->output.i_height / 2;
p_pic->p[V_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2;
p_pic->p[V_PLANE].i_pixel_pitch = 1;
p_pic->p[V_PLANE].i_visible_pitch = p_vout->output.i_width / 2 *
p_pic->i_planes = 3;
break;
+ case VLC_FOURCC('U','Y','V','Y'):
case VLC_FOURCC('Y','U','Y','2'):
p_pic->p->p_pixels = p_pic->p_sys->ddsd.lpSurface;
p_pic->p->i_lines = p_vout->output.i_height;
+ p_pic->p->i_visible_lines = p_vout->output.i_height;
p_pic->p->i_pitch = p_pic->p_sys->ddsd.lPitch;
p_pic->p->i_pixel_pitch = 2;
p_pic->p->i_visible_pitch = p_vout->output.i_width *
return i_rgb;
}
+/*****************************************************************************
+ * A few toolbox functions
+ *****************************************************************************/
+void SwitchWallpaperMode( vout_thread_t *p_vout, vlc_bool_t b_on )
+{
+ HWND hwnd;
+
+ if( p_vout->p_sys->b_wallpaper == b_on ) return; /* Nothing to do */
+
+ hwnd = FindWindow( "Progman", NULL );
+ if( hwnd ) hwnd = FindWindowEx( hwnd, NULL, "SHELLDLL_DefView", NULL );
+ if( hwnd ) hwnd = FindWindowEx( hwnd, NULL, "SysListView32", NULL );
+ if( !hwnd )
+ {
+ msg_Warn( p_vout, "couldn't find \"SysListView32\" window, "
+ "wallpaper mode not supported" );
+ return;
+ }
+
+ p_vout->p_sys->b_wallpaper = b_on;
+
+ msg_Dbg( p_vout, "wallpaper mode %s", b_on ? "enabled" : "disabled" );
+
+ if( p_vout->p_sys->b_wallpaper )
+ {
+ p_vout->p_sys->color_bkg = ListView_GetBkColor( hwnd );
+ p_vout->p_sys->color_bkgtxt = ListView_GetTextBkColor( hwnd );
+
+ ListView_SetBkColor( hwnd, p_vout->p_sys->i_rgb_colorkey );
+ ListView_SetTextBkColor( hwnd, p_vout->p_sys->i_rgb_colorkey );
+ }
+ else if( hwnd )
+ {
+ ListView_SetBkColor( hwnd, p_vout->p_sys->color_bkg );
+ ListView_SetTextBkColor( hwnd, p_vout->p_sys->color_bkgtxt );
+ }
+
+ /* Update desktop */
+ InvalidateRect( hwnd, NULL, TRUE );
+ UpdateWindow( hwnd );
+}
+
/*****************************************************************************
* config variable callback
*****************************************************************************/
FreeLibrary( hddraw_dll );
+ /* Signal change to the interface */
+ p_item->b_dirty = VLC_TRUE;
+
+ return VLC_SUCCESS;
+}
+
+static int WallpaperCallback( vlc_object_t *p_this, char const *psz_cmd,
+ vlc_value_t oldval, vlc_value_t newval,
+ void *p_data )
+{
+ vout_thread_t *p_vout = (vout_thread_t *)p_this;
+
+ if( (newval.b_bool && !p_vout->p_sys->b_wallpaper) ||
+ (!newval.b_bool && p_vout->p_sys->b_wallpaper) )
+ {
+ playlist_t *p_playlist;
+
+ p_playlist =
+ (playlist_t *)vlc_object_find( p_this, VLC_OBJECT_PLAYLIST,
+ FIND_PARENT );
+ if( p_playlist )
+ {
+ /* Modify playlist as well because the vout might have to be
+ * restarted */
+ var_Create( p_playlist, "directx-wallpaper", VLC_VAR_BOOL );
+ var_Set( p_playlist, "directx-wallpaper", newval );
+
+ vlc_object_release( p_playlist );
+ }
+
+ p_vout->p_sys->i_changes |= DX_WALLPAPER_CHANGE;
+ }
+
return VLC_SUCCESS;
}