///////////////////////////////////////////////////////////////////////////////
// Name:        src/os2/toplevel.cpp
// Purpose:     implements wxTopLevelWindow for OS/2
// Author:      Vadim Zeitlin
// Modified by:
// Created:     30.12.01
// RCS-ID:      $Id: toplevel.cpp 40943 2006-08-31 19:31:43Z ABX $
// Copyright:   (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
// License:     wxWindows licence
///////////////////////////////////////////////////////////////////////////////

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

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

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

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

#include "wx/toplevel.h"

#ifndef WX_PRECOMP
    #include "wx/app.h"
    #include "wx/dialog.h"
    #include "wx/string.h"
    #include "wx/log.h"
    #include "wx/intl.h"
    #include "wx/frame.h"
    #include "wx/control.h"
    #include "wx/containr.h"        // wxSetFocusToChild()
    #include "wx/settings.h"
    #include "wx/module.h"        // wxSetFocusToChild()
#endif //WX_PRECOMP

#include "wx/os2/private.h"

// ----------------------------------------------------------------------------
// stubs for missing functions under MicroWindows
// ----------------------------------------------------------------------------


// ----------------------------------------------------------------------------
// globals
// ----------------------------------------------------------------------------

// the name of the default wxWidgets class
extern void wxAssociateWinWithHandle( HWND hWnd, wxWindowOS2* pWin );

bool wxTopLevelWindowOS2::m_sbInitialized = false;
wxWindow* wxTopLevelWindowOS2::m_spHiddenParent = NULL;

// ============================================================================
// wxTopLevelWindowOS2 implementation
// ============================================================================

BEGIN_EVENT_TABLE(wxTopLevelWindowOS2, wxTopLevelWindowBase)
    EVT_ACTIVATE(wxTopLevelWindowOS2::OnActivate)
END_EVENT_TABLE()

// ============================================================================
// wxTopLevelWindowMSW implementation
// ============================================================================

// Dialog window proc
MRESULT EXPENTRY wxDlgProc( HWND WXUNUSED(hWnd)
                           ,UINT uMessage
                           ,void * WXUNUSED(wParam)
                           ,void * WXUNUSED(lParam)
                          )
{
    switch(uMessage)
    {
        case WM_INITDLG:
            //
            // For this message, returning TRUE tells system to set focus to
            // the first control in the dialog box, but we set the focus
            // ourselves, however in OS/2 we must return true to enable the dialog
            //
            return (MRESULT)TRUE;
        default:
            //
            // For all the other ones, FALSE means that we didn't process the
            // message
            //
            return (MRESULT)FALSE;
    }
} // end of wxDlgProc

// ----------------------------------------------------------------------------
// wxTLWHiddenParentModule: used to manage the hidden parent window (we need a
// module to ensure that the window is always deleted)
// ----------------------------------------------------------------------------

class wxTLWHiddenParentModule : public wxModule
{
public:
    //
    // Module init/finalize
    //
    virtual bool OnInit(void);
    virtual void OnExit(void);

    //
    // Get the hidden window (creates on demand)
    //
    static HWND GetHWND(void);

private:
    //
    // The HWND of the hidden parent
    //
    static HWND m_shWnd;

    //
    // The class used to create it
    //
    static const wxChar* m_szClassName;
    DECLARE_DYNAMIC_CLASS(wxTLWHiddenParentModule)
}; // end of CLASS wxTLWHiddenParentModule

IMPLEMENT_DYNAMIC_CLASS(wxTLWHiddenParentModule, wxModule)

// ----------------------------------------------------------------------------
// wxTopLevelWindowOS2 creation
// ----------------------------------------------------------------------------

void wxTopLevelWindowOS2::Init()
{
    m_bIconized = m_bMaximizeOnShow = false;

    //
    // Unlike (almost?) all other windows, frames are created hidden
    //
    m_isShown = false;

    //
    // Data to save/restore when calling ShowFullScreen
    m_lFsStyle          = 0;
    m_lFsOldWindowStyle = 0;
    m_bFsIsMaximized    = false;
    m_bFsIsShowing      = false;

    m_hFrame    = NULLHANDLE;
    memset(&m_vSwp, 0, sizeof(SWP));
    memset(&m_vSwpClient, 0, sizeof(SWP));
    m_pWinLastFocused = (wxWindow *)NULL;
} // end of wxTopLevelWindowIOS2::Init

