1 // This file is part of BOINC.
2 // http://boinc.berkeley.edu
3 // Copyright (C) 2008 University of California
4 //
5 // BOINC is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU Lesser General Public License
7 // as published by the Free Software Foundation,
8 // either version 3 of the License, or (at your option) any later version.
9 //
10 // BOINC is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 // See the GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with BOINC.  If not, see <http://www.gnu.org/licenses/>.
17 
18 #if defined(__GNUG__) && !defined(__APPLE__)
19 #pragma implementation "sg_DlgMessages.h"
20 #endif
21 
22 #include "stdwx.h"
23 #include "common_defs.h"
24 #include "diagnostics.h"
25 #include "str_util.h"
26 #include "mfile.h"
27 #include "miofile.h"
28 #include "parse.h"
29 #include "error_numbers.h"
30 #include "Events.h"
31 #include "BOINCGUIApp.h"
32 #include "SkinManager.h"
33 #include "MainDocument.h"
34 #include "BOINCBaseFrame.h"
35 #include "version.h"
36 #include "sg_DlgMessages.h"
37 #include "NoticeListCtrl.h"
38 
39 #define TEST_BACKGROUND_WITH_MAGENTA_FILL 0
40 
41 ////@begin includes
42 ////@end includes
43 
44 ////@begin XPM images
45 ////@end XPM images
46 
47 
48 #define COLUMN_PROJECT              0
49 #define COLUMN_TIME                 1
50 #define COLUMN_MESSAGE              2
51 
52 /*!
53  * CPanelMessages type definition
54  */
55 
IMPLEMENT_DYNAMIC_CLASS(CPanelMessages,wxPanel)56 IMPLEMENT_DYNAMIC_CLASS( CPanelMessages, wxPanel )
57 
58 /*!
59  * CPanelMessages event table definition
60  */
61 
62 BEGIN_EVENT_TABLE( CPanelMessages, wxPanel )
63 ////@begin CPanelMessages event table entries
64     EVT_ERASE_BACKGROUND( CPanelMessages::OnEraseBackground )
65     EVT_BUTTON( wxID_OK, CPanelMessages::OnOK )
66     EVT_BUTTON(ID_SIMPLE_HELP, CPanelMessages::OnButtonHelp)
67 ////@end CPanelMessages event table entries
68 END_EVENT_TABLE()
69 
70 /*!
71  * CPanelMessages constructors
72  */
73 
74 CPanelMessages::CPanelMessages( )
75 {
76 }
77 
78 
CPanelMessages(wxWindow * parent)79 CPanelMessages::CPanelMessages( wxWindow* parent ) :
80     wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER)
81 {
82     Create();
83 }
84 
85 
86 /*!
87  * CPanelMessages creator
88  */
89 
Create()90 bool CPanelMessages::Create()
91 {
92 ////@begin CPanelMessages member initialisation
93     m_bProcessingRefreshEvent = false;
94 ////@end CPanelMessages member initialisation
95 
96     CreateControls();
97 
98     GetSizer()->Fit(this);
99     GetSizer()->SetSizeHints(this);
100 
101     return true;
102 }
103 
104 
~CPanelMessages()105 CPanelMessages::~CPanelMessages()
106 {
107 }
108 
109 
110 /*!
111  * Control creation for CPanelMessages
112  */
113 
CreateControls()114 void CPanelMessages::CreateControls()
115 {
116     CPanelMessages* itemDialog1 = this;
117 
118     wxFlexGridSizer* itemFlexGridSizer2 = new wxFlexGridSizer(5, 1, 1, 0);
119     itemFlexGridSizer2->AddGrowableRow(2);
120     itemFlexGridSizer2->AddGrowableCol(0);
121 
122     m_FetchingNoticesText = new wxStaticText(
123                                     this, wxID_ANY,
124                                     _("Fetching notices; please wait..."),
125                                     wxPoint(20, 20), wxDefaultSize, 0
126                                     );
127     m_FetchingNoticesText->SetBackgroundColour(*wxWHITE);
128     itemFlexGridSizer2->Add(m_FetchingNoticesText, 0, wxEXPAND | wxLEFT | wxRIGHT, ADJUSTFORXDPI(5));
129 
130     m_NoNoticesText = new wxStaticText(
131                                     this, wxID_ANY,
132                                     _("There are no notices at this time."),
133                                     wxPoint(20, 20), wxDefaultSize, 0
134                                     );
135     m_NoNoticesText->SetBackgroundColour(*wxWHITE);
136     itemFlexGridSizer2->Add(m_NoNoticesText, 0, wxEXPAND | wxLEFT | wxRIGHT, ADJUSTFORXDPI(5));
137 
138 
139     m_pHtmlListPane = new CNoticeListCtrl(itemDialog1);
140 	wxASSERT(m_pHtmlListPane);
141 
142     itemFlexGridSizer2->Add(m_pHtmlListPane, 0, wxGROW|wxALL, ADJUSTFORXDPI(5));
143 
144     wxBoxSizer* itemBoxSizer4 = new wxBoxSizer(wxHORIZONTAL);
145 
146     wxButton* itemButton44 = new wxButton(itemDialog1, wxID_OK, _("Close"),  wxDefaultPosition, wxDefaultSize);
147 
148     itemBoxSizer4->Add(itemButton44, 0, wxALIGN_CENTER_VERTICAL|wxALL, ADJUSTFORXDPI(5));
149 
150 #ifdef __WXMAC__            // Don't let Close button overlap window's grow icon
151     itemFlexGridSizer2->Add(itemBoxSizer4, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL|wxALL, ADJUSTFORXDPI(12));
152 #else
153     itemFlexGridSizer2->Add(itemBoxSizer4, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL|wxALL, ADJUSTFORXDPI(5));
154 #endif
155 
156     itemDialog1->SetSizer(itemFlexGridSizer2);
157 
158     m_FetchingNoticesText->Hide();
159     m_bFetchingNoticesTextWasDisplayed = false;
160 
161     m_NoNoticesText->Hide();
162     m_bNoNoticesTextWasDisplayed = false;
163     Layout();
164 }
165 
166 
167 /*!
168  * wxEVT_ERASE_BACKGROUND event handler for ID_DLGMESSAGES
169  */
170 
OnEraseBackground(wxEraseEvent & event)171 void CPanelMessages::OnEraseBackground(wxEraseEvent& event){
172     CSkinSimple* pSkinSimple = wxGetApp().GetSkinManager()->GetSimple();
173 
174     wxASSERT(pSkinSimple);
175     wxASSERT(wxDynamicCast(pSkinSimple, CSkinSimple));
176 
177     wxMemoryDC memDC;
178     wxCoord w, h, x, y;
179 
180     // Get the desired background bitmap
181     wxBitmap bmp(*pSkinSimple->GetDialogBackgroundImage()->GetBitmap());
182 
183     // Dialog dimensions
184     wxSize sz = GetClientSize();
185 
186     // Create a buffered device context to reduce flicker
187     wxBufferedDC dc(event.GetDC(), sz, wxBUFFER_CLIENT_AREA);
188 
189     // bitmap dimensions
190     w = bmp.GetWidth();
191     h = bmp.GetHeight();
192 
193 #if TEST_BACKGROUND_WITH_MAGENTA_FILL
194     // Fill the dialog with a magenta color so people can detect when something
195     //   is wrong
196     dc.SetBrush(wxBrush(wxColour(255,0,255)));
197     dc.SetPen(wxPen(wxColour(255,0,255)));
198     dc.DrawRectangle(0, 0, sz.GetWidth(), sz.GetHeight());
199 #else
200     wxColour bgColor(*pSkinSimple->GetDialogBackgroundImage()->GetBackgroundColor());
201     SetBackgroundColour(bgColor);
202 #endif
203 
204     // Is the bitmap smaller than the window?
205     if ( (w < sz.x) || (h < sz.y) ) {
206         // Check to see if they need to be rescaled to fit in the window
207         wxImage img = bmp.ConvertToImage();
208         img.Rescale((int) sz.x, (int) sz.y);
209 
210         // Draw our cool background (centered)
211         dc.DrawBitmap(wxBitmap(img), 0, 0);
212     } else {
213         // Snag the center of the bitmap and use it
214         //   for the background image
215         x = wxMax(0, (w - sz.x)/2);
216         y = wxMax(0, (h - sz.y)/2);
217 
218         // Select the desired bitmap into the memory DC so we can take
219         //   the center chunk of it.
220         memDC.SelectObject(bmp);
221 
222         // Draw the center chunk on the window
223         dc.Blit(0, 0, w, h, &memDC, x, y, wxCOPY);
224 
225         // Drop the bitmap
226         memDC.SelectObject(wxNullBitmap);
227     }
228 }
229 
230 
231 /*!
232  * called from CSimpleFrame::OnRefreshView()
233  */
234 
OnRefresh()235 void CPanelMessages::OnRefresh() {
236     if (!m_bProcessingRefreshEvent) {
237         m_bProcessingRefreshEvent = true;
238 
239         static wxString strLastMachineName = wxEmptyString;
240         wxString strNewMachineName = wxEmptyString;
241         CC_STATUS status;
242         CMainDocument* pDoc = wxGetApp().GetDocument();
243 
244         wxASSERT(pDoc);
245         wxASSERT(m_pHtmlListPane);
246         wxASSERT(wxDynamicCast(pDoc, CMainDocument));
247 
248         if (pDoc->IsConnected()) {
249             pDoc->GetConnectedComputerName(strNewMachineName);
250             if (strLastMachineName != strNewMachineName) {
251                 strLastMachineName = strNewMachineName;
252                 m_FetchingNoticesText->Show();
253                 m_NoNoticesText->Hide();
254                 m_pHtmlListPane->Clear();
255                 if (m_bNoNoticesTextWasDisplayed || !m_bFetchingNoticesTextWasDisplayed) {
256                     Layout();
257                 }
258                 m_bFetchingNoticesTextWasDisplayed = true;
259                 m_bNoNoticesTextWasDisplayed = false;
260             }
261         } else {
262             m_pHtmlListPane->Clear();
263         }
264 
265         // Don't call Freeze() / Thaw() here because it causes an unnecessary redraw
266         m_pHtmlListPane->UpdateUI();
267 
268         if (m_bFetchingNoticesTextWasDisplayed != m_pHtmlListPane->m_bDisplayFetchingNotices) {
269             m_bFetchingNoticesTextWasDisplayed = m_pHtmlListPane->m_bDisplayFetchingNotices;
270             m_FetchingNoticesText->Show(m_bFetchingNoticesTextWasDisplayed);
271             Layout();
272         }
273         if (m_bNoNoticesTextWasDisplayed != m_pHtmlListPane->m_bDisplayEmptyNotice) {
274             m_bNoNoticesTextWasDisplayed = m_pHtmlListPane->m_bDisplayEmptyNotice;
275             m_NoNoticesText->Show(m_bNoNoticesTextWasDisplayed);
276             Layout();
277         }
278 
279         pDoc->UpdateUnreadNoticeState();
280     }
281 }
282 
283 
284 /*!
285  * wxEVT_COMMAND_BUTTON_CLICKED event handler for wxID_OK
286  */
287 
OnOK(wxCommandEvent & event)288 void CPanelMessages::OnOK( wxCommandEvent& event ) {
289     event.Skip();
290 }
291 
292 
293 /*!
294  * wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_SIMPLE_HELP
295  */
296 
OnButtonHelp(wxCommandEvent & WXUNUSED (event))297 void CPanelMessages::OnButtonHelp( wxCommandEvent& WXUNUSED(event) ) {
298     wxLogTrace(wxT("Function Start/End"), wxT("CPanelMessages::OnHelp - Function Begin"));
299 
300     if (IsShown()) {
301     	wxString strURL = wxGetApp().GetSkinManager()->GetAdvanced()->GetOrganizationHelpUrl();
302 
303 		wxString wxurl;
304 		wxurl.Printf(
305             wxT("%s?target=simple_messages&version=%s&controlid=%d"),
306             strURL.c_str(),
307             wxString(BOINC_VERSION_STRING, wxConvUTF8).c_str(),
308             ID_SIMPLE_HELP
309         );
310         wxLaunchDefaultBrowser(wxurl);
311     }
312 
313     wxLogTrace(wxT("Function Start/End"), wxT("CPanelMessages::OnHelp - Function End"));
314 }
315 
316 
317 /*!
318  * wxEVT_NOTICELIST_ITEM_DISPLAY event handler for ID_LIST_NOTIFICATIONSVIEW
319  */
320 
321 
OnSaveState(wxConfigBase *)322 bool CPanelMessages::OnSaveState(wxConfigBase* /* pConfig */) {
323     return true;
324 }
325 
326 
OnRestoreState(wxConfigBase *)327 bool CPanelMessages::OnRestoreState(wxConfigBase* /* pConfig */) {
328     return true;
329 }
330 
331 
332 /*!
333  * CDlgMessages type definition
334  */
335 
IMPLEMENT_DYNAMIC_CLASS(CDlgMessages,wxDialog)336 IMPLEMENT_DYNAMIC_CLASS( CDlgMessages, wxDialog )
337 
338 /*!
339  * CDlgMessages event table definition
340  */
341 
342 BEGIN_EVENT_TABLE( CDlgMessages, wxDialog )
343 ////@begin CDlgMessages event table entries
344     EVT_HELP(wxID_ANY, CDlgMessages::OnHelp)
345     EVT_SHOW( CDlgMessages::OnShow )
346     EVT_BUTTON( wxID_OK, CDlgMessages::OnOK )
347 	EVT_SIZE(CDlgMessages::OnSize)
348     EVT_MOVE(CDlgMessages::OnMove)
349 ////@end CDlgMessages event table entries
350 END_EVENT_TABLE()
351 
352 /*!
353  * CDlgMessages constructors
354  */
355 
356 CDlgMessages::CDlgMessages( )
357 {
358 }
359 
360 
CDlgMessages(wxWindow * parent,wxWindowID id,const wxString & caption,const wxPoint & pos,const wxSize & size,long style)361 CDlgMessages::CDlgMessages( wxWindow* parent, wxWindowID id, const wxString& caption, const wxPoint& pos, const wxSize& size, long style )
362 {
363     Create(parent, id, caption, pos, size, style);
364 }
365 
366 
~CDlgMessages()367 CDlgMessages::~CDlgMessages() {
368     wxLogTrace(wxT("Function Start/End"), wxT("CDlgMessages::CDlgMessages - Destructor Function Begin"));
369 
370 	SaveState();    // Save state if close box on window frame clicked
371     wxConfigBase::Get(FALSE)->Flush();
372 
373     wxLogTrace(wxT("Function Start/End"), wxT("CDlgMessages::CDlgMessages - Destructor Function End"));
374 }
375 
376 
377 /*!
378  * CDlgMessages creator
379  */
380 
Create(wxWindow * parent,wxWindowID id,const wxString & caption,const wxPoint & pos,const wxSize & size,long style)381 bool CDlgMessages::Create( wxWindow* parent, wxWindowID id, const wxString& caption, const wxPoint& pos, const wxSize& size, long style )
382 {
383     CSkinAdvanced*         pSkinAdvanced = wxGetApp().GetSkinManager()->GetAdvanced();
384     wxASSERT(pSkinAdvanced);
385     wxASSERT(wxDynamicCast(pSkinAdvanced, CSkinAdvanced));
386 
387 
388     SetExtraStyle(GetExtraStyle()|wxWS_EX_BLOCK_EVENTS);
389 
390     wxDialog::Create( parent, id, caption, pos, size, style );
391 
392     wxString strCaption = caption;
393     if (strCaption.IsEmpty()) {
394         strCaption.Printf(_("%s - Notices"), pSkinAdvanced->GetApplicationName().c_str());
395     }
396     SetTitle(strCaption);
397 
398     // Initialize Application Icon
399     SetIcons(*pSkinAdvanced->GetApplicationIcon());
400 
401     Freeze();
402 
403     SetBackgroundStyle(wxBG_STYLE_CUSTOM);
404 
405 #if TEST_BACKGROUND_WITH_MAGENTA_FILL
406     SetBackgroundColour(wxColour(255, 0, 255));
407 #endif
408     SetForegroundColour(*wxBLACK);
409 
410     CreateControls();
411 
412     GetSizer()->Fit(this);
413     GetSizer()->SetSizeHints(this);
414 
415     // To work properly on Mac, RestoreState() must be called _after_
416     //  calling GetSizer()->Fit(), GetSizer()->SetSizeHints() and Center()
417     RestoreState();
418 
419     Thaw();
420 
421     return true;
422 }
423 
424 
425 /*!
426  * Control creation for CDlgMessages
427  */
428 
CreateControls()429 void CDlgMessages::CreateControls(){
430     wxFlexGridSizer* itemFlexGridSizer2 = new wxFlexGridSizer(1, 1, 0, 0);
431     itemFlexGridSizer2->AddGrowableRow(0);
432     itemFlexGridSizer2->AddGrowableCol(0);
433     SetSizer(itemFlexGridSizer2);
434 
435     m_pBackgroundPanel = new CPanelMessages(this);
436     itemFlexGridSizer2->Add(m_pBackgroundPanel, 0, wxGROW, 0);
437 
438     SetSizer(itemFlexGridSizer2);
439 }
440 
441 
442 /*!
443  * wxEVT_SHOW event handler for ID_DLGMESSAGES
444  */
445 
OnShow(wxShowEvent & event)446 void CDlgMessages::OnShow(wxShowEvent& event) {
447     wxLogTrace(wxT("Function Start/End"), wxT("CDlgMessages::OnShow - Function Begin"));
448     static bool bAlreadyRunning = false;
449 
450     if ((event.GetEventObject() == this) && !bAlreadyRunning) {
451         bAlreadyRunning = true;
452 
453         wxLogTrace(wxT("Function Status"), wxT("CDlgMessages::OnShow - Show/Hide Event for CAdvancedFrame detected"));
454         if (event.IsShown()) {
455             RestoreWindowDimensions();
456         } else {
457             SaveWindowDimensions();
458         }
459 
460         bAlreadyRunning = false;
461     } else {
462         event.Skip();
463     }
464 
465     wxLogTrace(wxT("Function Start/End"), wxT("CDlgMessages::OnShow - Function End"));
466 }
467 
468 
469 /*!
470  * wxEVT_HELP event handler for ID_DLGMESSAGES
471  */
472 
OnHelp(wxHelpEvent & WXUNUSED (event))473 void CDlgMessages::OnHelp(wxHelpEvent& WXUNUSED(event)) {
474     wxLogTrace(wxT("Function Start/End"), wxT("CDlgMessages::OnHelp - Function Begin"));
475 
476     if (IsShown()) {
477         wxString strURL = wxGetApp().GetSkinManager()->GetAdvanced()->GetOrganizationHelpUrl();
478 
479         wxString wxurl;
480 		wxurl.Printf(
481             wxT("%s?target=simple_messages&version=%s&controlid=%d"),
482             strURL.c_str(),
483             wxString(BOINC_VERSION_STRING, wxConvUTF8).c_str(),
484             ID_SIMPLE_HELP
485         );
486         wxLaunchDefaultBrowser(wxurl);
487     }
488 
489     wxLogTrace(wxT("Function Start/End"), wxT("CDlgMessages::OnHelp - Function End"));
490 }
491 
492 
493 /*!
494  * wxEVT_COMMAND_BUTTON_CLICKED event handler for wxID_OK
495  */
496 
OnOK(wxCommandEvent &)497 void CDlgMessages::OnOK( wxCommandEvent& /*event*/ ) {
498     EndModal(wxID_OK);
499 }
500 
501 
SaveState()502 bool CDlgMessages::SaveState() {
503     wxLogTrace(wxT("Function Start/End"), wxT("CDlgMessages::SaveState - Function Begin"));
504 
505     wxString        strBaseConfigLocation = wxString(wxT("/Simple/Messages"));
506     wxConfigBase*   pConfig = wxConfigBase::Get(FALSE);
507 
508     wxASSERT(pConfig);
509 
510     // An odd case happens every once and awhile where wxWidgets looses
511     //   the pointer to the config object, or it is cleaned up before
512     //   the window has finished it's cleanup duty.  If we detect a NULL
513     //   pointer, return false.
514     if (!pConfig) return false;
515 
516     //
517     // Save Frame State
518     //
519     pConfig->SetPath(strBaseConfigLocation);
520 
521     // Reterieve and store the latest window dimensions.
522     SaveWindowDimensions();
523 
524     // Save the list ctrl state
525     m_pBackgroundPanel->OnSaveState(pConfig);
526 
527     wxLogTrace(wxT("Function Start/End"), wxT("CDlgMessages::SaveState - Function End"));
528     return true;
529 }
530 
531 
SaveWindowDimensions()532 void CDlgMessages::SaveWindowDimensions() {
533     wxString        strBaseConfigLocation = wxString(wxT("/Simple/Messages"));
534     wxConfigBase*   pConfig = wxConfigBase::Get(FALSE);
535 
536     wxASSERT(pConfig);
537 
538     pConfig->SetPath(strBaseConfigLocation);
539 
540     pConfig->Write(wxT("WindowIconized"), IsIconized());
541     pConfig->Write(wxT("WindowMaximized"), IsMaximized());
542     if (!IsIconized()) {
543         pConfig->Write(wxT("Width"), GetSize().GetWidth());
544         pConfig->Write(wxT("Height"), GetSize().GetHeight());
545         pConfig->Write(wxT("XPos"), GetPosition().x);
546         pConfig->Write(wxT("YPos"), GetPosition().y);
547     }
548 }
549 
550 
RestoreState()551 bool CDlgMessages::RestoreState() {
552     wxLogTrace(wxT("Function Start/End"), wxT("CDlgMessages::RestoreState - Function Begin"));
553 
554     wxString        strBaseConfigLocation = wxString(wxT("/Simple/Messages"));
555     wxConfigBase*   pConfig = wxConfigBase::Get(FALSE);
556 
557     wxASSERT(pConfig);
558 
559     // An odd case happens every once and awhile where wxWidgets looses
560     //   the pointer to the config object, or it is cleaned up before
561     //   the window has finished it's cleanup duty.  If we detect a NULL
562     //   pointer, return false.
563     if (!pConfig) return false;
564 
565     //
566     // Restore Frame State
567     //
568     pConfig->SetPath(strBaseConfigLocation);
569 
570     // Restore the windows properties
571     RestoreWindowDimensions();
572 
573     // Restore the list ctrl state
574     m_pBackgroundPanel->OnRestoreState(pConfig);
575 
576     wxLogTrace(wxT("Function Start/End"), wxT("CDlgMessages::RestoreState - Function End"));
577     return true;
578 }
579 
580 
RestoreWindowDimensions()581 void CDlgMessages::RestoreWindowDimensions() {
582     wxString        strBaseConfigLocation = wxString(wxT("/Simple/Messages"));
583     wxConfigBase*   pConfig = wxConfigBase::Get(FALSE);
584     bool            bWindowIconized = false;
585     bool            bWindowMaximized = false;
586     int             iHeight = 0;
587     int             iWidth = 0;
588     int             iTop = 0;
589     int             iLeft = 0;
590 
591     wxASSERT(pConfig);
592 
593     pConfig->SetPath(strBaseConfigLocation);
594 
595     pConfig->Read(wxT("YPos"), &iTop, 30);
596     pConfig->Read(wxT("XPos"), &iLeft, 30);
597     pConfig->Read(wxT("Width"), &iWidth, 640);
598     pConfig->Read(wxT("Height"), &iHeight, 480);
599     pConfig->Read(wxT("WindowIconized"), &bWindowIconized, false);
600     pConfig->Read(wxT("WindowMaximized"), &bWindowMaximized, false);
601 
602     // Guard against a rare situation where registry values are zero
603     if (iWidth < 50) iWidth = 640;
604     if (iHeight < 50) iHeight = 480;
605 
606 #ifndef __WXMAC__
607 
608     // If either co-ordinate is less then 0 then set it equal to 0 to ensure
609     // it displays on the screen.
610     if ( iLeft < 0 ) iLeft = 30;
611     if ( iTop < 0 ) iTop = 30;
612 
613     // Read the size of the screen
614     wxInt32 iMaxWidth = wxSystemSettings::GetMetric( wxSYS_SCREEN_X );
615     wxInt32 iMaxHeight = wxSystemSettings::GetMetric( wxSYS_SCREEN_Y );
616 
617     // Max sure that it doesn't go off to the right or bottom
618     if ( iLeft + iWidth > iMaxWidth ) iLeft = iMaxWidth - iWidth;
619     if ( iTop + iHeight > iMaxHeight ) iTop = iMaxHeight - iHeight;
620 
621     if (!IsIconized() && !IsMaximized()) {
622         SetSize(iLeft, iTop, iWidth, iHeight);
623     }
624     Iconize(bWindowIconized);
625     Maximize(bWindowMaximized);
626 
627 #else   // ! __WXMAC__
628 
629     // If the user has changed the arrangement of multiple
630     // displays, make sure the window title bar is still on-screen.
631     if (!IsWindowOnScreen(iLeft, iTop, iWidth, iHeight)) {
632         iTop = iLeft = 30;
633     }
634         SetSize(iLeft, iTop, iWidth, iHeight);
635 #endif  // ! __WXMAC__
636 }
637 
OnSize(wxSizeEvent & event)638 void CDlgMessages::OnSize(wxSizeEvent& event) {
639     if (IsShown()) {
640         SaveWindowDimensions();
641     }
642     event.Skip();
643 }
644 
645 
OnMove(wxMoveEvent & event)646 void CDlgMessages::OnMove(wxMoveEvent& event) {
647     if (IsShown()) {
648         SaveWindowDimensions();
649     }
650     event.Skip();
651 }
652