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 /* sent idle event to all who request them */
181 while (wxTheApp
->ProcessIdle()) { }
183 /* we don't want any more idle events until the next event is
185 gtk_idle_remove( wxTheApp
->m_idleTag
);
186 wxTheApp
->m_idleTag
= 0;
188 /* indicate that we are now in idle mode - even so deeply
189 in idle mode that we don't get any idle events anymore.
190 this is like wxMSW where an idle event is sent only
191 once each time after the event queue has been completely
195 /* wake up other threads */
203 void wxapp_install_idle_handler()
205 /* this routine gets called by all event handlers
206 indicating that the idle is over. */
208 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
213 //-----------------------------------------------------------------------------
215 //-----------------------------------------------------------------------------
217 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
219 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
220 EVT_IDLE(wxApp::OnIdle
)
227 m_topWindow
= (wxWindow
*) NULL
;
228 m_exitOnFrameDelete
= TRUE
;
230 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
232 m_colorCube
= (unsigned char*) NULL
;
237 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
239 if (m_colorCube
) free(m_colorCube
);
242 bool wxApp::OnInitGui()
244 /* Nothing to do for 15, 16, 24, 32 bit displays */
246 GdkVisual
*visual
= gdk_visual_get_system();
247 if (visual
->depth
> 8) return TRUE
;
249 /* this initiates the standard palette as defined by GdkImlib
250 in the GNOME libraries. it ensures that all GNOME applications
251 use the same 64 colormap entries on 8-bit displays so you
252 can use several rather graphics-heavy applications at the
254 NOTE: this doesn't really seem to work this way... */
257 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
259 for (int i = 0; i < 64; i++)
262 col.red = g_palette[i*3 + 0] << 8;
263 col.green = g_palette[i*3 + 1] << 8;
264 col.blue = g_palette[i*3 + 2] << 8;
267 gdk_color_alloc( cmap, &col );
270 gtk_widget_set_default_colormap( cmap );
273 /* initialize color cube for 8-bit color reduction dithering */
275 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
277 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
279 for (int r
= 0; r
< 32; r
++)
281 for (int g
= 0; g
< 32; g
++)
283 for (int b
= 0; b
< 32; b
++)
285 int rr
= (r
<< 3) | (r
>> 2);
286 int gg
= (g
<< 3) | (g
>> 2);
287 int bb
= (b
<< 3) | (b
>> 2);
291 GdkColor
*colors
= cmap
->colors
;
296 for (int i
= 0; i
< cmap
->size
; i
++)
298 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
299 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
300 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
301 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
304 index
= i
; max
= sum
;
309 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
317 bool wxApp::ProcessIdle()
320 event
.SetEventObject( this );
321 ProcessEvent( event
);
323 return event
.MoreRequested();
326 void wxApp::OnIdle( wxIdleEvent
&event
)
328 static bool inOnIdle
= FALSE
;
330 /* Avoid recursion (via ProcessEvent default case) */
337 /* Resend in the main thread events which have been prepared in other
339 ProcessPendingEvents();
342 /* 'Garbage' collection of windows deleted with Close(). */
343 DeletePendingObjects();
345 /* flush the logged messages if any */
346 wxLog
*log
= wxLog::GetActiveTarget();
347 if (log
!= NULL
&& log
->HasPendingMessages())
350 /* Send OnIdle events to all windows */
351 bool needMore
= SendIdleEvents();
354 event
.RequestMore(TRUE
);
359 bool wxApp::SendIdleEvents()
361 bool needMore
= FALSE
;
363 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
366 wxWindow
* win
= node
->GetData();
367 if (SendIdleEvents(win
))
369 node
= node
->GetNext();
375 bool wxApp::SendIdleEvents( wxWindow
* win
)
377 bool needMore
= FALSE
;
380 event
.SetEventObject(win
);
382 win
->OnInternalIdle();
384 win
->ProcessEvent(event
);
386 if (event
.MoreRequested())
389 wxNode
* node
= win
->GetChildren().First();
392 wxWindow
* win
= (wxWindow
*) node
->Data();
393 if (SendIdleEvents(win
))
401 int wxApp::MainLoop()
407 void wxApp::ExitMainLoop()
412 bool wxApp::Initialized()
414 return m_initialized
;
417 bool wxApp::Pending()
419 return (gtk_events_pending() > 0);
422 void wxApp::Dispatch()
424 gtk_main_iteration();
428 void wxApp::ProcessPendingEvents()
430 wxNode
*node
= wxPendingEvents
->First();
431 wxCriticalSectionLocker
locker(*wxPendingEventsLocker
);
435 wxEvtHandler
*handler
= (wxEvtHandler
*)node
->Data();
437 handler
->ProcessPendingEvents();
441 node
= wxPendingEvents
->First();
444 #endif // wxUSE_THREADS
446 void wxApp::DeletePendingObjects()
448 wxNode
*node
= wxPendingDelete
.First();
451 wxObject
*obj
= (wxObject
*)node
->Data();
455 if (wxPendingDelete
.Find(obj
))
458 node
= wxPendingDelete
.First();
462 wxWindow
*wxApp::GetTopWindow()
466 else if (wxTopLevelWindows
.GetCount() > 0)
467 return wxTopLevelWindows
.GetFirst()->GetData();
472 void wxApp::SetTopWindow( wxWindow
*win
)
477 bool wxApp::Initialize()
479 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
481 wxClassInfo::InitializeClasses();
483 wxSystemSettings::Init();
485 // GL: I'm annoyed ... I don't know where to put this and I don't want to
486 // create a module for that as it's part of the core.
488 wxPendingEvents
= new wxList();
489 wxPendingEventsLocker
= new wxCriticalSection();
493 wxTheFontNameDirectory = new wxFontNameDirectory;
494 wxTheFontNameDirectory->Initialize();
497 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
498 wxTheColourDatabase
->Initialize();
500 wxInitializeStockLists();
501 wxInitializeStockObjects();
503 #if wxUSE_WX_RESOURCES
504 wxTheResourceCache
= new wxResourceCache( wxKEY_STRING
);
506 wxInitializeResourceSystem();
509 wxImage::InitStandardHandlers();
511 /* no global cursor under X
512 g_globalCursor = new wxCursor; */
514 wxModule::RegisterModules();
515 if (!wxModule::InitializeModules()) return FALSE
;
520 void wxApp::CleanUp()
522 wxModule::CleanUpModules();
524 #if wxUSE_WX_RESOURCES
527 if (wxTheResourceCache
)
528 delete wxTheResourceCache
;
529 wxTheResourceCache
= (wxResourceCache
*) NULL
;
531 wxCleanUpResourceSystem();
534 if (wxTheColourDatabase
)
535 delete wxTheColourDatabase
;
536 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
539 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
540 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
543 wxDeleteStockObjects();
545 wxDeleteStockLists();
547 wxImage::CleanUpHandlers();
550 wxTheApp
= (wxApp
*) NULL
;
552 // GL: I'm annoyed ... I don't know where to put this and I don't want to
553 // create a module for that as it's part of the core.
555 delete wxPendingEvents
;
556 delete wxPendingEventsLocker
;
559 wxSystemSettings::Done();
563 wxClassInfo::CleanUpClasses();
565 // check for memory leaks
566 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
567 if (wxDebugContext::CountObjectsLeft() > 0)
569 wxLogDebug(_T("There were memory leaks.\n"));
570 wxDebugContext::Dump();
571 wxDebugContext::PrintStatistics();
575 // do this as the very last thing because everything else can log messages
576 wxLog::DontCreateOnDemand();
578 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
583 wxLog
*wxApp::CreateLogTarget()
588 //-----------------------------------------------------------------------------
590 //-----------------------------------------------------------------------------
592 int wxEntry( int argc
, char *argv
[] )
596 gtk_init( &argc
, &argv
);
598 if (!wxApp::Initialize())
603 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
604 _T("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
606 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
608 wxObject
*test_app
= app_ini();
610 wxTheApp
= (wxApp
*) test_app
;
613 wxCHECK_MSG( wxTheApp
, -1, _T("wxWindows error: no application object") );
615 wxTheApp
->argc
= argc
;
616 wxTheApp
->argv
= argv
;
618 wxString
name(wxFileNameFromPath(argv
[0]));
619 wxStripExtension( name
);
620 wxTheApp
->SetAppName( name
);
624 if ( !wxTheApp
->OnInitGui() )
627 // Here frames insert themselves automatically into wxTopLevelWindows by
628 // getting created in OnInit().
631 if ( !wxTheApp
->OnInit() )
637 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
639 if (wxTheApp
->Initialized())
640 retValue
= wxTheApp
->OnRun();
642 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
645 // Forcibly delete the window.
646 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
647 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
649 topWindow
->Close( TRUE
);
650 wxTheApp
->DeletePendingObjects();
655 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
662 // flush the logged messages if any
663 wxLog
*log
= wxLog::GetActiveTarget();
664 if (log
!= NULL
&& log
->HasPendingMessages())
667 // continuing to use user defined log target is unsafe from now on because
668 // some resources may be already unavailable, so replace it by something
670 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);