1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #pragma implementation "app.h"
15 #include "wx/gdicmn.h"
19 #include "wx/memory.h"
21 #include "wx/settings.h"
22 #include "wx/dialog.h"
24 #if wxUSE_WX_RESOURCES
25 #include "wx/resource.h"
28 #include "wx/module.h"
31 #include "wx/thread.h"
39 #include "wx/gtk/win_gtk.h"
41 //-----------------------------------------------------------------------------
43 //-----------------------------------------------------------------------------
45 wxApp
*wxTheApp
= (wxApp
*) NULL
;
46 wxAppInitializerFunction
wxApp::m_appInitFn
= (wxAppInitializerFunction
) NULL
;
48 extern wxList wxPendingDelete
;
50 extern wxList
*wxPendingEvents
;
51 extern wxCriticalSection
*wxPendingEventsLocker
;
53 extern wxResourceCache
*wxTheResourceCache
;
55 unsigned char g_palette
[64*3] =
123 //-----------------------------------------------------------------------------
125 //-----------------------------------------------------------------------------
127 extern void wxFlushResources(void);
129 //-----------------------------------------------------------------------------
131 //-----------------------------------------------------------------------------
139 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) );
143 // it's necessary to call ProcessIdle() to update the frames sizes which
144 // might have been changed (it also will update other things set from
145 // OnUpdateUI() which is a nice (and desired) side effect)
146 for ( wxWindowList::Node
*node
= wxTopLevelWindows
.GetFirst();
148 node
= node
->GetNext() )
150 wxWindow
*win
= node
->GetData();
151 win
->OnInternalIdle();
154 // We need to temporarily remove idle callbacks or the loop will
156 gtk_idle_remove( wxTheApp
->m_idleTag
);
158 while (gtk_events_pending())
159 gtk_main_iteration();
161 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
165 //-----------------------------------------------------------------------------
167 //-----------------------------------------------------------------------------
169 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
171 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
172 EVT_IDLE(wxApp::OnIdle
)
175 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
179 while (wxTheApp
->ProcessIdle())
195 m_topWindow
= (wxWindow
*) NULL
;
196 m_exitOnFrameDelete
= TRUE
;
198 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
200 m_colorCube
= (unsigned char*) NULL
;
205 gtk_idle_remove( m_idleTag
);
207 if (m_colorCube
) free(m_colorCube
);
210 bool wxApp::OnInitGui()
212 /* Nothing to do for 15, 16, 24, 32 bit displays */
214 GdkVisual
*visual
= gdk_visual_get_system();
215 if (visual
->depth
> 8) return TRUE
;
217 /* this initiates the standard palette as defined by GdkImlib
218 in the GNOME libraries. it ensures that all GNOME applications
219 use the same 64 colormap entries on 8-bit displays so you
220 can use several rather graphics-heavy applications at the
222 NOTE: this doesn't really seem to work this way... */
225 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
227 for (int i = 0; i < 64; i++)
230 col.red = g_palette[i*3 + 0] << 8;
231 col.green = g_palette[i*3 + 1] << 8;
232 col.blue = g_palette[i*3 + 2] << 8;
235 gdk_color_alloc( cmap, &col );
238 gtk_widget_set_default_colormap( cmap );
241 /* initialize color cube for 8-bit color reduction dithering */
243 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
245 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
247 for (int r
= 0; r
< 32; r
++)
249 for (int g
= 0; g
< 32; g
++)
251 for (int b
= 0; b
< 32; b
++)
253 int rr
= (r
<< 3) | (r
>> 2);
254 int gg
= (g
<< 3) | (g
>> 2);
255 int bb
= (b
<< 3) | (b
>> 2);
257 GdkColor
*colors
= cmap
->colors
;
258 int max
= 3 * (65536);
261 for (int i
= 0; i
< cmap
->size
; i
++)
263 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
264 int gdiff
= ((gg
<< 8)- colors
[i
].green
);
265 int bdiff
= ((bb
<< 8)- colors
[i
].blue
);
266 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
267 if (sum
< max
) { index
= i
; max
= sum
; }
270 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
279 bool wxApp::ProcessIdle()
282 event
.SetEventObject( this );
283 ProcessEvent( event
);
285 return event
.MoreRequested();
288 void wxApp::OnIdle( wxIdleEvent
&event
)
290 static bool inOnIdle
= FALSE
;
292 /* Avoid recursion (via ProcessEvent default case) */
299 /* Resend in the main thread events which have been prepared in other
301 ProcessPendingEvents();
304 /* 'Garbage' collection of windows deleted with Close(). */
305 DeletePendingObjects();
307 /* flush the logged messages if any */
308 wxLog
*log
= wxLog::GetActiveTarget();
309 if (log
!= NULL
&& log
->HasPendingMessages())
312 /* Send OnIdle events to all windows */
313 bool needMore
= SendIdleEvents();
316 event
.RequestMore(TRUE
);
321 bool wxApp::SendIdleEvents()
323 bool needMore
= FALSE
;
325 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
328 wxWindow
* win
= node
->GetData();
329 if (SendIdleEvents(win
))
331 node
= node
->GetNext();
337 bool wxApp::SendIdleEvents( wxWindow
* win
)
339 bool needMore
= FALSE
;
342 event
.SetEventObject(win
);
344 win
->OnInternalIdle();
346 win
->ProcessEvent(event
);
348 if (event
.MoreRequested())
351 wxNode
* node
= win
->GetChildren().First();
354 wxWindow
* win
= (wxWindow
*) node
->Data();
355 if (SendIdleEvents(win
))
363 int wxApp::MainLoop()
369 void wxApp::ExitMainLoop()
374 bool wxApp::Initialized()
376 return m_initialized
;
379 bool wxApp::Pending()
381 return gtk_events_pending();
384 void wxApp::Dispatch()
386 gtk_main_iteration();
390 void wxApp::ProcessPendingEvents()
392 wxNode
*node
= wxPendingEvents
->First();
393 wxCriticalSectionLocker
locker(*wxPendingEventsLocker
);
397 wxEvtHandler
*handler
= (wxEvtHandler
*)node
->Data();
399 handler
->ProcessPendingEvents();
403 node
= wxPendingEvents
->First();
406 #endif // wxUSE_THREADS
408 void wxApp::DeletePendingObjects()
410 wxNode
*node
= wxPendingDelete
.First();
413 wxObject
*obj
= (wxObject
*)node
->Data();
417 if (wxPendingDelete
.Member(obj
))
420 node
= wxPendingDelete
.First();
424 wxWindow
*wxApp::GetTopWindow()
428 else if (wxTopLevelWindows
.GetCount() > 0)
429 return wxTopLevelWindows
.GetFirst()->GetData();
434 void wxApp::SetTopWindow( wxWindow
*win
)
439 bool wxApp::Initialize()
441 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
443 wxClassInfo::InitializeClasses();
445 wxSystemSettings::Init();
447 // GL: I'm annoyed ... I don't know where to put this and I don't want to
448 // create a module for that as it's part of the core.
450 wxPendingEvents
= new wxList();
451 wxPendingEventsLocker
= new wxCriticalSection();
455 wxTheFontNameDirectory = new wxFontNameDirectory;
456 wxTheFontNameDirectory->Initialize();
459 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
460 wxTheColourDatabase
->Initialize();
462 wxInitializeStockLists();
463 wxInitializeStockObjects();
465 #if wxUSE_WX_RESOURCES
466 wxTheResourceCache
= new wxResourceCache( wxKEY_STRING
);
468 wxInitializeResourceSystem();
471 wxImage::InitStandardHandlers();
473 /* no global cursor under X
474 g_globalCursor = new wxCursor; */
476 wxModule::RegisterModules();
477 if (!wxModule::InitializeModules()) return FALSE
;
482 void wxApp::CleanUp()
484 wxModule::CleanUpModules();
486 #if wxUSE_WX_RESOURCES
489 if (wxTheResourceCache
)
490 delete wxTheResourceCache
;
491 wxTheResourceCache
= (wxResourceCache
*) NULL
;
493 wxCleanUpResourceSystem();
496 if (wxTheColourDatabase
)
497 delete wxTheColourDatabase
;
498 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
501 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
502 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
505 wxDeleteStockObjects();
507 wxDeleteStockLists();
509 wxImage::CleanUpHandlers();
512 wxTheApp
= (wxApp
*) NULL
;
514 // GL: I'm annoyed ... I don't know where to put this and I don't want to
515 // create a module for that as it's part of the core.
517 delete wxPendingEvents
;
518 delete wxPendingEventsLocker
;
521 wxSystemSettings::Done();
525 wxClassInfo::CleanUpClasses();
527 // check for memory leaks
528 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
529 if (wxDebugContext::CountObjectsLeft() > 0)
531 wxLogDebug(_T("There were memory leaks.\n"));
532 wxDebugContext::Dump();
533 wxDebugContext::PrintStatistics();
537 // do this as the very last thing because everything else can log messages
538 wxLog::DontCreateOnDemand();
540 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
545 wxLog
*wxApp::CreateLogTarget()
550 //-----------------------------------------------------------------------------
552 //-----------------------------------------------------------------------------
554 int wxEntry( int argc
, char *argv
[] )
558 gtk_init( &argc
, &argv
);
560 if (!wxApp::Initialize())
565 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
566 _T("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
568 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
570 wxObject
*test_app
= app_ini();
572 wxTheApp
= (wxApp
*) test_app
;
575 wxCHECK_MSG( wxTheApp
, -1, _T("wxWindows error: no application object") );
577 wxTheApp
->argc
= argc
;
578 wxTheApp
->argv
= argv
;
580 wxString
name(wxFileNameFromPath(argv
[0]));
581 wxStripExtension( name
);
582 wxTheApp
->SetAppName( name
);
586 if ( !wxTheApp
->OnInitGui() )
589 // Here frames insert themselves automatically into wxTopLevelWindows by
590 // getting created in OnInit().
593 if ( !wxTheApp
->OnInit() )
599 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
601 if (wxTheApp
->Initialized())
602 retValue
= wxTheApp
->OnRun();
604 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
607 // Forcibly delete the window.
608 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
609 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
611 topWindow
->Close( TRUE
);
612 wxTheApp
->DeletePendingObjects();
617 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
624 // flush the logged messages if any
625 wxLog
*log
= wxLog::GetActiveTarget();
626 if (log
!= NULL
&& log
->HasPendingMessages())
629 // continuing to use user defined log target is unsafe from now on because
630 // some resources may be already unavailable, so replace it by something
632 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);