void wxTopLevelWindowOS2::OnActivate(
  wxActivateEvent&                  rEvent
)
{
    if (rEvent.GetActive())
    {
        //
        // Restore focus to the child which was last focused
        //
        wxLogTrace(_T("focus"), _T("wxTLW %08lx activated."), m_hWnd);

        wxWindow*                   pParent = m_pWinLastFocused ? m_pWinLastFocused->GetParent()
                                                                : NULL;
        if (!pParent)
        {
            pParent = this;
        }

        wxSetFocusToChild( pParent
                          ,&m_pWinLastFocused
                         );
    }
    else // deactivating
    {
        //
        // Remember the last focused child if it is our child
        //
        m_pWinLastFocused = FindFocus();

        //
        // So we NULL it out if it's a child from some other frame
        //
        wxWindow*                   pWin = m_pWinLastFocused;

        while (pWin)
        {
            if (pWin->IsTopLevel())
            {
                if (pWin != this)
                {
                    m_pWinLastFocused = NULL;
                }
                break;
            }
            pWin = pWin->GetParent();
        }

        wxLogTrace(_T("focus"),
                   _T("wxTLW %08lx deactivated, last focused: %08lx."),
                   m_hWnd,
                   m_pWinLastFocused ? GetHwndOf(m_pWinLastFocused)
                                     : NULL);
        rEvent.Skip();
    }
} // end of wxTopLevelWindowOS2::OnActivate

WXDWORD wxTopLevelWindowOS2::OS2GetStyle(
  long                              lStyle
, WXDWORD*                          pdwExflags
) const
{
    long                            lMsflags = wxWindow::OS2GetStyle( (lStyle & ~wxBORDER_MASK) | wxBORDER_NONE
                                                                     ,pdwExflags
                                                                    );

    if ((lStyle & wxDEFAULT_FRAME_STYLE) == wxDEFAULT_FRAME_STYLE)
        lMsflags |= FCF_SIZEBORDER | FCF_TITLEBAR | FCF_SYSMENU |
                    FCF_MINMAX | FCF_TASKLIST;

    if ((lStyle & wxCAPTION) == wxCAPTION)
        lMsflags |= FCF_TASKLIST;
    else
        lMsflags |= FCF_NOMOVEWITHOWNER;

    if ((lStyle & wxVSCROLL) == wxVSCROLL)
        lMsflags |= FCF_VERTSCROLL;
    if ((lStyle & wxHSCROLL) == wxHSCROLL)
        lMsflags |= FCF_HORZSCROLL;
    if (lStyle & wxMINIMIZE_BOX)
        lMsflags |= FCF_MINBUTTON;
    if (lStyle & wxMAXIMIZE_BOX)
        lMsflags |= FCF_MAXBUTTON;
    if (lStyle & wxRESIZE_BORDER)
        lMsflags |= FCF_DLGBORDER;
    if (lStyle & wxSYSTEM_MENU)
        lMsflags |= FCF_SYSMENU;
    if (lStyle & wxCAPTION)
        lMsflags |= FCF_TASKLIST;
    if (lStyle & wxCLIP_CHILDREN)
    {
        // Invalid for frame windows under PM
    }

    if (lStyle & wxTINY_CAPTION_VERT)
        lMsflags |= FCF_TASKLIST;
    if (lStyle & wxTINY_CAPTION_HORIZ)
        lMsflags |= FCF_TASKLIST;

    if ((lStyle & wxRESIZE_BORDER) == 0)
        lMsflags |= FCF_BORDER;
    if (lStyle & wxFRAME_TOOL_WINDOW)
        *pdwExflags = kFrameToolWindow;

    if (lStyle & wxSTAY_ON_TOP)
        lMsflags |= FCF_SYSMODAL;

    return lMsflags;
} // end of wxTopLevelWindowOS2::OS2GetCreateWindowFlags

WXHWND wxTopLevelWindowOS2::OS2GetParent() const
{
    HWND                            hWndParent = NULL;

    //
    // For the frames without wxFRAME_FLOAT_ON_PARENT style we should use NULL
    // parent HWND or it would be always on top of its parent which is not what
    // we usually want (in fact, we only want it for frames with the
    // wxFRAME_FLOAT_ON_PARENT flag)
    //
    if (HasFlag(wxFRAME_FLOAT_ON_PARENT) )
    {
        const wxWindow*             pParent = GetParent();

        if (!pParent)
        {
            //
            // This flag doesn't make sense then and will be ignored
            //
            wxFAIL_MSG( _T("wxFRAME_FLOAT_ON_PARENT but no parent?") );
        }
        else
        {
            hWndParent = GetHwndOf(pParent);
        }
    }
    //else: don't float on parent, must not be owned

    //
    // Now deal with the 2nd taskbar-related problem (see comments above in
    // OS2GetStyle())
    //
    if (HasFlag(wxFRAME_NO_TASKBAR) && !hWndParent)
    {
        //
        // Use hidden parent
        //
        hWndParent = wxTLWHiddenParentModule::GetHWND();
    }
    return (WXHWND)hWndParent;
} // end of wxTopLevelWindowOS2::OS2GetParent


