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. */
232 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
239 void wxapp_install_thread_wakeup()
241 if (wxTheApp
->m_wakeUpTimerTag
) return;
243 wxTheApp
->m_wakeUpTimerTag
= gtk_timeout_add( 100, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
246 void wxapp_uninstall_thread_wakeup()
248 if (!wxTheApp
->m_wakeUpTimerTag
) return;
250 gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag
);
251 wxTheApp
->m_wakeUpTimerTag
= 0;
254 gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) )
256 wxapp_uninstall_thread_wakeup();
258 #if (GTK_MINOR_VERSION > 0)
259 // when getting called from GDK's time-out handler
260 // we are no longer within GDK's grab on the GUI
261 // thread so we must lock it here ourselves
262 GDK_THREADS_ENTER ();
265 // unblock other threads wishing to do some GUI things
268 // wake up other threads
271 // block other thread again
274 #if (GTK_MINOR_VERSION > 0)
275 // release lock again
276 GDK_THREADS_LEAVE ();
279 wxapp_install_thread_wakeup();
284 #endif // wxUSE_THREADS
286 //-----------------------------------------------------------------------------
288 //-----------------------------------------------------------------------------
290 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
292 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
293 EVT_IDLE(wxApp::OnIdle
)
300 m_topWindow
= (wxWindow
*) NULL
;
301 m_exitOnFrameDelete
= TRUE
;
303 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
306 m_wakeUpTimerTag
= 0;
307 wxapp_install_thread_wakeup();
310 m_colorCube
= (unsigned char*) NULL
;
315 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
318 wxapp_uninstall_thread_wakeup();
321 if (m_colorCube
) free(m_colorCube
);
324 bool wxApp::OnInitGui()
326 GdkVisual
*visual
= gdk_visual_get_system();
328 /* on some machines, the default visual is just 256 colours, so
329 we make sure we get the best. this can sometimes be wasteful,
330 of course, but what do these guys pay $30.000 for? */
332 if (gdk_visual_get_best() != gdk_visual_get_system())
334 GdkVisual* vis = gdk_visual_get_best();
335 gtk_widget_set_default_visual( vis );
337 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
338 gtk_widget_set_default_colormap( colormap );
344 /* Nothing to do for 15, 16, 24, 32 bit displays */
345 if (visual
->depth
> 8) return TRUE
;
347 /* this initiates the standard palette as defined by GdkImlib
348 in the GNOME libraries. it ensures that all GNOME applications
349 use the same 64 colormap entries on 8-bit displays so you
350 can use several rather graphics-heavy applications at the
352 NOTE: this doesn't really seem to work this way... */
355 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
357 for (int i = 0; i < 64; i++)
360 col.red = g_palette[i*3 + 0] << 8;
361 col.green = g_palette[i*3 + 1] << 8;
362 col.blue = g_palette[i*3 + 2] << 8;
365 gdk_color_alloc( cmap, &col );
368 gtk_widget_set_default_colormap( cmap );
371 /* initialize color cube for 8-bit color reduction dithering */
373 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
375 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
377 for (int r
= 0; r
< 32; r
++)
379 for (int g
= 0; g
< 32; g
++)
381 for (int b
= 0; b
< 32; b
++)
383 int rr
= (r
<< 3) | (r
>> 2);
384 int gg
= (g
<< 3) | (g
>> 2);
385 int bb
= (b
<< 3) | (b
>> 2);
389 GdkColor
*colors
= cmap
->colors
;
394 for (int i
= 0; i
< cmap
->size
; i
++)
396 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
397 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
398 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
399 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
402 index
= i
; max
= sum
;
408 #if (GTK_MINOR_VERSION > 0)
409 /* assume 8-bit true or static colors. this really
411 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
412 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
413 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
414 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
416 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
419 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
427 bool wxApp::ProcessIdle()
430 event
.SetEventObject( this );
431 ProcessEvent( event
);
433 return event
.MoreRequested();
436 void wxApp::OnIdle( wxIdleEvent
&event
)
438 static bool s_inOnIdle
= FALSE
;
440 /* Avoid recursion (via ProcessEvent default case) */
446 /* Resend in the main thread events which have been prepared in other
448 ProcessPendingEvents();
450 /* 'Garbage' collection of windows deleted with Close(). */
451 DeletePendingObjects();
453 /* flush the logged messages if any */
455 wxLog
*log
= wxLog::GetActiveTarget();
456 if (log
!= NULL
&& log
->HasPendingMessages())
460 /* Send OnIdle events to all windows */
461 bool needMore
= SendIdleEvents();
464 event
.RequestMore(TRUE
);
469 bool wxApp::SendIdleEvents()
471 bool needMore
= FALSE
;
473 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
476 wxWindow
* win
= node
->GetData();
477 if (SendIdleEvents(win
))
479 node
= node
->GetNext();
485 bool wxApp::SendIdleEvents( wxWindow
* win
)
487 bool needMore
= FALSE
;
490 event
.SetEventObject(win
);
492 win
->ProcessEvent(event
);
494 win
->OnInternalIdle();
496 if (event
.MoreRequested())
499 wxNode
* node
= win
->GetChildren().First();
502 wxWindow
* win
= (wxWindow
*) node
->Data();
503 if (SendIdleEvents(win
))
511 int wxApp::MainLoop()
517 void wxApp::ExitMainLoop()
522 bool wxApp::Initialized()
524 return m_initialized
;
527 bool wxApp::Pending()
529 return (gtk_events_pending() > 0);
532 void wxApp::Dispatch()
534 gtk_main_iteration();
537 void wxApp::DeletePendingObjects()
539 wxNode
*node
= wxPendingDelete
.First();
542 wxObject
*obj
= (wxObject
*)node
->Data();
546 if (wxPendingDelete
.Find(obj
))
549 node
= wxPendingDelete
.First();
553 bool wxApp::Initialize()
555 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
557 wxClassInfo::InitializeClasses();
559 wxSystemSettings::Init();
561 // GL: I'm annoyed ... I don't know where to put this and I don't want to
562 // create a module for that as it's part of the core.
564 wxPendingEvents
= new wxList();
565 wxPendingEventsLocker
= new wxCriticalSection();
569 wxTheFontNameDirectory = new wxFontNameDirectory;
570 wxTheFontNameDirectory->Initialize();
573 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
574 wxTheColourDatabase
->Initialize();
576 wxInitializeStockLists();
577 wxInitializeStockObjects();
579 #if wxUSE_WX_RESOURCES
580 wxTheResourceCache
= new wxResourceCache( wxKEY_STRING
);
582 wxInitializeResourceSystem();
585 wxModule::RegisterModules();
586 if (!wxModule::InitializeModules()) return FALSE
;
591 void wxApp::CleanUp()
593 wxModule::CleanUpModules();
595 #if wxUSE_WX_RESOURCES
598 if (wxTheResourceCache
)
599 delete wxTheResourceCache
;
600 wxTheResourceCache
= (wxResourceCache
*) NULL
;
602 wxCleanUpResourceSystem();
605 if (wxTheColourDatabase
)
606 delete wxTheColourDatabase
;
607 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
610 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
611 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
614 wxDeleteStockObjects();
616 wxDeleteStockLists();
619 wxTheApp
= (wxApp
*) NULL
;
621 // GL: I'm annoyed ... I don't know where to put this and I don't want to
622 // create a module for that as it's part of the core.
624 delete wxPendingEvents
;
625 delete wxPendingEventsLocker
;
628 wxSystemSettings::Done();
632 wxClassInfo::CleanUpClasses();
634 // check for memory leaks
635 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
636 if (wxDebugContext::CountObjectsLeft() > 0)
638 wxLogDebug(wxT("There were memory leaks.\n"));
639 wxDebugContext::Dump();
640 wxDebugContext::PrintStatistics();
645 // do this as the very last thing because everything else can log messages
646 wxLog::DontCreateOnDemand();
648 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
654 //-----------------------------------------------------------------------------
656 //-----------------------------------------------------------------------------
658 int wxEntry( int argc
, char *argv
[] )
663 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
665 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
668 gtk_init( &argc
, &argv
);
670 wxSetDetectableAutoRepeat( TRUE
);
672 if (!wxApp::Initialize())
677 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
678 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
680 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
682 wxObject
*test_app
= app_ini();
684 wxTheApp
= (wxApp
*) test_app
;
687 wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") );
689 wxTheApp
->argc
= argc
;
691 wxTheApp
->argv
= new wxChar
*[argc
+1];
693 while (mb_argc
< argc
) {
694 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
697 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
699 wxTheApp
->argv
= argv
;
702 wxString
name(wxFileNameFromPath(argv
[0]));
703 wxStripExtension( name
);
704 wxTheApp
->SetAppName( name
);
708 if ( !wxTheApp
->OnInitGui() )
711 // Here frames insert themselves automatically into wxTopLevelWindows by
712 // getting created in OnInit().
715 if ( !wxTheApp
->OnInit() )
721 /* delete pending toplevel windows (typically a single
722 dialog) so that, if there isn't any left, we don't
724 wxTheApp
->DeletePendingObjects();
726 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
728 if (wxTheApp
->Initialized())
730 retValue
= wxTheApp
->OnRun();
732 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
735 /* Forcibly delete the window. */
736 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
737 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
739 topWindow
->Close( TRUE
);
740 wxTheApp
->DeletePendingObjects();
745 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
753 // flush the logged messages if any
754 wxLog
*log
= wxLog::GetActiveTarget();
755 if (log
!= NULL
&& log
->HasPendingMessages())
758 // continuing to use user defined log target is unsafe from now on because
759 // some resources may be already unavailable, so replace it by something
761 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);
771 #include "wx/gtk/info.xpm"
772 #include "wx/gtk/error.xpm"
773 #include "wx/gtk/question.xpm"
774 #include "wx/gtk/warning.xpm"
777 wxApp::GetStdIcon(int which
) const
781 case wxICON_INFORMATION
:
782 return wxIcon(info_xpm
);
784 case wxICON_QUESTION
:
785 return wxIcon(question_xpm
);
787 case wxICON_EXCLAMATION
:
788 return wxIcon(warning_xpm
);
791 wxFAIL_MSG(wxT("requested non existent standard icon"));
792 // still fall through
795 return wxIcon(error_xpm
);