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 //-----------------------------------------------------------------------------
86 static bool s_inYield
= FALSE
;
89 wxFAIL_MSG( wxT("wxYield called recursively" ) );
96 // We need to remove idle callbacks or the loop will
98 gtk_idle_remove( wxTheApp
->m_idleTag
);
99 wxTheApp
->m_idleTag
= 0;
103 while (gtk_events_pending())
104 gtk_main_iteration();
106 // disable log flushing from here because a call to wxYield() shouldn't
107 // normally result in message boxes popping up &c
110 /* it's necessary to call ProcessIdle() to update the frames sizes which
111 might have been changed (it also will update other things set from
112 OnUpdateUI() which is a nice (and desired) side effect) */
113 while (wxTheApp
->ProcessIdle()) { }
115 // let the logs be flashed again
125 //-----------------------------------------------------------------------------
127 //-----------------------------------------------------------------------------
132 if (!wxThread::IsMain())
137 wxapp_install_idle_handler();
140 if (!wxThread::IsMain())
145 //-----------------------------------------------------------------------------
147 //-----------------------------------------------------------------------------
149 gint
wxapp_pending_callback( gpointer
WXUNUSED(data
) )
151 if (!wxTheApp
) return TRUE
;
153 // when getting called from GDK's time-out handler
154 // we are no longer within GDK's grab on the GUI
155 // thread so we must lock it here ourselves
158 // Sent idle event to all who request them
159 wxTheApp
->ProcessPendingEvents();
163 /* flush the logged messages if any */
165 wxLog::FlushActive();
168 // Release lock again
171 // Return FALSE to indicate that no more idle events are
172 // to be sent (single shot instead of continuous stream)
176 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
178 if (!wxTheApp
) return TRUE
;
180 // when getting called from GDK's time-out handler
181 // we are no longer within GDK's grab on the GUI
182 // thread so we must lock it here ourselves
185 // Sent idle event to all who request them
186 while (wxTheApp
->ProcessIdle()) { }
188 /* Indicate that we are now in idle mode - even so deeply
189 in idle mode that we don't get any idle events anymore.
190 this is like wxMSW where an idle event is sent only
191 once each time after the event queue has been completely
194 wxTheApp
->m_idleTag
= 0;
196 // Release lock again
199 // Return FALSE to indicate that no more idle events are
200 // to be sent (single shot instead of continuous stream)
204 void wxapp_install_idle_handler()
206 wxASSERT_MSG( wxTheApp
->m_idleTag
== 0, wxT("attempt to install idle handler twice") );
210 if (g_pendingTag
== 0)
211 g_pendingTag
= gtk_idle_add_priority( 900, wxapp_pending_callback
, (gpointer
) NULL
);
213 /* This routine gets called by all event handlers
214 indicating that the idle is over. It may also
215 get called from other thread for sending events
216 to the main thread (and processing these in
217 idle time). Very low priority. */
219 wxTheApp
->m_idleTag
= gtk_idle_add_priority( 1000, wxapp_idle_callback
, (gpointer
) NULL
);
224 static int g_threadUninstallLevel
= 0;
226 void wxapp_install_thread_wakeup()
228 g_threadUninstallLevel
++;
230 if (g_threadUninstallLevel
!= 1) return;
232 if (wxTheApp
->m_wakeUpTimerTag
) return;
234 wxTheApp
->m_wakeUpTimerTag
= gtk_timeout_add( 50, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
237 void wxapp_uninstall_thread_wakeup()
239 g_threadUninstallLevel
--;
241 if (g_threadUninstallLevel
!= 0) return;
243 if (!wxTheApp
->m_wakeUpTimerTag
) return;
245 gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag
);
246 wxTheApp
->m_wakeUpTimerTag
= 0;
249 gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) )
251 // when getting called from GDK's time-out handler
252 // we are no longer within GDK's grab on the GUI
253 // thread so we must lock it here ourselves
256 wxapp_uninstall_thread_wakeup();
258 // unblock other threads wishing to do some GUI things
261 g_mainThreadLocked
= TRUE
;
263 // wake up other threads
266 // block other thread again
269 g_mainThreadLocked
= FALSE
;
271 wxapp_install_thread_wakeup();
273 // release lock again
279 #endif // wxUSE_THREADS
281 //-----------------------------------------------------------------------------
283 //-----------------------------------------------------------------------------
285 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
287 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
288 EVT_IDLE(wxApp::OnIdle
)
295 m_topWindow
= (wxWindow
*) NULL
;
296 m_exitOnFrameDelete
= TRUE
;
299 wxapp_install_idle_handler();
302 m_wakeUpTimerTag
= 0;
303 wxapp_install_thread_wakeup();
306 m_colorCube
= (unsigned char*) NULL
;
308 m_useBestVisual
= FALSE
;
313 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
316 wxapp_uninstall_thread_wakeup();
319 if (m_colorCube
) free(m_colorCube
);
322 bool wxApp::OnInitGui()
324 GdkVisual
*visual
= gdk_visual_get_system();
326 /* on some machines, the default visual is just 256 colours, so
327 we make sure we get the best. this can sometimes be wasteful,
328 of course, but what do these guys pay $30.000 for? */
330 if ((gdk_visual_get_best() != gdk_visual_get_system()) &&
334 /* seems gtk_widget_set_default_visual no longer exists? */
335 GdkVisual
* vis
= gtk_widget_get_default_visual();
337 GdkVisual
* vis
= gdk_visual_get_best();
338 gtk_widget_set_default_visual( vis
);
341 GdkColormap
*colormap
= gdk_colormap_new( vis
, FALSE
);
342 gtk_widget_set_default_colormap( colormap
);
347 /* Nothing to do for 15, 16, 24, 32 bit displays */
348 if (visual
->depth
> 8) return TRUE
;
350 /* initialize color cube for 8-bit color reduction dithering */
352 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
354 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
356 for (int r
= 0; r
< 32; r
++)
358 for (int g
= 0; g
< 32; g
++)
360 for (int b
= 0; b
< 32; b
++)
362 int rr
= (r
<< 3) | (r
>> 2);
363 int gg
= (g
<< 3) | (g
>> 2);
364 int bb
= (b
<< 3) | (b
>> 2);
368 GdkColor
*colors
= cmap
->colors
;
373 for (int i
= 0; i
< cmap
->size
; i
++)
375 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
376 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
377 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
378 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
381 index
= i
; max
= sum
;
387 #if (GTK_MINOR_VERSION > 0)
388 /* assume 8-bit true or static colors. this really
390 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
391 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
392 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
393 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
395 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
398 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
406 bool wxApp::ProcessIdle()
409 event
.SetEventObject( this );
410 ProcessEvent( event
);
412 return event
.MoreRequested();
415 void wxApp::OnIdle( wxIdleEvent
&event
)
417 static bool s_inOnIdle
= FALSE
;
419 /* Avoid recursion (via ProcessEvent default case) */
425 /* Resend in the main thread events which have been prepared in other
427 ProcessPendingEvents();
429 /* 'Garbage' collection of windows deleted with Close(). */
430 DeletePendingObjects();
432 /* Send OnIdle events to all windows */
433 bool needMore
= SendIdleEvents();
436 event
.RequestMore(TRUE
);
441 bool wxApp::SendIdleEvents()
443 bool needMore
= FALSE
;
445 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
448 wxWindow
* win
= node
->GetData();
449 if (SendIdleEvents(win
))
451 node
= node
->GetNext();
457 bool wxApp::SendIdleEvents( wxWindow
* win
)
459 bool needMore
= FALSE
;
462 event
.SetEventObject(win
);
464 win
->GetEventHandler()->ProcessEvent(event
);
466 win
->OnInternalIdle();
468 if (event
.MoreRequested())
471 wxNode
* node
= win
->GetChildren().First();
474 wxWindow
* win
= (wxWindow
*) node
->Data();
475 if (SendIdleEvents(win
))
483 int wxApp::MainLoop()
489 void wxApp::ExitMainLoop()
491 if (gtk_main_level() > 0)
495 bool wxApp::Initialized()
497 return m_initialized
;
500 bool wxApp::Pending()
502 return (gtk_events_pending() > 0);
505 void wxApp::Dispatch()
507 gtk_main_iteration();
510 void wxApp::DeletePendingObjects()
512 wxNode
*node
= wxPendingDelete
.First();
515 wxObject
*obj
= (wxObject
*)node
->Data();
519 if (wxPendingDelete
.Find(obj
))
522 node
= wxPendingDelete
.First();
526 bool wxApp::Initialize()
528 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
530 wxClassInfo::InitializeClasses();
532 wxSystemSettings::Init();
534 // GL: I'm annoyed ... I don't know where to put this and I don't want to
535 // create a module for that as it's part of the core.
537 wxPendingEvents
= new wxList();
538 wxPendingEventsLocker
= new wxCriticalSection();
541 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
542 wxTheColourDatabase
->Initialize();
544 wxInitializeStockLists();
545 wxInitializeStockObjects();
547 #if wxUSE_WX_RESOURCES
548 wxInitializeResourceSystem();
551 wxModule::RegisterModules();
552 if (!wxModule::InitializeModules()) return FALSE
;
557 void wxApp::CleanUp()
559 wxModule::CleanUpModules();
561 #if wxUSE_WX_RESOURCES
562 wxCleanUpResourceSystem();
565 if (wxTheColourDatabase
)
566 delete wxTheColourDatabase
;
568 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
570 wxDeleteStockObjects();
572 wxDeleteStockLists();
575 wxTheApp
= (wxApp
*) NULL
;
577 // GL: I'm annoyed ... I don't know where to put this and I don't want to
578 // create a module for that as it's part of the core.
580 delete wxPendingEvents
;
581 delete wxPendingEventsLocker
;
584 wxSystemSettings::Done();
588 wxClassInfo::CleanUpClasses();
590 // check for memory leaks
591 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
592 if (wxDebugContext::CountObjectsLeft(TRUE
) > 0)
594 wxLogDebug(wxT("There were memory leaks.\n"));
595 wxDebugContext::Dump();
596 wxDebugContext::PrintStatistics();
601 // do this as the very last thing because everything else can log messages
602 wxLog::DontCreateOnDemand();
604 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
610 //-----------------------------------------------------------------------------
612 //-----------------------------------------------------------------------------
615 int wxEntryStart( int argc
, char *argv
[] )
618 /* GTK 1.2 up to version 1.2.3 has broken threads */
619 if ((gtk_major_version
== 1) &&
620 (gtk_minor_version
== 2) &&
621 (gtk_micro_version
< 4))
623 printf( "wxWindows warning: GUI threading disabled due to outdated GTK version\n" );
633 #if defined(__WXGTK20__)
634 // gtk+ 2.0 supports Unicode through UTF-8 strings
635 wxConvCurrent
= &wxConvUTF8
;
637 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
639 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
644 gtk_init( &argc
, &argv
);
646 wxSetDetectableAutoRepeat( TRUE
);
648 if (!wxApp::Initialize())
662 if ( !wxTheApp
->OnInitGui() )
665 wxRootWindow
= gtk_window_new( GTK_WINDOW_TOPLEVEL
);
666 gtk_widget_realize( wxRootWindow
);
672 void wxEntryCleanup()
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
);
695 int wxEntry( int argc
, char *argv
[] )
697 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
698 // This seems to be necessary since there are 'rogue'
699 // objects present at this point (perhaps global objects?)
700 // Setting a checkpoint will ignore them as far as the
701 // memory checking facility is concerned.
702 // Of course you may argue that memory allocated in globals should be
703 // checked, but this is a reasonable compromise.
704 wxDebugContext::SetCheckpoint();
706 int err
= wxEntryStart(argc
, argv
);
712 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
713 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
715 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
717 wxObject
*test_app
= app_ini();
719 wxTheApp
= (wxApp
*) test_app
;
722 wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") );
724 wxTheApp
->argc
= argc
;
726 wxTheApp
->argv
= new wxChar
*[argc
+1];
728 while (mb_argc
< argc
)
730 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
733 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
735 wxTheApp
->argv
= argv
;
738 wxString
name(wxFileNameFromPath(argv
[0]));
739 wxStripExtension( name
);
740 wxTheApp
->SetAppName( name
);
743 retValue
= wxEntryInitGui();
745 // Here frames insert themselves automatically into wxTopLevelWindows by
746 // getting created in OnInit().
749 if ( !wxTheApp
->OnInit() )
755 /* delete pending toplevel windows (typically a single
756 dialog) so that, if there isn't any left, we don't
758 wxTheApp
->DeletePendingObjects();
760 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
762 if (wxTheApp
->Initialized())
766 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
769 /* Forcibly delete the window. */
770 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
771 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
773 topWindow
->Close( TRUE
);
774 wxTheApp
->DeletePendingObjects();
779 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
783 retValue
= wxTheApp
->OnExit();
792 #include "wx/gtk/info.xpm"
793 #include "wx/gtk/error.xpm"
794 #include "wx/gtk/question.xpm"
795 #include "wx/gtk/warning.xpm"
798 wxApp::GetStdIcon(int which
) const
802 case wxICON_INFORMATION
:
803 return wxIcon(info_xpm
);
805 case wxICON_QUESTION
:
806 return wxIcon(question_xpm
);
808 case wxICON_EXCLAMATION
:
809 return wxIcon(warning_xpm
);
812 wxFAIL_MSG(wxT("requested non existent standard icon"));
813 // still fall through
816 return wxIcon(error_xpm
);