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())
96 /* it's necessary to call ProcessIdle() to update the frames sizes which
97 might have been changed (it also will update other things set from
98 OnUpdateUI() which is a nice (and desired) side effect) */
99 while (wxTheApp
->ProcessIdle()) { }
103 /* re-add idle handler */
104 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
110 //-----------------------------------------------------------------------------
112 //-----------------------------------------------------------------------------
117 if (!wxThread::IsMain())
122 wxapp_install_idle_handler();
125 if (!wxThread::IsMain())
130 //-----------------------------------------------------------------------------
132 //-----------------------------------------------------------------------------
134 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
136 if (!wxTheApp
) return TRUE
;
138 // when getting called from GDK's time-out handler
139 // we are no longer within GDK's grab on the GUI
140 // thread so we must lock it here ourselves
143 /* we don't want any more idle events until the next event is
145 gtk_idle_remove( wxTheApp
->m_idleTag
);
146 wxTheApp
->m_idleTag
= 0;
148 /* indicate that we are now in idle mode - even so deeply
149 in idle mode that we don't get any idle events anymore.
150 this is like wxMSW where an idle event is sent only
151 once each time after the event queue has been completely
155 /* sent idle event to all who request them */
156 while (wxTheApp
->ProcessIdle()) { }
158 // release lock again
164 void wxapp_install_idle_handler()
166 wxASSERT_MSG( wxTheApp
->m_idleTag
== 0, wxT("attempt to install idle handler twice") );
168 /* This routine gets called by all event handlers
169 indicating that the idle is over. It may also
170 get called from other thread for sending events
171 to the main thread (and processing these in
174 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
181 void wxapp_install_thread_wakeup()
183 if (wxTheApp
->m_wakeUpTimerTag
) return;
185 wxTheApp
->m_wakeUpTimerTag
= gtk_timeout_add( 50, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
188 void wxapp_uninstall_thread_wakeup()
190 if (!wxTheApp
->m_wakeUpTimerTag
) return;
192 gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag
);
193 wxTheApp
->m_wakeUpTimerTag
= 0;
196 gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) )
198 // when getting called from GDK's time-out handler
199 // we are no longer within GDK's grab on the GUI
200 // thread so we must lock it here ourselves
203 wxapp_uninstall_thread_wakeup();
205 // unblock other threads wishing to do some GUI things
208 g_mainThreadLocked
= TRUE
;
210 // wake up other threads
213 // block other thread again
216 g_mainThreadLocked
= FALSE
;
218 wxapp_install_thread_wakeup();
220 // release lock again
226 #endif // wxUSE_THREADS
228 //-----------------------------------------------------------------------------
230 //-----------------------------------------------------------------------------
232 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
234 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
235 EVT_IDLE(wxApp::OnIdle
)
242 m_topWindow
= (wxWindow
*) NULL
;
243 m_exitOnFrameDelete
= TRUE
;
245 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
248 m_wakeUpTimerTag
= 0;
249 wxapp_install_thread_wakeup();
252 m_colorCube
= (unsigned char*) NULL
;
254 m_useBestVisual
= FALSE
;
259 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
262 wxapp_uninstall_thread_wakeup();
265 if (m_colorCube
) free(m_colorCube
);
268 bool wxApp::OnInitGui()
270 GdkVisual
*visual
= gdk_visual_get_system();
272 /* on some machines, the default visual is just 256 colours, so
273 we make sure we get the best. this can sometimes be wasteful,
274 of course, but what do these guys pay $30.000 for? */
276 if ((gdk_visual_get_best() != gdk_visual_get_system()) &&
279 GdkVisual
* vis
= gdk_visual_get_best();
280 gtk_widget_set_default_visual( vis
);
282 GdkColormap
*colormap
= gdk_colormap_new( vis
, FALSE
);
283 gtk_widget_set_default_colormap( colormap
);
288 /* Nothing to do for 15, 16, 24, 32 bit displays */
289 if (visual
->depth
> 8) return TRUE
;
291 /* initialize color cube for 8-bit color reduction dithering */
293 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
295 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
297 for (int r
= 0; r
< 32; r
++)
299 for (int g
= 0; g
< 32; g
++)
301 for (int b
= 0; b
< 32; b
++)
303 int rr
= (r
<< 3) | (r
>> 2);
304 int gg
= (g
<< 3) | (g
>> 2);
305 int bb
= (b
<< 3) | (b
>> 2);
309 GdkColor
*colors
= cmap
->colors
;
314 for (int i
= 0; i
< cmap
->size
; i
++)
316 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
317 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
318 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
319 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
322 index
= i
; max
= sum
;
328 #if (GTK_MINOR_VERSION > 0)
329 /* assume 8-bit true or static colors. this really
331 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
332 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
333 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
334 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
336 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
339 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
347 bool wxApp::ProcessIdle()
350 event
.SetEventObject( this );
351 ProcessEvent( event
);
353 return event
.MoreRequested();
356 void wxApp::OnIdle( wxIdleEvent
&event
)
358 static bool s_inOnIdle
= FALSE
;
360 /* Avoid recursion (via ProcessEvent default case) */
366 /* Resend in the main thread events which have been prepared in other
368 ProcessPendingEvents();
370 /* 'Garbage' collection of windows deleted with Close(). */
371 DeletePendingObjects();
373 /* Send OnIdle events to all windows */
374 bool needMore
= SendIdleEvents();
377 event
.RequestMore(TRUE
);
381 /* flush the logged messages if any */
383 wxLog
*log
= wxLog::GetActiveTarget();
384 if (log
!= NULL
&& log
->HasPendingMessages())
389 bool wxApp::SendIdleEvents()
391 bool needMore
= FALSE
;
393 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
396 wxWindow
* win
= node
->GetData();
397 if (SendIdleEvents(win
))
399 node
= node
->GetNext();
405 bool wxApp::SendIdleEvents( wxWindow
* win
)
407 bool needMore
= FALSE
;
410 event
.SetEventObject(win
);
412 win
->ProcessEvent(event
);
414 win
->OnInternalIdle();
416 if (event
.MoreRequested())
419 wxNode
* node
= win
->GetChildren().First();
422 wxWindow
* win
= (wxWindow
*) node
->Data();
423 if (SendIdleEvents(win
))
431 int wxApp::MainLoop()
437 void wxApp::ExitMainLoop()
439 if (gtk_main_level() > 0)
443 bool wxApp::Initialized()
445 return m_initialized
;
448 bool wxApp::Pending()
450 return (gtk_events_pending() > 0);
453 void wxApp::Dispatch()
455 gtk_main_iteration();
458 void wxApp::DeletePendingObjects()
460 wxNode
*node
= wxPendingDelete
.First();
463 wxObject
*obj
= (wxObject
*)node
->Data();
467 if (wxPendingDelete
.Find(obj
))
470 node
= wxPendingDelete
.First();
474 bool wxApp::Initialize()
476 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
478 wxClassInfo::InitializeClasses();
480 wxSystemSettings::Init();
482 // GL: I'm annoyed ... I don't know where to put this and I don't want to
483 // create a module for that as it's part of the core.
485 wxPendingEvents
= new wxList();
486 wxPendingEventsLocker
= new wxCriticalSection();
489 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
490 wxTheColourDatabase
->Initialize();
492 wxInitializeStockLists();
493 wxInitializeStockObjects();
495 #if wxUSE_WX_RESOURCES
496 wxInitializeResourceSystem();
499 wxModule::RegisterModules();
500 if (!wxModule::InitializeModules()) return FALSE
;
505 void wxApp::CleanUp()
507 wxModule::CleanUpModules();
509 #if wxUSE_WX_RESOURCES
510 wxCleanUpResourceSystem();
513 if (wxTheColourDatabase
)
514 delete wxTheColourDatabase
;
516 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
518 wxDeleteStockObjects();
520 wxDeleteStockLists();
523 wxTheApp
= (wxApp
*) NULL
;
525 // GL: I'm annoyed ... I don't know where to put this and I don't want to
526 // create a module for that as it's part of the core.
528 delete wxPendingEvents
;
529 delete wxPendingEventsLocker
;
532 wxSystemSettings::Done();
536 wxClassInfo::CleanUpClasses();
538 // check for memory leaks
539 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
540 if (wxDebugContext::CountObjectsLeft() > 0)
542 wxLogDebug(wxT("There were memory leaks.\n"));
543 wxDebugContext::Dump();
544 wxDebugContext::PrintStatistics();
549 // do this as the very last thing because everything else can log messages
550 wxLog::DontCreateOnDemand();
552 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
558 //-----------------------------------------------------------------------------
560 //-----------------------------------------------------------------------------
562 int wxEntry( int argc
, char *argv
[] )
565 /* GTK 1.2 up to version 1.2.3 has broken threads */
566 if ((gtk_major_version
== 1) &&
567 (gtk_minor_version
== 2) &&
568 (gtk_micro_version
< 4))
570 printf( "wxWindows warning: Disabled GUI threading due to outdated GTK version\n" );
581 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
583 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
588 gtk_init( &argc
, &argv
);
590 wxSetDetectableAutoRepeat( TRUE
);
592 if (!wxApp::Initialize())
600 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
601 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
603 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
605 wxObject
*test_app
= app_ini();
607 wxTheApp
= (wxApp
*) test_app
;
610 wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") );
612 wxTheApp
->argc
= argc
;
614 wxTheApp
->argv
= new wxChar
*[argc
+1];
616 while (mb_argc
< argc
)
618 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
621 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
623 wxTheApp
->argv
= argv
;
626 wxString
name(wxFileNameFromPath(argv
[0]));
627 wxStripExtension( name
);
628 wxTheApp
->SetAppName( name
);
632 if ( !wxTheApp
->OnInitGui() )
635 wxRootWindow
= gtk_window_new( GTK_WINDOW_TOPLEVEL
);
636 gtk_widget_realize( wxRootWindow
);
638 // Here frames insert themselves automatically into wxTopLevelWindows by
639 // getting created in OnInit().
642 if ( !wxTheApp
->OnInit() )
648 /* delete pending toplevel windows (typically a single
649 dialog) so that, if there isn't any left, we don't
651 wxTheApp
->DeletePendingObjects();
653 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
655 if (wxTheApp
->Initialized())
657 retValue
= wxTheApp
->OnRun();
659 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
662 /* Forcibly delete the window. */
663 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
664 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
666 topWindow
->Close( TRUE
);
667 wxTheApp
->DeletePendingObjects();
672 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
680 // flush the logged messages if any
681 wxLog
*log
= wxLog::GetActiveTarget();
682 if (log
!= NULL
&& log
->HasPendingMessages())
685 // continuing to use user defined log target is unsafe from now on because
686 // some resources may be already unavailable, so replace it by something
688 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);
700 #include "wx/gtk/info.xpm"
701 #include "wx/gtk/error.xpm"
702 #include "wx/gtk/question.xpm"
703 #include "wx/gtk/warning.xpm"
706 wxApp::GetStdIcon(int which
) const
710 case wxICON_INFORMATION
:
711 return wxIcon(info_xpm
);
713 case wxICON_QUESTION
:
714 return wxIcon(question_xpm
);
716 case wxICON_EXCLAMATION
:
717 return wxIcon(warning_xpm
);
720 wxFAIL_MSG(wxT("requested non existent standard icon"));
721 // still fall through
724 return wxIcon(error_xpm
);