bool wxTopLevelWindowOS2::CreateDialog( ULONG           ulDlgTemplate,
                                        const wxString& WXUNUSED(rsTitle),
                                        const wxPoint&  rPos,
                                        const wxSize&   rSize )
{
    wxWindow*                       pParent = GetParent();

    //
    // For the dialogs without wxDIALOG_NO_PARENT style, use the top level
    // app window as parent - this avoids creating modal dialogs without
    // parent
    //
    if (!pParent && !(GetWindowStyleFlag() & wxDIALOG_NO_PARENT))
    {
        pParent = wxTheApp->GetTopWindow();

        if (pParent)
        {
            //
            // Don't use transient windows as parents, this is dangerous as it
            // can lead to a crash if the parent is destroyed before the child
            //
            // also don't use the window which is currently hidden as then the
            // dialog would be hidden as well
            if ((pParent->GetExtraStyle() & wxWS_EX_TRANSIENT) ||
                 !pParent->IsShown())
            {
                pParent = NULL;
            }
        }
    }

    HWND                            hWndDlg;
    HWND                            hWndOwner;

    if (pParent)
        hWndOwner = GetHwndOf(pParent);
    else
        hWndOwner = HWND_DESKTOP;

    hWndDlg = ::WinLoadDlg( HWND_DESKTOP
                           ,hWndOwner
                           ,(PFNWP)wxDlgProc
                           ,NULL
                           ,(ULONG)ulDlgTemplate
                           ,(PVOID)this
                          );

    m_hWnd = (WXHWND) hWndDlg;

    if ( !m_hWnd )
    {
        wxFAIL_MSG(wxT("Did you forget to include wx/os2/wx.rc in your resources?"));

        wxLogSysError(wxT("Can't create dialog using template '%ld'"), ulDlgTemplate);

        return false;
    }

    //
    // Move the dialog to its initial position without forcing repainting
    //
    int                             nX;
    int                             nY;
    int                             nWidth;
    int                             nHeight;

    if (!OS2GetCreateWindowCoords( rPos
                                  ,rSize
                                  ,nX
                                  ,nY
                                  ,nWidth
                                  ,nHeight
                                 ))
    {
        nX = nWidth = (int)CW_USEDEFAULT;
    }

    //
    // We can't use CW_USEDEFAULT here as we're not calling CreateWindow()
    // and passing CW_USEDEFAULT to MoveWindow() results in resizing the
    // window to (0, 0) size which breaks quite a lot of things, e.g. the
    // sizer calculation in wxSizer::Fit()
    //
    if (nWidth == (int)CW_USEDEFAULT)
    {
        //
        // The exact number doesn't matter, the dialog will be resized
        // again soon anyhow but it should be big enough to allow
        // calculation relying on "totalSize - clientSize > 0" work, i.e.
        // at least greater than the title bar height
        //
        nWidth = nHeight = 100;
    }
    if (nX == (int)CW_USEDEFAULT)
    {
        //
        // Centre it on the screen - what else can we do?
        //
        wxSize                      vSizeDpy = wxGetDisplaySize();

        nX = (vSizeDpy.x - nWidth) / 2;
        nY = (vSizeDpy.y - nHeight) / 2;
    }
    SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE));

    LONG                            lColor = (LONG)m_backgroundColour.GetPixel();

    if (!::WinSetPresParam( m_hWnd
                           ,PP_BACKGROUNDCOLOR
                           ,sizeof(LONG)
                           ,(PVOID)&lColor
                          ))
    {
        return false;
    }

    // Convert to OS/2 coordinates
    nY = GetOS2ParentHeight(pParent) - nY - nHeight;

    ::WinSetWindowPos( GetHwnd()
                      ,HWND_TOP
                      ,nX
                      ,nY
                      ,nWidth
                      ,nHeight
                      ,SWP_MOVE | SWP_SIZE | SWP_ZORDER | SWP_SHOW | SWP_ACTIVATE
                     );
    ::WinQueryWindowPos(GetHwnd(), GetSwp());
    m_hFrame = m_hWnd;
    SubclassWin(m_hWnd);
    return true;
} // end of wxTopLevelWindowOS2::CreateDialog

