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
;
53 gint g_pendingTag
= 0;
55 GtkWidget
*wxRootWindow
= (GtkWidget
*) NULL
;
57 //-----------------------------------------------------------------------------
59 //-----------------------------------------------------------------------------
61 /* forward declaration */
62 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) );
63 gint
wxapp_pending_callback( gpointer
WXUNUSED(data
) );
64 void wxapp_install_idle_handler();
67 gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) );
70 //-----------------------------------------------------------------------------
72 //-----------------------------------------------------------------------------
79 //-----------------------------------------------------------------------------
81 //-----------------------------------------------------------------------------
85 bool has_idle
= (wxTheApp
->m_idleTag
!= 0);
89 /* We need to temporarily remove idle callbacks or the loop will
91 gtk_idle_remove( wxTheApp
->m_idleTag
);
92 wxTheApp
->m_idleTag
= 0;
95 while (gtk_events_pending())
100 /* re-add idle handler (very low priority) */
101 wxTheApp
->m_idleTag
= gtk_idle_add_priority( 1000, wxapp_idle_callback
, (gpointer
) NULL
);
104 // disable log flushing from here because a call to wxYield() shouldn't
105 // normally result in message boxes popping up &c
108 /* it's necessary to call ProcessIdle() to update the frames sizes which
109 might have been changed (it also will update other things set from
110 OnUpdateUI() which is a nice (and desired) side effect) */
111 while (wxTheApp
->ProcessIdle()) { }
113 // let the logs be flashed again
119 //-----------------------------------------------------------------------------
121 //-----------------------------------------------------------------------------
126 if (!wxThread::IsMain())
131 wxapp_install_idle_handler();
134 if (!wxThread::IsMain())
139 //-----------------------------------------------------------------------------
141 //-----------------------------------------------------------------------------
143 gint
wxapp_pending_callback( gpointer
WXUNUSED(data
) )
145 if (!wxTheApp
) return TRUE
;
147 // when getting called from GDK's time-out handler
148 // we are no longer within GDK's grab on the GUI
149 // thread so we must lock it here ourselves
152 // Sent idle event to all who request them
153 wxTheApp
->ProcessPendingEvents();
157 /* flush the logged messages if any */
159 wxLog::FlushActive();
162 // Release lock again
165 // Return FALSE to indicate that no more idle events are
166 // to be sent (single shot instead of continuous stream)
170 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
172 if (!wxTheApp
) return TRUE
;
174 // when getting called from GDK's time-out handler
175 // we are no longer within GDK's grab on the GUI
176 // thread so we must lock it here ourselves
179 // Sent idle event to all who request them
180 while (wxTheApp
->ProcessIdle()) { }
182 /* Indicate that we are now in idle mode - even so deeply
183 in idle mode that we don't get any idle events anymore.
184 this is like wxMSW where an idle event is sent only
185 once each time after the event queue has been completely
188 wxTheApp
->m_idleTag
= 0;
190 // Release lock again
193 // Return FALSE to indicate that no more idle events are
194 // to be sent (single shot instead of continuous stream)
198 void wxapp_install_idle_handler()
200 wxASSERT_MSG( wxTheApp
->m_idleTag
== 0, wxT("attempt to install idle handler twice") );
202 if (g_pendingTag
== 0)
203 g_pendingTag
= gtk_idle_add_priority( 900, wxapp_pending_callback
, (gpointer
) NULL
);
205 /* This routine gets called by all event handlers
206 indicating that the idle is over. It may also
207 get called from other thread for sending events
208 to the main thread (and processing these in
209 idle time). Very low priority. */
211 wxTheApp
->m_idleTag
= gtk_idle_add_priority( 1000, wxapp_idle_callback
, (gpointer
) NULL
);
218 static int g_threadUninstallLevel
= 0;
220 void wxapp_install_thread_wakeup()
222 g_threadUninstallLevel
++;
224 if (g_threadUninstallLevel
!= 1) return;
226 if (wxTheApp
->m_wakeUpTimerTag
) return;
228 wxTheApp
->m_wakeUpTimerTag
= gtk_timeout_add( 50, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
231 void wxapp_uninstall_thread_wakeup()
233 g_threadUninstallLevel
--;
235 if (g_threadUninstallLevel
!= 0) return;
237 if (!wxTheApp
->m_wakeUpTimerTag
) return;
239 gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag
);
240 wxTheApp
->m_wakeUpTimerTag
= 0;
243 gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) )
245 // when getting called from GDK's time-out handler
246 // we are no longer within GDK's grab on the GUI
247 // thread so we must lock it here ourselves
250 wxapp_uninstall_thread_wakeup();
252 // unblock other threads wishing to do some GUI things
255 g_mainThreadLocked
= TRUE
;
257 // wake up other threads
260 // block other thread again
263 g_mainThreadLocked
= FALSE
;
265 wxapp_install_thread_wakeup();
267 // release lock again
273 #endif // wxUSE_THREADS
275 //-----------------------------------------------------------------------------
277 //-----------------------------------------------------------------------------
279 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
281 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
282 EVT_IDLE(wxApp::OnIdle
)
289 m_topWindow
= (wxWindow
*) NULL
;
290 m_exitOnFrameDelete
= TRUE
;
293 wxapp_install_idle_handler();
296 m_wakeUpTimerTag
= 0;
297 wxapp_install_thread_wakeup();
300 m_colorCube
= (unsigned char*) NULL
;
302 m_useBestVisual
= FALSE
;
307 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
310 wxapp_uninstall_thread_wakeup();
313 if (m_colorCube
) free(m_colorCube
);
316 bool wxApp::OnInitGui()
318 GdkVisual
*visual
= gdk_visual_get_system();
320 /* on some machines, the default visual is just 256 colours, so
321 we make sure we get the best. this can sometimes be wasteful,
322 of course, but what do these guys pay $30.000 for? */
324 if ((gdk_visual_get_best() != gdk_visual_get_system()) &&
328 /* seems gtk_widget_set_default_visual no longer exists? */
329 GdkVisual
* vis
= gtk_widget_get_default_visual();
331 GdkVisual
* vis
= gdk_visual_get_best();
332 gtk_widget_set_default_visual( vis
);
335 GdkColormap
*colormap
= gdk_colormap_new( vis
, FALSE
);
336 gtk_widget_set_default_colormap( colormap
);
341 /* Nothing to do for 15, 16, 24, 32 bit displays */
342 if (visual
->depth
> 8) return TRUE
;
344 /* initialize color cube for 8-bit color reduction dithering */
346 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
348 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
350 for (int r
= 0; r
< 32; r
++)
352 for (int g
= 0; g
< 32; g
++)
354 for (int b
= 0; b
< 32; b
++)
356 int rr
= (r
<< 3) | (r
>> 2);
357 int gg
= (g
<< 3) | (g
>> 2);
358 int bb
= (b
<< 3) | (b
>> 2);
362 GdkColor
*colors
= cmap
->colors
;
367 for (int i
= 0; i
< cmap
->size
; i
++)
369 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
370 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
371 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
372 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
375 index
= i
; max
= sum
;
381 #if (GTK_MINOR_VERSION > 0)
382 /* assume 8-bit true or static colors. this really
384 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
385 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
386 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
387 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
389 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
392 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
400 bool wxApp::ProcessIdle()
403 event
.SetEventObject( this );
404 ProcessEvent( event
);
406 return event
.MoreRequested();
409 void wxApp::OnIdle( wxIdleEvent
&event
)
411 static bool s_inOnIdle
= FALSE
;
413 /* Avoid recursion (via ProcessEvent default case) */
419 /* Resend in the main thread events which have been prepared in other
421 ProcessPendingEvents();
423 /* 'Garbage' collection of windows deleted with Close(). */
424 DeletePendingObjects();
426 /* Send OnIdle events to all windows */
427 bool needMore
= SendIdleEvents();
430 event
.RequestMore(TRUE
);
435 bool wxApp::SendIdleEvents()
437 bool needMore
= FALSE
;
439 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
442 wxWindow
* win
= node
->GetData();
443 if (SendIdleEvents(win
))
445 node
= node
->GetNext();
451 bool wxApp::SendIdleEvents( wxWindow
* win
)
453 bool needMore
= FALSE
;
456 event
.SetEventObject(win
);
458 win
->GetEventHandler()->ProcessEvent(event
);
460 win
->OnInternalIdle();
462 if (event
.MoreRequested())
465 wxNode
* node
= win
->GetChildren().First();
468 wxWindow
* win
= (wxWindow
*) node
->Data();
469 if (SendIdleEvents(win
))
477 int wxApp::MainLoop()
483 void wxApp::ExitMainLoop()
485 if (gtk_main_level() > 0)
489 bool wxApp::Initialized()
491 return m_initialized
;
494 bool wxApp::Pending()
496 return (gtk_events_pending() > 0);
499 void wxApp::Dispatch()
501 gtk_main_iteration();
504 void wxApp::DeletePendingObjects()
506 wxNode
*node
= wxPendingDelete
.First();
509 wxObject
*obj
= (wxObject
*)node
->Data();
513 if (wxPendingDelete
.Find(obj
))
516 node
= wxPendingDelete
.First();
520 bool wxApp::Initialize()
522 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
524 wxClassInfo::InitializeClasses();
526 wxSystemSettings::Init();
528 // GL: I'm annoyed ... I don't know where to put this and I don't want to
529 // create a module for that as it's part of the core.
531 wxPendingEvents
= new wxList();
532 wxPendingEventsLocker
= new wxCriticalSection();
535 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
536 wxTheColourDatabase
->Initialize();
538 wxInitializeStockLists();
539 wxInitializeStockObjects();
541 #if wxUSE_WX_RESOURCES
542 wxInitializeResourceSystem();
545 wxModule::RegisterModules();
546 if (!wxModule::InitializeModules()) return FALSE
;
551 void wxApp::CleanUp()
553 wxModule::CleanUpModules();
555 #if wxUSE_WX_RESOURCES
556 wxCleanUpResourceSystem();
559 if (wxTheColourDatabase
)
560 delete wxTheColourDatabase
;
562 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
564 wxDeleteStockObjects();
566 wxDeleteStockLists();
569 wxTheApp
= (wxApp
*) NULL
;
571 // GL: I'm annoyed ... I don't know where to put this and I don't want to
572 // create a module for that as it's part of the core.
574 delete wxPendingEvents
;
575 delete wxPendingEventsLocker
;
578 wxSystemSettings::Done();
582 wxClassInfo::CleanUpClasses();
584 // check for memory leaks
585 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
586 if (wxDebugContext::CountObjectsLeft(TRUE
) > 0)
588 wxLogDebug(wxT("There were memory leaks.\n"));
589 wxDebugContext::Dump();
590 wxDebugContext::PrintStatistics();
595 // do this as the very last thing because everything else can log messages
596 wxLog::DontCreateOnDemand();
598 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
604 //-----------------------------------------------------------------------------
606 //-----------------------------------------------------------------------------
609 int wxEntryStart( int argc
, char *argv
[] )
612 /* GTK 1.2 up to version 1.2.3 has broken threads */
613 if ((gtk_major_version
== 1) &&
614 (gtk_minor_version
== 2) &&
615 (gtk_micro_version
< 4))
617 printf( "wxWindows warning: GUI threading disabled due to outdated GTK version\n" );
627 #if defined(__WXGTK20__)
628 // gtk+ 2.0 supports Unicode through UTF-8 strings
629 wxConvCurrent
= &wxConvUTF8
;
631 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
633 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
638 gtk_init( &argc
, &argv
);
640 wxSetDetectableAutoRepeat( TRUE
);
642 if (!wxApp::Initialize())
656 if ( !wxTheApp
->OnInitGui() )
659 wxRootWindow
= gtk_window_new( GTK_WINDOW_TOPLEVEL
);
660 gtk_widget_realize( wxRootWindow
);
666 void wxEntryCleanup()
669 // flush the logged messages if any
670 wxLog
*log
= wxLog::GetActiveTarget();
671 if (log
!= NULL
&& log
->HasPendingMessages())
674 // continuing to use user defined log target is unsafe from now on because
675 // some resources may be already unavailable, so replace it by something
677 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);
689 int wxEntry( int argc
, char *argv
[] )
691 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
692 // This seems to be necessary since there are 'rogue'
693 // objects present at this point (perhaps global objects?)
694 // Setting a checkpoint will ignore them as far as the
695 // memory checking facility is concerned.
696 // Of course you may argue that memory allocated in globals should be
697 // checked, but this is a reasonable compromise.
698 wxDebugContext::SetCheckpoint();
700 int err
= wxEntryStart(argc
, argv
);
706 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
707 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
709 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
711 wxObject
*test_app
= app_ini();
713 wxTheApp
= (wxApp
*) test_app
;
716 wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") );
718 wxTheApp
->argc
= argc
;
720 wxTheApp
->argv
= new wxChar
*[argc
+1];
722 while (mb_argc
< argc
)
724 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
727 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
729 wxTheApp
->argv
= argv
;
732 wxString
name(wxFileNameFromPath(argv
[0]));
733 wxStripExtension( name
);
734 wxTheApp
->SetAppName( name
);
737 retValue
= wxEntryInitGui();
739 // Here frames insert themselves automatically into wxTopLevelWindows by
740 // getting created in OnInit().
743 if ( !wxTheApp
->OnInit() )
749 /* delete pending toplevel windows (typically a single
750 dialog) so that, if there isn't any left, we don't
752 wxTheApp
->DeletePendingObjects();
754 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
756 if (wxTheApp
->Initialized())
760 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
763 /* Forcibly delete the window. */
764 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
765 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
767 topWindow
->Close( TRUE
);
768 wxTheApp
->DeletePendingObjects();
773 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
777 retValue
= wxTheApp
->OnExit();
786 #include "wx/gtk/info.xpm"
787 #include "wx/gtk/error.xpm"
788 #include "wx/gtk/question.xpm"
789 #include "wx/gtk/warning.xpm"
792 wxApp::GetStdIcon(int which
) const
796 case wxICON_INFORMATION
:
797 return wxIcon(info_xpm
);
799 case wxICON_QUESTION
:
800 return wxIcon(question_xpm
);
802 case wxICON_EXCLAMATION
:
803 return wxIcon(warning_xpm
);
806 wxFAIL_MSG(wxT("requested non existent standard icon"));
807 // still fall through
810 return wxIcon(error_xpm
);