// Created: 30.12.01
// RCS-ID: $Id$
// Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
-// License: wxWindows license
+// License: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// ============================================================================
#include "wx/intl.h"
#include "wx/frame.h"
#include "wx/control.h"
+ #include "wx/containr.h" // wxSetFocusToChild()
#endif //WX_PRECOMP
+#include "wx/module.h" // wxSetFocusToChild()
#include "wx/os2/private.h"
// ----------------------------------------------------------------------------
,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
- ,MPARAM WXUNUSED(wParam)
- ,MPARAM WXUNUSED(lParam)
+ ,void * WXUNUSED(wParam)
+ ,void * WXUNUSED(lParam)
)
{
- if (uMessage == WM_INITDLG)
+ switch(uMessage)
{
- //
- // 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;
+ 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
// ----------------------------------------------------------------------------
m_hFrame = NULLHANDLE;
memset(&m_vSwp, 0, sizeof(SWP));
memset(&m_vSwpClient, 0, sizeof(SWP));
+ m_pWinLastFocused = (wxWindow *)NULL;
} // end of wxTopLevelWindowIOS2::Init
-long wxTopLevelWindowOS2::OS2GetCreateWindowFlags(
- long* plExflags
+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 lStyle = GetWindowStyle();
- long lMsflags = 0;
+ long lMsflags = wxWindow::OS2GetStyle( (lStyle & ~wxBORDER_MASK) | wxBORDER_NONE
+ ,pdwExflags
+ );
if (lStyle == wxDEFAULT_FRAME_STYLE)
- lMsflags = FCF_SIZEBORDER | FCF_TITLEBAR | FCF_SYSMENU |
- FCF_MINMAX | FCF_TASKLIST;
+ lMsflags |= FCF_SIZEBORDER | FCF_TITLEBAR | FCF_SYSMENU |
+ FCF_MINMAX | FCF_TASKLIST;
else
{
if ((lStyle & wxCAPTION) == wxCAPTION)
- lMsflags = FCF_TASKLIST;
+ lMsflags |= FCF_TASKLIST;
else
- lMsflags = FCF_NOMOVEWITHOWNER;
+ lMsflags |= FCF_NOMOVEWITHOWNER;
if ((lStyle & wxVSCROLL) == wxVSCROLL)
lMsflags |= FCF_VERTSCROLL;
if ((lStyle & wxTHICK_FRAME) == 0)
lMsflags |= FCF_BORDER;
if (lStyle & wxFRAME_TOOL_WINDOW)
- *plExflags = kFrameToolWindow;
+ *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& rsTitle
if ( !m_hWnd )
{
- wxFAIL_MSG(_("Did you forget to include wx/os2/wx.rc in your resources?"));
+ wxFAIL_MSG(wxT("Did you forget to include wx/os2/wx.rc in your resources?"));
- wxLogSysError(_("Can't create dialog using template '%ul'"), ulDlgTemplate);
+ wxLogSysError(wxT("Can't create dialog using template '%ld'"), ulDlgTemplate);
return FALSE;
}
,nY
,nWidth
,nHeight
- ,SWP_MOVE | SWP_SIZE | SWP_ZORDER | SWP_SHOW
+ ,SWP_MOVE | SWP_SIZE | SWP_ZORDER | SWP_SHOW | SWP_ACTIVATE
);
+ ::WinQueryWindowPos(GetHwnd(), GetSwp());
m_hFrame = m_hWnd;
SubclassWin(m_hWnd);
return TRUE;
, const wxSize& rSize
)
{
- long lExflags;
- long lFlags = OS2GetCreateWindowFlags(&lExflags);
+ WXDWORD lExflags;
+ WXDWORD lFlags = OS2GetCreateWindowFlags(&lExflags);
long lStyle = GetWindowStyleFlag();
int nX = rPos.x;
int nY = rPos.y;
{
vError = ::WinGetLastError(vHabmain);
sError = wxPMErrorToStr(vError);
- wxLogError("Error creating frame. Error: %s\n", sError);
+ wxLogError("Error creating frame. Error: %s\n", sError.c_str());
return FALSE;
}
{
vError = ::WinGetLastError(vHabmain);
sError = wxPMErrorToStr(vError);
- wxLogError("Error creating frame. Error: %s\n", sError);
+ wxLogError("Error creating frame. Error: %s\n", sError.c_str());
return FALSE;
}
{
vError = ::WinGetLastError(vHabmain);
sError = wxPMErrorToStr(vError);
- wxLogError("Error sizing frame. Error: %s\n", sError);
+ wxLogError("Error sizing frame. Error: %s\n", sError.c_str());
return FALSE;
}
lStyle = ::WinQueryWindowULong( m_hWnd
, wxWindowID vId
, const wxString& rsTitle
, const wxPoint& rPos
-, const wxSize& rSize
+, const wxSize& rSizeOrig
, long lStyle
, const wxString& rsName
)
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);
wxTopLevelWindowOS2::~wxTopLevelWindowOS2()
{
- wxTopLevelWindows.DeleteObject(this);
-
if (wxModelessWindows.Find(this))
wxModelessWindows.DeleteObject(this);
//
- // If this is the last top-level window, exit.
+ // 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 (wxTheApp && (wxTopLevelWindows.Number() == 0))
+ if (HasFlag(wxFRAME_FLOAT_ON_PARENT))
{
- 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;
-
- if (GetAutoLayout)
- //
- // Auto layouts taken care of elsewhere
- //
- return;
+ wxWindow* pParent = GetParent();
- ::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
-
-void wxTopLevelWindowOS2::UpdateInternalSize(
- wxWindow* pChild
-, int nChildWidth
-, int nChildHeight
-)
-{
- int nWidthAdjust = 0;
- int nHeightAdjust = 0;
- int nPosX;
- int nPosY;
- bool bNewYSize = FALSE;
- bool bNewXSize = FALSE;
-
- //
- // Under OS/2, if we have a srolled window as the child, the
- // scrollbars will be SIBLINGS of the scrolled window. So, in
- // order to be able to display the scrollbars properly we have to
- // resize the scrolled window. Of course, that means dealing with
- // child windows of that window as well, because OS/2 does not
- // tend to put them in the right place.
- //
- if (nChildHeight != m_vSwpClient.cy)
- bNewYSize = TRUE;
- if (nChildWidth != m_vSwpClient.cx)
- bNewXSize = TRUE;
- if (bNewXSize || bNewYSize)
- pChild->SetSize( 0
- ,0
- ,nChildWidth
- ,nChildHeight
- );
- if(bNewYSize)
- {
- //
- // This is needed SetSize will mess up the OS/2 child window
- // positioning because we position in wxWindows coordinates,
- // not OS/2 coordinates.
- //
- pChild->MoveChildren(m_vSwpClient.cy - nChildHeight);
- pChild->Refresh();
- }
-
- if (pChild->GetScrollBarHorz() != NULLHANDLE ||
- pChild->GetScrollBarVert() != NULLHANDLE)
- {
- if (bNewXSize || bNewYSize)
+ if (pParent)
{
- pChild->GetSize( &nChildWidth
- ,&nChildHeight
- );
- if (pChild->GetScrollBarHorz() != NULLHANDLE)
- nHeightAdjust = 20;
- if (pChild->GetScrollBarVert() != NULLHANDLE)
- nWidthAdjust = 20;
- pChild->GetPosition( &nPosX
- ,&nPosY
- );
- ::WinSetWindowPos( pChild->GetHWND()
+ ::WinSetWindowPos( GetHwndOf(pParent)
,HWND_TOP
- ,nPosX
- ,nPosY + nHeightAdjust
- ,nChildWidth - nWidthAdjust
- ,nChildHeight - nHeightAdjust
- ,SWP_MOVE | SWP_SIZE
+ ,0, 0, 0, 0
+ ,SWP_ZORDER
);
}
- if (bNewYSize && !m_sbInitialized)
- {
- //
- // Only need to readjust child control positions of
- // scrolled windows once on initialization. After that
- // the sizing takes care of things itself.
- //
- pChild->MoveChildren(nHeightAdjust);
- m_sbInitialized = TRUE;
- }
- if (bNewXSize || bNewYSize)
- {
- //
- // Always refresh to keep scollbars visible. They are
- // children of the Toplevel window, not the child panel.
- //
- pChild->Refresh();
- }
}
- //
- // This brings the internal "last size" up to date.
- //
- ::WinQueryWindowPos(GetHwnd(), &m_vSwpClient);
-} // end of wxTopLevelWindowOS2::UpdateInternalSize
+} // end of wxTopLevelWindowOS2::~wxTopLevelWindowOS2
// ----------------------------------------------------------------------------
// wxTopLevelWindowOS2 client size
{
int nShowCmd;
SWP vSwp;
- RECTL vRect;
+ if (bShow != IsShown() )
+ {
+ m_isShown = bShow;
+ }
+ else
+ {
+ return FALSE;
+ }
if (bShow)
{
if (m_bMaximizeOnShow)
m_bIconized = vSwp.fl & SWP_MINIMIZE;
::WinQueryWindowPos(m_hWnd, &m_vSwpClient);
::WinSendMsg(m_hFrame, WM_UPDATEFRAME, (MPARAM)~0, 0);
+ ::WinQueryWindowPos(m_hWnd, &vSwp);
::WinEnableWindow(m_hFrame, TRUE);
+
+ //
+ // Deal with children
+ //
+ MoveChildren(m_vSwpClient.cy - vSwp.cy);
vEvent.SetEventObject(this);
GetEventHandler()->ProcessEvent(vEvent);
}
::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);
}
}
// 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;
+ m_bMaximizeOnShow = bMaximize;
}
} // end of wxTopLevelWindowOS2::Maximize
bool wxTopLevelWindowOS2::IsMaximized() const
{
- bool bIconic;
::WinQueryWindowPos(m_hFrame, (PSWP)&m_vSwp);
return (m_vSwp.fl & SWP_MAXIMIZE);
void wxTopLevelWindowOS2::SetIcon(
const wxIcon& rIcon
)
+{
+ SetIcons(wxIconBundle(rIcon));
+} // end of wxTopLevelWindowOS2::SetIcon
+
+void wxTopLevelWindowOS2::SetIcons(
+ const wxIconBundle& rIcons
+)
{
//
// This sets m_icon
//
- wxTopLevelWindowBase::SetIcon(rIcon);
+ wxTopLevelWindowBase::SetIcons(rIcons);
+
+ const wxIcon& vIcon = rIcons.GetIcon(wxSize(32, 32));
- if (m_icon.Ok())
+ if (vIcon.Ok() && vIcon.GetWidth() == 32 && vIcon.GetHeight() == 32)
{
::WinSendMsg( m_hFrame
,WM_SETICON
- ,(MPARAM)((HPOINTER)m_icon.GetHICON())
+ ,(MPARAM)((HPOINTER)vIcon.GetHICON())
,NULL
);
::WinSendMsg( m_hFrame
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()
+ ,zHIDDEN_PARENT_CLASS
+ ,NULL
+ ,0
+ ,sizeof(ULONG)
+ ))
+ {
+ wxLogLastError(_T("RegisterClass(\"wxTLWHiddenParent\")"));
+ }
+ else
+ {
+ m_szClassName = zHIDDEN_PARENT_CLASS;
+ }
+ }
+ m_shWnd = ::WinCreateWindow( HWND_DESKTOP
+ ,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