bool wxTopLevelWindowOS2::CreateFrame( const wxString& rsTitle,
                                       const wxPoint& rPos,
                                       const wxSize& rSize )
{
    WXDWORD    lExflags;
    WXDWORD    lFlags = OS2GetCreateWindowFlags(&lExflags);
    long       lStyle = GetWindowStyleFlag();
    int        nX = rPos.x;
    int        nY = rPos.y;
    int        nWidth = rSize.x;
    int        nHeight = rSize.y;
    ULONG      ulStyleFlags = 0L;
    ERRORID    vError;
    wxString   sError;
    wxWindow*  pParent = GetParent();
    HWND       hParent;
    HWND       hFrame;
    HWND       hClient;

    if (pParent)
        hParent = GetHwndOf(pParent);
    else
        hParent = HWND_DESKTOP;

    if ((lStyle & wxMINIMIZE) || (lStyle & wxICONIZE))
        ulStyleFlags |= WS_MINIMIZED;
    if (lStyle & wxMAXIMIZE)
        ulStyleFlags |= WS_MAXIMIZED;

    //
    // Clear the visible flag, we always call show
    //
    ulStyleFlags &= (unsigned long)~WS_VISIBLE;
    m_bIconized = false;

    //
    // Create the frame window:  We break ranks with other ports now
    // and instead of calling down into the base wxWindow class' OS2Create
    // we do all our own stuff here.  We will set the needed pieces
    // of wxWindow manually, here.
    //

     hFrame = ::WinCreateStdWindow( hParent
                                   ,ulStyleFlags          // frame-window style
                                   ,(PULONG)&lFlags       // window style
                                   ,(PSZ)wxFrameClassName // class name
                                   ,(PSZ)rsTitle.c_str()  // window title
                                   ,0L                    // default client style
                                   ,NULLHANDLE            // resource in executable file
                                   ,0                     // resource id
                                   ,&hClient              // receives client window handle
                                  );
    if (!hFrame)
    {
        vError = ::WinGetLastError(vHabmain);
        sError = wxPMErrorToStr(vError);
        wxLogError(_T("Error creating frame. Error: %s\n"), sError.c_str());
        return false;
    }

    //
    // wxWindow class' m_hWnd set here and needed associations
    //
    m_hFrame = hFrame;
    m_hWnd   = hClient;
    wxAssociateWinWithHandle(m_hWnd, this);
    wxAssociateWinWithHandle(m_hFrame, this);

    SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE));

    LONG                            lColor = (LONG)m_backgroundColour.GetPixel();

    if (!::WinSetPresParam( m_hWnd
                           ,PP_BACKGROUNDCOLOR
                           ,sizeof(LONG)
                           ,(PVOID)&lColor
                          ))
    {
        vError = ::WinGetLastError(vHabmain);
        sError = wxPMErrorToStr(vError);
        wxLogError(_T("Error creating frame. Error: %s\n"), sError.c_str());
        return false;
    }

    //
    // Now need to subclass window.  Instead of calling the SubClassWin in wxWindow
    // we manually subclass here because we don't want to use the main wxWndProc
    // by default
    //
    m_fnOldWndProc = (WXFARPROC) ::WinSubclassWindow(m_hFrame, (PFNWP)wxFrameMainWndProc);

    //
    // Now size everything.  If adding a menu the client will need to be resized.
    //

    if (!OS2GetCreateWindowCoords( rPos
                                  ,rSize
                                  ,nX
                                  ,nY
                                  ,nWidth
                                  ,nHeight
                                 ))
    {
        nX = nWidth = (int)CW_USEDEFAULT;
    }

    //
    // We can't use CW_USEDEFAULT here as we're not calling CreateWindow()
    // and passing CW_USEDEFAULT to MoveWindow() results in resizing the
    // window to (0, 0) size which breaks quite a lot of things, e.g. the
    // sizer calculation in wxSizer::Fit()
    //
    if (nWidth == (int)CW_USEDEFAULT)
    {
       //
        // The exact number doesn't matter, the dialog will be resized
        // again soon anyhow but it should be big enough to allow
        // calculation relying on "totalSize - clientSize > 0" work, i.e.
        // at least greater than the title bar height
        //
        nWidth = nHeight = 100;
    }
    if (nX == (int)CW_USEDEFAULT)
    {
        //
        // Centre it on the screen for now - what else can we do?
        // TODO: We could try FCF_SHELLPOSITION but it will require moving
        //       things around a bit.
        //
        wxSize                      vSizeDpy = wxGetDisplaySize();

        nX = (vSizeDpy.x - nWidth) / 2;
        nY = (vSizeDpy.y - nHeight) / 2;
    }

    // Convert to OS/2 coordinates
    nY = GetOS2ParentHeight(pParent) - nY - nHeight;

    if (!::WinSetWindowPos( m_hFrame
                           ,HWND_TOP
                           ,nX
                           ,nY
                           ,nWidth
                           ,nHeight
                           ,SWP_SIZE | SWP_MOVE | SWP_ACTIVATE | SWP_ZORDER
                          ))
    {
        vError = ::WinGetLastError(vHabmain);
        sError = wxPMErrorToStr(vError);
        wxLogError(_T("Error sizing frame. Error: %s\n"), sError.c_str());
        return false;
    }
    lStyle =  ::WinQueryWindowULong( m_hWnd
                                    ,QWL_STYLE
                                   );
    lStyle |= WS_CLIPCHILDREN;
    ::WinSetWindowULong( m_hWnd
                        ,QWL_STYLE
                        ,lStyle
                       );
    return true;
} // end of wxTopLevelWindowOS2::CreateFrame

