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 /* forward declaration */
232 static gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) );
234 void wxapp_install_thread_wakeup()
236 if (wxTheApp
->m_wakeUpTimerTag
) return;
238 wxTheApp
->m_wakeUpTimerTag
= gtk_timeout_add( 100, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
241 void wxapp_uninstall_thread_wakeup()
243 if (!wxTheApp
->m_wakeUpTimerTag
) return;
245 gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag
);
246 wxTheApp
->m_wakeUpTimerTag
= 0;
249 static gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) )
251 wxapp_uninstall_thread_wakeup();
253 #if (GTK_MINOR_VERSION > 0)
254 // when getting called from GDK's time-out handler
255 // we are no longer within GDK's grab on the GUI
256 // thread so we must lock it here ourselves
257 GDK_THREADS_ENTER ();
260 // unblock other threads wishing to do some GUI things
263 // wake up other threads
266 // block other thread again
269 #if (GTK_MINOR_VERSION > 0)
270 // release lock again
271 GDK_THREADS_LEAVE ();
274 wxapp_install_thread_wakeup();
280 //-----------------------------------------------------------------------------
282 //-----------------------------------------------------------------------------
284 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
286 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
287 EVT_IDLE(wxApp::OnIdle
)
294 m_topWindow
= (wxWindow
*) NULL
;
295 m_exitOnFrameDelete
= TRUE
;
297 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
300 m_wakeUpTimerTag
= 0;
301 wxapp_install_thread_wakeup();
304 m_colorCube
= (unsigned char*) NULL
;
309 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
312 wxapp_uninstall_thread_wakeup();
315 if (m_colorCube
) free(m_colorCube
);
318 bool wxApp::OnInitGui()
320 GdkVisual
*visual
= gdk_visual_get_system();
322 /* on some machines, the default visual is just 256 colours, so
323 we make sure we get the best. this can sometimes be wasteful,
324 of course, but what do these guys pay $30.000 for? */
326 if (gdk_visual_get_best() != gdk_visual_get_system())
328 GdkVisual* vis = gdk_visual_get_best();
329 gtk_widget_set_default_visual( vis );
331 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
332 gtk_widget_set_default_colormap( colormap );
338 /* Nothing to do for 15, 16, 24, 32 bit displays */
339 if (visual
->depth
> 8) return TRUE
;
341 /* this initiates the standard palette as defined by GdkImlib
342 in the GNOME libraries. it ensures that all GNOME applications
343 use the same 64 colormap entries on 8-bit displays so you
344 can use several rather graphics-heavy applications at the
346 NOTE: this doesn't really seem to work this way... */
349 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
351 for (int i = 0; i < 64; i++)
354 col.red = g_palette[i*3 + 0] << 8;
355 col.green = g_palette[i*3 + 1] << 8;
356 col.blue = g_palette[i*3 + 2] << 8;
359 gdk_color_alloc( cmap, &col );
362 gtk_widget_set_default_colormap( cmap );
365 /* initialize color cube for 8-bit color reduction dithering */
367 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
369 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
371 for (int r
= 0; r
< 32; r
++)
373 for (int g
= 0; g
< 32; g
++)
375 for (int b
= 0; b
< 32; b
++)
377 int rr
= (r
<< 3) | (r
>> 2);
378 int gg
= (g
<< 3) | (g
>> 2);
379 int bb
= (b
<< 3) | (b
>> 2);
383 GdkColor
*colors
= cmap
->colors
;
388 for (int i
= 0; i
< cmap
->size
; i
++)
390 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
391 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
392 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
393 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
396 index
= i
; max
= sum
;
402 #if (GTK_MINOR_VERSION > 0)
403 /* assume 8-bit true or static colors. this really
405 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
406 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
407 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
408 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
410 wxFAIL_MSG( _T("Unsupported graphics hardware") );
413 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
421 bool wxApp::ProcessIdle()
424 event
.SetEventObject( this );
425 ProcessEvent( event
);
427 return event
.MoreRequested();
430 void wxApp::OnIdle( wxIdleEvent
&event
)
432 static bool inOnIdle
= FALSE
;
434 /* Avoid recursion (via ProcessEvent default case) */
441 /* Resend in the main thread events which have been prepared in other
443 ProcessPendingEvents();
446 /* 'Garbage' collection of windows deleted with Close(). */
447 DeletePendingObjects();
449 /* flush the logged messages if any */
451 wxLog
*log
= wxLog::GetActiveTarget();
452 if (log
!= NULL
&& log
->HasPendingMessages())
456 /* Send OnIdle events to all windows */
457 bool needMore
= SendIdleEvents();
460 event
.RequestMore(TRUE
);
465 bool wxApp::SendIdleEvents()
467 bool needMore
= FALSE
;
469 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
472 wxWindow
* win
= node
->GetData();
473 if (SendIdleEvents(win
))
475 node
= node
->GetNext();
481 bool wxApp::SendIdleEvents( wxWindow
* win
)
483 bool needMore
= FALSE
;
486 event
.SetEventObject(win
);
488 win
->OnInternalIdle();
490 win
->ProcessEvent(event
);
492 if (event
.MoreRequested())
495 wxNode
* node
= win
->GetChildren().First();
498 wxWindow
* win
= (wxWindow
*) node
->Data();
499 if (SendIdleEvents(win
))
507 int wxApp::MainLoop()
513 void wxApp::ExitMainLoop()
518 bool wxApp::Initialized()
520 return m_initialized
;
523 bool wxApp::Pending()
525 return (gtk_events_pending() > 0);
528 void wxApp::Dispatch()
530 gtk_main_iteration();
534 void wxApp::ProcessPendingEvents()
536 wxNode
*node
= wxPendingEvents
->First();
537 wxCriticalSectionLocker
locker(*wxPendingEventsLocker
);
541 wxEvtHandler
*handler
= (wxEvtHandler
*)node
->Data();
543 handler
->ProcessPendingEvents();
547 node
= wxPendingEvents
->First();
550 #endif // wxUSE_THREADS
552 void wxApp::DeletePendingObjects()
554 wxNode
*node
= wxPendingDelete
.First();
557 wxObject
*obj
= (wxObject
*)node
->Data();
561 if (wxPendingDelete
.Find(obj
))
564 node
= wxPendingDelete
.First();
568 bool wxApp::Initialize()
570 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
572 wxClassInfo::InitializeClasses();
574 wxSystemSettings::Init();
576 // GL: I'm annoyed ... I don't know where to put this and I don't want to
577 // create a module for that as it's part of the core.
579 wxPendingEvents
= new wxList();
580 wxPendingEventsLocker
= new wxCriticalSection();
584 wxTheFontNameDirectory = new wxFontNameDirectory;
585 wxTheFontNameDirectory->Initialize();
588 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
589 wxTheColourDatabase
->Initialize();
591 wxInitializeStockLists();
592 wxInitializeStockObjects();
594 #if wxUSE_WX_RESOURCES
595 wxTheResourceCache
= new wxResourceCache( wxKEY_STRING
);
597 wxInitializeResourceSystem();
600 wxImage::InitStandardHandlers();
602 wxModule::RegisterModules();
603 if (!wxModule::InitializeModules()) return FALSE
;
608 void wxApp::CleanUp()
610 wxModule::CleanUpModules();
612 #if wxUSE_WX_RESOURCES
615 if (wxTheResourceCache
)
616 delete wxTheResourceCache
;
617 wxTheResourceCache
= (wxResourceCache
*) NULL
;
619 wxCleanUpResourceSystem();
622 if (wxTheColourDatabase
)
623 delete wxTheColourDatabase
;
624 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
627 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
628 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
631 wxDeleteStockObjects();
633 wxDeleteStockLists();
635 wxImage::CleanUpHandlers();
638 wxTheApp
= (wxApp
*) NULL
;
640 // GL: I'm annoyed ... I don't know where to put this and I don't want to
641 // create a module for that as it's part of the core.
643 delete wxPendingEvents
;
644 delete wxPendingEventsLocker
;
647 wxSystemSettings::Done();
651 wxClassInfo::CleanUpClasses();
653 // check for memory leaks
654 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
655 if (wxDebugContext::CountObjectsLeft() > 0)
657 wxLogDebug(_T("There were memory leaks.\n"));
658 wxDebugContext::Dump();
659 wxDebugContext::PrintStatistics();
664 // do this as the very last thing because everything else can log messages
665 wxLog::DontCreateOnDemand();
667 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
674 //-----------------------------------------------------------------------------
676 //-----------------------------------------------------------------------------
678 int wxEntry( int argc
, char *argv
[] )
682 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
684 gtk_init( &argc
, &argv
);
686 wxSetDetectableAutoRepeat( TRUE
);
688 if (!wxApp::Initialize())
693 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
694 _T("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
696 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
698 wxObject
*test_app
= app_ini();
700 wxTheApp
= (wxApp
*) test_app
;
703 wxCHECK_MSG( wxTheApp
, -1, _T("wxWindows error: no application object") );
705 wxTheApp
->argc
= argc
;
707 wxTheApp
->argv
= new wxChar
*[argc
+1];
709 while (mb_argc
< argc
) {
710 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
713 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
715 wxTheApp
->argv
= argv
;
718 wxString
name(wxFileNameFromPath(argv
[0]));
719 wxStripExtension( name
);
720 wxTheApp
->SetAppName( name
);
724 if ( !wxTheApp
->OnInitGui() )
727 // Here frames insert themselves automatically into wxTopLevelWindows by
728 // getting created in OnInit().
731 if ( !wxTheApp
->OnInit() )
737 /* delete pending toplevel windows (typically a single
738 dialog) so that, if there isn't any left, we don't
740 wxTheApp
->DeletePendingObjects();
742 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
744 if (wxTheApp
->Initialized())
746 retValue
= wxTheApp
->OnRun();
748 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
751 /* Forcibly delete the window. */
752 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
753 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
755 topWindow
->Close( TRUE
);
756 wxTheApp
->DeletePendingObjects();
761 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
769 // flush the logged messages if any
770 wxLog
*log
= wxLog::GetActiveTarget();
771 if (log
!= NULL
&& log
->HasPendingMessages())
774 // continuing to use user defined log target is unsafe from now on because
775 // some resources may be already unavailable, so replace it by something
777 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);
787 #include "wx/gtk/info.xpm"
788 #include "wx/gtk/error.xpm"
789 #include "wx/gtk/question.xpm"
790 #include "wx/gtk/warning.xpm"
793 wxApp::GetStdIcon(int which
) const
797 case wxICON_INFORMATION
:
798 return wxIcon(info_xpm
);
800 case wxICON_QUESTION
:
801 return wxIcon(question_xpm
);
803 case wxICON_EXCLAMATION
:
804 return wxIcon(warning_xpm
);
807 wxFAIL_MSG(_T("requested non existent standard icon"));
808 // still fall through
811 return wxIcon(error_xpm
);