| 301 | | // ---------------------------------------------------------------------------- |
| 302 | | // wxDisplay implementation using DirectDraw |
| 303 | | // ---------------------------------------------------------------------------- |
| 304 | | |
| 305 | | #if wxUSE_DIRECTDRAW |
| 306 | | |
| 307 | | struct wxDisplayInfoDirectDraw : wxDisplayInfo |
| 308 | | { |
| 309 | | wxDisplayInfoDirectDraw(const GUID& guid, HMONITOR hmon, LPTSTR name) |
| 310 | | : wxDisplayInfo(hmon), |
| 311 | | m_guid(guid) |
| 312 | | { |
| 313 | | m_pDD2 = NULL; |
| 314 | | m_devName = name; |
| 315 | | } |
| 316 | | |
| 317 | | virtual ~wxDisplayInfoDirectDraw() |
| 318 | | { |
| 319 | | if ( m_pDD2 ) |
| 320 | | m_pDD2->Release(); |
| 321 | | } |
| 322 | | |
| 323 | | |
| 324 | | // IDirectDraw object used to control this display, may be NULL |
| 325 | | IDirectDraw2 *m_pDD2; |
| 326 | | |
| 327 | | // DirectDraw GUID for this display, only valid when using DirectDraw |
| 328 | | const GUID m_guid; |
| 329 | | |
| 330 | | |
| 331 | | wxDECLARE_NO_COPY_CLASS(wxDisplayInfoDirectDraw); |
| 332 | | }; |
| 333 | | |
| 334 | | class wxDisplayImplDirectDraw : public wxDisplayImplWin32Base |
| 335 | | { |
| 336 | | public: |
| 337 | | wxDisplayImplDirectDraw(unsigned n, wxDisplayInfo& info, IDirectDraw2 *pDD2) |
| 338 | | : wxDisplayImplWin32Base(n, info), |
| 339 | | m_pDD2(pDD2) |
| 340 | | { |
| 341 | | m_pDD2->AddRef(); |
| 342 | | } |
| 343 | | |
| 344 | | virtual ~wxDisplayImplDirectDraw() |
| 345 | | { |
| 346 | | m_pDD2->Release(); |
| 347 | | } |
| 348 | | |
| 349 | | virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const; |
| 350 | | virtual bool ChangeMode(const wxVideoMode& mode); |
| 351 | | |
| 352 | | private: |
| 353 | | IDirectDraw2 *m_pDD2; |
| 354 | | |
| 355 | | wxDECLARE_NO_COPY_CLASS(wxDisplayImplDirectDraw); |
| 356 | | }; |
| 357 | | |
| 358 | | class wxDisplayFactoryDirectDraw : public wxDisplayFactoryWin32Base |
| 359 | | { |
| 360 | | public: |
| 361 | | wxDisplayFactoryDirectDraw(); |
| 362 | | virtual ~wxDisplayFactoryDirectDraw(); |
| 363 | | |
| 364 | | virtual wxDisplayImpl *CreateDisplay(unsigned n); |
| 365 | | |
| 366 | | private: |
| 367 | | // callback used with DirectDrawEnumerateEx() |
| 368 | | static BOOL WINAPI DDEnumExCallback(GUID *pGuid, |
| 369 | | LPTSTR driverDescription, |
| 370 | | LPTSTR driverName, |
| 371 | | LPVOID lpContext, |
| 372 | | HMONITOR hmon); |
| 373 | | |
| 374 | | // add a monitor description to m_displays array |
| 375 | | void AddDisplay(const GUID& guid, HMONITOR hmon, LPTSTR name); |
| 376 | | |
| 377 | | |
| 378 | | // ddraw.dll |
| 379 | | wxDynamicLibrary m_dllDDraw; |
| 380 | | |
| 381 | | // dynamically resolved DirectDrawCreate() |
| 382 | | DirectDrawCreate_t m_pfnDirectDrawCreate; |
| 383 | | |
| 384 | | wxDECLARE_NO_COPY_CLASS(wxDisplayFactoryDirectDraw); |
| 385 | | }; |
| 386 | | |
| 387 | | #endif // wxUSE_DIRECTDRAW |
| 388 | | |
| 796 | | |
| 797 | | // ============================================================================ |
| 798 | | // DirectDraw-based wxDisplay implementation |
| 799 | | // ============================================================================ |
| 800 | | |
| 801 | | #if wxUSE_DIRECTDRAW |
| 802 | | |
| 803 | | // ---------------------------------------------------------------------------- |
| 804 | | // wxDisplayFactoryDirectDraw initialization |
| 805 | | // ---------------------------------------------------------------------------- |
| 806 | | |
| 807 | | wxDisplayFactoryDirectDraw::wxDisplayFactoryDirectDraw() |
| 808 | | { |
| 809 | | if ( !ms_supportsMultimon ) |
| 810 | | return; |
| 811 | | |
| 812 | | m_dllDDraw.Load(wxT("ddraw.dll"), wxDL_VERBATIM | wxDL_QUIET); |
| 813 | | |
| 814 | | if ( !m_dllDDraw.IsLoaded() ) |
| 815 | | return; |
| 816 | | |
| 817 | | DirectDrawEnumerateEx_t |
| 818 | | wxDL_INIT_FUNC_AW(pfn, DirectDrawEnumerateEx, m_dllDDraw); |
| 819 | | if ( !pfnDirectDrawEnumerateEx ) |
| 820 | | return; |
| 821 | | |
| 822 | | // we can't continue without DirectDrawCreate() later, so resolve it right |
| 823 | | // now and fail the initialization if it's not available |
| 824 | | if ( !wxDL_INIT_FUNC(m_pfn, DirectDrawCreate, m_dllDDraw) ) |
| 825 | | return; |
| 826 | | |
| 827 | | if ( (*pfnDirectDrawEnumerateEx)(DDEnumExCallback, |
| 828 | | this, |
| 829 | | DDENUM_ATTACHEDSECONDARYDEVICES) != DD_OK ) |
| 830 | | { |
| 831 | | wxLogLastError(wxT("DirectDrawEnumerateEx")); |
| 832 | | } |
| 833 | | } |
| 834 | | |
| 835 | | wxDisplayFactoryDirectDraw::~wxDisplayFactoryDirectDraw() |
| 836 | | { |
| 837 | | // we must clear m_displays now, before m_dllDDraw is unloaded as otherwise |
| 838 | | // calling m_pDD2->Release() later would crash |
| 839 | | Clear(); |
| 840 | | } |
| 841 | | |
| 842 | | // ---------------------------------------------------------------------------- |
| 843 | | // callbacks for monitor/modes enumeration stuff |
| 844 | | // ---------------------------------------------------------------------------- |
| 845 | | |
| 846 | | BOOL WINAPI |
| 847 | | wxDisplayFactoryDirectDraw::DDEnumExCallback(GUID *pGuid, |
| 848 | | LPTSTR WXUNUSED(driverDescription), |
| 849 | | LPTSTR driverName, |
| 850 | | LPVOID lpContext, |
| 851 | | HMONITOR hmon) |
| 852 | | { |
| 853 | | if ( pGuid ) |
| 854 | | { |
| 855 | | wxDisplayFactoryDirectDraw * self = |
| 856 | | static_cast<wxDisplayFactoryDirectDraw *>(lpContext); |
| 857 | | self->AddDisplay(*pGuid, hmon, driverName); |
| 858 | | } |
| 859 | | //else: we're called for the primary monitor, skip it |
| 860 | | |
| 861 | | // continue the enumeration |
| 862 | | return TRUE; |
| 863 | | } |
| 864 | | |
| 865 | | // ---------------------------------------------------------------------------- |
| 866 | | // wxDisplayFactoryDirectDraw helpers |
| 867 | | // ---------------------------------------------------------------------------- |
| 868 | | |
| 869 | | void wxDisplayFactoryDirectDraw::AddDisplay(const GUID& guid, |
| 870 | | HMONITOR hmon, |
| 871 | | LPTSTR name) |
| 872 | | { |
| 873 | | m_displays.Add(new wxDisplayInfoDirectDraw(guid, hmon, name)); |
| 874 | | } |
| 875 | | |
| 876 | | // ---------------------------------------------------------------------------- |
| 877 | | // wxDisplayFactoryDirectDraw inherited pure virtuals implementation |
| 878 | | // ---------------------------------------------------------------------------- |
| 879 | | |
| 880 | | wxDisplayImpl *wxDisplayFactoryDirectDraw::CreateDisplay(unsigned n) |
| 881 | | { |
| 882 | | wxCHECK_MSG( n < m_displays.size(), NULL, wxT("invalid display index") ); |
| 883 | | |
| 884 | | wxDisplayInfoDirectDraw * |
| 885 | | info = static_cast<wxDisplayInfoDirectDraw *>(m_displays[n]); |
| 886 | | |
| 887 | | if ( !info->m_pDD2 ) |
| 888 | | { |
| 889 | | IDirectDraw *pDD; |
| 890 | | GUID guid(info->m_guid); |
| 891 | | HRESULT hr = (*m_pfnDirectDrawCreate)(&guid, &pDD, NULL); |
| 892 | | |
| 893 | | if ( FAILED(hr) || !pDD ) |
| 894 | | { |
| 895 | | // what to do?? |
| 896 | | wxLogApiError(wxT("DirectDrawCreate"), hr); |
| 897 | | return NULL; |
| 898 | | } |
| 899 | | |
| 900 | | // we got IDirectDraw, but we need IDirectDraw2 |
| 901 | | hr = pDD->QueryInterface(wxIID_IDirectDraw2, (void **)&info->m_pDD2); |
| 902 | | pDD->Release(); |
| 903 | | |
| 904 | | if ( FAILED(hr) || !info->m_pDD2 ) |
| 905 | | { |
| 906 | | wxLogApiError(wxT("IDirectDraw::QueryInterface(IDD2)"), hr); |
| 907 | | return NULL; |
| 908 | | } |
| 909 | | |
| 910 | | // NB: m_pDD2 will now be only destroyed when m_displays is destroyed |
| 911 | | // which is ok as we don't want to recreate DD objects all the time |
| 912 | | } |
| 913 | | //else: DirectDraw object corresponding to our display already exists |
| 914 | | |
| 915 | | return new wxDisplayImplDirectDraw(n, *info, info->m_pDD2); |
| 916 | | } |
| 917 | | |
| 918 | | // ============================================================================ |
| 919 | | // wxDisplayImplDirectDraw |
| 920 | | // ============================================================================ |
| 921 | | |
| 922 | | // ---------------------------------------------------------------------------- |
| 923 | | // video modes enumeration |
| 924 | | // ---------------------------------------------------------------------------- |
| 925 | | |
| 926 | | // tiny helper class used to pass information from GetModes() to |
| 927 | | // wxDDEnumModesCallback |
| 928 | | class wxDDVideoModesAdder |
| 929 | | { |
| 930 | | public: |
| 931 | | // our Add() method will add modes matching modeMatch to modes array |
| 932 | | wxDDVideoModesAdder(wxArrayVideoModes& modes, const wxVideoMode& modeMatch) |
| 933 | | : m_modes(modes), |
| 934 | | m_modeMatch(modeMatch) |
| 935 | | { |
| 936 | | } |
| 937 | | |
| 938 | | void Add(const wxVideoMode& mode) |
| 939 | | { |
| 940 | | if ( mode.Matches(m_modeMatch) ) |
| 941 | | m_modes.Add(mode); |
| 942 | | } |
| 943 | | |
| 944 | | private: |
| 945 | | wxArrayVideoModes& m_modes; |
| 946 | | const wxVideoMode& m_modeMatch; |
| 947 | | |
| 948 | | wxDECLARE_NO_COPY_CLASS(wxDDVideoModesAdder); |
| 949 | | }; |
| 950 | | |
| 951 | | HRESULT WINAPI wxDDEnumModesCallback(LPDDSURFACEDESC lpDDSurfaceDesc, |
| 952 | | LPVOID lpContext) |
| 953 | | { |
| 954 | | // we need at least the mode size |
| 955 | | static const DWORD FLAGS_REQUIRED = DDSD_HEIGHT | DDSD_WIDTH; |
| 956 | | if ( (lpDDSurfaceDesc->dwFlags & FLAGS_REQUIRED) == FLAGS_REQUIRED ) |
| 957 | | { |
| 958 | | wxDDVideoModesAdder * const vmodes = |
| 959 | | static_cast<wxDDVideoModesAdder *>(lpContext); |
| 960 | | |
| 961 | | vmodes->Add(wxVideoMode(lpDDSurfaceDesc->dwWidth, |
| 962 | | lpDDSurfaceDesc->dwHeight, |
| 963 | | lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount, |
| 964 | | lpDDSurfaceDesc->dwRefreshRate)); |
| 965 | | } |
| 966 | | |
| 967 | | // continue the enumeration |
| 968 | | return DDENUMRET_OK; |
| 969 | | } |
| 970 | | |
| 971 | | wxArrayVideoModes |
| 972 | | wxDisplayImplDirectDraw::GetModes(const wxVideoMode& modeMatch) const |
| 973 | | { |
| 974 | | wxArrayVideoModes modes; |
| 975 | | wxDDVideoModesAdder modesAdder(modes, modeMatch); |
| 976 | | |
| 977 | | HRESULT hr = m_pDD2->EnumDisplayModes |
| 978 | | ( |
| 979 | | DDEDM_REFRESHRATES, |
| 980 | | NULL, // all modes |
| 981 | | &modesAdder, // callback parameter |
| 982 | | wxDDEnumModesCallback |
| 983 | | ); |
| 984 | | |
| 985 | | if ( FAILED(hr) ) |
| 986 | | { |
| 987 | | wxLogApiError(wxT("IDirectDraw::EnumDisplayModes"), hr); |
| 988 | | } |
| 989 | | |
| 990 | | return modes; |
| 991 | | } |
| 992 | | |
| 993 | | // ---------------------------------------------------------------------------- |
| 994 | | // video mode switching |
| 995 | | // ---------------------------------------------------------------------------- |
| 996 | | |
| 997 | | bool wxDisplayImplDirectDraw::ChangeMode(const wxVideoMode& mode) |
| 998 | | { |
| 999 | | wxWindow *winTop = wxTheApp->GetTopWindow(); |
| 1000 | | wxCHECK_MSG( winTop, false, wxT("top level window required for DirectX") ); |
| 1001 | | |
| 1002 | | HRESULT hr = m_pDD2->SetCooperativeLevel |
| 1003 | | ( |
| 1004 | | GetHwndOf(winTop), |
| 1005 | | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN |
| 1006 | | ); |
| 1007 | | if ( FAILED(hr) ) |
| 1008 | | { |
| 1009 | | wxLogApiError(wxT("IDirectDraw2::SetCooperativeLevel"), hr); |
| 1010 | | |
| 1011 | | return false; |
| 1012 | | } |
| 1013 | | |
| 1014 | | hr = m_pDD2->SetDisplayMode(mode.w, mode.h, mode.bpp, mode.refresh, 0); |
| 1015 | | if ( FAILED(hr) ) |
| 1016 | | { |
| 1017 | | wxLogApiError(wxT("IDirectDraw2::SetDisplayMode"), hr); |
| 1018 | | |
| 1019 | | return false; |
| 1020 | | } |
| 1021 | | |
| 1022 | | return true; |
| 1023 | | } |
| 1024 | | |
| 1025 | | #endif // wxUSE_DIRECTDRAW |
| 1026 | | |