1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: msw/toplevel.cpp
3 // Purpose: implements wxTopLevelWindow for MSW
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
9 // License: wxWindows license
10 ///////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
21 #pragma implementation "toplevel.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
33 #include "wx/toplevel.h"
34 #include "wx/string.h"
40 #include "wx/os2/private.h"
42 // ----------------------------------------------------------------------------
43 // stubs for missing functions under MicroWindows
44 // ----------------------------------------------------------------------------
47 // ----------------------------------------------------------------------------
49 // ----------------------------------------------------------------------------
51 // list of all frames and modeless dialogs
52 wxWindowList wxModelessWindows
;
54 // the name of the default wxWindows class
55 extern const wxChar
* wxCanvasClassName
;
56 extern const wxChar
* wxFrameClassName
;
58 // ============================================================================
59 // wxTopLevelWindowMSW implementation
60 // ============================================================================
63 MRESULT EXPENTRY
wxDlgProc( HWND
WXUNUSED(hWnd
)
65 ,MPARAM
WXUNUSED(wParam
)
66 ,MPARAM
WXUNUSED(lParam
)
69 if (uMessage
== WM_INITDLG
)
72 // For this message, returning TRUE tells system to set focus to the
73 // first control in the dialog box.
80 // For all the other ones, FALSE means that we didn't process the
83 return (MRESULT
)FALSE
;
87 // ----------------------------------------------------------------------------
88 // wxTopLevelWindowOS2 creation
89 // ----------------------------------------------------------------------------
91 void wxTopLevelWindowOS2::Init()
93 m_bIconized
= m_bMaximizeOnShow
= FALSE
;
96 // Unlike (almost?) all other windows, frames are created hidden
101 // Data to save/restore when calling ShowFullScreen
103 m_lFsOldWindowStyle
= 0;
104 m_bFsIsMaximized
= FALSE
;
105 m_bFsIsShowing
= FALSE
;
107 m_hFrame
= NULLHANDLE
;
108 memset(&m_vSwp
, 0, sizeof(SWP
));
109 memset(&m_vSwpClient
, 0, sizeof(SWP
));
110 } // end of wxTopLevelWindowIOS2::Init
112 long wxTopLevelWindowOS2::OS2GetCreateWindowFlags(
116 long lStyle
= GetWindowStyle();
119 if (lStyle
== wxDEFAULT_FRAME_STYLE
)
120 lMsflags
= FCF_SIZEBORDER
| FCF_TITLEBAR
| FCF_SYSMENU
|
121 FCF_MINMAX
| FCF_TASKLIST
;
124 if ((lStyle
& wxCAPTION
) == wxCAPTION
)
125 lMsflags
= FCF_TASKLIST
;
127 lMsflags
= FCF_NOMOVEWITHOWNER
;
129 if ((lStyle
& wxVSCROLL
) == wxVSCROLL
)
130 lMsflags
|= FCF_VERTSCROLL
;
131 if ((lStyle
& wxHSCROLL
) == wxHSCROLL
)
132 lMsflags
|= FCF_HORZSCROLL
;
133 if (lStyle
& wxMINIMIZE_BOX
)
134 lMsflags
|= FCF_MINBUTTON
;
135 if (lStyle
& wxMAXIMIZE_BOX
)
136 lMsflags
|= FCF_MAXBUTTON
;
137 if (lStyle
& wxTHICK_FRAME
)
138 lMsflags
|= FCF_DLGBORDER
;
139 if (lStyle
& wxSYSTEM_MENU
)
140 lMsflags
|= FCF_SYSMENU
;
141 if (lStyle
& wxCAPTION
)
142 lMsflags
|= FCF_TASKLIST
;
143 if (lStyle
& wxCLIP_CHILDREN
)
145 // Invalid for frame windows under PM
148 if (lStyle
& wxTINY_CAPTION_VERT
)
149 lMsflags
|= FCF_TASKLIST
;
150 if (lStyle
& wxTINY_CAPTION_HORIZ
)
151 lMsflags
|= FCF_TASKLIST
;
153 if ((lStyle
& wxTHICK_FRAME
) == 0)
154 lMsflags
|= FCF_BORDER
;
155 if (lStyle
& wxFRAME_TOOL_WINDOW
)
156 *plExflags
= kFrameToolWindow
;
158 if (lStyle
& wxSTAY_ON_TOP
)
159 lMsflags
|= FCF_SYSMODAL
;
162 } // end of wxTopLevelWindowOS2::OS2GetCreateWindowFlags
164 bool wxTopLevelWindowOS2::CreateDialog(
166 , const wxString
& rsTitle
167 , const wxPoint
& rPos
168 , const wxSize
& rSize
171 wxWindow
* pParent
= GetParent();
174 // For the dialogs without wxDIALOG_NO_PARENT style, use the top level
175 // app window as parent - this avoids creating modal dialogs without
178 if (!pParent
&& !(GetWindowStyleFlag() & wxDIALOG_NO_PARENT
))
180 pParent
= wxTheApp
->GetTopWindow();
185 // Don't use transient windows as parents, this is dangerous as it
186 // can lead to a crash if the parent is destroyed before the child
188 // also don't use the window which is currently hidden as then the
189 // dialog would be hidden as well
190 if ((pParent
->GetExtraStyle() & wxWS_EX_TRANSIENT
) ||
202 hWndParent
= GetHwndOf(pParent
);
204 hWndParent
= HWND_DESKTOP
;
206 hWndDlg
= ::WinLoadDlg( hWndParent
210 ,(ULONG
)ulDlgTemplate
214 m_hWnd
= (WXHWND
) hWndDlg
;
218 wxFAIL_MSG(_("Did you forget to include wx/os2/wx.rc in your resources?"));
220 wxLogSysError(_("Can't create dialog using template '%ul'"), ulDlgTemplate
);
226 // Move the dialog to its initial position without forcing repainting
233 if (!OS2GetCreateWindowCoords( rPos
241 nX
= nWidth
= (int)CW_USEDEFAULT
;
245 // We can't use CW_USEDEFAULT here as we're not calling CreateWindow()
246 // and passing CW_USEDEFAULT to MoveWindow() results in resizing the
247 // window to (0, 0) size which breaks quite a lot of things, e.g. the
248 // sizer calculation in wxSizer::Fit()
250 if (nWidth
== (int)CW_USEDEFAULT
)
253 // The exact number doesn't matter, the dialog will be resized
254 // again soon anyhow but it should be big enough to allow
255 // calculation relying on "totalSize - clientSize > 0" work, i.e.
256 // at least greater than the title bar height
258 nWidth
= nHeight
= 100;
260 if (nX
== (int)CW_USEDEFAULT
)
263 // Centre it on the screen - what else can we do?
265 wxSize vSizeDpy
= wxGetDisplaySize();
267 nX
= (vSizeDpy
.x
- nWidth
) / 2;
268 nY
= (vSizeDpy
.y
- nHeight
) / 2;
270 ::WinSetWindowPos( GetHwnd()
276 ,SWP_MOVE
| SWP_SIZE
| SWP_ZORDER
| SWP_SHOW
278 if (!rsTitle
.IsNull())
280 ::WinSetWindowText(GetHwnd(), rsTitle
.c_str());
284 } // end of wxTopLevelWindowOS2::CreateDialog
286 bool wxTopLevelWindowOS2::CreateFrame(
287 const wxString
& rsTitle
288 , const wxPoint
& rPos
289 , const wxSize
& rSize
293 long lFlags
= OS2GetCreateWindowFlags(&lExflags
);
294 long lStyle
= GetWindowStyleFlag();
297 int nWidth
= rSize
.x
;
298 int nHeight
= rSize
.y
;
299 ULONG ulStyleFlags
= 0L;
302 wxWindow
* pParent
= GetParent();
308 hParent
= GetHwndOf(pParent
);
310 hParent
= HWND_DESKTOP
;
312 if ((lStyle
& wxMINIMIZE
) || (lStyle
& wxICONIZE
))
313 ulStyleFlags
|= WS_MINIMIZED
;
314 if (lStyle
& wxMAXIMIZE
)
315 ulStyleFlags
|= WS_MAXIMIZED
;
318 // Clear the visible flag, we always call show
320 ulStyleFlags
&= (unsigned long)~WS_VISIBLE
;
324 // Create the frame window: We break ranks with other ports now
325 // and instead of calling down into the base wxWindow class' OS2Create
326 // we do all our own stuff here. We will set the needed pieces
327 // of wxWindow manually, here.
330 hFrame
= ::WinCreateStdWindow( hParent
331 ,ulStyleFlags
// frame-window style
332 ,(PULONG
)&lFlags
// window style
333 ,(PSZ
)wxFrameClassName
// class name
334 ,(PSZ
)rsTitle
.c_str() // window title
335 ,0L // default client style
336 ,NULLHANDLE
// resource in executable file
338 ,&hClient
// receives client window handle
342 vError
= ::WinGetLastError(vHabmain
);
343 sError
= wxPMErrorToStr(vError
);
344 wxLogError("Error creating frame. Error: %s\n", sError
);
349 // wxWindow class' m_hWnd set here and needed associations
353 wxAssociateWinWithHandle(m_hWnd
, this);
354 wxAssociateWinWithHandle(m_hFrame
, this);
356 m_backgroundColour
.Set(wxString("GREY"));
358 LONG lColor
= (LONG
)m_backgroundColour
.GetPixel();
360 if (!::WinSetPresParam( m_hWnd
366 vError
= ::WinGetLastError(vHabmain
);
367 sError
= wxPMErrorToStr(vError
);
368 wxLogError("Error creating frame. Error: %s\n", sError
);
373 // Now need to subclass window. Instead of calling the SubClassWin in wxWindow
374 // we manually subclass here because we don't want to use the main wxWndProc
377 m_fnOldWndProc
= (WXFARPROC
) ::WinSubclassWindow(m_hFrame
, (PFNWP
)wxFrameMainWndProc
);
380 // Now size everything. If adding a menu the client will need to be resized.
385 nY
= pParent
->GetSize().y
- (nY
+ nHeight
);
391 ::WinQueryWindowRect(HWND_DESKTOP
, &vRect
);
392 nY
= vRect
.yTop
- (nY
+ nHeight
);
394 if (!::WinSetWindowPos( m_hFrame
400 ,SWP_SIZE
| SWP_MOVE
| SWP_ACTIVATE
| SWP_ZORDER
403 vError
= ::WinGetLastError(vHabmain
);
404 sError
= wxPMErrorToStr(vError
);
405 wxLogError("Error sizing frame. Error: %s\n", sError
);
409 } // end of wxTopLevelWindowOS2::CreateFrame
411 bool wxTopLevelWindowOS2::Create(
414 , const wxString
& rsTitle
415 , const wxPoint
& rPos
416 , const wxSize
& rSize
418 , const wxString
& rsName
425 m_windowStyle
= lStyle
;
427 m_windowId
= vId
== -1 ? NewControlId() : vId
;
428 wxTopLevelWindows
.Append(this);
430 pParent
->AddChild(this);
432 if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG
)
435 // We have different dialog templates to allows creation of dialogs
436 // with & without captions under OS2indows, resizeable or not (but a
437 // resizeable dialog always has caption - otherwise it would look too
442 if (lStyle
& wxRESIZE_BORDER
)
443 ulDlgTemplate
= (ULONG
)kResizeableDialog
;
444 else if (lStyle
& wxCAPTION
)
445 ulDlgTemplate
= (ULONG
)kCaptionDialog
;
447 ulDlgTemplate
= (ULONG
)kNoCaptionDialog
;
448 return CreateDialog( ulDlgTemplate
456 return CreateFrame( rsTitle
461 } // end of wxTopLevelWindowOS2::Create
463 wxTopLevelWindowOS2::~wxTopLevelWindowOS2()
465 wxTopLevelWindows
.DeleteObject(this);
467 if (wxModelessWindows
.Find(this))
468 wxModelessWindows
.DeleteObject(this);
471 // If this is the last top-level window, exit.
473 if (wxTheApp
&& (wxTopLevelWindows
.Number() == 0))
475 wxTheApp
->SetTopWindow(NULL
);
476 if ( wxTheApp
->GetExitOnFrameDelete() )
478 ::WinPostMsg(NULL
, WM_QUIT
, 0, 0);
481 } // end of wxTopLevelWindowOS2::~wxTopLevelWindowOS2
484 // IF we have child controls in the Frame's client we need to alter
485 // the y position, because, OS/2 controls are positioned relative to
486 // wxWindows orgin (top left) not the OS/2 origin (bottom left)
488 void wxTopLevelWindowOS2::AlterChildPos()
491 // OS/2 is the only OS concerned about this
493 wxWindow
* pChild
= NULL
;
494 wxControl
* pCtrl
= NULL
;
498 ::WinQueryWindowRect(GetHwnd(), &vRect
);
499 for (wxWindowList::Node
* pNode
= GetChildren().GetFirst();
501 pNode
= pNode
->GetNext())
503 wxWindow
* pChild
= pNode
->GetData();
505 ::WinQueryWindowPos(pChild
->GetHWND(), &vSwp
);
506 vSwp
.y
+= (vRect
.yTop
- m_vSwpClient
.cy
);
507 if (pChild
->IsKindOf(CLASSINFO(wxControl
)))
509 pCtrl
= wxDynamicCast(pChild
, wxControl
);
511 // Must deal with controls that have margins like ENTRYFIELD. The SWP
512 // struct of such a control will have and origin offset from its intended
513 // position by the width of the margins.
515 vSwp
.y
-= pCtrl
->GetYComp();
516 vSwp
.x
-= pCtrl
->GetXComp();
518 ::WinSetWindowPos( pChild
->GetHWND()
526 ::WinQueryWindowPos(pChild
->GetHWND(), &vSwp
);
529 ::WinQueryWindowPos(GetHwnd(), &m_vSwpClient
);
530 } // end of wxTopLevelWindowOS2::AlterChildPos
532 // ----------------------------------------------------------------------------
533 // wxTopLevelWindowOS2 client size
534 // ----------------------------------------------------------------------------
536 void wxTopLevelWindowOS2::DoSetClientSize(
542 // Call GetClientAreaOrigin() to take the toolbar into account
544 wxPoint vPt
= GetClientAreaOrigin();
549 wxWindow::DoSetClientSize( nWidth
552 } // end of wxTopLevelWindowOS2::DoSetClientSize
554 void wxTopLevelWindowOS2::DoGetClientSize(
559 wxWindow::DoGetClientSize( pnX
563 wxPoint vPt
= GetClientAreaOrigin();
570 } // end of wxTopLevelWindowOS2::DoGetClientSize
572 // ----------------------------------------------------------------------------
573 // wxTopLevelWindowOS2 showing
574 // ----------------------------------------------------------------------------
576 void wxTopLevelWindowOS2::DoShowWindow(
580 ::WinShowWindow(m_hFrame
, (BOOL
)nShowCmd
);
581 m_bIconized
= nShowCmd
== SWP_MINIMIZE
;
582 } // end of wxTopLevelWindowOS2::DoShowWindow
584 bool wxTopLevelWindowOS2::Show(
594 if (m_bMaximizeOnShow
)
597 m_bMaximizeOnShow
= FALSE
;
608 DoShowWindow(nShowCmd
);
612 wxActivateEvent
vEvent(wxEVT_ACTIVATE
, TRUE
, m_windowId
);
614 ::WinQueryWindowPos(m_hFrame
, &vSwp
);
615 m_bIconized
= vSwp
.fl
& SWP_MINIMIZE
;
616 ::WinQueryWindowPos(m_hWnd
, &m_vSwpClient
);
617 ::WinSendMsg(m_hFrame
, WM_UPDATEFRAME
, (MPARAM
)~0, 0);
618 ::WinEnableWindow(m_hFrame
, TRUE
);
619 vEvent
.SetEventObject(this);
620 GetEventHandler()->ProcessEvent(vEvent
);
625 // Try to highlight the correct window (the parent)
629 HWND hWndParent
= GetHwndOf(GetParent());
631 ::WinQueryWindowPos(hWndParent
, &vSwp
);
632 m_bIconized
= vSwp
.fl
& SWP_MINIMIZE
;
634 ::WinSetWindowPos( hWndParent
640 ,SWP_ZORDER
| SWP_ACTIVATE
| SWP_SHOW
| SWP_MOVE
642 ::WinEnableWindow(hWndParent
, TRUE
);
646 } // end of wxTopLevelWindowOS2::Show
648 // ----------------------------------------------------------------------------
649 // wxTopLevelWindowOS2 maximize/minimize
650 // ----------------------------------------------------------------------------
652 void wxTopLevelWindowOS2::Maximize(
659 // Just maximize it directly
661 DoShowWindow(bMaximize
? SWP_MAXIMIZE
: SWP_RESTORE
);
666 // We can't maximize the hidden frame because it shows it as well, so
667 // just remember that we should do it later in this case
669 m_bMaximizeOnShow
= TRUE
;
671 } // end of wxTopLevelWindowOS2::Maximize
673 bool wxTopLevelWindowOS2::IsMaximized() const
677 ::WinQueryWindowPos(m_hFrame
, (PSWP
)&m_vSwp
);
678 return (m_vSwp
.fl
& SWP_MAXIMIZE
);
679 } // end of wxTopLevelWindowOS2::IsMaximized
681 void wxTopLevelWindowOS2::Iconize(
685 DoShowWindow(bIconize
? SWP_MINIMIZE
: SWP_RESTORE
);
686 } // end of wxTopLevelWindowOS2::Iconize
688 bool wxTopLevelWindowOS2::IsIconized() const
690 // also update the current state
691 ::WinQueryWindowPos(m_hFrame
, (PSWP
)&m_vSwp
);
692 if (m_vSwp
.fl
& SWP_MINIMIZE
)
693 ((wxTopLevelWindow
*)this)->m_bIconized
= TRUE
;
695 ((wxTopLevelWindow
*)this)->m_bIconized
= FALSE
;
697 } // end of wxTopLevelWindowOS2::IsIconized
699 void wxTopLevelWindowOS2::Restore()
701 DoShowWindow(SWP_RESTORE
);
702 } // end of wxTopLevelWindowOS2::Restore
704 // ----------------------------------------------------------------------------
705 // wxTopLevelWindowOS2 fullscreen
706 // ----------------------------------------------------------------------------
708 bool wxTopLevelWindowOS2::ShowFullScreen(
718 m_bFsIsShowing
= TRUE
;
722 // Zap the frame borders
726 // Save the 'normal' window lStyle
728 m_lFsOldWindowStyle
= ::WinQueryWindowULong( (HWND
)GetHWND()
733 // Save the old position, width & height, maximize state
735 m_vFsOldSize
= GetRect();
736 m_bFsIsMaximized
= IsMaximized();
739 // Decide which window lStyle flags to turn off
741 LONG lNewStyle
= m_lFsOldWindowStyle
;
744 if (lStyle
& wxFULLSCREEN_NOBORDER
)
745 lOffFlags
|= FCF_BORDER
;
746 if (lStyle
& wxFULLSCREEN_NOCAPTION
)
747 lOffFlags
|= (FCF_TASKLIST
| FCF_SYSMENU
);
749 lNewStyle
&= (~lOffFlags
);
752 // Change our window style to be compatible with full-screen mode
754 ::WinSetWindowULong( (HWND
)GetHWND()
760 // Resize to the size of the desktop
764 RECTL vRect
= wxGetWindowRect(HWND_DESKTOP
);
766 nWidth
= vRect
.xRight
- vRect
.xLeft
;
767 nHeight
= vRect
.yTop
- vRect
.yBottom
;
774 // Now flush the window style cache and actually go full-screen
776 ::WinSetWindowPos( m_hFrame
785 wxSizeEvent
vEvent( wxSize( nWidth
791 GetEventHandler()->ProcessEvent(vEvent
);
799 m_bFsIsShowing
= FALSE
;
800 Maximize(m_bFsIsMaximized
);
801 ::WinSetWindowULong( (HWND
)GetHWND()
805 ::WinSetWindowPos( m_hFrame
815 } // end of wxTopLevelWindowOS2::ShowFullScreen
817 // ----------------------------------------------------------------------------
818 // wxTopLevelWindowOS2 misc
819 // ----------------------------------------------------------------------------
821 void wxTopLevelWindowOS2::SetIcon(
828 wxTopLevelWindowBase::SetIcon(rIcon
);
832 ::WinSendMsg( m_hFrame
834 ,(MPARAM
)((HPOINTER
)m_icon
.GetHICON())
837 ::WinSendMsg( m_hFrame
843 } // end of wxTopLevelWindowOS2::SetIcon
845 bool wxTopLevelWindowOS2::EnableCloseButton(
850 // Get system (a.k.a. window) menu
852 HMENU hMenu
= ::WinWindowFromID(m_hFrame
, FID_SYSMENU
);
856 wxLogLastError(_T("GetSystemMenu"));
861 // Enabling/disabling the close item from it also automatically
862 // disables/enables the close title bar button
865 (void)::WinSendMsg( hMenu
867 ,MPFROM2SHORT(SC_CLOSE
, FALSE
)
868 ,MPFROM2SHORT(MIA_DISABLED
, FALSE
)
871 (void)::WinSendMsg( hMenu
873 ,MPFROM2SHORT(SC_CLOSE
, FALSE
)
874 ,MPFROM2SHORT(MIA_DISABLED
, MIA_DISABLED
)
878 // Update appearance immediately
880 ::WinSendMsg( m_hFrame
886 } // end of wxTopLevelWindowOS2::EnableCloseButton