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 wxRootWindow
= gtk_window_new( GTK_WINDOW_TOPLEVEL
);
289 gtk_widget_realize( wxRootWindow
);
291 /* Nothing to do for 15, 16, 24, 32 bit displays */
292 if (visual
->depth
> 8) return TRUE
;
294 /* initialize color cube for 8-bit color reduction dithering */
296 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
298 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
300 for (int r
= 0; r
< 32; r
++)
302 for (int g
= 0; g
< 32; g
++)
304 for (int b
= 0; b
< 32; b
++)
306 int rr
= (r
<< 3) | (r
>> 2);
307 int gg
= (g
<< 3) | (g
>> 2);
308 int bb
= (b
<< 3) | (b
>> 2);
312 GdkColor
*colors
= cmap
->colors
;
317 for (int i
= 0; i
< cmap
->size
; i
++)
319 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
320 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
321 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
322 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
325 index
= i
; max
= sum
;
331 #if (GTK_MINOR_VERSION > 0)
332 /* assume 8-bit true or static colors. this really
334 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
335 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
336 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
337 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
339 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
342 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
350 bool wxApp::ProcessIdle()
353 event
.SetEventObject( this );
354 ProcessEvent( event
);
356 return event
.MoreRequested();
359 void wxApp::OnIdle( wxIdleEvent
&event
)
361 static bool s_inOnIdle
= FALSE
;
363 /* Avoid recursion (via ProcessEvent default case) */
369 /* Resend in the main thread events which have been prepared in other
371 ProcessPendingEvents();
373 /* 'Garbage' collection of windows deleted with Close(). */
374 DeletePendingObjects();
376 /* Send OnIdle events to all windows */
377 bool needMore
= SendIdleEvents();
380 event
.RequestMore(TRUE
);
384 /* flush the logged messages if any */
386 wxLog
*log
= wxLog::GetActiveTarget();
387 if (log
!= NULL
&& log
->HasPendingMessages())
392 bool wxApp::SendIdleEvents()
394 bool needMore
= FALSE
;
396 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
399 wxWindow
* win
= node
->GetData();
400 if (SendIdleEvents(win
))
402 node
= node
->GetNext();
408 bool wxApp::SendIdleEvents( wxWindow
* win
)
410 bool needMore
= FALSE
;
413 event
.SetEventObject(win
);
415 win
->ProcessEvent(event
);
417 win
->OnInternalIdle();
419 if (event
.MoreRequested())
422 wxNode
* node
= win
->GetChildren().First();
425 wxWindow
* win
= (wxWindow
*) node
->Data();
426 if (SendIdleEvents(win
))
434 int wxApp::MainLoop()
440 void wxApp::ExitMainLoop()
442 if (gtk_main_level() > 0)
446 bool wxApp::Initialized()
448 return m_initialized
;
451 bool wxApp::Pending()
453 return (gtk_events_pending() > 0);
456 void wxApp::Dispatch()
458 gtk_main_iteration();
461 void wxApp::DeletePendingObjects()
463 wxNode
*node
= wxPendingDelete
.First();
466 wxObject
*obj
= (wxObject
*)node
->Data();
470 if (wxPendingDelete
.Find(obj
))
473 node
= wxPendingDelete
.First();
477 bool wxApp::Initialize()
479 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
481 wxClassInfo::InitializeClasses();
483 wxSystemSettings::Init();
485 // GL: I'm annoyed ... I don't know where to put this and I don't want to
486 // create a module for that as it's part of the core.
488 wxPendingEvents
= new wxList();
489 wxPendingEventsLocker
= new wxCriticalSection();
492 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
493 wxTheColourDatabase
->Initialize();
495 wxInitializeStockLists();
496 wxInitializeStockObjects();
498 #if wxUSE_WX_RESOURCES
499 wxInitializeResourceSystem();
502 wxModule::RegisterModules();
503 if (!wxModule::InitializeModules()) return FALSE
;
508 void wxApp::CleanUp()
510 wxModule::CleanUpModules();
512 #if wxUSE_WX_RESOURCES
513 wxCleanUpResourceSystem();
516 if (wxTheColourDatabase
)
517 delete wxTheColourDatabase
;
519 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
521 wxDeleteStockObjects();
523 wxDeleteStockLists();
526 wxTheApp
= (wxApp
*) NULL
;
528 // GL: I'm annoyed ... I don't know where to put this and I don't want to
529 // create a module for that as it's part of the core.
531 delete wxPendingEvents
;
532 delete wxPendingEventsLocker
;
535 wxSystemSettings::Done();
539 wxClassInfo::CleanUpClasses();
541 // check for memory leaks
542 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
543 if (wxDebugContext::CountObjectsLeft() > 0)
545 wxLogDebug(wxT("There were memory leaks.\n"));
546 wxDebugContext::Dump();
547 wxDebugContext::PrintStatistics();
552 // do this as the very last thing because everything else can log messages
553 wxLog::DontCreateOnDemand();
555 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
561 //-----------------------------------------------------------------------------
563 //-----------------------------------------------------------------------------
565 int wxEntry( int argc
, char *argv
[] )
568 /* GTK 1.2 up to version 1.2.3 has broken threads */
569 if ((gtk_major_version
== 1) &&
570 (gtk_minor_version
== 2) &&
571 (gtk_micro_version
< 4))
573 printf( "wxWindows warning: Disabled GUI threading due to outdated GTK version\n" );
584 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
586 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
591 gtk_init( &argc
, &argv
);
593 wxSetDetectableAutoRepeat( TRUE
);
595 if (!wxApp::Initialize())
603 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
604 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
606 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
608 wxObject
*test_app
= app_ini();
610 wxTheApp
= (wxApp
*) test_app
;
613 wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") );
615 wxTheApp
->argc
= argc
;
617 wxTheApp
->argv
= new wxChar
*[argc
+1];
619 while (mb_argc
< argc
)
621 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
624 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
626 wxTheApp
->argv
= argv
;
629 wxString
name(wxFileNameFromPath(argv
[0]));
630 wxStripExtension( name
);
631 wxTheApp
->SetAppName( name
);
635 if ( !wxTheApp
->OnInitGui() )
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
);