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
;
50 extern wxResourceCache
*wxTheResourceCache
;
53 //-----------------------------------------------------------------------------
55 //-----------------------------------------------------------------------------
57 extern void wxFlushResources();
59 /* forward declaration */
60 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) );
61 void wxapp_install_idle_handler();
64 gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) );
67 //-----------------------------------------------------------------------------
69 //-----------------------------------------------------------------------------
76 //-----------------------------------------------------------------------------
78 //-----------------------------------------------------------------------------
82 bool has_idle
= (wxTheApp
->m_idleTag
!= 0);
86 /* We need to temporarily remove idle callbacks or the loop will
88 gtk_idle_remove( wxTheApp
->m_idleTag
);
89 wxTheApp
->m_idleTag
= 0;
92 while (gtk_events_pending())
95 /* it's necessary to call ProcessIdle() to update the frames sizes which
96 might have been changed (it also will update other things set from
97 OnUpdateUI() which is a nice (and desired) side effect) */
98 while (wxTheApp
->ProcessIdle()) { }
102 /* re-add idle handler */
103 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
109 //-----------------------------------------------------------------------------
111 //-----------------------------------------------------------------------------
116 wxapp_install_idle_handler();
119 //-----------------------------------------------------------------------------
121 //-----------------------------------------------------------------------------
123 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
125 if (!wxTheApp
) return TRUE
;
127 #if (GTK_MINOR_VERSION > 0)
128 /* when getting called from GDK's idle handler we
129 are no longer within GDK's grab on the GUI
130 thread so we must lock it here ourselves */
131 GDK_THREADS_ENTER ();
134 /* sent idle event to all who request them */
135 while (wxTheApp
->ProcessIdle()) { }
137 /* we don't want any more idle events until the next event is
139 gtk_idle_remove( wxTheApp
->m_idleTag
);
140 wxTheApp
->m_idleTag
= 0;
142 /* indicate that we are now in idle mode - even so deeply
143 in idle mode that we don't get any idle events anymore.
144 this is like wxMSW where an idle event is sent only
145 once each time after the event queue has been completely
149 #if (GTK_MINOR_VERSION > 0)
150 /* release lock again */
151 GDK_THREADS_LEAVE ();
157 void wxapp_install_idle_handler()
159 wxASSERT_MSG( wxTheApp
->m_idleTag
== 0, wxT("attempt to install idle handler twice") );
161 /* This routine gets called by all event handlers
162 indicating that the idle is over. It may also
163 get called from other thread for sending events
164 to the main thread (and processing these in
168 if (!wxThread::IsMain())
169 GDK_THREADS_ENTER ();
172 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
177 if (!wxThread::IsMain())
178 GDK_THREADS_LEAVE ();
184 void wxapp_install_thread_wakeup()
186 if (wxTheApp
->m_wakeUpTimerTag
) return;
188 wxTheApp
->m_wakeUpTimerTag
= gtk_timeout_add( 100, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
191 void wxapp_uninstall_thread_wakeup()
193 if (!wxTheApp
->m_wakeUpTimerTag
) return;
195 gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag
);
196 wxTheApp
->m_wakeUpTimerTag
= 0;
199 gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) )
201 wxapp_uninstall_thread_wakeup();
203 #if (GTK_MINOR_VERSION > 0)
204 // when getting called from GDK's time-out handler
205 // we are no longer within GDK's grab on the GUI
206 // thread so we must lock it here ourselves
207 GDK_THREADS_ENTER ();
210 // unblock other threads wishing to do some GUI things
213 // wake up other threads
216 // block other thread again
219 #if (GTK_MINOR_VERSION > 0)
220 // release lock again
221 GDK_THREADS_LEAVE ();
224 wxapp_install_thread_wakeup();
229 #endif // wxUSE_THREADS
231 //-----------------------------------------------------------------------------
233 //-----------------------------------------------------------------------------
235 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
237 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
238 EVT_IDLE(wxApp::OnIdle
)
245 m_topWindow
= (wxWindow
*) NULL
;
246 m_exitOnFrameDelete
= TRUE
;
248 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
251 m_wakeUpTimerTag
= 0;
252 wxapp_install_thread_wakeup();
255 m_colorCube
= (unsigned char*) NULL
;
260 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
263 wxapp_uninstall_thread_wakeup();
266 if (m_colorCube
) free(m_colorCube
);
269 bool wxApp::OnInitGui()
271 GdkVisual
*visual
= gdk_visual_get_system();
273 /* on some machines, the default visual is just 256 colours, so
274 we make sure we get the best. this can sometimes be wasteful,
275 of course, but what do these guys pay $30.000 for? */
277 if (gdk_visual_get_best() != gdk_visual_get_system())
279 GdkVisual* vis = gdk_visual_get_best();
280 gtk_widget_set_default_visual( vis );
282 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
283 gtk_widget_set_default_colormap( colormap );
289 /* Nothing to do for 15, 16, 24, 32 bit displays */
290 if (visual
->depth
> 8) return TRUE
;
292 /* initialize color cube for 8-bit color reduction dithering */
294 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
296 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
298 for (int r
= 0; r
< 32; r
++)
300 for (int g
= 0; g
< 32; g
++)
302 for (int b
= 0; b
< 32; b
++)
304 int rr
= (r
<< 3) | (r
>> 2);
305 int gg
= (g
<< 3) | (g
>> 2);
306 int bb
= (b
<< 3) | (b
>> 2);
310 GdkColor
*colors
= cmap
->colors
;
315 for (int i
= 0; i
< cmap
->size
; i
++)
317 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
318 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
319 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
320 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
323 index
= i
; max
= sum
;
329 #if (GTK_MINOR_VERSION > 0)
330 /* assume 8-bit true or static colors. this really
332 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
333 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
334 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
335 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
337 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
340 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
348 bool wxApp::ProcessIdle()
351 event
.SetEventObject( this );
352 ProcessEvent( event
);
354 return event
.MoreRequested();
357 void wxApp::OnIdle( wxIdleEvent
&event
)
359 static bool s_inOnIdle
= FALSE
;
361 /* Avoid recursion (via ProcessEvent default case) */
367 /* Resend in the main thread events which have been prepared in other
369 ProcessPendingEvents();
371 /* 'Garbage' collection of windows deleted with Close(). */
372 DeletePendingObjects();
374 /* flush the logged messages if any */
376 wxLog
*log
= wxLog::GetActiveTarget();
377 if (log
!= NULL
&& log
->HasPendingMessages())
381 /* Send OnIdle events to all windows */
382 bool needMore
= SendIdleEvents();
385 event
.RequestMore(TRUE
);
390 bool wxApp::SendIdleEvents()
392 bool needMore
= FALSE
;
394 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
397 wxWindow
* win
= node
->GetData();
398 if (SendIdleEvents(win
))
400 node
= node
->GetNext();
406 bool wxApp::SendIdleEvents( wxWindow
* win
)
408 bool needMore
= FALSE
;
411 event
.SetEventObject(win
);
413 win
->ProcessEvent(event
);
415 win
->OnInternalIdle();
417 if (event
.MoreRequested())
420 wxNode
* node
= win
->GetChildren().First();
423 wxWindow
* win
= (wxWindow
*) node
->Data();
424 if (SendIdleEvents(win
))
432 int wxApp::MainLoop()
438 void wxApp::ExitMainLoop()
440 if (gtk_main_level() > 0)
444 bool wxApp::Initialized()
446 return m_initialized
;
449 bool wxApp::Pending()
451 return (gtk_events_pending() > 0);
454 void wxApp::Dispatch()
456 gtk_main_iteration();
459 void wxApp::DeletePendingObjects()
461 wxNode
*node
= wxPendingDelete
.First();
464 wxObject
*obj
= (wxObject
*)node
->Data();
468 if (wxPendingDelete
.Find(obj
))
471 node
= wxPendingDelete
.First();
475 bool wxApp::Initialize()
477 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
479 wxClassInfo::InitializeClasses();
481 wxSystemSettings::Init();
483 // GL: I'm annoyed ... I don't know where to put this and I don't want to
484 // create a module for that as it's part of the core.
486 wxPendingEvents
= new wxList();
487 wxPendingEventsLocker
= new wxCriticalSection();
491 wxTheFontNameDirectory = new wxFontNameDirectory;
492 wxTheFontNameDirectory->Initialize();
495 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
496 wxTheColourDatabase
->Initialize();
498 wxInitializeStockLists();
499 wxInitializeStockObjects();
501 #if wxUSE_WX_RESOURCES
502 wxTheResourceCache
= new wxResourceCache( wxKEY_STRING
);
504 wxInitializeResourceSystem();
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();
541 wxTheApp
= (wxApp
*) NULL
;
543 // GL: I'm annoyed ... I don't know where to put this and I don't want to
544 // create a module for that as it's part of the core.
546 delete wxPendingEvents
;
547 delete wxPendingEventsLocker
;
550 wxSystemSettings::Done();
554 wxClassInfo::CleanUpClasses();
556 // check for memory leaks
557 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
558 if (wxDebugContext::CountObjectsLeft() > 0)
560 wxLogDebug(wxT("There were memory leaks.\n"));
561 wxDebugContext::Dump();
562 wxDebugContext::PrintStatistics();
567 // do this as the very last thing because everything else can log messages
568 wxLog::DontCreateOnDemand();
570 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
576 //-----------------------------------------------------------------------------
578 //-----------------------------------------------------------------------------
580 int wxEntry( int argc
, char *argv
[] )
585 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
587 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
590 gtk_init( &argc
, &argv
);
592 wxSetDetectableAutoRepeat( TRUE
);
594 if (!wxApp::Initialize())
599 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
600 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
602 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
604 wxObject
*test_app
= app_ini();
606 wxTheApp
= (wxApp
*) test_app
;
609 wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") );
611 wxTheApp
->argc
= argc
;
613 wxTheApp
->argv
= new wxChar
*[argc
+1];
615 while (mb_argc
< argc
) {
616 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
619 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
621 wxTheApp
->argv
= argv
;
624 wxString
name(wxFileNameFromPath(argv
[0]));
625 wxStripExtension( name
);
626 wxTheApp
->SetAppName( name
);
630 if ( !wxTheApp
->OnInitGui() )
633 // Here frames insert themselves automatically into wxTopLevelWindows by
634 // getting created in OnInit().
637 if ( !wxTheApp
->OnInit() )
643 /* delete pending toplevel windows (typically a single
644 dialog) so that, if there isn't any left, we don't
646 wxTheApp
->DeletePendingObjects();
648 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
650 if (wxTheApp
->Initialized())
652 retValue
= wxTheApp
->OnRun();
654 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
657 /* Forcibly delete the window. */
658 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
659 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
661 topWindow
->Close( TRUE
);
662 wxTheApp
->DeletePendingObjects();
667 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
675 // flush the logged messages if any
676 wxLog
*log
= wxLog::GetActiveTarget();
677 if (log
!= NULL
&& log
->HasPendingMessages())
680 // continuing to use user defined log target is unsafe from now on because
681 // some resources may be already unavailable, so replace it by something
683 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
);