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();
132 gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) );
135 //-----------------------------------------------------------------------------
137 //-----------------------------------------------------------------------------
144 //-----------------------------------------------------------------------------
146 //-----------------------------------------------------------------------------
150 bool has_idle
= (wxTheApp
->m_idleTag
!= 0);
154 /* We need to temporarily remove idle callbacks or the loop will
156 gtk_idle_remove( wxTheApp
->m_idleTag
);
157 wxTheApp
->m_idleTag
= 0;
160 while (gtk_events_pending())
161 gtk_main_iteration();
163 /* it's necessary to call ProcessIdle() to update the frames sizes which
164 might have been changed (it also will update other things set from
165 OnUpdateUI() which is a nice (and desired) side effect) */
166 while (wxTheApp
->ProcessIdle()) { }
170 /* re-add idle handler */
171 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
177 //-----------------------------------------------------------------------------
179 //-----------------------------------------------------------------------------
184 wxapp_install_idle_handler();
187 //-----------------------------------------------------------------------------
189 //-----------------------------------------------------------------------------
191 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
193 if (!wxTheApp
) return TRUE
;
195 #if (GTK_MINOR_VERSION > 0)
196 /* when getting called from GDK's idle handler we
197 are no longer within GDK's grab on the GUI
198 thread so we must lock it here ourselves */
199 GDK_THREADS_ENTER ();
202 /* sent idle event to all who request them */
203 while (wxTheApp
->ProcessIdle()) { }
205 /* we don't want any more idle events until the next event is
207 gtk_idle_remove( wxTheApp
->m_idleTag
);
208 wxTheApp
->m_idleTag
= 0;
210 /* indicate that we are now in idle mode - even so deeply
211 in idle mode that we don't get any idle events anymore.
212 this is like wxMSW where an idle event is sent only
213 once each time after the event queue has been completely
217 #if (GTK_MINOR_VERSION > 0)
218 /* release lock again */
219 GDK_THREADS_LEAVE ();
225 void wxapp_install_idle_handler()
227 wxASSERT_MSG( wxTheApp
->m_idleTag
== 0, wxT("attempt to install idle handler twice") );
229 /* This routine gets called by all event handlers
230 indicating that the idle is over. It may also
231 get called from other thread for sending events
232 to the main thread (and processing these in
236 if (!wxThread::IsMain())
237 GDK_THREADS_ENTER ();
240 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
245 if (!wxThread::IsMain())
246 GDK_THREADS_LEAVE ();
252 void wxapp_install_thread_wakeup()
254 if (wxTheApp
->m_wakeUpTimerTag
) return;
256 wxTheApp
->m_wakeUpTimerTag
= gtk_timeout_add( 100, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
259 void wxapp_uninstall_thread_wakeup()
261 if (!wxTheApp
->m_wakeUpTimerTag
) return;
263 gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag
);
264 wxTheApp
->m_wakeUpTimerTag
= 0;
267 gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) )
269 wxapp_uninstall_thread_wakeup();
271 #if (GTK_MINOR_VERSION > 0)
272 // when getting called from GDK's time-out handler
273 // we are no longer within GDK's grab on the GUI
274 // thread so we must lock it here ourselves
275 GDK_THREADS_ENTER ();
278 // unblock other threads wishing to do some GUI things
281 // wake up other threads
284 // block other thread again
287 #if (GTK_MINOR_VERSION > 0)
288 // release lock again
289 GDK_THREADS_LEAVE ();
292 wxapp_install_thread_wakeup();
297 #endif // wxUSE_THREADS
299 //-----------------------------------------------------------------------------
301 //-----------------------------------------------------------------------------
303 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
305 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
306 EVT_IDLE(wxApp::OnIdle
)
313 m_topWindow
= (wxWindow
*) NULL
;
314 m_exitOnFrameDelete
= TRUE
;
316 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
319 m_wakeUpTimerTag
= 0;
320 wxapp_install_thread_wakeup();
323 m_colorCube
= (unsigned char*) NULL
;
328 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
331 wxapp_uninstall_thread_wakeup();
334 if (m_colorCube
) free(m_colorCube
);
337 bool wxApp::OnInitGui()
339 GdkVisual
*visual
= gdk_visual_get_system();
341 /* on some machines, the default visual is just 256 colours, so
342 we make sure we get the best. this can sometimes be wasteful,
343 of course, but what do these guys pay $30.000 for? */
345 if (gdk_visual_get_best() != gdk_visual_get_system())
347 GdkVisual* vis = gdk_visual_get_best();
348 gtk_widget_set_default_visual( vis );
350 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
351 gtk_widget_set_default_colormap( colormap );
357 /* Nothing to do for 15, 16, 24, 32 bit displays */
358 if (visual
->depth
> 8) return TRUE
;
360 /* this initiates the standard palette as defined by GdkImlib
361 in the GNOME libraries. it ensures that all GNOME applications
362 use the same 64 colormap entries on 8-bit displays so you
363 can use several rather graphics-heavy applications at the
365 NOTE: this doesn't really seem to work this way... */
368 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
370 for (int i = 0; i < 64; i++)
373 col.red = g_palette[i*3 + 0] << 8;
374 col.green = g_palette[i*3 + 1] << 8;
375 col.blue = g_palette[i*3 + 2] << 8;
378 gdk_color_alloc( cmap, &col );
381 gtk_widget_set_default_colormap( cmap );
384 /* initialize color cube for 8-bit color reduction dithering */
386 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
388 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
390 for (int r
= 0; r
< 32; r
++)
392 for (int g
= 0; g
< 32; g
++)
394 for (int b
= 0; b
< 32; b
++)
396 int rr
= (r
<< 3) | (r
>> 2);
397 int gg
= (g
<< 3) | (g
>> 2);
398 int bb
= (b
<< 3) | (b
>> 2);
402 GdkColor
*colors
= cmap
->colors
;
407 for (int i
= 0; i
< cmap
->size
; i
++)
409 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
410 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
411 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
412 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
415 index
= i
; max
= sum
;
421 #if (GTK_MINOR_VERSION > 0)
422 /* assume 8-bit true or static colors. this really
424 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
425 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
426 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
427 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
429 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
432 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
440 bool wxApp::ProcessIdle()
443 event
.SetEventObject( this );
444 ProcessEvent( event
);
446 return event
.MoreRequested();
449 void wxApp::OnIdle( wxIdleEvent
&event
)
451 static bool s_inOnIdle
= FALSE
;
453 /* Avoid recursion (via ProcessEvent default case) */
459 /* Resend in the main thread events which have been prepared in other
461 ProcessPendingEvents();
463 /* 'Garbage' collection of windows deleted with Close(). */
464 DeletePendingObjects();
466 /* flush the logged messages if any */
468 wxLog
*log
= wxLog::GetActiveTarget();
469 if (log
!= NULL
&& log
->HasPendingMessages())
473 /* Send OnIdle events to all windows */
474 bool needMore
= SendIdleEvents();
477 event
.RequestMore(TRUE
);
482 bool wxApp::SendIdleEvents()
484 bool needMore
= FALSE
;
486 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
489 wxWindow
* win
= node
->GetData();
490 if (SendIdleEvents(win
))
492 node
= node
->GetNext();
498 bool wxApp::SendIdleEvents( wxWindow
* win
)
500 bool needMore
= FALSE
;
503 event
.SetEventObject(win
);
505 win
->ProcessEvent(event
);
507 win
->OnInternalIdle();
509 if (event
.MoreRequested())
512 wxNode
* node
= win
->GetChildren().First();
515 wxWindow
* win
= (wxWindow
*) node
->Data();
516 if (SendIdleEvents(win
))
524 int wxApp::MainLoop()
530 void wxApp::ExitMainLoop()
535 bool wxApp::Initialized()
537 return m_initialized
;
540 bool wxApp::Pending()
542 return (gtk_events_pending() > 0);
545 void wxApp::Dispatch()
547 gtk_main_iteration();
550 void wxApp::DeletePendingObjects()
552 wxNode
*node
= wxPendingDelete
.First();
555 wxObject
*obj
= (wxObject
*)node
->Data();
559 if (wxPendingDelete
.Find(obj
))
562 node
= wxPendingDelete
.First();
566 bool wxApp::Initialize()
568 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
570 wxClassInfo::InitializeClasses();
572 wxSystemSettings::Init();
574 // GL: I'm annoyed ... I don't know where to put this and I don't want to
575 // create a module for that as it's part of the core.
577 wxPendingEvents
= new wxList();
578 wxPendingEventsLocker
= new wxCriticalSection();
582 wxTheFontNameDirectory = new wxFontNameDirectory;
583 wxTheFontNameDirectory->Initialize();
586 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
587 wxTheColourDatabase
->Initialize();
589 wxInitializeStockLists();
590 wxInitializeStockObjects();
592 #if wxUSE_WX_RESOURCES
593 wxTheResourceCache
= new wxResourceCache( wxKEY_STRING
);
595 wxInitializeResourceSystem();
598 wxModule::RegisterModules();
599 if (!wxModule::InitializeModules()) return FALSE
;
604 void wxApp::CleanUp()
606 wxModule::CleanUpModules();
608 #if wxUSE_WX_RESOURCES
611 if (wxTheResourceCache
)
612 delete wxTheResourceCache
;
613 wxTheResourceCache
= (wxResourceCache
*) NULL
;
615 wxCleanUpResourceSystem();
618 if (wxTheColourDatabase
)
619 delete wxTheColourDatabase
;
620 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
623 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
624 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
627 wxDeleteStockObjects();
629 wxDeleteStockLists();
632 wxTheApp
= (wxApp
*) NULL
;
634 // GL: I'm annoyed ... I don't know where to put this and I don't want to
635 // create a module for that as it's part of the core.
637 delete wxPendingEvents
;
638 delete wxPendingEventsLocker
;
641 wxSystemSettings::Done();
645 wxClassInfo::CleanUpClasses();
647 // check for memory leaks
648 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
649 if (wxDebugContext::CountObjectsLeft() > 0)
651 wxLogDebug(wxT("There were memory leaks.\n"));
652 wxDebugContext::Dump();
653 wxDebugContext::PrintStatistics();
658 // do this as the very last thing because everything else can log messages
659 wxLog::DontCreateOnDemand();
661 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
667 //-----------------------------------------------------------------------------
669 //-----------------------------------------------------------------------------
671 int wxEntry( int argc
, char *argv
[] )
676 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
678 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
681 gtk_init( &argc
, &argv
);
683 wxSetDetectableAutoRepeat( TRUE
);
685 if (!wxApp::Initialize())
690 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
691 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
693 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
695 wxObject
*test_app
= app_ini();
697 wxTheApp
= (wxApp
*) test_app
;
700 wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") );
702 wxTheApp
->argc
= argc
;
704 wxTheApp
->argv
= new wxChar
*[argc
+1];
706 while (mb_argc
< argc
) {
707 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
710 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
712 wxTheApp
->argv
= argv
;
715 wxString
name(wxFileNameFromPath(argv
[0]));
716 wxStripExtension( name
);
717 wxTheApp
->SetAppName( name
);
721 if ( !wxTheApp
->OnInitGui() )
724 // Here frames insert themselves automatically into wxTopLevelWindows by
725 // getting created in OnInit().
728 if ( !wxTheApp
->OnInit() )
734 /* delete pending toplevel windows (typically a single
735 dialog) so that, if there isn't any left, we don't
737 wxTheApp
->DeletePendingObjects();
739 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
741 if (wxTheApp
->Initialized())
743 retValue
= wxTheApp
->OnRun();
745 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
748 /* Forcibly delete the window. */
749 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
750 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
752 topWindow
->Close( TRUE
);
753 wxTheApp
->DeletePendingObjects();
758 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
766 // flush the logged messages if any
767 wxLog
*log
= wxLog::GetActiveTarget();
768 if (log
!= NULL
&& log
->HasPendingMessages())
771 // continuing to use user defined log target is unsafe from now on because
772 // some resources may be already unavailable, so replace it by something
774 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);
784 #include "wx/gtk/info.xpm"
785 #include "wx/gtk/error.xpm"
786 #include "wx/gtk/question.xpm"
787 #include "wx/gtk/warning.xpm"
790 wxApp::GetStdIcon(int which
) const
794 case wxICON_INFORMATION
:
795 return wxIcon(info_xpm
);
797 case wxICON_QUESTION
:
798 return wxIcon(question_xpm
);
800 case wxICON_EXCLAMATION
:
801 return wxIcon(warning_xpm
);
804 wxFAIL_MSG(wxT("requested non existent standard icon"));
805 // still fall through
808 return wxIcon(error_xpm
);