bool wxTopLevelWindowOS2::Create(
  wxWindow*                         pParent
, wxWindowID                        vId
, const wxString&                   rsTitle
, const wxPoint&                    rPos
, const wxSize&                     rSizeOrig
, long                              lStyle
, const wxString&                   rsName
)
{
    //
    // Init our fields
    //
    Init();
    m_windowStyle = lStyle;
    SetName(rsName);
    m_windowId = vId == -1 ? NewControlId() : vId;

    // always create a frame of some reasonable, even if arbitrary, size (at
    // least for MSW compatibility)
    wxSize rSize = rSizeOrig;
    if ( rSize.x == -1 || rSize.y == -1 )
    {
        wxSize sizeDpy = wxGetDisplaySize();
        if ( rSize.x == -1 )
            rSize.x = sizeDpy.x / 3;
        if ( rSize.y == -1 )
            rSize.y = sizeDpy.y / 5;
    }

    wxTopLevelWindows.Append(this);
    if (pParent)
        pParent->AddChild(this);

    if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)
    {
        //
        // We have different dialog templates to allow creation of dialogs
        // with & without captions under OS2indows, resizeable or not (but a
        // resizeable dialog always has caption - otherwise it would look too
        // strange)
        //
        ULONG                       ulDlgTemplate;

        if (lStyle & wxRESIZE_BORDER)
            ulDlgTemplate = (ULONG)kResizeableDialog;
        else if (lStyle & wxCAPTION)
            ulDlgTemplate = (ULONG)kCaptionDialog;
        else
            ulDlgTemplate = (ULONG)kNoCaptionDialog;
        return CreateDialog( ulDlgTemplate
                            ,rsTitle
                            ,rPos
                            ,rSize
                           );
    }
    else // !dialog
    {
        return CreateFrame( rsTitle
                           ,rPos
                           ,rSize
                          );
    }
} // end of wxTopLevelWindowOS2::Create

wxTopLevelWindowOS2::~wxTopLevelWindowOS2()
{
    //
    // After destroying an owned window, Windows activates the next top level
    // window in Z order but it may be different from our owner (to reproduce
    // this simply Alt-TAB to another application and back before closing the
    // owned frame) whereas we always want to yield activation to our parent
    //
    if (HasFlag(wxFRAME_FLOAT_ON_PARENT))
    {
        wxWindow*                   pParent = GetParent();

        if (pParent)
        {
            ::WinSetWindowPos( GetHwndOf(pParent)
                              ,HWND_TOP
                              ,0, 0, 0, 0
                              ,SWP_ZORDER
                             );
        }
    }
} // end of wxTopLevelWindowOS2::~wxTopLevelWindowOS2

// ----------------------------------------------------------------------------
// wxTopLevelWindowOS2 client size
// ----------------------------------------------------------------------------

