/*****************************************************************************
* events.c: Windows DirectX video output events handler
*****************************************************************************
- * Copyright (C) 2001-2004 the VideoLAN team
+ * Copyright (C) 2001-2009 the VideoLAN team
* $Id$
*
* Authors: Gildas Bazin <gbazin@videolan.org>
#include <vlc_interface.h>
#include <vlc_playlist.h>
#include <vlc_vout.h>
-#include <vlc_window.h>
+#include <vlc_vout_window.h>
#include <windows.h>
+#include <tchar.h>
#include <windowsx.h>
#include <shellapi.h>
-#ifdef MODULE_NAME_IS_vout_directx
+#ifdef MODULE_NAME_IS_directx
#include <ddraw.h>
#endif
#ifdef MODULE_NAME_IS_direct3d
#include <GL/gl.h>
#endif
-#include "vlc_keys.h"
+#include <vlc_keys.h>
#include "vout.h"
+#ifndef UNDER_CE
+#include <vlc_windows_interfaces.h>
+#endif
+
#ifdef UNDER_CE
#include <aygshell.h>
//WINSHELLAPI BOOL WINAPI SHFullScreen(HWND hwndRequester, DWORD dwState);
p_event->p_vout->fmt_in.i_y_offset;
var_Set( p_event->p_vout, "mouse-y", val );
- val.b_bool = true;
- var_Set( p_event->p_vout, "mouse-moved", val );
+ var_SetBool( p_event->p_vout, "mouse-moved", true );
}
case WM_NCMOUSEMOVE:
#ifdef MODULE_NAME_IS_direct3d
val.psz_string = strdup( VOUT_TITLE " (Direct3D output)" );
#endif
-#ifdef MODULE_NAME_IS_vout_directx
+#ifdef MODULE_NAME_IS_directx
if( p_event->p_vout->p_sys->b_using_overlay ) val.psz_string =
strdup( VOUT_TITLE " (hardware YUV overlay DirectX output)" );
else if( p_event->p_vout->p_sys->b_hw_yuv ) val.psz_string =
#endif
}
-#ifdef UNICODE
{
wchar_t *psz_title = malloc( strlen(val.psz_string) * 2 + 2 );
if( psz_title )
free( val.psz_string ); val.psz_string = (char *)psz_title;
}
}
-#endif
SetWindowText( p_event->p_vout->p_sys->hwnd,
(LPCTSTR)val.psz_string );
msg_Dbg( p_event, "DirectXEventThread terminating" );
- /* clear the changes formerly signaled */
- p_event->p_vout->p_sys->i_changes = 0;
-
DirectXCloseWindow( p_event->p_vout );
vlc_restorecancel (canc);
+
+ /* clear the changes formerly signaled */
+ p_event->p_vout->p_sys->i_changes = EVENT_THREAD_ENDED;
return NULL;
}
/* Get this module's instance */
hInstance = GetModuleHandle(NULL);
- /* If an external window was specified, we'll draw in it. */
- p_vout->p_sys->parent_window =
- 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 );
- p_vout->p_sys->hparent = p_vout->p_sys->parent_window->handle.hwnd;
+ #ifdef MODULE_NAME_IS_direct3d
+ if( !p_vout->p_sys->b_desktop )
+ {
+ #endif
+ vout_window_cfg_t wnd_cfg;
+ memset( &wnd_cfg, 0, sizeof(wnd_cfg) );
+ wnd_cfg.type = VOUT_WINDOW_TYPE_HWND;
+ wnd_cfg.x = p_vout->p_sys->i_window_x;
+ wnd_cfg.y = p_vout->p_sys->i_window_y;
+ wnd_cfg.width = p_vout->p_sys->i_window_width;
+ wnd_cfg.height = p_vout->p_sys->i_window_height;
+
+ /* If an external window was specified, we'll draw in it. */
+ p_vout->p_sys->parent_window = vout_window_New( VLC_OBJECT(p_vout), NULL, &wnd_cfg );
+ if( p_vout->p_sys->parent_window )
+ p_vout->p_sys->hparent = p_vout->p_sys->parent_window->handle.hwnd;
+ #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( p_vout, "Couldn't find desktop icon window. Desktop mode can't be established." );
+ p_vout->p_sys->hparent = hwnd;
+ }
+ #endif
/* We create the window ourself, there is no previous window proc. */
p_vout->p_sys->pf_wndproc = NULL;
DestroyWindow( p_vout->p_sys->hwnd );
if( p_vout->p_sys->hfswnd ) DestroyWindow( p_vout->p_sys->hfswnd );
- vout_ReleaseWindow( p_vout->p_sys->parent_window );
+ #ifdef MODULE_NAME_IS_direct3d
+ if( !p_vout->p_sys->b_desktop )
+ #endif
+ vout_window_Delete( p_vout->p_sys->parent_window );
p_vout->p_sys->hwnd = NULL;
/* We don't unregister the Window Class because it could lead to race
#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;
+ unsigned int i_width, i_height, i_x, i_y;
RECT rect;
POINT point;
rect_dest.top = point.y + i_y;
rect_dest.bottom = rect_dest.top + i_height;
-#ifdef MODULE_NAME_IS_vout_directx
+#ifdef MODULE_NAME_IS_directx
/* Apply overlay hardware constraints */
if( p_vout->p_sys->b_using_overlay )
{
return;
}
-#if 0
+#ifndef NDEBUG
msg_Dbg( p_vout, "DirectXUpdateRects image_dst_clipped coords:"
- " %i,%i,%i,%i",
+ " %li,%li,%li,%li",
rect_dest_clipped.left, rect_dest_clipped.top,
rect_dest_clipped.right, rect_dest_clipped.bottom );
#endif
-#else /* MODULE_NAME_IS_vout_directx */
+#else /* MODULE_NAME_IS_directx */
/* AFAIK, there are no clipping constraints in Direct3D, OpenGL and GDI */
rect_dest_clipped = rect_dest;
(rect_dest.bottom - rect_dest_clipped.bottom) *
p_vout->fmt_out.i_visible_height / (rect_dest.bottom - rect_dest.top);
-#ifdef MODULE_NAME_IS_vout_directx
+#ifdef MODULE_NAME_IS_directx
/* Apply overlay hardware constraints */
if( p_vout->p_sys->b_using_overlay )
{
}
#endif
-#if 0
+#ifndef NDEBUG
msg_Dbg( p_vout, "DirectXUpdateRects image_src_clipped"
- " coords: %i,%i,%i,%i",
+ " coords: %li,%li,%li,%li",
rect_src_clipped.left, rect_src_clipped.top,
rect_src_clipped.right, rect_src_clipped.bottom );
#endif
-#ifdef MODULE_NAME_IS_vout_directx
+#ifdef MODULE_NAME_IS_directx
/* 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;
DirectDrawUpdateOverlay( p_vout );
#endif
+#ifndef UNDER_CE
+ /* Windows 7 taskbar thumbnail code */
+ LPTASKBARLIST3 p_taskbl;
+ OSVERSIONINFO winVer;
+ winVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ if( GetVersionEx(&winVer) && winVer.dwMajorVersion > 5 )
+ {
+ CoInitialize( 0 );
+
+ if( S_OK == CoCreateInstance( &clsid_ITaskbarList,
+ NULL, CLSCTX_INPROC_SERVER,
+ &IID_ITaskbarList3,
+ &p_taskbl) )
+ {
+ RECT rect_video, rect_parent, rect_relative;
+ HWND hroot = GetAncestor(p_vout->p_sys->hwnd,GA_ROOT);
+
+ p_taskbl->vt->HrInit(p_taskbl);
+ GetWindowRect(p_vout->p_sys->hvideownd, &rect_video);
+ GetWindowRect(hroot, &rect_parent);
+ rect_relative.left = rect_video.left - rect_parent.left - 8;
+ rect_relative.right = rect_video.right - rect_video.left + rect_relative.left;
+ rect_relative.top = rect_video.top - rect_parent.top - 10;
+ rect_relative.bottom = rect_video.bottom - rect_video.top + rect_relative.top - 25;
+
+ if (S_OK != p_taskbl->vt->SetThumbnailClip(p_taskbl, hroot, &rect_relative))
+ msg_Err( p_vout, "SetThumbNailClip failed");
+
+ p_taskbl->vt->Release(p_taskbl);
+ }
+ CoUninitialize();
+ }
+#endif
/* Signal the change in size/position */
p_vout->p_sys->i_changes |= DX_POSITION_CHANGE;
}
else
{
- p_vout = (vout_thread_t *)GetWindowLongPtr( hwnd, GWLP_USERDATA );
+ LONG_PTR p_user_data = GetWindowLongPtr( hwnd, GWLP_USERDATA );
+ p_vout = (vout_thread_t *)p_user_data;
if( !p_vout )
{
/* Hmmm mozilla does manage somehow to save the pointer to our
{
switch( message )
{
-#ifdef MODULE_NAME_IS_vout_directx
+#ifdef MODULE_NAME_IS_directx
case WM_ERASEBKGND:
/* For overlay, we need to erase background */
return !p_vout->p_sys->b_using_overlay ?
*****************************************************************************/
static int Control( vout_thread_t *p_vout, int i_query, va_list args )
{
- unsigned int *pi_width, *pi_height;
- bool b_bool;
RECT rect_window;
- POINT point;
switch( i_query )
{
- case VOUT_GET_SIZE:
- if( p_vout->p_sys->parent_window )
- return vaControlParentWindow( p_vout, 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->parent_window )
return vaControlParentWindow( p_vout, i_query, args );
return VLC_SUCCESS;
- case VOUT_CLOSE:
- ShowWindow( p_vout->p_sys->hwnd, SW_HIDE );
- case VOUT_REPARENT:
- /* Retrieve the window position */
- point.x = point.y = 0;
- ClientToScreen( p_vout->p_sys->hwnd, &point );
-
- HWND d = 0;
-
- if( i_query == VOUT_REPARENT ) d = (HWND)va_arg( args, int );
- if( !d )
- {
- 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, 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 );
- }
- else
- {
- vlc_mutex_lock( &p_vout->p_sys->lock );
- p_vout->p_sys->hparent = d;
- vlc_mutex_unlock( &p_vout->p_sys->lock );
-
- SetParent( p_vout->p_sys->hwnd, d );
- p_vout->p_sys->i_window_style = WS_CLIPCHILDREN;
- 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 );
-
- /* Retrieve the parent size */
- RECT rect;
- GetClientRect( d, &rect );
- SetWindowPos( p_vout->p_sys->hwnd, d, point.x, point.y, rect.right, rect.bottom,
- SWP_FRAMECHANGED );
- }
-
- vout_ReleaseWindow( p_vout->p_sys->parent_window );
- return VLC_SUCCESS;
-
case VOUT_SET_STAY_ON_TOP:
if( p_vout->p_sys->hparent && !var_GetBool( p_vout, "fullscreen" ) )
return vaControlParentWindow( p_vout, i_query, args );
p_vout->p_sys->b_on_top_change = true;
return VLC_SUCCESS;
-#ifdef MODULE_NAME_IS_wingapi
- case VOUT_SET_FOCUS:
- b_bool = (bool) va_arg( args, int );
- 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 );
+ return VLC_EGENERIC;
}
}
return window_placement;
}
-/* Internal wrapper over SetWindowPlacement */
-static void SetWindowState(HWND hwnd, int nShowCmd,WINDOWPLACEMENT window_placement)
-{
- window_placement.showCmd = nShowCmd;
- SetWindowPlacement( hwnd, &window_placement );
- SetWindowPos( hwnd, 0, 0, 0, 0, 0,
- SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
-}
-
/* Internal wrapper to call vout_ControlWindow for hparent */
static int vaControlParentWindow( vout_thread_t *p_vout, int i_query,
va_list args )
{
- return vout_ControlWindow( p_vout->p_sys->parent_window, i_query, args );
+ switch( i_query )
+ {
+ case VOUT_SET_SIZE:
+ {
+ const unsigned i_width = va_arg(args, unsigned);
+ const unsigned i_height = va_arg(args, unsigned);
+ return vout_window_SetSize( p_vout->p_sys->parent_window, i_width, i_height );
+ }
+ case VOUT_SET_STAY_ON_TOP:
+ {
+ const bool is_on_top = va_arg(args, int);
+ return vout_window_SetOnTop( p_vout->p_sys->parent_window, is_on_top );
+ }
+ default:
+ return VLC_EGENERIC;
+ }
}
+#if 0
static int ControlParentWindow( vout_thread_t *p_vout, int i_query, ... )
{
va_list args;
va_end( args );
return ret;
}
+#endif
void Win32ToggleFullscreen( vout_thread_t *p_vout )
{
*on the right screen */
HMONITOR hmon = MonitorFromWindow(p_vout->p_sys->hparent,
MONITOR_DEFAULTTONEAREST);
- MONITORINFO mi = {sizeof(mi)};
+ MONITORINFO mi;
if (GetMonitorInfo(hmon, &mi))
SetWindowPos( hwnd, 0,
mi.rcMonitor.left,
SWP_NOZORDER|SWP_FRAMECHANGED );
#endif
}
-
- /* Maximize window */
- SetWindowState( hwnd, SW_SHOWMAXIMIZED, window_placement );
+ else
+ {
+ /* Maximize non embedded window */
+ ShowWindow( hwnd, SW_SHOWMAXIMIZED );
+ }
if( p_vout->p_sys->hparent )
{
/* Change window style, no borders and no title bar */
SetWindowLong( hwnd, GWL_STYLE, p_vout->p_sys->i_window_style );
- /* Normal window */
- SetWindowState( hwnd, SW_SHOWNORMAL, window_placement );
-
if( p_vout->p_sys->hparent )
{
RECT rect;
SetForegroundWindow( p_vout->p_sys->hparent );
ShowWindow( hwnd, SW_HIDE );
}
+ else
+ {
+ /* return to normal window for non embedded vout */
+ SetWindowPlacement( hwnd, &window_placement );
+ ShowWindow( hwnd, SW_SHOWNORMAL );
+ }
/* Make sure the mouse cursor is displayed */
PostMessage( p_vout->p_sys->hwnd, WM_VLC_SHOW_MOUSE, 0, 0 );
}
- vlc_value_t val;
/* Update the object variable and trigger callback */
- val.b_bool = p_vout->b_fullscreen;
- var_Set( p_vout, "fullscreen", val );
+ var_SetBool( p_vout, "fullscreen", p_vout->b_fullscreen );
+}
+
+#ifndef UNDER_CE
+void DisableScreensaver( vout_thread_t *p_vout )
+{
+ /* 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;
+ if( var_GetBool( p_vout, "disable-screensaver" ) )
+ {
+ 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);
+ }
+ }
+}
+
+void RestoreScreensaver( vout_thread_t *p_vout )
+{
+ /* 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
+
+int CreateEventThread( vout_thread_t *p_vout )
+{
+ if( !( p_vout->p_sys->i_changes & SWITCHING_MODE_FLAG ) )
+ vlc_mutex_init( &p_vout->p_sys->lock );
+
+ /* 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.
+ * 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;
+ p_vout->p_sys->p_event->window_ready = CreateEvent( NULL, TRUE, FALSE, NULL );
+ if( vlc_thread_create( p_vout->p_sys->p_event, "Vout Events Thread",
+ EventThread, 0 ) )
+ {
+ msg_Err( p_vout, "cannot create Vout EventThread" );
+ CloseHandle( p_vout->p_sys->p_event->window_ready );
+ vlc_object_release( p_vout->p_sys->p_event );
+ p_vout->p_sys->p_event = NULL;
+ return 0;
+ }
+ WaitForSingleObject( p_vout->p_sys->p_event->window_ready, INFINITE );
+ CloseHandle( p_vout->p_sys->p_event->window_ready );
+
+ if( p_vout->p_sys->p_event->b_error )
+ {
+ msg_Err( p_vout, "Vout EventThread failed" );
+ return 0;
+ }
+
+ vlc_object_attach( p_vout->p_sys->p_event, p_vout );
+
+ msg_Dbg( p_vout, "Vout EventThread running" );
+ return 1;
+}
+
+void StopEventThread( vout_thread_t *p_vout )
+{
+ if( p_vout->b_fullscreen )
+ {
+ msg_Dbg( p_vout, "Quitting fullscreen" );
+ Win32ToggleFullscreen( p_vout );
+ /* Force fullscreen in the core for the next video */
+ var_SetBool( p_vout, "fullscreen", true );
+ }
+
+ if( p_vout->p_sys->p_event )
+ {
+ vlc_object_detach( p_vout->p_sys->p_event );
+
+ /* Kill Vout EventThread */
+ vlc_object_kill( p_vout->p_sys->p_event );
+
+ /* 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_release( p_vout->p_sys->p_event );
+ }
+
+ if( !( p_vout->p_sys->i_changes & SWITCHING_MODE_FLAG ) )
+ vlc_mutex_destroy( &p_vout->p_sys->lock );
}