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
;
52 bool g_mainThreadLocked
= FALSE
;
54 GtkWidget
*wxRootWindow
= (GtkWidget
*) NULL
;
56 //-----------------------------------------------------------------------------
58 //-----------------------------------------------------------------------------
60 /* forward declaration */
61 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) );
62 void wxapp_install_idle_handler();
65 gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) );
68 //-----------------------------------------------------------------------------
70 //-----------------------------------------------------------------------------
77 //-----------------------------------------------------------------------------
79 //-----------------------------------------------------------------------------
83 bool has_idle
= (wxTheApp
->m_idleTag
!= 0);
87 /* We need to temporarily remove idle callbacks or the loop will
89 gtk_idle_remove( wxTheApp
->m_idleTag
);
90 wxTheApp
->m_idleTag
= 0;
93 while (gtk_events_pending())
98 /* re-add idle handler (very low priority) */
99 wxTheApp
->m_idleTag
= gtk_idle_add_priority( 500, wxapp_idle_callback
, (gpointer
) NULL
);
102 // disable log flushing from here because a call to wxYield() shouldn't
103 // normally result in message boxes popping up &c
106 /* it's necessary to call ProcessIdle() to update the frames sizes which
107 might have been changed (it also will update other things set from
108 OnUpdateUI() which is a nice (and desired) side effect) */
109 while (wxTheApp
->ProcessIdle())
112 // let the logs be flashed again
118 //-----------------------------------------------------------------------------
120 //-----------------------------------------------------------------------------
125 if (!wxThread::IsMain())
130 wxapp_install_idle_handler();
133 if (!wxThread::IsMain())
138 //-----------------------------------------------------------------------------
140 //-----------------------------------------------------------------------------
142 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
144 if (!wxTheApp
) return TRUE
;
146 // when getting called from GDK's time-out handler
147 // we are no longer within GDK's grab on the GUI
148 // thread so we must lock it here ourselves
151 /* we don't want any more idle events until the next event is
153 gtk_idle_remove( wxTheApp
->m_idleTag
);
154 wxTheApp
->m_idleTag
= 0;
156 /* indicate that we are now in idle mode - even so deeply
157 in idle mode that we don't get any idle events anymore.
158 this is like wxMSW where an idle event is sent only
159 once each time after the event queue has been completely
163 /* sent idle event to all who request them */
164 while (wxTheApp
->ProcessIdle()) { }
166 // release lock again
172 void wxapp_install_idle_handler()
174 wxASSERT_MSG( wxTheApp
->m_idleTag
== 0, wxT("attempt to install idle handler twice") );
176 /* This routine gets called by all event handlers
177 indicating that the idle is over. It may also
178 get called from other thread for sending events
179 to the main thread (and processing these in
180 idle time). Very low priority. */
182 wxTheApp
->m_idleTag
= gtk_idle_add_priority( 500, wxapp_idle_callback
, (gpointer
) NULL
);
189 void wxapp_install_thread_wakeup()
191 if (wxTheApp
->m_wakeUpTimerTag
) return;
193 wxTheApp
->m_wakeUpTimerTag
= gtk_timeout_add( 50, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
196 void wxapp_uninstall_thread_wakeup()
198 if (!wxTheApp
->m_wakeUpTimerTag
) return;
200 gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag
);
201 wxTheApp
->m_wakeUpTimerTag
= 0;
204 gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) )
206 // when getting called from GDK's time-out handler
207 // we are no longer within GDK's grab on the GUI
208 // thread so we must lock it here ourselves
211 wxapp_uninstall_thread_wakeup();
213 // unblock other threads wishing to do some GUI things
216 g_mainThreadLocked
= TRUE
;
218 // wake up other threads
221 // block other thread again
224 g_mainThreadLocked
= FALSE
;
226 wxapp_install_thread_wakeup();
228 // release lock again
234 #endif // wxUSE_THREADS
236 //-----------------------------------------------------------------------------
238 //-----------------------------------------------------------------------------
240 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
242 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
243 EVT_IDLE(wxApp::OnIdle
)
250 m_topWindow
= (wxWindow
*) NULL
;
251 m_exitOnFrameDelete
= TRUE
;
253 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
256 m_wakeUpTimerTag
= 0;
257 wxapp_install_thread_wakeup();
260 m_colorCube
= (unsigned char*) NULL
;
262 m_useBestVisual
= FALSE
;
267 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
270 wxapp_uninstall_thread_wakeup();
273 if (m_colorCube
) free(m_colorCube
);
276 bool wxApp::OnInitGui()
278 GdkVisual
*visual
= gdk_visual_get_system();
280 /* on some machines, the default visual is just 256 colours, so
281 we make sure we get the best. this can sometimes be wasteful,
282 of course, but what do these guys pay $30.000 for? */
284 if ((gdk_visual_get_best() != gdk_visual_get_system()) &&
287 GdkVisual
* vis
= gdk_visual_get_best();
288 gtk_widget_set_default_visual( vis
);
290 GdkColormap
*colormap
= gdk_colormap_new( vis
, FALSE
);
291 gtk_widget_set_default_colormap( colormap
);
296 /* Nothing to do for 15, 16, 24, 32 bit displays */
297 if (visual
->depth
> 8) return TRUE
;
299 /* initialize color cube for 8-bit color reduction dithering */
301 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
303 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
305 for (int r
= 0; r
< 32; r
++)
307 for (int g
= 0; g
< 32; g
++)
309 for (int b
= 0; b
< 32; b
++)
311 int rr
= (r
<< 3) | (r
>> 2);
312 int gg
= (g
<< 3) | (g
>> 2);
313 int bb
= (b
<< 3) | (b
>> 2);
317 GdkColor
*colors
= cmap
->colors
;
322 for (int i
= 0; i
< cmap
->size
; i
++)
324 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
325 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
326 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
327 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
330 index
= i
; max
= sum
;
336 #if (GTK_MINOR_VERSION > 0)
337 /* assume 8-bit true or static colors. this really
339 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
340 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
341 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
342 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
344 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
347 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
355 bool wxApp::ProcessIdle()
358 event
.SetEventObject( this );
359 ProcessEvent( event
);
361 return event
.MoreRequested();
364 void wxApp::OnIdle( wxIdleEvent
&event
)
366 static bool s_inOnIdle
= FALSE
;
368 /* Avoid recursion (via ProcessEvent default case) */
374 /* Resend in the main thread events which have been prepared in other
376 ProcessPendingEvents();
378 /* 'Garbage' collection of windows deleted with Close(). */
379 DeletePendingObjects();
381 /* Send OnIdle events to all windows */
382 bool needMore
= SendIdleEvents();
385 event
.RequestMore(TRUE
);
389 /* flush the logged messages if any */
391 wxLog::FlushActive();
395 bool wxApp::SendIdleEvents()
397 bool needMore
= FALSE
;
399 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
402 wxWindow
* win
= node
->GetData();
403 if (SendIdleEvents(win
))
405 node
= node
->GetNext();
411 bool wxApp::SendIdleEvents( wxWindow
* win
)
413 bool needMore
= FALSE
;
416 event
.SetEventObject(win
);
418 win
->ProcessEvent(event
);
420 win
->OnInternalIdle();
422 if (event
.MoreRequested())
425 wxNode
* node
= win
->GetChildren().First();
428 wxWindow
* win
= (wxWindow
*) node
->Data();
429 if (SendIdleEvents(win
))
437 int wxApp::MainLoop()
443 void wxApp::ExitMainLoop()
445 if (gtk_main_level() > 0)
449 bool wxApp::Initialized()
451 return m_initialized
;
454 bool wxApp::Pending()
456 return (gtk_events_pending() > 0);
459 void wxApp::Dispatch()
461 gtk_main_iteration();
464 void wxApp::DeletePendingObjects()
466 wxNode
*node
= wxPendingDelete
.First();
469 wxObject
*obj
= (wxObject
*)node
->Data();
473 if (wxPendingDelete
.Find(obj
))
476 node
= wxPendingDelete
.First();
480 bool wxApp::Initialize()
482 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
484 wxClassInfo::InitializeClasses();
486 wxSystemSettings::Init();
488 // GL: I'm annoyed ... I don't know where to put this and I don't want to
489 // create a module for that as it's part of the core.
491 wxPendingEvents
= new wxList();
492 wxPendingEventsLocker
= new wxCriticalSection();
495 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
496 wxTheColourDatabase
->Initialize();
498 wxInitializeStockLists();
499 wxInitializeStockObjects();
501 #if wxUSE_WX_RESOURCES
502 wxInitializeResourceSystem();
505 wxModule::RegisterModules();
506 if (!wxModule::InitializeModules()) return FALSE
;
511 void wxApp::CleanUp()
513 wxModule::CleanUpModules();
515 #if wxUSE_WX_RESOURCES
516 wxCleanUpResourceSystem();
519 if (wxTheColourDatabase
)
520 delete wxTheColourDatabase
;
522 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
524 wxDeleteStockObjects();
526 wxDeleteStockLists();
529 wxTheApp
= (wxApp
*) NULL
;
531 // GL: I'm annoyed ... I don't know where to put this and I don't want to
532 // create a module for that as it's part of the core.
534 delete wxPendingEvents
;
535 delete wxPendingEventsLocker
;
538 wxSystemSettings::Done();
542 wxClassInfo::CleanUpClasses();
544 // check for memory leaks
545 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
546 if (wxDebugContext::CountObjectsLeft() > 0)
548 wxLogDebug(wxT("There were memory leaks.\n"));
549 wxDebugContext::Dump();
550 wxDebugContext::PrintStatistics();
555 // do this as the very last thing because everything else can log messages
556 wxLog::DontCreateOnDemand();
558 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
564 //-----------------------------------------------------------------------------
566 //-----------------------------------------------------------------------------
569 int wxEntryStart( int argc
, char *argv
[] )
572 /* GTK 1.2 up to version 1.2.3 has broken threads */
574 if ((vms_gtk_major_version() == 1) &&
575 (vms_gtk_minor_version() == 2) &&
576 (vms_gtk_micro_version() < 4))
578 if ((gtk_major_version
== 1) &&
579 (gtk_minor_version
== 2) &&
580 (gtk_micro_version
< 4))
583 printf( "wxWindows warning: GUI threading disabled due to outdated GTK version\n" );
594 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
596 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
601 gtk_init( &argc
, &argv
);
603 wxSetDetectableAutoRepeat( TRUE
);
605 if (!wxApp::Initialize())
619 if ( !wxTheApp
->OnInitGui() )
622 wxRootWindow
= gtk_window_new( GTK_WINDOW_TOPLEVEL
);
623 gtk_widget_realize( wxRootWindow
);
629 void wxEntryCleanup()
632 // flush the logged messages if any
633 wxLog
*log
= wxLog::GetActiveTarget();
634 if (log
!= NULL
&& log
->HasPendingMessages())
637 // continuing to use user defined log target is unsafe from now on because
638 // some resources may be already unavailable, so replace it by something
640 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);
652 int wxEntry( int argc
, char *argv
[] )
654 int err
= wxEntryStart(argc
, argv
);
660 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
661 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
663 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
665 wxObject
*test_app
= app_ini();
667 wxTheApp
= (wxApp
*) test_app
;
670 wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") );
672 wxTheApp
->argc
= argc
;
674 wxTheApp
->argv
= new wxChar
*[argc
+1];
676 while (mb_argc
< argc
)
678 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
681 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
683 wxTheApp
->argv
= argv
;
686 wxString
name(wxFileNameFromPath(argv
[0]));
687 wxStripExtension( name
);
688 wxTheApp
->SetAppName( name
);
691 retValue
= wxEntryInitGui();
693 // Here frames insert themselves automatically into wxTopLevelWindows by
694 // getting created in OnInit().
697 if ( !wxTheApp
->OnInit() )
703 /* delete pending toplevel windows (typically a single
704 dialog) so that, if there isn't any left, we don't
706 wxTheApp
->DeletePendingObjects();
708 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
710 if (wxTheApp
->Initialized())
714 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
717 /* Forcibly delete the window. */
718 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
719 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
721 topWindow
->Close( TRUE
);
722 wxTheApp
->DeletePendingObjects();
727 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
731 retValue
= wxTheApp
->OnExit();
740 #include "wx/gtk/info.xpm"
741 #include "wx/gtk/error.xpm"
742 #include "wx/gtk/question.xpm"
743 #include "wx/gtk/warning.xpm"
746 wxApp::GetStdIcon(int which
) const
750 case wxICON_INFORMATION
:
751 return wxIcon(info_xpm
);
753 case wxICON_QUESTION
:
754 return wxIcon(question_xpm
);
756 case wxICON_EXCLAMATION
:
757 return wxIcon(warning_xpm
);
760 wxFAIL_MSG(wxT("requested non existent standard icon"));
761 // still fall through
764 return wxIcon(error_xpm
);