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
;
48 extern wxList wxPendingDelete
;
50 extern wxList
*wxPendingEvents
;
51 extern wxCriticalSection
*wxPendingEventsLocker
;
53 extern wxResourceCache
*wxTheResourceCache
;
56 unsigned char g_palette
[64*3] =
124 //-----------------------------------------------------------------------------
126 //-----------------------------------------------------------------------------
128 extern void wxFlushResources(void);
130 //-----------------------------------------------------------------------------
132 //-----------------------------------------------------------------------------
139 /* forward declaration */
140 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) );
144 // it's necessary to call ProcessIdle() to update the frames sizes which
145 // might have been changed (it also will update other things set from
146 // OnUpdateUI() which is a nice (and desired) side effect)
147 for ( wxWindowList::Node
*node
= wxTopLevelWindows
.GetFirst();
149 node
= node
->GetNext() )
151 wxWindow
*win
= node
->GetData();
152 win
->OnInternalIdle();
155 if (wxTheApp
->m_idleTag
)
157 /* We need to temporarily remove idle callbacks or the loop will
159 gtk_idle_remove( wxTheApp
->m_idleTag
);
160 wxTheApp
->m_idleTag
= 0;
162 while (gtk_events_pending())
163 gtk_main_iteration();
165 /* re-add idle handler */
166 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
170 while (gtk_events_pending())
171 gtk_main_iteration();
177 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
179 if (!wxTheApp
) return TRUE
;
181 /* sent idle event to all who request them */
182 while (wxTheApp
->ProcessIdle()) { }
184 /* we don't want any more idle events until the next event is
186 gtk_idle_remove( wxTheApp
->m_idleTag
);
187 wxTheApp
->m_idleTag
= 0;
189 /* indicate that we are now in idle mode - even so deeply
190 in idle mode that we don't get any idle events anymore.
191 this is like wxMSW where an idle event is sent only
192 once each time after the event queue has been completely
196 /* wxMutexGuiLeave();
198 wxMutexGuiEnter(); */
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);
289 GdkColor
*colors
= cmap
->colors
;
293 for (int i
= 0; i
< cmap
->size
; i
++)
295 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
296 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
297 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
298 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
299 if (sum
< max
) { index
= i
; max
= sum
; }
302 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
310 bool wxApp::ProcessIdle()
313 event
.SetEventObject( this );
314 ProcessEvent( event
);
316 return event
.MoreRequested();
319 void wxApp::OnIdle( wxIdleEvent
&event
)
321 static bool inOnIdle
= FALSE
;
323 /* Avoid recursion (via ProcessEvent default case) */
330 /* Resend in the main thread events which have been prepared in other
332 ProcessPendingEvents();
335 /* 'Garbage' collection of windows deleted with Close(). */
336 DeletePendingObjects();
338 /* flush the logged messages if any */
339 wxLog
*log
= wxLog::GetActiveTarget();
340 if (log
!= NULL
&& log
->HasPendingMessages())
343 /* Send OnIdle events to all windows */
344 bool needMore
= SendIdleEvents();
347 event
.RequestMore(TRUE
);
352 bool wxApp::SendIdleEvents()
354 bool needMore
= FALSE
;
356 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
359 wxWindow
* win
= node
->GetData();
360 if (SendIdleEvents(win
))
362 node
= node
->GetNext();
368 bool wxApp::SendIdleEvents( wxWindow
* win
)
370 bool needMore
= FALSE
;
373 event
.SetEventObject(win
);
375 win
->OnInternalIdle();
377 win
->ProcessEvent(event
);
379 if (event
.MoreRequested())
382 wxNode
* node
= win
->GetChildren().First();
385 wxWindow
* win
= (wxWindow
*) node
->Data();
386 if (SendIdleEvents(win
))
394 int wxApp::MainLoop()
400 void wxApp::ExitMainLoop()
405 bool wxApp::Initialized()
407 return m_initialized
;
410 bool wxApp::Pending()
412 return (gtk_events_pending() > 0);
415 void wxApp::Dispatch()
417 gtk_main_iteration();
421 void wxApp::ProcessPendingEvents()
423 wxNode
*node
= wxPendingEvents
->First();
424 wxCriticalSectionLocker
locker(*wxPendingEventsLocker
);
428 wxEvtHandler
*handler
= (wxEvtHandler
*)node
->Data();
430 handler
->ProcessPendingEvents();
434 node
= wxPendingEvents
->First();
437 #endif // wxUSE_THREADS
439 void wxApp::DeletePendingObjects()
441 wxNode
*node
= wxPendingDelete
.First();
444 wxObject
*obj
= (wxObject
*)node
->Data();
448 if (wxPendingDelete
.Member(obj
))
451 node
= wxPendingDelete
.First();
455 wxWindow
*wxApp::GetTopWindow()
459 else if (wxTopLevelWindows
.GetCount() > 0)
460 return wxTopLevelWindows
.GetFirst()->GetData();
465 void wxApp::SetTopWindow( wxWindow
*win
)
470 bool wxApp::Initialize()
472 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
474 wxClassInfo::InitializeClasses();
476 wxSystemSettings::Init();
478 // GL: I'm annoyed ... I don't know where to put this and I don't want to
479 // create a module for that as it's part of the core.
481 wxPendingEvents
= new wxList();
482 wxPendingEventsLocker
= new wxCriticalSection();
486 wxTheFontNameDirectory = new wxFontNameDirectory;
487 wxTheFontNameDirectory->Initialize();
490 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
491 wxTheColourDatabase
->Initialize();
493 wxInitializeStockLists();
494 wxInitializeStockObjects();
496 #if wxUSE_WX_RESOURCES
497 wxTheResourceCache
= new wxResourceCache( wxKEY_STRING
);
499 wxInitializeResourceSystem();
502 wxImage::InitStandardHandlers();
504 /* no global cursor under X
505 g_globalCursor = new wxCursor; */
507 wxModule::RegisterModules();
508 if (!wxModule::InitializeModules()) return FALSE
;
513 void wxApp::CleanUp()
515 wxModule::CleanUpModules();
517 #if wxUSE_WX_RESOURCES
520 if (wxTheResourceCache
)
521 delete wxTheResourceCache
;
522 wxTheResourceCache
= (wxResourceCache
*) NULL
;
524 wxCleanUpResourceSystem();
527 if (wxTheColourDatabase
)
528 delete wxTheColourDatabase
;
529 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
532 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
533 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
536 wxDeleteStockObjects();
538 wxDeleteStockLists();
540 wxImage::CleanUpHandlers();
543 wxTheApp
= (wxApp
*) NULL
;
545 // GL: I'm annoyed ... I don't know where to put this and I don't want to
546 // create a module for that as it's part of the core.
548 delete wxPendingEvents
;
549 delete wxPendingEventsLocker
;
552 wxSystemSettings::Done();
556 wxClassInfo::CleanUpClasses();
558 // check for memory leaks
559 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
560 if (wxDebugContext::CountObjectsLeft() > 0)
562 wxLogDebug(_T("There were memory leaks.\n"));
563 wxDebugContext::Dump();
564 wxDebugContext::PrintStatistics();
568 // do this as the very last thing because everything else can log messages
569 wxLog::DontCreateOnDemand();
571 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
576 wxLog
*wxApp::CreateLogTarget()
581 //-----------------------------------------------------------------------------
583 //-----------------------------------------------------------------------------
585 int wxEntry( int argc
, char *argv
[] )
589 gtk_init( &argc
, &argv
);
591 if (!wxApp::Initialize())
596 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
597 _T("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
599 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
601 wxObject
*test_app
= app_ini();
603 wxTheApp
= (wxApp
*) test_app
;
606 wxCHECK_MSG( wxTheApp
, -1, _T("wxWindows error: no application object") );
608 wxTheApp
->argc
= argc
;
609 wxTheApp
->argv
= argv
;
611 wxString
name(wxFileNameFromPath(argv
[0]));
612 wxStripExtension( name
);
613 wxTheApp
->SetAppName( name
);
617 if ( !wxTheApp
->OnInitGui() )
620 // Here frames insert themselves automatically into wxTopLevelWindows by
621 // getting created in OnInit().
624 if ( !wxTheApp
->OnInit() )
630 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
632 if (wxTheApp
->Initialized())
633 retValue
= wxTheApp
->OnRun();
635 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
638 // Forcibly delete the window.
639 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
640 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
642 topWindow
->Close( TRUE
);
643 wxTheApp
->DeletePendingObjects();
648 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
655 // flush the logged messages if any
656 wxLog
*log
= wxLog::GetActiveTarget();
657 if (log
!= NULL
&& log
->HasPendingMessages())
660 // continuing to use user defined log target is unsafe from now on because
661 // some resources may be already unavailable, so replace it by something
663 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);