1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #pragma implementation "appbase.h"
12 #pragma implementation "app.h"
16 #include "wx/gdicmn.h"
20 #include "wx/memory.h"
22 #include "wx/settings.h"
23 #include "wx/dialog.h"
25 #if wxUSE_WX_RESOURCES
26 #include "wx/resource.h"
29 #include "wx/module.h"
33 #include "wx/thread.h"
42 #include "wx/gtk/win_gtk.h"
44 //-----------------------------------------------------------------------------
46 //-----------------------------------------------------------------------------
48 wxApp
*wxTheApp
= (wxApp
*) NULL
;
49 wxAppInitializerFunction
wxAppBase::m_appInitFn
= (wxAppInitializerFunction
) NULL
;
52 extern wxList
*wxPendingEvents
;
53 extern wxCriticalSection
*wxPendingEventsLocker
;
55 extern wxResourceCache
*wxTheResourceCache
;
58 unsigned char g_palette
[64*3] =
126 //-----------------------------------------------------------------------------
128 //-----------------------------------------------------------------------------
130 extern void wxFlushResources(void);
132 //-----------------------------------------------------------------------------
134 //-----------------------------------------------------------------------------
141 /* forward declaration */
142 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) );
146 bool has_idle
= (wxTheApp
->m_idleTag
!= 0);
150 /* We need to temporarily remove idle callbacks or the loop will
152 gtk_idle_remove( wxTheApp
->m_idleTag
);
153 wxTheApp
->m_idleTag
= 0;
156 while (gtk_events_pending())
157 gtk_main_iteration();
159 /* it's necessary to call ProcessIdle() to update the frames sizes which
160 might have been changed (it also will update other things set from
161 OnUpdateUI() which is a nice (and desired) side effect) */
162 while (wxTheApp
->ProcessIdle()) { }
166 /* re-add idle handler */
167 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
173 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
175 if (!wxTheApp
) return TRUE
;
177 #if (GTK_MINOR_VERSION > 0)
178 /* when getting called from GDK's idle handler we
179 are no longer within GDK's grab on the GUI
180 thread so we must lock it here ourselves */
181 GDK_THREADS_ENTER ();
184 /* sent idle event to all who request them */
185 while (wxTheApp
->ProcessIdle()) { }
187 /* we don't want any more idle events until the next event is
189 gtk_idle_remove( wxTheApp
->m_idleTag
);
190 wxTheApp
->m_idleTag
= 0;
192 /* indicate that we are now in idle mode - even so deeply
193 in idle mode that we don't get any idle events anymore.
194 this is like wxMSW where an idle event is sent only
195 once each time after the event queue has been completely
199 #if (GTK_MINOR_VERSION > 0)
200 /* release lock again */
201 GDK_THREADS_LEAVE ();
207 void wxapp_install_idle_handler()
209 wxASSERT_MSG( wxTheApp
->m_idleTag
== 0, wxT("attempt to install idle handler twice") );
211 /* this routine gets called by all event handlers
212 indicating that the idle is over. */
214 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
221 /* forward declaration */
222 static gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) );
224 void wxapp_install_thread_wakeup()
226 if (wxTheApp
->m_wakeUpTimerTag
) return;
228 wxTheApp
->m_wakeUpTimerTag
= gtk_timeout_add( 100, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
231 void wxapp_uninstall_thread_wakeup()
233 if (!wxTheApp
->m_wakeUpTimerTag
) return;
235 gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag
);
236 wxTheApp
->m_wakeUpTimerTag
= 0;
239 static gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) )
241 wxapp_uninstall_thread_wakeup();
243 #if (GTK_MINOR_VERSION > 0)
244 // when getting called from GDK's time-out handler
245 // we are no longer within GDK's grab on the GUI
246 // thread so we must lock it here ourselves
247 GDK_THREADS_ENTER ();
250 // unblock other threads wishing to do some GUI things
253 // wake up other threads
256 // block other thread again
259 #if (GTK_MINOR_VERSION > 0)
260 // release lock again
261 GDK_THREADS_LEAVE ();
264 wxapp_install_thread_wakeup();
270 //-----------------------------------------------------------------------------
272 //-----------------------------------------------------------------------------
274 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
276 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
277 EVT_IDLE(wxApp::OnIdle
)
284 m_topWindow
= (wxWindow
*) NULL
;
285 m_exitOnFrameDelete
= TRUE
;
287 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
290 m_wakeUpTimerTag
= 0;
291 wxapp_install_thread_wakeup();
294 m_colorCube
= (unsigned char*) NULL
;
299 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
302 wxapp_uninstall_thread_wakeup();
305 if (m_colorCube
) free(m_colorCube
);
308 bool wxApp::OnInitGui()
310 GdkVisual
*visual
= gdk_visual_get_system();
312 /* on some machines, the default visual is just 256 colours, so
313 we make sure we get the best. this can sometimes be wasteful,
314 of course, but what do these guys pay $30.000 for? */
316 if (gdk_visual_get_best() != gdk_visual_get_system())
318 GdkVisual* vis = gdk_visual_get_best();
319 gtk_widget_set_default_visual( vis );
321 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
322 gtk_widget_set_default_colormap( colormap );
328 /* Nothing to do for 15, 16, 24, 32 bit displays */
329 if (visual
->depth
> 8) return TRUE
;
331 /* this initiates the standard palette as defined by GdkImlib
332 in the GNOME libraries. it ensures that all GNOME applications
333 use the same 64 colormap entries on 8-bit displays so you
334 can use several rather graphics-heavy applications at the
336 NOTE: this doesn't really seem to work this way... */
339 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
341 for (int i = 0; i < 64; i++)
344 col.red = g_palette[i*3 + 0] << 8;
345 col.green = g_palette[i*3 + 1] << 8;
346 col.blue = g_palette[i*3 + 2] << 8;
349 gdk_color_alloc( cmap, &col );
352 gtk_widget_set_default_colormap( cmap );
355 /* initialize color cube for 8-bit color reduction dithering */
357 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
359 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
361 for (int r
= 0; r
< 32; r
++)
363 for (int g
= 0; g
< 32; g
++)
365 for (int b
= 0; b
< 32; b
++)
367 int rr
= (r
<< 3) | (r
>> 2);
368 int gg
= (g
<< 3) | (g
>> 2);
369 int bb
= (b
<< 3) | (b
>> 2);
373 GdkColor
*colors
= cmap
->colors
;
378 for (int i
= 0; i
< cmap
->size
; i
++)
380 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
381 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
382 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
383 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
386 index
= i
; max
= sum
;
392 #if (GTK_MINOR_VERSION > 0)
393 /* assume 8-bit true or static colors. this really
395 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
396 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
397 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
398 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
400 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
403 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
411 bool wxApp::ProcessIdle()
414 event
.SetEventObject( this );
415 ProcessEvent( event
);
417 return event
.MoreRequested();
420 void wxApp::OnIdle( wxIdleEvent
&event
)
422 static bool s_inOnIdle
= FALSE
;
424 /* Avoid recursion (via ProcessEvent default case) */
431 /* Resend in the main thread events which have been prepared in other
433 ProcessPendingEvents();
436 /* 'Garbage' collection of windows deleted with Close(). */
437 DeletePendingObjects();
439 /* flush the logged messages if any */
441 wxLog
*log
= wxLog::GetActiveTarget();
442 if (log
!= NULL
&& log
->HasPendingMessages())
446 /* Send OnIdle events to all windows */
447 bool needMore
= SendIdleEvents();
450 event
.RequestMore(TRUE
);
455 bool wxApp::SendIdleEvents()
457 bool needMore
= FALSE
;
459 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
462 wxWindow
* win
= node
->GetData();
463 if (SendIdleEvents(win
))
465 node
= node
->GetNext();
471 bool wxApp::SendIdleEvents( wxWindow
* win
)
473 bool needMore
= FALSE
;
476 event
.SetEventObject(win
);
478 win
->ProcessEvent(event
);
480 win
->OnInternalIdle();
482 if (event
.MoreRequested())
485 wxNode
* node
= win
->GetChildren().First();
488 wxWindow
* win
= (wxWindow
*) node
->Data();
489 if (SendIdleEvents(win
))
497 int wxApp::MainLoop()
503 void wxApp::ExitMainLoop()
508 bool wxApp::Initialized()
510 return m_initialized
;
513 bool wxApp::Pending()
515 return (gtk_events_pending() > 0);
518 void wxApp::Dispatch()
520 gtk_main_iteration();
524 void wxApp::ProcessPendingEvents()
526 wxNode
*node
= wxPendingEvents
->First();
527 wxCriticalSectionLocker
locker(*wxPendingEventsLocker
);
531 wxEvtHandler
*handler
= (wxEvtHandler
*)node
->Data();
533 handler
->ProcessPendingEvents();
537 node
= wxPendingEvents
->First();
540 #endif // wxUSE_THREADS
542 void wxApp::DeletePendingObjects()
544 wxNode
*node
= wxPendingDelete
.First();
547 wxObject
*obj
= (wxObject
*)node
->Data();
551 if (wxPendingDelete
.Find(obj
))
554 node
= wxPendingDelete
.First();
558 bool wxApp::Initialize()
560 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
562 wxClassInfo::InitializeClasses();
564 wxSystemSettings::Init();
566 // GL: I'm annoyed ... I don't know where to put this and I don't want to
567 // create a module for that as it's part of the core.
569 wxPendingEvents
= new wxList();
570 wxPendingEventsLocker
= new wxCriticalSection();
574 wxTheFontNameDirectory = new wxFontNameDirectory;
575 wxTheFontNameDirectory->Initialize();
578 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
579 wxTheColourDatabase
->Initialize();
581 wxInitializeStockLists();
582 wxInitializeStockObjects();
584 #if wxUSE_WX_RESOURCES
585 wxTheResourceCache
= new wxResourceCache( wxKEY_STRING
);
587 wxInitializeResourceSystem();
590 wxModule::RegisterModules();
591 if (!wxModule::InitializeModules()) return FALSE
;
596 void wxApp::CleanUp()
598 wxModule::CleanUpModules();
600 #if wxUSE_WX_RESOURCES
603 if (wxTheResourceCache
)
604 delete wxTheResourceCache
;
605 wxTheResourceCache
= (wxResourceCache
*) NULL
;
607 wxCleanUpResourceSystem();
610 if (wxTheColourDatabase
)
611 delete wxTheColourDatabase
;
612 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
615 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
616 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
619 wxDeleteStockObjects();
621 wxDeleteStockLists();
624 wxTheApp
= (wxApp
*) NULL
;
626 // GL: I'm annoyed ... I don't know where to put this and I don't want to
627 // create a module for that as it's part of the core.
629 delete wxPendingEvents
;
630 delete wxPendingEventsLocker
;
633 wxSystemSettings::Done();
637 wxClassInfo::CleanUpClasses();
639 // check for memory leaks
640 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
641 if (wxDebugContext::CountObjectsLeft() > 0)
643 wxLogDebug(wxT("There were memory leaks.\n"));
644 wxDebugContext::Dump();
645 wxDebugContext::PrintStatistics();
650 // do this as the very last thing because everything else can log messages
651 wxLog::DontCreateOnDemand();
653 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
660 //-----------------------------------------------------------------------------
662 //-----------------------------------------------------------------------------
664 int wxEntry( int argc
, char *argv
[] )
669 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
671 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
674 gtk_init( &argc
, &argv
);
676 wxSetDetectableAutoRepeat( TRUE
);
678 if (!wxApp::Initialize())
683 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
684 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
686 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
688 wxObject
*test_app
= app_ini();
690 wxTheApp
= (wxApp
*) test_app
;
693 wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") );
695 wxTheApp
->argc
= argc
;
697 wxTheApp
->argv
= new wxChar
*[argc
+1];
699 while (mb_argc
< argc
) {
700 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
703 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
705 wxTheApp
->argv
= argv
;
708 wxString
name(wxFileNameFromPath(argv
[0]));
709 wxStripExtension( name
);
710 wxTheApp
->SetAppName( name
);
714 if ( !wxTheApp
->OnInitGui() )
717 // Here frames insert themselves automatically into wxTopLevelWindows by
718 // getting created in OnInit().
721 if ( !wxTheApp
->OnInit() )
727 /* delete pending toplevel windows (typically a single
728 dialog) so that, if there isn't any left, we don't
730 wxTheApp
->DeletePendingObjects();
732 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
734 if (wxTheApp
->Initialized())
736 retValue
= wxTheApp
->OnRun();
738 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
741 /* Forcibly delete the window. */
742 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
743 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
745 topWindow
->Close( TRUE
);
746 wxTheApp
->DeletePendingObjects();
751 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
759 // flush the logged messages if any
760 wxLog
*log
= wxLog::GetActiveTarget();
761 if (log
!= NULL
&& log
->HasPendingMessages())
764 // continuing to use user defined log target is unsafe from now on because
765 // some resources may be already unavailable, so replace it by something
767 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);
777 #include "wx/gtk/info.xpm"
778 #include "wx/gtk/error.xpm"
779 #include "wx/gtk/question.xpm"
780 #include "wx/gtk/warning.xpm"
783 wxApp::GetStdIcon(int which
) const
787 case wxICON_INFORMATION
:
788 return wxIcon(info_xpm
);
790 case wxICON_QUESTION
:
791 return wxIcon(question_xpm
);
793 case wxICON_EXCLAMATION
:
794 return wxIcon(warning_xpm
);
797 wxFAIL_MSG(wxT("requested non existent standard icon"));
798 // still fall through
801 return wxIcon(error_xpm
);