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
;
56 unsigned char g_palette
[64*3] =
124 //-----------------------------------------------------------------------------
126 //-----------------------------------------------------------------------------
128 extern void wxFlushResources(void);
130 //-----------------------------------------------------------------------------
132 //-----------------------------------------------------------------------------
139 /* forward declaration */
140 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) );
144 // it's necessary to call ProcessIdle() to update the frames sizes which
145 // might have been changed (it also will update other things set from
146 // OnUpdateUI() which is a nice (and desired) side effect)
147 for ( wxWindowList::Node
*node
= wxTopLevelWindows
.GetFirst();
149 node
= node
->GetNext() )
151 wxWindow
*win
= node
->GetData();
152 win
->OnInternalIdle();
155 if (wxTheApp
->m_idleTag
)
157 /* We need to temporarily remove idle callbacks or the loop will
159 gtk_idle_remove( wxTheApp
->m_idleTag
);
160 wxTheApp
->m_idleTag
= 0;
162 while (gtk_events_pending())
163 gtk_main_iteration();
165 /* re-add idle handler */
166 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
170 while (gtk_events_pending())
171 gtk_main_iteration();
177 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
179 if (!wxTheApp
) return TRUE
;
181 /* sent idle event to all who request them */
182 while (wxTheApp
->ProcessIdle()) { }
184 /* we don't want any more idle events until the next event is
186 gtk_idle_remove( wxTheApp
->m_idleTag
);
187 wxTheApp
->m_idleTag
= 0;
189 /* indicate that we are now in idle mode - even so deeply
190 in idle mode that we don't get any idle events anymore.
191 this is like wxMSW where an idle event is sent only
192 once each time after the event queue has been completely
196 /* wake up other threads */
204 void wxapp_install_idle_handler()
206 /* this routine gets called by all event handlers
207 indicating that the idle is over. */
209 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
214 //-----------------------------------------------------------------------------
216 //-----------------------------------------------------------------------------
218 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
220 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
221 EVT_IDLE(wxApp::OnIdle
)
228 m_topWindow
= (wxWindow
*) NULL
;
229 m_exitOnFrameDelete
= TRUE
;
231 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
233 m_colorCube
= (unsigned char*) NULL
;
238 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
240 if (m_colorCube
) free(m_colorCube
);
243 bool wxApp::OnInitGui()
245 /* Nothing to do for 15, 16, 24, 32 bit displays */
247 GdkVisual
*visual
= gdk_visual_get_system();
248 if (visual
->depth
> 8) return TRUE
;
250 /* this initiates the standard palette as defined by GdkImlib
251 in the GNOME libraries. it ensures that all GNOME applications
252 use the same 64 colormap entries on 8-bit displays so you
253 can use several rather graphics-heavy applications at the
255 NOTE: this doesn't really seem to work this way... */
258 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
260 for (int i = 0; i < 64; i++)
263 col.red = g_palette[i*3 + 0] << 8;
264 col.green = g_palette[i*3 + 1] << 8;
265 col.blue = g_palette[i*3 + 2] << 8;
268 gdk_color_alloc( cmap, &col );
271 gtk_widget_set_default_colormap( cmap );
274 /* initialize color cube for 8-bit color reduction dithering */
276 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
278 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
280 for (int r
= 0; r
< 32; r
++)
282 for (int g
= 0; g
< 32; g
++)
284 for (int b
= 0; b
< 32; b
++)
286 int rr
= (r
<< 3) | (r
>> 2);
287 int gg
= (g
<< 3) | (g
>> 2);
288 int bb
= (b
<< 3) | (b
>> 2);
290 GdkColor
*colors
= cmap
->colors
;
296 for (int i
= 0; i
< cmap
->size
; i
++)
298 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
299 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
300 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
301 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
302 if (sum
< max
) { index
= i
; max
= sum
; }
305 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
313 bool wxApp::ProcessIdle()
316 event
.SetEventObject( this );
317 ProcessEvent( event
);
319 return event
.MoreRequested();
322 void wxApp::OnIdle( wxIdleEvent
&event
)
324 static bool inOnIdle
= FALSE
;
326 /* Avoid recursion (via ProcessEvent default case) */
333 /* Resend in the main thread events which have been prepared in other
335 ProcessPendingEvents();
338 /* 'Garbage' collection of windows deleted with Close(). */
339 DeletePendingObjects();
341 /* flush the logged messages if any */
342 wxLog
*log
= wxLog::GetActiveTarget();
343 if (log
!= NULL
&& log
->HasPendingMessages())
346 /* Send OnIdle events to all windows */
347 bool needMore
= SendIdleEvents();
350 event
.RequestMore(TRUE
);
355 bool wxApp::SendIdleEvents()
357 bool needMore
= FALSE
;
359 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
362 wxWindow
* win
= node
->GetData();
363 if (SendIdleEvents(win
))
365 node
= node
->GetNext();
371 bool wxApp::SendIdleEvents( wxWindow
* win
)
373 bool needMore
= FALSE
;
376 event
.SetEventObject(win
);
378 win
->OnInternalIdle();
380 win
->ProcessEvent(event
);
382 if (event
.MoreRequested())
385 wxNode
* node
= win
->GetChildren().First();
388 wxWindow
* win
= (wxWindow
*) node
->Data();
389 if (SendIdleEvents(win
))
397 int wxApp::MainLoop()
403 void wxApp::ExitMainLoop()
408 bool wxApp::Initialized()
410 return m_initialized
;
413 bool wxApp::Pending()
415 return (gtk_events_pending() > 0);
418 void wxApp::Dispatch()
420 gtk_main_iteration();
424 void wxApp::ProcessPendingEvents()
426 wxNode
*node
= wxPendingEvents
->First();
427 wxCriticalSectionLocker
locker(*wxPendingEventsLocker
);
431 wxEvtHandler
*handler
= (wxEvtHandler
*)node
->Data();
433 handler
->ProcessPendingEvents();
437 node
= wxPendingEvents
->First();
440 #endif // wxUSE_THREADS
442 void wxApp::DeletePendingObjects()
444 wxNode
*node
= wxPendingDelete
.First();
447 wxObject
*obj
= (wxObject
*)node
->Data();
451 if (wxPendingDelete
.Member(obj
))
454 node
= wxPendingDelete
.First();
458 wxWindow
*wxApp::GetTopWindow()
462 else if (wxTopLevelWindows
.GetCount() > 0)
463 return wxTopLevelWindows
.GetFirst()->GetData();
468 void wxApp::SetTopWindow( wxWindow
*win
)
473 bool wxApp::Initialize()
475 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
477 wxClassInfo::InitializeClasses();
479 wxSystemSettings::Init();
481 // GL: I'm annoyed ... I don't know where to put this and I don't want to
482 // create a module for that as it's part of the core.
484 wxPendingEvents
= new wxList();
485 wxPendingEventsLocker
= new wxCriticalSection();
489 wxTheFontNameDirectory = new wxFontNameDirectory;
490 wxTheFontNameDirectory->Initialize();
493 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
494 wxTheColourDatabase
->Initialize();
496 wxInitializeStockLists();
497 wxInitializeStockObjects();
499 #if wxUSE_WX_RESOURCES
500 wxTheResourceCache
= new wxResourceCache( wxKEY_STRING
);
502 wxInitializeResourceSystem();
505 wxImage::InitStandardHandlers();
507 /* no global cursor under X
508 g_globalCursor = new wxCursor; */
510 wxModule::RegisterModules();
511 if (!wxModule::InitializeModules()) return FALSE
;
516 void wxApp::CleanUp()
518 wxModule::CleanUpModules();
520 #if wxUSE_WX_RESOURCES
523 if (wxTheResourceCache
)
524 delete wxTheResourceCache
;
525 wxTheResourceCache
= (wxResourceCache
*) NULL
;
527 wxCleanUpResourceSystem();
530 if (wxTheColourDatabase
)
531 delete wxTheColourDatabase
;
532 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
535 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
536 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
539 wxDeleteStockObjects();
541 wxDeleteStockLists();
543 wxImage::CleanUpHandlers();
546 wxTheApp
= (wxApp
*) NULL
;
548 // GL: I'm annoyed ... I don't know where to put this and I don't want to
549 // create a module for that as it's part of the core.
551 delete wxPendingEvents
;
552 delete wxPendingEventsLocker
;
555 wxSystemSettings::Done();
559 wxClassInfo::CleanUpClasses();
561 // check for memory leaks
562 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
563 if (wxDebugContext::CountObjectsLeft() > 0)
565 wxLogDebug(_T("There were memory leaks.\n"));
566 wxDebugContext::Dump();
567 wxDebugContext::PrintStatistics();
571 // do this as the very last thing because everything else can log messages
572 wxLog::DontCreateOnDemand();
574 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
579 wxLog
*wxApp::CreateLogTarget()
584 //-----------------------------------------------------------------------------
586 //-----------------------------------------------------------------------------
588 int wxEntry( int argc
, char *argv
[] )
592 gtk_init( &argc
, &argv
);
594 if (!wxApp::Initialize())
599 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
600 _T("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
602 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
604 wxObject
*test_app
= app_ini();
606 wxTheApp
= (wxApp
*) test_app
;
609 wxCHECK_MSG( wxTheApp
, -1, _T("wxWindows error: no application object") );
611 wxTheApp
->argc
= argc
;
612 wxTheApp
->argv
= argv
;
614 wxString
name(wxFileNameFromPath(argv
[0]));
615 wxStripExtension( name
);
616 wxTheApp
->SetAppName( name
);
620 if ( !wxTheApp
->OnInitGui() )
623 // Here frames insert themselves automatically into wxTopLevelWindows by
624 // getting created in OnInit().
627 if ( !wxTheApp
->OnInit() )
633 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
635 if (wxTheApp
->Initialized())
636 retValue
= wxTheApp
->OnRun();
638 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
641 // Forcibly delete the window.
642 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
643 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
645 topWindow
->Close( TRUE
);
646 wxTheApp
->DeletePendingObjects();
651 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
658 // flush the logged messages if any
659 wxLog
*log
= wxLog::GetActiveTarget();
660 if (log
!= NULL
&& log
->HasPendingMessages())
663 // continuing to use user defined log target is unsafe from now on because
664 // some resources may be already unavailable, so replace it by something
666 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);