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
199 wxapp_uninstall_thread_wakeup();
201 // unblock other threads wishing to do some GUI things
204 // wake up other threads
207 // block other thread again
210 wxapp_install_thread_wakeup();
212 // release lock again
218 #endif // wxUSE_THREADS
220 //-----------------------------------------------------------------------------
222 //-----------------------------------------------------------------------------
224 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
226 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
227 EVT_IDLE(wxApp::OnIdle
)
234 m_topWindow
= (wxWindow
*) NULL
;
235 m_exitOnFrameDelete
= TRUE
;
237 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
240 m_wakeUpTimerTag
= 0;
241 wxapp_install_thread_wakeup();
244 m_colorCube
= (unsigned char*) NULL
;
249 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
252 wxapp_uninstall_thread_wakeup();
255 if (m_colorCube
) free(m_colorCube
);
258 bool wxApp::OnInitGui()
260 GdkVisual
*visual
= gdk_visual_get_system();
262 /* on some machines, the default visual is just 256 colours, so
263 we make sure we get the best. this can sometimes be wasteful,
264 of course, but what do these guys pay $30.000 for? */
266 if (gdk_visual_get_best() != gdk_visual_get_system())
268 GdkVisual* vis = gdk_visual_get_best();
269 gtk_widget_set_default_visual( vis );
271 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
272 gtk_widget_set_default_colormap( colormap );
278 /* Nothing to do for 15, 16, 24, 32 bit displays */
279 if (visual
->depth
> 8) return TRUE
;
281 /* initialize color cube for 8-bit color reduction dithering */
283 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
285 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
287 for (int r
= 0; r
< 32; r
++)
289 for (int g
= 0; g
< 32; g
++)
291 for (int b
= 0; b
< 32; b
++)
293 int rr
= (r
<< 3) | (r
>> 2);
294 int gg
= (g
<< 3) | (g
>> 2);
295 int bb
= (b
<< 3) | (b
>> 2);
299 GdkColor
*colors
= cmap
->colors
;
304 for (int i
= 0; i
< cmap
->size
; i
++)
306 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
307 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
308 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
309 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
312 index
= i
; max
= sum
;
318 #if (GTK_MINOR_VERSION > 0)
319 /* assume 8-bit true or static colors. this really
321 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
322 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
323 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
324 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
326 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
329 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
337 bool wxApp::ProcessIdle()
340 event
.SetEventObject( this );
341 ProcessEvent( event
);
343 return event
.MoreRequested();
346 void wxApp::OnIdle( wxIdleEvent
&event
)
348 static bool s_inOnIdle
= FALSE
;
350 /* Avoid recursion (via ProcessEvent default case) */
356 /* Resend in the main thread events which have been prepared in other
358 ProcessPendingEvents();
360 /* 'Garbage' collection of windows deleted with Close(). */
361 DeletePendingObjects();
363 /* flush the logged messages if any */
365 wxLog
*log
= wxLog::GetActiveTarget();
366 if (log
!= NULL
&& log
->HasPendingMessages())
370 /* Send OnIdle events to all windows */
371 bool needMore
= SendIdleEvents();
374 event
.RequestMore(TRUE
);
379 bool wxApp::SendIdleEvents()
381 bool needMore
= FALSE
;
383 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
386 wxWindow
* win
= node
->GetData();
387 if (SendIdleEvents(win
))
389 node
= node
->GetNext();
395 bool wxApp::SendIdleEvents( wxWindow
* win
)
397 bool needMore
= FALSE
;
400 event
.SetEventObject(win
);
402 win
->ProcessEvent(event
);
404 win
->OnInternalIdle();
406 if (event
.MoreRequested())
409 wxNode
* node
= win
->GetChildren().First();
412 wxWindow
* win
= (wxWindow
*) node
->Data();
413 if (SendIdleEvents(win
))
421 int wxApp::MainLoop()
427 void wxApp::ExitMainLoop()
429 if (gtk_main_level() > 0)
433 bool wxApp::Initialized()
435 return m_initialized
;
438 bool wxApp::Pending()
440 return (gtk_events_pending() > 0);
443 void wxApp::Dispatch()
445 gtk_main_iteration();
448 void wxApp::DeletePendingObjects()
450 wxNode
*node
= wxPendingDelete
.First();
453 wxObject
*obj
= (wxObject
*)node
->Data();
457 if (wxPendingDelete
.Find(obj
))
460 node
= wxPendingDelete
.First();
464 bool wxApp::Initialize()
466 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
468 wxClassInfo::InitializeClasses();
470 wxSystemSettings::Init();
472 // GL: I'm annoyed ... I don't know where to put this and I don't want to
473 // create a module for that as it's part of the core.
475 wxPendingEvents
= new wxList();
476 wxPendingEventsLocker
= new wxCriticalSection();
479 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
480 wxTheColourDatabase
->Initialize();
482 wxInitializeStockLists();
483 wxInitializeStockObjects();
485 #if wxUSE_WX_RESOURCES
486 wxInitializeResourceSystem();
489 wxModule::RegisterModules();
490 if (!wxModule::InitializeModules()) return FALSE
;
495 void wxApp::CleanUp()
497 wxModule::CleanUpModules();
499 #if wxUSE_WX_RESOURCES
500 wxCleanUpResourceSystem();
503 if (wxTheColourDatabase
)
504 delete wxTheColourDatabase
;
506 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
508 wxDeleteStockObjects();
510 wxDeleteStockLists();
513 wxTheApp
= (wxApp
*) NULL
;
515 // GL: I'm annoyed ... I don't know where to put this and I don't want to
516 // create a module for that as it's part of the core.
518 delete wxPendingEvents
;
519 delete wxPendingEventsLocker
;
522 wxSystemSettings::Done();
526 wxClassInfo::CleanUpClasses();
528 // check for memory leaks
529 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
530 if (wxDebugContext::CountObjectsLeft() > 0)
532 wxLogDebug(wxT("There were memory leaks.\n"));
533 wxDebugContext::Dump();
534 wxDebugContext::PrintStatistics();
539 // do this as the very last thing because everything else can log messages
540 wxLog::DontCreateOnDemand();
542 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
548 //-----------------------------------------------------------------------------
550 //-----------------------------------------------------------------------------
552 int wxEntry( int argc
, char *argv
[] )
561 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
563 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
568 gtk_init( &argc
, &argv
);
570 wxSetDetectableAutoRepeat( TRUE
);
572 if (!wxApp::Initialize())
580 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
581 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
583 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
585 wxObject
*test_app
= app_ini();
587 wxTheApp
= (wxApp
*) test_app
;
590 wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") );
592 wxTheApp
->argc
= argc
;
594 wxTheApp
->argv
= new wxChar
*[argc
+1];
596 while (mb_argc
< argc
)
598 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
601 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
603 wxTheApp
->argv
= argv
;
606 wxString
name(wxFileNameFromPath(argv
[0]));
607 wxStripExtension( name
);
608 wxTheApp
->SetAppName( name
);
612 if ( !wxTheApp
->OnInitGui() )
615 // Here frames insert themselves automatically into wxTopLevelWindows by
616 // getting created in OnInit().
619 if ( !wxTheApp
->OnInit() )
625 /* delete pending toplevel windows (typically a single
626 dialog) so that, if there isn't any left, we don't
628 wxTheApp
->DeletePendingObjects();
630 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
632 if (wxTheApp
->Initialized())
634 retValue
= wxTheApp
->OnRun();
636 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
639 /* Forcibly delete the window. */
640 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
641 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
643 topWindow
->Close( TRUE
);
644 wxTheApp
->DeletePendingObjects();
649 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
657 // flush the logged messages if any
658 wxLog
*log
= wxLog::GetActiveTarget();
659 if (log
!= NULL
&& log
->HasPendingMessages())
662 // continuing to use user defined log target is unsafe from now on because
663 // some resources may be already unavailable, so replace it by something
665 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);
677 #include "wx/gtk/info.xpm"
678 #include "wx/gtk/error.xpm"
679 #include "wx/gtk/question.xpm"
680 #include "wx/gtk/warning.xpm"
683 wxApp::GetStdIcon(int which
) const
687 case wxICON_INFORMATION
:
688 return wxIcon(info_xpm
);
690 case wxICON_QUESTION
:
691 return wxIcon(question_xpm
);
693 case wxICON_EXCLAMATION
:
694 return wxIcon(warning_xpm
);
697 wxFAIL_MSG(wxT("requested non existent standard icon"));
698 // still fall through
701 return wxIcon(error_xpm
);