void wxTopLevelWindowOS2::DoSetClientSize(
  int                               nWidth
, int                               nHeight
)
{
    //
    // Call GetClientAreaOrigin() to take the toolbar into account
    //
    wxPoint                         vPt = GetClientAreaOrigin();

    nWidth  += vPt.x;
    nHeight += vPt.y;

    wxWindow::DoSetClientSize( nWidth
                              ,nHeight
                             );
} // end of wxTopLevelWindowOS2::DoSetClientSize

void wxTopLevelWindowOS2::DoGetClientSize(
  int*                              pnX
, int*                              pnY
) const
{
    wxWindow::DoGetClientSize( pnX
                              ,pnY
                             );

    wxPoint                         vPt = GetClientAreaOrigin();

    if (pnX)
        *pnX -= vPt.x;

    if (pnY)
        *pnY += vPt.y;
} // end of wxTopLevelWindowOS2::DoGetClientSize

// ----------------------------------------------------------------------------
// wxTopLevelWindowOS2 showing
// ----------------------------------------------------------------------------

void wxTopLevelWindowOS2::DoShowWindow(
  int                               nShowCmd
)
{
    ::WinShowWindow(m_hFrame, (BOOL)(nShowCmd & SWP_SHOW));

    //
    // Need to artificially send a size event as wxApps often expect to do some
    // final child control sizing
    SendSizeEvent();
    m_bIconized = nShowCmd == SWP_MINIMIZE;
} // end of wxTopLevelWindowOS2::DoShowWindow

bool wxTopLevelWindowOS2::Show( bool bShow )
{
    int nShowCmd;
    SWP vSwp;

    if (bShow != IsShown() )
    {
        m_isShown = bShow;
    }
    else
    {
        return false;
    }
    if (bShow)
    {
        if (m_bMaximizeOnShow)
        {
            nShowCmd = SWP_MAXIMIZE;
            m_bMaximizeOnShow = false;
        }
        else
        {
            nShowCmd = SWP_SHOW;
        }
    }
    else // hide
    {
        nShowCmd = SWP_HIDE;
    }
    DoShowWindow(nShowCmd);

    if (bShow)
    {
        wxActivateEvent vEvent(wxEVT_ACTIVATE, true, m_windowId);

        ::WinQueryWindowPos(m_hFrame, &vSwp);
        m_bIconized = ( vSwp.fl & SWP_MINIMIZE ) == SWP_MINIMIZE ;
        ::WinQueryWindowPos(m_hWnd, &m_vSwpClient);
        ::WinSendMsg(m_hFrame, WM_UPDATEFRAME, (MPARAM)~0, 0);
        ::WinQueryWindowPos(m_hWnd, &vSwp);
        ::WinEnableWindow(m_hFrame, TRUE);

        vEvent.SetEventObject(this);
        GetEventHandler()->ProcessEvent(vEvent);
    }
    else
    {
        //
        // Try to highlight the correct window (the parent)
        //
        if (GetParent())
        {
            HWND hWndParent = GetHwndOf(GetParent());

            ::WinQueryWindowPos(hWndParent, &vSwp);
            m_bIconized = (vSwp.fl & SWP_MINIMIZE)==SWP_MINIMIZE;
            ::WinEnableWindow(hWndParent, TRUE);
        }
    }
    return true;
} // end of wxTopLevelWindowOS2::Show

// ----------------------------------------------------------------------------
// wxTopLevelWindowOS2 maximize/minimize
// ----------------------------------------------------------------------------

void wxTopLevelWindowOS2::Maximize(
  bool                              bMaximize
)
{
    if (IsShown())
    {
        //
        // Just maximize it directly
        //
        DoShowWindow(bMaximize ? SWP_MAXIMIZE : SWP_RESTORE);
    }
    else // hidden
    {
        //
        // We can't maximize the hidden frame because it shows it as well, so
        // just remember that we should do it later in this case
        //
        m_bMaximizeOnShow = bMaximize;
    }
} // end of wxTopLevelWindowOS2::Maximize

bool wxTopLevelWindowOS2::IsMaximized() const
{
    ::WinQueryWindowPos(m_hFrame, (PSWP)&m_vSwp);
    return (m_vSwp.fl & SWP_MAXIMIZE) == SWP_MAXIMIZE;
} // end of wxTopLevelWindowOS2::IsMaximized

void wxTopLevelWindowOS2::SetTitle( const wxString& title)
{
    SetLabel(title);
}

wxString wxTopLevelWindowOS2::GetTitle() const
{
    return GetLabel();
}

