| 107 | | // ---------------------------------------------------------------------------- |
| 108 | | // display information classes |
| 109 | | // ---------------------------------------------------------------------------- |
| 110 | | |
| 111 | | struct wxDisplayInfo |
| 112 | | { |
| 113 | | wxDisplayInfo(HMONITOR hmon = NULL) |
| 114 | | { |
| 115 | | m_hmon = hmon; |
| 116 | | m_flags = (DWORD)-1; |
| 117 | | } |
| 118 | | |
| 119 | | virtual ~wxDisplayInfo() { } |
| 120 | | |
| 121 | | |
| 122 | | // use GetMonitorInfo() to fill in all of our fields if needed (i.e. if it |
| 123 | | // hadn't been done before) |
| 124 | | void Initialize(); |
| 125 | | |
| 126 | | |
| 127 | | // handle of this monitor used by MonitorXXX() functions, never NULL |
| 128 | | HMONITOR m_hmon; |
| 129 | | |
| 130 | | // the entire area of this monitor in virtual screen coordinates |
| 131 | | wxRect m_rect; |
| 132 | | |
| 133 | | // the work or client area, i.e. the area available for the normal windows |
| 134 | | wxRect m_rectClient; |
| 135 | | |
| 136 | | // the display device name for this monitor, empty initially and retrieved |
| 137 | | // on demand by DoGetName() |
| 138 | | wxString m_devName; |
| 139 | | |
| 140 | | // the flags of this monitor, also used as initialization marker: if this |
| 141 | | // is -1, GetMonitorInfo() hadn't been called yet |
| 142 | | DWORD m_flags; |
| 143 | | }; |
| 144 | | |
| 145 | | WX_DEFINE_ARRAY_PTR(wxDisplayInfo *, wxDisplayInfoArray); |
| 146 | | |
| 147 | | // ---------------------------------------------------------------------------- |
| 148 | | // common base class for all Win32 wxDisplayImpl versions |
| 149 | | // ---------------------------------------------------------------------------- |
| 150 | | |
| 151 | | class wxDisplayImplWin32Base : public wxDisplayImpl |
| | 107 | |
| | 108 | // ---------------------------------------------------------------------------- |
| | 109 | // wxDisplayMSW declaration |
| | 110 | // ---------------------------------------------------------------------------- |
| | 111 | |
| | 112 | class wxDisplayMSW : public wxDisplayImpl |
| 202 | | |
| 203 | | protected: |
| 204 | | // ctor checks if the current system supports multimon API and dynamically |
| 205 | | // bind the functions we need if this is the case and sets |
| 206 | | // ms_supportsMultimon if they're available |
| 207 | | wxDisplayFactoryWin32Base(); |
| 208 | | |
| 209 | | // delete all m_displays elements: can be called from the derived class |
| 210 | | // dtor if it is important to do this before destroying it, |
| 211 | | // otherwise will be done by our dtor |
| 212 | | void Clear(); |
| 213 | | |
| 214 | | // find the monitor corresponding to the given handle, return wxNOT_FOUND |
| 215 | | // if not found |
| 216 | | int FindDisplayFromHMONITOR(HMONITOR hmon) const; |
| 217 | | |
| 218 | | |
| 219 | | // flag indicating whether gs_MonitorXXX functions are available |
| 220 | | static int ms_supportsMultimon; |
| 221 | | |
| 222 | | // the array containing information about all available displays, should be |
| 223 | | // filled by the derived class ctors |
| 224 | | wxDisplayInfoArray m_displays; |
| 225 | | |
| 226 | | |
| 227 | | wxDECLARE_NO_COPY_CLASS(wxDisplayFactoryWin32Base); |
| 228 | | }; |
| 229 | | |
| 230 | | // ---------------------------------------------------------------------------- |
| 231 | | // wxDisplay implementation using Windows multi-monitor support functions |
| 232 | | // ---------------------------------------------------------------------------- |
| 233 | | |
| 234 | | class wxDisplayImplMultimon : public wxDisplayImplWin32Base |
| 235 | | { |
| 236 | | public: |
| 237 | | wxDisplayImplMultimon(unsigned n, wxDisplayInfo& info) |
| 238 | | : wxDisplayImplWin32Base(n, info) |
| 239 | | { |
| 240 | | } |
| 241 | | |
| 242 | | virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const; |
| 243 | | virtual bool ChangeMode(const wxVideoMode& mode); |
| 244 | | |
| 245 | | private: |
| 246 | | wxDECLARE_NO_COPY_CLASS(wxDisplayImplMultimon); |
| 247 | | }; |
| 248 | | |
| 249 | | class wxDisplayFactoryMultimon : public wxDisplayFactoryWin32Base |
| 250 | | { |
| 251 | | public: |
| 252 | | wxDisplayFactoryMultimon(); |
| 253 | | |
| 254 | | virtual wxDisplayImpl *CreateDisplay(unsigned n); |
| 291 | | // wxDisplayInfo |
| 292 | | // ---------------------------------------------------------------------------- |
| 293 | | |
| 294 | | void wxDisplayInfo::Initialize() |
| 295 | | { |
| 296 | | if ( m_flags == (DWORD)-1 ) |
| 297 | | { |
| 298 | | WinStruct<MONITORINFOEX> monInfo; |
| 299 | | if ( !gs_GetMonitorInfo(m_hmon, (LPMONITORINFO)&monInfo) ) |
| 300 | | { |
| 301 | | wxLogLastError(wxT("GetMonitorInfo")); |
| 302 | | m_flags = 0; |
| 303 | | return; |
| 304 | | } |
| 305 | | |
| 306 | | wxCopyRECTToRect(monInfo.rcMonitor, m_rect); |
| 307 | | wxCopyRECTToRect(monInfo.rcWork, m_rectClient); |
| 308 | | m_devName = monInfo.szDevice; |
| 309 | | m_flags = monInfo.dwFlags; |
| 310 | | } |
| 311 | | } |
| 312 | | |
| 313 | | // ---------------------------------------------------------------------------- |
| 314 | | // wxDisplayImplWin32Base |
| 315 | | // ---------------------------------------------------------------------------- |
| 316 | | |
| 317 | | wxRect wxDisplayImplWin32Base::GetGeometry() const |
| 318 | | { |
| 319 | | if ( m_info.m_rect.IsEmpty() ) |
| 320 | | m_info.Initialize(); |
| 321 | | |
| 322 | | return m_info.m_rect; |
| 323 | | } |
| 324 | | |
| 325 | | wxRect wxDisplayImplWin32Base::GetClientArea() const |
| 326 | | { |
| 327 | | if ( m_info.m_rectClient.IsEmpty() ) |
| 328 | | m_info.Initialize(); |
| 329 | | |
| 330 | | return m_info.m_rectClient; |
| 331 | | } |
| 332 | | |
| 333 | | wxString wxDisplayImplWin32Base::GetName() const |
| 334 | | { |
| 335 | | if ( m_info.m_devName.empty() ) |
| 336 | | m_info.Initialize(); |
| 337 | | |
| 338 | | return m_info.m_devName; |
| 339 | | } |
| 340 | | |
| 341 | | bool wxDisplayImplWin32Base::IsPrimary() const |
| 342 | | { |
| 343 | | if ( m_info.m_flags == (DWORD)-1 ) |
| 344 | | m_info.Initialize(); |
| 345 | | |
| 346 | | return (m_info.m_flags & MONITORINFOF_PRIMARY) != 0; |
| 347 | | } |
| 348 | | |
| 349 | | wxVideoMode wxDisplayImplWin32Base::GetCurrentMode() const |
| | 215 | // wxDisplayMSW implementation |
| | 216 | // ---------------------------------------------------------------------------- |
| | 217 | |
| | 218 | wxRect wxDisplayMSW::GetGeometry() const |
| | 219 | { |
| | 220 | WinStruct<MONITORINFOEX> monInfo; |
| | 221 | |
| | 222 | if ( !gs_GetMonitorInfo(m_hmon, (LPMONITORINFO)&monInfo) ) |
| | 223 | { |
| | 224 | wxLogLastError(wxT(__FUNCTION__)); |
| | 225 | return wxRect(); |
| | 226 | } |
| | 227 | |
| | 228 | wxRect rect; |
| | 229 | wxCopyRECTToRect(monInfo.rcMonitor, rect); |
| | 230 | |
| | 231 | return rect; |
| | 232 | } |
| | 233 | |
| | 234 | wxRect wxDisplayMSW::GetClientArea() const |
| | 235 | { |
| | 236 | WinStruct<MONITORINFOEX> monInfo; |
| | 237 | |
| | 238 | if ( !gs_GetMonitorInfo(m_hmon, (LPMONITORINFO)&monInfo) ) |
| | 239 | { |
| | 240 | wxLogLastError(wxT(__FUNCTION__)); |
| | 241 | return wxRect(); |
| | 242 | } |
| | 243 | |
| | 244 | wxRect rectClient; |
| | 245 | wxCopyRECTToRect(monInfo.rcWork, rectClient); |
| | 246 | |
| | 247 | return rectClient; |
| | 248 | } |
| | 249 | |
| | 250 | wxString wxDisplayMSW::GetName() const |
| | 251 | { |
| | 252 | WinStruct<MONITORINFOEX> monInfo; |
| | 253 | |
| | 254 | if ( !gs_GetMonitorInfo(m_hmon, (LPMONITORINFO)&monInfo) ) |
| | 255 | { |
| | 256 | wxLogLastError(wxT(__FUNCTION__)); |
| | 257 | return ""; |
| | 258 | } |
| | 259 | |
| | 260 | return monInfo.szDevice; |
| | 261 | } |
| | 262 | |
| | 263 | bool wxDisplayMSW::IsPrimary() const |
| | 264 | { |
| | 265 | WinStruct<MONITORINFOEX> monInfo; |
| | 266 | |
| | 267 | if ( !gs_GetMonitorInfo(m_hmon, (LPMONITORINFO)&monInfo) ) |
| | 268 | { |
| | 269 | wxLogLastError(wxT(__FUNCTION__)); |
| | 270 | return false; |
| | 271 | } |
| | 272 | |
| | 273 | return (monInfo.dwFlags & MONITORINFOF_PRIMARY) != 0; |
| | 274 | } |
| | 275 | |
| | 276 | wxVideoMode wxDisplayMSW::GetCurrentMode() const |
| 376 | | // ---------------------------------------------------------------------------- |
| 377 | | // wxDisplayFactoryWin32Base |
| 378 | | // ---------------------------------------------------------------------------- |
| 379 | | |
| 380 | | int wxDisplayFactoryWin32Base::ms_supportsMultimon = -1; |
| 381 | | |
| 382 | | wxDisplayFactoryWin32Base::wxDisplayFactoryWin32Base() |
| 383 | | { |
| 384 | | if ( ms_supportsMultimon == -1 ) |
| 385 | | { |
| 386 | | ms_supportsMultimon = 0; |
| 387 | | |
| 388 | | wxDynamicLibrary dllDisplay(displayDllName, wxDL_VERBATIM | wxDL_QUIET); |
| 389 | | |
| 390 | | if ( (wxDL_INIT_FUNC(gs_, MonitorFromPoint, dllDisplay)) == NULL || |
| 391 | | (wxDL_INIT_FUNC(gs_, MonitorFromWindow, dllDisplay)) == NULL || |
| 392 | | (wxDL_INIT_FUNC_AW(gs_, GetMonitorInfo, dllDisplay)) == NULL ) |
| 393 | | return; |
| 394 | | |
| 395 | | ms_supportsMultimon = 1; |
| 396 | | |
| 397 | | // we can safely let dllDisplay go out of scope, the DLL itself will |
| 398 | | // still remain loaded as all programs link to it statically anyhow |
| 399 | | } |
| 400 | | } |
| 401 | | |
| 402 | | void wxDisplayFactoryWin32Base::Clear() |
| 403 | | { |
| 404 | | WX_CLEAR_ARRAY(m_displays); |
| 405 | | } |
| 406 | | |
| 407 | | wxDisplayFactoryWin32Base::~wxDisplayFactoryWin32Base() |
| 408 | | { |
| 409 | | Clear(); |
| 410 | | } |
| 411 | | |
| 412 | | // helper for GetFromPoint() and GetFromWindow() |
| 413 | | int wxDisplayFactoryWin32Base::FindDisplayFromHMONITOR(HMONITOR hmon) const |
| 414 | | { |
| 415 | | if ( hmon ) |
| 416 | | { |
| 417 | | const size_t count = m_displays.size(); |
| 418 | | for ( size_t n = 0; n < count; n++ ) |
| 419 | | { |
| 420 | | if ( hmon == m_displays[n]->m_hmon ) |
| 421 | | return n; |
| 422 | | } |
| 423 | | } |
| 424 | | |
| 425 | | return wxNOT_FOUND; |
| 426 | | } |
| 427 | | |
| 428 | | int wxDisplayFactoryWin32Base::GetFromPoint(const wxPoint& pt) |
| 429 | | { |
| 430 | | POINT pt2; |
| 431 | | pt2.x = pt.x; |
| 432 | | pt2.y = pt.y; |
| 433 | | |
| 434 | | return FindDisplayFromHMONITOR(gs_MonitorFromPoint(pt2, |
| 435 | | MONITOR_DEFAULTTONULL)); |
| 436 | | } |
| 437 | | |
| 438 | | int wxDisplayFactoryWin32Base::GetFromWindow(const wxWindow *window) |
| 439 | | { |
| 440 | | return FindDisplayFromHMONITOR(gs_MonitorFromWindow(GetHwndOf(window), |
| 441 | | MONITOR_DEFAULTTONULL)); |
| 442 | | } |
| 443 | | |
| 444 | | // ============================================================================ |
| 445 | | // wxDisplay implementation using Win32 multimon API |
| 446 | | // ============================================================================ |
| 447 | | |
| 448 | | // ---------------------------------------------------------------------------- |
| 449 | | // wxDisplayFactoryMultimon initialization |
| 450 | | // ---------------------------------------------------------------------------- |
| 451 | | |
| 452 | | wxDisplayFactoryMultimon::wxDisplayFactoryMultimon() |
| 453 | | { |
| 454 | | if ( !ms_supportsMultimon ) |
| 455 | | return; |
| 456 | | |
| 457 | | // look up EnumDisplayMonitors() |
| 458 | | EnumDisplayMonitors_t pfnEnumDisplayMonitors; |
| 459 | | { |
| 460 | | wxDynamicLibrary dllDisplay(displayDllName, wxDL_VERBATIM | wxDL_QUIET); |
| 461 | | if ( (wxDL_INIT_FUNC(pfn, EnumDisplayMonitors, dllDisplay)) == NULL ) |
| 462 | | return; |
| 463 | | } |
| 464 | | |
| 465 | | // enumerate all displays |
| 466 | | if ( !pfnEnumDisplayMonitors(NULL, NULL, MultimonEnumProc, (LPARAM)this) ) |
| 467 | | { |
| 468 | | wxLogLastError(wxT("EnumDisplayMonitors")); |
| 469 | | } |
| 470 | | } |
| 471 | | |
| 472 | | /* static */ |
| 473 | | BOOL CALLBACK |
| 474 | | wxDisplayFactoryMultimon::MultimonEnumProc( |
| 475 | | HMONITOR hMonitor, // handle to display monitor |
| 476 | | HDC WXUNUSED(hdcMonitor), // handle to monitor-appropriate device context |
| 477 | | LPRECT lprcMonitor, // pointer to monitor intersection rectangle |
| 478 | | LPARAM dwData // data passed from EnumDisplayMonitors (this) |
| 479 | | ) |
| 480 | | { |
| 481 | | wxDisplayFactoryMultimon *const self = (wxDisplayFactoryMultimon *)dwData; |
| 482 | | self->AddDisplay(hMonitor, lprcMonitor); |
| 483 | | |
| 484 | | // continue the enumeration |
| 485 | | return TRUE; |
| 486 | | } |
| 487 | | |
| 488 | | // ---------------------------------------------------------------------------- |
| 489 | | // wxDisplayFactoryMultimon helper functions |
| 490 | | // ---------------------------------------------------------------------------- |
| 491 | | |
| 492 | | void wxDisplayFactoryMultimon::AddDisplay(HMONITOR hMonitor, LPRECT lprcMonitor) |
| 493 | | { |
| 494 | | wxDisplayInfo *info = new wxDisplayInfo(hMonitor); |
| 495 | | |
| 496 | | // we also store the display geometry |
| 497 | | info->m_rect = wxRect(lprcMonitor->left, lprcMonitor->top, |
| 498 | | lprcMonitor->right - lprcMonitor->left, |
| 499 | | lprcMonitor->bottom - lprcMonitor->top); |
| 500 | | |
| 501 | | // now add this monitor to the array |
| 502 | | m_displays.Add(info); |
| 503 | | } |
| 504 | | |
| 505 | | // ---------------------------------------------------------------------------- |
| 506 | | // wxDisplayFactoryMultimon inherited pure virtuals implementation |
| 507 | | // ---------------------------------------------------------------------------- |
| 508 | | |
| 509 | | wxDisplayImpl *wxDisplayFactoryMultimon::CreateDisplay(unsigned n) |
| 510 | | { |
| 511 | | wxCHECK_MSG( n < m_displays.size(), NULL, wxT("invalid display index") ); |
| 512 | | |
| 513 | | return new wxDisplayImplMultimon(n, *(m_displays[n])); |
| 514 | | } |
| 515 | | |
| 516 | | // ---------------------------------------------------------------------------- |
| 517 | | // wxDisplayImplMultimon implementation |
| 518 | | // ---------------------------------------------------------------------------- |
| 519 | | |
| 520 | | wxArrayVideoModes |
| 521 | | wxDisplayImplMultimon::GetModes(const wxVideoMode& modeMatch) const |
| | 304 | wxArrayVideoModes wxDisplayMSW::GetModes(const wxVideoMode& modeMatch) const |
| | 443 | |
| | 444 | // ---------------------------------------------------------------------------- |
| | 445 | // wxDisplayFactoryMSW implementation |
| | 446 | // ---------------------------------------------------------------------------- |
| | 447 | |
| | 448 | wxDisplayFactoryMSW::wxDisplayFactoryMSW() |
| | 449 | { |
| | 450 | if ( gs_MonitorFromPoint==NULL || gs_MonitorFromWindow==NULL |
| | 451 | || gs_GetMonitorInfo==NULL || gs_EnumDisplayMonitors==NULL ) |
| | 452 | { |
| | 453 | // First initialization, or last initialization failed. |
| | 454 | wxDynamicLibrary dllDisplay(displayDllName, wxDL_VERBATIM | wxDL_QUIET); |
| | 455 | |
| | 456 | wxDL_INIT_FUNC(gs_, MonitorFromPoint, dllDisplay); |
| | 457 | wxDL_INIT_FUNC(gs_, MonitorFromWindow, dllDisplay); |
| | 458 | wxDL_INIT_FUNC_AW(gs_, GetMonitorInfo, dllDisplay); |
| | 459 | wxDL_INIT_FUNC(gs_, EnumDisplayMonitors, dllDisplay); |
| | 460 | |
| | 461 | // we can safely let dllDisplay go out of scope, the DLL itself will |
| | 462 | // still remain loaded as all programs link to it statically anyhow |
| | 463 | } |
| | 464 | |
| | 465 | if ( gs_MonitorFromPoint==NULL || gs_MonitorFromWindow==NULL |
| | 466 | || gs_GetMonitorInfo==NULL || gs_EnumDisplayMonitors==NULL ) |
| | 467 | return; |
| | 468 | |
| | 469 | // enumerate all displays |
| | 470 | if ( !gs_EnumDisplayMonitors(NULL, NULL, MultimonEnumProc, (LPARAM)this) ) |
| | 471 | { |
| | 472 | wxLogLastError(wxT("EnumDisplayMonitors")); |
| | 473 | } |
| | 474 | } |
| | 475 | |
| | 476 | /* static */ |
| | 477 | BOOL CALLBACK |
| | 478 | wxDisplayFactoryMSW::MultimonEnumProc( |
| | 479 | HMONITOR hMonitor, // handle to display monitor |
| | 480 | HDC WXUNUSED(hdcMonitor), // handle to monitor-appropriate device context |
| | 481 | LPRECT WXUNUSED(lprcMonitor), // pointer to monitor intersection rectangle |
| | 482 | LPARAM dwData) // data passed from EnumDisplayMonitors (this) |
| | 483 | { |
| | 484 | wxDisplayFactoryMSW *const self = (wxDisplayFactoryMSW *)dwData; |
| | 485 | |
| | 486 | self->m_displays.Add(hMonitor); |
| | 487 | |
| | 488 | // continue the enumeration |
| | 489 | return TRUE; |
| | 490 | } |
| | 491 | |
| | 492 | wxDisplayImpl *wxDisplayFactoryMSW::CreateDisplay(unsigned n) |
| | 493 | { |
| | 494 | wxCHECK_MSG( n < m_displays.size(), NULL, wxT("An invalid index was passed to wxDisplay") ); |
| | 495 | |
| | 496 | return new wxDisplayMSW(n, m_displays[n]); |
| | 497 | } |
| | 498 | |
| | 499 | // helper for GetFromPoint() and GetFromWindow() |
| | 500 | int wxDisplayFactoryMSW::FindDisplayFromHMONITOR(HMONITOR hmon) const |
| | 501 | { |
| | 502 | if ( hmon ) |
| | 503 | { |
| | 504 | const size_t count = m_displays.size(); |
| | 505 | for ( size_t n = 0; n < count; n++ ) |
| | 506 | { |
| | 507 | if ( hmon == m_displays[n] ) |
| | 508 | return n; |
| | 509 | } |
| | 510 | } |
| | 511 | |
| | 512 | return wxNOT_FOUND; |
| | 513 | } |
| | 514 | |
| | 515 | int wxDisplayFactoryMSW::GetFromPoint(const wxPoint& pt) |
| | 516 | { |
| | 517 | POINT pt2; |
| | 518 | pt2.x = pt.x; |
| | 519 | pt2.y = pt.y; |
| | 520 | |
| | 521 | return FindDisplayFromHMONITOR(gs_MonitorFromPoint(pt2, |
| | 522 | MONITOR_DEFAULTTONULL)); |
| | 523 | } |
| | 524 | |
| | 525 | int wxDisplayFactoryMSW::GetFromWindow(const wxWindow *window) |
| | 526 | { |
| | 527 | return FindDisplayFromHMONITOR(gs_MonitorFromWindow(GetHwndOf(window), |
| | 528 | MONITOR_DEFAULTTONULL)); |
| | 529 | } |
| | 530 | |