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 //-----------------------------------------------------------------------------
83 static bool gs_inYield
= FALSE
;
88 if ( !wxThread::IsMain() )
90 // can't call gtk_main_iteration() from other threads like this
93 #endif // wxUSE_THREADS
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
131 //-----------------------------------------------------------------------------
133 // Like wxYield, but fails silently if the yield is recursive.
134 //-----------------------------------------------------------------------------
136 bool wxYieldIfNeeded()
144 //-----------------------------------------------------------------------------
146 //-----------------------------------------------------------------------------
151 if (!wxThread::IsMain())
156 wxapp_install_idle_handler();
159 if (!wxThread::IsMain())
164 //-----------------------------------------------------------------------------
166 //-----------------------------------------------------------------------------
168 gint
wxapp_pending_callback( gpointer
WXUNUSED(data
) )
170 if (!wxTheApp
) return TRUE
;
172 // when getting called from GDK's time-out handler
173 // we are no longer within GDK's grab on the GUI
174 // thread so we must lock it here ourselves
177 // Sent idle event to all who request them
178 wxTheApp
->ProcessPendingEvents();
182 /* flush the logged messages if any */
184 wxLog::FlushActive();
187 // Release lock again
190 // Return FALSE to indicate that no more idle events are
191 // to be sent (single shot instead of continuous stream)
195 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
197 if (!wxTheApp
) return TRUE
;
199 // when getting called from GDK's time-out handler
200 // we are no longer within GDK's grab on the GUI
201 // thread so we must lock it here ourselves
204 /* Indicate that we are now in idle mode - even so deeply
205 in idle mode that we don't get any idle events anymore.
206 this is like wxMSW where an idle event is sent only
207 once each time after the event queue has been completely
210 wxTheApp
->m_idleTag
= 0;
212 // Sent idle event to all who request them
213 while (wxTheApp
->ProcessIdle()) { }
215 // Release lock again
218 // Return FALSE to indicate that no more idle events are
219 // to be sent (single shot instead of continuous stream)
223 void wxapp_install_idle_handler()
225 wxASSERT_MSG( wxTheApp
->m_idleTag
== 0, wxT("attempt to install idle handler twice") );
229 if (g_pendingTag
== 0)
230 g_pendingTag
= gtk_idle_add_priority( 900, wxapp_pending_callback
, (gpointer
) NULL
);
232 /* This routine gets called by all event handlers
233 indicating that the idle is over. It may also
234 get called from other thread for sending events
235 to the main thread (and processing these in
236 idle time). Very low priority. */
238 wxTheApp
->m_idleTag
= gtk_idle_add_priority( 1000, wxapp_idle_callback
, (gpointer
) NULL
);
243 static int g_threadUninstallLevel
= 0;
245 void wxapp_install_thread_wakeup()
247 g_threadUninstallLevel
++;
249 if (g_threadUninstallLevel
!= 1) return;
251 if (wxTheApp
->m_wakeUpTimerTag
) return;
253 wxTheApp
->m_wakeUpTimerTag
= gtk_timeout_add( 50, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
256 void wxapp_uninstall_thread_wakeup()
258 g_threadUninstallLevel
--;
260 if (g_threadUninstallLevel
!= 0) return;
262 if (!wxTheApp
->m_wakeUpTimerTag
) return;
264 gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag
);
265 wxTheApp
->m_wakeUpTimerTag
= 0;
268 gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) )
270 // when getting called from GDK's time-out handler
271 // we are no longer within GDK's grab on the GUI
272 // thread so we must lock it here ourselves
275 wxapp_uninstall_thread_wakeup();
277 // unblock other threads wishing to do some GUI things
280 g_mainThreadLocked
= TRUE
;
282 // wake up other threads
285 // block other thread again
288 g_mainThreadLocked
= FALSE
;
290 wxapp_install_thread_wakeup();
292 // release lock again
298 #endif // wxUSE_THREADS
300 //-----------------------------------------------------------------------------
302 //-----------------------------------------------------------------------------
304 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
306 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
307 EVT_IDLE(wxApp::OnIdle
)
314 m_topWindow
= (wxWindow
*) NULL
;
315 m_exitOnFrameDelete
= TRUE
;
318 wxapp_install_idle_handler();
321 m_wakeUpTimerTag
= 0;
322 wxapp_install_thread_wakeup();
325 m_colorCube
= (unsigned char*) NULL
;
327 m_useBestVisual
= FALSE
;
332 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
335 wxapp_uninstall_thread_wakeup();
338 if (m_colorCube
) free(m_colorCube
);
341 bool wxApp::OnInitGui()
343 GdkVisual
*visual
= gdk_visual_get_system();
345 /* on some machines, the default visual is just 256 colours, so
346 we make sure we get the best. this can sometimes be wasteful,
347 of course, but what do these guys pay $30.000 for? */
349 if ((gdk_visual_get_best() != gdk_visual_get_system()) &&
353 /* seems gtk_widget_set_default_visual no longer exists? */
354 GdkVisual
* vis
= gtk_widget_get_default_visual();
356 GdkVisual
* vis
= gdk_visual_get_best();
357 gtk_widget_set_default_visual( vis
);
360 GdkColormap
*colormap
= gdk_colormap_new( vis
, FALSE
);
361 gtk_widget_set_default_colormap( colormap
);
366 /* Nothing to do for 15, 16, 24, 32 bit displays */
367 if (visual
->depth
> 8) return TRUE
;
369 /* initialize color cube for 8-bit color reduction dithering */
371 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
373 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
375 for (int r
= 0; r
< 32; r
++)
377 for (int g
= 0; g
< 32; g
++)
379 for (int b
= 0; b
< 32; b
++)
381 int rr
= (r
<< 3) | (r
>> 2);
382 int gg
= (g
<< 3) | (g
>> 2);
383 int bb
= (b
<< 3) | (b
>> 2);
387 GdkColor
*colors
= cmap
->colors
;
392 for (int i
= 0; i
< cmap
->size
; i
++)
394 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
395 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
396 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
397 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
400 index
= i
; max
= sum
;
406 #if (GTK_MINOR_VERSION > 0)
407 /* assume 8-bit true or static colors. this really
409 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
410 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
411 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
412 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
414 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
417 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
425 bool wxApp::ProcessIdle()
428 event
.SetEventObject( this );
429 ProcessEvent( event
);
431 return event
.MoreRequested();
434 void wxApp::OnIdle( wxIdleEvent
&event
)
436 static bool s_inOnIdle
= FALSE
;
438 /* Avoid recursion (via ProcessEvent default case) */
444 /* Resend in the main thread events which have been prepared in other
446 ProcessPendingEvents();
448 /* 'Garbage' collection of windows deleted with Close(). */
449 DeletePendingObjects();
451 /* Send OnIdle events to all windows */
452 bool needMore
= SendIdleEvents();
455 event
.RequestMore(TRUE
);
460 bool wxApp::SendIdleEvents()
462 bool needMore
= FALSE
;
464 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
467 wxWindow
* win
= node
->GetData();
468 if (SendIdleEvents(win
))
470 node
= node
->GetNext();
476 bool wxApp::SendIdleEvents( wxWindow
* win
)
478 bool needMore
= FALSE
;
481 event
.SetEventObject(win
);
483 win
->GetEventHandler()->ProcessEvent(event
);
485 win
->OnInternalIdle();
487 if (event
.MoreRequested())
490 wxNode
* node
= win
->GetChildren().First();
493 wxWindow
* win
= (wxWindow
*) node
->Data();
494 if (SendIdleEvents(win
))
502 int wxApp::MainLoop()
508 void wxApp::ExitMainLoop()
510 if (gtk_main_level() > 0)
514 bool wxApp::Initialized()
516 return m_initialized
;
519 bool wxApp::Pending()
521 return (gtk_events_pending() > 0);
524 void wxApp::Dispatch()
526 gtk_main_iteration();
529 void wxApp::DeletePendingObjects()
531 wxNode
*node
= wxPendingDelete
.First();
534 wxObject
*obj
= (wxObject
*)node
->Data();
538 if (wxPendingDelete
.Find(obj
))
541 node
= wxPendingDelete
.First();
545 bool wxApp::Initialize()
547 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
549 wxClassInfo::InitializeClasses();
551 wxSystemSettings::Init();
553 // GL: I'm annoyed ... I don't know where to put this and I don't want to
554 // create a module for that as it's part of the core.
556 wxPendingEvents
= new wxList();
557 wxPendingEventsLocker
= new wxCriticalSection();
560 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
561 wxTheColourDatabase
->Initialize();
563 wxInitializeStockLists();
564 wxInitializeStockObjects();
566 #if wxUSE_WX_RESOURCES
567 wxInitializeResourceSystem();
570 wxModule::RegisterModules();
571 if (!wxModule::InitializeModules()) return FALSE
;
576 void wxApp::CleanUp()
578 wxModule::CleanUpModules();
580 #if wxUSE_WX_RESOURCES
581 wxCleanUpResourceSystem();
584 if (wxTheColourDatabase
)
585 delete wxTheColourDatabase
;
587 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
589 wxDeleteStockObjects();
591 wxDeleteStockLists();
594 wxTheApp
= (wxApp
*) NULL
;
596 // GL: I'm annoyed ... I don't know where to put this and I don't want to
597 // create a module for that as it's part of the core.
599 delete wxPendingEvents
;
600 delete wxPendingEventsLocker
;
603 wxSystemSettings::Done();
607 wxClassInfo::CleanUpClasses();
609 // check for memory leaks
610 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
611 if (wxDebugContext::CountObjectsLeft(TRUE
) > 0)
613 wxLogDebug(wxT("There were memory leaks.\n"));
614 wxDebugContext::Dump();
615 wxDebugContext::PrintStatistics();
620 // do this as the very last thing because everything else can log messages
621 wxLog::DontCreateOnDemand();
623 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
629 //-----------------------------------------------------------------------------
631 //-----------------------------------------------------------------------------
634 int wxEntryStart( int argc
, char *argv
[] )
637 /* GTK 1.2 up to version 1.2.3 has broken threads */
638 if ((gtk_major_version
== 1) &&
639 (gtk_minor_version
== 2) &&
640 (gtk_micro_version
< 4))
642 printf( "wxWindows warning: GUI threading disabled due to outdated GTK version\n" );
652 // We should have the wxUSE_WCHAR_T test on the _outside_
654 #if defined(__WXGTK20__)
655 // gtk+ 2.0 supports Unicode through UTF-8 strings
656 wxConvCurrent
= &wxConvUTF8
;
658 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
661 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
666 gtk_init( &argc
, &argv
);
668 wxSetDetectableAutoRepeat( TRUE
);
670 if (!wxApp::Initialize())
683 if ( !wxTheApp
->OnInitGui() )
686 wxRootWindow
= gtk_window_new( GTK_WINDOW_TOPLEVEL
);
687 gtk_widget_realize( wxRootWindow
);
693 void wxEntryCleanup()
696 // flush the logged messages if any
697 wxLog
*log
= wxLog::GetActiveTarget();
698 if (log
!= NULL
&& log
->HasPendingMessages())
701 // continuing to use user defined log target is unsafe from now on because
702 // some resources may be already unavailable, so replace it by something
704 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);
716 int wxEntry( int argc
, char *argv
[] )
718 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
719 // This seems to be necessary since there are 'rogue'
720 // objects present at this point (perhaps global objects?)
721 // Setting a checkpoint will ignore them as far as the
722 // memory checking facility is concerned.
723 // Of course you may argue that memory allocated in globals should be
724 // checked, but this is a reasonable compromise.
725 wxDebugContext::SetCheckpoint();
727 int err
= wxEntryStart(argc
, argv
);
733 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
734 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
736 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
738 wxObject
*test_app
= app_ini();
740 wxTheApp
= (wxApp
*) test_app
;
743 wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") );
745 wxTheApp
->argc
= argc
;
747 wxTheApp
->argv
= new wxChar
*[argc
+1];
749 while (mb_argc
< argc
)
751 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
754 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
756 wxTheApp
->argv
= argv
;
759 wxString
name(wxFileNameFromPath(argv
[0]));
760 wxStripExtension( name
);
761 wxTheApp
->SetAppName( name
);
764 retValue
= wxEntryInitGui();
766 // Here frames insert themselves automatically into wxTopLevelWindows by
767 // getting created in OnInit().
770 if ( !wxTheApp
->OnInit() )
776 /* delete pending toplevel windows (typically a single
777 dialog) so that, if there isn't any left, we don't
779 wxTheApp
->DeletePendingObjects();
781 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
783 if (wxTheApp
->Initialized())
787 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
790 /* Forcibly delete the window. */
791 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
792 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
794 topWindow
->Close( TRUE
);
795 wxTheApp
->DeletePendingObjects();
800 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
804 retValue
= wxTheApp
->OnExit();
813 #include "wx/gtk/info.xpm"
814 #include "wx/gtk/error.xpm"
815 #include "wx/gtk/question.xpm"
816 #include "wx/gtk/warning.xpm"
819 wxApp::GetStdIcon(int which
) const
823 case wxICON_INFORMATION
:
824 return wxIcon(info_xpm
);
826 case wxICON_QUESTION
:
827 return wxIcon(question_xpm
);
829 case wxICON_EXCLAMATION
:
830 return wxIcon(warning_xpm
);
833 wxFAIL_MSG(wxT("requested non existent standard icon"));
834 // still fall through
837 return wxIcon(error_xpm
);