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
);
246 //-----------------------------------------------------------------------------
248 //-----------------------------------------------------------------------------
250 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
252 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
253 EVT_IDLE(wxApp::OnIdle
)
260 m_topWindow
= (wxWindow
*) NULL
;
261 m_exitOnFrameDelete
= TRUE
;
263 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
265 m_wakeUpTimerTag
= gtk_timeout_add( 10, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
267 m_colorCube
= (unsigned char*) NULL
;
272 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
274 if (m_wakeUpTimerTag
) gtk_timeout_remove( m_wakeUpTimerTag
);
276 if (m_colorCube
) free(m_colorCube
);
279 bool wxApp::OnInitGui()
281 /* Nothing to do for 15, 16, 24, 32 bit displays */
283 GdkVisual
*visual
= gdk_visual_get_system();
284 if (visual
->depth
> 8) return TRUE
;
286 /* this initiates the standard palette as defined by GdkImlib
287 in the GNOME libraries. it ensures that all GNOME applications
288 use the same 64 colormap entries on 8-bit displays so you
289 can use several rather graphics-heavy applications at the
291 NOTE: this doesn't really seem to work this way... */
294 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
296 for (int i = 0; i < 64; i++)
299 col.red = g_palette[i*3 + 0] << 8;
300 col.green = g_palette[i*3 + 1] << 8;
301 col.blue = g_palette[i*3 + 2] << 8;
304 gdk_color_alloc( cmap, &col );
307 gtk_widget_set_default_colormap( cmap );
310 /* initialize color cube for 8-bit color reduction dithering */
312 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
314 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
316 for (int r
= 0; r
< 32; r
++)
318 for (int g
= 0; g
< 32; g
++)
320 for (int b
= 0; b
< 32; b
++)
322 int rr
= (r
<< 3) | (r
>> 2);
323 int gg
= (g
<< 3) | (g
>> 2);
324 int bb
= (b
<< 3) | (b
>> 2);
328 GdkColor
*colors
= cmap
->colors
;
333 for (int i
= 0; i
< cmap
->size
; i
++)
335 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
336 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
337 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
338 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
341 index
= i
; max
= sum
;
346 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
354 bool wxApp::ProcessIdle()
357 event
.SetEventObject( this );
358 ProcessEvent( event
);
360 return event
.MoreRequested();
363 void wxApp::OnIdle( wxIdleEvent
&event
)
365 static bool inOnIdle
= FALSE
;
367 /* Avoid recursion (via ProcessEvent default case) */
374 /* Resend in the main thread events which have been prepared in other
376 ProcessPendingEvents();
379 /* 'Garbage' collection of windows deleted with Close(). */
380 DeletePendingObjects();
382 /* flush the logged messages if any */
383 wxLog
*log
= wxLog::GetActiveTarget();
384 if (log
!= NULL
&& log
->HasPendingMessages())
387 /* Send OnIdle events to all windows */
388 bool needMore
= SendIdleEvents();
391 event
.RequestMore(TRUE
);
396 bool wxApp::SendIdleEvents()
398 bool needMore
= FALSE
;
400 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
403 wxWindow
* win
= node
->GetData();
404 if (SendIdleEvents(win
))
406 node
= node
->GetNext();
412 bool wxApp::SendIdleEvents( wxWindow
* win
)
414 bool needMore
= FALSE
;
417 event
.SetEventObject(win
);
419 win
->OnInternalIdle();
421 win
->ProcessEvent(event
);
423 if (event
.MoreRequested())
426 wxNode
* node
= win
->GetChildren().First();
429 wxWindow
* win
= (wxWindow
*) node
->Data();
430 if (SendIdleEvents(win
))
438 int wxApp::MainLoop()
444 void wxApp::ExitMainLoop()
449 bool wxApp::Initialized()
451 return m_initialized
;
454 bool wxApp::Pending()
456 return (gtk_events_pending() > 0);
459 void wxApp::Dispatch()
461 gtk_main_iteration();
465 void wxApp::ProcessPendingEvents()
467 wxNode
*node
= wxPendingEvents
->First();
468 wxCriticalSectionLocker
locker(*wxPendingEventsLocker
);
472 wxEvtHandler
*handler
= (wxEvtHandler
*)node
->Data();
474 handler
->ProcessPendingEvents();
478 node
= wxPendingEvents
->First();
481 #endif // wxUSE_THREADS
483 void wxApp::DeletePendingObjects()
485 wxNode
*node
= wxPendingDelete
.First();
488 wxObject
*obj
= (wxObject
*)node
->Data();
492 if (wxPendingDelete
.Find(obj
))
495 node
= wxPendingDelete
.First();
499 wxWindow
*wxApp::GetTopWindow()
503 else if (wxTopLevelWindows
.GetCount() > 0)
504 return wxTopLevelWindows
.GetFirst()->GetData();
509 void wxApp::SetTopWindow( wxWindow
*win
)
514 bool wxApp::Initialize()
516 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
518 wxClassInfo::InitializeClasses();
520 wxSystemSettings::Init();
522 // GL: I'm annoyed ... I don't know where to put this and I don't want to
523 // create a module for that as it's part of the core.
525 wxPendingEvents
= new wxList();
526 wxPendingEventsLocker
= new wxCriticalSection();
530 wxTheFontNameDirectory = new wxFontNameDirectory;
531 wxTheFontNameDirectory->Initialize();
534 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
535 wxTheColourDatabase
->Initialize();
537 wxInitializeStockLists();
538 wxInitializeStockObjects();
540 #if wxUSE_WX_RESOURCES
541 wxTheResourceCache
= new wxResourceCache( wxKEY_STRING
);
543 wxInitializeResourceSystem();
546 wxImage::InitStandardHandlers();
548 /* no global cursor under X
549 g_globalCursor = new wxCursor; */
551 wxModule::RegisterModules();
552 if (!wxModule::InitializeModules()) return FALSE
;
557 void wxApp::CleanUp()
559 wxModule::CleanUpModules();
561 #if wxUSE_WX_RESOURCES
564 if (wxTheResourceCache
)
565 delete wxTheResourceCache
;
566 wxTheResourceCache
= (wxResourceCache
*) NULL
;
568 wxCleanUpResourceSystem();
571 if (wxTheColourDatabase
)
572 delete wxTheColourDatabase
;
573 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
576 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
577 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
580 wxDeleteStockObjects();
582 wxDeleteStockLists();
584 wxImage::CleanUpHandlers();
587 wxTheApp
= (wxApp
*) NULL
;
589 // GL: I'm annoyed ... I don't know where to put this and I don't want to
590 // create a module for that as it's part of the core.
592 delete wxPendingEvents
;
593 delete wxPendingEventsLocker
;
596 wxSystemSettings::Done();
600 wxClassInfo::CleanUpClasses();
602 // check for memory leaks
603 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
604 if (wxDebugContext::CountObjectsLeft() > 0)
606 wxLogDebug(_T("There were memory leaks.\n"));
607 wxDebugContext::Dump();
608 wxDebugContext::PrintStatistics();
612 // do this as the very last thing because everything else can log messages
613 wxLog::DontCreateOnDemand();
615 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
620 wxLog
*wxApp::CreateLogTarget()
625 //-----------------------------------------------------------------------------
627 //-----------------------------------------------------------------------------
629 int wxEntry( int argc
, char *argv
[] )
633 gtk_init( &argc
, &argv
);
635 wxSetDetectableAutoRepeat( TRUE
);
637 if (!wxApp::Initialize())
642 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
643 _T("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
645 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
647 wxObject
*test_app
= app_ini();
649 wxTheApp
= (wxApp
*) test_app
;
652 wxCHECK_MSG( wxTheApp
, -1, _T("wxWindows error: no application object") );
654 wxTheApp
->argc
= argc
;
655 wxTheApp
->argv
= argv
;
657 wxString
name(wxFileNameFromPath(argv
[0]));
658 wxStripExtension( name
);
659 wxTheApp
->SetAppName( name
);
663 if ( !wxTheApp
->OnInitGui() )
666 // Here frames insert themselves automatically into wxTopLevelWindows by
667 // getting created in OnInit().
670 if ( !wxTheApp
->OnInit() )
676 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
678 if (wxTheApp
->Initialized())
679 retValue
= wxTheApp
->OnRun();
681 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
684 // Forcibly delete the window.
685 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
686 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
688 topWindow
->Close( TRUE
);
689 wxTheApp
->DeletePendingObjects();
694 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
701 // flush the logged messages if any
702 wxLog
*log
= wxLog::GetActiveTarget();
703 if (log
!= NULL
&& log
->HasPendingMessages())
706 // continuing to use user defined log target is unsafe from now on because
707 // some resources may be already unavailable, so replace it by something
709 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);