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 if ( !wxThread::IsMain() )
88 // can't call gtk_main_iteration() from other threads like this
91 #endif // wxUSE_THREADS
94 static bool s_inYield
= FALSE
;
97 wxFAIL_MSG( wxT("wxYield called recursively" ) );
104 // We need to remove idle callbacks or the loop will
106 gtk_idle_remove( wxTheApp
->m_idleTag
);
107 wxTheApp
->m_idleTag
= 0;
111 while (gtk_events_pending())
112 gtk_main_iteration();
114 // disable log flushing from here because a call to wxYield() shouldn't
115 // normally result in message boxes popping up &c
118 /* it's necessary to call ProcessIdle() to update the frames sizes which
119 might have been changed (it also will update other things set from
120 OnUpdateUI() which is a nice (and desired) side effect) */
121 while (wxTheApp
->ProcessIdle()) { }
123 // let the logs be flashed again
133 //-----------------------------------------------------------------------------
135 //-----------------------------------------------------------------------------
140 if (!wxThread::IsMain())
145 wxapp_install_idle_handler();
148 if (!wxThread::IsMain())
153 //-----------------------------------------------------------------------------
155 //-----------------------------------------------------------------------------
157 gint
wxapp_pending_callback( gpointer
WXUNUSED(data
) )
159 if (!wxTheApp
) return TRUE
;
161 // when getting called from GDK's time-out handler
162 // we are no longer within GDK's grab on the GUI
163 // thread so we must lock it here ourselves
166 // Sent idle event to all who request them
167 wxTheApp
->ProcessPendingEvents();
171 /* flush the logged messages if any */
173 wxLog::FlushActive();
176 // Release lock again
179 // Return FALSE to indicate that no more idle events are
180 // to be sent (single shot instead of continuous stream)
184 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
186 if (!wxTheApp
) return TRUE
;
188 // when getting called from GDK's time-out handler
189 // we are no longer within GDK's grab on the GUI
190 // thread so we must lock it here ourselves
193 /* Indicate that we are now in idle mode - even so deeply
194 in idle mode that we don't get any idle events anymore.
195 this is like wxMSW where an idle event is sent only
196 once each time after the event queue has been completely
199 wxTheApp
->m_idleTag
= 0;
201 // Sent idle event to all who request them
202 while (wxTheApp
->ProcessIdle()) { }
204 // Release lock again
207 // Return FALSE to indicate that no more idle events are
208 // to be sent (single shot instead of continuous stream)
212 void wxapp_install_idle_handler()
214 wxASSERT_MSG( wxTheApp
->m_idleTag
== 0, wxT("attempt to install idle handler twice") );
218 if (g_pendingTag
== 0)
219 g_pendingTag
= gtk_idle_add_priority( 900, wxapp_pending_callback
, (gpointer
) NULL
);
221 /* This routine gets called by all event handlers
222 indicating that the idle is over. It may also
223 get called from other thread for sending events
224 to the main thread (and processing these in
225 idle time). Very low priority. */
227 wxTheApp
->m_idleTag
= gtk_idle_add_priority( 1000, wxapp_idle_callback
, (gpointer
) NULL
);
232 static int g_threadUninstallLevel
= 0;
234 void wxapp_install_thread_wakeup()
236 g_threadUninstallLevel
++;
238 if (g_threadUninstallLevel
!= 1) return;
240 if (wxTheApp
->m_wakeUpTimerTag
) return;
242 wxTheApp
->m_wakeUpTimerTag
= gtk_timeout_add( 50, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
245 void wxapp_uninstall_thread_wakeup()
247 g_threadUninstallLevel
--;
249 if (g_threadUninstallLevel
!= 0) return;
251 if (!wxTheApp
->m_wakeUpTimerTag
) return;
253 gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag
);
254 wxTheApp
->m_wakeUpTimerTag
= 0;
257 gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) )
259 // when getting called from GDK's time-out handler
260 // we are no longer within GDK's grab on the GUI
261 // thread so we must lock it here ourselves
264 wxapp_uninstall_thread_wakeup();
266 // unblock other threads wishing to do some GUI things
269 g_mainThreadLocked
= TRUE
;
271 // wake up other threads
274 // block other thread again
277 g_mainThreadLocked
= FALSE
;
279 wxapp_install_thread_wakeup();
281 // release lock again
287 #endif // wxUSE_THREADS
289 //-----------------------------------------------------------------------------
291 //-----------------------------------------------------------------------------
293 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
295 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
296 EVT_IDLE(wxApp::OnIdle
)
303 m_topWindow
= (wxWindow
*) NULL
;
304 m_exitOnFrameDelete
= TRUE
;
307 wxapp_install_idle_handler();
310 m_wakeUpTimerTag
= 0;
311 wxapp_install_thread_wakeup();
314 m_colorCube
= (unsigned char*) NULL
;
316 m_useBestVisual
= FALSE
;
321 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
324 wxapp_uninstall_thread_wakeup();
327 if (m_colorCube
) free(m_colorCube
);
330 bool wxApp::OnInitGui()
332 GdkVisual
*visual
= gdk_visual_get_system();
334 /* on some machines, the default visual is just 256 colours, so
335 we make sure we get the best. this can sometimes be wasteful,
336 of course, but what do these guys pay $30.000 for? */
338 if ((gdk_visual_get_best() != gdk_visual_get_system()) &&
342 /* seems gtk_widget_set_default_visual no longer exists? */
343 GdkVisual
* vis
= gtk_widget_get_default_visual();
345 GdkVisual
* vis
= gdk_visual_get_best();
346 gtk_widget_set_default_visual( vis
);
349 GdkColormap
*colormap
= gdk_colormap_new( vis
, FALSE
);
350 gtk_widget_set_default_colormap( colormap
);
355 /* Nothing to do for 15, 16, 24, 32 bit displays */
356 if (visual
->depth
> 8) return TRUE
;
358 /* initialize color cube for 8-bit color reduction dithering */
360 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
362 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
364 for (int r
= 0; r
< 32; r
++)
366 for (int g
= 0; g
< 32; g
++)
368 for (int b
= 0; b
< 32; b
++)
370 int rr
= (r
<< 3) | (r
>> 2);
371 int gg
= (g
<< 3) | (g
>> 2);
372 int bb
= (b
<< 3) | (b
>> 2);
376 GdkColor
*colors
= cmap
->colors
;
381 for (int i
= 0; i
< cmap
->size
; i
++)
383 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
384 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
385 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
386 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
389 index
= i
; max
= sum
;
395 #if (GTK_MINOR_VERSION > 0)
396 /* assume 8-bit true or static colors. this really
398 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
399 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
400 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
401 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
403 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
406 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
414 bool wxApp::ProcessIdle()
417 event
.SetEventObject( this );
418 ProcessEvent( event
);
420 return event
.MoreRequested();
423 void wxApp::OnIdle( wxIdleEvent
&event
)
425 static bool s_inOnIdle
= FALSE
;
427 /* Avoid recursion (via ProcessEvent default case) */
433 /* Resend in the main thread events which have been prepared in other
435 ProcessPendingEvents();
437 /* 'Garbage' collection of windows deleted with Close(). */
438 DeletePendingObjects();
440 /* Send OnIdle events to all windows */
441 bool needMore
= SendIdleEvents();
444 event
.RequestMore(TRUE
);
449 bool wxApp::SendIdleEvents()
451 bool needMore
= FALSE
;
453 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
456 wxWindow
* win
= node
->GetData();
457 if (SendIdleEvents(win
))
459 node
= node
->GetNext();
465 bool wxApp::SendIdleEvents( wxWindow
* win
)
467 bool needMore
= FALSE
;
470 event
.SetEventObject(win
);
472 win
->GetEventHandler()->ProcessEvent(event
);
474 win
->OnInternalIdle();
476 if (event
.MoreRequested())
479 wxNode
* node
= win
->GetChildren().First();
482 wxWindow
* win
= (wxWindow
*) node
->Data();
483 if (SendIdleEvents(win
))
491 int wxApp::MainLoop()
497 void wxApp::ExitMainLoop()
499 if (gtk_main_level() > 0)
503 bool wxApp::Initialized()
505 return m_initialized
;
508 bool wxApp::Pending()
510 return (gtk_events_pending() > 0);
513 void wxApp::Dispatch()
515 gtk_main_iteration();
518 void wxApp::DeletePendingObjects()
520 wxNode
*node
= wxPendingDelete
.First();
523 wxObject
*obj
= (wxObject
*)node
->Data();
527 if (wxPendingDelete
.Find(obj
))
530 node
= wxPendingDelete
.First();
534 bool wxApp::Initialize()
536 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
538 wxClassInfo::InitializeClasses();
540 wxSystemSettings::Init();
542 // GL: I'm annoyed ... I don't know where to put this and I don't want to
543 // create a module for that as it's part of the core.
545 wxPendingEvents
= new wxList();
546 wxPendingEventsLocker
= new wxCriticalSection();
549 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
550 wxTheColourDatabase
->Initialize();
552 wxInitializeStockLists();
553 wxInitializeStockObjects();
555 #if wxUSE_WX_RESOURCES
556 wxInitializeResourceSystem();
559 wxModule::RegisterModules();
560 if (!wxModule::InitializeModules()) return FALSE
;
565 void wxApp::CleanUp()
567 wxModule::CleanUpModules();
569 #if wxUSE_WX_RESOURCES
570 wxCleanUpResourceSystem();
573 if (wxTheColourDatabase
)
574 delete wxTheColourDatabase
;
576 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
578 wxDeleteStockObjects();
580 wxDeleteStockLists();
583 wxTheApp
= (wxApp
*) NULL
;
585 // GL: I'm annoyed ... I don't know where to put this and I don't want to
586 // create a module for that as it's part of the core.
588 delete wxPendingEvents
;
589 delete wxPendingEventsLocker
;
592 wxSystemSettings::Done();
596 wxClassInfo::CleanUpClasses();
598 // check for memory leaks
599 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
600 if (wxDebugContext::CountObjectsLeft(TRUE
) > 0)
602 wxLogDebug(wxT("There were memory leaks.\n"));
603 wxDebugContext::Dump();
604 wxDebugContext::PrintStatistics();
609 // do this as the very last thing because everything else can log messages
610 wxLog::DontCreateOnDemand();
612 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
618 //-----------------------------------------------------------------------------
620 //-----------------------------------------------------------------------------
623 int wxEntryStart( int argc
, char *argv
[] )
626 /* GTK 1.2 up to version 1.2.3 has broken threads */
627 if ((gtk_major_version
== 1) &&
628 (gtk_minor_version
== 2) &&
629 (gtk_micro_version
< 4))
631 printf( "wxWindows warning: GUI threading disabled due to outdated GTK version\n" );
641 // We should have the wxUSE_WCHAR_T test on the _outside_
643 #if defined(__WXGTK20__)
644 // gtk+ 2.0 supports Unicode through UTF-8 strings
645 wxConvCurrent
= &wxConvUTF8
;
647 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
650 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
655 gtk_init( &argc
, &argv
);
657 wxSetDetectableAutoRepeat( TRUE
);
659 if (!wxApp::Initialize())
672 if ( !wxTheApp
->OnInitGui() )
675 wxRootWindow
= gtk_window_new( GTK_WINDOW_TOPLEVEL
);
676 gtk_widget_realize( wxRootWindow
);
682 void wxEntryCleanup()
685 // flush the logged messages if any
686 wxLog
*log
= wxLog::GetActiveTarget();
687 if (log
!= NULL
&& log
->HasPendingMessages())
690 // continuing to use user defined log target is unsafe from now on because
691 // some resources may be already unavailable, so replace it by something
693 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);
705 int wxEntry( int argc
, char *argv
[] )
707 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
708 // This seems to be necessary since there are 'rogue'
709 // objects present at this point (perhaps global objects?)
710 // Setting a checkpoint will ignore them as far as the
711 // memory checking facility is concerned.
712 // Of course you may argue that memory allocated in globals should be
713 // checked, but this is a reasonable compromise.
714 wxDebugContext::SetCheckpoint();
716 int err
= wxEntryStart(argc
, argv
);
722 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
723 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
725 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
727 wxObject
*test_app
= app_ini();
729 wxTheApp
= (wxApp
*) test_app
;
732 wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") );
734 wxTheApp
->argc
= argc
;
736 wxTheApp
->argv
= new wxChar
*[argc
+1];
738 while (mb_argc
< argc
)
740 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
743 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
745 wxTheApp
->argv
= argv
;
748 wxString
name(wxFileNameFromPath(argv
[0]));
749 wxStripExtension( name
);
750 wxTheApp
->SetAppName( name
);
753 retValue
= wxEntryInitGui();
755 // Here frames insert themselves automatically into wxTopLevelWindows by
756 // getting created in OnInit().
759 if ( !wxTheApp
->OnInit() )
765 /* delete pending toplevel windows (typically a single
766 dialog) so that, if there isn't any left, we don't
768 wxTheApp
->DeletePendingObjects();
770 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
772 if (wxTheApp
->Initialized())
776 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
779 /* Forcibly delete the window. */
780 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
781 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
783 topWindow
->Close( TRUE
);
784 wxTheApp
->DeletePendingObjects();
789 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
793 retValue
= wxTheApp
->OnExit();
802 #include "wx/gtk/info.xpm"
803 #include "wx/gtk/error.xpm"
804 #include "wx/gtk/question.xpm"
805 #include "wx/gtk/warning.xpm"
808 wxApp::GetStdIcon(int which
) const
812 case wxICON_INFORMATION
:
813 return wxIcon(info_xpm
);
815 case wxICON_QUESTION
:
816 return wxIcon(question_xpm
);
818 case wxICON_EXCLAMATION
:
819 return wxIcon(warning_xpm
);
822 wxFAIL_MSG(wxT("requested non existent standard icon"));
823 // still fall through
826 return wxIcon(error_xpm
);