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 for ( wxWindowList::Node
*node
= wxTopLevelWindows
.GetFirst();
148 node
= node
->GetNext() )
150 wxWindow
*win
= node
->GetData();
151 win
->OnInternalIdle();
154 if (wxTheApp
->m_idleTag
)
156 /* We need to temporarily remove idle callbacks or the loop will
158 gtk_idle_remove( wxTheApp
->m_idleTag
);
159 wxTheApp
->m_idleTag
= 0;
161 while (gtk_events_pending())
162 gtk_main_iteration();
164 /* re-add idle handler */
165 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
169 while (gtk_events_pending())
170 gtk_main_iteration();
176 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
178 if (!wxTheApp
) return TRUE
;
180 #if (GTK_MINOR_VERSION > 0)
181 /* when getting called from GDK's idle handler we
182 are no longer within GDK's grab on the GUI
183 thread so we must lock it here ourselves */
184 GDK_THREADS_ENTER ();
187 /* sent idle event to all who request them */
188 while (wxTheApp
->ProcessIdle()) { }
190 /* we don't want any more idle events until the next event is
192 gtk_idle_remove( wxTheApp
->m_idleTag
);
193 wxTheApp
->m_idleTag
= 0;
195 /* indicate that we are now in idle mode - even so deeply
196 in idle mode that we don't get any idle events anymore.
197 this is like wxMSW where an idle event is sent only
198 once each time after the event queue has been completely
202 #if (GTK_MINOR_VERSION > 0)
203 /* release lock again */
204 GDK_THREADS_LEAVE ();
210 void wxapp_install_idle_handler()
212 wxASSERT_MSG( wxTheApp
->m_idleTag
== 0, "attempt to install idle handler twice" );
214 /* this routine gets called by all event handlers
215 indicating that the idle is over. */
217 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
223 static gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) )
225 gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag
);
226 wxTheApp
->m_wakeUpTimerTag
= 0;
228 #if (GTK_MINOR_VERSION > 0)
229 /* when getting called from GDK's time-out handler
230 we are no longer within GDK's grab on the GUI
231 thread so we must lock it here ourselves */
232 GDK_THREADS_ENTER ();
235 /* unblock other threads wishing to do some GUI things */
238 /* wake up other threads */
241 /* block other thread again */
244 #if (GTK_MINOR_VERSION > 0)
245 /* release lock again */
246 GDK_THREADS_LEAVE ();
249 wxTheApp
->m_wakeUpTimerTag
= gtk_timeout_add( 10, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
255 //-----------------------------------------------------------------------------
257 //-----------------------------------------------------------------------------
259 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
261 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
262 EVT_IDLE(wxApp::OnIdle
)
269 m_topWindow
= (wxWindow
*) NULL
;
270 m_exitOnFrameDelete
= TRUE
;
272 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
275 m_wakeUpTimerTag
= gtk_timeout_add( 10, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
278 m_colorCube
= (unsigned char*) NULL
;
283 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
286 if (m_wakeUpTimerTag
) gtk_timeout_remove( m_wakeUpTimerTag
);
289 if (m_colorCube
) free(m_colorCube
);
292 bool wxApp::OnInitGui()
294 /* Nothing to do for 15, 16, 24, 32 bit displays */
296 GdkVisual
*visual
= gdk_visual_get_system();
297 if (visual
->depth
> 8) return TRUE
;
299 /* this initiates the standard palette as defined by GdkImlib
300 in the GNOME libraries. it ensures that all GNOME applications
301 use the same 64 colormap entries on 8-bit displays so you
302 can use several rather graphics-heavy applications at the
304 NOTE: this doesn't really seem to work this way... */
307 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
309 for (int i = 0; i < 64; i++)
312 col.red = g_palette[i*3 + 0] << 8;
313 col.green = g_palette[i*3 + 1] << 8;
314 col.blue = g_palette[i*3 + 2] << 8;
317 gdk_color_alloc( cmap, &col );
320 gtk_widget_set_default_colormap( cmap );
323 /* initialize color cube for 8-bit color reduction dithering */
325 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
327 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
329 for (int r
= 0; r
< 32; r
++)
331 for (int g
= 0; g
< 32; g
++)
333 for (int b
= 0; b
< 32; b
++)
335 int rr
= (r
<< 3) | (r
>> 2);
336 int gg
= (g
<< 3) | (g
>> 2);
337 int bb
= (b
<< 3) | (b
>> 2);
341 GdkColor
*colors
= cmap
->colors
;
346 for (int i
= 0; i
< cmap
->size
; i
++)
348 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
349 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
350 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
351 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
354 index
= i
; max
= sum
;
359 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
367 bool wxApp::ProcessIdle()
370 event
.SetEventObject( this );
371 ProcessEvent( event
);
373 return event
.MoreRequested();
376 void wxApp::OnIdle( wxIdleEvent
&event
)
378 static bool inOnIdle
= FALSE
;
380 /* Avoid recursion (via ProcessEvent default case) */
387 /* Resend in the main thread events which have been prepared in other
389 ProcessPendingEvents();
392 /* 'Garbage' collection of windows deleted with Close(). */
393 DeletePendingObjects();
395 /* flush the logged messages if any */
396 wxLog
*log
= wxLog::GetActiveTarget();
397 if (log
!= NULL
&& log
->HasPendingMessages())
400 /* Send OnIdle events to all windows */
401 bool needMore
= SendIdleEvents();
404 event
.RequestMore(TRUE
);
409 bool wxApp::SendIdleEvents()
411 bool needMore
= FALSE
;
413 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
416 wxWindow
* win
= node
->GetData();
417 if (SendIdleEvents(win
))
419 node
= node
->GetNext();
425 bool wxApp::SendIdleEvents( wxWindow
* win
)
427 bool needMore
= FALSE
;
430 event
.SetEventObject(win
);
432 win
->OnInternalIdle();
434 win
->ProcessEvent(event
);
436 if (event
.MoreRequested())
439 wxNode
* node
= win
->GetChildren().First();
442 wxWindow
* win
= (wxWindow
*) node
->Data();
443 if (SendIdleEvents(win
))
451 int wxApp::MainLoop()
457 void wxApp::ExitMainLoop()
462 bool wxApp::Initialized()
464 return m_initialized
;
467 bool wxApp::Pending()
469 return (gtk_events_pending() > 0);
472 void wxApp::Dispatch()
474 gtk_main_iteration();
478 void wxApp::ProcessPendingEvents()
480 wxNode
*node
= wxPendingEvents
->First();
481 wxCriticalSectionLocker
locker(*wxPendingEventsLocker
);
485 wxEvtHandler
*handler
= (wxEvtHandler
*)node
->Data();
487 handler
->ProcessPendingEvents();
491 node
= wxPendingEvents
->First();
494 #endif // wxUSE_THREADS
496 void wxApp::DeletePendingObjects()
498 wxNode
*node
= wxPendingDelete
.First();
501 wxObject
*obj
= (wxObject
*)node
->Data();
505 if (wxPendingDelete
.Find(obj
))
508 node
= wxPendingDelete
.First();
512 wxWindow
*wxApp::GetTopWindow()
516 else if (wxTopLevelWindows
.GetCount() > 0)
517 return wxTopLevelWindows
.GetFirst()->GetData();
522 void wxApp::SetTopWindow( wxWindow
*win
)
527 bool wxApp::Initialize()
529 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
531 wxClassInfo::InitializeClasses();
533 wxSystemSettings::Init();
535 // GL: I'm annoyed ... I don't know where to put this and I don't want to
536 // create a module for that as it's part of the core.
538 wxPendingEvents
= new wxList();
539 wxPendingEventsLocker
= new wxCriticalSection();
543 wxTheFontNameDirectory = new wxFontNameDirectory;
544 wxTheFontNameDirectory->Initialize();
547 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
548 wxTheColourDatabase
->Initialize();
550 wxInitializeStockLists();
551 wxInitializeStockObjects();
553 #if wxUSE_WX_RESOURCES
554 wxTheResourceCache
= new wxResourceCache( wxKEY_STRING
);
556 wxInitializeResourceSystem();
559 wxImage::InitStandardHandlers();
561 /* no global cursor under X
562 g_globalCursor = new wxCursor; */
564 wxModule::RegisterModules();
565 if (!wxModule::InitializeModules()) return FALSE
;
570 void wxApp::CleanUp()
572 wxModule::CleanUpModules();
574 #if wxUSE_WX_RESOURCES
577 if (wxTheResourceCache
)
578 delete wxTheResourceCache
;
579 wxTheResourceCache
= (wxResourceCache
*) NULL
;
581 wxCleanUpResourceSystem();
584 if (wxTheColourDatabase
)
585 delete wxTheColourDatabase
;
586 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
589 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
590 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
593 wxDeleteStockObjects();
595 wxDeleteStockLists();
597 wxImage::CleanUpHandlers();
600 wxTheApp
= (wxApp
*) NULL
;
602 // GL: I'm annoyed ... I don't know where to put this and I don't want to
603 // create a module for that as it's part of the core.
605 delete wxPendingEvents
;
606 delete wxPendingEventsLocker
;
609 wxSystemSettings::Done();
613 wxClassInfo::CleanUpClasses();
615 // check for memory leaks
616 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
617 if (wxDebugContext::CountObjectsLeft() > 0)
619 wxLogDebug(_T("There were memory leaks.\n"));
620 wxDebugContext::Dump();
621 wxDebugContext::PrintStatistics();
625 // do this as the very last thing because everything else can log messages
626 wxLog::DontCreateOnDemand();
628 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
633 wxLog
*wxApp::CreateLogTarget()
638 //-----------------------------------------------------------------------------
640 //-----------------------------------------------------------------------------
642 int wxEntry( int argc
, char *argv
[] )
646 gtk_init( &argc
, &argv
);
648 wxSetDetectableAutoRepeat( TRUE
);
650 if (!wxApp::Initialize())
655 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
656 _T("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
658 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
660 wxObject
*test_app
= app_ini();
662 wxTheApp
= (wxApp
*) test_app
;
665 wxCHECK_MSG( wxTheApp
, -1, _T("wxWindows error: no application object") );
667 wxTheApp
->argc
= argc
;
668 wxTheApp
->argv
= argv
;
670 wxString
name(wxFileNameFromPath(argv
[0]));
671 wxStripExtension( name
);
672 wxTheApp
->SetAppName( name
);
676 if ( !wxTheApp
->OnInitGui() )
679 // Here frames insert themselves automatically into wxTopLevelWindows by
680 // getting created in OnInit().
683 if ( !wxTheApp
->OnInit() )
689 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
691 if (wxTheApp
->Initialized())
692 retValue
= wxTheApp
->OnRun();
694 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
697 // Forcibly delete the window.
698 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
699 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
701 topWindow
->Close( TRUE
);
702 wxTheApp
->DeletePendingObjects();
707 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
714 // flush the logged messages if any
715 wxLog
*log
= wxLog::GetActiveTarget();
716 if (log
!= NULL
&& log
->HasPendingMessages())
719 // continuing to use user defined log target is unsafe from now on because
720 // some resources may be already unavailable, so replace it by something
722 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);