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 //-----------------------------------------------------------------------------
54 //-----------------------------------------------------------------------------
56 /* forward declaration */
57 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) );
58 void wxapp_install_idle_handler();
61 gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) );
64 //-----------------------------------------------------------------------------
66 //-----------------------------------------------------------------------------
73 //-----------------------------------------------------------------------------
75 //-----------------------------------------------------------------------------
79 bool has_idle
= (wxTheApp
->m_idleTag
!= 0);
83 /* We need to temporarily remove idle callbacks or the loop will
85 gtk_idle_remove( wxTheApp
->m_idleTag
);
86 wxTheApp
->m_idleTag
= 0;
89 while (gtk_events_pending())
92 /* it's necessary to call ProcessIdle() to update the frames sizes which
93 might have been changed (it also will update other things set from
94 OnUpdateUI() which is a nice (and desired) side effect) */
95 while (wxTheApp
->ProcessIdle()) { }
99 /* re-add idle handler */
100 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
106 //-----------------------------------------------------------------------------
108 //-----------------------------------------------------------------------------
113 wxapp_install_idle_handler();
116 //-----------------------------------------------------------------------------
118 //-----------------------------------------------------------------------------
120 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
122 if (!wxTheApp
) return TRUE
;
124 #if (GTK_MINOR_VERSION > 0)
125 /* when getting called from GDK's idle handler we
126 are no longer within GDK's grab on the GUI
127 thread so we must lock it here ourselves */
128 GDK_THREADS_ENTER ();
131 /* sent idle event to all who request them */
132 while (wxTheApp
->ProcessIdle()) { }
134 /* we don't want any more idle events until the next event is
136 gtk_idle_remove( wxTheApp
->m_idleTag
);
137 wxTheApp
->m_idleTag
= 0;
139 /* indicate that we are now in idle mode - even so deeply
140 in idle mode that we don't get any idle events anymore.
141 this is like wxMSW where an idle event is sent only
142 once each time after the event queue has been completely
146 #if (GTK_MINOR_VERSION > 0)
147 /* release lock again */
148 GDK_THREADS_LEAVE ();
154 void wxapp_install_idle_handler()
156 wxASSERT_MSG( wxTheApp
->m_idleTag
== 0, wxT("attempt to install idle handler twice") );
158 /* This routine gets called by all event handlers
159 indicating that the idle is over. It may also
160 get called from other thread for sending events
161 to the main thread (and processing these in
165 if (!wxThread::IsMain())
166 GDK_THREADS_ENTER ();
169 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
174 if (!wxThread::IsMain())
175 GDK_THREADS_LEAVE ();
181 void wxapp_install_thread_wakeup()
183 if (wxTheApp
->m_wakeUpTimerTag
) return;
185 wxTheApp
->m_wakeUpTimerTag
= gtk_timeout_add( 100, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
188 void wxapp_uninstall_thread_wakeup()
190 if (!wxTheApp
->m_wakeUpTimerTag
) return;
192 gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag
);
193 wxTheApp
->m_wakeUpTimerTag
= 0;
196 gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) )
198 wxapp_uninstall_thread_wakeup();
200 #if (GTK_MINOR_VERSION > 0)
201 // when getting called from GDK's time-out handler
202 // we are no longer within GDK's grab on the GUI
203 // thread so we must lock it here ourselves
204 GDK_THREADS_ENTER ();
207 // unblock other threads wishing to do some GUI things
210 // wake up other threads
213 // block other thread again
216 #if (GTK_MINOR_VERSION > 0)
217 // release lock again
218 GDK_THREADS_LEAVE ();
221 wxapp_install_thread_wakeup();
226 #endif // wxUSE_THREADS
228 //-----------------------------------------------------------------------------
230 //-----------------------------------------------------------------------------
232 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
234 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
235 EVT_IDLE(wxApp::OnIdle
)
242 m_topWindow
= (wxWindow
*) NULL
;
243 m_exitOnFrameDelete
= TRUE
;
245 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
248 m_wakeUpTimerTag
= 0;
249 wxapp_install_thread_wakeup();
252 m_colorCube
= (unsigned char*) NULL
;
257 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
260 wxapp_uninstall_thread_wakeup();
263 if (m_colorCube
) free(m_colorCube
);
266 bool wxApp::OnInitGui()
268 GdkVisual
*visual
= gdk_visual_get_system();
270 /* on some machines, the default visual is just 256 colours, so
271 we make sure we get the best. this can sometimes be wasteful,
272 of course, but what do these guys pay $30.000 for? */
274 if (gdk_visual_get_best() != gdk_visual_get_system())
276 GdkVisual* vis = gdk_visual_get_best();
277 gtk_widget_set_default_visual( vis );
279 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
280 gtk_widget_set_default_colormap( colormap );
286 /* Nothing to do for 15, 16, 24, 32 bit displays */
287 if (visual
->depth
> 8) return TRUE
;
289 /* initialize color cube for 8-bit color reduction dithering */
291 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
293 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
295 for (int r
= 0; r
< 32; r
++)
297 for (int g
= 0; g
< 32; g
++)
299 for (int b
= 0; b
< 32; b
++)
301 int rr
= (r
<< 3) | (r
>> 2);
302 int gg
= (g
<< 3) | (g
>> 2);
303 int bb
= (b
<< 3) | (b
>> 2);
307 GdkColor
*colors
= cmap
->colors
;
312 for (int i
= 0; i
< cmap
->size
; i
++)
314 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
315 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
316 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
317 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
320 index
= i
; max
= sum
;
326 #if (GTK_MINOR_VERSION > 0)
327 /* assume 8-bit true or static colors. this really
329 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
330 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
331 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
332 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
334 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
337 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
345 bool wxApp::ProcessIdle()
348 event
.SetEventObject( this );
349 ProcessEvent( event
);
351 return event
.MoreRequested();
354 void wxApp::OnIdle( wxIdleEvent
&event
)
356 static bool s_inOnIdle
= FALSE
;
358 /* Avoid recursion (via ProcessEvent default case) */
364 /* Resend in the main thread events which have been prepared in other
366 ProcessPendingEvents();
368 /* 'Garbage' collection of windows deleted with Close(). */
369 DeletePendingObjects();
371 /* flush the logged messages if any */
373 wxLog
*log
= wxLog::GetActiveTarget();
374 if (log
!= NULL
&& log
->HasPendingMessages())
378 /* Send OnIdle events to all windows */
379 bool needMore
= SendIdleEvents();
382 event
.RequestMore(TRUE
);
387 bool wxApp::SendIdleEvents()
389 bool needMore
= FALSE
;
391 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
394 wxWindow
* win
= node
->GetData();
395 if (SendIdleEvents(win
))
397 node
= node
->GetNext();
403 bool wxApp::SendIdleEvents( wxWindow
* win
)
405 bool needMore
= FALSE
;
408 event
.SetEventObject(win
);
410 win
->ProcessEvent(event
);
412 win
->OnInternalIdle();
414 if (event
.MoreRequested())
417 wxNode
* node
= win
->GetChildren().First();
420 wxWindow
* win
= (wxWindow
*) node
->Data();
421 if (SendIdleEvents(win
))
429 int wxApp::MainLoop()
435 void wxApp::ExitMainLoop()
437 if (gtk_main_level() > 0)
441 bool wxApp::Initialized()
443 return m_initialized
;
446 bool wxApp::Pending()
448 return (gtk_events_pending() > 0);
451 void wxApp::Dispatch()
453 gtk_main_iteration();
456 void wxApp::DeletePendingObjects()
458 wxNode
*node
= wxPendingDelete
.First();
461 wxObject
*obj
= (wxObject
*)node
->Data();
465 if (wxPendingDelete
.Find(obj
))
468 node
= wxPendingDelete
.First();
472 bool wxApp::Initialize()
474 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
476 wxClassInfo::InitializeClasses();
478 wxSystemSettings::Init();
480 // GL: I'm annoyed ... I don't know where to put this and I don't want to
481 // create a module for that as it's part of the core.
483 wxPendingEvents
= new wxList();
484 wxPendingEventsLocker
= new wxCriticalSection();
488 wxTheFontNameDirectory = new wxFontNameDirectory;
489 wxTheFontNameDirectory->Initialize();
492 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
493 wxTheColourDatabase
->Initialize();
495 wxInitializeStockLists();
496 wxInitializeStockObjects();
498 wxModule::RegisterModules();
499 if (!wxModule::InitializeModules()) return FALSE
;
504 void wxApp::CleanUp()
506 wxModule::CleanUpModules();
508 if (wxTheColourDatabase
)
509 delete wxTheColourDatabase
;
510 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
513 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
514 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
517 wxDeleteStockObjects();
519 wxDeleteStockLists();
522 wxTheApp
= (wxApp
*) NULL
;
524 // GL: I'm annoyed ... I don't know where to put this and I don't want to
525 // create a module for that as it's part of the core.
527 delete wxPendingEvents
;
528 delete wxPendingEventsLocker
;
531 wxSystemSettings::Done();
535 wxClassInfo::CleanUpClasses();
537 // check for memory leaks
538 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
539 if (wxDebugContext::CountObjectsLeft() > 0)
541 wxLogDebug(wxT("There were memory leaks.\n"));
542 wxDebugContext::Dump();
543 wxDebugContext::PrintStatistics();
548 // do this as the very last thing because everything else can log messages
549 wxLog::DontCreateOnDemand();
551 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
557 //-----------------------------------------------------------------------------
559 //-----------------------------------------------------------------------------
561 int wxEntry( int argc
, char *argv
[] )
566 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
568 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
571 gtk_init( &argc
, &argv
);
573 wxSetDetectableAutoRepeat( TRUE
);
575 if (!wxApp::Initialize())
580 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
581 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
583 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
585 wxObject
*test_app
= app_ini();
587 wxTheApp
= (wxApp
*) test_app
;
590 wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") );
592 wxTheApp
->argc
= argc
;
594 wxTheApp
->argv
= new wxChar
*[argc
+1];
596 while (mb_argc
< argc
) {
597 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
600 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
602 wxTheApp
->argv
= argv
;
605 wxString
name(wxFileNameFromPath(argv
[0]));
606 wxStripExtension( name
);
607 wxTheApp
->SetAppName( name
);
611 if ( !wxTheApp
->OnInitGui() )
614 // Here frames insert themselves automatically into wxTopLevelWindows by
615 // getting created in OnInit().
618 if ( !wxTheApp
->OnInit() )
624 /* delete pending toplevel windows (typically a single
625 dialog) so that, if there isn't any left, we don't
627 wxTheApp
->DeletePendingObjects();
629 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
631 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
);
656 // flush the logged messages if any
657 wxLog
*log
= wxLog::GetActiveTarget();
658 if (log
!= NULL
&& log
->HasPendingMessages())
661 // continuing to use user defined log target is unsafe from now on because
662 // some resources may be already unavailable, so replace it by something
664 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);
674 #include "wx/gtk/info.xpm"
675 #include "wx/gtk/error.xpm"
676 #include "wx/gtk/question.xpm"
677 #include "wx/gtk/warning.xpm"
680 wxApp::GetStdIcon(int which
) const
684 case wxICON_INFORMATION
:
685 return wxIcon(info_xpm
);
687 case wxICON_QUESTION
:
688 return wxIcon(question_xpm
);
690 case wxICON_EXCLAMATION
:
691 return wxIcon(warning_xpm
);
694 wxFAIL_MSG(wxT("requested non existent standard icon"));
695 // still fall through
698 return wxIcon(error_xpm
);