1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/msw/toplevel.cpp
3 // Purpose:     implements wxTopLevelWindow for MSW
4 // Author:      Vadim Zeitlin
5 // Modified by:
6 // Created:     24.09.01
7 // Copyright:   (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
8 // Licence:     wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10 
11 // ============================================================================
12 // declarations
13 // ============================================================================
14 
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18 
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21 
22 #ifdef __BORLANDC__
23     #pragma hdrstop
24 #endif
25 
26 #include "wx/toplevel.h"
27 
28 #ifndef WX_PRECOMP
29     #include "wx/app.h"
30     #include "wx/dialog.h"
31     #include "wx/string.h"
32     #include "wx/log.h"
33     #include "wx/intl.h"
34     #include "wx/frame.h"
35     #include "wx/menu.h"
36     #include "wx/containr.h"        // wxSetFocusToChild()
37     #include "wx/module.h"
38 #endif //WX_PRECOMP
39 
40 #include "wx/dynlib.h"
41 
42 #include "wx/msw/private.h"
43 #if defined(__WXWINCE__) && !defined(__HANDHELDPC__)
44     #include <ole2.h>
45     #include <shellapi.h>
46     // Standard SDK doesn't have aygshell.dll: see include/wx/msw/wince/libraries.h
47     #if _WIN32_WCE < 400 || !defined(__WINCE_STANDARDSDK__)
48         #include <aygshell.h>
49     #endif
50 #endif
51 
52 #include "wx/msw/winundef.h"
53 #include "wx/msw/missing.h"
54 
55 #include "wx/display.h"
56 
57 #ifndef ICON_BIG
58     #define ICON_BIG 1
59 #endif
60 
61 #ifndef ICON_SMALL
62     #define ICON_SMALL 0
63 #endif
64 
65 // FIXME-VC6: Only VC6 doesn't have this in its standard headers so this
66 //            could be removed once support for it is dropped.
67 #ifndef WM_UNINITMENUPOPUP
68     #define WM_UNINITMENUPOPUP 0x0125
69 #endif
70 
71 // ----------------------------------------------------------------------------
72 // globals
73 // ----------------------------------------------------------------------------
74 
75 #if wxUSE_MENUS || wxUSE_MENUS_NATIVE
76     extern wxMenu *wxCurrentPopupMenu;
77 #endif // wxUSE_MENUS || wxUSE_MENUS_NATIVE
78 
79 
80 // ----------------------------------------------------------------------------
81 // stubs for missing functions under MicroWindows
82 // ----------------------------------------------------------------------------
83 
84 #ifdef __WXMICROWIN__
85 
86 // static inline bool IsIconic(HWND WXUNUSED(hwnd)) { return false; }
IsZoomed(HWND WXUNUSED (hwnd))87 static inline bool IsZoomed(HWND WXUNUSED(hwnd)) { return false; }
88 
89 #endif // __WXMICROWIN__
90 
91 // NB: wxDlgProc must be defined here and not in dialog.cpp because the latter
92 //     is not included by wxUniv build which does need wxDlgProc
93 LONG APIENTRY _EXPORT
94 wxDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
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 
101 class wxTLWHiddenParentModule : public wxModule
102 {
103 public:
104     // module init/finalize
105     virtual bool OnInit();
106     virtual void OnExit();
107 
108     // get the hidden window (creates on demand)
109     static HWND GetHWND();
110 
111 private:
112     // the HWND of the hidden parent
113     static HWND ms_hwnd;
114 
115     // the class used to create it
116     static const wxChar *ms_className;
117 
118     DECLARE_DYNAMIC_CLASS(wxTLWHiddenParentModule)
119 };
120 
IMPLEMENT_DYNAMIC_CLASS(wxTLWHiddenParentModule,wxModule)121 IMPLEMENT_DYNAMIC_CLASS(wxTLWHiddenParentModule, wxModule)
122 
123 // ============================================================================
124 // wxTopLevelWindowMSW implementation
125 // ============================================================================
126 
127 BEGIN_EVENT_TABLE(wxTopLevelWindowMSW, wxTopLevelWindowBase)
128     EVT_ACTIVATE(wxTopLevelWindowMSW::OnActivate)
129 END_EVENT_TABLE()
130 
131 // ----------------------------------------------------------------------------
132 // wxTopLevelWindowMSW creation
133 // ----------------------------------------------------------------------------
134 
135 void wxTopLevelWindowMSW::Init()
136 {
137     m_iconized =
138     m_maximizeOnShow = false;
139 
140     // Data to save/restore when calling ShowFullScreen
141     m_fsStyle = 0;
142     m_fsOldWindowStyle = 0;
143     m_fsIsMaximized = false;
144     m_fsIsShowing = false;
145 
146     m_winLastFocused = NULL;
147 
148 #if defined(__SMARTPHONE__) && defined(__WXWINCE__)
149     m_MenuBarHWND = 0;
150 #endif
151 
152 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
153     SHACTIVATEINFO* info = new SHACTIVATEINFO;
154     wxZeroMemory(*info);
155     info->cbSize = sizeof(SHACTIVATEINFO);
156 
157     m_activateInfo = (void*) info;
158 #endif
159 
160     m_menuSystem = NULL;
161     m_menuDepth = 0;
162 }
163 
MSWGetStyle(long style,WXDWORD * exflags) const164 WXDWORD wxTopLevelWindowMSW::MSWGetStyle(long style, WXDWORD *exflags) const
165 {
166     // let the base class deal with the common styles but fix the ones which
167     // don't make sense for us (we also deal with the borders ourselves)
168     WXDWORD msflags = wxWindow::MSWGetStyle
169                       (
170                         (style & ~wxBORDER_MASK) | wxBORDER_NONE, exflags
171                       ) & ~WS_CHILD & ~WS_VISIBLE;
172 
173     // For some reason, WS_VISIBLE needs to be defined on creation for
174     // SmartPhone 2003. The title can fail to be displayed otherwise.
175 #if defined(__SMARTPHONE__) || (defined(__WXWINCE__) && _WIN32_WCE < 400)
176     msflags |= WS_VISIBLE;
177     ((wxTopLevelWindowMSW*)this)->wxWindowBase::Show(true);
178 #endif
179 
180     // first select the kind of window being created
181     //
182     // note that if we don't set WS_POPUP, Windows assumes WS_OVERLAPPED and
183     // creates a window with both caption and border, hence we need to use
184     // WS_POPUP in a few cases just to avoid having caption/border which we
185     // don't want
186 
187     // border and caption styles
188     if ( ( style & wxRESIZE_BORDER ) && !IsAlwaysMaximized())
189         msflags |= WS_THICKFRAME;
190     else if ( exflags && ((style & wxBORDER_DOUBLE) || (style & wxBORDER_RAISED)) )
191         *exflags |= WS_EX_DLGMODALFRAME;
192     else if ( !(style & wxBORDER_NONE) )
193         msflags |= WS_BORDER;
194 #ifndef __POCKETPC__
195     else
196         msflags |= WS_POPUP;
197 #endif
198 
199     // normally we consider that all windows without a caption must be popups,
200     // but CE is an exception: there windows normally do not have the caption
201     // but shouldn't be made popups as popups can't have menus and don't look
202     // like normal windows anyhow
203 
204     // TODO: Smartphone appears to like wxCAPTION, but we should check that
205     // we need it.
206 #if defined(__SMARTPHONE__) || !defined(__WXWINCE__)
207     if ( style & wxCAPTION )
208         msflags |= WS_CAPTION;
209 #ifndef __WXWINCE__
210     else
211         msflags |= WS_POPUP;
212 #endif // !__WXWINCE__
213 #endif
214 
215     // next translate the individual flags
216 
217     // WS_EX_CONTEXTHELP is incompatible with WS_MINIMIZEBOX and WS_MAXIMIZEBOX
218     // and is ignored if we specify both of them, but chances are that if we
219     // use wxWS_EX_CONTEXTHELP, we really do want to have the context help
220     // button while wxMINIMIZE/wxMAXIMIZE are included by default, so the help
221     // takes precedence
222     if ( !(GetExtraStyle() & wxWS_EX_CONTEXTHELP) )
223     {
224         if ( style & wxMINIMIZE_BOX )
225             msflags |= WS_MINIMIZEBOX;
226         if ( style & wxMAXIMIZE_BOX )
227             msflags |= WS_MAXIMIZEBOX;
228     }
229 
230 #ifndef __WXWINCE__
231     // notice that if wxCLOSE_BOX is specified we need to use WS_SYSMENU too as
232     // otherwise the close box doesn't appear
233     if ( style & (wxSYSTEM_MENU | wxCLOSE_BOX) )
234         msflags |= WS_SYSMENU;
235 #endif // !__WXWINCE__
236 
237     // NB: under CE these 2 styles are not supported currently, we should
238     //     call Minimize()/Maximize() "manually" if we want to support them
239     if ( style & wxMINIMIZE )
240         msflags |= WS_MINIMIZE;
241 
242     if ( style & wxMAXIMIZE )
243         msflags |= WS_MAXIMIZE;
244 
245     // Keep this here because it saves recoding this function in wxTinyFrame
246     if ( style & wxTINY_CAPTION )
247         msflags |= WS_CAPTION;
248 
249     if ( exflags )
250     {
251         // there is no taskbar under CE, so omit all this
252 #if !defined(__WXWINCE__)
253         if ( !(GetExtraStyle() & wxTOPLEVEL_EX_DIALOG) )
254         {
255             if ( style & wxFRAME_TOOL_WINDOW )
256             {
257                 // create the palette-like window
258                 *exflags |= WS_EX_TOOLWINDOW;
259 
260                 // tool windows shouldn't appear on the taskbar (as documented)
261                 style |= wxFRAME_NO_TASKBAR;
262             }
263 
264             // We have to solve 2 different problems here:
265             //
266             // 1. frames with wxFRAME_NO_TASKBAR flag shouldn't appear in the
267             //    taskbar even if they don't have a parent
268             //
269             // 2. frames without this style should appear in the taskbar even
270             //    if they're owned (Windows only puts non owned windows into
271             //    the taskbar normally)
272             //
273             // The second one is solved here by using WS_EX_APPWINDOW flag, the
274             // first one is dealt with in our MSWGetParent() method
275             // implementation
276             if ( !(style & wxFRAME_NO_TASKBAR) && GetParent() )
277             {
278                 // need to force the frame to appear in the taskbar
279                 *exflags |= WS_EX_APPWINDOW;
280             }
281             //else: nothing to do [here]
282         }
283 
284         if ( GetExtraStyle() & wxWS_EX_CONTEXTHELP )
285             *exflags |= WS_EX_CONTEXTHELP;
286 #endif // !__WXWINCE__
287 
288         if ( style & wxSTAY_ON_TOP )
289             *exflags |= WS_EX_TOPMOST;
290     }
291 
292     return msflags;
293 }
294 
MSWGetParent() const295 WXHWND wxTopLevelWindowMSW::MSWGetParent() const
296 {
297     // for the frames without wxFRAME_FLOAT_ON_PARENT style we should use NULL
298     // parent HWND or it would be always on top of its parent which is not what
299     // we usually want (in fact, we only want it for frames with the
300     // wxFRAME_FLOAT_ON_PARENT flag)
301     HWND hwndParent = NULL;
302     if ( HasFlag(wxFRAME_FLOAT_ON_PARENT) )
303     {
304         const wxWindow *parent = GetParent();
305 
306         if ( !parent )
307         {
308             // this flag doesn't make sense then and will be ignored
309             wxFAIL_MSG( wxT("wxFRAME_FLOAT_ON_PARENT but no parent?") );
310         }
311         else
312         {
313             hwndParent = GetHwndOf(parent);
314         }
315     }
316     //else: don't float on parent, must not be owned
317 
318     // now deal with the 2nd taskbar-related problem (see comments above in
319     // MSWGetStyle())
320     if ( HasFlag(wxFRAME_NO_TASKBAR) && !hwndParent )
321     {
322         // use hidden parent
323         hwndParent = wxTLWHiddenParentModule::GetHWND();
324     }
325 
326     return (WXHWND)hwndParent;
327 }
328 
329 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
HandleSettingChange(WXWPARAM wParam,WXLPARAM lParam)330 bool wxTopLevelWindowMSW::HandleSettingChange(WXWPARAM wParam, WXLPARAM lParam)
331 {
332     SHACTIVATEINFO *info = (SHACTIVATEINFO*) m_activateInfo;
333     if ( info )
334     {
335         SHHandleWMSettingChange(GetHwnd(), wParam, lParam, info);
336     }
337 
338     return wxWindowMSW::HandleSettingChange(wParam, lParam);
339 }
340 #endif
341 
MSWWindowProc(WXUINT message,WXWPARAM wParam,WXLPARAM lParam)342 WXLRESULT wxTopLevelWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
343 {
344     WXLRESULT rc = 0;
345     bool processed = false;
346 
347     switch ( message )
348     {
349 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
350         case WM_ACTIVATE:
351         {
352             SHACTIVATEINFO* info = (SHACTIVATEINFO*) m_activateInfo;
353             if (info)
354             {
355                 DWORD flags = 0;
356                 if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG) flags = SHA_INPUTDIALOG;
357                 SHHandleWMActivate(GetHwnd(), wParam, lParam, info, flags);
358             }
359 
360             // This implicitly sends a wxEVT_ACTIVATE_APP event
361             if (wxTheApp)
362                 wxTheApp->SetActive(wParam != 0, FindFocus());
363 
364             break;
365         }
366         case WM_HIBERNATE:
367         {
368             if (wxTheApp)
369             {
370                 wxActivateEvent event(wxEVT_HIBERNATE, true, wxID_ANY);
371                 event.SetEventObject(wxTheApp);
372                 processed = wxTheApp->ProcessEvent(event);
373             }
374             break;
375         }
376 #endif // __SMARTPHONE__ || __POCKETPC__
377 
378         case WM_SYSCOMMAND:
379             {
380                 // From MSDN:
381                 //
382                 //      ... the four low-order bits of the wParam parameter are
383                 //      used internally by the system. To obtain the correct
384                 //      result when testing the value of wParam, an application
385                 //      must combine the value 0xFFF0 with the wParam value by
386                 //      using the bitwise AND operator.
387                 unsigned id = wParam & 0xfff0;
388 
389                 // Preserve the focus when minimizing/restoring the window: we
390                 // need to do it manually as DefWindowProc() doesn't appear to
391                 // do this for us for some reason (perhaps because we don't use
392                 // WM_NEXTDLGCTL for setting focus?). Moreover, our code in
393                 // OnActivate() doesn't work in this case as we receive the
394                 // deactivation event too late when the window is being
395                 // minimized and the focus is already NULL by then. Similarly,
396                 // we receive the activation event too early and restoring
397                 // focus in it fails because the window is still minimized. So
398                 // we need to do it here.
399                 if ( id == SC_MINIMIZE )
400                 {
401                     // For minimization, it's simple enough: just save the
402                     // focus as usual. The important thing is that we're not
403                     // minimized yet, so this works correctly.
404                     DoSaveLastFocus();
405                 }
406                 else if ( id == SC_RESTORE )
407                 {
408                     // For restoring, it's trickier as DefWindowProc() sets
409                     // focus to the window itself. So run it first and restore
410                     // our saved focus only afterwards.
411                     processed = true;
412                     rc = wxTopLevelWindowBase::MSWWindowProc(message,
413                                                              wParam, lParam);
414 
415                     DoRestoreLastFocus();
416                 }
417 
418 #ifndef __WXUNIVERSAL__
419                 // We need to generate events for the custom items added to the
420                 // system menu if it had been created (and presumably modified).
421                 // As SC_SIZE is the first of the system-defined commands, we
422                 // only do this for the custom commands before it and leave
423                 // SC_SIZE and everything after it to DefWindowProc().
424                 if ( m_menuSystem && id < SC_SIZE )
425                 {
426                     if ( m_menuSystem->MSWCommand(0 /* unused anyhow */, id) )
427                         processed = true;
428                 }
429 #endif // #ifndef __WXUNIVERSAL__
430             }
431             break;
432 
433 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
434 #if wxUSE_MENUS
435         case WM_INITMENUPOPUP:
436             processed = HandleMenuPopup(wxEVT_MENU_OPEN, (WXHMENU)wParam);
437             break;
438 
439         case WM_MENUSELECT:
440             {
441                 WXWORD item, flags;
442                 WXHMENU hmenu;
443                 UnpackMenuSelect(wParam, lParam, &item, &flags, &hmenu);
444 
445                 processed = HandleMenuSelect(item, flags, hmenu);
446             }
447             break;
448 
449         case WM_EXITMENULOOP:
450             // Under Windows 98 and 2000 and later we're going to get
451             // WM_UNINITMENUPOPUP which will be used to generate this event
452             // with more information (notably the menu that was closed) so we
453             // only need this one under old Windows systems where the newer
454             // event is never sent.
455             if ( wxGetWinVersion() < wxWinVersion_98 )
456                 processed = HandleExitMenuLoop(wParam);
457             break;
458 
459         case WM_UNINITMENUPOPUP:
460             processed = HandleMenuPopup(wxEVT_MENU_CLOSE, (WXHMENU)wParam);
461             break;
462 #endif // wxUSE_MENUS
463 #endif // !__WXMICROWIN__
464     }
465 
466     if ( !processed )
467         rc = wxTopLevelWindowBase::MSWWindowProc(message, wParam, lParam);
468 
469     return rc;
470 }
471 
CreateDialog(const void * dlgTemplate,const wxString & title,const wxPoint & pos,const wxSize & size)472 bool wxTopLevelWindowMSW::CreateDialog(const void *dlgTemplate,
473                                        const wxString& title,
474                                        const wxPoint& pos,
475                                        const wxSize& size)
476 {
477 #ifdef __WXMICROWIN__
478     // no dialogs support under MicroWin yet
479     return CreateFrame(title, pos, size);
480 #else // !__WXMICROWIN__
481     // static cast is valid as we're only ever called for dialogs
482     wxWindow * const
483         parent = static_cast<wxDialog *>(this)->GetParentForModalDialog();
484 
485     m_hWnd = (WXHWND)::CreateDialogIndirect
486                        (
487                         wxGetInstance(),
488                         (DLGTEMPLATE*)dlgTemplate,
489                         parent ? GetHwndOf(parent) : NULL,
490                         (DLGPROC)wxDlgProc
491                        );
492 
493     if ( !m_hWnd )
494     {
495         wxFAIL_MSG(wxT("Failed to create dialog. Incorrect DLGTEMPLATE?"));
496 
497         wxLogSysError(wxT("Can't create dialog using memory template"));
498 
499         return false;
500     }
501 
502 #if !defined(__WXWINCE__)
503     // For some reason, the system menu is activated when we use the
504     // WS_EX_CONTEXTHELP style, so let's set a reasonable icon
505     if ( HasExtraStyle(wxWS_EX_CONTEXTHELP) )
506     {
507         wxFrame *winTop = wxDynamicCast(wxTheApp->GetTopWindow(), wxFrame);
508         if ( winTop )
509         {
510             wxIcon icon = winTop->GetIcon();
511             if ( icon.IsOk() )
512             {
513                 ::SendMessage(GetHwnd(), WM_SETICON,
514                               (WPARAM)TRUE,
515                               (LPARAM)GetHiconOf(icon));
516             }
517         }
518     }
519 #endif // !__WXWINCE__
520 
521     if ( !title.empty() )
522     {
523         ::SetWindowText(GetHwnd(), title.t_str());
524     }
525 
526     SubclassWin(m_hWnd);
527 
528 #if !defined(__WXWINCE__) || defined(__WINCE_STANDARDSDK__)
529     // move the dialog to its initial position without forcing repainting
530     int x, y, w, h;
531     (void)MSWGetCreateWindowCoords(pos, size, x, y, w, h);
532 
533     if ( x == (int)CW_USEDEFAULT )
534     {
535         // Let the system position the window, just set its size.
536         ::SetWindowPos(GetHwnd(), 0,
537                        0, 0, w, h,
538                        SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
539     }
540     else // Move the window to the desired location and set its size too.
541     {
542         if ( !::MoveWindow(GetHwnd(), x, y, w, h, FALSE) )
543         {
544             wxLogLastError(wxT("MoveWindow"));
545         }
546     }
547 #endif // !__WXWINCE__
548 
549 #ifdef __SMARTPHONE__
550     // Work around title non-display glitch
551     Show(false);
552 #endif
553 
554     return true;
555 #endif // __WXMICROWIN__/!__WXMICROWIN__
556 }
557 
CreateFrame(const wxString & title,const wxPoint & pos,const wxSize & size)558 bool wxTopLevelWindowMSW::CreateFrame(const wxString& title,
559                                       const wxPoint& pos,
560                                       const wxSize& size)
561 {
562     WXDWORD exflags;
563     WXDWORD flags = MSWGetCreateWindowFlags(&exflags);
564 
565     const wxSize sz = IsAlwaysMaximized() ? wxDefaultSize : size;
566 
567 #ifndef __WXWINCE__
568     if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft )
569         exflags |= WS_EX_LAYOUTRTL;
570 #endif
571 
572     return MSWCreate(MSWGetRegisteredClassName(),
573                      title.t_str(), pos, sz, flags, exflags);
574 }
575 
Create(wxWindow * parent,wxWindowID id,const wxString & title,const wxPoint & pos,const wxSize & size,long style,const wxString & name)576 bool wxTopLevelWindowMSW::Create(wxWindow *parent,
577                                  wxWindowID id,
578                                  const wxString& title,
579                                  const wxPoint& pos,
580                                  const wxSize& size,
581                                  long style,
582                                  const wxString& name)
583 {
584     wxSize sizeReal = size;
585     if ( !sizeReal.IsFullySpecified() )
586     {
587         sizeReal.SetDefaults(GetDefaultSize());
588     }
589 
590     // notice that we should append this window to wxTopLevelWindows list
591     // before calling CreateBase() as it behaves differently for TLW and
592     // non-TLW windows
593     wxTopLevelWindows.Append(this);
594 
595     bool ret = CreateBase(parent, id, pos, sizeReal, style, name);
596     if ( !ret )
597         return false;
598 
599     if ( parent )
600         parent->AddChild(this);
601 
602     if ( GetExtraStyle() & wxTOPLEVEL_EX_DIALOG )
603     {
604         // we have different dialog templates to allows creation of dialogs
605         // with & without captions under MSWindows, resizable or not (but a
606         // resizable dialog always has caption - otherwise it would look too
607         // strange)
608 
609         // we need 3 additional WORDs for dialog menu, class and title (as we
610         // don't use DS_SETFONT we don't need the fourth WORD for the font)
611         static const int dlgsize = sizeof(DLGTEMPLATE) + (sizeof(WORD) * 3);
612         DLGTEMPLATE *dlgTemplate = (DLGTEMPLATE *)malloc(dlgsize);
613         memset(dlgTemplate, 0, dlgsize);
614 
615         // these values are arbitrary, they won't be used normally anyhow
616         const LONG baseUnits = ::GetDialogBaseUnits();
617         dlgTemplate->x = 34;
618         dlgTemplate->y  = 22;
619         dlgTemplate->cx = ::MulDiv(sizeReal.x, 4, LOWORD(baseUnits));
620         dlgTemplate->cy = ::MulDiv(sizeReal.y, 8, HIWORD(baseUnits));
621 
622         // reuse the code in MSWGetStyle() but correct the results slightly for
623         // the dialog
624         //
625         // NB: we need a temporary variable as we can't pass pointer to
626         //     dwExtendedStyle directly, it's not aligned correctly for 64 bit
627         //     architectures
628         WXDWORD dwExtendedStyle;
629         dlgTemplate->style = MSWGetStyle(style, &dwExtendedStyle);
630         dlgTemplate->dwExtendedStyle = dwExtendedStyle;
631 
632         // all dialogs are popups
633         dlgTemplate->style |= WS_POPUP;
634 
635 #ifndef __WXWINCE__
636         if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft )
637         {
638             dlgTemplate->dwExtendedStyle |= WS_EX_LAYOUTRTL;
639         }
640 
641         // force 3D-look if necessary, it looks impossibly ugly otherwise
642         if ( style & (wxRESIZE_BORDER | wxCAPTION) )
643             dlgTemplate->style |= DS_MODALFRAME;
644 #endif
645 
646         ret = CreateDialog(dlgTemplate, title, pos, sizeReal);
647         free(dlgTemplate);
648     }
649     else // !dialog
650     {
651         ret = CreateFrame(title, pos, sizeReal);
652     }
653 
654 #ifndef __WXWINCE__
655     if ( ret && !(GetWindowStyleFlag() & wxCLOSE_BOX) )
656     {
657         EnableCloseButton(false);
658     }
659 #endif
660 
661     // for standard dialogs the dialog manager generates WM_CHANGEUISTATE
662     // itself but for custom windows we have to do it ourselves in order to
663     // make the keyboard indicators (such as underlines for accelerators and
664     // focus rectangles) work under Win2k+
665     if ( ret )
666     {
667         MSWUpdateUIState(UIS_INITIALIZE);
668     }
669 
670     // Note: if we include PocketPC in this test, dialogs can fail to show up,
671     // for example the text entry dialog in the dialogs sample. Problem with Maximise()?
672 #if defined(__WXWINCE__) && (defined(__SMARTPHONE__) || defined(__WINCE_STANDARDSDK__))
673     if ( ( style & wxMAXIMIZE ) || IsAlwaysMaximized() )
674     {
675         this->Maximize();
676     }
677 #endif
678 
679 #if defined(__SMARTPHONE__) && defined(__WXWINCE__)
680     SetRightMenu(); // to nothing for initialization
681 #endif
682 
683     return ret;
684 }
685 
~wxTopLevelWindowMSW()686 wxTopLevelWindowMSW::~wxTopLevelWindowMSW()
687 {
688     delete m_menuSystem;
689 
690     SendDestroyEvent();
691 
692 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
693     SHACTIVATEINFO* info = (SHACTIVATEINFO*) m_activateInfo;
694     delete info;
695     m_activateInfo = NULL;
696 #endif
697 
698     // after destroying an owned window, Windows activates the next top level
699     // window in Z order but it may be different from our owner (to reproduce
700     // this simply Alt-TAB to another application and back before closing the
701     // owned frame) whereas we always want to yield activation to our parent
702     if ( HasFlag(wxFRAME_FLOAT_ON_PARENT) )
703     {
704         wxWindow *parent = GetParent();
705         if ( parent )
706         {
707             ::BringWindowToTop(GetHwndOf(parent));
708         }
709     }
710 }
711 
712 // ----------------------------------------------------------------------------
713 // wxTopLevelWindowMSW showing
714 // ----------------------------------------------------------------------------
715 
DoShowWindow(int nShowCmd)716 void wxTopLevelWindowMSW::DoShowWindow(int nShowCmd)
717 {
718     ::ShowWindow(GetHwnd(), nShowCmd);
719 
720     // Hiding the window doesn't change its iconized state.
721     if ( nShowCmd != SW_HIDE )
722     {
723         // Otherwise restoring, maximizing or showing the window normally also
724         // makes it not iconized and only minimizing it does make it iconized.
725         m_iconized = nShowCmd == SW_MINIMIZE;
726     }
727 }
728 
ShowWithoutActivating()729 void wxTopLevelWindowMSW::ShowWithoutActivating()
730 {
731     if ( !wxWindowBase::Show(true) )
732         return;
733 
734     DoShowWindow(SW_SHOWNA);
735 }
736 
Show(bool show)737 bool wxTopLevelWindowMSW::Show(bool show)
738 {
739     // don't use wxWindow version as we want to call DoShowWindow() ourselves
740     if ( !wxWindowBase::Show(show) )
741         return false;
742 
743     int nShowCmd;
744     if ( show )
745     {
746         if ( m_maximizeOnShow )
747         {
748             // show and maximize
749             nShowCmd = SW_MAXIMIZE;
750 
751             // This is necessary, or no window appears
752 #if defined( __WINCE_STANDARDSDK__) || defined(__SMARTPHONE__)
753             DoShowWindow(SW_SHOW);
754 #endif
755 
756             m_maximizeOnShow = false;
757         }
758         else if ( m_iconized )
759         {
760             // We were iconized while we were hidden, so now we need to show
761             // the window in iconized state.
762             nShowCmd = SW_MINIMIZE;
763         }
764         else if ( ::IsIconic(GetHwnd()) )
765         {
766             // We were restored while we were hidden, so now we need to show
767             // the window in its normal state.
768             //
769             // As below, don't activate some kinds of windows.
770             if ( HasFlag(wxFRAME_TOOL_WINDOW) || !IsEnabled() )
771                 nShowCmd = SW_SHOWNOACTIVATE;
772             else
773                 nShowCmd = SW_RESTORE;
774         }
775         else // just show
776         {
777             // we shouldn't use SW_SHOW which also activates the window for
778             // tool frames (as they shouldn't steal focus from the main window)
779             // nor for the currently disabled windows as they would be enabled
780             // as a side effect
781             if ( HasFlag(wxFRAME_TOOL_WINDOW) || !IsEnabled() )
782                 nShowCmd = SW_SHOWNA;
783             else
784                 nShowCmd = SW_SHOW;
785         }
786     }
787     else // hide
788     {
789         nShowCmd = SW_HIDE;
790     }
791 
792 #if wxUSE_DEFERRED_SIZING
793     // we only set pending size if we're maximized before being shown, now that
794     // we're shown we don't need it any more (it is reset in size event handler
795     // for child windows but we have to do it ourselves for this parent window)
796     //
797     // make sure to reset it before actually showing the window as this will
798     // generate WM_SIZE events and we want to use the correct client size from
799     // them, not the size returned by WM_NCCALCSIZE in DoGetClientSize() which
800     // turns out to be wrong for maximized windows (see #11762)
801     m_pendingSize = wxDefaultSize;
802 #endif // wxUSE_DEFERRED_SIZING
803 
804     DoShowWindow(nShowCmd);
805 
806 #if defined(__WXWINCE__) && (_WIN32_WCE >= 400 && !defined(__POCKETPC__) && !defined(__SMARTPHONE__))
807     // Addornments have to be added when the frame is the correct size
808     wxFrame* frame = wxDynamicCast(this, wxFrame);
809     if (frame && frame->GetMenuBar())
810         frame->GetMenuBar()->AddAdornments(GetWindowStyleFlag());
811 #endif
812 
813     return true;
814 }
815 
Raise()816 void wxTopLevelWindowMSW::Raise()
817 {
818     ::SetForegroundWindow(GetHwnd());
819 }
820 
821 // ----------------------------------------------------------------------------
822 // wxTopLevelWindowMSW maximize/minimize
823 // ----------------------------------------------------------------------------
824 
Maximize(bool maximize)825 void wxTopLevelWindowMSW::Maximize(bool maximize)
826 {
827     if ( IsShown() )
828     {
829         // just maximize it directly
830         DoShowWindow(maximize ? SW_MAXIMIZE : SW_RESTORE);
831     }
832     else // hidden
833     {
834         // we can't maximize the hidden frame because it shows it as well,
835         // so just remember that we should do it later in this case
836         m_maximizeOnShow = maximize;
837 
838 #if wxUSE_DEFERRED_SIZING
839         // after calling Maximize() the client code expects to get the frame
840         // "real" size and doesn't want to know that, because of implementation
841         // details, the frame isn't really maximized yet but will be only once
842         // it's shown, so return our size as it will be then in this case
843         if ( maximize )
844         {
845             // we must only change pending size here, and not call SetSize()
846             // because otherwise Windows would think that this (full screen)
847             // size is the natural size for the frame and so would use it when
848             // the user clicks on "restore" title bar button instead of the
849             // correct initial frame size
850             //
851             // NB: unfortunately we don't know which display we're on yet so we
852             //     have to use the default one
853             m_pendingSize = wxGetClientDisplayRect().GetSize();
854         }
855         //else: can't do anything in this case, we don't have the old size
856 #endif // wxUSE_DEFERRED_SIZING
857     }
858 }
859 
IsMaximized() const860 bool wxTopLevelWindowMSW::IsMaximized() const
861 {
862     return IsAlwaysMaximized() ||
863 #if !defined(__SMARTPHONE__) && !defined(__POCKETPC__) && !defined(__WINCE_STANDARDSDK__)
864 
865            (::IsZoomed(GetHwnd()) != 0) ||
866 #endif
867            m_maximizeOnShow;
868 }
869 
Iconize(bool iconize)870 void wxTopLevelWindowMSW::Iconize(bool iconize)
871 {
872     if ( iconize == m_iconized )
873     {
874         // Do nothing, in particular don't restore non-iconized windows when
875         // Iconize(false) is called as this would wrongly un-maximize them.
876         return;
877     }
878 
879     if ( IsShown() )
880     {
881         // change the window state immediately
882         DoShowWindow(iconize ? SW_MINIMIZE : SW_RESTORE);
883     }
884     else // hidden
885     {
886         // iconizing the window shouldn't show it so just update the internal
887         // state (otherwise it's done by DoShowWindow() itself)
888         m_iconized = iconize;
889     }
890 }
891 
IsIconized() const892 bool wxTopLevelWindowMSW::IsIconized() const
893 {
894 #ifdef __WXWINCE__
895     return false;
896 #else
897     if ( !IsShown() )
898         return m_iconized;
899 
900     // don't use m_iconized, it may be briefly out of sync with the real state
901     // as it's only modified when we receive a WM_SIZE and we could be called
902     // from an event handler from one of the messages we receive before it,
903     // such as WM_MOVE
904     return ::IsIconic(GetHwnd()) != 0;
905 #endif
906 }
907 
Restore()908 void wxTopLevelWindowMSW::Restore()
909 {
910     DoShowWindow(SW_RESTORE);
911 }
912 
SetLayoutDirection(wxLayoutDirection dir)913 void wxTopLevelWindowMSW::SetLayoutDirection(wxLayoutDirection dir)
914 {
915     if ( dir == wxLayout_Default )
916         dir = wxTheApp->GetLayoutDirection();
917 
918     if ( dir != wxLayout_Default )
919         wxTopLevelWindowBase::SetLayoutDirection(dir);
920 }
921 
922 // ----------------------------------------------------------------------------
923 // wxTopLevelWindowMSW geometry
924 // ----------------------------------------------------------------------------
925 
926 #ifndef __WXWINCE__
927 
DoGetPosition(int * x,int * y) const928 void wxTopLevelWindowMSW::DoGetPosition(int *x, int *y) const
929 {
930     if ( IsIconized() )
931     {
932         WINDOWPLACEMENT wp;
933         wp.length = sizeof(WINDOWPLACEMENT);
934         if ( ::GetWindowPlacement(GetHwnd(), &wp) )
935         {
936             RECT& rc = wp.rcNormalPosition;
937 
938             // the position returned by GetWindowPlacement() is in workspace
939             // coordinates except for windows with WS_EX_TOOLWINDOW style
940             if ( !HasFlag(wxFRAME_TOOL_WINDOW) )
941             {
942                 // we must use the correct display for the translation as the
943                 // task bar might be shown on one display but not the other one
944                 int n = wxDisplay::GetFromWindow(this);
945                 wxDisplay dpy(n == wxNOT_FOUND ? 0 : n);
946                 const wxPoint ptOfs = dpy.GetClientArea().GetPosition() -
947                                       dpy.GetGeometry().GetPosition();
948 
949                 rc.left += ptOfs.x;
950                 rc.top += ptOfs.y;
951             }
952 
953             if ( x )
954                 *x = rc.left;
955             if ( y )
956                 *y = rc.top;
957 
958             return;
959         }
960 
961         wxLogLastError(wxT("GetWindowPlacement"));
962     }
963     //else: normal case
964 
965     wxTopLevelWindowBase::DoGetPosition(x, y);
966 }
967 
DoGetSize(int * width,int * height) const968 void wxTopLevelWindowMSW::DoGetSize(int *width, int *height) const
969 {
970     if ( IsIconized() )
971     {
972         WINDOWPLACEMENT wp;
973         wp.length = sizeof(WINDOWPLACEMENT);
974         if ( ::GetWindowPlacement(GetHwnd(), &wp) )
975         {
976             const RECT& rc = wp.rcNormalPosition;
977 
978             if ( width )
979                 *width = rc.right - rc.left;
980             if ( height )
981                 *height = rc.bottom - rc.top;
982 
983             return;
984         }
985 
986         wxLogLastError(wxT("GetWindowPlacement"));
987     }
988     //else: normal case
989 
990     wxTopLevelWindowBase::DoGetSize(width, height);
991 }
992 
993 #endif // __WXWINCE__
994 
995 void
MSWGetCreateWindowCoords(const wxPoint & pos,const wxSize & size,int & x,int & y,int & w,int & h) const996 wxTopLevelWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
997                                               const wxSize& size,
998                                               int& x, int& y,
999                                               int& w, int& h) const
1000 {
1001     // let the system position the window if no explicit position was specified
1002     if ( pos.x == wxDefaultCoord )
1003     {
1004         // if x is set to CW_USEDEFAULT, y parameter is ignored anyhow so we
1005         // can just as well set it to CW_USEDEFAULT as well
1006         x =
1007         y = CW_USEDEFAULT;
1008     }
1009     else
1010     {
1011         // OTOH, if x is not set to CW_USEDEFAULT, y shouldn't be set to it
1012         // neither because it is not handled as a special value by Windows then
1013         // and so we have to choose some default value for it, even if a
1014         // completely arbitrary one
1015         static const int DEFAULT_Y = 200;
1016 
1017         x = pos.x;
1018         y = pos.y == wxDefaultCoord ? DEFAULT_Y : pos.y;
1019     }
1020 
1021     if ( size.x == wxDefaultCoord || size.y == wxDefaultCoord )
1022     {
1023         // We don't use CW_USEDEFAULT here for several reasons:
1024         //
1025         //  1. It results in huge frames on modern screens (1000*800 is not
1026         //     uncommon on my 1280*1024 screen) which is way too big for a half
1027         //     empty frame of most of wxWidgets samples for example)
1028         //
1029         //  2. It is buggy for frames with wxFRAME_TOOL_WINDOW style for which
1030         //     the default is for whatever reason 8*8 which breaks client <->
1031         //     window size calculations (it would be nice if it didn't, but it
1032         //     does and the simplest way to fix it seemed to change the broken
1033         //     default size anyhow)
1034         //
1035         //  3. There is just no advantage in doing it: with x and y it is
1036         //     possible that [future versions of] Windows position the new top
1037         //     level window in some smart way which we can't do, but we can
1038         //     guess a reasonably good size for a new window just as well
1039         //     ourselves
1040         //
1041         // The only exception is for the Windows CE platform where the system
1042         // does know better than we how should the windows be sized
1043 #ifdef _WIN32_WCE
1044         w =
1045         h = CW_USEDEFAULT;
1046 #else // !_WIN32_WCE
1047         wxSize sizeReal = size;
1048         sizeReal.SetDefaults(GetDefaultSize());
1049 
1050         w = sizeReal.x;
1051         h = sizeReal.y;
1052 #endif // _WIN32_WCE/!_WIN32_WCE
1053     }
1054     else
1055     {
1056         w = size.x;
1057         h = size.y;
1058     }
1059 }
1060 
1061 // ----------------------------------------------------------------------------
1062 // wxTopLevelWindowMSW fullscreen
1063 // ----------------------------------------------------------------------------
1064 
ShowFullScreen(bool show,long style)1065 bool wxTopLevelWindowMSW::ShowFullScreen(bool show, long style)
1066 {
1067     if ( show == IsFullScreen() )
1068     {
1069         // nothing to do
1070         return true;
1071     }
1072 
1073     m_fsIsShowing = show;
1074 
1075     if ( show )
1076     {
1077         m_fsStyle = style;
1078 
1079         // zap the frame borders
1080 
1081         // save the 'normal' window style
1082         m_fsOldWindowStyle = GetWindowLong(GetHwnd(), GWL_STYLE);
1083 
1084         // save the old position, width & height, maximize state
1085         m_fsOldSize = GetRect();
1086         m_fsIsMaximized = IsMaximized();
1087 
1088         // decide which window style flags to turn off
1089         LONG newStyle = m_fsOldWindowStyle;
1090         LONG offFlags = 0;
1091 
1092         if (style & wxFULLSCREEN_NOBORDER)
1093         {
1094             offFlags |= WS_BORDER;
1095 #ifndef __WXWINCE__
1096             offFlags |= WS_THICKFRAME;
1097 #endif
1098         }
1099         if (style & wxFULLSCREEN_NOCAPTION)
1100             offFlags |= WS_CAPTION | WS_SYSMENU;
1101 
1102         newStyle &= ~offFlags;
1103 
1104         // Full screen windows should logically be popups as they don't have
1105         // decorations (and are definitely not children) and while not using
1106         // this style doesn't seem to make any difference for most windows, it
1107         // breaks wxGLCanvas in some cases, see #15434, so just always use it.
1108         newStyle |= WS_POPUP;
1109 
1110         // change our window style to be compatible with full-screen mode
1111         ::SetWindowLong(GetHwnd(), GWL_STYLE, newStyle);
1112 
1113         wxRect rect;
1114 #if wxUSE_DISPLAY
1115         // resize to the size of the display containing us
1116         int dpy = wxDisplay::GetFromWindow(this);
1117         if ( dpy != wxNOT_FOUND )
1118         {
1119             rect = wxDisplay(dpy).GetGeometry();
1120         }
1121         else // fall back to the main desktop
1122 #endif // wxUSE_DISPLAY
1123         {
1124             // resize to the size of the desktop
1125             wxCopyRECTToRect(wxGetWindowRect(::GetDesktopWindow()), rect);
1126 #ifdef __WXWINCE__
1127             // FIXME: size of the bottom menu (toolbar)
1128             // should be taken in account
1129             rect.height += rect.y;
1130             rect.y       = 0;
1131 #endif
1132         }
1133 
1134         SetSize(rect);
1135 
1136         // now flush the window style cache and actually go full-screen
1137         long flags = SWP_FRAMECHANGED;
1138 
1139         // showing the frame full screen should also show it if it's still
1140         // hidden
1141         if ( !IsShown() )
1142         {
1143             // don't call wxWindow version to avoid flicker from calling
1144             // ::ShowWindow() -- we're going to show the window at the correct
1145             // location directly below -- but do call the wxWindowBase version
1146             // to sync the internal m_isShown flag
1147             wxWindowBase::Show();
1148 
1149             flags |= SWP_SHOWWINDOW;
1150         }
1151 
1152         SetWindowPos(GetHwnd(), HWND_TOP,
1153                      rect.x, rect.y, rect.width, rect.height,
1154                      flags);
1155 
1156 #if !defined(__HANDHELDPC__) && (defined(__WXWINCE__) && (_WIN32_WCE < 400))
1157         ::SHFullScreen(GetHwnd(), SHFS_HIDETASKBAR | SHFS_HIDESIPBUTTON);
1158 #endif
1159 
1160         // finally send an event allowing the window to relayout itself &c
1161         wxSizeEvent event(rect.GetSize(), GetId());
1162         event.SetEventObject(this);
1163         HandleWindowEvent(event);
1164     }
1165     else // stop showing full screen
1166     {
1167 #if !defined(__HANDHELDPC__) && (defined(__WXWINCE__) && (_WIN32_WCE < 400))
1168         ::SHFullScreen(GetHwnd(), SHFS_SHOWTASKBAR | SHFS_SHOWSIPBUTTON);
1169 #endif
1170         Maximize(m_fsIsMaximized);
1171         SetWindowLong(GetHwnd(),GWL_STYLE, m_fsOldWindowStyle);
1172         SetWindowPos(GetHwnd(),HWND_TOP,m_fsOldSize.x, m_fsOldSize.y,
1173             m_fsOldSize.width, m_fsOldSize.height, SWP_FRAMECHANGED);
1174     }
1175 
1176     return true;
1177 }
1178 
1179 // ----------------------------------------------------------------------------
1180 // wxTopLevelWindowMSW misc
1181 // ----------------------------------------------------------------------------
1182 
SetTitle(const wxString & title)1183 void wxTopLevelWindowMSW::SetTitle( const wxString& title)
1184 {
1185     SetLabel(title);
1186 }
1187 
GetTitle() const1188 wxString wxTopLevelWindowMSW::GetTitle() const
1189 {
1190     return GetLabel();
1191 }
1192 
DoSelectAndSetIcon(const wxIconBundle & icons,int smX,int smY,int i)1193 bool wxTopLevelWindowMSW::DoSelectAndSetIcon(const wxIconBundle& icons,
1194                                              int smX,
1195                                              int smY,
1196                                              int i)
1197 {
1198     const wxSize size(::GetSystemMetrics(smX), ::GetSystemMetrics(smY));
1199 
1200     wxIcon icon = icons.GetIcon(size, wxIconBundle::FALLBACK_NEAREST_LARGER);
1201 
1202     if ( !icon.IsOk() )
1203         return false;
1204 
1205     ::SendMessage(GetHwnd(), WM_SETICON, i, (LPARAM)GetHiconOf(icon));
1206     return true;
1207 }
1208 
SetIcons(const wxIconBundle & icons)1209 void wxTopLevelWindowMSW::SetIcons(const wxIconBundle& icons)
1210 {
1211     wxTopLevelWindowBase::SetIcons(icons);
1212 
1213     if ( icons.IsEmpty() )
1214     {
1215         // FIXME: SetIcons(wxNullIconBundle) should unset existing icons,
1216         //        but we currently don't do that
1217         wxASSERT_MSG( m_icons.IsEmpty(), "unsetting icons doesn't work" );
1218         return;
1219     }
1220 
1221     DoSelectAndSetIcon(icons, SM_CXSMICON, SM_CYSMICON, ICON_SMALL);
1222     DoSelectAndSetIcon(icons, SM_CXICON, SM_CYICON, ICON_BIG);
1223 }
1224 
EnableCloseButton(bool enable)1225 bool wxTopLevelWindowMSW::EnableCloseButton(bool enable)
1226 {
1227 #if !defined(__WXMICROWIN__)
1228     // get system (a.k.a. window) menu
1229     HMENU hmenu = GetSystemMenu(GetHwnd(), FALSE /* get it */);
1230     if ( !hmenu )
1231     {
1232         // no system menu at all -- ok if we want to remove the close button
1233         // anyhow, but bad if we want to show it
1234         return !enable;
1235     }
1236 
1237     // enabling/disabling the close item from it also automatically
1238     // disables/enables the close title bar button
1239     if ( ::EnableMenuItem(hmenu, SC_CLOSE,
1240                           MF_BYCOMMAND |
1241                           (enable ? MF_ENABLED : MF_GRAYED)) == -1 )
1242     {
1243         wxLogLastError(wxT("EnableMenuItem(SC_CLOSE)"));
1244 
1245         return false;
1246     }
1247 #ifndef __WXWINCE__
1248     // update appearance immediately
1249     if ( !::DrawMenuBar(GetHwnd()) )
1250     {
1251         wxLogLastError(wxT("DrawMenuBar"));
1252     }
1253 #endif
1254 #endif // !__WXMICROWIN__
1255 
1256     return true;
1257 }
1258 
RequestUserAttention(int flags)1259 void wxTopLevelWindowMSW::RequestUserAttention(int flags)
1260 {
1261     // check if we can use FlashWindowEx(): unfortunately a simple test for
1262     // FLASHW_STOP doesn't work because MSVC6 headers do #define it but don't
1263     // provide FlashWindowEx() declaration, so try to detect whether we have
1264     // real headers for WINVER 0x0500 by checking for existence of a symbol not
1265     // declated in MSVC6 header
1266 #if defined(FLASHW_STOP) && defined(VK_XBUTTON1) && wxUSE_DYNLIB_CLASS
1267     // available in the headers, check if it is supported by the system
1268     typedef BOOL (WINAPI *FlashWindowEx_t)(FLASHWINFO *pfwi);
1269     static FlashWindowEx_t s_pfnFlashWindowEx = NULL;
1270     if ( !s_pfnFlashWindowEx )
1271     {
1272         wxDynamicLibrary dllUser32(wxT("user32.dll"));
1273         s_pfnFlashWindowEx = (FlashWindowEx_t)
1274                                 dllUser32.GetSymbol(wxT("FlashWindowEx"));
1275 
1276         // we can safely unload user32.dll here, it's going to remain loaded as
1277         // long as the program is running anyhow
1278     }
1279 
1280     if ( s_pfnFlashWindowEx )
1281     {
1282         WinStruct<FLASHWINFO> fwi;
1283         fwi.hwnd = GetHwnd();
1284         fwi.dwFlags = FLASHW_ALL;
1285         if ( flags & wxUSER_ATTENTION_INFO )
1286         {
1287             // just flash a few times
1288             fwi.uCount = 3;
1289         }
1290         else // wxUSER_ATTENTION_ERROR
1291         {
1292             // flash until the user notices it
1293             fwi.dwFlags |= FLASHW_TIMERNOFG;
1294         }
1295 
1296         s_pfnFlashWindowEx(&fwi);
1297     }
1298     else // FlashWindowEx() not available
1299 #endif // FlashWindowEx() defined
1300     {
1301         wxUnusedVar(flags);
1302 #ifndef __WXWINCE__
1303         ::FlashWindow(GetHwnd(), TRUE);
1304 #endif // __WXWINCE__
1305     }
1306 }
1307 
MSWGetSystemMenu() const1308 wxMenu *wxTopLevelWindowMSW::MSWGetSystemMenu() const
1309 {
1310 #ifndef __WXUNIVERSAL__
1311     if ( !m_menuSystem )
1312     {
1313         HMENU hmenu = ::GetSystemMenu(GetHwnd(), FALSE);
1314         if ( !hmenu )
1315         {
1316             wxLogLastError(wxT("GetSystemMenu()"));
1317             return NULL;
1318         }
1319 
1320         wxTopLevelWindowMSW * const
1321             self = const_cast<wxTopLevelWindowMSW *>(this);
1322 
1323         self->m_menuSystem = wxMenu::MSWNewFromHMENU(hmenu);
1324 
1325         // We need to somehow associate this menu with this window to ensure
1326         // that we get events from it. A natural idea would be to pretend that
1327         // it's attached to our menu bar but this wouldn't work if we don't
1328         // have any menu bar which is a common case for applications using
1329         // custom items in the system menu (they mostly do it exactly because
1330         // they don't have any other menus).
1331         //
1332         // So reuse the invoking window pointer instead, this is not exactly
1333         // correct but doesn't seem to have any serious drawbacks.
1334         m_menuSystem->SetInvokingWindow(self);
1335     }
1336 #endif // #ifndef __WXUNIVERSAL__
1337 
1338     return m_menuSystem;
1339 }
1340 
1341 // ----------------------------------------------------------------------------
1342 // Transparency support
1343 // ---------------------------------------------------------------------------
1344 
SetTransparent(wxByte alpha)1345 bool wxTopLevelWindowMSW::SetTransparent(wxByte alpha)
1346 {
1347 #if wxUSE_DYNLIB_CLASS
1348     typedef DWORD (WINAPI *PSETLAYEREDWINDOWATTR)(HWND, DWORD, BYTE, DWORD);
1349     static PSETLAYEREDWINDOWATTR
1350         pSetLayeredWindowAttributes = (PSETLAYEREDWINDOWATTR)-1;
1351 
1352     if ( pSetLayeredWindowAttributes == (PSETLAYEREDWINDOWATTR)-1 )
1353     {
1354         wxDynamicLibrary dllUser32(wxT("user32.dll"));
1355 
1356         // use RawGetSymbol() and not GetSymbol() to avoid error messages under
1357         // Windows 95: there is nothing the user can do about this anyhow
1358         pSetLayeredWindowAttributes = (PSETLAYEREDWINDOWATTR)
1359             dllUser32.RawGetSymbol(wxT("SetLayeredWindowAttributes"));
1360 
1361         // it's ok to destroy dllUser32 here, we link statically to user32.dll
1362         // anyhow so it won't be unloaded
1363     }
1364 
1365     if ( !pSetLayeredWindowAttributes )
1366         return false;
1367 #endif // wxUSE_DYNLIB_CLASS
1368 
1369     LONG exstyle = GetWindowLong(GetHwnd(), GWL_EXSTYLE);
1370 
1371     // if setting alpha to fully opaque then turn off the layered style
1372     if (alpha == 255)
1373     {
1374         SetWindowLong(GetHwnd(), GWL_EXSTYLE, exstyle & ~WS_EX_LAYERED);
1375         Refresh();
1376         return true;
1377     }
1378 
1379 #if wxUSE_DYNLIB_CLASS
1380     // Otherwise, set the layered style if needed and set the alpha value
1381     if ((exstyle & WS_EX_LAYERED) == 0 )
1382         SetWindowLong(GetHwnd(), GWL_EXSTYLE, exstyle | WS_EX_LAYERED);
1383 
1384     if ( pSetLayeredWindowAttributes(GetHwnd(), 0, (BYTE)alpha, LWA_ALPHA) )
1385         return true;
1386 #endif // wxUSE_DYNLIB_CLASS
1387 
1388     return false;
1389 }
1390 
CanSetTransparent()1391 bool wxTopLevelWindowMSW::CanSetTransparent()
1392 {
1393     // The API is available on win2k and above
1394 
1395     static int os_type = -1;
1396     static int ver_major = -1;
1397 
1398     if (os_type == -1)
1399         os_type = ::wxGetOsVersion(&ver_major);
1400 
1401     return (os_type == wxOS_WINDOWS_NT && ver_major >= 5);
1402 }
1403 
DoFreeze()1404 void wxTopLevelWindowMSW::DoFreeze()
1405 {
1406     // do nothing: freezing toplevel window causes paint and mouse events
1407     // to go through it any TLWs under it, so the best we can do is to freeze
1408     // all children -- and wxWindowBase::Freeze() does that
1409 }
1410 
DoThaw()1411 void wxTopLevelWindowMSW::DoThaw()
1412 {
1413     // intentionally empty -- see DoFreeze()
1414 }
1415 
1416 
1417 // ----------------------------------------------------------------------------
1418 // wxTopLevelWindow event handling
1419 // ----------------------------------------------------------------------------
1420 
DoSaveLastFocus()1421 void wxTopLevelWindowMSW::DoSaveLastFocus()
1422 {
1423     if ( m_iconized )
1424         return;
1425 
1426     // remember the last focused child if it is our child
1427     m_winLastFocused = FindFocus();
1428 
1429     if ( m_winLastFocused )
1430     {
1431         // and don't remember it if it's a child from some other frame
1432         if ( wxGetTopLevelParent(m_winLastFocused) != this )
1433         {
1434             m_winLastFocused = NULL;
1435         }
1436     }
1437 }
1438 
DoRestoreLastFocus()1439 void wxTopLevelWindowMSW::DoRestoreLastFocus()
1440 {
1441     wxWindow *parent = m_winLastFocused ? m_winLastFocused->GetParent()
1442                                         : NULL;
1443     if ( !parent )
1444     {
1445         parent = this;
1446     }
1447 
1448     wxSetFocusToChild(parent, &m_winLastFocused);
1449 }
1450 
OnActivate(wxActivateEvent & event)1451 void wxTopLevelWindowMSW::OnActivate(wxActivateEvent& event)
1452 {
1453     if ( event.GetActive() )
1454     {
1455         // We get WM_ACTIVATE before being restored from iconized state, so we
1456         // can be still iconized here. In this case, avoid restoring the focus
1457         // as it doesn't work anyhow and we will do when we're really restored.
1458         if ( m_iconized )
1459         {
1460             event.Skip();
1461             return;
1462         }
1463 
1464         // restore focus to the child which was last focused unless we already
1465         // have it
1466         wxLogTrace(wxT("focus"), wxT("wxTLW %p activated."), m_hWnd);
1467 
1468         wxWindow *winFocus = FindFocus();
1469         if ( !winFocus || wxGetTopLevelParent(winFocus) != this )
1470             DoRestoreLastFocus();
1471     }
1472     else // deactivating
1473     {
1474         DoSaveLastFocus();
1475 
1476         wxLogTrace(wxT("focus"),
1477                    wxT("wxTLW %p deactivated, last focused: %p."),
1478                    m_hWnd,
1479                    m_winLastFocused ? GetHwndOf(m_winLastFocused) : NULL);
1480 
1481         event.Skip();
1482     }
1483 }
1484 
1485 #if wxUSE_MENUS
1486 
1487 bool
HandleMenuSelect(WXWORD nItem,WXWORD flags,WXHMENU hMenu)1488 wxTopLevelWindowMSW::HandleMenuSelect(WXWORD nItem, WXWORD flags, WXHMENU hMenu)
1489 {
1490     // Ignore the special messages generated when the menu is closed (this is
1491     // the only case when the flags are set to -1), in particular don't clear
1492     // the help string in the status bar when this happens as it had just been
1493     // restored by the base class code.
1494     if ( !hMenu && flags == 0xffff )
1495         return false;
1496 
1497     // Unfortunately we also need to ignore another message which is sent after
1498     // closing the currently active submenu of the menu bar by pressing Escape:
1499     // in this case we get WM_UNINITMENUPOPUP, from which we generate
1500     // wxEVT_MENU_CLOSE, and _then_ we get WM_MENUSELECT for the top level menu
1501     // from which we overwrite the help string just restored by OnMenuClose()
1502     // handler in wxFrameBase. To prevent this from happening we discard these
1503     // messages but only in the case it's really the top level menu as we still
1504     // need to clear the help string when a submenu is selected in a menu.
1505     if ( flags == (MF_POPUP | MF_HILITE) && !m_menuDepth )
1506         return false;
1507 
1508     // sign extend to int from unsigned short we get from Windows
1509     int item = (signed short)nItem;
1510 
1511     // WM_MENUSELECT is generated for both normal items and menus, including
1512     // the top level menus of the menu bar, which can't be represented using
1513     // any valid identifier in wxMenuEvent so use an otherwise unused value for
1514     // them
1515     if ( flags & (MF_POPUP | MF_SEPARATOR) )
1516         item = wxID_NONE;
1517 
1518     wxMenuEvent event(wxEVT_MENU_HIGHLIGHT, item);
1519     event.SetEventObject(this);
1520 
1521     if ( HandleWindowEvent(event) )
1522         return true;
1523 
1524     // by default, i.e. if the event wasn't handled above, clear the status bar
1525     // text when an item which can't have any associated help string in wx API
1526     // is selected
1527     if ( item == wxID_NONE )
1528         DoGiveHelp(wxEmptyString, true);
1529 
1530     return false;
1531 }
1532 
1533 bool
DoSendMenuOpenCloseEvent(wxEventType evtType,wxMenu * menu,bool popup)1534 wxTopLevelWindowMSW::DoSendMenuOpenCloseEvent(wxEventType evtType, wxMenu* menu, bool popup)
1535 {
1536     // Update the menu depth when dealing with the top level menus.
1537     if ( !popup )
1538     {
1539         if ( evtType == wxEVT_MENU_OPEN )
1540         {
1541             m_menuDepth++;
1542         }
1543         else if ( evtType == wxEVT_MENU_CLOSE )
1544         {
1545             wxASSERT_MSG( m_menuDepth > 0, wxS("No open menus?") );
1546 
1547             m_menuDepth--;
1548         }
1549         else
1550         {
1551             wxFAIL_MSG( wxS("Unexpected menu event type") );
1552         }
1553     }
1554 
1555     wxMenuEvent event(evtType, popup ? wxID_ANY : 0, menu);
1556     event.SetEventObject(menu);
1557 
1558     return HandleWindowEvent(event);
1559 }
1560 
HandleExitMenuLoop(WXWORD isPopup)1561 bool wxTopLevelWindowMSW::HandleExitMenuLoop(WXWORD isPopup)
1562 {
1563     return DoSendMenuOpenCloseEvent(wxEVT_MENU_CLOSE,
1564                                     isPopup ? wxCurrentPopupMenu : NULL,
1565                                     isPopup != 0);
1566 }
1567 
HandleMenuPopup(wxEventType evtType,WXHMENU hMenu)1568 bool wxTopLevelWindowMSW::HandleMenuPopup(wxEventType evtType, WXHMENU hMenu)
1569 {
1570     bool isPopup = false;
1571     wxMenu* menu = NULL;
1572     if ( wxCurrentPopupMenu && wxCurrentPopupMenu->GetHMenu() == hMenu )
1573     {
1574         menu = wxCurrentPopupMenu;
1575         isPopup = true;
1576     }
1577     else
1578     {
1579         menu = MSWFindMenuFromHMENU(hMenu);
1580     }
1581 
1582 
1583     return DoSendMenuOpenCloseEvent(evtType, menu, isPopup);
1584 }
1585 
MSWFindMenuFromHMENU(WXHMENU WXUNUSED (hMenu))1586 wxMenu* wxTopLevelWindowMSW::MSWFindMenuFromHMENU(WXHMENU WXUNUSED(hMenu))
1587 {
1588     // We don't have any menus at this level.
1589     return NULL;
1590 }
1591 
1592 #endif // wxUSE_MENUS
1593 
1594 
1595 
1596 // the DialogProc for all wxWidgets dialogs
1597 LONG APIENTRY _EXPORT
wxDlgProc(HWND hDlg,UINT message,WPARAM WXUNUSED (wParam),LPARAM WXUNUSED (lParam))1598 wxDlgProc(HWND hDlg,
1599           UINT message,
1600           WPARAM WXUNUSED(wParam),
1601           LPARAM WXUNUSED(lParam))
1602 {
1603     switch ( message )
1604     {
1605         case WM_INITDIALOG:
1606         {
1607             // under CE, add a "Ok" button in the dialog title bar and make it full
1608             // screen
1609             //
1610             // TODO: find the window for this HWND, and take into account
1611             // wxMAXIMIZE and wxCLOSE_BOX. For now, assume both are present.
1612             //
1613             // Standard SDK doesn't have aygshell.dll: see
1614             // include/wx/msw/wince/libraries.h
1615 #if defined(__WXWINCE__) && !defined(__WINCE_STANDARDSDK__) && !defined(__HANDHELDPC__)
1616             SHINITDLGINFO shidi;
1617             shidi.dwMask = SHIDIM_FLAGS;
1618             shidi.dwFlags = SHIDIF_SIZEDLG // take account of the SIP or menubar
1619 #ifndef __SMARTPHONE__
1620                             | SHIDIF_DONEBUTTON
1621 #endif
1622                         ;
1623             shidi.hDlg = hDlg;
1624             SHInitDialog( &shidi );
1625 #else // no SHInitDialog()
1626             wxUnusedVar(hDlg);
1627 #endif
1628             // for WM_INITDIALOG, returning TRUE tells system to set focus to
1629             // the first control in the dialog box, but as we set the focus
1630             // ourselves, we return FALSE for it as well
1631             return FALSE;
1632         }
1633     }
1634 
1635     // for almost all messages, returning FALSE means that we didn't process
1636     // the message
1637     return FALSE;
1638 }
1639 
1640 // ============================================================================
1641 // wxTLWHiddenParentModule implementation
1642 // ============================================================================
1643 
1644 HWND wxTLWHiddenParentModule::ms_hwnd = NULL;
1645 
1646 const wxChar *wxTLWHiddenParentModule::ms_className = NULL;
1647 
OnInit()1648 bool wxTLWHiddenParentModule::OnInit()
1649 {
1650     ms_hwnd = NULL;
1651     ms_className = NULL;
1652 
1653     return true;
1654 }
1655 
OnExit()1656 void wxTLWHiddenParentModule::OnExit()
1657 {
1658     if ( ms_hwnd )
1659     {
1660         if ( !::DestroyWindow(ms_hwnd) )
1661         {
1662             wxLogLastError(wxT("DestroyWindow(hidden TLW parent)"));
1663         }
1664 
1665         ms_hwnd = NULL;
1666     }
1667 
1668     if ( ms_className )
1669     {
1670         if ( !::UnregisterClass(ms_className, wxGetInstance()) )
1671         {
1672             wxLogLastError(wxT("UnregisterClass(\"wxTLWHiddenParent\")"));
1673         }
1674 
1675         ms_className = NULL;
1676     }
1677 }
1678 
1679 /* static */
GetHWND()1680 HWND wxTLWHiddenParentModule::GetHWND()
1681 {
1682     if ( !ms_hwnd )
1683     {
1684         if ( !ms_className )
1685         {
1686             static const wxChar *HIDDEN_PARENT_CLASS = wxT("wxTLWHiddenParent");
1687 
1688             WNDCLASS wndclass;
1689             wxZeroMemory(wndclass);
1690 
1691             wndclass.lpfnWndProc   = DefWindowProc;
1692             wndclass.hInstance     = wxGetInstance();
1693             wndclass.lpszClassName = HIDDEN_PARENT_CLASS;
1694 
1695             if ( !::RegisterClass(&wndclass) )
1696             {
1697                 wxLogLastError(wxT("RegisterClass(\"wxTLWHiddenParent\")"));
1698             }
1699             else
1700             {
1701                 ms_className = HIDDEN_PARENT_CLASS;
1702             }
1703         }
1704 
1705         ms_hwnd = ::CreateWindow(ms_className, wxEmptyString, 0, 0, 0, 0, 0, NULL,
1706                                  (HMENU)NULL, wxGetInstance(), NULL);
1707         if ( !ms_hwnd )
1708         {
1709             wxLogLastError(wxT("CreateWindow(hidden TLW parent)"));
1710         }
1711     }
1712 
1713     return ms_hwnd;
1714 }
1715