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
;
50 extern wxResourceCache
*wxTheResourceCache
;
53 unsigned char g_palette
[64*3] =
121 //-----------------------------------------------------------------------------
123 //-----------------------------------------------------------------------------
125 extern void wxFlushResources();
127 /* forward declaration */
128 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) );
129 void wxapp_install_idle_handler();
130 static gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) );
132 //-----------------------------------------------------------------------------
134 //-----------------------------------------------------------------------------
141 //-----------------------------------------------------------------------------
143 //-----------------------------------------------------------------------------
147 bool has_idle
= (wxTheApp
->m_idleTag
!= 0);
151 /* We need to temporarily remove idle callbacks or the loop will
153 gtk_idle_remove( wxTheApp
->m_idleTag
);
154 wxTheApp
->m_idleTag
= 0;
157 while (gtk_events_pending())
158 gtk_main_iteration();
160 /* it's necessary to call ProcessIdle() to update the frames sizes which
161 might have been changed (it also will update other things set from
162 OnUpdateUI() which is a nice (and desired) side effect) */
163 while (wxTheApp
->ProcessIdle()) { }
167 /* re-add idle handler */
168 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
174 //-----------------------------------------------------------------------------
176 //-----------------------------------------------------------------------------
181 wxapp_install_idle_handler();
184 //-----------------------------------------------------------------------------
186 //-----------------------------------------------------------------------------
188 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
190 if (!wxTheApp
) return TRUE
;
192 #if (GTK_MINOR_VERSION > 0)
193 /* when getting called from GDK's idle handler we
194 are no longer within GDK's grab on the GUI
195 thread so we must lock it here ourselves */
196 GDK_THREADS_ENTER ();
199 /* sent idle event to all who request them */
200 while (wxTheApp
->ProcessIdle()) { }
202 /* we don't want any more idle events until the next event is
204 gtk_idle_remove( wxTheApp
->m_idleTag
);
205 wxTheApp
->m_idleTag
= 0;
207 /* indicate that we are now in idle mode - even so deeply
208 in idle mode that we don't get any idle events anymore.
209 this is like wxMSW where an idle event is sent only
210 once each time after the event queue has been completely
214 #if (GTK_MINOR_VERSION > 0)
215 /* release lock again */
216 GDK_THREADS_LEAVE ();
222 void wxapp_install_idle_handler()
224 wxASSERT_MSG( wxTheApp
->m_idleTag
== 0, wxT("attempt to install idle handler twice") );
226 /* this routine gets called by all event handlers
227 indicating that the idle is over. */
229 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
236 void wxapp_install_thread_wakeup()
238 if (wxTheApp
->m_wakeUpTimerTag
) return;
240 wxTheApp
->m_wakeUpTimerTag
= gtk_timeout_add( 100, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
243 void wxapp_uninstall_thread_wakeup()
245 if (!wxTheApp
->m_wakeUpTimerTag
) return;
247 gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag
);
248 wxTheApp
->m_wakeUpTimerTag
= 0;
251 static gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) )
253 wxapp_uninstall_thread_wakeup();
255 #if (GTK_MINOR_VERSION > 0)
256 // when getting called from GDK's time-out handler
257 // we are no longer within GDK's grab on the GUI
258 // thread so we must lock it here ourselves
259 GDK_THREADS_ENTER ();
262 // unblock other threads wishing to do some GUI things
265 // wake up other threads
268 // block other thread again
271 #if (GTK_MINOR_VERSION > 0)
272 // release lock again
273 GDK_THREADS_LEAVE ();
276 wxapp_install_thread_wakeup();
281 #endif // wxUSE_THREADS
283 //-----------------------------------------------------------------------------
285 //-----------------------------------------------------------------------------
287 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
289 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
290 EVT_IDLE(wxApp::OnIdle
)
297 m_topWindow
= (wxWindow
*) NULL
;
298 m_exitOnFrameDelete
= TRUE
;
300 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
303 m_wakeUpTimerTag
= 0;
304 wxapp_install_thread_wakeup();
307 m_colorCube
= (unsigned char*) NULL
;
312 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
315 wxapp_uninstall_thread_wakeup();
318 if (m_colorCube
) free(m_colorCube
);
321 bool wxApp::OnInitGui()
323 GdkVisual
*visual
= gdk_visual_get_system();
325 /* on some machines, the default visual is just 256 colours, so
326 we make sure we get the best. this can sometimes be wasteful,
327 of course, but what do these guys pay $30.000 for? */
329 if (gdk_visual_get_best() != gdk_visual_get_system())
331 GdkVisual* vis = gdk_visual_get_best();
332 gtk_widget_set_default_visual( vis );
334 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
335 gtk_widget_set_default_colormap( colormap );
341 /* Nothing to do for 15, 16, 24, 32 bit displays */
342 if (visual
->depth
> 8) return TRUE
;
344 /* this initiates the standard palette as defined by GdkImlib
345 in the GNOME libraries. it ensures that all GNOME applications
346 use the same 64 colormap entries on 8-bit displays so you
347 can use several rather graphics-heavy applications at the
349 NOTE: this doesn't really seem to work this way... */
352 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
354 for (int i = 0; i < 64; i++)
357 col.red = g_palette[i*3 + 0] << 8;
358 col.green = g_palette[i*3 + 1] << 8;
359 col.blue = g_palette[i*3 + 2] << 8;
362 gdk_color_alloc( cmap, &col );
365 gtk_widget_set_default_colormap( cmap );
368 /* initialize color cube for 8-bit color reduction dithering */
370 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
372 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
374 for (int r
= 0; r
< 32; r
++)
376 for (int g
= 0; g
< 32; g
++)
378 for (int b
= 0; b
< 32; b
++)
380 int rr
= (r
<< 3) | (r
>> 2);
381 int gg
= (g
<< 3) | (g
>> 2);
382 int bb
= (b
<< 3) | (b
>> 2);
386 GdkColor
*colors
= cmap
->colors
;
391 for (int i
= 0; i
< cmap
->size
; i
++)
393 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
394 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
395 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
396 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
399 index
= i
; max
= sum
;
405 #if (GTK_MINOR_VERSION > 0)
406 /* assume 8-bit true or static colors. this really
408 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
409 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
410 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
411 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
413 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
416 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
424 bool wxApp::ProcessIdle()
427 event
.SetEventObject( this );
428 ProcessEvent( event
);
430 return event
.MoreRequested();
433 void wxApp::OnIdle( wxIdleEvent
&event
)
435 static bool s_inOnIdle
= FALSE
;
437 /* Avoid recursion (via ProcessEvent default case) */
443 /* Resend in the main thread events which have been prepared in other
445 ProcessPendingEvents();
447 /* 'Garbage' collection of windows deleted with Close(). */
448 DeletePendingObjects();
450 /* flush the logged messages if any */
452 wxLog
*log
= wxLog::GetActiveTarget();
453 if (log
!= NULL
&& log
->HasPendingMessages())
457 /* Send OnIdle events to all windows */
458 bool needMore
= SendIdleEvents();
461 event
.RequestMore(TRUE
);
466 bool wxApp::SendIdleEvents()
468 bool needMore
= FALSE
;
470 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
473 wxWindow
* win
= node
->GetData();
474 if (SendIdleEvents(win
))
476 node
= node
->GetNext();
482 bool wxApp::SendIdleEvents( wxWindow
* win
)
484 bool needMore
= FALSE
;
487 event
.SetEventObject(win
);
489 win
->ProcessEvent(event
);
491 win
->OnInternalIdle();
493 if (event
.MoreRequested())
496 wxNode
* node
= win
->GetChildren().First();
499 wxWindow
* win
= (wxWindow
*) node
->Data();
500 if (SendIdleEvents(win
))
508 int wxApp::MainLoop()
514 void wxApp::ExitMainLoop()
519 bool wxApp::Initialized()
521 return m_initialized
;
524 bool wxApp::Pending()
526 return (gtk_events_pending() > 0);
529 void wxApp::Dispatch()
531 gtk_main_iteration();
534 void wxApp::DeletePendingObjects()
536 wxNode
*node
= wxPendingDelete
.First();
539 wxObject
*obj
= (wxObject
*)node
->Data();
543 if (wxPendingDelete
.Find(obj
))
546 node
= wxPendingDelete
.First();
550 bool wxApp::Initialize()
552 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
554 wxClassInfo::InitializeClasses();
556 wxSystemSettings::Init();
558 // GL: I'm annoyed ... I don't know where to put this and I don't want to
559 // create a module for that as it's part of the core.
561 wxPendingEvents
= new wxList();
562 wxPendingEventsLocker
= new wxCriticalSection();
566 wxTheFontNameDirectory = new wxFontNameDirectory;
567 wxTheFontNameDirectory->Initialize();
570 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
571 wxTheColourDatabase
->Initialize();
573 wxInitializeStockLists();
574 wxInitializeStockObjects();
576 #if wxUSE_WX_RESOURCES
577 wxTheResourceCache
= new wxResourceCache( wxKEY_STRING
);
579 wxInitializeResourceSystem();
582 wxModule::RegisterModules();
583 if (!wxModule::InitializeModules()) return FALSE
;
588 void wxApp::CleanUp()
590 wxModule::CleanUpModules();
592 #if wxUSE_WX_RESOURCES
595 if (wxTheResourceCache
)
596 delete wxTheResourceCache
;
597 wxTheResourceCache
= (wxResourceCache
*) NULL
;
599 wxCleanUpResourceSystem();
602 if (wxTheColourDatabase
)
603 delete wxTheColourDatabase
;
604 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
607 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
608 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
611 wxDeleteStockObjects();
613 wxDeleteStockLists();
616 wxTheApp
= (wxApp
*) NULL
;
618 // GL: I'm annoyed ... I don't know where to put this and I don't want to
619 // create a module for that as it's part of the core.
621 delete wxPendingEvents
;
622 delete wxPendingEventsLocker
;
625 wxSystemSettings::Done();
629 wxClassInfo::CleanUpClasses();
631 // check for memory leaks
632 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
633 if (wxDebugContext::CountObjectsLeft() > 0)
635 wxLogDebug(wxT("There were memory leaks.\n"));
636 wxDebugContext::Dump();
637 wxDebugContext::PrintStatistics();
642 // do this as the very last thing because everything else can log messages
643 wxLog::DontCreateOnDemand();
645 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
651 //-----------------------------------------------------------------------------
653 //-----------------------------------------------------------------------------
655 int wxEntry( int argc
, char *argv
[] )
660 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
662 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
665 gtk_init( &argc
, &argv
);
667 wxSetDetectableAutoRepeat( TRUE
);
669 if (!wxApp::Initialize())
674 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
675 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
677 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
679 wxObject
*test_app
= app_ini();
681 wxTheApp
= (wxApp
*) test_app
;
684 wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") );
686 wxTheApp
->argc
= argc
;
688 wxTheApp
->argv
= new wxChar
*[argc
+1];
690 while (mb_argc
< argc
) {
691 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
694 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
696 wxTheApp
->argv
= argv
;
699 wxString
name(wxFileNameFromPath(argv
[0]));
700 wxStripExtension( name
);
701 wxTheApp
->SetAppName( name
);
705 if ( !wxTheApp
->OnInitGui() )
708 // Here frames insert themselves automatically into wxTopLevelWindows by
709 // getting created in OnInit().
712 if ( !wxTheApp
->OnInit() )
718 /* delete pending toplevel windows (typically a single
719 dialog) so that, if there isn't any left, we don't
721 wxTheApp
->DeletePendingObjects();
723 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
725 if (wxTheApp
->Initialized())
727 retValue
= wxTheApp
->OnRun();
729 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
732 /* Forcibly delete the window. */
733 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
734 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
736 topWindow
->Close( TRUE
);
737 wxTheApp
->DeletePendingObjects();
742 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
750 // flush the logged messages if any
751 wxLog
*log
= wxLog::GetActiveTarget();
752 if (log
!= NULL
&& log
->HasPendingMessages())
755 // continuing to use user defined log target is unsafe from now on because
756 // some resources may be already unavailable, so replace it by something
758 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);
768 #include "wx/gtk/info.xpm"
769 #include "wx/gtk/error.xpm"
770 #include "wx/gtk/question.xpm"
771 #include "wx/gtk/warning.xpm"
774 wxApp::GetStdIcon(int which
) const
778 case wxICON_INFORMATION
:
779 return wxIcon(info_xpm
);
781 case wxICON_QUESTION
:
782 return wxIcon(question_xpm
);
784 case wxICON_EXCLAMATION
:
785 return wxIcon(warning_xpm
);
788 wxFAIL_MSG(wxT("requested non existent standard icon"));
789 // still fall through
792 return wxIcon(error_xpm
);