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
;
51 extern wxResourceCache
*wxTheResourceCache
;
54 unsigned char g_palette
[64*3] =
122 //-----------------------------------------------------------------------------
124 //-----------------------------------------------------------------------------
126 extern void wxFlushResources();
128 //-----------------------------------------------------------------------------
130 //-----------------------------------------------------------------------------
137 /* forward declaration */
138 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) );
142 bool has_idle
= (wxTheApp
->m_idleTag
!= 0);
146 /* We need to temporarily remove idle callbacks or the loop will
148 gtk_idle_remove( wxTheApp
->m_idleTag
);
149 wxTheApp
->m_idleTag
= 0;
152 while (gtk_events_pending())
153 gtk_main_iteration();
155 /* it's necessary to call ProcessIdle() to update the frames sizes which
156 might have been changed (it also will update other things set from
157 OnUpdateUI() which is a nice (and desired) side effect) */
158 while (wxTheApp
->ProcessIdle()) { }
162 /* re-add idle handler */
163 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
169 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
171 if (!wxTheApp
) return TRUE
;
173 #if (GTK_MINOR_VERSION > 0)
174 /* when getting called from GDK's idle handler we
175 are no longer within GDK's grab on the GUI
176 thread so we must lock it here ourselves */
177 GDK_THREADS_ENTER ();
180 /* sent idle event to all who request them */
181 while (wxTheApp
->ProcessIdle()) { }
183 /* we don't want any more idle events until the next event is
185 gtk_idle_remove( wxTheApp
->m_idleTag
);
186 wxTheApp
->m_idleTag
= 0;
188 /* indicate that we are now in idle mode - even so deeply
189 in idle mode that we don't get any idle events anymore.
190 this is like wxMSW where an idle event is sent only
191 once each time after the event queue has been completely
195 #if (GTK_MINOR_VERSION > 0)
196 /* release lock again */
197 GDK_THREADS_LEAVE ();
203 void wxapp_install_idle_handler()
205 wxASSERT_MSG( wxTheApp
->m_idleTag
== 0, wxT("attempt to install idle handler twice") );
207 /* this routine gets called by all event handlers
208 indicating that the idle is over. */
210 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
217 /* forward declaration */
218 static gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) );
220 void wxapp_install_thread_wakeup()
222 if (wxTheApp
->m_wakeUpTimerTag
) return;
224 wxTheApp
->m_wakeUpTimerTag
= gtk_timeout_add( 100, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
227 void wxapp_uninstall_thread_wakeup()
229 if (!wxTheApp
->m_wakeUpTimerTag
) return;
231 gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag
);
232 wxTheApp
->m_wakeUpTimerTag
= 0;
235 static gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) )
237 wxapp_uninstall_thread_wakeup();
239 #if (GTK_MINOR_VERSION > 0)
240 // when getting called from GDK's time-out handler
241 // we are no longer within GDK's grab on the GUI
242 // thread so we must lock it here ourselves
243 GDK_THREADS_ENTER ();
246 // unblock other threads wishing to do some GUI things
249 // wake up other threads
252 // block other thread again
255 #if (GTK_MINOR_VERSION > 0)
256 // release lock again
257 GDK_THREADS_LEAVE ();
260 wxapp_install_thread_wakeup();
265 #endif // wxUSE_THREADS
267 //-----------------------------------------------------------------------------
269 //-----------------------------------------------------------------------------
271 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
273 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
274 EVT_IDLE(wxApp::OnIdle
)
281 m_topWindow
= (wxWindow
*) NULL
;
282 m_exitOnFrameDelete
= TRUE
;
284 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
287 m_wakeUpTimerTag
= 0;
288 wxapp_install_thread_wakeup();
291 m_colorCube
= (unsigned char*) NULL
;
296 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
299 wxapp_uninstall_thread_wakeup();
302 if (m_colorCube
) free(m_colorCube
);
305 bool wxApp::OnInitGui()
307 GdkVisual
*visual
= gdk_visual_get_system();
309 /* on some machines, the default visual is just 256 colours, so
310 we make sure we get the best. this can sometimes be wasteful,
311 of course, but what do these guys pay $30.000 for? */
313 if (gdk_visual_get_best() != gdk_visual_get_system())
315 GdkVisual* vis = gdk_visual_get_best();
316 gtk_widget_set_default_visual( vis );
318 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
319 gtk_widget_set_default_colormap( colormap );
325 /* Nothing to do for 15, 16, 24, 32 bit displays */
326 if (visual
->depth
> 8) return TRUE
;
328 /* this initiates the standard palette as defined by GdkImlib
329 in the GNOME libraries. it ensures that all GNOME applications
330 use the same 64 colormap entries on 8-bit displays so you
331 can use several rather graphics-heavy applications at the
333 NOTE: this doesn't really seem to work this way... */
336 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
338 for (int i = 0; i < 64; i++)
341 col.red = g_palette[i*3 + 0] << 8;
342 col.green = g_palette[i*3 + 1] << 8;
343 col.blue = g_palette[i*3 + 2] << 8;
346 gdk_color_alloc( cmap, &col );
349 gtk_widget_set_default_colormap( cmap );
352 /* initialize color cube for 8-bit color reduction dithering */
354 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
356 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
358 for (int r
= 0; r
< 32; r
++)
360 for (int g
= 0; g
< 32; g
++)
362 for (int b
= 0; b
< 32; b
++)
364 int rr
= (r
<< 3) | (r
>> 2);
365 int gg
= (g
<< 3) | (g
>> 2);
366 int bb
= (b
<< 3) | (b
>> 2);
370 GdkColor
*colors
= cmap
->colors
;
375 for (int i
= 0; i
< cmap
->size
; i
++)
377 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
378 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
379 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
380 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
383 index
= i
; max
= sum
;
389 #if (GTK_MINOR_VERSION > 0)
390 /* assume 8-bit true or static colors. this really
392 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
393 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
394 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
395 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
397 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
400 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
408 bool wxApp::ProcessIdle()
411 event
.SetEventObject( this );
412 ProcessEvent( event
);
414 return event
.MoreRequested();
417 void wxApp::OnIdle( wxIdleEvent
&event
)
419 static bool s_inOnIdle
= FALSE
;
421 /* Avoid recursion (via ProcessEvent default case) */
427 /* Resend in the main thread events which have been prepared in other
429 ProcessPendingEvents();
431 /* 'Garbage' collection of windows deleted with Close(). */
432 DeletePendingObjects();
434 /* flush the logged messages if any */
436 wxLog
*log
= wxLog::GetActiveTarget();
437 if (log
!= NULL
&& log
->HasPendingMessages())
441 /* Send OnIdle events to all windows */
442 bool needMore
= SendIdleEvents();
445 event
.RequestMore(TRUE
);
450 bool wxApp::SendIdleEvents()
452 bool needMore
= FALSE
;
454 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
457 wxWindow
* win
= node
->GetData();
458 if (SendIdleEvents(win
))
460 node
= node
->GetNext();
466 bool wxApp::SendIdleEvents( wxWindow
* win
)
468 bool needMore
= FALSE
;
471 event
.SetEventObject(win
);
473 win
->ProcessEvent(event
);
475 win
->OnInternalIdle();
477 if (event
.MoreRequested())
480 wxNode
* node
= win
->GetChildren().First();
483 wxWindow
* win
= (wxWindow
*) node
->Data();
484 if (SendIdleEvents(win
))
492 int wxApp::MainLoop()
498 void wxApp::ExitMainLoop()
503 bool wxApp::Initialized()
505 return m_initialized
;
508 bool wxApp::Pending()
510 return (gtk_events_pending() > 0);
513 void wxApp::Dispatch()
515 gtk_main_iteration();
518 void wxApp::ProcessPendingEvents()
521 wxCriticalSectionLocker
locker(*wxPendingEventsLocker
);
522 #endif // wxUSE_THREADS
524 if ( !wxPendingEvents
)
527 wxNode
*node
= wxPendingEvents
->First();
530 wxEvtHandler
*handler
= (wxEvtHandler
*)node
->Data();
532 handler
->ProcessPendingEvents();
536 node
= wxPendingEvents
->First();
540 void wxApp::DeletePendingObjects()
542 wxNode
*node
= wxPendingDelete
.First();
545 wxObject
*obj
= (wxObject
*)node
->Data();
549 if (wxPendingDelete
.Find(obj
))
552 node
= wxPendingDelete
.First();
556 bool wxApp::Initialize()
558 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
560 wxClassInfo::InitializeClasses();
562 wxSystemSettings::Init();
564 // GL: I'm annoyed ... I don't know where to put this and I don't want to
565 // create a module for that as it's part of the core.
567 wxPendingEvents
= new wxList();
568 wxPendingEventsLocker
= new wxCriticalSection();
572 wxTheFontNameDirectory = new wxFontNameDirectory;
573 wxTheFontNameDirectory->Initialize();
576 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
577 wxTheColourDatabase
->Initialize();
579 wxInitializeStockLists();
580 wxInitializeStockObjects();
582 #if wxUSE_WX_RESOURCES
583 wxTheResourceCache
= new wxResourceCache( wxKEY_STRING
);
585 wxInitializeResourceSystem();
588 wxModule::RegisterModules();
589 if (!wxModule::InitializeModules()) return FALSE
;
594 void wxApp::CleanUp()
596 wxModule::CleanUpModules();
598 #if wxUSE_WX_RESOURCES
601 if (wxTheResourceCache
)
602 delete wxTheResourceCache
;
603 wxTheResourceCache
= (wxResourceCache
*) NULL
;
605 wxCleanUpResourceSystem();
608 if (wxTheColourDatabase
)
609 delete wxTheColourDatabase
;
610 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
613 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
614 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
617 wxDeleteStockObjects();
619 wxDeleteStockLists();
622 wxTheApp
= (wxApp
*) NULL
;
624 // GL: I'm annoyed ... I don't know where to put this and I don't want to
625 // create a module for that as it's part of the core.
627 delete wxPendingEvents
;
628 delete wxPendingEventsLocker
;
631 wxSystemSettings::Done();
635 wxClassInfo::CleanUpClasses();
637 // check for memory leaks
638 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
639 if (wxDebugContext::CountObjectsLeft() > 0)
641 wxLogDebug(wxT("There were memory leaks.\n"));
642 wxDebugContext::Dump();
643 wxDebugContext::PrintStatistics();
648 // do this as the very last thing because everything else can log messages
649 wxLog::DontCreateOnDemand();
651 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
657 //-----------------------------------------------------------------------------
659 //-----------------------------------------------------------------------------
661 int wxEntry( int argc
, char *argv
[] )
666 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
668 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
671 gtk_init( &argc
, &argv
);
673 wxSetDetectableAutoRepeat( TRUE
);
675 if (!wxApp::Initialize())
680 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
681 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
683 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
685 wxObject
*test_app
= app_ini();
687 wxTheApp
= (wxApp
*) test_app
;
690 wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") );
692 wxTheApp
->argc
= argc
;
694 wxTheApp
->argv
= new wxChar
*[argc
+1];
696 while (mb_argc
< argc
) {
697 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
700 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
702 wxTheApp
->argv
= argv
;
705 wxString
name(wxFileNameFromPath(argv
[0]));
706 wxStripExtension( name
);
707 wxTheApp
->SetAppName( name
);
711 if ( !wxTheApp
->OnInitGui() )
714 // Here frames insert themselves automatically into wxTopLevelWindows by
715 // getting created in OnInit().
718 if ( !wxTheApp
->OnInit() )
724 /* delete pending toplevel windows (typically a single
725 dialog) so that, if there isn't any left, we don't
727 wxTheApp
->DeletePendingObjects();
729 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
731 if (wxTheApp
->Initialized())
733 retValue
= wxTheApp
->OnRun();
735 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
738 /* Forcibly delete the window. */
739 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
740 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
742 topWindow
->Close( TRUE
);
743 wxTheApp
->DeletePendingObjects();
748 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
756 // flush the logged messages if any
757 wxLog
*log
= wxLog::GetActiveTarget();
758 if (log
!= NULL
&& log
->HasPendingMessages())
761 // continuing to use user defined log target is unsafe from now on because
762 // some resources may be already unavailable, so replace it by something
764 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);
774 #include "wx/gtk/info.xpm"
775 #include "wx/gtk/error.xpm"
776 #include "wx/gtk/question.xpm"
777 #include "wx/gtk/warning.xpm"
780 wxApp::GetStdIcon(int which
) const
784 case wxICON_INFORMATION
:
785 return wxIcon(info_xpm
);
787 case wxICON_QUESTION
:
788 return wxIcon(question_xpm
);
790 case wxICON_EXCLAMATION
:
791 return wxIcon(warning_xpm
);
794 wxFAIL_MSG(wxT("requested non existent standard icon"));
795 // still fall through
798 return wxIcon(error_xpm
);