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
;
292 m_idleTag
= gtk_idle_add_priority( 1000, wxapp_idle_callback
, (gpointer
) NULL
);
295 m_wakeUpTimerTag
= 0;
296 wxapp_install_thread_wakeup();
299 m_colorCube
= (unsigned char*) NULL
;
301 m_useBestVisual
= FALSE
;
306 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
309 wxapp_uninstall_thread_wakeup();
312 if (m_colorCube
) free(m_colorCube
);
315 bool wxApp::OnInitGui()
317 GdkVisual
*visual
= gdk_visual_get_system();
319 /* on some machines, the default visual is just 256 colours, so
320 we make sure we get the best. this can sometimes be wasteful,
321 of course, but what do these guys pay $30.000 for? */
323 if ((gdk_visual_get_best() != gdk_visual_get_system()) &&
327 /* seems gtk_widget_set_default_visual no longer exists? */
328 GdkVisual
* vis
= gtk_widget_get_default_visual();
330 GdkVisual
* vis
= gdk_visual_get_best();
331 gtk_widget_set_default_visual( vis
);
334 GdkColormap
*colormap
= gdk_colormap_new( vis
, FALSE
);
335 gtk_widget_set_default_colormap( colormap
);
340 /* Nothing to do for 15, 16, 24, 32 bit displays */
341 if (visual
->depth
> 8) return TRUE
;
343 /* initialize color cube for 8-bit color reduction dithering */
345 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
347 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
349 for (int r
= 0; r
< 32; r
++)
351 for (int g
= 0; g
< 32; g
++)
353 for (int b
= 0; b
< 32; b
++)
355 int rr
= (r
<< 3) | (r
>> 2);
356 int gg
= (g
<< 3) | (g
>> 2);
357 int bb
= (b
<< 3) | (b
>> 2);
361 GdkColor
*colors
= cmap
->colors
;
366 for (int i
= 0; i
< cmap
->size
; i
++)
368 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
369 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
370 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
371 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
374 index
= i
; max
= sum
;
380 #if (GTK_MINOR_VERSION > 0)
381 /* assume 8-bit true or static colors. this really
383 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
384 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
385 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
386 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
388 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
391 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
399 bool wxApp::ProcessIdle()
402 event
.SetEventObject( this );
403 ProcessEvent( event
);
405 return event
.MoreRequested();
408 void wxApp::OnIdle( wxIdleEvent
&event
)
410 static bool s_inOnIdle
= FALSE
;
412 /* Avoid recursion (via ProcessEvent default case) */
418 /* Resend in the main thread events which have been prepared in other
420 ProcessPendingEvents();
422 /* 'Garbage' collection of windows deleted with Close(). */
423 DeletePendingObjects();
425 /* Send OnIdle events to all windows */
426 bool needMore
= SendIdleEvents();
429 event
.RequestMore(TRUE
);
434 bool wxApp::SendIdleEvents()
436 bool needMore
= FALSE
;
438 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
441 wxWindow
* win
= node
->GetData();
442 if (SendIdleEvents(win
))
444 node
= node
->GetNext();
450 bool wxApp::SendIdleEvents( wxWindow
* win
)
452 bool needMore
= FALSE
;
455 event
.SetEventObject(win
);
457 win
->GetEventHandler()->ProcessEvent(event
);
459 win
->OnInternalIdle();
461 if (event
.MoreRequested())
464 wxNode
* node
= win
->GetChildren().First();
467 wxWindow
* win
= (wxWindow
*) node
->Data();
468 if (SendIdleEvents(win
))
476 int wxApp::MainLoop()
482 void wxApp::ExitMainLoop()
484 if (gtk_main_level() > 0)
488 bool wxApp::Initialized()
490 return m_initialized
;
493 bool wxApp::Pending()
495 return (gtk_events_pending() > 0);
498 void wxApp::Dispatch()
500 gtk_main_iteration();
503 void wxApp::DeletePendingObjects()
505 wxNode
*node
= wxPendingDelete
.First();
508 wxObject
*obj
= (wxObject
*)node
->Data();
512 if (wxPendingDelete
.Find(obj
))
515 node
= wxPendingDelete
.First();
519 bool wxApp::Initialize()
521 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
523 wxClassInfo::InitializeClasses();
525 wxSystemSettings::Init();
527 // GL: I'm annoyed ... I don't know where to put this and I don't want to
528 // create a module for that as it's part of the core.
530 wxPendingEvents
= new wxList();
531 wxPendingEventsLocker
= new wxCriticalSection();
534 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
535 wxTheColourDatabase
->Initialize();
537 wxInitializeStockLists();
538 wxInitializeStockObjects();
540 #if wxUSE_WX_RESOURCES
541 wxInitializeResourceSystem();
544 wxModule::RegisterModules();
545 if (!wxModule::InitializeModules()) return FALSE
;
550 void wxApp::CleanUp()
552 wxModule::CleanUpModules();
554 #if wxUSE_WX_RESOURCES
555 wxCleanUpResourceSystem();
558 if (wxTheColourDatabase
)
559 delete wxTheColourDatabase
;
561 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
563 wxDeleteStockObjects();
565 wxDeleteStockLists();
568 wxTheApp
= (wxApp
*) NULL
;
570 // GL: I'm annoyed ... I don't know where to put this and I don't want to
571 // create a module for that as it's part of the core.
573 delete wxPendingEvents
;
574 delete wxPendingEventsLocker
;
577 wxSystemSettings::Done();
581 wxClassInfo::CleanUpClasses();
583 // check for memory leaks
584 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
585 if (wxDebugContext::CountObjectsLeft(TRUE
) > 0)
587 wxLogDebug(wxT("There were memory leaks.\n"));
588 wxDebugContext::Dump();
589 wxDebugContext::PrintStatistics();
594 // do this as the very last thing because everything else can log messages
595 wxLog::DontCreateOnDemand();
597 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
603 //-----------------------------------------------------------------------------
605 //-----------------------------------------------------------------------------
608 int wxEntryStart( int argc
, char *argv
[] )
611 /* GTK 1.2 up to version 1.2.3 has broken threads */
612 if ((gtk_major_version
== 1) &&
613 (gtk_minor_version
== 2) &&
614 (gtk_micro_version
< 4))
616 printf( "wxWindows warning: GUI threading disabled due to outdated GTK version\n" );
626 #if defined(__WXGTK20__)
627 // gtk+ 2.0 supports Unicode through UTF-8 strings
628 wxConvCurrent
= &wxConvUTF8
;
630 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
632 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
637 gtk_init( &argc
, &argv
);
639 wxSetDetectableAutoRepeat( TRUE
);
641 if (!wxApp::Initialize())
655 if ( !wxTheApp
->OnInitGui() )
658 wxRootWindow
= gtk_window_new( GTK_WINDOW_TOPLEVEL
);
659 gtk_widget_realize( wxRootWindow
);
665 void wxEntryCleanup()
668 // flush the logged messages if any
669 wxLog
*log
= wxLog::GetActiveTarget();
670 if (log
!= NULL
&& log
->HasPendingMessages())
673 // continuing to use user defined log target is unsafe from now on because
674 // some resources may be already unavailable, so replace it by something
676 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);
688 int wxEntry( int argc
, char *argv
[] )
690 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
691 // This seems to be necessary since there are 'rogue'
692 // objects present at this point (perhaps global objects?)
693 // Setting a checkpoint will ignore them as far as the
694 // memory checking facility is concerned.
695 // Of course you may argue that memory allocated in globals should be
696 // checked, but this is a reasonable compromise.
697 wxDebugContext::SetCheckpoint();
699 int err
= wxEntryStart(argc
, argv
);
705 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
706 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
708 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
710 wxObject
*test_app
= app_ini();
712 wxTheApp
= (wxApp
*) test_app
;
715 wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") );
717 wxTheApp
->argc
= argc
;
719 wxTheApp
->argv
= new wxChar
*[argc
+1];
721 while (mb_argc
< argc
)
723 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
726 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
728 wxTheApp
->argv
= argv
;
731 wxString
name(wxFileNameFromPath(argv
[0]));
732 wxStripExtension( name
);
733 wxTheApp
->SetAppName( name
);
736 retValue
= wxEntryInitGui();
738 // Here frames insert themselves automatically into wxTopLevelWindows by
739 // getting created in OnInit().
742 if ( !wxTheApp
->OnInit() )
748 /* delete pending toplevel windows (typically a single
749 dialog) so that, if there isn't any left, we don't
751 wxTheApp
->DeletePendingObjects();
753 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
755 if (wxTheApp
->Initialized())
759 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
762 /* Forcibly delete the window. */
763 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
764 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
766 topWindow
->Close( TRUE
);
767 wxTheApp
->DeletePendingObjects();
772 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
776 retValue
= wxTheApp
->OnExit();
785 #include "wx/gtk/info.xpm"
786 #include "wx/gtk/error.xpm"
787 #include "wx/gtk/question.xpm"
788 #include "wx/gtk/warning.xpm"
791 wxApp::GetStdIcon(int which
) const
795 case wxICON_INFORMATION
:
796 return wxIcon(info_xpm
);
798 case wxICON_QUESTION
:
799 return wxIcon(question_xpm
);
801 case wxICON_EXCLAMATION
:
802 return wxIcon(warning_xpm
);
805 wxFAIL_MSG(wxT("requested non existent standard icon"));
806 // still fall through
809 return wxIcon(error_xpm
);