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
;
54 GtkWidget
*wxRootWindow
= (GtkWidget
*) NULL
;
56 //-----------------------------------------------------------------------------
58 //-----------------------------------------------------------------------------
60 /* forward declaration */
61 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) );
62 void wxapp_install_idle_handler();
65 gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) );
68 //-----------------------------------------------------------------------------
70 //-----------------------------------------------------------------------------
77 //-----------------------------------------------------------------------------
79 //-----------------------------------------------------------------------------
83 bool has_idle
= (wxTheApp
->m_idleTag
!= 0);
87 /* We need to temporarily remove idle callbacks or the loop will
89 gtk_idle_remove( wxTheApp
->m_idleTag
);
90 wxTheApp
->m_idleTag
= 0;
93 while (gtk_events_pending())
98 /* re-add idle handler (very low priority) */
99 wxTheApp
->m_idleTag
= gtk_idle_add_priority( 1000, wxapp_idle_callback
, (gpointer
) NULL
);
102 // disable log flushing from here because a call to wxYield() shouldn't
103 // normally result in message boxes popping up &c
106 /* it's necessary to call ProcessIdle() to update the frames sizes which
107 might have been changed (it also will update other things set from
108 OnUpdateUI() which is a nice (and desired) side effect) */
109 while (wxTheApp
->ProcessIdle())
112 // let the logs be flashed again
118 //-----------------------------------------------------------------------------
120 //-----------------------------------------------------------------------------
125 if (!wxThread::IsMain())
130 wxapp_install_idle_handler();
133 if (!wxThread::IsMain())
138 //-----------------------------------------------------------------------------
140 //-----------------------------------------------------------------------------
142 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
144 if (!wxTheApp
) return TRUE
;
146 // when getting called from GDK's time-out handler
147 // we are no longer within GDK's grab on the GUI
148 // thread so we must lock it here ourselves
151 /* we don't want any more idle events until the next event is
153 gtk_idle_remove( wxTheApp
->m_idleTag
);
154 wxTheApp
->m_idleTag
= 0;
156 /* indicate that we are now in idle mode - even so deeply
157 in idle mode that we don't get any idle events anymore.
158 this is like wxMSW where an idle event is sent only
159 once each time after the event queue has been completely
163 /* sent idle event to all who request them */
164 while (wxTheApp
->ProcessIdle()) { }
166 // release lock again
172 void wxapp_install_idle_handler()
174 wxASSERT_MSG( wxTheApp
->m_idleTag
== 0, wxT("attempt to install idle handler twice") );
176 /* This routine gets called by all event handlers
177 indicating that the idle is over. It may also
178 get called from other thread for sending events
179 to the main thread (and processing these in
180 idle time). Very low priority. */
182 wxTheApp
->m_idleTag
= gtk_idle_add_priority( 1000, wxapp_idle_callback
, (gpointer
) NULL
);
189 void wxapp_install_thread_wakeup()
191 if (wxTheApp
->m_wakeUpTimerTag
) return;
193 wxTheApp
->m_wakeUpTimerTag
= gtk_timeout_add( 50, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
196 void wxapp_uninstall_thread_wakeup()
198 if (!wxTheApp
->m_wakeUpTimerTag
) return;
200 gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag
);
201 wxTheApp
->m_wakeUpTimerTag
= 0;
204 gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) )
206 // when getting called from GDK's time-out handler
207 // we are no longer within GDK's grab on the GUI
208 // thread so we must lock it here ourselves
211 wxapp_uninstall_thread_wakeup();
213 // unblock other threads wishing to do some GUI things
216 g_mainThreadLocked
= TRUE
;
218 // wake up other threads
221 // block other thread again
224 g_mainThreadLocked
= FALSE
;
226 wxapp_install_thread_wakeup();
228 // release lock again
234 #endif // wxUSE_THREADS
236 //-----------------------------------------------------------------------------
238 //-----------------------------------------------------------------------------
240 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
242 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
243 EVT_IDLE(wxApp::OnIdle
)
250 m_topWindow
= (wxWindow
*) NULL
;
251 m_exitOnFrameDelete
= TRUE
;
253 m_idleTag
= gtk_idle_add_priority( 1000, wxapp_idle_callback
, (gpointer
) NULL
);
256 m_wakeUpTimerTag
= 0;
257 wxapp_install_thread_wakeup();
260 m_colorCube
= (unsigned char*) NULL
;
262 m_useBestVisual
= FALSE
;
267 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
270 wxapp_uninstall_thread_wakeup();
273 if (m_colorCube
) free(m_colorCube
);
276 bool wxApp::OnInitGui()
278 GdkVisual
*visual
= gdk_visual_get_system();
280 /* on some machines, the default visual is just 256 colours, so
281 we make sure we get the best. this can sometimes be wasteful,
282 of course, but what do these guys pay $30.000 for? */
284 if ((gdk_visual_get_best() != gdk_visual_get_system()) &&
288 /* seems gtk_widget_set_default_visual no longer exists? */
289 GdkVisual
* vis
= gtk_widget_get_default_visual();
291 GdkVisual
* vis
= gdk_visual_get_best();
292 gtk_widget_set_default_visual( vis
);
295 GdkColormap
*colormap
= gdk_colormap_new( vis
, FALSE
);
296 gtk_widget_set_default_colormap( colormap
);
301 /* Nothing to do for 15, 16, 24, 32 bit displays */
302 if (visual
->depth
> 8) return TRUE
;
304 /* initialize color cube for 8-bit color reduction dithering */
306 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
308 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
310 for (int r
= 0; r
< 32; r
++)
312 for (int g
= 0; g
< 32; g
++)
314 for (int b
= 0; b
< 32; b
++)
316 int rr
= (r
<< 3) | (r
>> 2);
317 int gg
= (g
<< 3) | (g
>> 2);
318 int bb
= (b
<< 3) | (b
>> 2);
322 GdkColor
*colors
= cmap
->colors
;
327 for (int i
= 0; i
< cmap
->size
; i
++)
329 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
330 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
331 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
332 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
335 index
= i
; max
= sum
;
341 #if (GTK_MINOR_VERSION > 0)
342 /* assume 8-bit true or static colors. this really
344 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
345 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
346 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
347 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
349 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
352 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
360 bool wxApp::ProcessIdle()
363 event
.SetEventObject( this );
364 ProcessEvent( event
);
366 return event
.MoreRequested();
369 void wxApp::OnIdle( wxIdleEvent
&event
)
371 static bool s_inOnIdle
= FALSE
;
373 /* Avoid recursion (via ProcessEvent default case) */
379 /* Resend in the main thread events which have been prepared in other
381 ProcessPendingEvents();
383 /* 'Garbage' collection of windows deleted with Close(). */
384 DeletePendingObjects();
386 /* Send OnIdle events to all windows */
387 bool needMore
= SendIdleEvents();
390 event
.RequestMore(TRUE
);
394 /* flush the logged messages if any */
396 wxLog::FlushActive();
400 bool wxApp::SendIdleEvents()
402 bool needMore
= FALSE
;
404 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
407 wxWindow
* win
= node
->GetData();
408 if (SendIdleEvents(win
))
410 node
= node
->GetNext();
416 bool wxApp::SendIdleEvents( wxWindow
* win
)
418 bool needMore
= FALSE
;
421 event
.SetEventObject(win
);
423 win
->GetEventHandler()->ProcessEvent(event
);
425 win
->OnInternalIdle();
427 if (event
.MoreRequested())
430 wxNode
* node
= win
->GetChildren().First();
433 wxWindow
* win
= (wxWindow
*) node
->Data();
434 if (SendIdleEvents(win
))
442 int wxApp::MainLoop()
448 void wxApp::ExitMainLoop()
450 if (gtk_main_level() > 0)
454 bool wxApp::Initialized()
456 return m_initialized
;
459 bool wxApp::Pending()
461 return (gtk_events_pending() > 0);
464 void wxApp::Dispatch()
466 gtk_main_iteration();
469 void wxApp::DeletePendingObjects()
471 wxNode
*node
= wxPendingDelete
.First();
474 wxObject
*obj
= (wxObject
*)node
->Data();
478 if (wxPendingDelete
.Find(obj
))
481 node
= wxPendingDelete
.First();
485 bool wxApp::Initialize()
487 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
489 wxClassInfo::InitializeClasses();
491 wxSystemSettings::Init();
493 // GL: I'm annoyed ... I don't know where to put this and I don't want to
494 // create a module for that as it's part of the core.
496 wxPendingEvents
= new wxList();
497 wxPendingEventsLocker
= new wxCriticalSection();
500 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
501 wxTheColourDatabase
->Initialize();
503 wxInitializeStockLists();
504 wxInitializeStockObjects();
506 #if wxUSE_WX_RESOURCES
507 wxInitializeResourceSystem();
510 wxModule::RegisterModules();
511 if (!wxModule::InitializeModules()) return FALSE
;
516 void wxApp::CleanUp()
518 wxModule::CleanUpModules();
520 #if wxUSE_WX_RESOURCES
521 wxCleanUpResourceSystem();
524 if (wxTheColourDatabase
)
525 delete wxTheColourDatabase
;
527 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
529 wxDeleteStockObjects();
531 wxDeleteStockLists();
534 wxTheApp
= (wxApp
*) NULL
;
536 // GL: I'm annoyed ... I don't know where to put this and I don't want to
537 // create a module for that as it's part of the core.
539 delete wxPendingEvents
;
540 delete wxPendingEventsLocker
;
543 wxSystemSettings::Done();
547 wxClassInfo::CleanUpClasses();
549 // check for memory leaks
550 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
551 if (wxDebugContext::CountObjectsLeft() > 0)
553 wxLogDebug(wxT("There were memory leaks.\n"));
554 wxDebugContext::Dump();
555 wxDebugContext::PrintStatistics();
560 // do this as the very last thing because everything else can log messages
561 wxLog::DontCreateOnDemand();
563 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
569 //-----------------------------------------------------------------------------
571 //-----------------------------------------------------------------------------
574 int wxEntryStart( int argc
, char *argv
[] )
577 /* GTK 1.2 up to version 1.2.3 has broken threads */
578 if ((gtk_major_version
== 1) &&
579 (gtk_minor_version
== 2) &&
580 (gtk_micro_version
< 4))
582 printf( "wxWindows warning: GUI threading disabled due to outdated GTK version\n" );
592 #if defined(__WXGTK20__)
593 // gtk+ 2.0 supports Unicode through UTF-8 strings
594 wxConvCurrent
= &wxConvUTF8
;
596 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
598 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
603 gtk_init( &argc
, &argv
);
605 wxSetDetectableAutoRepeat( TRUE
);
607 if (!wxApp::Initialize())
621 if ( !wxTheApp
->OnInitGui() )
624 wxRootWindow
= gtk_window_new( GTK_WINDOW_TOPLEVEL
);
625 gtk_widget_realize( wxRootWindow
);
631 void wxEntryCleanup()
634 // flush the logged messages if any
635 wxLog
*log
= wxLog::GetActiveTarget();
636 if (log
!= NULL
&& log
->HasPendingMessages())
639 // continuing to use user defined log target is unsafe from now on because
640 // some resources may be already unavailable, so replace it by something
642 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);
654 int wxEntry( int argc
, char *argv
[] )
656 int err
= wxEntryStart(argc
, argv
);
662 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
663 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
665 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
667 wxObject
*test_app
= app_ini();
669 wxTheApp
= (wxApp
*) test_app
;
672 wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") );
674 wxTheApp
->argc
= argc
;
676 wxTheApp
->argv
= new wxChar
*[argc
+1];
678 while (mb_argc
< argc
)
680 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
683 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
685 wxTheApp
->argv
= argv
;
688 wxString
name(wxFileNameFromPath(argv
[0]));
689 wxStripExtension( name
);
690 wxTheApp
->SetAppName( name
);
693 retValue
= wxEntryInitGui();
695 // Here frames insert themselves automatically into wxTopLevelWindows by
696 // getting created in OnInit().
699 if ( !wxTheApp
->OnInit() )
705 /* delete pending toplevel windows (typically a single
706 dialog) so that, if there isn't any left, we don't
708 wxTheApp
->DeletePendingObjects();
710 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
712 if (wxTheApp
->Initialized())
716 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
719 /* Forcibly delete the window. */
720 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
721 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
723 topWindow
->Close( TRUE
);
724 wxTheApp
->DeletePendingObjects();
729 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
733 retValue
= wxTheApp
->OnExit();
742 #include "wx/gtk/info.xpm"
743 #include "wx/gtk/error.xpm"
744 #include "wx/gtk/question.xpm"
745 #include "wx/gtk/warning.xpm"
748 wxApp::GetStdIcon(int which
) const
752 case wxICON_INFORMATION
:
753 return wxIcon(info_xpm
);
755 case wxICON_QUESTION
:
756 return wxIcon(question_xpm
);
758 case wxICON_EXCLAMATION
:
759 return wxIcon(warning_xpm
);
762 wxFAIL_MSG(wxT("requested non existent standard icon"));
763 // still fall through
766 return wxIcon(error_xpm
);