From f45e4fad134eb296566ba1b35a9b716c52c11e6a Mon Sep 17 00:00:00 2001 From: David Webster Date: Mon, 7 Jan 2002 00:49:52 +0000 Subject: [PATCH] Toplevel window support git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@13431 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- src/os2/toplevel.cpp | 887 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 887 insertions(+) create mode 100644 src/os2/toplevel.cpp diff --git a/src/os2/toplevel.cpp b/src/os2/toplevel.cpp new file mode 100644 index 0000000000..ced8e43b34 --- /dev/null +++ b/src/os2/toplevel.cpp @@ -0,0 +1,887 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: msw/toplevel.cpp +// Purpose: implements wxTopLevelWindow for MSW +// Author: Vadim Zeitlin +// Modified by: +// Created: 30.12.01 +// RCS-ID: $Id$ +// Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com) +// License: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#ifdef __GNUG__ + #pragma implementation "toplevel.h" +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/toplevel.h" + #include "wx/string.h" + #include "wx/log.h" + #include "wx/intl.h" + #include "wx/frame.h" +#endif //WX_PRECOMP + +#include "wx/os2/private.h" + +// ---------------------------------------------------------------------------- +// stubs for missing functions under MicroWindows +// ---------------------------------------------------------------------------- + + +// ---------------------------------------------------------------------------- +// globals +// ---------------------------------------------------------------------------- + +// list of all frames and modeless dialogs +wxWindowList wxModelessWindows; + +// the name of the default wxWindows class +extern const wxChar* wxCanvasClassName; +extern const wxChar* wxFrameClassName; + +// ============================================================================ +// wxTopLevelWindowMSW implementation +// ============================================================================ + +// Dialog window proc +MRESULT EXPENTRY wxDlgProc( HWND WXUNUSED(hWnd) + ,UINT uMessage + ,MPARAM WXUNUSED(wParam) + ,MPARAM WXUNUSED(lParam) + ) +{ + if (uMessage == WM_INITDLG) + { + // + // For this message, returning TRUE tells system to set focus to the + // first control in the dialog box. + // + return (MRESULT)TRUE; + } + else + { + // + // For all the other ones, FALSE means that we didn't process the + // message + // + return (MRESULT)FALSE; + } +} // end of wxDlgProc + +// ---------------------------------------------------------------------------- +// 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)); +} // end of wxTopLevelWindowIOS2::Init + +long wxTopLevelWindowOS2::OS2GetCreateWindowFlags( + long* plExflags +) const +{ + long lStyle = GetWindowStyle(); + long lMsflags = 0; + + if (lStyle == wxDEFAULT_FRAME_STYLE) + lMsflags = FCF_SIZEBORDER | FCF_TITLEBAR | FCF_SYSMENU | + FCF_MINMAX | FCF_TASKLIST; + else + { + 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 & wxTHICK_FRAME) + 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 & wxTHICK_FRAME) == 0) + lMsflags |= FCF_BORDER; + if (lStyle & wxFRAME_TOOL_WINDOW) + *plExflags = kFrameToolWindow; + + if (lStyle & wxSTAY_ON_TOP) + lMsflags |= FCF_SYSMODAL; + } + return lMsflags; +} // end of wxTopLevelWindowOS2::OS2GetCreateWindowFlags + +bool wxTopLevelWindowOS2::CreateDialog( + ULONG ulDlgTemplate +, const wxString& 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 hWndParent; + + if (pParent) + hWndParent = GetHwndOf(pParent); + else + hWndParent = HWND_DESKTOP; + + hWndDlg = ::WinLoadDlg( hWndParent + ,hWndParent + ,(PFNWP)wxDlgProc + ,NULL + ,(ULONG)ulDlgTemplate + ,(PVOID)this + ); + + m_hWnd = (WXHWND) hWndDlg; + + if ( !m_hWnd ) + { + wxFAIL_MSG(_("Did you forget to include wx/os2/wx.rc in your resources?")); + + wxLogSysError(_("Can't create dialog using template '%ul'"), 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; + } + ::WinSetWindowPos( GetHwnd() + ,HWND_TOP + ,nX + ,nY + ,nWidth + ,nHeight + ,SWP_MOVE | SWP_SIZE | SWP_ZORDER | SWP_SHOW + ); + if (!rsTitle.IsNull()) + { + ::WinSetWindowText(GetHwnd(), rsTitle.c_str()); + } + SubclassWin(m_hWnd); + return TRUE; +} // end of wxTopLevelWindowOS2::CreateDialog + +bool wxTopLevelWindowOS2::CreateFrame( + const wxString& rsTitle +, const wxPoint& rPos +, const wxSize& rSize +) +{ + long lExflags; + long 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("Error creating frame. Error: %s\n", sError); + 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); + + m_backgroundColour.Set(wxString("GREY")); + + LONG lColor = (LONG)m_backgroundColour.GetPixel(); + + if (!::WinSetPresParam( m_hWnd + ,PP_BACKGROUNDCOLOR + ,sizeof(LONG) + ,(PVOID)&lColor + )) + { + vError = ::WinGetLastError(vHabmain); + sError = wxPMErrorToStr(vError); + wxLogError("Error creating frame. Error: %s\n", sError); + 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 (pParent) + { + nY = pParent->GetSize().y - (nY + nHeight); + } + else + { + RECTL vRect; + + ::WinQueryWindowRect(HWND_DESKTOP, &vRect); + nY = vRect.yTop - (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("Error sizing frame. Error: %s\n", sError); + return FALSE; + } + return TRUE; +} // end of wxTopLevelWindowOS2::CreateFrame + +bool wxTopLevelWindowOS2::Create( + wxWindow* pParent +, wxWindowID vId +, const wxString& rsTitle +, const wxPoint& rPos +, const wxSize& rSize +, long lStyle +, const wxString& rsName +) +{ + // + // Init our fields + // + Init(); + m_windowStyle = lStyle; + SetName(rsName); + m_windowId = vId == -1 ? NewControlId() : vId; + wxTopLevelWindows.Append(this); + if (pParent) + pParent->AddChild(this); + + if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG) + { + // + // We have different dialog templates to allows 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() +{ + wxTopLevelWindows.DeleteObject(this); + + if (wxModelessWindows.Find(this)) + wxModelessWindows.DeleteObject(this); + + // + // If this is the last top-level window, exit. + // + if (wxTheApp && (wxTopLevelWindows.Number() == 0)) + { + wxTheApp->SetTopWindow(NULL); + if ( wxTheApp->GetExitOnFrameDelete() ) + { + ::WinPostMsg(NULL, WM_QUIT, 0, 0); + } + } +} // end of wxTopLevelWindowOS2::~wxTopLevelWindowOS2 + +// +// IF we have child controls in the Frame's client we need to alter +// the y position, because, OS/2 controls are positioned relative to +// wxWindows orgin (top left) not the OS/2 origin (bottom left) +// +void wxTopLevelWindowOS2::AlterChildPos() +{ + // + // OS/2 is the only OS concerned about this + // + wxWindow* pChild = NULL; + wxControl* pCtrl = NULL; + RECTL vRect; + SWP vSwp; + + ::WinQueryWindowRect(GetHwnd(), &vRect); + for (wxWindowList::Node* pNode = GetChildren().GetFirst(); + pNode; + pNode = pNode->GetNext()) + { + wxWindow* pChild = pNode->GetData(); + + ::WinQueryWindowPos(pChild->GetHWND(), &vSwp); + vSwp.y += (vRect.yTop - m_vSwpClient.cy); + if (pChild->IsKindOf(CLASSINFO(wxControl))) + { + pCtrl = wxDynamicCast(pChild, wxControl); + // + // Must deal with controls that have margins like ENTRYFIELD. The SWP + // struct of such a control will have and origin offset from its intended + // position by the width of the margins. + // + vSwp.y -= pCtrl->GetYComp(); + vSwp.x -= pCtrl->GetXComp(); + } + ::WinSetWindowPos( pChild->GetHWND() + ,HWND_TOP + ,vSwp.x + ,vSwp.y + ,vSwp.cx + ,vSwp.cy + ,SWP_MOVE + ); + ::WinQueryWindowPos(pChild->GetHWND(), &vSwp); + pChild = NULL; + } + ::WinQueryWindowPos(GetHwnd(), &m_vSwpClient); +} // end of wxTopLevelWindowOS2::AlterChildPos + +// ---------------------------------------------------------------------------- +// 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); + m_bIconized = nShowCmd == SWP_MINIMIZE; +} // end of wxTopLevelWindowOS2::DoShowWindow + +bool wxTopLevelWindowOS2::Show( + bool bShow +) +{ + int nShowCmd; + SWP vSwp; + RECTL vRect; + + if (bShow) + { + if (m_bMaximizeOnShow) + { + nShowCmd = SWP_SHOW; + m_bMaximizeOnShow = FALSE; + } + else + { + nShowCmd = SWP_HIDE; + } + } + 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; + ::WinQueryWindowPos(m_hWnd, &m_vSwpClient); + ::WinSendMsg(m_hFrame, WM_UPDATEFRAME, (MPARAM)~0, 0); + ::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; + if (hWndParent) + ::WinSetWindowPos( hWndParent + ,HWND_TOP + ,vSwp.x + ,vSwp.y + ,vSwp.cx + ,vSwp.cy + ,SWP_ZORDER | SWP_ACTIVATE | SWP_SHOW | SWP_MOVE + ); + ::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 = TRUE; + } +} // end of wxTopLevelWindowOS2::Maximize + +bool wxTopLevelWindowOS2::IsMaximized() const +{ + bool bIconic; + + ::WinQueryWindowPos(m_hFrame, (PSWP)&m_vSwp); + return (m_vSwp.fl & SWP_MAXIMIZE); +} // end of wxTopLevelWindowOS2::IsMaximized + +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 + +// ---------------------------------------------------------------------------- +// 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 + ); + + wxSizeEvent vEvent( wxSize( nWidth + ,nHeight + ) + ,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 +) +{ + // + // This sets m_icon + // + wxTopLevelWindowBase::SetIcon(rIcon); + + if (m_icon.Ok()) + { + ::WinSendMsg( m_hFrame + ,WM_SETICON + ,(MPARAM)((HPOINTER)m_icon.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 + -- 2.47.2