1/////////////////////////////////////////////////////////////////////////////
2// Name:        src/mgl/app.cpp
3// Author:      Vaclav Slavik
4//              based on GTK and MSW implementations
5// Id:          $Id: app.cpp 53607 2008-05-16 15:21:40Z SN $
6// Copyright:   (c) 2001-2002 SciTech Software, Inc. (www.scitechsoft.com)
7// Licence:     wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
13#ifdef __BORLANDC__
14    #pragma hdrstop
15#endif
16
17#include "wx/app.h"
18
19#ifndef WX_PRECOMP
20    #include "wx/settings.h"
21    #include "wx/frame.h"
22    #include "wx/dialog.h"
23    #include "wx/log.h"
24    #include "wx/intl.h"
25    #include "wx/module.h"
26#endif
27
28#include "wx/evtloop.h"
29#include "wx/fontutil.h"
30#include "wx/univ/theme.h"
31#include "wx/univ/renderer.h"
32#include "wx/univ/colschem.h"
33#include "wx/sysopt.h"
34#include "wx/mgl/private.h"
35#include "wx/private/fontmgr.h"
36
37//-----------------------------------------------------------------------------
38// wxApp::Exit()
39//-----------------------------------------------------------------------------
40
41void wxApp::Exit()
42{
43    MGL_exit();
44    exit(0);
45}
46
47//-----------------------------------------------------------------------------
48// wxYield
49//-----------------------------------------------------------------------------
50
51static bool gs_inYield = false;
52
53bool wxApp::Yield(bool onlyIfNeeded)
54{
55    if ( gs_inYield )
56    {
57        if ( !onlyIfNeeded )
58        {
59            wxFAIL_MSG( wxT("wxYield called recursively" ) );
60        }
61
62        return false;
63    }
64
65#if wxUSE_THREADS
66    if ( !wxThread::IsMain() )
67    {
68        // can't process events from other threads, MGL is thread-unsafe
69        return true;
70    }
71#endif // wxUSE_THREADS
72
73    gs_inYield = true;
74
75    wxLog::Suspend();
76
77    // A guarentee that there will be an active event loop:
78    wxEventLoopGuarantor dummyLoopIfNeeded;
79    while (wxEventLoop::GetActive()->Pending())
80        wxEventLoop::GetActive()->Dispatch();
81
82    /* it's necessary to call ProcessIdle() to update the frames sizes which
83       might have been changed (it also will update other things set from
84       OnUpdateUI() which is a nice (and desired) side effect) */
85    while (wxTheApp->ProcessIdle()) { }
86
87    wxLog::Resume();
88
89    gs_inYield = false;
90
91    return true;
92}
93
94
95//-----------------------------------------------------------------------------
96// wxWakeUpIdle
97//-----------------------------------------------------------------------------
98
99void wxApp::WakeUpIdle()
100{
101#if wxUSE_THREADS
102    if (!wxThread::IsMain())
103        wxMutexGuiEnter();
104#endif
105
106    while (wxTheApp->ProcessIdle())
107        ;
108
109#if wxUSE_THREADS
110    if (!wxThread::IsMain())
111        wxMutexGuiLeave();
112#endif
113}
114
115//-----------------------------------------------------------------------------
116// Root window
117//-----------------------------------------------------------------------------
118
119class wxRootWindow : public wxWindow
120{
121    public:
122        wxRootWindow() : wxWindow(NULL, wxID_ANY)
123        {
124            SetMGLwindow_t(MGL_wmGetRootWindow(g_winMng));
125            SetBackgroundColour(wxTHEME_COLOUR(DESKTOP));
126        }
127        virtual ~wxRootWindow()
128        {
129            // we don't want to delete MGL_WM's rootWnd
130            m_wnd = NULL;
131        }
132
133        virtual bool AcceptsFocus() const { return false; }
134
135        DECLARE_DYNAMIC_CLASS(wxRootWindow)
136};
137
138IMPLEMENT_DYNAMIC_CLASS(wxRootWindow, wxWindow)
139
140static wxRootWindow *gs_rootWindow = NULL;
141
142//-----------------------------------------------------------------------------
143// MGL initialization
144//-----------------------------------------------------------------------------
145
146static bool wxCreateMGL_WM(const wxVideoMode& displayMode)
147{
148    int mode;
149    int refresh = MGL_DEFAULT_REFRESH;
150
151#if wxUSE_SYSTEM_OPTIONS
152    if ( wxSystemOptions::HasOption(wxT("mgl.screen-refresh")) )
153        refresh = wxSystemOptions::GetOptionInt(wxT("mgl.screen-refresh"));
154#endif
155
156    mode = MGL_findMode(displayMode.GetWidth(),
157                        displayMode.GetHeight(),
158                        displayMode.GetDepth());
159    if ( mode == -1 )
160    {
161        wxLogError(_("Mode %ix%i-%i not available."),
162                     displayMode.GetWidth(),
163                     displayMode.GetHeight(),
164                     displayMode.GetDepth());
165        return false;
166    }
167    g_displayDC = new MGLDisplayDC(mode, 1, refresh);
168    if ( !g_displayDC->isValid() )
169    {
170        delete g_displayDC;
171        g_displayDC = NULL;
172        return false;
173    }
174
175    g_winMng = MGL_wmCreate(g_displayDC->getDC());
176    if (!g_winMng)
177        return false;
178
179    return true;
180}
181
182static void wxDestroyMGL_WM()
183{
184    if ( g_winMng )
185    {
186        MGL_wmDestroy(g_winMng);
187        g_winMng = NULL;
188    }
189    if ( g_displayDC )
190    {
191        delete g_displayDC;
192        g_displayDC = NULL;
193    }
194}
195
196//-----------------------------------------------------------------------------
197// wxApp
198//-----------------------------------------------------------------------------
199
200IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler)
201
202BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
203    EVT_IDLE(wxAppBase::OnIdle)
204END_EVENT_TABLE()
205
206
207wxApp::wxApp()
208{
209}
210
211wxApp::~wxApp()
212{
213}
214
215wxVideoMode wxGetDefaultDisplayMode()
216{
217    wxString mode;
218    unsigned w, h, bpp;
219
220    if ( !wxGetEnv(wxT("WXMODE"), &mode) ||
221         (wxSscanf(mode.c_str(), _T("%ux%u-%u"), &w, &h, &bpp) != 3) )
222    {
223        w = 640, h = 480, bpp = 16;
224    }
225
226    return wxVideoMode(w, h, bpp);
227}
228
229bool wxApp::SetDisplayMode(const wxVideoMode& mode)
230{
231    if ( !mode.IsOk() )
232    {
233        return false;
234    }
235    if ( g_displayDC != NULL )
236    {
237        // FIXME_MGL -- we currently don't allow to switch video mode
238        // more than once. This can hopefully be changed...
239        wxFAIL_MSG(wxT("Can't change display mode after intialization!"));
240        return false;
241    }
242
243    if ( !wxCreateMGL_WM(mode) )
244        return false;
245    gs_rootWindow = new wxRootWindow;
246
247    m_displayMode = mode;
248
249    return true;
250}
251
252bool wxApp::OnInitGui()
253{
254    if ( !wxAppBase::OnInitGui() )
255        return false;
256
257#ifdef __WXDEBUG__
258    // MGL redirects stdout and stderr to physical console, so lets redirect
259    // it to file in debug build. Do it only when WXSTDERR environment variable is set
260    wxString redirect;
261    if ( wxGetEnv(wxT("WXSTDERR"), &redirect) )
262        freopen(redirect.mb_str(), "wt", stderr);
263#endif // __WXDEBUG__
264
265    wxLog *oldLog = wxLog::SetActiveTarget(new wxLogGui);
266    if ( oldLog ) delete oldLog;
267
268    return true;
269}
270
271bool wxApp::Initialize(int& argc, wxChar **argv)
272{
273#ifdef __DJGPP__
274    // VS: disable long filenames under DJGPP as the very first thing,
275    //     since SciTech MGL doesn't like them much...
276    wxSetEnv(wxT("LFN"), wxT("N"));
277#endif
278
279    // intialize MGL before creating wxFontsManager since it uses MGL funcs
280    if ( MGL_init(".", NULL) == 0 )
281    {
282        wxLogError(_("Cannot initialize SciTech MGL!"));
283        return false;
284    }
285
286    if ( !wxAppBase::Initialize(argc, argv) )
287    {
288        MGL_exit();
289        return false;
290    }
291
292#if wxUSE_INTL
293    wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
294#endif
295
296    return true;
297}
298
299// Modules are cleaned up after wxApp::CleanUp(), and some modules may
300// require MGL to still be alive, e.g. the stock fonts need the fonts
301// manager. So append this module last minute in wxApp::CleanUp() to close
302// down MGL after all the other modules have been cleaned up.
303//
304struct wxMGLFinalCleanup: public wxModule
305{
306    bool OnInit() { return true; }
307
308    void OnExit()
309    {
310        wxFontsManager::CleanUp();
311
312        wxDestroyMGL_WM();
313        MGL_exit();
314    }
315};
316
317void wxApp::CleanUp()
318{
319    delete gs_rootWindow;
320
321    wxAppBase::CleanUp();
322
323    wxModule::RegisterModule(new wxMGLFinalCleanup);
324}
325