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
;
49 extern wxList
*wxPendingEvents
;
50 extern wxCriticalSection
*wxPendingEventsLocker
;
52 extern wxResourceCache
*wxTheResourceCache
;
55 unsigned char g_palette
[64*3] =
123 //-----------------------------------------------------------------------------
125 //-----------------------------------------------------------------------------
127 extern void wxFlushResources(void);
129 //-----------------------------------------------------------------------------
131 //-----------------------------------------------------------------------------
138 /* forward declaration */
139 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) );
143 /* it's necessary to call ProcessIdle() to update the frames sizes which
144 might have been changed (it also will update other things set from
145 OnUpdateUI() which is a nice (and desired) side effect) */
146 while (wxTheApp
->ProcessIdle()) { }
149 for ( wxWindowList::Node
*node
= wxTopLevelWindows
.GetFirst();
151 node
= node
->GetNext() )
153 wxWindow
*win
= node
->GetData();
154 win
->OnInternalIdle();
158 if (wxTheApp
->m_idleTag
)
160 /* We need to temporarily remove idle callbacks or the loop will
162 gtk_idle_remove( wxTheApp
->m_idleTag
);
163 wxTheApp
->m_idleTag
= 0;
165 while (gtk_events_pending())
166 gtk_main_iteration();
168 /* re-add idle handler */
169 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
173 while (gtk_events_pending())
174 gtk_main_iteration();
180 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
182 if (!wxTheApp
) return TRUE
;
184 #if (GTK_MINOR_VERSION > 0)
185 /* when getting called from GDK's idle handler we
186 are no longer within GDK's grab on the GUI
187 thread so we must lock it here ourselves */
188 GDK_THREADS_ENTER ();
191 /* sent idle event to all who request them */
192 while (wxTheApp
->ProcessIdle()) { }
194 /* we don't want any more idle events until the next event is
196 gtk_idle_remove( wxTheApp
->m_idleTag
);
197 wxTheApp
->m_idleTag
= 0;
199 /* indicate that we are now in idle mode - even so deeply
200 in idle mode that we don't get any idle events anymore.
201 this is like wxMSW where an idle event is sent only
202 once each time after the event queue has been completely
206 #if (GTK_MINOR_VERSION > 0)
207 /* release lock again */
208 GDK_THREADS_LEAVE ();
214 void wxapp_install_idle_handler()
216 wxASSERT_MSG( wxTheApp
->m_idleTag
== 0, "attempt to install idle handler twice" );
218 /* this routine gets called by all event handlers
219 indicating that the idle is over. */
221 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
227 static gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) )
229 gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag
);
230 wxTheApp
->m_wakeUpTimerTag
= 0;
232 #if (GTK_MINOR_VERSION > 0)
233 /* when getting called from GDK's time-out handler
234 we are no longer within GDK's grab on the GUI
235 thread so we must lock it here ourselves */
236 GDK_THREADS_ENTER ();
239 /* unblock other threads wishing to do some GUI things */
242 /* wake up other threads */
245 /* block other thread again */
248 #if (GTK_MINOR_VERSION > 0)
249 /* release lock again */
250 GDK_THREADS_LEAVE ();
253 wxTheApp
->m_wakeUpTimerTag
= gtk_timeout_add( 10, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
259 //-----------------------------------------------------------------------------
261 //-----------------------------------------------------------------------------
263 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
265 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
266 EVT_IDLE(wxApp::OnIdle
)
273 m_topWindow
= (wxWindow
*) NULL
;
274 m_exitOnFrameDelete
= TRUE
;
276 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
279 m_wakeUpTimerTag
= gtk_timeout_add( 10, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
282 m_colorCube
= (unsigned char*) NULL
;
287 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
290 if (m_wakeUpTimerTag
) gtk_timeout_remove( m_wakeUpTimerTag
);
293 if (m_colorCube
) free(m_colorCube
);
296 bool wxApp::OnInitGui()
298 /* Nothing to do for 15, 16, 24, 32 bit displays */
300 GdkVisual
*visual
= gdk_visual_get_system();
301 if (visual
->depth
> 8) return TRUE
;
303 /* this initiates the standard palette as defined by GdkImlib
304 in the GNOME libraries. it ensures that all GNOME applications
305 use the same 64 colormap entries on 8-bit displays so you
306 can use several rather graphics-heavy applications at the
308 NOTE: this doesn't really seem to work this way... */
311 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
313 for (int i = 0; i < 64; i++)
316 col.red = g_palette[i*3 + 0] << 8;
317 col.green = g_palette[i*3 + 1] << 8;
318 col.blue = g_palette[i*3 + 2] << 8;
321 gdk_color_alloc( cmap, &col );
324 gtk_widget_set_default_colormap( cmap );
327 /* initialize color cube for 8-bit color reduction dithering */
329 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
331 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
333 for (int r
= 0; r
< 32; r
++)
335 for (int g
= 0; g
< 32; g
++)
337 for (int b
= 0; b
< 32; b
++)
339 int rr
= (r
<< 3) | (r
>> 2);
340 int gg
= (g
<< 3) | (g
>> 2);
341 int bb
= (b
<< 3) | (b
>> 2);
345 GdkColor
*colors
= cmap
->colors
;
350 for (int i
= 0; i
< cmap
->size
; i
++)
352 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
353 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
354 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
355 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
358 index
= i
; max
= sum
;
363 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
371 bool wxApp::ProcessIdle()
374 event
.SetEventObject( this );
375 ProcessEvent( event
);
377 return event
.MoreRequested();
380 void wxApp::OnIdle( wxIdleEvent
&event
)
382 static bool inOnIdle
= FALSE
;
384 /* Avoid recursion (via ProcessEvent default case) */
391 /* Resend in the main thread events which have been prepared in other
393 ProcessPendingEvents();
396 /* 'Garbage' collection of windows deleted with Close(). */
397 DeletePendingObjects();
399 /* flush the logged messages if any */
400 wxLog
*log
= wxLog::GetActiveTarget();
401 if (log
!= NULL
&& log
->HasPendingMessages())
404 /* Send OnIdle events to all windows */
405 bool needMore
= SendIdleEvents();
408 event
.RequestMore(TRUE
);
413 bool wxApp::SendIdleEvents()
415 bool needMore
= FALSE
;
417 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
420 wxWindow
* win
= node
->GetData();
421 if (SendIdleEvents(win
))
423 node
= node
->GetNext();
429 bool wxApp::SendIdleEvents( wxWindow
* win
)
431 bool needMore
= FALSE
;
434 event
.SetEventObject(win
);
436 win
->OnInternalIdle();
438 win
->ProcessEvent(event
);
440 if (event
.MoreRequested())
443 wxNode
* node
= win
->GetChildren().First();
446 wxWindow
* win
= (wxWindow
*) node
->Data();
447 if (SendIdleEvents(win
))
455 int wxApp::MainLoop()
461 void wxApp::ExitMainLoop()
466 bool wxApp::Initialized()
468 return m_initialized
;
471 bool wxApp::Pending()
473 return (gtk_events_pending() > 0);
476 void wxApp::Dispatch()
478 gtk_main_iteration();
482 void wxApp::ProcessPendingEvents()
484 wxNode
*node
= wxPendingEvents
->First();
485 wxCriticalSectionLocker
locker(*wxPendingEventsLocker
);
489 wxEvtHandler
*handler
= (wxEvtHandler
*)node
->Data();
491 handler
->ProcessPendingEvents();
495 node
= wxPendingEvents
->First();
498 #endif // wxUSE_THREADS
500 void wxApp::DeletePendingObjects()
502 wxNode
*node
= wxPendingDelete
.First();
505 wxObject
*obj
= (wxObject
*)node
->Data();
509 if (wxPendingDelete
.Find(obj
))
512 node
= wxPendingDelete
.First();
516 wxWindow
*wxApp::GetTopWindow()
520 else if (wxTopLevelWindows
.GetCount() > 0)
521 return wxTopLevelWindows
.GetFirst()->GetData();
526 void wxApp::SetTopWindow( wxWindow
*win
)
531 bool wxApp::Initialize()
533 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
535 wxClassInfo::InitializeClasses();
537 wxSystemSettings::Init();
539 // GL: I'm annoyed ... I don't know where to put this and I don't want to
540 // create a module for that as it's part of the core.
542 wxPendingEvents
= new wxList();
543 wxPendingEventsLocker
= new wxCriticalSection();
547 wxTheFontNameDirectory = new wxFontNameDirectory;
548 wxTheFontNameDirectory->Initialize();
551 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
552 wxTheColourDatabase
->Initialize();
554 wxInitializeStockLists();
555 wxInitializeStockObjects();
557 #if wxUSE_WX_RESOURCES
558 wxTheResourceCache
= new wxResourceCache( wxKEY_STRING
);
560 wxInitializeResourceSystem();
563 wxImage::InitStandardHandlers();
565 /* no global cursor under X
566 g_globalCursor = new wxCursor; */
568 wxModule::RegisterModules();
569 if (!wxModule::InitializeModules()) return FALSE
;
574 void wxApp::CleanUp()
576 wxModule::CleanUpModules();
578 #if wxUSE_WX_RESOURCES
581 if (wxTheResourceCache
)
582 delete wxTheResourceCache
;
583 wxTheResourceCache
= (wxResourceCache
*) NULL
;
585 wxCleanUpResourceSystem();
588 if (wxTheColourDatabase
)
589 delete wxTheColourDatabase
;
590 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
593 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
594 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
597 wxDeleteStockObjects();
599 wxDeleteStockLists();
601 wxImage::CleanUpHandlers();
604 wxTheApp
= (wxApp
*) NULL
;
606 // GL: I'm annoyed ... I don't know where to put this and I don't want to
607 // create a module for that as it's part of the core.
609 delete wxPendingEvents
;
610 delete wxPendingEventsLocker
;
613 wxSystemSettings::Done();
617 wxClassInfo::CleanUpClasses();
619 // check for memory leaks
620 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
621 if (wxDebugContext::CountObjectsLeft() > 0)
623 wxLogDebug(_T("There were memory leaks.\n"));
624 wxDebugContext::Dump();
625 wxDebugContext::PrintStatistics();
629 // do this as the very last thing because everything else can log messages
630 wxLog::DontCreateOnDemand();
632 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
637 wxLog
*wxApp::CreateLogTarget()
642 //-----------------------------------------------------------------------------
644 //-----------------------------------------------------------------------------
646 int wxEntry( int argc
, char *argv
[] )
650 gtk_init( &argc
, &argv
);
652 wxSetDetectableAutoRepeat( TRUE
);
654 if (!wxApp::Initialize())
659 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
660 _T("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
662 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
664 wxObject
*test_app
= app_ini();
666 wxTheApp
= (wxApp
*) test_app
;
669 wxCHECK_MSG( wxTheApp
, -1, _T("wxWindows error: no application object") );
671 wxTheApp
->argc
= argc
;
672 wxTheApp
->argv
= argv
;
674 wxString
name(wxFileNameFromPath(argv
[0]));
675 wxStripExtension( name
);
676 wxTheApp
->SetAppName( name
);
680 if ( !wxTheApp
->OnInitGui() )
683 // Here frames insert themselves automatically into wxTopLevelWindows by
684 // getting created in OnInit().
687 if ( !wxTheApp
->OnInit() )
693 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
695 if (wxTheApp
->Initialized())
696 retValue
= wxTheApp
->OnRun();
698 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
701 // Forcibly delete the window.
702 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
703 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
705 topWindow
->Close( TRUE
);
706 wxTheApp
->DeletePendingObjects();
711 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
718 // flush the logged messages if any
719 wxLog
*log
= wxLog::GetActiveTarget();
720 if (log
!= NULL
&& log
->HasPendingMessages())
723 // continuing to use user defined log target is unsafe from now on because
724 // some resources may be already unavailable, so replace it by something
726 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);