void wxTopLevelWindowOS2::Iconize( bool bIconize )
{
    DoShowWindow(bIconize ? SWP_MINIMIZE : SWP_RESTORE);
} // end of wxTopLevelWindowOS2::Iconize

bool wxTopLevelWindowOS2::IsIconized() const
{
    // also update the current state
    ::WinQueryWindowPos(m_hFrame, (PSWP)&m_vSwp);
    if (m_vSwp.fl & SWP_MINIMIZE)
        ((wxTopLevelWindow*)this)->m_bIconized = true;
    else
        ((wxTopLevelWindow*)this)->m_bIconized = false;
    return m_bIconized;
} // end of wxTopLevelWindowOS2::IsIconized

void wxTopLevelWindowOS2::Restore()
{
    DoShowWindow(SWP_RESTORE);
} // end of wxTopLevelWindowOS2::Restore

// generate an artificial resize event
void wxTopLevelWindowOS2::SendSizeEvent()
{
    if (!m_bIconized)
    {
        RECTL                       vRect = wxGetWindowRect(GetHwnd());

        (void)::WinPostMsg( m_hFrame
                           ,WM_SIZE
                           ,MPFROM2SHORT(vRect.xRight - vRect.xLeft, vRect.yTop - vRect.yBottom)
                           ,MPFROM2SHORT(vRect.xRight - vRect.xLeft, vRect.yTop - vRect.yBottom)
                          );
    }
} // end of wxTopLevelWindowOS2::SendSizeEvent

// ----------------------------------------------------------------------------
// wxTopLevelWindowOS2 fullscreen
// ----------------------------------------------------------------------------

bool wxTopLevelWindowOS2::ShowFullScreen( bool bShow,
                                          long lStyle )
{
    if (bShow)
    {
        if (IsFullScreen())
            return false;

        m_bFsIsShowing = true;
        m_lFsStyle = lStyle;

        //
        // Zap the frame borders
        //

        //
        // Save the 'normal' window lStyle
        //
        m_lFsOldWindowStyle = ::WinQueryWindowULong( (HWND)GetHWND()
                                                    ,QWL_STYLE
                                                   );

        //
        // Save the old position, width & height, maximize state
        //
        m_vFsOldSize = GetRect();
        m_bFsIsMaximized = IsMaximized();

        //
        // Decide which window lStyle flags to turn off
        //
        LONG lNewStyle = m_lFsOldWindowStyle;
        LONG lOffFlags = 0;

        if (lStyle & wxFULLSCREEN_NOBORDER)
            lOffFlags |= FCF_BORDER;
        if (lStyle & wxFULLSCREEN_NOCAPTION)
            lOffFlags |= (FCF_TASKLIST | FCF_SYSMENU);

        lNewStyle &= (~lOffFlags);

        //
        // Change our window style to be compatible with full-screen mode
        //
        ::WinSetWindowULong( (HWND)GetHWND()
                            ,QWL_STYLE
                            ,lNewStyle
                           );

        //
        // Resize to the size of the desktop
        //
        int   nWidth;
        int   nHeight;
        RECTL vRect = wxGetWindowRect(HWND_DESKTOP);

        nWidth = vRect.xRight - vRect.xLeft;
        nHeight = vRect.yTop - vRect.yBottom;

        SetSize( nWidth, nHeight );

        //
        // Now flush the window style cache and actually go full-screen
        //
        ::WinSetWindowPos( m_hFrame
                          ,HWND_TOP
                          ,0
                          ,0
                          ,nWidth
                          ,nHeight
                          ,SWP_SIZE | SWP_MOVE
                         );

        wxSize full( nWidth, nHeight );
        wxSizeEvent vEvent( full, GetId() );
        GetEventHandler()->ProcessEvent(vEvent);
        return true;
    }
    else
    {
        if (!IsFullScreen())
            return false;

        m_bFsIsShowing = false;
        Maximize(m_bFsIsMaximized);
        ::WinSetWindowULong( (HWND)GetHWND()
                            ,QWL_STYLE
                            ,m_lFsOldWindowStyle
                           );
        ::WinSetWindowPos( m_hFrame
                          ,HWND_TOP
                          ,m_vFsOldSize.x
                          ,m_vFsOldSize.y
                          ,m_vFsOldSize.width
                          ,m_vFsOldSize.height
                          ,SWP_SIZE | SWP_MOVE
                         );
        return true;
    }
} // end of wxTopLevelWindowOS2::ShowFullScreen

// ----------------------------------------------------------------------------
// wxTopLevelWindowOS2 misc
// ----------------------------------------------------------------------------

