From d98e43b1c635d2e91dc950536d75dcb0c2c1c8b2 Mon Sep 17 00:00:00 2001 From: Laurent Aimar Date: Tue, 5 Jan 2010 19:53:51 +0100 Subject: [PATCH] Revert "Removed old msw files." This reverts commit e145f5a5bb6d61d67a8b9a6d1a4f1b33976c8ff6. --- modules/video_output/msw/common_vo.c | 761 ++++++++++++++++++ modules/video_output/msw/events_vo.c | 1093 ++++++++++++++++++++++++++ modules/video_output/msw/events_vo.h | 57 ++ modules/video_output/msw/vout.h | 306 +++++++ 4 files changed, 2217 insertions(+) create mode 100644 modules/video_output/msw/common_vo.c create mode 100644 modules/video_output/msw/events_vo.c create mode 100644 modules/video_output/msw/events_vo.h create mode 100644 modules/video_output/msw/vout.h diff --git a/modules/video_output/msw/common_vo.c b/modules/video_output/msw/common_vo.c new file mode 100644 index 0000000000..07841c304e --- /dev/null +++ b/modules/video_output/msw/common_vo.c @@ -0,0 +1,761 @@ +/***************************************************************************** + * common.c: + ***************************************************************************** + * Copyright (C) 2001-2009 the VideoLAN team + * $Id$ + * + * Authors: Gildas Bazin + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + + +/***************************************************************************** + * Preamble: This file contains the functions related to the creation of + * a window and the handling of its messages (events). + *****************************************************************************/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include +#include +#include + +#ifdef MODULE_NAME_IS_directx +#include +#endif +#ifdef MODULE_NAME_IS_direct3d +#include +#endif +#ifdef MODULE_NAME_IS_glwin32 +#include +#endif + +#include "vout.h" + +#ifndef UNDER_CE +#include +#endif + +#ifdef UNDER_CE +#include + //WINSHELLAPI BOOL WINAPI SHFullScreen(HWND hwndRequester, DWORD dwState); +#endif + +static int vaControlParentWindow( vout_thread_t *, int, va_list ); + +/* */ +int CommonInit( vout_thread_t *p_vout ) +{ + vout_sys_t *p_sys = p_vout->p_sys; + + p_sys->hwnd = NULL; + p_sys->hvideownd = NULL; + p_sys->hparent = NULL; + p_sys->hfswnd = NULL; + p_sys->i_changes = 0; + SetRectEmpty( &p_sys->rect_display ); + SetRectEmpty( &p_sys->rect_parent ); + + var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); + + /* Set main window's size */ + vout_window_cfg_t wnd_cfg; + + memset( &wnd_cfg, 0, sizeof(wnd_cfg) ); + wnd_cfg.type = VOUT_WINDOW_TYPE_HWND; + wnd_cfg.x = 0; + wnd_cfg.y = 0; + wnd_cfg.width = p_vout->i_window_width; + wnd_cfg.height = p_vout->i_window_height; + + p_sys->p_event = EventThreadCreate( p_vout, &wnd_cfg ); + if( !p_sys->p_event ) + return VLC_EGENERIC; + + event_cfg_t cfg; + memset(&cfg, 0, sizeof(cfg)); +#ifdef MODULE_NAME_IS_direct3d + cfg.use_desktop = p_vout->p_sys->b_desktop; +#endif +#ifdef MODULE_NAME_IS_directx + cfg.use_overlay = p_vout->p_sys->b_using_overlay; +#endif + event_hwnd_t hwnd; + if( EventThreadStart( p_sys->p_event, &hwnd, &cfg ) ) + return VLC_EGENERIC; + + p_sys->parent_window = hwnd.parent_window; + p_sys->hparent = hwnd.hparent; + p_sys->hwnd = hwnd.hwnd; + p_sys->hvideownd = hwnd.hvideownd; + p_sys->hfswnd = hwnd.hfswnd; + + /* Variable to indicate if the window should be on top of others */ + /* Trigger a callback right now */ + var_TriggerCallback( p_vout, "video-on-top" ); + + /* Why not with glwin32 */ +#if !defined(UNDER_CE) && !defined(MODULE_NAME_IS_glwin32) + var_Create( p_vout, "disable-screensaver", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); + DisableScreensaver ( p_vout ); +#endif + + return VLC_SUCCESS; +} + +/* */ +void CommonClean( vout_thread_t *p_vout ) +{ + vout_sys_t *p_sys = p_vout->p_sys; + + ExitFullscreen( p_vout ); + if( p_sys->p_event ) + { + EventThreadStop( p_sys->p_event ); + EventThreadDestroy( p_sys->p_event ); + } + +#if !defined(UNDER_CE) && !defined(MODULE_NAME_IS_glwin32) + RestoreScreensaver( p_vout ); +#endif +} + +void CommonManage( 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. */ + if( p_vout->p_sys->hparent ) + { + RECT rect_parent; + POINT point; + + 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; + + /* FIXME I find such #ifdef quite weirds. Are they really needed ? */ + +#if defined(MODULE_NAME_IS_direct3d) + SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0, + rect_parent.right - rect_parent.left, + rect_parent.bottom - rect_parent.top, + SWP_NOZORDER ); + UpdateRects( p_vout, true ); +#else + /* 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 ); + +#if defined(MODULE_NAME_IS_wingdi) || defined(MODULE_NAME_IS_wingapi) + unsigned int i_x, i_y, i_width, i_height; + vout_PlacePicture( p_vout, rect_parent.right - rect_parent.left, + rect_parent.bottom - rect_parent.top, + &i_x, &i_y, &i_width, &i_height ); + + SetWindowPos( p_vout->p_sys->hvideownd, HWND_TOP, + i_x, i_y, i_width, i_height, 0 ); +#endif +#endif + } + } + + /* */ + p_vout->p_sys->i_changes |= EventThreadRetreiveChanges( p_vout->p_sys->p_event ); + + /* autoscale toggle */ + if( p_vout->i_changes & VOUT_SCALE_CHANGE ) + { + p_vout->i_changes &= ~VOUT_SCALE_CHANGE; + + p_vout->b_autoscale = var_GetBool( p_vout, "autoscale" ); + p_vout->i_zoom = (int) ZOOM_FP_FACTOR; + + UpdateRects( p_vout, true ); + } + + /* scaling factor */ + if( p_vout->i_changes & VOUT_ZOOM_CHANGE ) + { + p_vout->i_changes &= ~VOUT_ZOOM_CHANGE; + + p_vout->b_autoscale = false; + p_vout->i_zoom = + (int)( ZOOM_FP_FACTOR * var_GetFloat( p_vout, "scale" ) ); + UpdateRects( p_vout, true ); + } + + /* 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_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 = (int64_t)VOUT_ASPECT_FACTOR * + p_vout->fmt_in.i_sar_num * p_vout->fmt_in.i_width / + (p_vout->fmt_in.i_sar_den * p_vout->fmt_in.i_height); + UpdateRects( p_vout, true ); + } + + /* We used to call the Win32 PeekMessage function here to read the window + * messages. But since window can stay blocked into this function for a + * long time (for example when you move your window on the screen), I + * decided to isolate PeekMessage in another thread. */ + + /* + * Fullscreen change + */ + if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE + || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE ) + { + Win32ToggleFullscreen( p_vout ); + + p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE; + p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE; + } + + /* + * Pointer change + */ + EventThreadMouseAutoHide( p_vout->p_sys->p_event ); + + /* + * "Always on top" status change + */ + if( p_vout->p_sys->b_on_top_change ) + { + HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE ); + bool b = var_GetBool( p_vout, "video-on-top" ); + + /* Set the window on top if necessary */ + if( b && !( 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( !b && ( 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 ); + } + + p_vout->p_sys->b_on_top_change = false; + } +} + +/***************************************************************************** + * 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 UpdateRects( vout_thread_t *p_vout, bool 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 + + unsigned 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 */ + bool b_changed; + EventThreadUpdateWindowPosition( p_vout->p_sys->p_event, &b_changed, + point.x, point.y, + rect.right, rect.bottom ); + if( !b_force && !b_changed ) + return; + + /* Update the window position and size */ + 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, 0, + i_x, i_y, i_width, i_height, + SWP_NOCOPYBITS|SWP_NOZORDER|SWP_ASYNCWINDOWPOS ); + + /* Destination image position and dimensions */ +#if defined(MODULE_NAME_IS_direct3d) + rect_dest.left = 0; + rect_dest.right = i_width; + rect_dest.top = 0; + rect_dest.bottom = i_height; +#else + 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; + +#ifdef MODULE_NAME_IS_directx + /* Apply overlay hardware constraints */ + if( p_vout->p_sys->b_using_overlay ) + { + if( p_vout->p_sys->i_align_dest_boundary ) + rect_dest.left = ( rect_dest.left + + p_vout->p_sys->i_align_dest_boundary / 2 ) & + ~p_vout->p_sys->i_align_dest_boundary; + + if( p_vout->p_sys->i_align_dest_size ) + rect_dest.right = (( rect_dest.right - rect_dest.left + + p_vout->p_sys->i_align_dest_size / 2 ) & + ~p_vout->p_sys->i_align_dest_size) + rect_dest.left; + } +#endif + +#endif + +#if defined(MODULE_NAME_IS_directx) || defined(MODULE_NAME_IS_direct3d) + /* UpdateOverlay directdraw function doesn't automatically clip to the + * display size so we need to do it otherwise it will fail + * It is also needed for d3d to avoid exceding our surface size */ + + /* Clip the destination window */ + if( !IntersectRect( &rect_dest_clipped, &rect_dest, + &p_vout->p_sys->rect_display ) ) + { + SetRectEmpty( &rect_src_clipped ); + return; + } + +#ifndef NDEBUG + msg_Dbg( p_vout, "DirectXUpdateRects image_dst_clipped coords:" + " %li,%li,%li,%li", + rect_dest_clipped.left, rect_dest_clipped.top, + rect_dest_clipped.right, rect_dest_clipped.bottom ); +#endif + +#else + + /* AFAIK, there are no clipping constraints in Direct3D, OpenGL and GDI */ + rect_dest_clipped = rect_dest; + +#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->render.i_width; + rect_src.bottom = p_vout->render.i_height; + + /* Clip the source image */ + rect_src_clipped.left = p_vout->fmt_out.i_x_offset + + (rect_dest_clipped.left - rect_dest.left) * + p_vout->fmt_out.i_visible_width / (rect_dest.right - rect_dest.left); + rect_src_clipped.right = p_vout->fmt_out.i_x_offset + + p_vout->fmt_out.i_visible_width - + (rect_dest.right - rect_dest_clipped.right) * + p_vout->fmt_out.i_visible_width / (rect_dest.right - rect_dest.left); + rect_src_clipped.top = p_vout->fmt_out.i_y_offset + + (rect_dest_clipped.top - rect_dest.top) * + p_vout->fmt_out.i_visible_height / (rect_dest.bottom - rect_dest.top); + rect_src_clipped.bottom = p_vout->fmt_out.i_y_offset + + p_vout->fmt_out.i_visible_height - + (rect_dest.bottom - rect_dest_clipped.bottom) * + p_vout->fmt_out.i_visible_height / (rect_dest.bottom - rect_dest.top); + +#ifdef MODULE_NAME_IS_directx + /* Apply overlay hardware constraints */ + if( p_vout->p_sys->b_using_overlay ) + { + if( p_vout->p_sys->i_align_src_boundary ) + rect_src_clipped.left = ( rect_src_clipped.left + + p_vout->p_sys->i_align_src_boundary / 2 ) & + ~p_vout->p_sys->i_align_src_boundary; + + if( p_vout->p_sys->i_align_src_size ) + rect_src_clipped.right = (( rect_src_clipped.right - + rect_src_clipped.left + + p_vout->p_sys->i_align_src_size / 2 ) & + ~p_vout->p_sys->i_align_src_size) + rect_src_clipped.left; + } +#elif defined(MODULE_NAME_IS_direct3d) + /* Needed at least with YUV content */ + rect_src_clipped.left &= ~1; + rect_src_clipped.right &= ~1; + rect_src_clipped.top &= ~1; + rect_src_clipped.bottom &= ~1; +#endif + +#ifndef NDEBUG + msg_Dbg( p_vout, "DirectXUpdateRects image_src_clipped" + " 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_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; + 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; + + if( p_vout->p_sys->b_using_overlay ) + 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; + +#undef rect_src +#undef rect_src_clipped +#undef rect_dest +#undef rect_dest_clipped +} + +/***************************************************************************** + * Control: control facility for the vout + *****************************************************************************/ +int Control( vout_thread_t *p_vout, int i_query, va_list args ) +{ + RECT rect_window; + + switch( i_query ) + { + case VOUT_SET_SIZE: + if( p_vout->p_sys->parent_window ) + return vaControlParentWindow( p_vout, 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, EventThreadGetWindowStyle( p_vout->p_sys->p_event ), 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_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; + + default: + return VLC_EGENERIC; + } +} + + +/* Internal wrapper over GetWindowPlacement */ +static WINDOWPLACEMENT getWindowState(HWND hwnd) +{ + WINDOWPLACEMENT window_placement; + window_placement.length = sizeof(WINDOWPLACEMENT); + GetWindowPlacement( hwnd, &window_placement ); + return window_placement; +} + +/* Internal wrapper to call vout_ControlWindow for hparent */ +static int vaControlParentWindow( vout_thread_t *p_vout, int i_query, + va_list 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_SetState( 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; + int ret; + + va_start( args, i_query ); + ret = vaControlParentWindow( p_vout, i_query, args ); + va_end( args ); + return ret; +} +#endif + +void ExitFullscreen( 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 ); + } +} + +void Win32ToggleFullscreen( vout_thread_t *p_vout ) +{ + HWND hwnd = (p_vout->p_sys->hparent && p_vout->p_sys->hfswnd) ? + p_vout->p_sys->hfswnd : p_vout->p_sys->hwnd; + + /* Save the current windows placement/placement to restore + when fullscreen is over */ + WINDOWPLACEMENT window_placement = getWindowState( hwnd ); + + p_vout->b_fullscreen = ! p_vout->b_fullscreen; + + if( p_vout->p_sys->parent_window ) + { + vout_window_SetFullScreen( p_vout->p_sys->parent_window, + p_vout->b_fullscreen ); + return; + } + + /* We want to go to Fullscreen */ + if( p_vout->b_fullscreen ) + { + msg_Dbg( p_vout, "entering fullscreen mode" ); + + /* 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 ) + { +#ifdef UNDER_CE + 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 ); +#else + /* Retrieve current window position so fullscreen will happen + *on the right screen */ + HMONITOR hmon = MonitorFromWindow(p_vout->p_sys->hparent, + MONITOR_DEFAULTTONEAREST); + MONITORINFO mi; + mi.cbSize = sizeof(MONITORINFO); + if (GetMonitorInfo(hmon, &mi)) + SetWindowPos( hwnd, 0, + mi.rcMonitor.left, + mi.rcMonitor.top, + mi.rcMonitor.right - mi.rcMonitor.left, + mi.rcMonitor.bottom - mi.rcMonitor.top, + SWP_NOZORDER|SWP_FRAMECHANGED ); +#endif + } + else + { + /* Maximize non embedded window */ + ShowWindow( hwnd, SW_SHOWMAXIMIZED ); + } + + if( p_vout->p_sys->hparent ) + { + /* Hide the previous window */ + 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 ); + +#ifdef UNDER_CE + HWND topLevelParent = GetParent( p_vout->p_sys->hparent ); +#else + HWND topLevelParent = GetAncestor( p_vout->p_sys->hparent, GA_ROOT ); +#endif + ShowWindow( topLevelParent, SW_HIDE ); + } + + SetForegroundWindow( hwnd ); + } + else + { + msg_Dbg( p_vout, "leaving fullscreen mode" ); + /* Change window style, no borders and no title bar */ + SetWindowLong( hwnd, GWL_STYLE, EventThreadGetWindowStyle( p_vout->p_sys->p_event ) ); + + 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 ); + +#ifdef UNDER_CE + HWND topLevelParent = GetParent( p_vout->p_sys->hparent ); +#else + HWND topLevelParent = GetAncestor( p_vout->p_sys->hparent, GA_ROOT ); +#endif + ShowWindow( topLevelParent, SW_SHOW ); + 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 */ + EventThreadMouseShow( p_vout->p_sys->p_event ); + } + + /* Update the object variable and trigger callback */ + 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 + diff --git a/modules/video_output/msw/events_vo.c b/modules/video_output/msw/events_vo.c new file mode 100644 index 0000000000..49597ab0ac --- /dev/null +++ b/modules/video_output/msw/events_vo.c @@ -0,0 +1,1093 @@ +/***************************************************************************** + * events.c: Windows DirectX video output events handler + ***************************************************************************** + * Copyright (C) 2001-2009 the VideoLAN team + * $Id$ + * + * Authors: Gildas Bazin + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + + +/***************************************************************************** + * Preamble: This file contains the functions related to the creation of + * a window and the handling of its messages (events). + *****************************************************************************/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#ifdef MODULE_NAME_IS_directx +#include +#endif +#ifdef MODULE_NAME_IS_direct3d +#include +#endif +#ifdef MODULE_NAME_IS_glwin32 +#include +#endif + +#include +#include "vout.h" + +#ifdef UNDER_CE +#include + //WINSHELLAPI BOOL WINAPI SHFullScreen(HWND hwndRequester, DWORD dwState); +#endif + +/*#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. + *****************************************************************************/ +#define WM_VLC_HIDE_MOUSE (WM_APP + 0) +#define WM_VLC_SHOW_MOUSE (WM_APP + 1) +#define WM_VLC_CHANGE_TEXT (WM_APP + 2) + +struct event_thread_t +{ + vout_thread_t *p_vout; + + /* */ + vlc_thread_t thread; + vlc_mutex_t lock; + vlc_cond_t wait; + bool b_ready; + bool b_done; + bool b_error; + + /* */ + bool use_desktop; + bool use_overlay; + + /* Mouse */ + volatile bool b_cursor_hidden; + volatile mtime_t i_lastmoved; + mtime_t i_mouse_hide_timeout; + + /* Title */ + char *psz_title; + + int i_window_style; + vout_window_cfg_t wnd_cfg; + + /* */ + unsigned i_changes; + + /* */ + vout_window_t *parent_window; + HWND hparent; + HWND hwnd; + HWND hvideownd; + HWND hfswnd; +}; + +static int DirectXCreateWindow( event_thread_t * ); +static void DirectXCloseWindow ( event_thread_t * ); +static long FAR PASCAL DirectXEventProc( HWND, UINT, WPARAM, LPARAM ); + +static void DirectXPopupMenu( event_thread_t *p_event, bool b_open ) +{ + var_SetBool( p_event->p_vout->p_libvlc, "intf-popupmenu", b_open ); +} + +static int DirectXConvertKey( int i_key ); + +/***************************************************************************** + * 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. + *****************************************************************************/ +static void *EventThread( void *p_this ) +{ + event_thread_t *p_event = (event_thread_t *)p_this; + vout_thread_t *p_vout = p_event->p_vout; + MSG msg; + POINT old_mouse_pos = {0,0}, mouse_pos; + vlc_value_t val; + unsigned int i_width, i_height, i_x, i_y; + HMODULE hkernel32; + int canc = vlc_savecancel (); + + vlc_mutex_lock( &p_event->lock ); + /* Create a window for the video */ + /* Creating a window under Windows also initializes the thread's event + * message queue */ + if( DirectXCreateWindow( p_event ) ) + p_event->b_error = true; + + p_event->b_ready = true; + vlc_cond_signal( &p_event->wait ); + + const bool b_error = p_event->b_error; + vlc_mutex_unlock( &p_event->lock ); + + if( b_error ) + { + vlc_restorecancel( canc ); + return NULL; + } + +#ifndef UNDER_CE + /* Set power management stuff */ + if( (hkernel32 = GetModuleHandle( _T("KERNEL32") ) ) ) + { + ULONG (WINAPI* OurSetThreadExecutionState)( ULONG ); + + OurSetThreadExecutionState = (ULONG (WINAPI*)( ULONG )) + GetProcAddress( hkernel32, _T("SetThreadExecutionState") ); + + if( OurSetThreadExecutionState ) + /* Prevent monitor from powering off */ + OurSetThreadExecutionState( ES_DISPLAY_REQUIRED | ES_CONTINUOUS ); + else + msg_Dbg( p_vout, "no support for SetThreadExecutionState()" ); + } +#endif + + /* Main loop */ + /* GetMessage will sleep if there's no message in the queue */ + for( ;; ) + { + if( !GetMessage( &msg, 0, 0, 0 ) ) + { + vlc_mutex_lock( &p_event->lock ); + p_event->b_done = true; + vlc_mutex_unlock( &p_event->lock ); + break; + } + + /* Check if we are asked to exit */ + vlc_mutex_lock( &p_event->lock ); + const bool b_done = p_event->b_done; + vlc_mutex_unlock( &p_event->lock ); + if( b_done ) + break; + + /* */ + switch( msg.message ) + { + + case WM_MOUSEMOVE: + vlc_mutex_lock( &p_event->lock ); + vout_PlacePicture( p_event->p_vout, + p_event->wnd_cfg.width, + p_event->wnd_cfg.height, + &i_x, &i_y, &i_width, &i_height ); + vlc_mutex_unlock( &p_event->lock ); + + if( msg.hwnd == p_event->hvideownd ) + { + /* Child window */ + i_x = i_y = 0; + } + + if( i_width && i_height ) + { + val.i_int = ( GET_X_LPARAM(msg.lParam) - i_x ) * + p_event->p_vout->fmt_in.i_visible_width / i_width + + p_event->p_vout->fmt_in.i_x_offset; + var_Set( p_event->p_vout, "mouse-x", val ); + val.i_int = ( GET_Y_LPARAM(msg.lParam) - i_y ) * + p_event->p_vout->fmt_in.i_visible_height / i_height + + p_event->p_vout->fmt_in.i_y_offset; + var_Set( p_event->p_vout, "mouse-y", val ); + + var_SetBool( p_event->p_vout, "mouse-moved", true ); + } + + case WM_NCMOUSEMOVE: + 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->i_lastmoved = mdate(); + + if( p_event->b_cursor_hidden ) + { + p_event->b_cursor_hidden = 0; + ShowCursor( TRUE ); + } + } + break; + + case WM_VLC_HIDE_MOUSE: + if( p_event->b_cursor_hidden ) break; + p_event->b_cursor_hidden = true; + GetCursorPos( &old_mouse_pos ); + ShowCursor( FALSE ); + break; + + case WM_VLC_SHOW_MOUSE: + if( !p_event->b_cursor_hidden ) break; + p_event->b_cursor_hidden = false; + GetCursorPos( &old_mouse_pos ); + ShowCursor( TRUE ); + break; + + case WM_LBUTTONDOWN: + var_Get( p_event->p_vout, "mouse-button-down", &val ); + val.i_int |= 1; + var_Set( p_event->p_vout, "mouse-button-down", val ); + DirectXPopupMenu( p_event, false ); + break; + + case WM_LBUTTONUP: + var_Get( p_event->p_vout, "mouse-button-down", &val ); + val.i_int &= ~1; + var_Set( p_event->p_vout, "mouse-button-down", val ); + + var_SetBool( p_event->p_vout, "mouse-clicked", true ); + break; + + case WM_LBUTTONDBLCLK: + vlc_mutex_lock( &p_event->lock ); + p_event->i_changes |= VOUT_FULLSCREEN_CHANGE; + vlc_mutex_unlock( &p_event->lock ); + break; + + case WM_MBUTTONDOWN: + var_Get( p_event->p_vout, "mouse-button-down", &val ); + val.i_int |= 2; + var_Set( p_event->p_vout, "mouse-button-down", val ); + DirectXPopupMenu( p_event, false ); + var_ToggleBool( p_event->p_vout->p_libvlc, "intf-show" ); + break; + + case WM_MBUTTONUP: + var_Get( p_event->p_vout, "mouse-button-down", &val ); + val.i_int &= ~2; + var_Set( p_event->p_vout, "mouse-button-down", val ); + break; + + case WM_RBUTTONDOWN: + var_Get( p_event->p_vout, "mouse-button-down", &val ); + val.i_int |= 4; + var_Set( p_event->p_vout, "mouse-button-down", val ); + DirectXPopupMenu( p_event, false ); + break; + + case WM_RBUTTONUP: + var_Get( p_event->p_vout, "mouse-button-down", &val ); + val.i_int &= ~4; + var_Set( p_event->p_vout, "mouse-button-down", val ); + DirectXPopupMenu( p_event, true ); + break; + + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + /* The key events are first processed here and not translated + * into WM_CHAR events because we need to know the status of the + * modifier keys. */ + val.i_int = DirectXConvertKey( msg.wParam ); + if( !val.i_int ) + { + /* This appears to be a "normal" (ascii) key */ + val.i_int = tolower( MapVirtualKey( msg.wParam, 2 ) ); + } + + if( val.i_int ) + { + if( GetKeyState(VK_CONTROL) & 0x8000 ) + { + val.i_int |= KEY_MODIFIER_CTRL; + } + if( GetKeyState(VK_SHIFT) & 0x8000 ) + { + val.i_int |= KEY_MODIFIER_SHIFT; + } + if( GetKeyState(VK_MENU) & 0x8000 ) + { + val.i_int |= KEY_MODIFIER_ALT; + } + + var_Set( p_vout->p_libvlc, "key-pressed", val ); + } + break; + + case WM_MOUSEWHEEL: + if( GET_WHEEL_DELTA_WPARAM( msg.wParam ) > 0 ) + { + val.i_int = KEY_MOUSEWHEELUP; + } + else + { + val.i_int = KEY_MOUSEWHEELDOWN; + } + if( val.i_int ) + { + if( GetKeyState(VK_CONTROL) & 0x8000 ) + { + val.i_int |= KEY_MODIFIER_CTRL; + } + if( GetKeyState(VK_SHIFT) & 0x8000 ) + { + val.i_int |= KEY_MODIFIER_SHIFT; + } + if( GetKeyState(VK_MENU) & 0x8000 ) + { + val.i_int |= KEY_MODIFIER_ALT; + } + + var_Set( p_vout->p_libvlc, "key-pressed", val ); + } + break; + + case WM_VLC_CHANGE_TEXT: + { + vlc_mutex_lock( &p_event->lock ); + wchar_t *pwz_title = NULL; + if( p_event->psz_title ) + { + const size_t i_length = strlen(p_event->psz_title); + pwz_title = malloc( 2 * (i_length + 1) ); + if( pwz_title ) + { + mbstowcs( pwz_title, p_event->psz_title, 2 * i_length ); + pwz_title[i_length] = 0; + } + } + vlc_mutex_unlock( &p_event->lock ); + + if( pwz_title ) + { + SetWindowText( p_event->hwnd, (LPCTSTR)pwz_title ); + if( p_event->hfswnd ) + SetWindowText( p_event->hfswnd, (LPCTSTR)pwz_title ); + free( pwz_title ); + } + break; + } + + default: + /* Messages we don't handle directly are dispatched to the + * window procedure */ + TranslateMessage(&msg); + DispatchMessage(&msg); + break; + + } /* End Switch */ + + } /* End Main loop */ + + /* Check for WM_QUIT if we created the window */ + if( !p_event->hparent && msg.message == WM_QUIT ) + { + msg_Warn( p_vout, "WM_QUIT... should not happen!!" ); + p_event->hwnd = NULL; /* Window already destroyed */ + } + + msg_Dbg( p_vout, "DirectXEventThread terminating" ); + + DirectXCloseWindow( p_event ); + vlc_restorecancel(canc); + return NULL; +} + + +/* following functions are local */ + +/***************************************************************************** + * DirectXCreateWindow: create a window for the video. + ***************************************************************************** + * Before creating a direct draw surface, we need to create a window in which + * the video will be displayed. This window will also allow us to capture the + * events. + *****************************************************************************/ +static int DirectXCreateWindow( event_thread_t *p_event ) +{ + vout_thread_t *p_vout = p_event->p_vout; + HINSTANCE hInstance; + HMENU hMenu; + RECT rect_window; + WNDCLASS wc; /* window class components */ + HICON vlc_icon; + char vlc_path[MAX_PATH+1]; + int i_style, i_stylex; + + msg_Dbg( p_vout, "DirectXCreateWindow" ); + + /* Get this module's instance */ + hInstance = GetModuleHandle(NULL); + + #ifdef MODULE_NAME_IS_direct3d + if( !p_event->use_desktop ) + { + #endif + /* If an external window was specified, we'll draw in it. */ + p_event->parent_window = vout_window_New( VLC_OBJECT(p_vout), NULL, &p_event->wnd_cfg ); + if( p_event->parent_window ) + p_event->hparent = p_event->parent_window->hwnd; + else + p_event->hparent = NULL; + #ifdef MODULE_NAME_IS_direct3d + } + else + { + /* Find Program Manager */ + HWND hwnd = FindWindow( _T("Progman"), NULL ); + if( hwnd ) hwnd = FindWindowEx( hwnd, NULL, _T("SHELLDLL_DefView"), NULL ); + if( hwnd ) hwnd = FindWindowEx( hwnd, NULL, _T("SysListView32"), NULL ); + if( !hwnd ) + msg_Err( p_vout, "Couldn't find desktop icon window. Desktop mode can't be established." ); + p_event->hparent = hwnd; + } + #endif + + /* Get the Icon from the main app */ + vlc_icon = NULL; +#ifndef UNDER_CE + if( GetModuleFileName( NULL, vlc_path, MAX_PATH ) ) + { + vlc_icon = ExtractIcon( hInstance, vlc_path, 0 ); + } +#endif + + /* Fill in the window class structure */ + wc.style = CS_OWNDC|CS_DBLCLKS; /* style: dbl click */ + wc.lpfnWndProc = (WNDPROC)DirectXEventProc; /* event handler */ + wc.cbClsExtra = 0; /* no extra class data */ + wc.cbWndExtra = 0; /* no extra window data */ + wc.hInstance = hInstance; /* instance */ + wc.hIcon = vlc_icon; /* load the vlc big icon */ + wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* default cursor */ + wc.hbrBackground = GetStockObject(BLACK_BRUSH); /* background color */ + wc.lpszMenuName = NULL; /* no menu */ + wc.lpszClassName = _T("VLC DirectX"); /* use a special class */ + + /* Register the window class */ + if( !RegisterClass(&wc) ) + { + WNDCLASS wndclass; + + if( vlc_icon ) DestroyIcon( vlc_icon ); + + /* Check why it failed. If it's because one already exists + * then fine, otherwise return with an error. */ + if( !GetClassInfo( hInstance, _T("VLC DirectX"), &wndclass ) ) + { + msg_Err( p_vout, "DirectXCreateWindow RegisterClass FAILED (err=%lu)", GetLastError() ); + return VLC_EGENERIC; + } + } + + /* Register the video sub-window class */ + wc.lpszClassName = _T("VLC DirectX video"); wc.hIcon = 0; + wc.hbrBackground = NULL; /* no background color */ + if( !RegisterClass(&wc) ) + { + WNDCLASS wndclass; + + /* Check why it failed. If it's because one already exists + * then fine, otherwise return with an error. */ + if( !GetClassInfo( hInstance, _T("VLC DirectX video"), &wndclass ) ) + { + msg_Err( p_vout, "DirectXCreateWindow RegisterClass FAILED (err=%lu)", GetLastError() ); + 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_event->wnd_cfg.width; + rect_window.bottom = rect_window.top + p_event->wnd_cfg.height; + + if( var_GetBool( p_vout, "video-deco" ) ) + { + /* Open with window decoration */ + AdjustWindowRect( &rect_window, WS_OVERLAPPEDWINDOW|WS_SIZEBOX, 0 ); + i_style = WS_OVERLAPPEDWINDOW|WS_SIZEBOX|WS_VISIBLE|WS_CLIPCHILDREN; + i_stylex = 0; + } + else + { + /* No window decoration */ + AdjustWindowRect( &rect_window, WS_POPUP, 0 ); + i_style = WS_POPUP|WS_VISIBLE|WS_CLIPCHILDREN; + i_stylex = 0; // WS_EX_TOOLWINDOW; Is TOOLWINDOW really needed ? + // It messes up the fullscreen window. + } + + if( p_event->hparent ) + { + i_style = WS_VISIBLE|WS_CLIPCHILDREN|WS_CHILD; + i_stylex = 0; + } + + p_event->i_window_style = i_style; + + /* Create the window */ + p_event->hwnd = + CreateWindowEx( WS_EX_NOPARENTNOTIFY | i_stylex, + _T("VLC DirectX"), /* name of window class */ + _T(VOUT_TITLE) _T(" (DirectX Output)"), /* window title */ + i_style, /* window style */ + (p_event->wnd_cfg.x < 0) ? CW_USEDEFAULT : + (UINT)p_event->wnd_cfg.x, /* default X coordinate */ + (p_event->wnd_cfg.y < 0) ? CW_USEDEFAULT : + (UINT)p_event->wnd_cfg.y, /* default Y coordinate */ + rect_window.right - rect_window.left, /* window width */ + rect_window.bottom - rect_window.top, /* window height */ + p_event->hparent, /* parent window */ + NULL, /* no menu in this window */ + hInstance, /* handle of this program instance */ + (LPVOID)p_event ); /* send p_vout to WM_CREATE */ + + if( !p_event->hwnd ) + { + msg_Warn( p_vout, "DirectXCreateWindow create window FAILED (err=%lu)", GetLastError() ); + return VLC_EGENERIC; + } + + if( p_event->hparent ) + { + LONG i_style; + + /* We don't want the window owner to overwrite our client area */ + i_style = GetWindowLong( p_event->hparent, GWL_STYLE ); + + if( !(i_style & WS_CLIPCHILDREN) ) + /* Hmmm, apparently this is a blocking call... */ + SetWindowLong( p_event->hparent, GWL_STYLE, + i_style | WS_CLIPCHILDREN ); + + /* Create our fullscreen window */ + p_event->hfswnd = + CreateWindowEx( WS_EX_APPWINDOW, _T("VLC DirectX"), + _T(VOUT_TITLE) _T(" (DirectX Output)"), + WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_SIZEBOX, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + NULL, NULL, hInstance, NULL ); + } + else + { + p_event->hfswnd = NULL; + } + + /* Append a "Always On Top" entry in the system menu */ + hMenu = GetSystemMenu( p_event->hwnd, FALSE ); + AppendMenu( hMenu, MF_SEPARATOR, 0, _T("") ); + AppendMenu( hMenu, MF_STRING | MF_UNCHECKED, + IDM_TOGGLE_ON_TOP, _T("Always on &Top") ); + + /* Create video sub-window. This sub window will always exactly match + * the size of the video, which allows us to use crazy overlay colorkeys + * without having them shown outside of the video area. */ + p_event->hvideownd = + CreateWindow( _T("VLC DirectX video"), _T(""), /* window class */ + WS_CHILD, /* window style, not visible initially */ + 0, 0, + p_vout->render.i_width, /* default width */ + p_vout->render.i_height, /* default height */ + p_event->hwnd, /* parent window */ + NULL, hInstance, + (LPVOID)p_event ); /* send p_vout to WM_CREATE */ + + if( !p_event->hvideownd ) + msg_Warn( p_vout, "can't create video sub-window" ); + else + msg_Dbg( p_vout, "created video sub-window" ); + + /* Now display the window */ + ShowWindow( p_event->hwnd, SW_SHOW ); + + return VLC_SUCCESS; +} + +/***************************************************************************** + * DirectXCloseWindow: close the window created by DirectXCreateWindow + ***************************************************************************** + * This function returns all resources allocated by DirectXCreateWindow. + *****************************************************************************/ +static void DirectXCloseWindow( event_thread_t *p_event ) +{ + vout_thread_t *p_vout = p_event->p_vout; + msg_Dbg( p_vout, "DirectXCloseWindow" ); + + DestroyWindow( p_event->hwnd ); + if( p_event->hfswnd ) DestroyWindow( p_event->hfswnd ); + + #ifdef MODULE_NAME_IS_direct3d + if( !p_event->use_desktop ) + #endif + vout_window_Delete( p_event->parent_window ); + p_event->hwnd = NULL; + + /* We don't unregister the Window Class because it could lead to race + * conditions and it will be done anyway by the system when the app will + * exit */ +} + +/***************************************************************************** + * DirectXEventProc: This is the window event processing function. + ***************************************************************************** + * On Windows, when you create a window you have to attach an event processing + * function to it. The aim of this function is to manage "Queued Messages" and + * "Nonqueued Messages". + * Queued Messages are those picked up and retransmitted by vout_Manage + * (using the GetMessage and DispatchMessage functions). + * Nonqueued Messages are those that Windows will send directly to this + * procedure (like WM_DESTROY, WM_WINDOWPOSCHANGED...) + *****************************************************************************/ +static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam ) +{ + event_thread_t *p_event; + + if( message == WM_CREATE ) + { + /* Store p_vout for future use */ + p_event = (event_thread_t *)((CREATESTRUCT *)lParam)->lpCreateParams; + SetWindowLongPtr( hwnd, GWLP_USERDATA, (LONG_PTR)p_event ); + return TRUE; + } + else + { + LONG_PTR p_user_data = GetWindowLongPtr( hwnd, GWLP_USERDATA ); + p_event = (event_thread_t *)p_user_data; + if( !p_event ) + { + /* 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); + } + } + vout_thread_t *p_vout = p_event->p_vout; + +#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( hwnd == p_event->hvideownd ) + { +#ifdef MODULE_NAME_IS_directx + vlc_mutex_lock( &p_event->lock ); + const bool use_overlay = p_event->use_overlay; + vlc_mutex_unlock( &p_event->lock ); +#endif + + switch( message ) + { +#ifdef MODULE_NAME_IS_directx + case WM_ERASEBKGND: + /* For overlay, we need to erase background */ + return !use_overlay ? 1 : DefWindowProc(hwnd, message, wParam, lParam); + case WM_PAINT: + /* + ** For overlay, DefWindowProc() will erase dirty regions + ** with colorkey. + ** For non-overlay, vout will paint the whole window at + ** regular interval, therefore dirty regions can be ignored + ** to minimize repaint. + */ + if( !use_overlay ) + { + ValidateRect(hwnd, NULL); + } + // fall through to default +#else + /* + ** For OpenGL and Direct3D, vout will update the whole + ** window at regular interval, therefore dirty region + ** can be ignored to minimize repaint. + */ + case WM_ERASEBKGND: + /* nothing to erase */ + return 1; + case WM_PAINT: + /* nothing to repaint */ + ValidateRect(hwnd, NULL); + // fall through +#endif + default: + return DefWindowProc(hwnd, message, wParam, lParam); + } + } + + switch( message ) + { + + case WM_WINDOWPOSCHANGED: + UpdateRects( p_vout, true ); + return 0; + + /* the user wants to close the window */ + case WM_CLOSE: + { + playlist_t * p_playlist = pl_Hold( p_vout ); + if( p_playlist ) + { + playlist_Stop( p_playlist ); + pl_Release( p_vout ); + } + return 0; + } + + /* the window has been closed so shut down everything now */ + case WM_DESTROY: + msg_Dbg( p_vout, "WinProc WM_DESTROY" ); + /* just destroy the window */ + PostQuitMessage( 0 ); + return 0; + + case WM_SYSCOMMAND: + switch (wParam) + { + case IDM_TOGGLE_ON_TOP: /* toggle the "on top" status */ + { + msg_Dbg( p_vout, "WinProc WM_SYSCOMMAND: IDM_TOGGLE_ON_TOP"); + + /* Change the current value */ + var_ToggleBool( p_vout, "video-on-top" ); + return 0; + } + } + break; + + case WM_PAINT: + case WM_NCPAINT: + case WM_ERASEBKGND: + return DefWindowProc(hwnd, message, wParam, lParam); + + case WM_KILLFOCUS: +#ifdef MODULE_NAME_IS_wingapi + GXSuspend(); +#endif +#ifdef UNDER_CE + if( hwnd == p_event->hfswnd ) + { + HWND htbar = FindWindow( _T("HHTaskbar"), NULL ); + ShowWindow( htbar, SW_SHOW ); + } + + if( !p_event->hparent || + hwnd == p_event->hfswnd ) + { + SHFullScreen( hwnd, SHFS_SHOWSIPBUTTON ); + } +#endif + return 0; + + case WM_SETFOCUS: +#ifdef MODULE_NAME_IS_wingapi + GXResume(); +#endif +#ifdef UNDER_CE + if( p_event->hparent && + hwnd != p_event->hfswnd && p_vout->b_fullscreen ) + { + vlc_mutex_lock( &p_event->lock ); + p_event->i_changes |= VOUT_FULLSCREEN_CHANGE; + vlc_mutex_unlock( &p_event->lock ); + } + + if( hwnd == p_event->hfswnd ) + { + HWND htbar = FindWindow( _T("HHTaskbar"), NULL ); + ShowWindow( htbar, SW_HIDE ); + } + + if( !p_event->hparent || + hwnd == p_event->hfswnd ) + { + SHFullScreen( hwnd, SHFS_HIDESIPBUTTON ); + } +#endif + return 0; + + default: + //msg_Dbg( p_vout, "WinProc WM Default %i", message ); + break; + } + + /* Let windows handle the message */ + return DefWindowProc(hwnd, message, wParam, lParam); +} + +static struct +{ + int i_dxkey; + int i_vlckey; + +} dxkeys_to_vlckeys[] = +{ + { VK_F1, KEY_F1 }, { VK_F2, KEY_F2 }, { VK_F3, KEY_F3 }, { VK_F4, KEY_F4 }, + { VK_F5, KEY_F5 }, { VK_F6, KEY_F6 }, { VK_F7, KEY_F7 }, { VK_F8, KEY_F8 }, + { VK_F9, KEY_F9 }, { VK_F10, KEY_F10 }, { VK_F11, KEY_F11 }, + { VK_F12, KEY_F12 }, + + { VK_RETURN, KEY_ENTER }, + { VK_SPACE, ' ' }, + { VK_ESCAPE, KEY_ESC }, + + { VK_LEFT, KEY_LEFT }, + { VK_RIGHT, KEY_RIGHT }, + { VK_UP, KEY_UP }, + { VK_DOWN, KEY_DOWN }, + + { VK_HOME, KEY_HOME }, + { VK_END, KEY_END }, + { VK_PRIOR, KEY_PAGEUP }, + { VK_NEXT, KEY_PAGEDOWN }, + + { VK_INSERT, KEY_INSERT }, + { VK_DELETE, KEY_DELETE }, + + { VK_CONTROL, 0 }, + { VK_SHIFT, 0 }, + { VK_MENU, 0 }, + + { VK_BROWSER_BACK, KEY_BROWSER_BACK }, + { VK_BROWSER_FORWARD, KEY_BROWSER_FORWARD }, + { VK_BROWSER_REFRESH, KEY_BROWSER_REFRESH }, + { VK_BROWSER_STOP, KEY_BROWSER_STOP }, + { VK_BROWSER_SEARCH, KEY_BROWSER_SEARCH }, + { VK_BROWSER_FAVORITES, KEY_BROWSER_FAVORITES }, + { VK_BROWSER_HOME, KEY_BROWSER_HOME }, + { VK_VOLUME_MUTE, KEY_VOLUME_MUTE }, + { VK_VOLUME_DOWN, KEY_VOLUME_DOWN }, + { VK_VOLUME_UP, KEY_VOLUME_UP }, + { VK_MEDIA_NEXT_TRACK, KEY_MEDIA_NEXT_TRACK }, + { VK_MEDIA_PREV_TRACK, KEY_MEDIA_PREV_TRACK }, + { VK_MEDIA_STOP, KEY_MEDIA_STOP }, + { VK_MEDIA_PLAY_PAUSE, KEY_MEDIA_PLAY_PAUSE }, + + { 0, 0 } +}; + +static int DirectXConvertKey( int i_key ) +{ + int i; + + for( i = 0; dxkeys_to_vlckeys[i].i_dxkey != 0; i++ ) + { + if( dxkeys_to_vlckeys[i].i_dxkey == i_key ) + { + return dxkeys_to_vlckeys[i].i_vlckey; + } + } + + return 0; +} + +void EventThreadMouseAutoHide( event_thread_t *p_event ) +{ + vout_thread_t *p_vout = p_event->p_vout; + + if( p_vout->b_fullscreen && + !p_event->b_cursor_hidden && + (mdate() - p_event->i_lastmoved) > p_event->i_mouse_hide_timeout ) + { + /* Hide the cursor only if it is inside our window */ + POINT point; + GetCursorPos( &point ); + + HWND hwnd = WindowFromPoint(point); + if( hwnd == p_event->hwnd || hwnd == p_event->hvideownd ) + { + PostMessage( p_event->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 ); + } + else + { + p_event->i_lastmoved = mdate(); + } + } +} +void EventThreadMouseShow( event_thread_t *p_event ) +{ + PostMessage( p_event->hwnd, WM_VLC_SHOW_MOUSE, 0, 0 ); +} +void EventThreadUpdateTitle( event_thread_t *p_event, const char *psz_fallback ) +{ + char *psz_title = var_GetNonEmptyString( p_event->p_vout, "video-title" ); + if( !psz_title ) + psz_title = strdup( psz_fallback ); + if( !psz_title ) + return; + + vlc_mutex_lock( &p_event->lock ); + free( p_event->psz_title ); + p_event->psz_title = psz_title; + vlc_mutex_unlock( &p_event->lock ); + + PostMessage( p_event->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 ); +} +unsigned EventThreadRetreiveChanges( event_thread_t *p_event ) +{ + vlc_mutex_lock( &p_event->lock ); + unsigned i_changes = p_event->i_changes; + p_event->i_changes = 0; + vlc_mutex_unlock( &p_event->lock ); + + return i_changes; +} +int EventThreadGetWindowStyle( event_thread_t *p_event ) +{ + /* No need to lock, it is serialized by EventThreadStart */ + return p_event->i_window_style; +} + +void EventThreadUpdateWindowPosition( event_thread_t *p_event, bool *pb_changed, + int x, int y, int w, int h ) +{ + vlc_mutex_lock( &p_event->lock ); + *pb_changed = x != p_event->wnd_cfg.x || + y != p_event->wnd_cfg.y || + w != p_event->wnd_cfg.width || + h != p_event->wnd_cfg.height; + + p_event->wnd_cfg.x = x; + p_event->wnd_cfg.y = y; + p_event->wnd_cfg.width = w; + p_event->wnd_cfg.height = h; + vlc_mutex_unlock( &p_event->lock ); +} + +void EventThreadUseOverlay( event_thread_t *p_event, bool b_used ) +{ + vlc_mutex_lock( &p_event->lock ); + p_event->use_overlay = b_used; + vlc_mutex_unlock( &p_event->lock ); +} + +event_thread_t *EventThreadCreate( vout_thread_t *p_vout, const vout_window_cfg_t *p_wnd_cfg ) +{ + /* 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" ); + event_thread_t *p_event = malloc( sizeof(*p_event) ); + if( !p_event ) + return NULL; + + p_event->p_vout = p_vout; + vlc_mutex_init( &p_event->lock ); + vlc_cond_init( &p_event->wait ); + + p_event->b_cursor_hidden = false; + p_event->i_lastmoved = mdate(); + p_event->i_mouse_hide_timeout = + var_GetInteger(p_vout, "mouse-hide-timeout") * 1000; + p_event->psz_title = NULL; + p_event->wnd_cfg = *p_wnd_cfg; + + return p_event; +} + +void EventThreadDestroy( event_thread_t *p_event ) +{ + free( p_event->psz_title ); + vlc_cond_destroy( &p_event->wait ); + vlc_mutex_destroy( &p_event->lock ); + free( p_event ); +} + +int EventThreadStart( event_thread_t *p_event, event_hwnd_t *p_hwnd, const event_cfg_t *p_cfg ) +{ + p_event->use_desktop = p_cfg->use_desktop; + p_event->use_overlay = p_cfg->use_overlay; + + p_event->i_changes = 0; + + p_event->b_ready = false; + p_event->b_done = false; + p_event->b_error = false; + + if( vlc_clone( &p_event->thread, EventThread, p_event, + VLC_THREAD_PRIORITY_LOW ) ) + { + msg_Err( p_event->p_vout, "cannot create Vout EventThread" ); + return VLC_EGENERIC; + } + + vlc_mutex_lock( &p_event->lock ); + while( !p_event->b_ready ) + vlc_cond_wait( &p_event->wait, &p_event->lock ); + const bool b_error = p_event->b_error; + vlc_mutex_unlock( &p_event->lock ); + + if( b_error ) + { + vlc_join( p_event->thread, NULL ); + p_event->b_ready = false; + return VLC_EGENERIC; + } + msg_Dbg( p_event->p_vout, "Vout EventThread running" ); + + if( !p_event->use_desktop ) + p_hwnd->parent_window = p_event->parent_window; + else + p_hwnd->parent_window = NULL; + p_hwnd->hparent = p_event->hparent; + p_hwnd->hwnd = p_event->hwnd; + p_hwnd->hvideownd = p_event->hvideownd; + p_hwnd->hfswnd = p_event->hfswnd; + return VLC_SUCCESS; +} + +void EventThreadStop( event_thread_t *p_event ) +{ + if( !p_event->b_ready ) + return; + + vlc_mutex_lock( &p_event->lock ); + p_event->b_done = true; + vlc_mutex_unlock( &p_event->lock ); + + /* we need to be sure Vout EventThread won't stay stuck in + * GetMessage, so we send a fake message */ + if( p_event->hwnd ) + PostMessage( p_event->hwnd, WM_NULL, 0, 0); + + vlc_join( p_event->thread, NULL ); + p_event->b_ready = false; +} + diff --git a/modules/video_output/msw/events_vo.h b/modules/video_output/msw/events_vo.h new file mode 100644 index 0000000000..4cc1d4ee18 --- /dev/null +++ b/modules/video_output/msw/events_vo.h @@ -0,0 +1,57 @@ +/***************************************************************************** + * event.h: Windows video output header file + ***************************************************************************** + * Copyright (C) 2001-2009 the VideoLAN team + * $Id$ + * + * Authors: Gildas Bazin + * Damien Fouilleul + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#include + +/** + * HWNDs manager. + */ +typedef struct event_thread_t event_thread_t; + +typedef struct { + bool use_desktop; /* direct3d */ + bool use_overlay; /* directx */ +} event_cfg_t; + +typedef struct { + vout_window_t *parent_window; + HWND hparent; + HWND hwnd; + HWND hvideownd; + HWND hfswnd; +} event_hwnd_t; + +event_thread_t *EventThreadCreate( vout_thread_t *, const vout_window_cfg_t * ); +void EventThreadDestroy( event_thread_t * ); +int EventThreadStart( event_thread_t *, event_hwnd_t *, const event_cfg_t * ); +void EventThreadStop( event_thread_t * ); + +void EventThreadMouseAutoHide( event_thread_t * ); +void EventThreadMouseShow( event_thread_t * ); +void EventThreadUpdateTitle( event_thread_t *, const char *psz_fallback ); +unsigned EventThreadRetreiveChanges( event_thread_t * ); +int EventThreadGetWindowStyle( event_thread_t * ); +void EventThreadUpdateWindowPosition( event_thread_t *, bool *pb_changed, + int x, int y, int w, int h ); +void EventThreadUseOverlay( event_thread_t *, bool b_used ); diff --git a/modules/video_output/msw/vout.h b/modules/video_output/msw/vout.h new file mode 100644 index 0000000000..da44a42cab --- /dev/null +++ b/modules/video_output/msw/vout.h @@ -0,0 +1,306 @@ +/***************************************************************************** + * vout.h: Windows video output header file + ***************************************************************************** + * Copyright (C) 2001-2009 the VideoLAN team + * $Id$ + * + * Authors: Gildas Bazin + * Damien Fouilleul + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +/***************************************************************************** + * event_thread_t: event thread + *****************************************************************************/ +#include "events_vo.h" + +#ifdef MODULE_NAME_IS_wingapi + typedef struct GXDisplayProperties { + DWORD cxWidth; + DWORD cyHeight; + long cbxPitch; + long cbyPitch; + long cBPP; + DWORD ffFormat; + } GXDisplayProperties; + + typedef struct GXScreenRect { + DWORD dwTop; + DWORD dwLeft; + DWORD dwWidth; + DWORD dwHeight; + } GXScreenRect; + +# define GX_FULLSCREEN 0x01 +# define GX_NORMALKEYS 0x02 +# define GX_LANDSCAPEKEYS 0x03 + +# ifndef kfLandscape +# define kfLandscape 0x8 +# define kfPalette 0x10 +# define kfDirect 0x20 +# define kfDirect555 0x40 +# define kfDirect565 0x80 +# define kfDirect888 0x100 +# define kfDirect444 0x200 +# define kfDirectInverted 0x400 +# endif + +#endif + +struct vout_window_t; + +/***************************************************************************** + * vout_sys_t: video output method descriptor + ***************************************************************************** + * This structure is part of the video output thread descriptor. + * It describes the module specific properties of an output thread. + *****************************************************************************/ +struct vout_sys_t +{ + HWND hwnd; /* Handle of the main window */ + HWND hvideownd; /* Handle of the video sub-window */ + struct vout_window_t *parent_window; /* Parent window VLC object */ + HWND hparent; /* Handle of the parent window */ + HWND hfswnd; /* Handle of the fullscreen window */ + + /* Multi-monitor support */ + HMONITOR hmonitor; /* handle of the current monitor */ + GUID *p_display_driver; + HMONITOR (WINAPI* MonitorFromWindow)( HWND, DWORD ); + BOOL (WINAPI* GetMonitorInfo)( HMONITOR, LPMONITORINFO ); + + /* size of the display */ + RECT rect_display; + int i_display_depth; + + /* size of the overall window (including black bands) */ + RECT rect_parent; + + volatile uint16_t i_changes; /* changes made to the video display */ + + /* Misc */ + bool b_on_top_change; + +#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; + RECT rect_dest; + RECT rect_dest_clipped; + + bool b_hw_yuv; /* Should we use hardware YUV->RGB conversions */ + + +#ifdef MODULE_NAME_IS_directx + /* Overlay alignment restrictions */ + int i_align_src_boundary; + int i_align_src_size; + int i_align_dest_boundary; + int i_align_dest_size; + + bool b_wallpaper; /* show as desktop wallpaper ? */ + + bool b_using_overlay; /* Are we using an overlay surface */ + bool b_use_sysmem; /* Should we use system memory for surfaces */ + bool b_3buf_overlay; /* Should we use triple buffered overlays */ + + /* DDraw capabilities */ + int b_caps_overlay_clipping; + + unsigned int i_rgb_colorkey; /* colorkey in RGB used by the overlay */ + unsigned int i_colorkey; /* colorkey used by the overlay */ + + COLORREF color_bkg; + COLORREF color_bkgtxt; + + LPDIRECTDRAW2 p_ddobject; /* DirectDraw object */ + LPDIRECTDRAWSURFACE2 p_display; /* Display device */ + LPDIRECTDRAWSURFACE2 p_current_surface; /* surface currently displayed */ + LPDIRECTDRAWCLIPPER p_clipper; /* clipper used for blitting */ + HINSTANCE hddraw_dll; /* handle of the opened ddraw dll */ + vlc_mutex_t lock; +#endif + +#ifdef MODULE_NAME_IS_glwin32 + HDC hGLDC; + HGLRC hGLRC; +#endif + +#ifdef MODULE_NAME_IS_direct3d + /* show video on desktop window ? */ + bool b_desktop; + + // core objects + HINSTANCE hd3d9_dll; /* handle of the opened d3d9 dll */ + LPDIRECT3D9 p_d3dobj; + LPDIRECT3DDEVICE9 p_d3ddev; + D3DPRESENT_PARAMETERS d3dpp; + // scene objects + LPDIRECT3DTEXTURE9 p_d3dtex; + 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; + /* 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; + + 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 + + event_thread_t *p_event; +}; + +#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 +#endif + +/***************************************************************************** + * Prototypes from directx.c + *****************************************************************************/ +int DirectDrawUpdateOverlay( vout_thread_t *p_vout ); + +/***************************************************************************** + * Prototypes from common.c + *****************************************************************************/ +int CommonInit( vout_thread_t * ); +void CommonClean( vout_thread_t * ); +void CommonManage( vout_thread_t * ); + +int Control( vout_thread_t *p_vout, int i_query, va_list args ); + +void UpdateRects ( vout_thread_t *p_vout, bool b_force ); +void Win32ToggleFullscreen ( vout_thread_t *p_vout ); +void ExitFullscreen( vout_thread_t *p_vout ); +#ifndef UNDER_CE +void DisableScreensaver ( vout_thread_t *p_vout ); +void RestoreScreensaver ( vout_thread_t *p_vout ); +#endif + +/***************************************************************************** + * Constants + *****************************************************************************/ +#define IDM_TOGGLE_ON_TOP WM_USER + 1 +#define DX_POSITION_CHANGE 0x1000 +#define DX_WALLPAPER_CHANGE 0x2000 +#define DX_DESKTOP_CHANGE 0x4000 + +/***************************************************************************** + * WinCE helpers + *****************************************************************************/ +#ifdef UNDER_CE + +#define AdjustWindowRect(a,b,c) AdjustWindowRectEx(a,b,c,0) + +#ifndef GCL_HBRBACKGROUND +# define GCL_HBRBACKGROUND (-10) +#endif + +//#define FindWindowEx(a,b,c,d) 0 + +#define GetWindowPlacement(a,b) +#define SetWindowPlacement(a,b) +/*typedef struct _WINDOWPLACEMENT { + UINT length; + UINT flags; + UINT showCmd; + POINT ptMinPosition; + POINT ptMaxPosition; + RECT rcNormalPosition; +} WINDOWPLACEMENT;*/ + +#ifndef WM_NCMOUSEMOVE +# define WM_NCMOUSEMOVE 160 +#endif +#ifndef CS_OWNDC +# define CS_OWNDC 32 +#endif +#ifndef SC_SCREENSAVE +# define SC_SCREENSAVE 0xF140 +#endif +#ifndef SC_MONITORPOWER +# define SC_MONITORPOWER 0xF170 +#endif +#ifndef WM_NCPAINT +# define WM_NCPAINT 133 +#endif +#ifndef WS_OVERLAPPEDWINDOW +# define WS_OVERLAPPEDWINDOW 0xcf0000 +#endif +#ifndef WS_EX_NOPARENTNOTIFY +# define WS_EX_NOPARENTNOTIFY 4 +#endif +#ifndef WS_EX_APPWINDOW +#define WS_EX_APPWINDOW 0x40000 +#endif + +//#define SetWindowLongPtr SetWindowLong +//#define GetWindowLongPtr GetWindowLong +//#define GWLP_USERDATA GWL_USERDATA + +#endif //UNDER_CE -- 2.39.5