1///////////////////////////////////////////////////////////////////////////////
2// Name:        src/os2/toplevel.cpp
3// Purpose:     implements wxTopLevelWindow for OS/2
4// Author:      Vadim Zeitlin
5// Modified by:
6// Created:     30.12.01
7// RCS-ID:      $Id: toplevel.cpp 40943 2006-08-31 19:31:43Z ABX $
8// Copyright:   (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
9// License:     wxWindows licence
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24    #pragma hdrstop
25#endif
26
27#include "wx/toplevel.h"
28
29#ifndef WX_PRECOMP
30    #include "wx/app.h"
31    #include "wx/dialog.h"
32    #include "wx/string.h"
33    #include "wx/log.h"
34    #include "wx/intl.h"
35    #include "wx/frame.h"
36    #include "wx/control.h"
37    #include "wx/containr.h"        // wxSetFocusToChild()
38    #include "wx/settings.h"
39    #include "wx/module.h"        // wxSetFocusToChild()
40#endif //WX_PRECOMP
41
42#include "wx/os2/private.h"
43
44// ----------------------------------------------------------------------------
45// stubs for missing functions under MicroWindows
46// ----------------------------------------------------------------------------
47
48
49// ----------------------------------------------------------------------------
50// globals
51// ----------------------------------------------------------------------------
52
53// the name of the default wxWidgets class
54extern void wxAssociateWinWithHandle( HWND hWnd, wxWindowOS2* pWin );
55
56bool wxTopLevelWindowOS2::m_sbInitialized = false;
57wxWindow* wxTopLevelWindowOS2::m_spHiddenParent = NULL;
58
59// ============================================================================
60// wxTopLevelWindowOS2 implementation
61// ============================================================================
62
63BEGIN_EVENT_TABLE(wxTopLevelWindowOS2, wxTopLevelWindowBase)
64    EVT_ACTIVATE(wxTopLevelWindowOS2::OnActivate)
65END_EVENT_TABLE()
66
67// ============================================================================
68// wxTopLevelWindowMSW implementation
69// ============================================================================
70
71// Dialog window proc
72MRESULT EXPENTRY wxDlgProc( HWND WXUNUSED(hWnd)
73                           ,UINT uMessage
74                           ,void * WXUNUSED(wParam)
75                           ,void * WXUNUSED(lParam)
76                          )
77{
78    switch(uMessage)
79    {
80        case WM_INITDLG:
81            //
82            // For this message, returning TRUE tells system to set focus to
83            // the first control in the dialog box, but we set the focus
84            // ourselves, however in OS/2 we must return true to enable the dialog
85            //
86            return (MRESULT)TRUE;
87        default:
88            //
89            // For all the other ones, FALSE means that we didn't process the
90            // message
91            //
92            return (MRESULT)FALSE;
93    }
94} // end of wxDlgProc
95
96// ----------------------------------------------------------------------------
97// wxTLWHiddenParentModule: used to manage the hidden parent window (we need a
98// module to ensure that the window is always deleted)
99// ----------------------------------------------------------------------------
100
101class wxTLWHiddenParentModule : public wxModule
102{
103public:
104    //
105    // Module init/finalize
106    //
107    virtual bool OnInit(void);
108    virtual void OnExit(void);
109
110    //
111    // Get the hidden window (creates on demand)
112    //
113    static HWND GetHWND(void);
114
115private:
116    //
117    // The HWND of the hidden parent
118    //
119    static HWND m_shWnd;
120
121    //
122    // The class used to create it
123    //
124    static const wxChar* m_szClassName;
125    DECLARE_DYNAMIC_CLASS(wxTLWHiddenParentModule)
126}; // end of CLASS wxTLWHiddenParentModule
127
128IMPLEMENT_DYNAMIC_CLASS(wxTLWHiddenParentModule, wxModule)
129
130// ----------------------------------------------------------------------------
131// wxTopLevelWindowOS2 creation
132// ----------------------------------------------------------------------------
133
134void wxTopLevelWindowOS2::Init()
135{
136    m_bIconized = m_bMaximizeOnShow = false;
137
138    //
139    // Unlike (almost?) all other windows, frames are created hidden
140    //
141    m_isShown = false;
142
143    //
144    // Data to save/restore when calling ShowFullScreen
145    m_lFsStyle          = 0;
146    m_lFsOldWindowStyle = 0;
147    m_bFsIsMaximized    = false;
148    m_bFsIsShowing      = false;
149
150    m_hFrame    = NULLHANDLE;
151    memset(&m_vSwp, 0, sizeof(SWP));
152    memset(&m_vSwpClient, 0, sizeof(SWP));
153    m_pWinLastFocused = (wxWindow *)NULL;
154} // end of wxTopLevelWindowIOS2::Init
155
156void wxTopLevelWindowOS2::OnActivate(
157  wxActivateEvent&                  rEvent
158)
159{
160    if (rEvent.GetActive())
161    {
162        //
163        // Restore focus to the child which was last focused
164        //
165        wxLogTrace(_T("focus"), _T("wxTLW %08lx activated."), m_hWnd);
166
167        wxWindow*                   pParent = m_pWinLastFocused ? m_pWinLastFocused->GetParent()
168                                                                : NULL;
169        if (!pParent)
170        {
171            pParent = this;
172        }
173
174        wxSetFocusToChild( pParent
175                          ,&m_pWinLastFocused
176                         );
177    }
178    else // deactivating
179    {
180        //
181        // Remember the last focused child if it is our child
182        //
183        m_pWinLastFocused = FindFocus();
184
185        //
186        // So we NULL it out if it's a child from some other frame
187        //
188        wxWindow*                   pWin = m_pWinLastFocused;
189
190        while (pWin)
191        {
192            if (pWin->IsTopLevel())
193            {
194                if (pWin != this)
195                {
196                    m_pWinLastFocused = NULL;
197                }
198                break;
199            }
200            pWin = pWin->GetParent();
201        }
202
203        wxLogTrace(_T("focus"),
204                   _T("wxTLW %08lx deactivated, last focused: %08lx."),
205                   m_hWnd,
206                   m_pWinLastFocused ? GetHwndOf(m_pWinLastFocused)
207                                     : NULL);
208        rEvent.Skip();
209    }
210} // end of wxTopLevelWindowOS2::OnActivate
211
212WXDWORD wxTopLevelWindowOS2::OS2GetStyle(
213  long                              lStyle
214, WXDWORD*                          pdwExflags
215) const
216{
217    long                            lMsflags = wxWindow::OS2GetStyle( (lStyle & ~wxBORDER_MASK) | wxBORDER_NONE
218                                                                     ,pdwExflags
219                                                                    );
220
221    if ((lStyle & wxDEFAULT_FRAME_STYLE) == wxDEFAULT_FRAME_STYLE)
222        lMsflags |= FCF_SIZEBORDER | FCF_TITLEBAR | FCF_SYSMENU |
223                    FCF_MINMAX | FCF_TASKLIST;
224
225    if ((lStyle & wxCAPTION) == wxCAPTION)
226        lMsflags |= FCF_TASKLIST;
227    else
228        lMsflags |= FCF_NOMOVEWITHOWNER;
229
230    if ((lStyle & wxVSCROLL) == wxVSCROLL)
231        lMsflags |= FCF_VERTSCROLL;
232    if ((lStyle & wxHSCROLL) == wxHSCROLL)
233        lMsflags |= FCF_HORZSCROLL;
234    if (lStyle & wxMINIMIZE_BOX)
235        lMsflags |= FCF_MINBUTTON;
236    if (lStyle & wxMAXIMIZE_BOX)
237        lMsflags |= FCF_MAXBUTTON;
238    if (lStyle & wxRESIZE_BORDER)
239        lMsflags |= FCF_DLGBORDER;
240    if (lStyle & wxSYSTEM_MENU)
241        lMsflags |= FCF_SYSMENU;
242    if (lStyle & wxCAPTION)
243        lMsflags |= FCF_TASKLIST;
244    if (lStyle & wxCLIP_CHILDREN)
245    {
246        // Invalid for frame windows under PM
247    }
248
249    if (lStyle & wxTINY_CAPTION_VERT)
250        lMsflags |= FCF_TASKLIST;
251    if (lStyle & wxTINY_CAPTION_HORIZ)
252        lMsflags |= FCF_TASKLIST;
253
254    if ((lStyle & wxRESIZE_BORDER) == 0)
255        lMsflags |= FCF_BORDER;
256    if (lStyle & wxFRAME_TOOL_WINDOW)
257        *pdwExflags = kFrameToolWindow;
258
259    if (lStyle & wxSTAY_ON_TOP)
260        lMsflags |= FCF_SYSMODAL;
261
262    return lMsflags;
263} // end of wxTopLevelWindowOS2::OS2GetCreateWindowFlags
264
265WXHWND wxTopLevelWindowOS2::OS2GetParent() const
266{
267    HWND                            hWndParent = NULL;
268
269    //
270    // For the frames without wxFRAME_FLOAT_ON_PARENT style we should use NULL
271    // parent HWND or it would be always on top of its parent which is not what
272    // we usually want (in fact, we only want it for frames with the
273    // wxFRAME_FLOAT_ON_PARENT flag)
274    //
275    if (HasFlag(wxFRAME_FLOAT_ON_PARENT) )
276    {
277        const wxWindow*             pParent = GetParent();
278
279        if (!pParent)
280        {
281            //
282            // This flag doesn't make sense then and will be ignored
283            //
284            wxFAIL_MSG( _T("wxFRAME_FLOAT_ON_PARENT but no parent?") );
285        }
286        else
287        {
288            hWndParent = GetHwndOf(pParent);
289        }
290    }
291    //else: don't float on parent, must not be owned
292
293    //
294    // Now deal with the 2nd taskbar-related problem (see comments above in
295    // OS2GetStyle())
296    //
297    if (HasFlag(wxFRAME_NO_TASKBAR) && !hWndParent)
298    {
299        //
300        // Use hidden parent
301        //
302        hWndParent = wxTLWHiddenParentModule::GetHWND();
303    }
304    return (WXHWND)hWndParent;
305} // end of wxTopLevelWindowOS2::OS2GetParent
306
307
308bool wxTopLevelWindowOS2::CreateDialog( ULONG           ulDlgTemplate,
309                                        const wxString& WXUNUSED(rsTitle),
310                                        const wxPoint&  rPos,
311                                        const wxSize&   rSize )
312{
313    wxWindow*                       pParent = GetParent();
314
315    //
316    // For the dialogs without wxDIALOG_NO_PARENT style, use the top level
317    // app window as parent - this avoids creating modal dialogs without
318    // parent
319    //
320    if (!pParent && !(GetWindowStyleFlag() & wxDIALOG_NO_PARENT))
321    {
322        pParent = wxTheApp->GetTopWindow();
323
324        if (pParent)
325        {
326            //
327            // Don't use transient windows as parents, this is dangerous as it
328            // can lead to a crash if the parent is destroyed before the child
329            //
330            // also don't use the window which is currently hidden as then the
331            // dialog would be hidden as well
332            if ((pParent->GetExtraStyle() & wxWS_EX_TRANSIENT) ||
333                 !pParent->IsShown())
334            {
335                pParent = NULL;
336            }
337        }
338    }
339
340    HWND                            hWndDlg;
341    HWND                            hWndOwner;
342
343    if (pParent)
344        hWndOwner = GetHwndOf(pParent);
345    else
346        hWndOwner = HWND_DESKTOP;
347
348    hWndDlg = ::WinLoadDlg( HWND_DESKTOP
349                           ,hWndOwner
350                           ,(PFNWP)wxDlgProc
351                           ,NULL
352                           ,(ULONG)ulDlgTemplate
353                           ,(PVOID)this
354                          );
355
356    m_hWnd = (WXHWND) hWndDlg;
357
358    if ( !m_hWnd )
359    {
360        wxFAIL_MSG(wxT("Did you forget to include wx/os2/wx.rc in your resources?"));
361
362        wxLogSysError(wxT("Can't create dialog using template '%ld'"), ulDlgTemplate);
363
364        return false;
365    }
366
367    //
368    // Move the dialog to its initial position without forcing repainting
369    //
370    int                             nX;
371    int                             nY;
372    int                             nWidth;
373    int                             nHeight;
374
375    if (!OS2GetCreateWindowCoords( rPos
376                                  ,rSize
377                                  ,nX
378                                  ,nY
379                                  ,nWidth
380                                  ,nHeight
381                                 ))
382    {
383        nX = nWidth = (int)CW_USEDEFAULT;
384    }
385
386    //
387    // We can't use CW_USEDEFAULT here as we're not calling CreateWindow()
388    // and passing CW_USEDEFAULT to MoveWindow() results in resizing the
389    // window to (0, 0) size which breaks quite a lot of things, e.g. the
390    // sizer calculation in wxSizer::Fit()
391    //
392    if (nWidth == (int)CW_USEDEFAULT)
393    {
394        //
395        // The exact number doesn't matter, the dialog will be resized
396        // again soon anyhow but it should be big enough to allow
397        // calculation relying on "totalSize - clientSize > 0" work, i.e.
398        // at least greater than the title bar height
399        //
400        nWidth = nHeight = 100;
401    }
402    if (nX == (int)CW_USEDEFAULT)
403    {
404        //
405        // Centre it on the screen - what else can we do?
406        //
407        wxSize                      vSizeDpy = wxGetDisplaySize();
408
409        nX = (vSizeDpy.x - nWidth) / 2;
410        nY = (vSizeDpy.y - nHeight) / 2;
411    }
412    SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE));
413
414    LONG                            lColor = (LONG)m_backgroundColour.GetPixel();
415
416    if (!::WinSetPresParam( m_hWnd
417                           ,PP_BACKGROUNDCOLOR
418                           ,sizeof(LONG)
419                           ,(PVOID)&lColor
420                          ))
421    {
422        return false;
423    }
424
425    // Convert to OS/2 coordinates
426    nY = GetOS2ParentHeight(pParent) - nY - nHeight;
427
428    ::WinSetWindowPos( GetHwnd()
429                      ,HWND_TOP
430                      ,nX
431                      ,nY
432                      ,nWidth
433                      ,nHeight
434                      ,SWP_MOVE | SWP_SIZE | SWP_ZORDER | SWP_SHOW | SWP_ACTIVATE
435                     );
436    ::WinQueryWindowPos(GetHwnd(), GetSwp());
437    m_hFrame = m_hWnd;
438    SubclassWin(m_hWnd);
439    return true;
440} // end of wxTopLevelWindowOS2::CreateDialog
441
442bool wxTopLevelWindowOS2::CreateFrame( const wxString& rsTitle,
443                                       const wxPoint& rPos,
444                                       const wxSize& rSize )
445{
446    WXDWORD    lExflags;
447    WXDWORD    lFlags = OS2GetCreateWindowFlags(&lExflags);
448    long       lStyle = GetWindowStyleFlag();
449    int        nX = rPos.x;
450    int        nY = rPos.y;
451    int        nWidth = rSize.x;
452    int        nHeight = rSize.y;
453    ULONG      ulStyleFlags = 0L;
454    ERRORID    vError;
455    wxString   sError;
456    wxWindow*  pParent = GetParent();
457    HWND       hParent;
458    HWND       hFrame;
459    HWND       hClient;
460
461    if (pParent)
462        hParent = GetHwndOf(pParent);
463    else
464        hParent = HWND_DESKTOP;
465
466    if ((lStyle & wxMINIMIZE) || (lStyle & wxICONIZE))
467        ulStyleFlags |= WS_MINIMIZED;
468    if (lStyle & wxMAXIMIZE)
469        ulStyleFlags |= WS_MAXIMIZED;
470
471    //
472    // Clear the visible flag, we always call show
473    //
474    ulStyleFlags &= (unsigned long)~WS_VISIBLE;
475    m_bIconized = false;
476
477    //
478    // Create the frame window:  We break ranks with other ports now
479    // and instead of calling down into the base wxWindow class' OS2Create
480    // we do all our own stuff here.  We will set the needed pieces
481    // of wxWindow manually, here.
482    //
483
484     hFrame = ::WinCreateStdWindow( hParent
485                                   ,ulStyleFlags          // frame-window style
486                                   ,(PULONG)&lFlags       // window style
487                                   ,(PSZ)wxFrameClassName // class name
488                                   ,(PSZ)rsTitle.c_str()  // window title
489                                   ,0L                    // default client style
490                                   ,NULLHANDLE            // resource in executable file
491                                   ,0                     // resource id
492                                   ,&hClient              // receives client window handle
493                                  );
494    if (!hFrame)
495    {
496        vError = ::WinGetLastError(vHabmain);
497        sError = wxPMErrorToStr(vError);
498        wxLogError(_T("Error creating frame. Error: %s\n"), sError.c_str());
499        return false;
500    }
501
502    //
503    // wxWindow class' m_hWnd set here and needed associations
504    //
505    m_hFrame = hFrame;
506    m_hWnd   = hClient;
507    wxAssociateWinWithHandle(m_hWnd, this);
508    wxAssociateWinWithHandle(m_hFrame, this);
509
510    SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE));
511
512    LONG                            lColor = (LONG)m_backgroundColour.GetPixel();
513
514    if (!::WinSetPresParam( m_hWnd
515                           ,PP_BACKGROUNDCOLOR
516                           ,sizeof(LONG)
517                           ,(PVOID)&lColor
518                          ))
519    {
520        vError = ::WinGetLastError(vHabmain);
521        sError = wxPMErrorToStr(vError);
522        wxLogError(_T("Error creating frame. Error: %s\n"), sError.c_str());
523        return false;
524    }
525
526    //
527    // Now need to subclass window.  Instead of calling the SubClassWin in wxWindow
528    // we manually subclass here because we don't want to use the main wxWndProc
529    // by default
530    //
531    m_fnOldWndProc = (WXFARPROC) ::WinSubclassWindow(m_hFrame, (PFNWP)wxFrameMainWndProc);
532
533    //
534    // Now size everything.  If adding a menu the client will need to be resized.
535    //
536
537    if (!OS2GetCreateWindowCoords( rPos
538                                  ,rSize
539                                  ,nX
540                                  ,nY
541                                  ,nWidth
542                                  ,nHeight
543                                 ))
544    {
545        nX = nWidth = (int)CW_USEDEFAULT;
546    }
547
548    //
549    // We can't use CW_USEDEFAULT here as we're not calling CreateWindow()
550    // and passing CW_USEDEFAULT to MoveWindow() results in resizing the
551    // window to (0, 0) size which breaks quite a lot of things, e.g. the
552    // sizer calculation in wxSizer::Fit()
553    //
554    if (nWidth == (int)CW_USEDEFAULT)
555    {
556       //
557        // The exact number doesn't matter, the dialog will be resized
558        // again soon anyhow but it should be big enough to allow
559        // calculation relying on "totalSize - clientSize > 0" work, i.e.
560        // at least greater than the title bar height
561        //
562        nWidth = nHeight = 100;
563    }
564    if (nX == (int)CW_USEDEFAULT)
565    {
566        //
567        // Centre it on the screen for now - what else can we do?
568        // TODO: We could try FCF_SHELLPOSITION but it will require moving
569        //       things around a bit.
570        //
571        wxSize                      vSizeDpy = wxGetDisplaySize();
572
573        nX = (vSizeDpy.x - nWidth) / 2;
574        nY = (vSizeDpy.y - nHeight) / 2;
575    }
576
577    // Convert to OS/2 coordinates
578    nY = GetOS2ParentHeight(pParent) - nY - nHeight;
579
580    if (!::WinSetWindowPos( m_hFrame
581                           ,HWND_TOP
582                           ,nX
583                           ,nY
584                           ,nWidth
585                           ,nHeight
586                           ,SWP_SIZE | SWP_MOVE | SWP_ACTIVATE | SWP_ZORDER
587                          ))
588    {
589        vError = ::WinGetLastError(vHabmain);
590        sError = wxPMErrorToStr(vError);
591        wxLogError(_T("Error sizing frame. Error: %s\n"), sError.c_str());
592        return false;
593    }
594    lStyle =  ::WinQueryWindowULong( m_hWnd
595                                    ,QWL_STYLE
596                                   );
597    lStyle |= WS_CLIPCHILDREN;
598    ::WinSetWindowULong( m_hWnd
599                        ,QWL_STYLE
600                        ,lStyle
601                       );
602    return true;
603} // end of wxTopLevelWindowOS2::CreateFrame
604
605bool wxTopLevelWindowOS2::Create(
606  wxWindow*                         pParent
607, wxWindowID                        vId
608, const wxString&                   rsTitle
609, const wxPoint&                    rPos
610, const wxSize&                     rSizeOrig
611, long                              lStyle
612, const wxString&                   rsName
613)
614{
615    //
616    // Init our fields
617    //
618    Init();
619    m_windowStyle = lStyle;
620    SetName(rsName);
621    m_windowId = vId == -1 ? NewControlId() : vId;
622
623    // always create a frame of some reasonable, even if arbitrary, size (at
624    // least for MSW compatibility)
625    wxSize rSize = rSizeOrig;
626    if ( rSize.x == -1 || rSize.y == -1 )
627    {
628        wxSize sizeDpy = wxGetDisplaySize();
629        if ( rSize.x == -1 )
630            rSize.x = sizeDpy.x / 3;
631        if ( rSize.y == -1 )
632            rSize.y = sizeDpy.y / 5;
633    }
634
635    wxTopLevelWindows.Append(this);
636    if (pParent)
637        pParent->AddChild(this);
638
639    if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)
640    {
641        //
642        // We have different dialog templates to allow creation of dialogs
643        // with & without captions under OS2indows, resizeable or not (but a
644        // resizeable dialog always has caption - otherwise it would look too
645        // strange)
646        //
647        ULONG                       ulDlgTemplate;
648
649        if (lStyle & wxRESIZE_BORDER)
650            ulDlgTemplate = (ULONG)kResizeableDialog;
651        else if (lStyle & wxCAPTION)
652            ulDlgTemplate = (ULONG)kCaptionDialog;
653        else
654            ulDlgTemplate = (ULONG)kNoCaptionDialog;
655        return CreateDialog( ulDlgTemplate
656                            ,rsTitle
657                            ,rPos
658                            ,rSize
659                           );
660    }
661    else // !dialog
662    {
663        return CreateFrame( rsTitle
664                           ,rPos
665                           ,rSize
666                          );
667    }
668} // end of wxTopLevelWindowOS2::Create
669
670wxTopLevelWindowOS2::~wxTopLevelWindowOS2()
671{
672    //
673    // After destroying an owned window, Windows activates the next top level
674    // window in Z order but it may be different from our owner (to reproduce
675    // this simply Alt-TAB to another application and back before closing the
676    // owned frame) whereas we always want to yield activation to our parent
677    //
678    if (HasFlag(wxFRAME_FLOAT_ON_PARENT))
679    {
680        wxWindow*                   pParent = GetParent();
681
682        if (pParent)
683        {
684            ::WinSetWindowPos( GetHwndOf(pParent)
685                              ,HWND_TOP
686                              ,0, 0, 0, 0
687                              ,SWP_ZORDER
688                             );
689        }
690    }
691} // end of wxTopLevelWindowOS2::~wxTopLevelWindowOS2
692
693// ----------------------------------------------------------------------------
694// wxTopLevelWindowOS2 client size
695// ----------------------------------------------------------------------------
696
697void wxTopLevelWindowOS2::DoSetClientSize(
698  int                               nWidth
699, int                               nHeight
700)
701{
702    //
703    // Call GetClientAreaOrigin() to take the toolbar into account
704    //
705    wxPoint                         vPt = GetClientAreaOrigin();
706
707    nWidth  += vPt.x;
708    nHeight += vPt.y;
709
710    wxWindow::DoSetClientSize( nWidth
711                              ,nHeight
712                             );
713} // end of wxTopLevelWindowOS2::DoSetClientSize
714
715void wxTopLevelWindowOS2::DoGetClientSize(
716  int*                              pnX
717, int*                              pnY
718) const
719{
720    wxWindow::DoGetClientSize( pnX
721                              ,pnY
722                             );
723
724    wxPoint                         vPt = GetClientAreaOrigin();
725
726    if (pnX)
727        *pnX -= vPt.x;
728
729    if (pnY)
730        *pnY += vPt.y;
731} // end of wxTopLevelWindowOS2::DoGetClientSize
732
733// ----------------------------------------------------------------------------
734// wxTopLevelWindowOS2 showing
735// ----------------------------------------------------------------------------
736
737void wxTopLevelWindowOS2::DoShowWindow(
738  int                               nShowCmd
739)
740{
741    ::WinShowWindow(m_hFrame, (BOOL)(nShowCmd & SWP_SHOW));
742
743    //
744    // Need to artificially send a size event as wxApps often expect to do some
745    // final child control sizing
746    SendSizeEvent();
747    m_bIconized = nShowCmd == SWP_MINIMIZE;
748} // end of wxTopLevelWindowOS2::DoShowWindow
749
750bool wxTopLevelWindowOS2::Show( bool bShow )
751{
752    int nShowCmd;
753    SWP vSwp;
754
755    if (bShow != IsShown() )
756    {
757        m_isShown = bShow;
758    }
759    else
760    {
761        return false;
762    }
763    if (bShow)
764    {
765        if (m_bMaximizeOnShow)
766        {
767            nShowCmd = SWP_MAXIMIZE;
768            m_bMaximizeOnShow = false;
769        }
770        else
771        {
772            nShowCmd = SWP_SHOW;
773        }
774    }
775    else // hide
776    {
777        nShowCmd = SWP_HIDE;
778    }
779    DoShowWindow(nShowCmd);
780
781    if (bShow)
782    {
783        wxActivateEvent vEvent(wxEVT_ACTIVATE, true, m_windowId);
784
785        ::WinQueryWindowPos(m_hFrame, &vSwp);
786        m_bIconized = ( vSwp.fl & SWP_MINIMIZE ) == SWP_MINIMIZE ;
787        ::WinQueryWindowPos(m_hWnd, &m_vSwpClient);
788        ::WinSendMsg(m_hFrame, WM_UPDATEFRAME, (MPARAM)~0, 0);
789        ::WinQueryWindowPos(m_hWnd, &vSwp);
790        ::WinEnableWindow(m_hFrame, TRUE);
791
792        vEvent.SetEventObject(this);
793        GetEventHandler()->ProcessEvent(vEvent);
794    }
795    else
796    {
797        //
798        // Try to highlight the correct window (the parent)
799        //
800        if (GetParent())
801        {
802            HWND hWndParent = GetHwndOf(GetParent());
803
804            ::WinQueryWindowPos(hWndParent, &vSwp);
805            m_bIconized = (vSwp.fl & SWP_MINIMIZE)==SWP_MINIMIZE;
806            ::WinEnableWindow(hWndParent, TRUE);
807        }
808    }
809    return true;
810} // end of wxTopLevelWindowOS2::Show
811
812// ----------------------------------------------------------------------------
813// wxTopLevelWindowOS2 maximize/minimize
814// ----------------------------------------------------------------------------
815
816void wxTopLevelWindowOS2::Maximize(
817  bool                              bMaximize
818)
819{
820    if (IsShown())
821    {
822        //
823        // Just maximize it directly
824        //
825        DoShowWindow(bMaximize ? SWP_MAXIMIZE : SWP_RESTORE);
826    }
827    else // hidden
828    {
829        //
830        // We can't maximize the hidden frame because it shows it as well, so
831        // just remember that we should do it later in this case
832        //
833        m_bMaximizeOnShow = bMaximize;
834    }
835} // end of wxTopLevelWindowOS2::Maximize
836
837bool wxTopLevelWindowOS2::IsMaximized() const
838{
839    ::WinQueryWindowPos(m_hFrame, (PSWP)&m_vSwp);
840    return (m_vSwp.fl & SWP_MAXIMIZE) == SWP_MAXIMIZE;
841} // end of wxTopLevelWindowOS2::IsMaximized
842
843void wxTopLevelWindowOS2::SetTitle( const wxString& title)
844{
845    SetLabel(title);
846}
847
848wxString wxTopLevelWindowOS2::GetTitle() const
849{
850    return GetLabel();
851}
852
853void wxTopLevelWindowOS2::Iconize( bool bIconize )
854{
855    DoShowWindow(bIconize ? SWP_MINIMIZE : SWP_RESTORE);
856} // end of wxTopLevelWindowOS2::Iconize
857
858bool wxTopLevelWindowOS2::IsIconized() const
859{
860    // also update the current state
861    ::WinQueryWindowPos(m_hFrame, (PSWP)&m_vSwp);
862    if (m_vSwp.fl & SWP_MINIMIZE)
863        ((wxTopLevelWindow*)this)->m_bIconized = true;
864    else
865        ((wxTopLevelWindow*)this)->m_bIconized = false;
866    return m_bIconized;
867} // end of wxTopLevelWindowOS2::IsIconized
868
869void wxTopLevelWindowOS2::Restore()
870{
871    DoShowWindow(SWP_RESTORE);
872} // end of wxTopLevelWindowOS2::Restore
873
874// generate an artificial resize event
875void wxTopLevelWindowOS2::SendSizeEvent()
876{
877    if (!m_bIconized)
878    {
879        RECTL                       vRect = wxGetWindowRect(GetHwnd());
880
881        (void)::WinPostMsg( m_hFrame
882                           ,WM_SIZE
883                           ,MPFROM2SHORT(vRect.xRight - vRect.xLeft, vRect.yTop - vRect.yBottom)
884                           ,MPFROM2SHORT(vRect.xRight - vRect.xLeft, vRect.yTop - vRect.yBottom)
885                          );
886    }
887} // end of wxTopLevelWindowOS2::SendSizeEvent
888
889// ----------------------------------------------------------------------------
890// wxTopLevelWindowOS2 fullscreen
891// ----------------------------------------------------------------------------
892
893bool wxTopLevelWindowOS2::ShowFullScreen( bool bShow,
894                                          long lStyle )
895{
896    if (bShow)
897    {
898        if (IsFullScreen())
899            return false;
900
901        m_bFsIsShowing = true;
902        m_lFsStyle = lStyle;
903
904        //
905        // Zap the frame borders
906        //
907
908        //
909        // Save the 'normal' window lStyle
910        //
911        m_lFsOldWindowStyle = ::WinQueryWindowULong( (HWND)GetHWND()
912                                                    ,QWL_STYLE
913                                                   );
914
915        //
916        // Save the old position, width & height, maximize state
917        //
918        m_vFsOldSize = GetRect();
919        m_bFsIsMaximized = IsMaximized();
920
921        //
922        // Decide which window lStyle flags to turn off
923        //
924        LONG lNewStyle = m_lFsOldWindowStyle;
925        LONG lOffFlags = 0;
926
927        if (lStyle & wxFULLSCREEN_NOBORDER)
928            lOffFlags |= FCF_BORDER;
929        if (lStyle & wxFULLSCREEN_NOCAPTION)
930            lOffFlags |= (FCF_TASKLIST | FCF_SYSMENU);
931
932        lNewStyle &= (~lOffFlags);
933
934        //
935        // Change our window style to be compatible with full-screen mode
936        //
937        ::WinSetWindowULong( (HWND)GetHWND()
938                            ,QWL_STYLE
939                            ,lNewStyle
940                           );
941
942        //
943        // Resize to the size of the desktop
944        //
945        int   nWidth;
946        int   nHeight;
947        RECTL vRect = wxGetWindowRect(HWND_DESKTOP);
948
949        nWidth = vRect.xRight - vRect.xLeft;
950        nHeight = vRect.yTop - vRect.yBottom;
951
952        SetSize( nWidth, nHeight );
953
954        //
955        // Now flush the window style cache and actually go full-screen
956        //
957        ::WinSetWindowPos( m_hFrame
958                          ,HWND_TOP
959                          ,0
960                          ,0
961                          ,nWidth
962                          ,nHeight
963                          ,SWP_SIZE | SWP_MOVE
964                         );
965
966        wxSize full( nWidth, nHeight );
967        wxSizeEvent vEvent( full, GetId() );
968        GetEventHandler()->ProcessEvent(vEvent);
969        return true;
970    }
971    else
972    {
973        if (!IsFullScreen())
974            return false;
975
976        m_bFsIsShowing = false;
977        Maximize(m_bFsIsMaximized);
978        ::WinSetWindowULong( (HWND)GetHWND()
979                            ,QWL_STYLE
980                            ,m_lFsOldWindowStyle
981                           );
982        ::WinSetWindowPos( m_hFrame
983                          ,HWND_TOP
984                          ,m_vFsOldSize.x
985                          ,m_vFsOldSize.y
986                          ,m_vFsOldSize.width
987                          ,m_vFsOldSize.height
988                          ,SWP_SIZE | SWP_MOVE
989                         );
990        return true;
991    }
992} // end of wxTopLevelWindowOS2::ShowFullScreen
993
994// ----------------------------------------------------------------------------
995// wxTopLevelWindowOS2 misc
996// ----------------------------------------------------------------------------
997
998void wxTopLevelWindowOS2::SetIcon(
999  const wxIcon&                     rIcon
1000)
1001{
1002    SetIcons(wxIconBundle(rIcon));
1003} // end of wxTopLevelWindowOS2::SetIcon
1004
1005void wxTopLevelWindowOS2::SetIcons(
1006  const wxIconBundle&               rIcons
1007)
1008{
1009    //
1010    // This sets m_icon
1011    //
1012    wxTopLevelWindowBase::SetIcons(rIcons);
1013
1014    const wxIcon&                   vIcon = rIcons.GetIcon(wxSize(32, 32));
1015
1016    if (vIcon.Ok() && vIcon.GetWidth() == 32 && vIcon.GetHeight() == 32)
1017    {
1018        ::WinSendMsg( m_hFrame
1019                     ,WM_SETICON
1020                     ,(MPARAM)((HPOINTER)vIcon.GetHICON())
1021                     ,NULL
1022                    );
1023        ::WinSendMsg( m_hFrame
1024                     ,WM_UPDATEFRAME
1025                     ,(MPARAM)FCF_ICON
1026                     ,(MPARAM)0
1027                    );
1028    }
1029} // end of wxTopLevelWindowOS2::SetIcon
1030
1031bool wxTopLevelWindowOS2::EnableCloseButton( bool bEnable )
1032{
1033    //
1034    // Get system (a.k.a. window) menu
1035    //
1036    HMENU hMenu = ::WinWindowFromID(m_hFrame, FID_SYSMENU);
1037
1038    if (!hMenu)
1039    {
1040        wxLogLastError(_T("GetSystemMenu"));
1041        return false;
1042    }
1043
1044    //
1045    // Enabling/disabling the close item from it also automatically
1046    // disables/enables the close title bar button
1047    //
1048    if (bEnable)
1049        (void)::WinSendMsg( hMenu
1050                           ,MM_SETITEMATTR
1051                           ,MPFROM2SHORT(SC_CLOSE, FALSE)
1052                           ,MPFROM2SHORT(MIA_DISABLED, FALSE)
1053                          );
1054    else
1055        (void)::WinSendMsg( hMenu
1056                           ,MM_SETITEMATTR
1057                           ,MPFROM2SHORT(SC_CLOSE, FALSE)
1058                           ,MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED)
1059                          );
1060
1061    //
1062    // Update appearance immediately
1063    //
1064    ::WinSendMsg( m_hFrame
1065                 ,WM_UPDATEFRAME
1066                 ,(MPARAM)FCF_MENU
1067                 ,(MPARAM)0
1068                );
1069    return true;
1070} // end of wxTopLevelWindowOS2::EnableCloseButton
1071
1072// ============================================================================
1073// wxTLWHiddenParentModule implementation
1074// ============================================================================
1075
1076HWND          wxTLWHiddenParentModule::m_shWnd = NULL;
1077const wxChar* wxTLWHiddenParentModule::m_szClassName = NULL;
1078
1079bool wxTLWHiddenParentModule::OnInit()
1080{
1081    m_shWnd = NULL;
1082    m_szClassName = NULL;
1083    return true;
1084} // end of wxTLWHiddenParentModule::OnInit
1085
1086void wxTLWHiddenParentModule::OnExit()
1087{
1088    if (m_shWnd)
1089    {
1090        if (!::WinDestroyWindow(m_shWnd))
1091        {
1092            wxLogLastError(_T("DestroyWindow(hidden TLW parent)"));
1093        }
1094        m_shWnd = NULL;
1095    }
1096
1097    m_szClassName = NULL;
1098} // end of wxTLWHiddenParentModule::OnExit
1099
1100/* static */
1101HWND wxTLWHiddenParentModule::GetHWND()
1102{
1103    if (!m_shWnd)
1104    {
1105        if (!m_szClassName)
1106        {
1107            static const wxChar*    zHIDDEN_PARENT_CLASS = _T("wxTLWHiddenParent");
1108
1109            if (!::WinRegisterClass( wxGetInstance()
1110                                    ,(PSZ)zHIDDEN_PARENT_CLASS
1111                                    ,NULL
1112                                    ,0
1113                                    ,sizeof(ULONG)
1114                                   ))
1115            {
1116                wxLogLastError(_T("RegisterClass(\"wxTLWHiddenParent\")"));
1117            }
1118            else
1119            {
1120                m_szClassName = zHIDDEN_PARENT_CLASS;
1121            }
1122        }
1123        m_shWnd = ::WinCreateWindow( HWND_DESKTOP,
1124                                     (PSZ)m_szClassName,
1125                                     "",
1126                                     0L,
1127                                     (LONG)0L,
1128                                     (LONG)0L,
1129                                     (LONG)0L,
1130                                     (LONG)0L,
1131                                     NULLHANDLE,
1132                                     HWND_TOP,
1133                                     0L,
1134                                     NULL,
1135                                     NULL );
1136        if (!m_shWnd)
1137        {
1138            wxLogLastError(_T("CreateWindow(hidden TLW parent)"));
1139        }
1140    }
1141    return m_shWnd;
1142} // end of wxTLWHiddenParentModule::GetHWND
1143