void wxTopLevelWindowOS2::SetIcon(
  const wxIcon&                     rIcon
)
{
    SetIcons(wxIconBundle(rIcon));
} // end of wxTopLevelWindowOS2::SetIcon

void wxTopLevelWindowOS2::SetIcons(
  const wxIconBundle&               rIcons
)
{
    //
    // This sets m_icon
    //
    wxTopLevelWindowBase::SetIcons(rIcons);

    const wxIcon&                   vIcon = rIcons.GetIcon(wxSize(32, 32));

    if (vIcon.Ok() && vIcon.GetWidth() == 32 && vIcon.GetHeight() == 32)
    {
        ::WinSendMsg( m_hFrame
                     ,WM_SETICON
                     ,(MPARAM)((HPOINTER)vIcon.GetHICON())
                     ,NULL
                    );
        ::WinSendMsg( m_hFrame
                     ,WM_UPDATEFRAME
                     ,(MPARAM)FCF_ICON
                     ,(MPARAM)0
                    );
    }
} // end of wxTopLevelWindowOS2::SetIcon

bool wxTopLevelWindowOS2::EnableCloseButton( bool bEnable )
{
    //
    // Get system (a.k.a. window) menu
    //
    HMENU hMenu = ::WinWindowFromID(m_hFrame, FID_SYSMENU);

    if (!hMenu)
    {
        wxLogLastError(_T("GetSystemMenu"));
        return false;
    }

    //
    // Enabling/disabling the close item from it also automatically
    // disables/enables the close title bar button
    //
    if (bEnable)
        (void)::WinSendMsg( hMenu
                           ,MM_SETITEMATTR
                           ,MPFROM2SHORT(SC_CLOSE, FALSE)
                           ,MPFROM2SHORT(MIA_DISABLED, FALSE)
                          );
    else
        (void)::WinSendMsg( hMenu
                           ,MM_SETITEMATTR
                           ,MPFROM2SHORT(SC_CLOSE, FALSE)
                           ,MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED)
                          );

    //
    // Update appearance immediately
    //
    ::WinSendMsg( m_hFrame
                 ,WM_UPDATEFRAME
                 ,(MPARAM)FCF_MENU
                 ,(MPARAM)0
                );
    return true;
} // end of wxTopLevelWindowOS2::EnableCloseButton

// ============================================================================
// wxTLWHiddenParentModule implementation
// ============================================================================

HWND          wxTLWHiddenParentModule::m_shWnd = NULL;
const wxChar* wxTLWHiddenParentModule::m_szClassName = NULL;

bool wxTLWHiddenParentModule::OnInit()
{
    m_shWnd = NULL;
    m_szClassName = NULL;
    return true;
} // end of wxTLWHiddenParentModule::OnInit

void wxTLWHiddenParentModule::OnExit()
{
    if (m_shWnd)
    {
        if (!::WinDestroyWindow(m_shWnd))
        {
            wxLogLastError(_T("DestroyWindow(hidden TLW parent)"));
        }
        m_shWnd = NULL;
    }

    m_szClassName = NULL;
} // end of wxTLWHiddenParentModule::OnExit

/* static */
HWND wxTLWHiddenParentModule::GetHWND()
{
    if (!m_shWnd)
    {
        if (!m_szClassName)
        {
            static const wxChar*    zHIDDEN_PARENT_CLASS = _T("wxTLWHiddenParent");

            if (!::WinRegisterClass( wxGetInstance()
                                    ,(PSZ)zHIDDEN_PARENT_CLASS
                                    ,NULL
                                    ,0
                                    ,sizeof(ULONG)
                                   ))
            {
                wxLogLastError(_T("RegisterClass(\"wxTLWHiddenParent\")"));
            }
            else
            {
                m_szClassName = zHIDDEN_PARENT_CLASS;
            }
        }
        m_shWnd = ::WinCreateWindow( HWND_DESKTOP,
                                     (PSZ)m_szClassName,
                                     "",
                                     0L,
                                     (LONG)0L,
                                     (LONG)0L,
                                     (LONG)0L,
                                     (LONG)0L,
                                     NULLHANDLE,
                                     HWND_TOP,
                                     0L,
                                     NULL,
                                     NULL );
        if (!m_shWnd)
        {
            wxLogLastError(_T("CreateWindow(hidden TLW parent)"));
        }
    }
    return m_shWnd;
} // end of wxTLWHiddenParentModule::GetHWND
