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 */
204 void wxapp_install_idle_handler()
206 /* this routine gets called by all event handlers
207 indicating that the idle is over. */
209 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
214 //-----------------------------------------------------------------------------
216 //-----------------------------------------------------------------------------
218 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
220 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
221 EVT_IDLE(wxApp::OnIdle
)
228 m_topWindow
= (wxWindow
*) NULL
;
229 m_exitOnFrameDelete
= TRUE
;
231 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
233 m_colorCube
= (unsigned char*) NULL
;
238 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
240 if (m_colorCube
) free(m_colorCube
);
243 bool wxApp::OnInitGui()
245 /* Nothing to do for 15, 16, 24, 32 bit displays */
247 GdkVisual
*visual
= gdk_visual_get_system();
248 if (visual
->depth
> 8) return TRUE
;
250 /* this initiates the standard palette as defined by GdkImlib
251 in the GNOME libraries. it ensures that all GNOME applications
252 use the same 64 colormap entries on 8-bit displays so you
253 can use several rather graphics-heavy applications at the
255 NOTE: this doesn't really seem to work this way... */
258 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
260 for (int i = 0; i < 64; i++)
263 col.red = g_palette[i*3 + 0] << 8;
264 col.green = g_palette[i*3 + 1] << 8;
265 col.blue = g_palette[i*3 + 2] << 8;
268 gdk_color_alloc( cmap, &col );
271 gtk_widget_set_default_colormap( cmap );
274 /* initialize color cube for 8-bit color reduction dithering */
276 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
278 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
280 for (int r
= 0; r
< 32; r
++)
282 for (int g
= 0; g
< 32; g
++)
284 for (int b
= 0; b
< 32; b
++)
286 int rr
= (r
<< 3) | (r
>> 2);
287 int gg
= (g
<< 3) | (g
>> 2);
288 int bb
= (b
<< 3) | (b
>> 2);
292 GdkColor
*colors
= cmap
->colors
;
297 for (int i
= 0; i
< cmap
->size
; i
++)
299 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
300 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
301 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
302 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
305 index
= i
; max
= sum
;
310 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
318 bool wxApp::ProcessIdle()
321 event
.SetEventObject( this );
322 ProcessEvent( event
);
324 return event
.MoreRequested();
327 void wxApp::OnIdle( wxIdleEvent
&event
)
329 static bool inOnIdle
= FALSE
;
331 /* Avoid recursion (via ProcessEvent default case) */
338 /* Resend in the main thread events which have been prepared in other
340 ProcessPendingEvents();
343 /* 'Garbage' collection of windows deleted with Close(). */
344 DeletePendingObjects();
346 /* flush the logged messages if any */
347 wxLog
*log
= wxLog::GetActiveTarget();
348 if (log
!= NULL
&& log
->HasPendingMessages())
351 /* Send OnIdle events to all windows */
352 bool needMore
= SendIdleEvents();
355 event
.RequestMore(TRUE
);
360 bool wxApp::SendIdleEvents()
362 bool needMore
= FALSE
;
364 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
367 wxWindow
* win
= node
->GetData();
368 if (SendIdleEvents(win
))
370 node
= node
->GetNext();
376 bool wxApp::SendIdleEvents( wxWindow
* win
)
378 bool needMore
= FALSE
;
381 event
.SetEventObject(win
);
383 win
->OnInternalIdle();
385 win
->ProcessEvent(event
);
387 if (event
.MoreRequested())
390 wxNode
* node
= win
->GetChildren().First();
393 wxWindow
* win
= (wxWindow
*) node
->Data();
394 if (SendIdleEvents(win
))
402 int wxApp::MainLoop()
408 void wxApp::ExitMainLoop()
413 bool wxApp::Initialized()
415 return m_initialized
;
418 bool wxApp::Pending()
420 return (gtk_events_pending() > 0);
423 void wxApp::Dispatch()
425 gtk_main_iteration();
429 void wxApp::ProcessPendingEvents()
431 wxNode
*node
= wxPendingEvents
->First();
432 wxCriticalSectionLocker
locker(*wxPendingEventsLocker
);
436 wxEvtHandler
*handler
= (wxEvtHandler
*)node
->Data();
438 handler
->ProcessPendingEvents();
442 node
= wxPendingEvents
->First();
445 #endif // wxUSE_THREADS
447 void wxApp::DeletePendingObjects()
449 wxNode
*node
= wxPendingDelete
.First();
452 wxObject
*obj
= (wxObject
*)node
->Data();
456 if (wxPendingDelete
.Find(obj
))
459 node
= wxPendingDelete
.First();
463 wxWindow
*wxApp::GetTopWindow()
467 else if (wxTopLevelWindows
.GetCount() > 0)
468 return wxTopLevelWindows
.GetFirst()->GetData();
473 void wxApp::SetTopWindow( wxWindow
*win
)
478 bool wxApp::Initialize()
480 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
482 wxClassInfo::InitializeClasses();
484 wxSystemSettings::Init();
486 // GL: I'm annoyed ... I don't know where to put this and I don't want to
487 // create a module for that as it's part of the core.
489 wxPendingEvents
= new wxList();
490 wxPendingEventsLocker
= new wxCriticalSection();
494 wxTheFontNameDirectory = new wxFontNameDirectory;
495 wxTheFontNameDirectory->Initialize();
498 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
499 wxTheColourDatabase
->Initialize();
501 wxInitializeStockLists();
502 wxInitializeStockObjects();
504 #if wxUSE_WX_RESOURCES
505 wxTheResourceCache
= new wxResourceCache( wxKEY_STRING
);
507 wxInitializeResourceSystem();
510 wxImage::InitStandardHandlers();
512 /* no global cursor under X
513 g_globalCursor = new wxCursor; */
515 wxModule::RegisterModules();
516 if (!wxModule::InitializeModules()) return FALSE
;
521 void wxApp::CleanUp()
523 wxModule::CleanUpModules();
525 #if wxUSE_WX_RESOURCES
528 if (wxTheResourceCache
)
529 delete wxTheResourceCache
;
530 wxTheResourceCache
= (wxResourceCache
*) NULL
;
532 wxCleanUpResourceSystem();
535 if (wxTheColourDatabase
)
536 delete wxTheColourDatabase
;
537 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
540 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
541 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
544 wxDeleteStockObjects();
546 wxDeleteStockLists();
548 wxImage::CleanUpHandlers();
551 wxTheApp
= (wxApp
*) NULL
;
553 // GL: I'm annoyed ... I don't know where to put this and I don't want to
554 // create a module for that as it's part of the core.
556 delete wxPendingEvents
;
557 delete wxPendingEventsLocker
;
560 wxSystemSettings::Done();
564 wxClassInfo::CleanUpClasses();
566 // check for memory leaks
567 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
568 if (wxDebugContext::CountObjectsLeft() > 0)
570 wxLogDebug(_T("There were memory leaks.\n"));
571 wxDebugContext::Dump();
572 wxDebugContext::PrintStatistics();
576 // do this as the very last thing because everything else can log messages
577 wxLog::DontCreateOnDemand();
579 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
584 wxLog
*wxApp::CreateLogTarget()
589 //-----------------------------------------------------------------------------
591 //-----------------------------------------------------------------------------
593 int wxEntry( int argc
, char *argv
[] )
597 gtk_init( &argc
, &argv
);
599 wxSetDetectableAutoRepeat( TRUE
);
601 if (!wxApp::Initialize())
606 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
607 _T("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
609 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
611 wxObject
*test_app
= app_ini();
613 wxTheApp
= (wxApp
*) test_app
;
616 wxCHECK_MSG( wxTheApp
, -1, _T("wxWindows error: no application object") );
618 wxTheApp
->argc
= argc
;
619 wxTheApp
->argv
= argv
;
621 wxString
name(wxFileNameFromPath(argv
[0]));
622 wxStripExtension( name
);
623 wxTheApp
->SetAppName( name
);
627 if ( !wxTheApp
->OnInitGui() )
630 // Here frames insert themselves automatically into wxTopLevelWindows by
631 // getting created in OnInit().
634 if ( !wxTheApp
->OnInit() )
640 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
642 if (wxTheApp
->Initialized())
643 retValue
= wxTheApp
->OnRun();
645 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
648 // Forcibly delete the window.
649 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
650 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
652 topWindow
->Close( TRUE
);
653 wxTheApp
->DeletePendingObjects();
658 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
665 // flush the logged messages if any
666 wxLog
*log
= wxLog::GetActiveTarget();
667 if (log
!= NULL
&& log
->HasPendingMessages())
670 // continuing to use user defined log target is unsafe from now on because
671 // some resources may be already unavailable, so replace it by something
673 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);