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"
32 #include "wx/thread.h"
41 #include "wx/gtk/win_gtk.h"
43 //-----------------------------------------------------------------------------
45 //-----------------------------------------------------------------------------
47 wxApp
*wxTheApp
= (wxApp
*) NULL
;
48 wxAppInitializerFunction
wxAppBase::m_appInitFn
= (wxAppInitializerFunction
) NULL
;
52 bool g_mainThreadLocked
= FALSE
;
54 //-----------------------------------------------------------------------------
56 //-----------------------------------------------------------------------------
58 /* forward declaration */
59 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) );
60 void wxapp_install_idle_handler();
63 gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) );
66 //-----------------------------------------------------------------------------
68 //-----------------------------------------------------------------------------
75 //-----------------------------------------------------------------------------
77 //-----------------------------------------------------------------------------
81 bool has_idle
= (wxTheApp
->m_idleTag
!= 0);
85 /* We need to temporarily remove idle callbacks or the loop will
87 gtk_idle_remove( wxTheApp
->m_idleTag
);
88 wxTheApp
->m_idleTag
= 0;
91 while (gtk_events_pending())
94 /* it's necessary to call ProcessIdle() to update the frames sizes which
95 might have been changed (it also will update other things set from
96 OnUpdateUI() which is a nice (and desired) side effect) */
97 while (wxTheApp
->ProcessIdle()) { }
101 /* re-add idle handler */
102 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
108 //-----------------------------------------------------------------------------
110 //-----------------------------------------------------------------------------
115 if (!wxThread::IsMain())
120 wxapp_install_idle_handler();
123 if (!wxThread::IsMain())
128 //-----------------------------------------------------------------------------
130 //-----------------------------------------------------------------------------
132 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
134 if (!wxTheApp
) return TRUE
;
136 // when getting called from GDK's time-out handler
137 // we are no longer within GDK's grab on the GUI
138 // thread so we must lock it here ourselves
141 /* we don't want any more idle events until the next event is
143 gtk_idle_remove( wxTheApp
->m_idleTag
);
144 wxTheApp
->m_idleTag
= 0;
146 /* indicate that we are now in idle mode - even so deeply
147 in idle mode that we don't get any idle events anymore.
148 this is like wxMSW where an idle event is sent only
149 once each time after the event queue has been completely
153 /* sent idle event to all who request them */
154 while (wxTheApp
->ProcessIdle()) { }
156 // release lock again
162 void wxapp_install_idle_handler()
164 wxASSERT_MSG( wxTheApp
->m_idleTag
== 0, wxT("attempt to install idle handler twice") );
166 /* This routine gets called by all event handlers
167 indicating that the idle is over. It may also
168 get called from other thread for sending events
169 to the main thread (and processing these in
172 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
179 void wxapp_install_thread_wakeup()
181 if (wxTheApp
->m_wakeUpTimerTag
) return;
183 wxTheApp
->m_wakeUpTimerTag
= gtk_timeout_add( 50, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
186 void wxapp_uninstall_thread_wakeup()
188 if (!wxTheApp
->m_wakeUpTimerTag
) return;
190 gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag
);
191 wxTheApp
->m_wakeUpTimerTag
= 0;
194 gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) )
196 // when getting called from GDK's time-out handler
197 // we are no longer within GDK's grab on the GUI
198 // thread so we must lock it here ourselves
201 wxapp_uninstall_thread_wakeup();
203 // unblock other threads wishing to do some GUI things
206 g_mainThreadLocked
= TRUE
;
208 // wake up other threads
211 // block other thread again
214 g_mainThreadLocked
= FALSE
;
216 wxapp_install_thread_wakeup();
218 // release lock again
224 #endif // wxUSE_THREADS
226 //-----------------------------------------------------------------------------
228 //-----------------------------------------------------------------------------
230 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
232 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
233 EVT_IDLE(wxApp::OnIdle
)
240 m_topWindow
= (wxWindow
*) NULL
;
241 m_exitOnFrameDelete
= TRUE
;
243 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
246 m_wakeUpTimerTag
= 0;
247 wxapp_install_thread_wakeup();
250 m_colorCube
= (unsigned char*) NULL
;
255 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
258 wxapp_uninstall_thread_wakeup();
261 if (m_colorCube
) free(m_colorCube
);
264 bool wxApp::OnInitGui()
266 GdkVisual
*visual
= gdk_visual_get_system();
268 /* on some machines, the default visual is just 256 colours, so
269 we make sure we get the best. this can sometimes be wasteful,
270 of course, but what do these guys pay $30.000 for? */
272 if (gdk_visual_get_best() != gdk_visual_get_system())
274 GdkVisual* vis = gdk_visual_get_best();
275 gtk_widget_set_default_visual( vis );
277 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
278 gtk_widget_set_default_colormap( colormap );
284 /* Nothing to do for 15, 16, 24, 32 bit displays */
285 if (visual
->depth
> 8) return TRUE
;
287 /* initialize color cube for 8-bit color reduction dithering */
289 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
291 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
293 for (int r
= 0; r
< 32; r
++)
295 for (int g
= 0; g
< 32; g
++)
297 for (int b
= 0; b
< 32; b
++)
299 int rr
= (r
<< 3) | (r
>> 2);
300 int gg
= (g
<< 3) | (g
>> 2);
301 int bb
= (b
<< 3) | (b
>> 2);
305 GdkColor
*colors
= cmap
->colors
;
310 for (int i
= 0; i
< cmap
->size
; i
++)
312 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
313 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
314 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
315 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
318 index
= i
; max
= sum
;
324 #if (GTK_MINOR_VERSION > 0)
325 /* assume 8-bit true or static colors. this really
327 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
328 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
329 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
330 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
332 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
335 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
343 bool wxApp::ProcessIdle()
346 event
.SetEventObject( this );
347 ProcessEvent( event
);
349 return event
.MoreRequested();
352 void wxApp::OnIdle( wxIdleEvent
&event
)
354 static bool s_inOnIdle
= FALSE
;
356 /* Avoid recursion (via ProcessEvent default case) */
362 /* Resend in the main thread events which have been prepared in other
364 ProcessPendingEvents();
366 /* 'Garbage' collection of windows deleted with Close(). */
367 DeletePendingObjects();
369 /* Send OnIdle events to all windows */
370 bool needMore
= SendIdleEvents();
373 event
.RequestMore(TRUE
);
377 /* flush the logged messages if any */
379 wxLog
*log
= wxLog::GetActiveTarget();
380 if (log
!= NULL
&& log
->HasPendingMessages())
385 bool wxApp::SendIdleEvents()
387 bool needMore
= FALSE
;
389 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
392 wxWindow
* win
= node
->GetData();
393 if (SendIdleEvents(win
))
395 node
= node
->GetNext();
401 bool wxApp::SendIdleEvents( wxWindow
* win
)
403 bool needMore
= FALSE
;
406 event
.SetEventObject(win
);
408 win
->ProcessEvent(event
);
410 win
->OnInternalIdle();
412 if (event
.MoreRequested())
415 wxNode
* node
= win
->GetChildren().First();
418 wxWindow
* win
= (wxWindow
*) node
->Data();
419 if (SendIdleEvents(win
))
427 int wxApp::MainLoop()
433 void wxApp::ExitMainLoop()
435 if (gtk_main_level() > 0)
439 bool wxApp::Initialized()
441 return m_initialized
;
444 bool wxApp::Pending()
446 return (gtk_events_pending() > 0);
449 void wxApp::Dispatch()
451 gtk_main_iteration();
454 void wxApp::DeletePendingObjects()
456 wxNode
*node
= wxPendingDelete
.First();
459 wxObject
*obj
= (wxObject
*)node
->Data();
463 if (wxPendingDelete
.Find(obj
))
466 node
= wxPendingDelete
.First();
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();
485 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
486 wxTheColourDatabase
->Initialize();
488 wxInitializeStockLists();
489 wxInitializeStockObjects();
491 #if wxUSE_WX_RESOURCES
492 wxInitializeResourceSystem();
495 wxModule::RegisterModules();
496 if (!wxModule::InitializeModules()) return FALSE
;
501 void wxApp::CleanUp()
503 wxModule::CleanUpModules();
505 #if wxUSE_WX_RESOURCES
506 wxCleanUpResourceSystem();
509 if (wxTheColourDatabase
)
510 delete wxTheColourDatabase
;
512 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
514 wxDeleteStockObjects();
516 wxDeleteStockLists();
519 wxTheApp
= (wxApp
*) NULL
;
521 // GL: I'm annoyed ... I don't know where to put this and I don't want to
522 // create a module for that as it's part of the core.
524 delete wxPendingEvents
;
525 delete wxPendingEventsLocker
;
528 wxSystemSettings::Done();
532 wxClassInfo::CleanUpClasses();
534 // check for memory leaks
535 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
536 if (wxDebugContext::CountObjectsLeft() > 0)
538 wxLogDebug(wxT("There were memory leaks.\n"));
539 wxDebugContext::Dump();
540 wxDebugContext::PrintStatistics();
545 // do this as the very last thing because everything else can log messages
546 wxLog::DontCreateOnDemand();
548 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
554 //-----------------------------------------------------------------------------
556 //-----------------------------------------------------------------------------
558 int wxEntry( int argc
, char *argv
[] )
561 /* GTK 1.2 up to version 1.2.3 has broken threads */
562 if ((gtk_major_version
== 1) &&
563 (gtk_minor_version
== 2) &&
564 (gtk_micro_version
< 4))
566 printf( "wxWindows warning: Disabled GUI threading due to outdated GTK version\n" );
577 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
579 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
584 gtk_init( &argc
, &argv
);
586 wxSetDetectableAutoRepeat( TRUE
);
588 if (!wxApp::Initialize())
596 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
597 wxT("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, wxT("wxWindows error: no application object") );
608 wxTheApp
->argc
= argc
;
610 wxTheApp
->argv
= new wxChar
*[argc
+1];
612 while (mb_argc
< argc
)
614 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
617 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
619 wxTheApp
->argv
= argv
;
622 wxString
name(wxFileNameFromPath(argv
[0]));
623 wxStripExtension( name
);
624 wxTheApp
->SetAppName( name
);
628 if ( !wxTheApp
->OnInitGui() )
631 // Here frames insert themselves automatically into wxTopLevelWindows by
632 // getting created in OnInit().
635 if ( !wxTheApp
->OnInit() )
641 /* delete pending toplevel windows (typically a single
642 dialog) so that, if there isn't any left, we don't
644 wxTheApp
->DeletePendingObjects();
646 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
648 if (wxTheApp
->Initialized())
650 retValue
= wxTheApp
->OnRun();
652 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
655 /* Forcibly delete the window. */
656 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
657 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
659 topWindow
->Close( TRUE
);
660 wxTheApp
->DeletePendingObjects();
665 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
673 // flush the logged messages if any
674 wxLog
*log
= wxLog::GetActiveTarget();
675 if (log
!= NULL
&& log
->HasPendingMessages())
678 // continuing to use user defined log target is unsafe from now on because
679 // some resources may be already unavailable, so replace it by something
681 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);
693 #include "wx/gtk/info.xpm"
694 #include "wx/gtk/error.xpm"
695 #include "wx/gtk/question.xpm"
696 #include "wx/gtk/warning.xpm"
699 wxApp::GetStdIcon(int which
) const
703 case wxICON_INFORMATION
:
704 return wxIcon(info_xpm
);
706 case wxICON_QUESTION
:
707 return wxIcon(question_xpm
);
709 case wxICON_EXCLAMATION
:
710 return wxIcon(warning_xpm
);
713 wxFAIL_MSG(wxT("requested non existent standard icon"));
714 // still fall through
717 return wxIcon(error_xpm
);