/////////////////////////////////////////////////////////////////////////////
// Name:        display.cpp
// Purpose:     MSW Implementation of wxDisplay class
// Author:      Royce Mitchell III
// Modified by:
// Created:     06/21/02
// RCS-ID:      $Id: display.cpp,v 1.1 2002/07/19 20:42:34 JS Exp $
// Copyright:   (c) wxWindows team
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

// ===========================================================================
// declarations
// ===========================================================================

// ---------------------------------------------------------------------------
// headers
// ---------------------------------------------------------------------------

#ifdef __GNUG__
    #pragma implementation "display.h"
#endif

// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

#if wxUSE_DISPLAY

#ifndef WX_PRECOMP
   #include "wx/dynarray.h"
#endif

#include "wx/display.h"

// the following define is necessary to access the multi-monitor function
// declarations in a manner safe to use w/ Windows 95
// JACS: not used for now until we're clear about the legality
// of distributing multimon.h. Meanwhile you can download the file
// yourself from:
// http://www.microsoft.com/msj/0697/monitor/monitortextfigs.htm#fig4

#if 0
#define COMPILE_MULTIMON_STUBS
#include "wx/msw/multimon.h"
#endif

// ---------------------------------------------------------------------------
// constants
// ---------------------------------------------------------------------------

// ---------------------------------------------------------------------------
// private functions
// ---------------------------------------------------------------------------

void wxmswInitDisplayRectArray();

// ----------------------------------------------------------------------------
// private classes
// ----------------------------------------------------------------------------

class wxmswDisplayInfo;

WX_DECLARE_OBJARRAY(wxmswDisplayInfo, wxmswDisplayInfoArray);

class wxmswDisplayInfo
{
public:
	HMONITOR m_hmon;
    DISPLAY_DEVICE m_dd;
    wxRect m_rect;
    int m_depth;
};

wxmswDisplayInfoArray* g_wxmswDisplayInfoArray = 0;

#include <wx/arrimpl.cpp> // this is a magic incantation which must be done!
WX_DEFINE_OBJARRAY(wxmswDisplayInfoArray);

// ===========================================================================
// implementation
// ===========================================================================

BOOL CALLBACK wxmswMonitorEnumProc (
  HMONITOR hMonitor,  // handle to display monitor
  HDC hdcMonitor,     // handle to monitor-appropriate device context
  LPRECT lprcMonitor, // pointer to monitor intersection rectangle
  LPARAM dwData       // data passed from EnumDisplayMonitors
)
{
    wxmswDisplayInfo* info = new wxmswDisplayInfo();
    info->m_hmon = hMonitor;
    info->m_rect.SetX ( lprcMonitor->left );
    info->m_rect.SetY ( lprcMonitor->top );
    info->m_rect.SetWidth ( lprcMonitor->right - lprcMonitor->left );
    info->m_rect.SetHeight ( lprcMonitor->bottom - lprcMonitor->top );
    // now add this monitor to the array
    g_wxmswDisplayInfoArray->Add ( info );

    return TRUE; // continue the enumeration
}

class wxmswDisplayModule : public wxModule
{
    DECLARE_DYNAMIC_CLASS(wxmswDisplayModule)
public:
    wxmswDisplayModule() {}
    bool OnInit();
    void OnExit();
};

IMPLEMENT_DYNAMIC_CLASS(wxmswDisplayModule, wxModule)

bool wxmswDisplayModule::OnInit()
{
    g_wxmswDisplayInfoArray = new wxmswDisplayInfoArray();
    if ( !g_wxmswDisplayInfoArray )
    {
        wxFAIL_MSG(wxT("Couldn't allocate array for display information"));
        return FALSE;
    }

    // Royce3: I'm assuming that the monitor's are enumerated in the same
    // order as the calls to EnumDisplayDevices below. We shall soon see
    // if that assumption is correct.
    if ( !EnumDisplayMonitors ( NULL, NULL, wxmswMonitorEnumProc, 0 ) )
        wxLogLastError(wxT("EnumDisplayMonitors"));

    size_t iDevNum = 0, count = g_wxmswDisplayInfoArray->Count();
    while ( iDevNum < count )
    {
        wxmswDisplayInfo& info = (*g_wxmswDisplayInfoArray)[iDevNum];

        // MSDN: Before calling EnumDisplayDevices, you must initialize the cb
        // member of DISPLAY_DEVICE to the size, in bytes, of DISPLAY_DEVICE
        info.m_dd.cb = sizeof(info.m_dd);

        if ( !EnumDisplayDevices ( NULL, iDevNum, &info.m_dd, 0 ) )
            wxLogLastError(wxT("EnumDisplayDevices"));

        // get this display's Depth
        DEVMODE devmode;
        memset ( &devmode, 0, sizeof(devmode) );

        // MSDN: Before calling EnumDisplaySettings, set the dmSize member to
        // sizeof(DEVMODE), and set the dmDriverExtra member to indicate the size,
        // in bytes, of the additional space available to receive private
        // driver-data.
        devmode.dmSize = sizeof(devmode);
        devmode.dmDriverExtra = 0;

        if ( !EnumDisplaySettings ( info.m_dd.DeviceName, ENUM_CURRENT_SETTINGS, &devmode ) )
        {
            wxLogLastError(wxT("EnumDisplaySettings"));
            devmode.dmFields = 0;
        }

        if ( !(devmode.dmFields&DM_BITSPERPEL) )
            info.m_depth = -1;
        else
            info.m_depth = devmode.dmBitsPerPel;


        iDevNum++;
    }
    return TRUE;
}

void wxmswDisplayModule::OnExit()
{
    size_t count = g_wxmswDisplayInfoArray->Count();
    while ( count-- )
    {
        wxmswDisplayInfo* info = g_wxmswDisplayInfoArray->Detach ( count );
        delete info;
    }
    delete g_wxmswDisplayInfoArray;
    g_wxmswDisplayInfoArray = 0;
}

// ---------------------------------------------------------------------------
// wxDisplay
// ---------------------------------------------------------------------------

size_t wxDisplayBase::GetCount()
{
    return GetSystemMetrics ( SM_CMONITORS );
}

int wxDisplayBase::GetFromPoint ( const wxPoint& pt )
{
    POINT pt2;
    pt2.x = pt.x;
    pt2.y = pt.y;

    HMONITOR hmon = MonitorFromPoint ( pt2, 0 );
    if ( !hmon )
        return -1;
    size_t count = wxDisplayBase::GetCount(), index;

    for ( index = 0; index < count; index++ )
    {
        if ( hmon == (*g_wxmswDisplayInfoArray)[index].m_hmon )
            return index;
    }

    return -1;
}

wxDisplay::wxDisplay ( size_t index ) : wxDisplayBase ( index )
{
}

wxRect wxDisplay::GetGeometry() const
{
    return (*g_wxmswDisplayInfoArray)[m_index].m_rect;
}

int wxDisplay::GetDepth() const
{
    return (*g_wxmswDisplayInfoArray)[m_index].m_depth;
}

wxString wxDisplay::GetName() const
{
    return wxString ( (*g_wxmswDisplayInfoArray)[m_index].m_dd.DeviceName );
}

#endif//wxUSE_DISPLAY
