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
);
230 static gint wxapp_wakeup_timerout_callback( gpointer WXUNUSED(data) )
232 gtk_timeout_remove( wxTheApp->m_wakeUpTimerTag );
233 wxTheApp->m_wakeUpTimerTag = 0;
235 #if (GTK_MINOR_VERSION > 0)
236 // when getting called from GDK's time-out handler
237 // we are no longer within GDK's grab on the GUI
238 // thread so we must lock it here ourselves
239 GDK_THREADS_ENTER ();
242 // unblock other threads wishing to do some GUI things
245 // wake up other threads
248 // block other thread again
251 #if (GTK_MINOR_VERSION > 0)
252 // release lock again
253 GDK_THREADS_LEAVE ();
256 wxTheApp->m_wakeUpTimerTag = gtk_timeout_add( 20, wxapp_wakeup_timerout_callback, (gpointer) NULL );
263 //-----------------------------------------------------------------------------
265 //-----------------------------------------------------------------------------
267 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
269 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
270 EVT_IDLE(wxApp::OnIdle
)
277 m_topWindow
= (wxWindow
*) NULL
;
278 m_exitOnFrameDelete
= TRUE
;
280 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
284 m_wakeUpTimerTag = gtk_timeout_add( 20, wxapp_wakeup_timerout_callback, (gpointer) NULL );
288 m_colorCube
= (unsigned char*) NULL
;
293 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
297 if (m_wakeUpTimerTag) gtk_timeout_remove( m_wakeUpTimerTag );
301 if (m_colorCube
) free(m_colorCube
);
304 bool wxApp::OnInitGui()
306 GdkVisual
*visual
= gdk_visual_get_system();
308 /* on some machines, the default visual is just 256 colours, so
309 we make sure we get the best. this can sometimes be wasteful,
310 of course, but what do these guys pay $30.000 for? */
312 if (gdk_visual_get_best() != gdk_visual_get_system())
314 GdkVisual* vis = gdk_visual_get_best();
315 gtk_widget_set_default_visual( vis );
317 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
318 gtk_widget_set_default_colormap( colormap );
324 /* Nothing to do for 15, 16, 24, 32 bit displays */
325 if (visual
->depth
> 8) return TRUE
;
327 /* this initiates the standard palette as defined by GdkImlib
328 in the GNOME libraries. it ensures that all GNOME applications
329 use the same 64 colormap entries on 8-bit displays so you
330 can use several rather graphics-heavy applications at the
332 NOTE: this doesn't really seem to work this way... */
335 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
337 for (int i = 0; i < 64; i++)
340 col.red = g_palette[i*3 + 0] << 8;
341 col.green = g_palette[i*3 + 1] << 8;
342 col.blue = g_palette[i*3 + 2] << 8;
345 gdk_color_alloc( cmap, &col );
348 gtk_widget_set_default_colormap( cmap );
351 /* initialize color cube for 8-bit color reduction dithering */
353 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
355 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
357 for (int r
= 0; r
< 32; r
++)
359 for (int g
= 0; g
< 32; g
++)
361 for (int b
= 0; b
< 32; b
++)
363 int rr
= (r
<< 3) | (r
>> 2);
364 int gg
= (g
<< 3) | (g
>> 2);
365 int bb
= (b
<< 3) | (b
>> 2);
369 GdkColor
*colors
= cmap
->colors
;
374 for (int i
= 0; i
< cmap
->size
; i
++)
376 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
377 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
378 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
379 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
382 index
= i
; max
= sum
;
388 #if (GTK_MINOR_VERSION > 0)
389 /* assume 8-bit true or static colors. this really
391 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
392 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
393 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
394 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
396 wxFAIL_MSG( _T("Unsupported graphics hardware") );
399 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
407 bool wxApp::ProcessIdle()
410 event
.SetEventObject( this );
411 ProcessEvent( event
);
413 return event
.MoreRequested();
416 void wxApp::OnIdle( wxIdleEvent
&event
)
418 static bool inOnIdle
= FALSE
;
420 /* Avoid recursion (via ProcessEvent default case) */
427 /* Resend in the main thread events which have been prepared in other
429 ProcessPendingEvents();
432 /* 'Garbage' collection of windows deleted with Close(). */
433 DeletePendingObjects();
435 /* flush the logged messages if any */
437 wxLog
*log
= wxLog::GetActiveTarget();
438 if (log
!= NULL
&& log
->HasPendingMessages())
442 /* Send OnIdle events to all windows */
443 bool needMore
= SendIdleEvents();
446 event
.RequestMore(TRUE
);
451 bool wxApp::SendIdleEvents()
453 bool needMore
= FALSE
;
455 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
458 wxWindow
* win
= node
->GetData();
459 if (SendIdleEvents(win
))
461 node
= node
->GetNext();
467 bool wxApp::SendIdleEvents( wxWindow
* win
)
469 bool needMore
= FALSE
;
472 event
.SetEventObject(win
);
474 win
->OnInternalIdle();
476 win
->ProcessEvent(event
);
478 if (event
.MoreRequested())
481 wxNode
* node
= win
->GetChildren().First();
484 wxWindow
* win
= (wxWindow
*) node
->Data();
485 if (SendIdleEvents(win
))
493 int wxApp::MainLoop()
499 void wxApp::ExitMainLoop()
504 bool wxApp::Initialized()
506 return m_initialized
;
509 bool wxApp::Pending()
511 return (gtk_events_pending() > 0);
514 void wxApp::Dispatch()
516 gtk_main_iteration();
520 void wxApp::ProcessPendingEvents()
522 wxNode
*node
= wxPendingEvents
->First();
523 wxCriticalSectionLocker
locker(*wxPendingEventsLocker
);
527 wxEvtHandler
*handler
= (wxEvtHandler
*)node
->Data();
529 handler
->ProcessPendingEvents();
533 node
= wxPendingEvents
->First();
536 #endif // wxUSE_THREADS
538 void wxApp::DeletePendingObjects()
540 wxNode
*node
= wxPendingDelete
.First();
543 wxObject
*obj
= (wxObject
*)node
->Data();
547 if (wxPendingDelete
.Find(obj
))
550 node
= wxPendingDelete
.First();
554 bool wxApp::Initialize()
556 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
558 wxClassInfo::InitializeClasses();
560 wxSystemSettings::Init();
562 // GL: I'm annoyed ... I don't know where to put this and I don't want to
563 // create a module for that as it's part of the core.
565 wxPendingEvents
= new wxList();
566 wxPendingEventsLocker
= new wxCriticalSection();
570 wxTheFontNameDirectory = new wxFontNameDirectory;
571 wxTheFontNameDirectory->Initialize();
574 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
575 wxTheColourDatabase
->Initialize();
577 wxInitializeStockLists();
578 wxInitializeStockObjects();
580 #if wxUSE_WX_RESOURCES
581 wxTheResourceCache
= new wxResourceCache( wxKEY_STRING
);
583 wxInitializeResourceSystem();
586 wxImage::InitStandardHandlers();
588 wxModule::RegisterModules();
589 if (!wxModule::InitializeModules()) return FALSE
;
594 void wxApp::CleanUp()
596 wxModule::CleanUpModules();
598 #if wxUSE_WX_RESOURCES
601 if (wxTheResourceCache
)
602 delete wxTheResourceCache
;
603 wxTheResourceCache
= (wxResourceCache
*) NULL
;
605 wxCleanUpResourceSystem();
608 if (wxTheColourDatabase
)
609 delete wxTheColourDatabase
;
610 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
613 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
614 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
617 wxDeleteStockObjects();
619 wxDeleteStockLists();
621 wxImage::CleanUpHandlers();
624 wxTheApp
= (wxApp
*) NULL
;
626 // GL: I'm annoyed ... I don't know where to put this and I don't want to
627 // create a module for that as it's part of the core.
629 delete wxPendingEvents
;
630 delete wxPendingEventsLocker
;
633 wxSystemSettings::Done();
637 wxClassInfo::CleanUpClasses();
639 // check for memory leaks
640 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
641 if (wxDebugContext::CountObjectsLeft() > 0)
643 wxLogDebug(_T("There were memory leaks.\n"));
644 wxDebugContext::Dump();
645 wxDebugContext::PrintStatistics();
650 // do this as the very last thing because everything else can log messages
651 wxLog::DontCreateOnDemand();
653 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
660 //-----------------------------------------------------------------------------
662 //-----------------------------------------------------------------------------
664 int wxEntry( int argc
, char *argv
[] )
668 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
670 gtk_init( &argc
, &argv
);
672 wxSetDetectableAutoRepeat( TRUE
);
674 if (!wxApp::Initialize())
679 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
680 _T("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
682 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
684 wxObject
*test_app
= app_ini();
686 wxTheApp
= (wxApp
*) test_app
;
689 wxCHECK_MSG( wxTheApp
, -1, _T("wxWindows error: no application object") );
691 wxTheApp
->argc
= argc
;
692 wxTheApp
->argv
= argv
;
694 wxString
name(wxFileNameFromPath(argv
[0]));
695 wxStripExtension( name
);
696 wxTheApp
->SetAppName( name
);
700 if ( !wxTheApp
->OnInitGui() )
703 // Here frames insert themselves automatically into wxTopLevelWindows by
704 // getting created in OnInit().
707 if ( !wxTheApp
->OnInit() )
713 /* delete pending toplevel windows (typically a single
714 dialog) so that, if there isn't any left, we don't
716 wxTheApp
->DeletePendingObjects();
718 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
720 if (wxTheApp
->Initialized())
722 retValue
= wxTheApp
->OnRun();
724 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
727 /* Forcibly delete the window. */
728 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
729 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
731 topWindow
->Close( TRUE
);
732 wxTheApp
->DeletePendingObjects();
737 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
745 // flush the logged messages if any
746 wxLog
*log
= wxLog::GetActiveTarget();
747 if (log
!= NULL
&& log
->HasPendingMessages())
750 // continuing to use user defined log target is unsafe from now on because
751 // some resources may be already unavailable, so replace it by something
753 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);
763 #include "wx/gtk/info.xpm"
764 #include "wx/gtk/error.xpm"
765 #include "wx/gtk/question.xpm"
766 #include "wx/gtk/warning.xpm"
769 wxApp::GetStdIcon(int which
) const
773 case wxICON_INFORMATION
:
774 return wxIcon(info_xpm
);
776 case wxICON_QUESTION
:
777 return wxIcon(question_xpm
);
779 case wxICON_EXCLAMATION
:
780 return wxIcon(warning_xpm
);
783 wxFAIL_MSG("requested non existent standard icon");
784 // still fall through
787 return wxIcon(error_xpm
);