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"
32 #include "wx/thread.h"
41 #include "wx/gtk/win_gtk.h"
43 //-----------------------------------------------------------------------------
45 //-----------------------------------------------------------------------------
47 wxApp
*wxTheApp
= (wxApp
*) NULL
;
48 wxAppInitializerFunction
wxApp::m_appInitFn
= (wxAppInitializerFunction
) NULL
;
51 extern wxList
*wxPendingEvents
;
52 extern wxCriticalSection
*wxPendingEventsLocker
;
54 extern wxResourceCache
*wxTheResourceCache
;
57 unsigned char g_palette
[64*3] =
125 //-----------------------------------------------------------------------------
127 //-----------------------------------------------------------------------------
129 extern void wxFlushResources(void);
131 //-----------------------------------------------------------------------------
133 //-----------------------------------------------------------------------------
140 /* forward declaration */
141 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) );
145 /* it's necessary to call ProcessIdle() to update the frames sizes which
146 might have been changed (it also will update other things set from
147 OnUpdateUI() which is a nice (and desired) side effect) */
148 while (wxTheApp
->ProcessIdle()) { }
151 for ( wxWindowList::Node
*node
= wxTopLevelWindows
.GetFirst();
153 node
= node
->GetNext() )
155 wxWindow
*win
= node
->GetData();
156 win
->OnInternalIdle();
160 if (wxTheApp
->m_idleTag
)
162 /* We need to temporarily remove idle callbacks or the loop will
164 gtk_idle_remove( wxTheApp
->m_idleTag
);
165 wxTheApp
->m_idleTag
= 0;
167 while (gtk_events_pending())
168 gtk_main_iteration();
170 /* re-add idle handler */
171 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
175 while (gtk_events_pending())
176 gtk_main_iteration();
182 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
184 if (!wxTheApp
) return TRUE
;
186 #if (GTK_MINOR_VERSION > 0)
187 /* when getting called from GDK's idle handler we
188 are no longer within GDK's grab on the GUI
189 thread so we must lock it here ourselves */
190 GDK_THREADS_ENTER ();
193 /* sent idle event to all who request them */
194 while (wxTheApp
->ProcessIdle()) { }
196 /* we don't want any more idle events until the next event is
198 gtk_idle_remove( wxTheApp
->m_idleTag
);
199 wxTheApp
->m_idleTag
= 0;
201 /* indicate that we are now in idle mode - even so deeply
202 in idle mode that we don't get any idle events anymore.
203 this is like wxMSW where an idle event is sent only
204 once each time after the event queue has been completely
208 #if (GTK_MINOR_VERSION > 0)
209 /* release lock again */
210 GDK_THREADS_LEAVE ();
216 void wxapp_install_idle_handler()
218 wxASSERT_MSG( wxTheApp
->m_idleTag
== 0, _T("attempt to install idle handler twice") );
220 /* this routine gets called by all event handlers
221 indicating that the idle is over. */
223 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
229 static gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) )
231 gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag
);
232 wxTheApp
->m_wakeUpTimerTag
= 0;
234 #if (GTK_MINOR_VERSION > 0)
235 /* when getting called from GDK's time-out handler
236 we are no longer within GDK's grab on the GUI
237 thread so we must lock it here ourselves */
238 GDK_THREADS_ENTER ();
241 /* unblock other threads wishing to do some GUI things */
244 /* wake up other threads */
247 /* block other thread again */
250 #if (GTK_MINOR_VERSION > 0)
251 /* release lock again */
252 GDK_THREADS_LEAVE ();
255 wxTheApp
->m_wakeUpTimerTag
= gtk_timeout_add( 20, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
261 //-----------------------------------------------------------------------------
263 //-----------------------------------------------------------------------------
265 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
267 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
268 EVT_IDLE(wxApp::OnIdle
)
275 m_topWindow
= (wxWindow
*) NULL
;
276 m_exitOnFrameDelete
= TRUE
;
278 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
281 m_wakeUpTimerTag
= gtk_timeout_add( 20, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
284 m_colorCube
= (unsigned char*) NULL
;
289 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
292 if (m_wakeUpTimerTag
) gtk_timeout_remove( m_wakeUpTimerTag
);
295 if (m_colorCube
) free(m_colorCube
);
298 bool wxApp::OnInitGui()
300 /* on some SGIs, the default visual is just 256 colours, so we
301 make sure we get the best. this can sometimes be wasteful,
302 of course, but what do these guys pay $30.000 for? */
303 GdkVisual
* visual
= gdk_visual_get_best();
304 gtk_widget_set_default_visual( visual
);
306 /* Nothing to do for 15, 16, 24, 32 bit displays */
307 if (visual
->depth
> 8) return TRUE
;
309 /* this initiates the standard palette as defined by GdkImlib
310 in the GNOME libraries. it ensures that all GNOME applications
311 use the same 64 colormap entries on 8-bit displays so you
312 can use several rather graphics-heavy applications at the
314 NOTE: this doesn't really seem to work this way... */
317 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
319 for (int i = 0; i < 64; i++)
322 col.red = g_palette[i*3 + 0] << 8;
323 col.green = g_palette[i*3 + 1] << 8;
324 col.blue = g_palette[i*3 + 2] << 8;
327 gdk_color_alloc( cmap, &col );
330 gtk_widget_set_default_colormap( cmap );
333 /* initialize color cube for 8-bit color reduction dithering */
335 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
337 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
339 for (int r
= 0; r
< 32; r
++)
341 for (int g
= 0; g
< 32; g
++)
343 for (int b
= 0; b
< 32; b
++)
345 int rr
= (r
<< 3) | (r
>> 2);
346 int gg
= (g
<< 3) | (g
>> 2);
347 int bb
= (b
<< 3) | (b
>> 2);
351 GdkColor
*colors
= cmap
->colors
;
356 for (int i
= 0; i
< cmap
->size
; i
++)
358 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
359 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
360 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
361 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
364 index
= i
; max
= sum
;
370 #if (GTK_MINOR_VERSION > 0)
371 /* assume 8-bit true or static colors. this really
373 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
374 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
375 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
376 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
378 wxFAIL_MSG( _T("Unsupported graphics hardware") );
381 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
389 bool wxApp::ProcessIdle()
392 event
.SetEventObject( this );
393 ProcessEvent( event
);
395 return event
.MoreRequested();
398 void wxApp::OnIdle( wxIdleEvent
&event
)
400 static bool inOnIdle
= FALSE
;
402 /* Avoid recursion (via ProcessEvent default case) */
409 /* Resend in the main thread events which have been prepared in other
411 ProcessPendingEvents();
414 /* 'Garbage' collection of windows deleted with Close(). */
415 DeletePendingObjects();
417 /* flush the logged messages if any */
419 wxLog
*log
= wxLog::GetActiveTarget();
420 if (log
!= NULL
&& log
->HasPendingMessages())
424 /* Send OnIdle events to all windows */
425 bool needMore
= SendIdleEvents();
428 event
.RequestMore(TRUE
);
433 bool wxApp::SendIdleEvents()
435 bool needMore
= FALSE
;
437 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
440 wxWindow
* win
= node
->GetData();
441 if (SendIdleEvents(win
))
443 node
= node
->GetNext();
449 bool wxApp::SendIdleEvents( wxWindow
* win
)
451 bool needMore
= FALSE
;
454 event
.SetEventObject(win
);
456 win
->OnInternalIdle();
458 win
->ProcessEvent(event
);
460 if (event
.MoreRequested())
463 wxNode
* node
= win
->GetChildren().First();
466 wxWindow
* win
= (wxWindow
*) node
->Data();
467 if (SendIdleEvents(win
))
475 int wxApp::MainLoop()
481 void wxApp::ExitMainLoop()
486 bool wxApp::Initialized()
488 return m_initialized
;
491 bool wxApp::Pending()
493 return (gtk_events_pending() > 0);
496 void wxApp::Dispatch()
498 gtk_main_iteration();
502 void wxApp::ProcessPendingEvents()
504 wxNode
*node
= wxPendingEvents
->First();
505 wxCriticalSectionLocker
locker(*wxPendingEventsLocker
);
509 wxEvtHandler
*handler
= (wxEvtHandler
*)node
->Data();
511 handler
->ProcessPendingEvents();
515 node
= wxPendingEvents
->First();
518 #endif // wxUSE_THREADS
520 void wxApp::DeletePendingObjects()
522 wxNode
*node
= wxPendingDelete
.First();
525 wxObject
*obj
= (wxObject
*)node
->Data();
529 if (wxPendingDelete
.Find(obj
))
532 node
= wxPendingDelete
.First();
536 wxWindow
*wxApp::GetTopWindow()
540 else if (wxTopLevelWindows
.GetCount() > 0)
541 return wxTopLevelWindows
.GetFirst()->GetData();
546 void wxApp::SetTopWindow( wxWindow
*win
)
551 bool wxApp::Initialize()
553 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
555 wxClassInfo::InitializeClasses();
557 wxSystemSettings::Init();
559 // GL: I'm annoyed ... I don't know where to put this and I don't want to
560 // create a module for that as it's part of the core.
562 wxPendingEvents
= new wxList();
563 wxPendingEventsLocker
= new wxCriticalSection();
567 wxTheFontNameDirectory = new wxFontNameDirectory;
568 wxTheFontNameDirectory->Initialize();
571 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
572 wxTheColourDatabase
->Initialize();
574 wxInitializeStockLists();
575 wxInitializeStockObjects();
577 #if wxUSE_WX_RESOURCES
578 wxTheResourceCache
= new wxResourceCache( wxKEY_STRING
);
580 wxInitializeResourceSystem();
583 wxImage::InitStandardHandlers();
585 wxModule::RegisterModules();
586 if (!wxModule::InitializeModules()) return FALSE
;
591 void wxApp::CleanUp()
593 wxModule::CleanUpModules();
595 #if wxUSE_WX_RESOURCES
598 if (wxTheResourceCache
)
599 delete wxTheResourceCache
;
600 wxTheResourceCache
= (wxResourceCache
*) NULL
;
602 wxCleanUpResourceSystem();
605 if (wxTheColourDatabase
)
606 delete wxTheColourDatabase
;
607 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
610 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
611 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
614 wxDeleteStockObjects();
616 wxDeleteStockLists();
618 wxImage::CleanUpHandlers();
621 wxTheApp
= (wxApp
*) NULL
;
623 // GL: I'm annoyed ... I don't know where to put this and I don't want to
624 // create a module for that as it's part of the core.
626 delete wxPendingEvents
;
627 delete wxPendingEventsLocker
;
630 wxSystemSettings::Done();
634 wxClassInfo::CleanUpClasses();
636 // check for memory leaks
637 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
638 if (wxDebugContext::CountObjectsLeft() > 0)
640 wxLogDebug(_T("There were memory leaks.\n"));
641 wxDebugContext::Dump();
642 wxDebugContext::PrintStatistics();
647 // do this as the very last thing because everything else can log messages
648 wxLog::DontCreateOnDemand();
650 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
655 wxLog
*wxApp::CreateLogTarget()
661 //-----------------------------------------------------------------------------
663 //-----------------------------------------------------------------------------
665 int wxEntry( int argc
, char *argv
[] )
669 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
671 gtk_init( &argc
, &argv
);
673 wxSetDetectableAutoRepeat( TRUE
);
675 if (!wxApp::Initialize())
680 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
681 _T("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
683 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
685 wxObject
*test_app
= app_ini();
687 wxTheApp
= (wxApp
*) test_app
;
690 wxCHECK_MSG( wxTheApp
, -1, _T("wxWindows error: no application object") );
692 wxTheApp
->argc
= argc
;
693 wxTheApp
->argv
= argv
;
695 wxString
name(wxFileNameFromPath(argv
[0]));
696 wxStripExtension( name
);
697 wxTheApp
->SetAppName( name
);
701 if ( !wxTheApp
->OnInitGui() )
704 // Here frames insert themselves automatically into wxTopLevelWindows by
705 // getting created in OnInit().
708 if ( !wxTheApp
->OnInit() )
714 /* delete pending toplevel windows (typically a single
715 dialog) so that, if there isn't any left, we don't
717 wxTheApp
->DeletePendingObjects();
719 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
721 if (wxTheApp
->Initialized())
723 retValue
= wxTheApp
->OnRun();
725 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
728 /* Forcibly delete the window. */
729 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
730 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
732 topWindow
->Close( TRUE
);
733 wxTheApp
->DeletePendingObjects();
738 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
746 // flush the logged messages if any
747 wxLog
*log
= wxLog::GetActiveTarget();
748 if (log
!= NULL
&& log
->HasPendingMessages())
751 // continuing to use user defined log target is unsafe from now on because
752 // some resources may be already unavailable, so replace it by something
754 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);