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 //-----------------------------------------------------------------------------
54 //-----------------------------------------------------------------------------
56 /* forward declaration */
57 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) );
58 void wxapp_install_idle_handler();
61 gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) );
64 //-----------------------------------------------------------------------------
66 //-----------------------------------------------------------------------------
73 //-----------------------------------------------------------------------------
75 //-----------------------------------------------------------------------------
79 bool has_idle
= (wxTheApp
->m_idleTag
!= 0);
83 /* We need to temporarily remove idle callbacks or the loop will
85 gtk_idle_remove( wxTheApp
->m_idleTag
);
86 wxTheApp
->m_idleTag
= 0;
89 while (gtk_events_pending())
92 /* it's necessary to call ProcessIdle() to update the frames sizes which
93 might have been changed (it also will update other things set from
94 OnUpdateUI() which is a nice (and desired) side effect) */
95 while (wxTheApp
->ProcessIdle()) { }
99 /* re-add idle handler */
100 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
106 //-----------------------------------------------------------------------------
108 //-----------------------------------------------------------------------------
113 if (!wxThread::IsMain())
118 wxapp_install_idle_handler();
121 if (!wxThread::IsMain())
126 //-----------------------------------------------------------------------------
128 //-----------------------------------------------------------------------------
130 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
132 if (!wxTheApp
) return TRUE
;
134 // when getting called from GDK's time-out handler
135 // we are no longer within GDK's grab on the GUI
136 // thread so we must lock it here ourselves
139 /* sent idle event to all who request them */
140 while (wxTheApp
->ProcessIdle()) { }
142 /* we don't want any more idle events until the next event is
144 gtk_idle_remove( wxTheApp
->m_idleTag
);
145 wxTheApp
->m_idleTag
= 0;
147 /* indicate that we are now in idle mode - even so deeply
148 in idle mode that we don't get any idle events anymore.
149 this is like wxMSW where an idle event is sent only
150 once each time after the event queue has been completely
154 // release lock again
160 void wxapp_install_idle_handler()
162 wxASSERT_MSG( wxTheApp
->m_idleTag
== 0, wxT("attempt to install idle handler twice") );
164 /* This routine gets called by all event handlers
165 indicating that the idle is over. It may also
166 get called from other thread for sending events
167 to the main thread (and processing these in
170 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
177 void wxapp_install_thread_wakeup()
179 if (wxTheApp
->m_wakeUpTimerTag
) return;
181 wxTheApp
->m_wakeUpTimerTag
= gtk_timeout_add( 50, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
184 void wxapp_uninstall_thread_wakeup()
186 if (!wxTheApp
->m_wakeUpTimerTag
) return;
188 gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag
);
189 wxTheApp
->m_wakeUpTimerTag
= 0;
192 gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) )
194 // when getting called from GDK's time-out handler
195 // we are no longer within GDK's grab on the GUI
196 // thread so we must lock it here ourselves
200 wxapp_uninstall_thread_wakeup();
202 // unblock other threads wishing to do some GUI things
205 // wake up other threads
208 // block other thread again
211 wxapp_install_thread_wakeup();
213 // release lock again
219 #endif // wxUSE_THREADS
221 //-----------------------------------------------------------------------------
223 //-----------------------------------------------------------------------------
225 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
227 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
228 EVT_IDLE(wxApp::OnIdle
)
235 m_topWindow
= (wxWindow
*) NULL
;
236 m_exitOnFrameDelete
= TRUE
;
238 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
241 m_wakeUpTimerTag
= 0;
242 wxapp_install_thread_wakeup();
245 m_colorCube
= (unsigned char*) NULL
;
250 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
253 wxapp_uninstall_thread_wakeup();
256 if (m_colorCube
) free(m_colorCube
);
259 bool wxApp::OnInitGui()
261 GdkVisual
*visual
= gdk_visual_get_system();
263 /* on some machines, the default visual is just 256 colours, so
264 we make sure we get the best. this can sometimes be wasteful,
265 of course, but what do these guys pay $30.000 for? */
267 if (gdk_visual_get_best() != gdk_visual_get_system())
269 GdkVisual* vis = gdk_visual_get_best();
270 gtk_widget_set_default_visual( vis );
272 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
273 gtk_widget_set_default_colormap( colormap );
279 /* Nothing to do for 15, 16, 24, 32 bit displays */
280 if (visual
->depth
> 8) return TRUE
;
282 /* initialize color cube for 8-bit color reduction dithering */
284 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
286 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
288 for (int r
= 0; r
< 32; r
++)
290 for (int g
= 0; g
< 32; g
++)
292 for (int b
= 0; b
< 32; b
++)
294 int rr
= (r
<< 3) | (r
>> 2);
295 int gg
= (g
<< 3) | (g
>> 2);
296 int bb
= (b
<< 3) | (b
>> 2);
300 GdkColor
*colors
= cmap
->colors
;
305 for (int i
= 0; i
< cmap
->size
; i
++)
307 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
308 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
309 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
310 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
313 index
= i
; max
= sum
;
319 #if (GTK_MINOR_VERSION > 0)
320 /* assume 8-bit true or static colors. this really
322 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
323 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
324 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
325 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
327 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
330 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
338 bool wxApp::ProcessIdle()
341 event
.SetEventObject( this );
342 ProcessEvent( event
);
344 return event
.MoreRequested();
347 void wxApp::OnIdle( wxIdleEvent
&event
)
349 static bool s_inOnIdle
= FALSE
;
351 /* Avoid recursion (via ProcessEvent default case) */
357 /* Resend in the main thread events which have been prepared in other
359 ProcessPendingEvents();
361 /* 'Garbage' collection of windows deleted with Close(). */
362 DeletePendingObjects();
364 /* flush the logged messages if any */
366 wxLog
*log
= wxLog::GetActiveTarget();
367 if (log
!= NULL
&& log
->HasPendingMessages())
371 /* Send OnIdle events to all windows */
372 bool needMore
= SendIdleEvents();
375 event
.RequestMore(TRUE
);
380 bool wxApp::SendIdleEvents()
382 bool needMore
= FALSE
;
384 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
387 wxWindow
* win
= node
->GetData();
388 if (SendIdleEvents(win
))
390 node
= node
->GetNext();
396 bool wxApp::SendIdleEvents( wxWindow
* win
)
398 bool needMore
= FALSE
;
401 event
.SetEventObject(win
);
403 win
->ProcessEvent(event
);
405 win
->OnInternalIdle();
407 if (event
.MoreRequested())
410 wxNode
* node
= win
->GetChildren().First();
413 wxWindow
* win
= (wxWindow
*) node
->Data();
414 if (SendIdleEvents(win
))
422 int wxApp::MainLoop()
428 void wxApp::ExitMainLoop()
430 if (gtk_main_level() > 0)
434 bool wxApp::Initialized()
436 return m_initialized
;
439 bool wxApp::Pending()
441 return (gtk_events_pending() > 0);
444 void wxApp::Dispatch()
446 gtk_main_iteration();
449 void wxApp::DeletePendingObjects()
451 wxNode
*node
= wxPendingDelete
.First();
454 wxObject
*obj
= (wxObject
*)node
->Data();
458 if (wxPendingDelete
.Find(obj
))
461 node
= wxPendingDelete
.First();
465 bool wxApp::Initialize()
467 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
469 wxClassInfo::InitializeClasses();
471 wxSystemSettings::Init();
473 // GL: I'm annoyed ... I don't know where to put this and I don't want to
474 // create a module for that as it's part of the core.
476 wxPendingEvents
= new wxList();
477 wxPendingEventsLocker
= new wxCriticalSection();
481 wxTheFontNameDirectory = new wxFontNameDirectory;
482 wxTheFontNameDirectory->Initialize();
485 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
486 wxTheColourDatabase
->Initialize();
488 wxInitializeStockLists();
489 wxInitializeStockObjects();
491 wxModule::RegisterModules();
492 if (!wxModule::InitializeModules()) return FALSE
;
497 void wxApp::CleanUp()
499 wxModule::CleanUpModules();
501 if (wxTheColourDatabase
)
502 delete wxTheColourDatabase
;
503 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
506 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
507 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
510 wxDeleteStockObjects();
512 wxDeleteStockLists();
515 wxTheApp
= (wxApp
*) NULL
;
517 // GL: I'm annoyed ... I don't know where to put this and I don't want to
518 // create a module for that as it's part of the core.
520 delete wxPendingEvents
;
521 delete wxPendingEventsLocker
;
524 wxSystemSettings::Done();
528 wxClassInfo::CleanUpClasses();
530 // check for memory leaks
531 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
532 if (wxDebugContext::CountObjectsLeft() > 0)
534 wxLogDebug(wxT("There were memory leaks.\n"));
535 wxDebugContext::Dump();
536 wxDebugContext::PrintStatistics();
541 // do this as the very last thing because everything else can log messages
542 wxLog::DontCreateOnDemand();
544 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
550 //-----------------------------------------------------------------------------
552 //-----------------------------------------------------------------------------
554 int wxEntry( int argc
, char *argv
[] )
563 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
565 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
570 gtk_init( &argc
, &argv
);
572 wxSetDetectableAutoRepeat( TRUE
);
574 if (!wxApp::Initialize())
582 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
583 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
585 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
587 wxObject
*test_app
= app_ini();
589 wxTheApp
= (wxApp
*) test_app
;
592 wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") );
594 wxTheApp
->argc
= argc
;
596 wxTheApp
->argv
= new wxChar
*[argc
+1];
598 while (mb_argc
< argc
)
600 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
603 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
605 wxTheApp
->argv
= argv
;
608 wxString
name(wxFileNameFromPath(argv
[0]));
609 wxStripExtension( name
);
610 wxTheApp
->SetAppName( name
);
614 if ( !wxTheApp
->OnInitGui() )
617 // Here frames insert themselves automatically into wxTopLevelWindows by
618 // getting created in OnInit().
621 if ( !wxTheApp
->OnInit() )
627 /* delete pending toplevel windows (typically a single
628 dialog) so that, if there isn't any left, we don't
630 wxTheApp
->DeletePendingObjects();
632 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
634 if (wxTheApp
->Initialized())
636 retValue
= wxTheApp
->OnRun();
638 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
641 /* Forcibly delete the window. */
642 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
643 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
645 topWindow
->Close( TRUE
);
646 wxTheApp
->DeletePendingObjects();
651 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
659 // flush the logged messages if any
660 wxLog
*log
= wxLog::GetActiveTarget();
661 if (log
!= NULL
&& log
->HasPendingMessages())
664 // continuing to use user defined log target is unsafe from now on because
665 // some resources may be already unavailable, so replace it by something
667 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);
679 #include "wx/gtk/info.xpm"
680 #include "wx/gtk/error.xpm"
681 #include "wx/gtk/question.xpm"
682 #include "wx/gtk/warning.xpm"
685 wxApp::GetStdIcon(int which
) const
689 case wxICON_INFORMATION
:
690 return wxIcon(info_xpm
);
692 case wxICON_QUESTION
:
693 return wxIcon(question_xpm
);
695 case wxICON_EXCLAMATION
:
696 return wxIcon(warning_xpm
);
699 wxFAIL_MSG(wxT("requested non existent standard icon"));
700 // still fall through
703 return wxIcon(error_xpm
);