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 /* when getting called from GDK's idle handler we
181 are no longer within GDK's grab on the GUI
182 thread so we must lock it here ourselves */
183 GDK_THREADS_ENTER ();
185 /* sent idle event to all who request them */
186 while (wxTheApp
->ProcessIdle()) { }
188 /* we don't want any more idle events until the next event is
190 gtk_idle_remove( wxTheApp
->m_idleTag
);
191 wxTheApp
->m_idleTag
= 0;
193 /* indicate that we are now in idle mode - even so deeply
194 in idle mode that we don't get any idle events anymore.
195 this is like wxMSW where an idle event is sent only
196 once each time after the event queue has been completely
200 /* release lock again */
201 GDK_THREADS_LEAVE ();
206 void wxapp_install_idle_handler()
208 wxASSERT_MSG( wxTheApp
->m_idleTag
== 0, "attempt to install idle handler twice" );
210 /* this routine gets called by all event handlers
211 indicating that the idle is over. */
213 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
219 static gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) )
221 gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag
);
222 wxTheApp
->m_wakeUpTimerTag
= 0;
224 /* when getting called from GDK's time-out handler
225 we are no longer within GDK's grab on the GUI
226 thread so we must lock it here ourselves */
227 GDK_THREADS_ENTER ();
229 /* unblock other threads wishing to do some GUI things */
232 /* wake up other threads */
235 /* block other thread again */
238 /* release lock again */
239 GDK_THREADS_LEAVE ();
241 wxTheApp
->m_wakeUpTimerTag
= gtk_timeout_add( 10, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
247 //-----------------------------------------------------------------------------
249 //-----------------------------------------------------------------------------
251 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
253 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
254 EVT_IDLE(wxApp::OnIdle
)
261 m_topWindow
= (wxWindow
*) NULL
;
262 m_exitOnFrameDelete
= TRUE
;
264 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
267 m_wakeUpTimerTag
= gtk_timeout_add( 10, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
270 m_colorCube
= (unsigned char*) NULL
;
275 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
278 if (m_wakeUpTimerTag
) gtk_timeout_remove( m_wakeUpTimerTag
);
281 if (m_colorCube
) free(m_colorCube
);
284 bool wxApp::OnInitGui()
286 /* Nothing to do for 15, 16, 24, 32 bit displays */
288 GdkVisual
*visual
= gdk_visual_get_system();
289 if (visual
->depth
> 8) return TRUE
;
291 /* this initiates the standard palette as defined by GdkImlib
292 in the GNOME libraries. it ensures that all GNOME applications
293 use the same 64 colormap entries on 8-bit displays so you
294 can use several rather graphics-heavy applications at the
296 NOTE: this doesn't really seem to work this way... */
299 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
301 for (int i = 0; i < 64; i++)
304 col.red = g_palette[i*3 + 0] << 8;
305 col.green = g_palette[i*3 + 1] << 8;
306 col.blue = g_palette[i*3 + 2] << 8;
309 gdk_color_alloc( cmap, &col );
312 gtk_widget_set_default_colormap( cmap );
315 /* initialize color cube for 8-bit color reduction dithering */
317 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
319 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
321 for (int r
= 0; r
< 32; r
++)
323 for (int g
= 0; g
< 32; g
++)
325 for (int b
= 0; b
< 32; b
++)
327 int rr
= (r
<< 3) | (r
>> 2);
328 int gg
= (g
<< 3) | (g
>> 2);
329 int bb
= (b
<< 3) | (b
>> 2);
333 GdkColor
*colors
= cmap
->colors
;
338 for (int i
= 0; i
< cmap
->size
; i
++)
340 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
341 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
342 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
343 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
346 index
= i
; max
= sum
;
351 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
359 bool wxApp::ProcessIdle()
362 event
.SetEventObject( this );
363 ProcessEvent( event
);
365 return event
.MoreRequested();
368 void wxApp::OnIdle( wxIdleEvent
&event
)
370 static bool inOnIdle
= FALSE
;
372 /* Avoid recursion (via ProcessEvent default case) */
379 /* Resend in the main thread events which have been prepared in other
381 ProcessPendingEvents();
384 /* 'Garbage' collection of windows deleted with Close(). */
385 DeletePendingObjects();
387 /* flush the logged messages if any */
388 wxLog
*log
= wxLog::GetActiveTarget();
389 if (log
!= NULL
&& log
->HasPendingMessages())
392 /* Send OnIdle events to all windows */
393 bool needMore
= SendIdleEvents();
396 event
.RequestMore(TRUE
);
401 bool wxApp::SendIdleEvents()
403 bool needMore
= FALSE
;
405 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
408 wxWindow
* win
= node
->GetData();
409 if (SendIdleEvents(win
))
411 node
= node
->GetNext();
417 bool wxApp::SendIdleEvents( wxWindow
* win
)
419 bool needMore
= FALSE
;
422 event
.SetEventObject(win
);
424 win
->OnInternalIdle();
426 win
->ProcessEvent(event
);
428 if (event
.MoreRequested())
431 wxNode
* node
= win
->GetChildren().First();
434 wxWindow
* win
= (wxWindow
*) node
->Data();
435 if (SendIdleEvents(win
))
443 int wxApp::MainLoop()
449 void wxApp::ExitMainLoop()
454 bool wxApp::Initialized()
456 return m_initialized
;
459 bool wxApp::Pending()
461 return (gtk_events_pending() > 0);
464 void wxApp::Dispatch()
466 gtk_main_iteration();
470 void wxApp::ProcessPendingEvents()
472 wxNode
*node
= wxPendingEvents
->First();
473 wxCriticalSectionLocker
locker(*wxPendingEventsLocker
);
477 wxEvtHandler
*handler
= (wxEvtHandler
*)node
->Data();
479 handler
->ProcessPendingEvents();
483 node
= wxPendingEvents
->First();
486 #endif // wxUSE_THREADS
488 void wxApp::DeletePendingObjects()
490 wxNode
*node
= wxPendingDelete
.First();
493 wxObject
*obj
= (wxObject
*)node
->Data();
497 if (wxPendingDelete
.Find(obj
))
500 node
= wxPendingDelete
.First();
504 wxWindow
*wxApp::GetTopWindow()
508 else if (wxTopLevelWindows
.GetCount() > 0)
509 return wxTopLevelWindows
.GetFirst()->GetData();
514 void wxApp::SetTopWindow( wxWindow
*win
)
519 bool wxApp::Initialize()
521 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
523 wxClassInfo::InitializeClasses();
525 wxSystemSettings::Init();
527 // GL: I'm annoyed ... I don't know where to put this and I don't want to
528 // create a module for that as it's part of the core.
530 wxPendingEvents
= new wxList();
531 wxPendingEventsLocker
= new wxCriticalSection();
535 wxTheFontNameDirectory = new wxFontNameDirectory;
536 wxTheFontNameDirectory->Initialize();
539 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
540 wxTheColourDatabase
->Initialize();
542 wxInitializeStockLists();
543 wxInitializeStockObjects();
545 #if wxUSE_WX_RESOURCES
546 wxTheResourceCache
= new wxResourceCache( wxKEY_STRING
);
548 wxInitializeResourceSystem();
551 wxImage::InitStandardHandlers();
553 /* no global cursor under X
554 g_globalCursor = new wxCursor; */
556 wxModule::RegisterModules();
557 if (!wxModule::InitializeModules()) return FALSE
;
562 void wxApp::CleanUp()
564 wxModule::CleanUpModules();
566 #if wxUSE_WX_RESOURCES
569 if (wxTheResourceCache
)
570 delete wxTheResourceCache
;
571 wxTheResourceCache
= (wxResourceCache
*) NULL
;
573 wxCleanUpResourceSystem();
576 if (wxTheColourDatabase
)
577 delete wxTheColourDatabase
;
578 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
581 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
582 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
585 wxDeleteStockObjects();
587 wxDeleteStockLists();
589 wxImage::CleanUpHandlers();
592 wxTheApp
= (wxApp
*) NULL
;
594 // GL: I'm annoyed ... I don't know where to put this and I don't want to
595 // create a module for that as it's part of the core.
597 delete wxPendingEvents
;
598 delete wxPendingEventsLocker
;
601 wxSystemSettings::Done();
605 wxClassInfo::CleanUpClasses();
607 // check for memory leaks
608 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
609 if (wxDebugContext::CountObjectsLeft() > 0)
611 wxLogDebug(_T("There were memory leaks.\n"));
612 wxDebugContext::Dump();
613 wxDebugContext::PrintStatistics();
617 // do this as the very last thing because everything else can log messages
618 wxLog::DontCreateOnDemand();
620 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
625 wxLog
*wxApp::CreateLogTarget()
630 //-----------------------------------------------------------------------------
632 //-----------------------------------------------------------------------------
634 int wxEntry( int argc
, char *argv
[] )
638 gtk_init( &argc
, &argv
);
640 wxSetDetectableAutoRepeat( TRUE
);
642 if (!wxApp::Initialize())
647 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
648 _T("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
650 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
652 wxObject
*test_app
= app_ini();
654 wxTheApp
= (wxApp
*) test_app
;
657 wxCHECK_MSG( wxTheApp
, -1, _T("wxWindows error: no application object") );
659 wxTheApp
->argc
= argc
;
660 wxTheApp
->argv
= argv
;
662 wxString
name(wxFileNameFromPath(argv
[0]));
663 wxStripExtension( name
);
664 wxTheApp
->SetAppName( name
);
668 if ( !wxTheApp
->OnInitGui() )
671 // Here frames insert themselves automatically into wxTopLevelWindows by
672 // getting created in OnInit().
675 if ( !wxTheApp
->OnInit() )
681 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
683 if (wxTheApp
->Initialized())
684 retValue
= wxTheApp
->OnRun();
686 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
689 // Forcibly delete the window.
690 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
691 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
693 topWindow
->Close( TRUE
);
694 wxTheApp
->DeletePendingObjects();
699 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
706 // flush the logged messages if any
707 wxLog
*log
= wxLog::GetActiveTarget();
708 if (log
!= NULL
&& log
->HasPendingMessages())
711 // continuing to use user defined log target is unsafe from now on because
712 // some resources may be already unavailable, so replace it by something
714 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);