home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 275 / DPCS0111DVD.ISO / Toolkit / Audio-Visual / VirtualDub / Source / VirtualDub-1.9.10-src.7z / src / Riza / source / display.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2009-09-24  |  35.8 KB  |  1,333 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    A/V interface library
  3. //    Copyright (C) 1998-2005 Avery Lee
  4. //
  5. //    This program is free software; you can redistribute it and/or modify
  6. //    it under the terms of the GNU General Public License as published by
  7. //    the Free Software Foundation; either version 2 of the License, or
  8. //    (at your option) any later version.
  9. //
  10. //    This program is distributed in the hope that it will be useful,
  11. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. //    GNU General Public License for more details.
  14. //
  15. //    You should have received a copy of the GNU General Public License
  16. //    along with this program; if not, write to the Free Software
  17. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19. #include <vector>
  20. #include <algorithm>
  21. #include <stddef.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <vd2/system/atomic.h>
  25. #include <vd2/system/thread.h>
  26. #include <vd2/system/vdalloc.h>
  27. #include <vd2/system/vdtypes.h>
  28. #include <vd2/system/VDString.h>
  29. #include <vd2/system/w32assist.h>
  30. #include <vd2/Kasumi/pixmap.h>
  31. #include <vd2/Kasumi/pixmaputils.h>
  32.  
  33. #include <vd2/Riza/display.h>
  34. #include "displaymgr.h"
  35. #include "displaydrv.h"
  36.  
  37. #define VDDEBUG_DISP (void)sizeof printf
  38. //#define VDDEBUG_DISP VDDEBUG
  39.  
  40. extern const char g_szVideoDisplayControlName[] = "phaeronVideoDisplay";
  41.  
  42. extern void VDMemcpyRect(void *dst, ptrdiff_t dststride, const void *src, ptrdiff_t srcstride, size_t w, size_t h);
  43.  
  44. extern IVDVideoDisplayMinidriver *VDCreateVideoDisplayMinidriverD3DFX(bool clipToMonitor);
  45.  
  46. vdautoptr<VDVideoDisplayManager> g_pVDVideoDisplayManager;
  47.  
  48. ///////////////////////////////////////////////////////////////////////////
  49.  
  50. namespace {
  51.     bool VDIsTerminalServicesClient() {
  52.         if ((sint32)(GetVersion() & 0x000000FF) >= 0x00000005) {
  53.             return GetSystemMetrics(SM_REMOTESESSION) != 0;        // Requires Windows NT SP4 or later.
  54.         }
  55.  
  56.         return false;    // Ignore Windows 95/98/98SE/ME/NT3/NT4.  (Broken on NT4 Terminal Server, but oh well.)
  57.     }
  58. }
  59.  
  60. ///////////////////////////////////////////////////////////////////////////
  61.  
  62. VDVideoDisplayFrame::VDVideoDisplayFrame()
  63.     : mRefCount(0)
  64. {
  65. }
  66.  
  67. VDVideoDisplayFrame::~VDVideoDisplayFrame() {
  68. }
  69.  
  70. int VDVideoDisplayFrame::AddRef() {
  71.     return ++mRefCount;
  72. }
  73.  
  74. int VDVideoDisplayFrame::Release() {
  75.     int rc = --mRefCount;
  76.  
  77.     if (!rc)
  78.         delete this;
  79.  
  80.     return rc;
  81. }
  82.  
  83. ///////////////////////////////////////////////////////////////////////////
  84.  
  85. class VDVideoDisplayWindow : public IVDVideoDisplay, public IVDVideoDisplayMinidriverCallback, public VDVideoDisplayClient {
  86. public:
  87.     static ATOM Register();
  88.  
  89. protected:
  90.     VDVideoDisplayWindow(HWND hwnd, const CREATESTRUCT& createInfo);
  91.     ~VDVideoDisplayWindow();
  92.  
  93.     void SetSourceMessage(const wchar_t *msg);
  94.     void SetSourcePalette(const uint32 *palette, int count);
  95.     bool SetSource(bool bAutoUpdate, const VDPixmap& src, void *pSharedObject, ptrdiff_t sharedOffset, bool bAllowConversion, bool bInterlaced);
  96.     bool SetSourcePersistent(bool bAutoUpdate, const VDPixmap& src, bool bAllowConversion, bool bInterlaced);
  97.     void SetSourceSubrect(const vdrect32 *r);
  98.     void SetSourceSolidColor(uint32 color);
  99.     void SetReturnFocus(bool fs);
  100.     void SetFullScreen(bool fs);
  101.     void PostBuffer(VDVideoDisplayFrame *);
  102.     bool RevokeBuffer(bool allowFrameSkip, VDVideoDisplayFrame **ppFrame);
  103.     void FlushBuffers();
  104.     void Update(int);
  105.     void Destroy();
  106.     void Reset();
  107.     void Cache();
  108.     void SetCallback(IVDVideoDisplayCallback *pcb);
  109.     void SetAccelerationMode(AccelerationMode mode);
  110.     FilterMode GetFilterMode();
  111.     void SetFilterMode(FilterMode mode);
  112.     float GetSyncDelta() const { return mSyncDelta; }
  113.  
  114.     void OnTick() {
  115.         if (mpMiniDriver)
  116.             mpMiniDriver->Poll();
  117.     }
  118.  
  119. protected:
  120.     void ReleaseActiveFrame();
  121.     void RequestNextFrame();
  122.     void DispatchNextFrame();
  123.     bool DispatchActiveFrame();
  124.  
  125. protected:
  126.     static LRESULT CALLBACK StaticChildWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  127.     LRESULT ChildWndProc(UINT msg, WPARAM wParam, LPARAM lParam);
  128.  
  129.     void OnChildPaint();
  130.  
  131.     static LRESULT CALLBACK StaticWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  132.     LRESULT WndProc(UINT msg, WPARAM wParam, LPARAM lParam);
  133.  
  134.     void OnPaint();
  135.     void SyncSetSourceMessage(const wchar_t *);
  136.     bool SyncSetSource(bool bAutoUpdate, const VDVideoDisplaySourceInfo& params);
  137.     void SyncReset();
  138.     bool SyncInit(bool bAutoRefresh, bool bAllowNonpersistentSource);
  139.     void SyncUpdate(int);
  140.     void SyncCache();
  141.     void SyncSetFilterMode(FilterMode mode);
  142.     void SyncSetSolidColor(uint32 color);
  143.     void OnDisplayChange();
  144.     void OnForegroundChange(bool bForeground);
  145.     void OnRealizePalette();
  146.     bool InitMiniDriver();
  147.     void ShutdownMiniDriver();
  148.     void RequestUpdate();
  149.     void VerifyDriverResult(bool result);
  150.     bool CheckForMonitorChange();
  151.     bool IsOnSecondaryMonitor() const;
  152.  
  153. protected:
  154.     enum {
  155.         kReinitDisplayTimerId = 500
  156.     };
  157.  
  158.     HWND        mhwnd;
  159.     HWND        mhwndChild;
  160.     HPALETTE    mhOldPalette;
  161.     HMONITOR    mhLastMonitor;
  162.     RECT        mLastMonitorCheckRect;
  163.  
  164.     VDCriticalSection            mMutex;
  165.     vdlist<VDVideoDisplayFrame>    mPendingFrames;
  166.     vdlist<VDVideoDisplayFrame>    mIdleFrames;
  167.     VDVideoDisplayFrame            *mpActiveFrame;
  168.     VDVideoDisplayFrame            *mpLastFrame;
  169.     VDVideoDisplaySourceInfo    mSource;
  170.  
  171.     IVDVideoDisplayMinidriver *mpMiniDriver;
  172.     bool    mbMiniDriverSecondarySensitive;
  173.     UINT    mReinitDisplayTimer;
  174.  
  175.     IVDVideoDisplayCallback        *mpCB;
  176.     int        mInhibitRefresh;
  177.  
  178.     VDAtomicFloat    mSyncDelta;
  179.  
  180.     FilterMode    mFilterMode;
  181.     AccelerationMode    mAccelMode;
  182.  
  183.     bool        mbIgnoreMouse;
  184.     bool        mbUseSubrect;
  185.     bool        mbReturnFocus;
  186.     bool        mbFullScreen;
  187.     vdrect32    mSourceSubrect;
  188.     VDStringW    mMessage;
  189.  
  190.     uint32                mSolidColorBuffer;
  191.  
  192.     VDPixmapBuffer        mCachedImage;
  193.  
  194.     uint32    mSourcePalette[256];
  195.  
  196.     static ATOM                sChildWindowClass;
  197.  
  198. public:
  199.     static bool        sbEnableDX;
  200.     static bool        sbEnableDXOverlay;
  201.     static bool        sbEnableD3D;
  202.     static bool        sbEnableD3DFX;
  203.     static bool        sbEnableOGL;
  204.     static bool        sbEnableTS;
  205.     static bool        sbEnableDebugInfo;
  206.     static bool        sbEnableHighPrecision;
  207.     static bool        sbEnableBackgroundFallback;
  208.     static bool        sbEnableSecondaryMonitorDX;
  209. };
  210.  
  211. ATOM                                    VDVideoDisplayWindow::sChildWindowClass;
  212. bool VDVideoDisplayWindow::sbEnableDX = true;
  213. bool VDVideoDisplayWindow::sbEnableDXOverlay = true;
  214. bool VDVideoDisplayWindow::sbEnableD3D;
  215. bool VDVideoDisplayWindow::sbEnableD3DFX;
  216. bool VDVideoDisplayWindow::sbEnableOGL;
  217. bool VDVideoDisplayWindow::sbEnableTS;
  218. bool VDVideoDisplayWindow::sbEnableDebugInfo;
  219. bool VDVideoDisplayWindow::sbEnableHighPrecision;
  220. bool VDVideoDisplayWindow::sbEnableBackgroundFallback;
  221. bool VDVideoDisplayWindow::sbEnableSecondaryMonitorDX;
  222.  
  223. ///////////////////////////////////////////////////////////////////////////
  224.  
  225. void VDVideoDisplaySetDebugInfoEnabled(bool enable) {
  226.     VDVideoDisplayWindow::sbEnableDebugInfo = enable;
  227. }
  228.  
  229. void VDVideoDisplaySetBackgroundFallbackEnabled(bool enable) {
  230.     VDVideoDisplayWindow::sbEnableBackgroundFallback = enable;
  231.  
  232.     if (g_pVDVideoDisplayManager)
  233.         g_pVDVideoDisplayManager->SetBackgroundFallbackEnabled(enable);
  234. }
  235.  
  236. void VDVideoDisplaySetSecondaryDXEnabled(bool enable) {
  237.     VDVideoDisplayWindow::sbEnableSecondaryMonitorDX = enable;
  238. }
  239.  
  240. void VDVideoDisplaySetFeatures(bool enableDirectX, bool enableDirectXOverlay, bool enableTermServ, bool enableOpenGL, bool enableDirect3D, bool enableDirect3DFX, bool enableHighPrecision) {
  241.     VDVideoDisplayWindow::sbEnableDX = enableDirectX;
  242.     VDVideoDisplayWindow::sbEnableDXOverlay = enableDirectXOverlay;
  243.     VDVideoDisplayWindow::sbEnableD3D = enableDirect3D;
  244.     VDVideoDisplayWindow::sbEnableD3DFX = enableDirect3DFX;
  245.     VDVideoDisplayWindow::sbEnableOGL = enableOpenGL;
  246.     VDVideoDisplayWindow::sbEnableTS = enableTermServ;
  247.     VDVideoDisplayWindow::sbEnableHighPrecision = enableHighPrecision;
  248. }
  249.  
  250. ///////////////////////////////////////////////////////////////////////////
  251.  
  252. ATOM VDVideoDisplayWindow::Register() {
  253.     WNDCLASS wc;
  254.     HMODULE hInst = VDGetLocalModuleHandleW32();
  255.  
  256.     if (!sChildWindowClass) {
  257.         wc.style            = CS_HREDRAW | CS_VREDRAW;
  258.         wc.lpfnWndProc        = StaticChildWndProc;
  259.         wc.cbClsExtra        = 0;
  260.         wc.cbWndExtra        = sizeof(VDVideoDisplayWindow *);
  261.         wc.hInstance        = hInst;
  262.         wc.hIcon            = 0;
  263.         wc.hCursor            = LoadCursor(NULL, IDC_ARROW);
  264.         wc.hbrBackground    = 0;
  265.         wc.lpszMenuName        = 0;
  266.         wc.lpszClassName    = "phaeronVideoDisplayChild";
  267.  
  268.         sChildWindowClass = RegisterClass(&wc);
  269.         if (!sChildWindowClass)
  270.             return NULL;
  271.     }
  272.  
  273.     wc.style            = CS_HREDRAW | CS_VREDRAW;
  274.     wc.lpfnWndProc        = StaticWndProc;
  275.     wc.cbClsExtra        = 0;
  276.     wc.cbWndExtra        = sizeof(VDVideoDisplayWindow *);
  277.     wc.hInstance        = hInst;
  278.     wc.hIcon            = 0;
  279.     wc.hCursor            = LoadCursor(NULL, IDC_ARROW);
  280.     wc.hbrBackground    = (HBRUSH)(COLOR_3DFACE + 1);
  281.     wc.lpszMenuName        = 0;
  282.     wc.lpszClassName    = g_szVideoDisplayControlName;
  283.  
  284.     return RegisterClass(&wc);
  285. }
  286.  
  287. IVDVideoDisplay *VDGetIVideoDisplay(VDGUIHandle hwnd) {
  288.     return static_cast<IVDVideoDisplay *>(reinterpret_cast<VDVideoDisplayWindow*>(GetWindowLongPtr((HWND)hwnd, 0)));
  289. }
  290.  
  291. bool VDRegisterVideoDisplayControl() {
  292.     return 0 != VDVideoDisplayWindow::Register();
  293. }
  294.  
  295. ///////////////////////////////////////////////////////////////////////////
  296.  
  297. VDVideoDisplayWindow::VDVideoDisplayWindow(HWND hwnd, const CREATESTRUCT& createInfo)
  298.     : mhwnd(hwnd)
  299.     , mhwndChild(NULL)
  300.     , mhLastMonitor(NULL)
  301.     , mhOldPalette(0)
  302.     , mpMiniDriver(0)
  303.     , mbMiniDriverSecondarySensitive(false)
  304.     , mReinitDisplayTimer(0)
  305.     , mpCB(0)
  306.     , mInhibitRefresh(0)
  307.     , mSyncDelta(0.0f)
  308.     , mFilterMode(kFilterAnySuitable)
  309.     , mAccelMode(VDVideoDisplayWindow::sbEnableBackgroundFallback ? kAccelOnlyInForeground : kAccelAlways)
  310.     , mbIgnoreMouse(false)
  311.     , mbUseSubrect(false)
  312.     , mbReturnFocus(false)
  313.     , mbFullScreen(false)
  314.     , mpActiveFrame(NULL)
  315.     , mpLastFrame(NULL)
  316. {
  317.     mSource.pixmap.data = 0;
  318.  
  319.     memset(&mLastMonitorCheckRect, 0, sizeof mLastMonitorCheckRect);
  320.  
  321.     if (createInfo.hwndParent) {
  322.         DWORD dwThreadId = GetWindowThreadProcessId(createInfo.hwndParent, NULL);
  323.         if (dwThreadId == GetCurrentThreadId())
  324.             mbIgnoreMouse = true;
  325.     }
  326.  
  327.     VDVideoDisplayManager *vdm = (VDVideoDisplayManager *)createInfo.lpCreateParams;
  328.     vdm->AddClient(this);
  329. }
  330.  
  331. VDVideoDisplayWindow::~VDVideoDisplayWindow() {
  332.     mpManager->RemoveClient(this);
  333. }
  334.  
  335. ///////////////////////////////////////////////////////////////////////////
  336.  
  337. #define MYWM_SETSOURCE        (WM_USER + 0x100)
  338. #define MYWM_UPDATE            (WM_USER + 0x101)
  339. #define MYWM_CACHE            (WM_USER + 0x102)
  340. #define MYWM_RESET            (WM_USER + 0x103)
  341. #define MYWM_SETSOURCEMSG    (WM_USER + 0x104)
  342. #define MYWM_PROCESSNEXTFRAME    (WM_USER+0x105)
  343. #define MYWM_DESTROY        (WM_USER + 0x106)
  344. #define MYWM_SETFILTERMODE    (WM_USER + 0x107)
  345. #define MYWM_SETSOLIDCOLOR    (WM_USER + 0x108)
  346.  
  347. void VDVideoDisplayWindow::SetSourceMessage(const wchar_t *msg) {
  348.     SendMessage(mhwnd, MYWM_SETSOURCEMSG, 0, (LPARAM)msg);
  349. }
  350.  
  351. void VDVideoDisplayWindow::SetSourcePalette(const uint32 *palette, int count) {
  352.     memcpy(mSourcePalette, palette, 4*std::min<int>(count, 256));
  353. }
  354.  
  355. bool VDVideoDisplayWindow::SetSource(bool bAutoUpdate, const VDPixmap& src, void *pObject, ptrdiff_t offset, bool bAllowConversion, bool bInterlaced) {
  356.     // We do allow data to be NULL for set-without-load.
  357.     if (src.data)
  358.         VDAssertValidPixmap(src);
  359.  
  360.     VDVideoDisplaySourceInfo params;
  361.  
  362.     params.pixmap            = src;
  363.     params.pSharedObject    = pObject;
  364.     params.sharedOffset        = offset;
  365.     params.bAllowConversion    = bAllowConversion;
  366.     params.bPersistent        = pObject != 0;
  367.     params.bInterlaced        = bInterlaced;
  368.  
  369.     const VDPixmapFormatInfo& info = VDPixmapGetInfo(src.format);
  370.     params.bpp = info.qsize >> info.qhbits;
  371.     params.bpr = (((src.w-1) >> info.qwbits)+1) * info.qsize;
  372.  
  373.     params.mpCB                = this;
  374.  
  375.     return 0 != SendMessage(mhwnd, MYWM_SETSOURCE, bAutoUpdate, (LPARAM)¶ms);
  376. }
  377.  
  378. bool VDVideoDisplayWindow::SetSourcePersistent(bool bAutoUpdate, const VDPixmap& src, bool bAllowConversion, bool bInterlaced) {
  379.     // We do allow data to be NULL for set-without-load.
  380.     if (src.data)
  381.         VDAssertValidPixmap(src);
  382.  
  383.     VDVideoDisplaySourceInfo params;
  384.  
  385.     params.pixmap            = src;
  386.     params.pSharedObject    = NULL;
  387.     params.sharedOffset        = 0;
  388.     params.bAllowConversion    = bAllowConversion;
  389.     params.bPersistent        = true;
  390.     params.bInterlaced        = bInterlaced;
  391.  
  392.     const VDPixmapFormatInfo& info = VDPixmapGetInfo(src.format);
  393.     params.bpp = info.qsize >> info.qhbits;
  394.     params.bpr = (((src.w-1) >> info.qwbits)+1) * info.qsize;
  395.     params.mpCB                = this;
  396.  
  397.     return 0 != SendMessage(mhwnd, MYWM_SETSOURCE, bAutoUpdate, (LPARAM)¶ms);
  398. }
  399.  
  400. void VDVideoDisplayWindow::SetSourceSubrect(const vdrect32 *r) {
  401.     if (r) {
  402.         mbUseSubrect = true;
  403.         mSourceSubrect = *r;
  404.     } else
  405.         mbUseSubrect = false;
  406.  
  407.     if (mpMiniDriver) {
  408.         if (!mpMiniDriver->SetSubrect(r))
  409.             SyncReset();
  410.     }
  411. }
  412.  
  413. void VDVideoDisplayWindow::SetSourceSolidColor(uint32 color) {
  414.     SendMessage(mhwnd, MYWM_SETSOLIDCOLOR, 0, (LPARAM)color);
  415. }
  416.  
  417. void VDVideoDisplayWindow::SetReturnFocus(bool enable) {
  418.     mbReturnFocus = enable;
  419. }
  420.  
  421. void VDVideoDisplayWindow::SetFullScreen(bool fs) {
  422.     mbFullScreen = fs;
  423.     if (mpMiniDriver)
  424.         mpMiniDriver->SetFullScreen(fs);
  425.     SetRequiresFullScreen(fs);
  426. }
  427.  
  428. void VDVideoDisplayWindow::PostBuffer(VDVideoDisplayFrame *p) {
  429.     p->AddRef();
  430.  
  431.     VDASSERT(p->mFlags & IVDVideoDisplay::kAllFields);
  432.  
  433.     bool wasIdle = false;
  434.     vdsynchronized(mMutex) {
  435.         if (!mpMiniDriver || !mpActiveFrame && mPendingFrames.empty())
  436.             wasIdle = true;
  437.  
  438.         mPendingFrames.push_back(p);
  439.     }
  440.  
  441.     if (wasIdle)
  442.         PostMessage(mhwnd, MYWM_PROCESSNEXTFRAME, 0, 0);
  443. }
  444.  
  445. bool VDVideoDisplayWindow::RevokeBuffer(bool allowFrameSkip, VDVideoDisplayFrame **ppFrame) {
  446.     VDVideoDisplayFrame *p = NULL;
  447.     vdsynchronized(mMutex) {
  448.         if (allowFrameSkip && (!mPendingFrames.empty() && mPendingFrames.front() != mPendingFrames.back())) {
  449.             p = mPendingFrames.back();
  450.             mPendingFrames.pop_back();
  451.         } else if (!mIdleFrames.empty()) {
  452.             p = mIdleFrames.front();
  453.             mIdleFrames.pop_front();
  454.         }
  455.     }
  456.  
  457.     if (!p)
  458.         return false;
  459.  
  460.     *ppFrame = p;
  461.     return true;
  462. }
  463.  
  464. void VDVideoDisplayWindow::FlushBuffers() {
  465.     vdlist<VDVideoDisplayFrame> frames;
  466.     if (mpLastFrame) {
  467.         frames.push_back(mpLastFrame);
  468.         mpLastFrame = NULL;
  469.     }
  470.  
  471.     // wait for any current frame to clear
  472.     for(;;) {
  473.         bool idle;
  474.         vdsynchronized(mMutex) {
  475.             // clear existing pending frames so the display doesn't start another render
  476.             if (!mPendingFrames.empty())
  477.                 frames.splice(frames.end(), mIdleFrames);
  478.  
  479.             idle = !mpActiveFrame;
  480.         }
  481.  
  482.         if (idle)
  483.             break;
  484.  
  485.         ::Sleep(1);
  486.         OnTick();
  487.     }
  488.  
  489.     vdsynchronized(mMutex) {
  490.         frames.splice(frames.end(), mIdleFrames);
  491.         frames.splice(frames.end(), mPendingFrames);
  492.     }
  493.  
  494.     while(!frames.empty()) {
  495.         VDVideoDisplayFrame *p = frames.back();
  496.         frames.pop_back();
  497.  
  498.         p->Release();
  499.     }
  500. }
  501.  
  502. void VDVideoDisplayWindow::Update(int fieldmode) {
  503.     SendMessage(mhwnd, MYWM_UPDATE, fieldmode, 0);
  504. }
  505.  
  506. void VDVideoDisplayWindow::Cache() {
  507.     SendMessage(mhwnd, MYWM_CACHE, 0, 0);
  508. }
  509.  
  510. void VDVideoDisplayWindow::Destroy() {
  511.     SendMessage(mhwnd, MYWM_DESTROY, 0, 0);
  512. }
  513.  
  514. void VDVideoDisplayWindow::Reset() {
  515.     SendMessage(mhwnd, MYWM_RESET, 0, 0);
  516. }
  517.  
  518. void VDVideoDisplayWindow::SetCallback(IVDVideoDisplayCallback *pCB) {
  519.     mpCB = pCB;
  520. }
  521.  
  522. void VDVideoDisplayWindow::SetAccelerationMode(AccelerationMode mode) {
  523.     mAccelMode = mode;
  524. }
  525.  
  526. IVDVideoDisplay::FilterMode VDVideoDisplayWindow::GetFilterMode() {
  527.     return mFilterMode;
  528. }
  529.  
  530. void VDVideoDisplayWindow::SetFilterMode(FilterMode mode) {
  531.     SendMessage(mhwnd, MYWM_SETFILTERMODE, 0, (LPARAM)mode);
  532. }
  533.  
  534. void VDVideoDisplayWindow::ReleaseActiveFrame() {
  535.     VDVideoDisplayFrame *pFrameToDiscard = NULL;
  536.     VDVideoDisplayFrame *pFrameToDiscard2 = NULL;
  537.  
  538.     vdsynchronized(mMutex) {
  539.         if (mpActiveFrame) {
  540.             if (mpLastFrame) {
  541.                 if (mpLastFrame->mFlags & kDoNotCache)
  542.                     pFrameToDiscard = mpLastFrame;
  543.                 else
  544.                     mIdleFrames.push_front(mpLastFrame);
  545.                 mpLastFrame = NULL;
  546.             }
  547.  
  548.             if (mpActiveFrame->mFlags & kAutoFlipFields) {
  549.                 if (mpActiveFrame->mFlags & (kBobEven | kBobOdd))
  550.                     mpActiveFrame->mFlags ^= kBobEven | kBobOdd;
  551.                 else
  552.                     mpActiveFrame->mFlags ^= kEvenFieldOnly | kOddFieldOnly;
  553.  
  554.                 mpActiveFrame->mFlags &= ~(kAutoFlipFields | kFirstField);
  555.                 mPendingFrames.push_front(mpActiveFrame);
  556.             } else if (mpActiveFrame->mFlags & kDoNotCache) {
  557.                 pFrameToDiscard2 = mpActiveFrame;
  558.             } else {
  559.                 mpLastFrame = mpActiveFrame;
  560.             }
  561.  
  562.             mpActiveFrame = NULL;
  563.         }
  564.     }
  565.  
  566.     if (pFrameToDiscard)
  567.         pFrameToDiscard->Release();
  568.  
  569.     if (pFrameToDiscard2)
  570.         pFrameToDiscard2->Release();
  571. }
  572.  
  573. void VDVideoDisplayWindow::RequestNextFrame() {
  574.     PostMessage(mhwnd, MYWM_PROCESSNEXTFRAME, 0, 0);
  575. }
  576.  
  577. void VDVideoDisplayWindow::DispatchNextFrame() {
  578.     vdsynchronized(mMutex) {
  579.         VDASSERT(!mpActiveFrame);
  580.         if (!mPendingFrames.empty()) {
  581.             mpActiveFrame = mPendingFrames.front();
  582.             mPendingFrames.pop_front();
  583.         }
  584.     }
  585.  
  586.     DispatchActiveFrame();
  587. }
  588.  
  589. bool VDVideoDisplayWindow::DispatchActiveFrame() {
  590.     if (mpActiveFrame) {
  591.         VDVideoDisplaySourceInfo params;
  592.  
  593.         params.pixmap            = mpActiveFrame->mPixmap;
  594.  
  595.         uint32 flags = mpActiveFrame->mFlags;
  596.         bool interlaced = mpActiveFrame->mbInterlaced;
  597.  
  598.         if (flags & kBobEven) {
  599.             params.pixmap = VDPixmapExtractField(params.pixmap, false);
  600.             interlaced = false;
  601.         } else if (flags & kBobOdd) {
  602.             params.pixmap = VDPixmapExtractField(params.pixmap, true);
  603.             interlaced = false;
  604.         } else if (flags & kSequentialFields) {
  605.             params.pixmap = VDPixmapExtractField(params.pixmap, (flags & kOddFieldOnly) != 0);
  606.             flags &= ~(kSequentialFields | kEvenFieldOnly | kOddFieldOnly);
  607.             interlaced = false;
  608.         }
  609.  
  610.         params.pSharedObject    = NULL;
  611.         params.sharedOffset        = 0;
  612.         params.bAllowConversion    = mpActiveFrame->mbAllowConversion;
  613.         params.bPersistent        = false;
  614.         params.bInterlaced        = interlaced;
  615.  
  616.         const VDPixmapFormatInfo& info = VDPixmapGetInfo(mpActiveFrame->mPixmap.format);
  617.         params.bpp = info.qsize >> info.qhbits;
  618.         params.bpr = (((mpActiveFrame->mPixmap.w-1) >> info.qwbits)+1) * info.qsize;
  619.  
  620.         params.mpCB                = this;
  621.  
  622.         if (!SyncSetSource(false, params)) {
  623.             ReleaseActiveFrame();
  624.             return false;
  625.         }
  626.  
  627.         SyncUpdate(flags);
  628.         return true;
  629.     }
  630.  
  631.     return false;
  632. }
  633.  
  634. ///////////////////////////////////////////////////////////////////////////
  635.  
  636. LRESULT CALLBACK VDVideoDisplayWindow::StaticChildWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
  637.     VDVideoDisplayWindow *pThis = (VDVideoDisplayWindow *)GetWindowLongPtr(hwnd, 0);
  638.  
  639.     switch(msg) {
  640.     case WM_NCCREATE:
  641.         pThis = (VDVideoDisplayWindow *)(((LPCREATESTRUCT)lParam)->lpCreateParams);
  642.         pThis->mhwndChild = hwnd;
  643.         SetWindowLongPtr(hwnd, 0, (DWORD_PTR)pThis);
  644.         break;
  645.     case WM_NCDESTROY:
  646.         SetWindowLongPtr(hwnd, 0, (DWORD_PTR)NULL);
  647.         break;
  648.     }
  649.  
  650.     return pThis ? pThis->ChildWndProc(msg, wParam, lParam) : DefWindowProc(hwnd, msg, wParam, lParam);
  651. }
  652.  
  653. LRESULT VDVideoDisplayWindow::ChildWndProc(UINT msg, WPARAM wParam, LPARAM lParam) {
  654.     switch(msg) {
  655.     case WM_PAINT:
  656.         OnChildPaint();
  657.         return 0;
  658.     case WM_NCHITTEST:
  659.         if (mbIgnoreMouse)
  660.             return HTTRANSPARENT;
  661.         break;
  662.     case WM_ERASEBKGND:
  663.         return FALSE;
  664.  
  665.     case WM_SETFOCUS:
  666.         if (mbReturnFocus) {
  667.             HWND hwndParent = GetParent(mhwnd);
  668.             if (hwndParent)
  669.                 SetFocus(GetParent(mhwnd));
  670.         }
  671.         break;
  672.  
  673.     case WM_TIMER:
  674.         if (mpMiniDriver)
  675.             VerifyDriverResult(mpMiniDriver->Tick((int)wParam));
  676.         break;
  677.     }
  678.  
  679.     return DefWindowProc(mhwndChild, msg, wParam, lParam);
  680. }
  681.  
  682. void VDVideoDisplayWindow::OnChildPaint() {
  683.     ++mInhibitRefresh;
  684.  
  685.     bool bDisplayOK = false;
  686.  
  687.     if (mpMiniDriver) {
  688.         if (mpMiniDriver->IsValid())
  689.             bDisplayOK = true;
  690.         else if (mSource.pixmap.data && mSource.bPersistent && !mpMiniDriver->Update(IVDVideoDisplayMinidriver::kModeAllFields))
  691.             bDisplayOK = true;
  692.     }
  693.  
  694.     if (!bDisplayOK) {
  695.         PAINTSTRUCT ps;
  696.         BeginPaint(mhwndChild, &ps);
  697.         EndPaint(mhwndChild, &ps);
  698.  
  699.         --mInhibitRefresh;
  700.         RequestUpdate();
  701.         return;
  702.     }
  703.  
  704.     VDASSERT(IsWindow(mhwndChild));
  705.  
  706.     PAINTSTRUCT ps;
  707.     HDC hdc = BeginPaint(mhwndChild, &ps);
  708.  
  709.     if (hdc) {
  710.         RECT r;
  711.  
  712.         GetClientRect(mhwndChild, &r);
  713.  
  714.         if (mpMiniDriver && mpMiniDriver->IsValid())
  715.             VerifyDriverResult(mpMiniDriver->Paint(hdc, r, IVDVideoDisplayMinidriver::kModeAllFields));
  716.  
  717.         EndPaint(mhwndChild, &ps);
  718.     }
  719.  
  720.  
  721.     --mInhibitRefresh;
  722. }
  723.  
  724. ///////////////////////////////////////////////////////////////////////////
  725.  
  726. LRESULT CALLBACK VDVideoDisplayWindow::StaticWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
  727.     VDVideoDisplayWindow *pThis = (VDVideoDisplayWindow *)GetWindowLongPtr(hwnd, 0);
  728.  
  729.     switch(msg) {
  730.     case WM_NCCREATE:
  731.         pThis = new VDVideoDisplayWindow(hwnd, *(const CREATESTRUCT *)lParam);
  732.         SetWindowLongPtr(hwnd, 0, (DWORD_PTR)pThis);
  733.         break;
  734.     case WM_NCDESTROY:
  735.         if (pThis)
  736.             pThis->SyncReset();
  737.         delete pThis;
  738.         pThis = NULL;
  739.         SetWindowLongPtr(hwnd, 0, 0);
  740.         break;
  741.     }
  742.  
  743.     return pThis ? pThis->WndProc(msg, wParam, lParam) : DefWindowProc(hwnd, msg, wParam, lParam);
  744. }
  745.  
  746. LRESULT VDVideoDisplayWindow::WndProc(UINT msg, WPARAM wParam, LPARAM lParam) {
  747.     switch(msg) {
  748.     case WM_DESTROY:
  749.         SyncReset();
  750.         ReleaseActiveFrame();
  751.         FlushBuffers();
  752.  
  753.         if (mReinitDisplayTimer) {
  754.             KillTimer(mhwnd, mReinitDisplayTimer);
  755.             mReinitDisplayTimer = 0;
  756.         }
  757.  
  758.         if (mhOldPalette) {
  759.             DeleteObject(mhOldPalette);
  760.             mhOldPalette = 0;
  761.         }
  762.  
  763.         break;
  764.     case WM_PAINT:
  765.         OnPaint();
  766.         return 0;
  767.     case MYWM_SETSOURCE:
  768.         ReleaseActiveFrame();
  769.         FlushBuffers();
  770.         return SyncSetSource(wParam != 0, *(const VDVideoDisplaySourceInfo *)lParam);
  771.     case MYWM_UPDATE:
  772.         SyncUpdate((FieldMode)wParam);
  773.         return 0;
  774.     case MYWM_DESTROY:
  775.         SyncReset();
  776.         DestroyWindow(mhwnd);
  777.         return 0;
  778.     case MYWM_RESET:
  779.         mMessage.clear();
  780.         InvalidateRect(mhwnd, NULL, TRUE);
  781.         SyncReset();
  782.         mSource.pixmap.data = NULL;
  783.         return 0;
  784.     case MYWM_SETSOURCEMSG:
  785.         SyncSetSourceMessage((const wchar_t *)lParam);
  786.         return 0;
  787.     case MYWM_PROCESSNEXTFRAME:
  788.         if (!mpMiniDriver || !mpMiniDriver->IsFramePending()) {
  789.             bool newframe;
  790.             vdsynchronized(mMutex) {
  791.                 newframe = !mpActiveFrame;
  792.             }
  793.  
  794.             if (newframe)
  795.                 DispatchNextFrame();
  796.         }
  797.         return 0;
  798.     case MYWM_SETFILTERMODE:
  799.         SyncSetFilterMode((FilterMode)lParam);
  800.         return 0;
  801.     case MYWM_SETSOLIDCOLOR:
  802.         SyncSetSolidColor((uint32)lParam);
  803.         return 0;
  804.     case WM_SIZE:
  805.         if (mhwndChild)
  806.             SetWindowPos(mhwndChild, NULL, 0, 0, LOWORD(lParam), HIWORD(lParam), SWP_NOMOVE|SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOACTIVATE);
  807.         if (mpMiniDriver)
  808.             VerifyDriverResult(mpMiniDriver->Resize());
  809.         break;
  810.     case WM_TIMER:
  811.         if (wParam == mReinitDisplayTimer) {
  812.             SyncInit(true, false);
  813.             return 0;
  814.         }
  815.         break;
  816.     case WM_NCHITTEST:
  817.         if (mbIgnoreMouse) {
  818.             LRESULT lr = DefWindowProc(mhwnd, msg, wParam, lParam);
  819.  
  820.             if (lr != HTCLIENT)
  821.                 return lr;
  822.             return HTTRANSPARENT;
  823.         }
  824.         break;
  825.     case WM_SETFOCUS:
  826.         if (mbReturnFocus) {
  827.             HWND hwndParent = GetParent(mhwnd);
  828.             if (hwndParent)
  829.                 SetFocus(GetParent(mhwnd));
  830.         }
  831.         break;
  832.     }
  833.  
  834.     return DefWindowProc(mhwnd, msg, wParam, lParam);
  835. }
  836.  
  837. void VDVideoDisplayWindow::OnPaint() {
  838.  
  839.     ++mInhibitRefresh;
  840.     bool bDisplayOK = false;
  841.  
  842.     if (mpMiniDriver) {
  843.         if (mpMiniDriver->IsValid())
  844.             bDisplayOK = true;
  845.         else if (mSource.pixmap.data && mSource.bPersistent && !mpMiniDriver->Update(IVDVideoDisplayMinidriver::kModeAllFields))
  846.             bDisplayOK = true;
  847.     }
  848.  
  849.     if (!bDisplayOK) {
  850.         --mInhibitRefresh;
  851.         RequestUpdate();
  852.         ++mInhibitRefresh;
  853.     }
  854.  
  855.     PAINTSTRUCT ps;
  856.     HDC hdc = BeginPaint(mhwnd, &ps);
  857.  
  858.     if (hdc) {
  859.         RECT r;
  860.  
  861.         GetClientRect(mhwnd, &r);
  862.  
  863.         FillRect(hdc, &r, (HBRUSH)(COLOR_3DFACE + 1));
  864.         if (!mMessage.empty()) {
  865.             HGDIOBJ hgo = SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
  866.             SetBkMode(hdc, TRANSPARENT);
  867.             VDDrawTextW32(hdc, mMessage.data(), mMessage.size(), &r, DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_WORDBREAK);
  868.             SelectObject(hdc, hgo);
  869.         }
  870.  
  871.         EndPaint(mhwnd, &ps);
  872.     }
  873.  
  874.     --mInhibitRefresh;
  875. }
  876.  
  877. bool VDVideoDisplayWindow::SyncSetSource(bool bAutoUpdate, const VDVideoDisplaySourceInfo& params) {
  878.     mCachedImage.clear();
  879.  
  880.     mSource = params;
  881.     mMessage.clear();
  882.  
  883.     if (mpMiniDriver) {
  884.         // Check if a monitor change has occurred (and we care).
  885.         if (sbEnableSecondaryMonitorDX || !CheckForMonitorChange()) {
  886.             // Check if the driver sensitive to secondary monitors and if we're now on the secondary
  887.             // monitor.
  888.             if (!mbMiniDriverSecondarySensitive || !IsOnSecondaryMonitor()) {
  889.                 // Check if the driver can adapt to the current format.
  890.                 if (mpMiniDriver->ModifySource(mSource)) {
  891.                     mpMiniDriver->SetColorOverride(0);
  892.  
  893.                     mSource.bAllowConversion = true;
  894.  
  895.                     if (bAutoUpdate)
  896.                         SyncUpdate(kAllFields);
  897.                     return true;
  898.                 }
  899.             }
  900.         }
  901.     }
  902.  
  903.     SyncReset();
  904.     if (!SyncInit(bAutoUpdate, true))
  905.         return false;
  906.  
  907.     mSource.bAllowConversion = true;
  908.     return true;
  909. }
  910.  
  911. void VDVideoDisplayWindow::SyncReset() {
  912.     if (mpMiniDriver) {
  913.         ShutdownMiniDriver();
  914.         VDASSERT(!mpMiniDriver);
  915.  
  916.         SetPreciseMode(false);
  917.         SetTicksEnabled(false);
  918.     }
  919. }
  920.  
  921. void VDVideoDisplayWindow::SyncSetSourceMessage(const wchar_t *msg) {
  922.     if (!mpMiniDriver && mMessage == msg)
  923.         return;
  924.  
  925.     SyncReset();
  926.     ReleaseActiveFrame();
  927.     FlushBuffers();
  928.     mSource.pixmap.format = 0;
  929.     mMessage = msg;
  930.     InvalidateRect(mhwnd, NULL, TRUE);
  931. }
  932.  
  933. bool VDVideoDisplayWindow::SyncInit(bool bAutoRefresh, bool bAllowNonpersistentSource) {
  934.     if (!mSource.pixmap.data || !mSource.pixmap.format)
  935.         return true;
  936.  
  937.     VDASSERT(!mpMiniDriver);
  938.     mbMiniDriverSecondarySensitive = false;
  939.  
  940.     bool bIsForeground = VDIsForegroundTaskW32();
  941.  
  942.     do {
  943.         if (sbEnableTS || !VDIsTerminalServicesClient()) {
  944.             if (mAccelMode != kAccelOnlyInForeground || !mSource.bAllowConversion || bIsForeground) {
  945.                 // The 3D drivers don't currently support subrects.
  946.                 if (sbEnableDX) {
  947.                     if (!mbUseSubrect && sbEnableOGL) {
  948.                         mpMiniDriver = VDCreateVideoDisplayMinidriverOpenGL();
  949.                         if (InitMiniDriver())
  950.                             break;
  951.                         SyncReset();
  952.                     }
  953.  
  954.                     if (sbEnableSecondaryMonitorDX || !(CheckForMonitorChange(), IsOnSecondaryMonitor())) {
  955.                         if (!mbUseSubrect && sbEnableD3D) {
  956.                             if (sbEnableD3DFX)
  957.                                 mpMiniDriver = VDCreateVideoDisplayMinidriverD3DFX(!sbEnableSecondaryMonitorDX);
  958.                             else
  959.                                 mpMiniDriver = VDCreateVideoDisplayMinidriverDX9(!sbEnableSecondaryMonitorDX);
  960.  
  961.                             if (InitMiniDriver()) {
  962.                                 mbMiniDriverSecondarySensitive = !sbEnableSecondaryMonitorDX;
  963.                                 break;
  964.                             }
  965.  
  966.                             SyncReset();
  967.                         }
  968.  
  969.                         mpMiniDriver = VDCreateVideoDisplayMinidriverDirectDraw(sbEnableDXOverlay, sbEnableSecondaryMonitorDX);
  970.                         if (InitMiniDriver()) {
  971.                             mbMiniDriverSecondarySensitive = !sbEnableSecondaryMonitorDX;
  972.                             break;
  973.                         }
  974.                         SyncReset();
  975.                     }
  976.                 }
  977.  
  978.             } else {
  979.                 VDDEBUG_DISP("VideoDisplay: Application in background -- disabling accelerated preview.\n");
  980.             }
  981.         }
  982.  
  983.         mpMiniDriver = VDCreateVideoDisplayMinidriverGDI();
  984.         if (InitMiniDriver())
  985.             break;
  986.  
  987.         VDDEBUG_DISP("VideoDisplay: No driver was able to handle the requested format! (%d)\n", mSource.pixmap.format);
  988.         SyncReset();
  989.     } while(false);
  990.  
  991.     if (mpMiniDriver) {
  992.         mpMiniDriver->SetLogicalPalette(GetLogicalPalette());
  993.  
  994.         if (mReinitDisplayTimer)
  995.             KillTimer(mhwnd, mReinitDisplayTimer);
  996.  
  997.         if (bAutoRefresh) {
  998.             if (bAllowNonpersistentSource)
  999.                 SyncUpdate(kAllFields);
  1000.             else
  1001.                 RequestUpdate();
  1002.         }
  1003.     }
  1004.  
  1005.     return mpMiniDriver != 0;
  1006. }
  1007.  
  1008. void VDVideoDisplayWindow::SyncUpdate(int mode) {
  1009.     if (mSource.pixmap.data && !mpMiniDriver) {
  1010.         mSyncDelta = 0.0f;
  1011.         SyncInit(true, true);
  1012.         return;
  1013.     }
  1014.  
  1015.     if (mpMiniDriver) {
  1016.         bool vsync = 0 != (mode & kVSync);
  1017.         SetPreciseMode(vsync);
  1018.         SetTicksEnabled(vsync);
  1019.  
  1020.         mpMiniDriver->SetColorOverride(0);
  1021.  
  1022.         if (mode & kVisibleOnly) {
  1023.             bool bVisible = true;
  1024.  
  1025.             if (HDC hdc = GetDCEx(mhwnd, NULL, 0)) {
  1026.                 RECT r;
  1027.                 GetClientRect(mhwnd, &r);
  1028.                 bVisible = 0 != RectVisible(hdc, &r);
  1029.                 ReleaseDC(mhwnd, hdc);
  1030.             }
  1031.  
  1032.             mode = (FieldMode)(mode & ~kVisibleOnly);
  1033.  
  1034.             if (!bVisible)
  1035.                 return;
  1036.         }
  1037.  
  1038.         mSyncDelta = 0.0f;
  1039.  
  1040.         bool success = mpMiniDriver->Update((IVDVideoDisplayMinidriver::UpdateMode)mode);
  1041.         ReleaseActiveFrame();
  1042.         if (success) {
  1043.             if (!mInhibitRefresh) {
  1044.                 mpMiniDriver->Refresh((IVDVideoDisplayMinidriver::UpdateMode)mode);
  1045.                 mSyncDelta = mpMiniDriver->GetSyncDelta();
  1046.  
  1047.                 if (!mpMiniDriver->IsFramePending())
  1048.                     RequestNextFrame();
  1049.             }
  1050.         }
  1051.     }
  1052. }
  1053.  
  1054. void VDVideoDisplayWindow::SyncCache() {
  1055.     if (mSource.pixmap.data && mSource.pixmap.data != mCachedImage.data) {
  1056.         mCachedImage.assign(mSource.pixmap);
  1057.  
  1058.         mSource.pixmap        = mCachedImage;
  1059.         mSource.bPersistent    = true;
  1060.     }
  1061.  
  1062.     if (mSource.pixmap.data && !mpMiniDriver)
  1063.         SyncInit(true, true);
  1064. }
  1065.  
  1066. void VDVideoDisplayWindow::SyncSetFilterMode(FilterMode mode) {
  1067.     if (mFilterMode != mode) {
  1068.         mFilterMode = mode;
  1069.  
  1070.         if (mpMiniDriver) {
  1071.             mpMiniDriver->SetFilterMode((IVDVideoDisplayMinidriver::FilterMode)mode);
  1072.             InvalidateRect(mhwnd, NULL, FALSE);
  1073.             InvalidateRect(mhwndChild, NULL, FALSE);
  1074.         }
  1075.     }
  1076. }
  1077.  
  1078. void VDVideoDisplayWindow::SyncSetSolidColor(uint32 color) {
  1079.     ReleaseActiveFrame();
  1080.     FlushBuffers();
  1081.  
  1082.     mSolidColorBuffer = color;
  1083.  
  1084.     VDVideoDisplaySourceInfo info;
  1085.  
  1086.     info.bAllowConversion    = true;
  1087.     info.bInterlaced        = false;
  1088.     info.bPersistent        = true;
  1089.     info.bpp                = 4;
  1090.     info.bpr                = 4;
  1091.     info.mpCB                = this;
  1092.     info.pixmap.data        = &mSolidColorBuffer;
  1093.     info.pixmap.format        = nsVDPixmap::kPixFormat_XRGB8888;
  1094.     info.pixmap.w            = 1;
  1095.     info.pixmap.h            = 1;
  1096.     info.pixmap.pitch        = 0;
  1097.     info.pSharedObject        = NULL;
  1098.     info.sharedOffset        = 0;
  1099.  
  1100.     SyncSetSource(false, info);
  1101.  
  1102.     if (mpMiniDriver) {
  1103.         mpMiniDriver->SetColorOverride(color);
  1104.         InvalidateRect(mhwnd, NULL, FALSE);
  1105.         InvalidateRect(mhwndChild, NULL, FALSE);
  1106.     }
  1107. }
  1108.  
  1109. void VDVideoDisplayWindow::OnDisplayChange() {
  1110.     HPALETTE hPal = GetPalette();
  1111.     if (mhOldPalette && !hPal) {
  1112.         if (HDC hdc = GetDC(mhwnd)) {
  1113.             SelectPalette(hdc, mhOldPalette, FALSE);
  1114.             mhOldPalette = 0;
  1115.             ReleaseDC(mhwnd, hdc);
  1116.         }
  1117.     }
  1118.     if (!mhOldPalette && hPal) {
  1119.         if (HDC hdc = GetDC(mhwnd)) {
  1120.             mhOldPalette = SelectPalette(hdc, hPal, FALSE);
  1121.             ReleaseDC(mhwnd, hdc);
  1122.         }
  1123.     }
  1124.     if (!mReinitDisplayTimer && !mbFullScreen) {
  1125.         SyncReset();
  1126.         if (!SyncInit(true, false))
  1127.             mReinitDisplayTimer = SetTimer(mhwnd, kReinitDisplayTimerId, 500, NULL);
  1128.     }
  1129. }
  1130.  
  1131. void VDVideoDisplayWindow::OnForegroundChange(bool bForeground) {
  1132.     if (mAccelMode != kAccelAlways)
  1133.         SyncReset();
  1134.  
  1135.     OnRealizePalette();
  1136. }
  1137.  
  1138. void VDVideoDisplayWindow::OnRealizePalette() {
  1139.     if (HDC hdc = GetDC(mhwnd)) {
  1140.         HPALETTE newPal = GetPalette();
  1141.         HPALETTE pal = SelectPalette(hdc, newPal, FALSE);
  1142.         if (!mhOldPalette)
  1143.             mhOldPalette = pal;
  1144.         RealizePalette(hdc);
  1145.         RemapPalette();
  1146.  
  1147.         if (mpMiniDriver) {
  1148.             mpMiniDriver->SetLogicalPalette(GetLogicalPalette());
  1149.             RequestUpdate();
  1150.         }
  1151.  
  1152.         ReleaseDC(mhwnd, hdc);
  1153.     }
  1154. }
  1155.  
  1156. bool VDVideoDisplayWindow::InitMiniDriver() {
  1157.     if (mhwndChild) {
  1158.         DestroyWindow(mhwndChild);
  1159.         mhwndChild = NULL;
  1160.     }
  1161.  
  1162.     RECT r;
  1163.     GetClientRect(mhwnd, &r);
  1164.     mhwndChild = CreateWindowEx(WS_EX_NOPARENTNOTIFY, (LPCTSTR)sChildWindowClass, "", WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS, 0, 0, r.right, r.bottom, mhwnd, NULL, VDGetLocalModuleHandleW32(), this);
  1165.     if (!mhwndChild)
  1166.         return false;
  1167.  
  1168.     mpMiniDriver->SetFilterMode((IVDVideoDisplayMinidriver::FilterMode)mFilterMode);
  1169.     mpMiniDriver->SetSubrect(mbUseSubrect ? &mSourceSubrect : NULL);
  1170.     mpMiniDriver->SetDisplayDebugInfo(sbEnableDebugInfo);
  1171.     mpMiniDriver->SetFullScreen(mbFullScreen);
  1172.     mpMiniDriver->SetHighPrecision(sbEnableHighPrecision);
  1173.  
  1174.     if (!mpMiniDriver->Init(mhwndChild, mSource)) {
  1175.         DestroyWindow(mhwndChild);
  1176.         mhwndChild = NULL;
  1177.         return false;
  1178.     }
  1179.  
  1180.     return true;
  1181. }
  1182.  
  1183. void VDVideoDisplayWindow::ShutdownMiniDriver() {
  1184.     if (mpMiniDriver) {
  1185.         // prevent recursion due to messages being triggered by Direct3D
  1186.         IVDVideoDisplayMinidriver *pMiniDriver = mpMiniDriver;
  1187.         mpMiniDriver = NULL;
  1188.         pMiniDriver->Shutdown();
  1189.         delete pMiniDriver;
  1190.     }
  1191.  
  1192.     if (mhwndChild) {
  1193.         DestroyWindow(mhwndChild);
  1194.         mhwndChild = NULL;
  1195.     }
  1196. }
  1197.  
  1198. void VDVideoDisplayWindow::RequestUpdate() {
  1199.     if (mpLastFrame) {
  1200.         if (!mpActiveFrame) {
  1201.             VDASSERT(!mpMiniDriver || !mpMiniDriver->IsFramePending());
  1202.             mpActiveFrame = mpLastFrame;
  1203.             mpLastFrame = NULL;
  1204.  
  1205.             DispatchActiveFrame();
  1206.         }
  1207.     } else if (mpCB)
  1208.         mpCB->DisplayRequestUpdate(this);
  1209.     else if (mSource.pixmap.data && mSource.bPersistent) {
  1210.         SyncUpdate(kAllFields);
  1211.     }
  1212. }
  1213.  
  1214. void VDVideoDisplayWindow::VerifyDriverResult(bool result) {
  1215.     if (!result) {
  1216.         if (mpMiniDriver) {
  1217.             ShutdownMiniDriver();
  1218.         }
  1219.  
  1220.         if (!mReinitDisplayTimer)
  1221.             mReinitDisplayTimer = SetTimer(mhwnd, kReinitDisplayTimerId, 500, NULL);
  1222.     }
  1223. }
  1224.  
  1225. bool VDVideoDisplayWindow::CheckForMonitorChange() {
  1226.     HMONITOR hmon = NULL;
  1227.  
  1228.     typedef HMONITOR (WINAPI *tpMonitorFromRect)(LPCRECT, DWORD);
  1229.     static const HMODULE shmodUser32 = GetModuleHandleA("user32");
  1230.     static const tpMonitorFromRect spMonitorFromRect = (tpMonitorFromRect)GetProcAddress(shmodUser32, "MonitorFromRect");
  1231.  
  1232.     if (!spMonitorFromRect)
  1233.         return false;
  1234.  
  1235.     RECT r;
  1236.     if (!GetWindowRect(mhwnd, &r))
  1237.         return false;
  1238.  
  1239.     // As a (mostly safe) optimization, don't check if we haven't moved. Note that
  1240.     // we are checking the window rect in screen space and not in positioning space.
  1241.     if (!memcmp(&r, &mLastMonitorCheckRect, sizeof r))
  1242.         return false;
  1243.  
  1244.     mLastMonitorCheckRect = r;
  1245.  
  1246.     HWND hwndTest = mhwnd; 
  1247.  
  1248.     while(GetWindowLong(hwndTest, GWL_STYLE) & WS_CHILD) {
  1249.         HWND hwndParent = GetParent(hwndTest);
  1250.         if (!hwndParent)
  1251.             break;
  1252.  
  1253.         RECT rParent;
  1254.         GetWindowRect(hwndParent, &rParent);
  1255.  
  1256.         if (r.left  < rParent.left)  r.left  = rParent.left;
  1257.         if (r.right < rParent.left)  r.right = rParent.left;
  1258.         if (r.left  > rParent.right) r.left  = rParent.right;
  1259.         if (r.right > rParent.right) r.right = rParent.right;
  1260.         if (r.top    < rParent.top)    r.top    = rParent.top;
  1261.         if (r.bottom < rParent.top)    r.bottom = rParent.top;
  1262.         if (r.top    > rParent.bottom) r.top    = rParent.bottom;
  1263.         if (r.bottom > rParent.bottom) r.bottom = rParent.bottom;
  1264.  
  1265.         hwndTest = hwndParent;
  1266.     }
  1267.  
  1268.     hmon = spMonitorFromRect(&r, MONITOR_DEFAULTTONEAREST);
  1269.     if (hmon == mhLastMonitor)
  1270.         return false;
  1271.  
  1272.     mhLastMonitor = hmon;
  1273.     return true;
  1274. }
  1275.  
  1276. bool VDVideoDisplayWindow::IsOnSecondaryMonitor() const {
  1277.     if (!mhLastMonitor)
  1278.         return false;
  1279.  
  1280.     typedef BOOL (WINAPI *tpGetMonitorInfo)(HMONITOR, LPMONITORINFO);
  1281.  
  1282.     static const HMODULE shmodUser32 = GetModuleHandleA("user32");
  1283.     static const tpGetMonitorInfo spGetMonitorInfo = (tpGetMonitorInfo)GetProcAddress(shmodUser32, "GetMonitorInfoA");
  1284.  
  1285.     if (!spGetMonitorInfo)
  1286.         return false;
  1287.  
  1288.     MONITORINFO monInfo = {sizeof(MONITORINFO)};
  1289.     if (!spGetMonitorInfo(mhLastMonitor, &monInfo))
  1290.         return false;
  1291.  
  1292.     return !(monInfo.dwFlags & MONITORINFOF_PRIMARY);
  1293. }
  1294.  
  1295. ///////////////////////////////////////////////////////////////////////////////
  1296.  
  1297. VDVideoDisplayManager *VDGetVideoDisplayManager() {
  1298.     if (!g_pVDVideoDisplayManager) {
  1299.         g_pVDVideoDisplayManager = new VDVideoDisplayManager;
  1300.         g_pVDVideoDisplayManager->Init();
  1301.         g_pVDVideoDisplayManager->SetBackgroundFallbackEnabled(VDVideoDisplayWindow::sbEnableBackgroundFallback);
  1302.     }
  1303.  
  1304.     return g_pVDVideoDisplayManager;
  1305. }
  1306.  
  1307. VDGUIHandle VDCreateDisplayWindowW32(uint32 dwExFlags, uint32 dwFlags, int x, int y, int width, int height, VDGUIHandle hwndParent) {
  1308.     VDVideoDisplayManager *vdm = VDGetVideoDisplayManager();
  1309.  
  1310.     if (!vdm)
  1311.         return NULL;
  1312.  
  1313.     struct RemoteCreateCall {
  1314.         DWORD dwExFlags;
  1315.         DWORD dwFlags;
  1316.         int x;
  1317.         int y;
  1318.         int width;
  1319.         int height;
  1320.         HWND hwndParent;
  1321.         VDVideoDisplayManager *vdm;
  1322.         HWND hwndResult;
  1323.  
  1324.         static void Dispatch(void *p0) {
  1325.             RemoteCreateCall *p = (RemoteCreateCall *)p0;
  1326.             p->hwndResult = CreateWindowEx(p->dwExFlags, g_szVideoDisplayControlName, "", p->dwFlags, p->x, p->y, p->width, p->height, p->hwndParent, NULL, VDGetLocalModuleHandleW32(), p->vdm);
  1327.         }
  1328.     } rmc = {dwExFlags, dwFlags | WS_CLIPCHILDREN, x, y, width, height, (HWND)hwndParent, vdm};
  1329.  
  1330.     vdm->RemoteCall(RemoteCreateCall::Dispatch, &rmc);
  1331.     return (VDGUIHandle)rmc.hwndResult;
  1332. }
  1333.