1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #pragma implementation "appbase.h"
12 #pragma implementation "app.h"
16 #include "wx/gdicmn.h"
20 #include "wx/memory.h"
22 #include "wx/settings.h"
23 #include "wx/dialog.h"
25 #if wxUSE_WX_RESOURCES
26 #include "wx/resource.h"
29 #include "wx/module.h"
33 #include "wx/thread.h"
42 #include "wx/gtk/win_gtk.h"
44 //-----------------------------------------------------------------------------
46 //-----------------------------------------------------------------------------
48 wxApp
*wxTheApp
= (wxApp
*) NULL
;
49 wxAppInitializerFunction
wxAppBase::m_appInitFn
= (wxAppInitializerFunction
) NULL
;
52 extern wxList
*wxPendingEvents
;
53 extern wxCriticalSection
*wxPendingEventsLocker
;
55 extern wxResourceCache
*wxTheResourceCache
;
58 unsigned char g_palette
[64*3] =
126 //-----------------------------------------------------------------------------
128 //-----------------------------------------------------------------------------
130 extern void wxFlushResources(void);
132 //-----------------------------------------------------------------------------
134 //-----------------------------------------------------------------------------
141 /* forward declaration */
142 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) );
146 /* it's necessary to call ProcessIdle() to update the frames sizes which
147 might have been changed (it also will update other things set from
148 OnUpdateUI() which is a nice (and desired) side effect) */
149 while (wxTheApp
->ProcessIdle()) { }
152 for ( wxWindowList::Node
*node
= wxTopLevelWindows
.GetFirst();
154 node
= node
->GetNext() )
156 wxWindow
*win
= node
->GetData();
157 win
->OnInternalIdle();
161 if (wxTheApp
->m_idleTag
)
163 /* We need to temporarily remove idle callbacks or the loop will
165 gtk_idle_remove( wxTheApp
->m_idleTag
);
166 wxTheApp
->m_idleTag
= 0;
168 while (gtk_events_pending())
169 gtk_main_iteration();
171 /* re-add idle handler */
172 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
176 while (gtk_events_pending())
177 gtk_main_iteration();
183 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
185 if (!wxTheApp
) return TRUE
;
187 #if (GTK_MINOR_VERSION > 0)
188 /* when getting called from GDK's idle handler we
189 are no longer within GDK's grab on the GUI
190 thread so we must lock it here ourselves */
191 GDK_THREADS_ENTER ();
194 /* sent idle event to all who request them */
195 while (wxTheApp
->ProcessIdle()) { }
197 /* we don't want any more idle events until the next event is
199 gtk_idle_remove( wxTheApp
->m_idleTag
);
200 wxTheApp
->m_idleTag
= 0;
202 /* indicate that we are now in idle mode - even so deeply
203 in idle mode that we don't get any idle events anymore.
204 this is like wxMSW where an idle event is sent only
205 once each time after the event queue has been completely
209 #if (GTK_MINOR_VERSION > 0)
210 /* release lock again */
211 GDK_THREADS_LEAVE ();
217 void wxapp_install_idle_handler()
219 wxASSERT_MSG( wxTheApp
->m_idleTag
== 0, _T("attempt to install idle handler twice") );
221 /* this routine gets called by all event handlers
222 indicating that the idle is over. */
224 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
231 static gint wxapp_wakeup_timerout_callback( gpointer WXUNUSED(data) )
233 gtk_timeout_remove( wxTheApp->m_wakeUpTimerTag );
234 wxTheApp->m_wakeUpTimerTag = 0;
236 #if (GTK_MINOR_VERSION > 0)
237 // when getting called from GDK's time-out handler
238 // we are no longer within GDK's grab on the GUI
239 // thread so we must lock it here ourselves
240 GDK_THREADS_ENTER ();
243 // unblock other threads wishing to do some GUI things
246 // wake up other threads
249 // block other thread again
252 #if (GTK_MINOR_VERSION > 0)
253 // release lock again
254 GDK_THREADS_LEAVE ();
257 wxTheApp->m_wakeUpTimerTag = gtk_timeout_add( 20, wxapp_wakeup_timerout_callback, (gpointer) NULL );
264 //-----------------------------------------------------------------------------
266 //-----------------------------------------------------------------------------
268 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
270 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
271 EVT_IDLE(wxApp::OnIdle
)
278 m_topWindow
= (wxWindow
*) NULL
;
279 m_exitOnFrameDelete
= TRUE
;
281 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
285 m_wakeUpTimerTag = gtk_timeout_add( 20, wxapp_wakeup_timerout_callback, (gpointer) NULL );
289 m_colorCube
= (unsigned char*) NULL
;
294 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
298 if (m_wakeUpTimerTag) gtk_timeout_remove( m_wakeUpTimerTag );
302 if (m_colorCube
) free(m_colorCube
);
305 bool wxApp::OnInitGui()
307 GdkVisual
*visual
= gdk_visual_get_system();
309 /* on some machines, the default visual is just 256 colours, so
310 we make sure we get the best. this can sometimes be wasteful,
311 of course, but what do these guys pay $30.000 for? */
313 if (gdk_visual_get_best() != gdk_visual_get_system())
315 GdkVisual* vis = gdk_visual_get_best();
316 gtk_widget_set_default_visual( vis );
318 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
319 gtk_widget_set_default_colormap( colormap );
325 /* Nothing to do for 15, 16, 24, 32 bit displays */
326 if (visual
->depth
> 8) return TRUE
;
328 /* this initiates the standard palette as defined by GdkImlib
329 in the GNOME libraries. it ensures that all GNOME applications
330 use the same 64 colormap entries on 8-bit displays so you
331 can use several rather graphics-heavy applications at the
333 NOTE: this doesn't really seem to work this way... */
336 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
338 for (int i = 0; i < 64; i++)
341 col.red = g_palette[i*3 + 0] << 8;
342 col.green = g_palette[i*3 + 1] << 8;
343 col.blue = g_palette[i*3 + 2] << 8;
346 gdk_color_alloc( cmap, &col );
349 gtk_widget_set_default_colormap( cmap );
352 /* initialize color cube for 8-bit color reduction dithering */
354 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
356 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
358 for (int r
= 0; r
< 32; r
++)
360 for (int g
= 0; g
< 32; g
++)
362 for (int b
= 0; b
< 32; b
++)
364 int rr
= (r
<< 3) | (r
>> 2);
365 int gg
= (g
<< 3) | (g
>> 2);
366 int bb
= (b
<< 3) | (b
>> 2);
370 GdkColor
*colors
= cmap
->colors
;
375 for (int i
= 0; i
< cmap
->size
; i
++)
377 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
378 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
379 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
380 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
383 index
= i
; max
= sum
;
389 #if (GTK_MINOR_VERSION > 0)
390 /* assume 8-bit true or static colors. this really
392 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
393 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
394 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
395 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
397 wxFAIL_MSG( _T("Unsupported graphics hardware") );
400 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
408 bool wxApp::ProcessIdle()
411 event
.SetEventObject( this );
412 ProcessEvent( event
);
414 return event
.MoreRequested();
417 void wxApp::OnIdle( wxIdleEvent
&event
)
419 static bool inOnIdle
= FALSE
;
421 /* Avoid recursion (via ProcessEvent default case) */
428 /* Resend in the main thread events which have been prepared in other
430 ProcessPendingEvents();
433 /* 'Garbage' collection of windows deleted with Close(). */
434 DeletePendingObjects();
436 /* flush the logged messages if any */
438 wxLog
*log
= wxLog::GetActiveTarget();
439 if (log
!= NULL
&& log
->HasPendingMessages())
443 /* Send OnIdle events to all windows */
444 bool needMore
= SendIdleEvents();
447 event
.RequestMore(TRUE
);
452 bool wxApp::SendIdleEvents()
454 bool needMore
= FALSE
;
456 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
459 wxWindow
* win
= node
->GetData();
460 if (SendIdleEvents(win
))
462 node
= node
->GetNext();
468 bool wxApp::SendIdleEvents( wxWindow
* win
)
470 bool needMore
= FALSE
;
473 event
.SetEventObject(win
);
475 win
->OnInternalIdle();
477 win
->ProcessEvent(event
);
479 if (event
.MoreRequested())
482 wxNode
* node
= win
->GetChildren().First();
485 wxWindow
* win
= (wxWindow
*) node
->Data();
486 if (SendIdleEvents(win
))
494 int wxApp::MainLoop()
500 void wxApp::ExitMainLoop()
505 bool wxApp::Initialized()
507 return m_initialized
;
510 bool wxApp::Pending()
512 return (gtk_events_pending() > 0);
515 void wxApp::Dispatch()
517 gtk_main_iteration();
521 void wxApp::ProcessPendingEvents()
523 wxNode
*node
= wxPendingEvents
->First();
524 wxCriticalSectionLocker
locker(*wxPendingEventsLocker
);
528 wxEvtHandler
*handler
= (wxEvtHandler
*)node
->Data();
530 handler
->ProcessPendingEvents();
534 node
= wxPendingEvents
->First();
537 #endif // wxUSE_THREADS
539 void wxApp::DeletePendingObjects()
541 wxNode
*node
= wxPendingDelete
.First();
544 wxObject
*obj
= (wxObject
*)node
->Data();
548 if (wxPendingDelete
.Find(obj
))
551 node
= wxPendingDelete
.First();
555 bool wxApp::Initialize()
557 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
559 wxClassInfo::InitializeClasses();
561 wxSystemSettings::Init();
563 // GL: I'm annoyed ... I don't know where to put this and I don't want to
564 // create a module for that as it's part of the core.
566 wxPendingEvents
= new wxList();
567 wxPendingEventsLocker
= new wxCriticalSection();
571 wxTheFontNameDirectory = new wxFontNameDirectory;
572 wxTheFontNameDirectory->Initialize();
575 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
576 wxTheColourDatabase
->Initialize();
578 wxInitializeStockLists();
579 wxInitializeStockObjects();
581 #if wxUSE_WX_RESOURCES
582 wxTheResourceCache
= new wxResourceCache( wxKEY_STRING
);
584 wxInitializeResourceSystem();
587 wxImage::InitStandardHandlers();
589 wxModule::RegisterModules();
590 if (!wxModule::InitializeModules()) return FALSE
;
595 void wxApp::CleanUp()
597 wxModule::CleanUpModules();
599 #if wxUSE_WX_RESOURCES
602 if (wxTheResourceCache
)
603 delete wxTheResourceCache
;
604 wxTheResourceCache
= (wxResourceCache
*) NULL
;
606 wxCleanUpResourceSystem();
609 if (wxTheColourDatabase
)
610 delete wxTheColourDatabase
;
611 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
614 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
615 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
618 wxDeleteStockObjects();
620 wxDeleteStockLists();
622 wxImage::CleanUpHandlers();
625 wxTheApp
= (wxApp
*) NULL
;
627 // GL: I'm annoyed ... I don't know where to put this and I don't want to
628 // create a module for that as it's part of the core.
630 delete wxPendingEvents
;
631 delete wxPendingEventsLocker
;
634 wxSystemSettings::Done();
638 wxClassInfo::CleanUpClasses();
640 // check for memory leaks
641 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
642 if (wxDebugContext::CountObjectsLeft() > 0)
644 wxLogDebug(_T("There were memory leaks.\n"));
645 wxDebugContext::Dump();
646 wxDebugContext::PrintStatistics();
651 // do this as the very last thing because everything else can log messages
652 wxLog::DontCreateOnDemand();
654 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
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
;
694 wxTheApp
->argv
= new wxChar
*[argc
+1];
696 while (mb_argc
< argc
) {
697 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
700 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
702 wxTheApp
->argv
= argv
;
705 wxString
name(wxFileNameFromPath(argv
[0]));
706 wxStripExtension( name
);
707 wxTheApp
->SetAppName( name
);
711 if ( !wxTheApp
->OnInitGui() )
714 // Here frames insert themselves automatically into wxTopLevelWindows by
715 // getting created in OnInit().
718 if ( !wxTheApp
->OnInit() )
724 /* delete pending toplevel windows (typically a single
725 dialog) so that, if there isn't any left, we don't
727 wxTheApp
->DeletePendingObjects();
729 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
731 if (wxTheApp
->Initialized())
733 retValue
= wxTheApp
->OnRun();
735 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
738 /* Forcibly delete the window. */
739 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
740 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
742 topWindow
->Close( TRUE
);
743 wxTheApp
->DeletePendingObjects();
748 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
756 // flush the logged messages if any
757 wxLog
*log
= wxLog::GetActiveTarget();
758 if (log
!= NULL
&& log
->HasPendingMessages())
761 // continuing to use user defined log target is unsafe from now on because
762 // some resources may be already unavailable, so replace it by something
764 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);
774 #include "wx/gtk/info.xpm"
775 #include "wx/gtk/error.xpm"
776 #include "wx/gtk/question.xpm"
777 #include "wx/gtk/warning.xpm"
780 wxApp::GetStdIcon(int which
) const
784 case wxICON_INFORMATION
:
785 return wxIcon(info_xpm
);
787 case wxICON_QUESTION
:
788 return wxIcon(question_xpm
);
790 case wxICON_EXCLAMATION
:
791 return wxIcon(warning_xpm
);
794 wxFAIL_MSG(_T("requested non existent standard icon"));
795 // still fall through
798 return wxIcon(error_xpm
);