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 <vms_jackets.h>
19 #include "wx/gdicmn.h"
23 #include "wx/memory.h"
25 #include "wx/settings.h"
26 #include "wx/dialog.h"
27 #include "wx/msgdlg.h"
30 #if wxUSE_WX_RESOURCES
31 #include "wx/resource.h"
34 #include "wx/module.h"
37 #ifdef __WXUNIVERSAL__
38 #include "wx/univ/theme.h"
39 #include "wx/univ/renderer.h"
43 #include "wx/thread.h"
47 #if defined(__DARWIN__)
48 # warning "FIXME: select must be used instead of poll (GD)"
52 # include <sys/poll.h>
54 #include "wx/gtk/win_gtk.h"
59 //-----------------------------------------------------------------------------
61 //-----------------------------------------------------------------------------
63 wxApp
*wxTheApp
= (wxApp
*) NULL
;
64 wxAppInitializerFunction
wxAppBase::m_appInitFn
= (wxAppInitializerFunction
) NULL
;
66 bool g_mainThreadLocked
= FALSE
;
67 gint g_pendingTag
= 0;
69 static GtkWidget
*gs_RootWindow
= (GtkWidget
*) NULL
;
71 //-----------------------------------------------------------------------------
73 //-----------------------------------------------------------------------------
77 void wxapp_install_idle_handler();
79 //-----------------------------------------------------------------------------
81 //-----------------------------------------------------------------------------
88 //-----------------------------------------------------------------------------
90 //-----------------------------------------------------------------------------
92 // not static because used by textctrl.cpp
95 bool wxIsInsideYield
= FALSE
;
97 bool wxApp::Yield(bool onlyIfNeeded
)
99 if ( wxIsInsideYield
)
103 wxFAIL_MSG( wxT("wxYield called recursively" ) );
110 if ( !wxThread::IsMain() )
112 // can't call gtk_main_iteration() from other threads like this
115 #endif // wxUSE_THREADS
117 wxIsInsideYield
= TRUE
;
121 // We need to remove idle callbacks or the loop will
123 gtk_idle_remove( m_idleTag
);
128 // disable log flushing from here because a call to wxYield() shouldn't
129 // normally result in message boxes popping up &c
132 while (gtk_events_pending())
133 gtk_main_iteration();
135 // It's necessary to call ProcessIdle() to update the frames sizes which
136 // might have been changed (it also will update other things set from
137 // OnUpdateUI() which is a nice (and desired) side effect). But we
138 // call ProcessIdle() only once since this is not meant for longish
139 // background jobs (controlled by wxIdleEvent::RequestMore() and the
140 // return value of Processidle().
143 // let the logs be flashed again
146 wxIsInsideYield
= FALSE
;
151 //-----------------------------------------------------------------------------
153 //-----------------------------------------------------------------------------
158 if (!wxThread::IsMain())
163 wxapp_install_idle_handler();
166 if (!wxThread::IsMain())
171 //-----------------------------------------------------------------------------
173 //-----------------------------------------------------------------------------
175 // the callback functions must be extern "C" to comply with GTK+ declarations
179 static gint
wxapp_pending_callback( gpointer
WXUNUSED(data
) )
181 if (!wxTheApp
) return TRUE
;
183 // When getting called from GDK's time-out handler
184 // we are no longer within GDK's grab on the GUI
185 // thread so we must lock it here ourselves.
188 // Sent idle event to all who request them.
189 wxTheApp
->ProcessPendingEvents();
193 // Flush the logged messages if any.
195 wxLog::FlushActive();
198 // Release lock again
201 // Return FALSE to indicate that no more idle events are
202 // to be sent (single shot instead of continuous stream)
206 static gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
212 // don't generate the idle events while the assert modal dialog is shown,
213 // this completely confuses the apps which don't expect to be reentered
214 // from some safely-looking functions
215 if ( wxTheApp
->IsInAssert() )
217 // But repaint the assertion message if necessary
218 if (wxTopLevelWindows
.GetCount() > 0)
220 wxWindow
* win
= (wxWindow
*) wxTopLevelWindows
.Last()->Data();
221 if (win
->IsKindOf(CLASSINFO(wxGenericMessageDialog
)))
222 win
->OnInternalIdle();
226 #endif // __WXDEBUG__
228 // When getting called from GDK's time-out handler
229 // we are no longer within GDK's grab on the GUI
230 // thread so we must lock it here ourselves.
233 // Indicate that we are now in idle mode and event handlers
234 // will have to reinstall the idle handler again.
236 wxTheApp
->m_idleTag
= 0;
238 // Send idle event to all who request them as long as
239 // no events have popped up in the event queue.
240 while (wxTheApp
->ProcessIdle() && (gtk_events_pending() == 0))
243 // Release lock again
246 // Return FALSE to indicate that no more idle events are
247 // to be sent (single shot instead of continuous stream).
253 static gint
wxapp_poll_func( GPollFD
*ufds
, guint nfds
, gint timeout
)
259 g_mainThreadLocked
= TRUE
;
262 // FIXME: poll is not available under Darwin/Mac OS X and this needs
263 // to be implemented using select instead (GD)
264 // what about other BSD derived systems?
267 res
= poll( (struct pollfd
*) ufds
, nfds
, timeout
);
271 g_mainThreadLocked
= FALSE
;
278 #endif // wxUSE_THREADS
282 void wxapp_install_idle_handler()
284 wxASSERT_MSG( wxTheApp
->m_idleTag
== 0, wxT("attempt to install idle handler twice") );
288 if (g_pendingTag
== 0)
289 g_pendingTag
= gtk_idle_add_priority( 900, wxapp_pending_callback
, (gpointer
) NULL
);
291 // This routine gets called by all event handlers
292 // indicating that the idle is over. It may also
293 // get called from other thread for sending events
294 // to the main thread (and processing these in
295 // idle time). Very low priority.
296 wxTheApp
->m_idleTag
= gtk_idle_add_priority( 1000, wxapp_idle_callback
, (gpointer
) NULL
);
299 //-----------------------------------------------------------------------------
300 // Access to the root window global
301 //-----------------------------------------------------------------------------
303 GtkWidget
* wxGetRootWindow()
305 if (gs_RootWindow
== NULL
)
307 gs_RootWindow
= gtk_window_new( GTK_WINDOW_TOPLEVEL
);
308 gtk_widget_realize( gs_RootWindow
);
310 return gs_RootWindow
;
313 //-----------------------------------------------------------------------------
315 //-----------------------------------------------------------------------------
317 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
319 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
320 EVT_IDLE(wxApp::OnIdle
)
325 m_initialized
= FALSE
;
327 m_isInAssert
= FALSE
;
328 #endif // __WXDEBUG__
331 wxapp_install_idle_handler();
334 g_main_set_poll_func( wxapp_poll_func
);
337 m_colorCube
= (unsigned char*) NULL
;
339 // this is NULL for a "regular" wxApp, but is set (and freed) by a wxGLApp
340 m_glVisualInfo
= (void *) NULL
;
345 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
347 if (m_colorCube
) free(m_colorCube
);
350 bool wxApp::OnInitGui()
352 if ( !wxAppBase::OnInitGui() )
355 GdkVisual
*visual
= gdk_visual_get_system();
357 // if this is a wxGLApp (derived from wxApp), and we've already
358 // chosen a specific visual, then derive the GdkVisual from that
359 if (m_glVisualInfo
!= NULL
)
362 // seems gtk_widget_set_default_visual no longer exists?
363 GdkVisual
* vis
= gtk_widget_get_default_visual();
365 GdkVisual
* vis
= gdkx_visual_get(
366 ((XVisualInfo
*) m_glVisualInfo
) ->visualid
);
367 gtk_widget_set_default_visual( vis
);
370 GdkColormap
*colormap
= gdk_colormap_new( vis
, FALSE
);
371 gtk_widget_set_default_colormap( colormap
);
376 // On some machines, the default visual is just 256 colours, so
377 // we make sure we get the best. This can sometimes be wasteful.
380 if ((gdk_visual_get_best() != gdk_visual_get_system()) && (m_useBestVisual
))
383 /* seems gtk_widget_set_default_visual no longer exists? */
384 GdkVisual
* vis
= gtk_widget_get_default_visual();
386 GdkVisual
* vis
= gdk_visual_get_best();
387 gtk_widget_set_default_visual( vis
);
390 GdkColormap
*colormap
= gdk_colormap_new( vis
, FALSE
);
391 gtk_widget_set_default_colormap( colormap
);
396 // Nothing to do for 15, 16, 24, 32 bit displays
397 if (visual
->depth
> 8) return TRUE
;
399 // initialize color cube for 8-bit color reduction dithering
401 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
403 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
405 for (int r
= 0; r
< 32; r
++)
407 for (int g
= 0; g
< 32; g
++)
409 for (int b
= 0; b
< 32; b
++)
411 int rr
= (r
<< 3) | (r
>> 2);
412 int gg
= (g
<< 3) | (g
>> 2);
413 int bb
= (b
<< 3) | (b
>> 2);
417 GdkColor
*colors
= cmap
->colors
;
422 for (int i
= 0; i
< cmap
->size
; i
++)
424 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
425 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
426 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
427 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
430 index
= i
; max
= sum
;
436 // assume 8-bit true or static colors. this really exists
437 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
438 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
439 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
440 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
442 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
450 GdkVisual
*wxApp::GetGdkVisual()
452 GdkVisual
*visual
= NULL
;
455 visual
= gdkx_visual_get( ((XVisualInfo
*) m_glVisualInfo
)->visualid
);
457 visual
= gdk_window_get_visual( wxGetRootWindow()->window
);
464 bool wxApp::ProcessIdle()
467 event
.SetEventObject( this );
468 ProcessEvent( event
);
470 return event
.MoreRequested();
473 void wxApp::OnIdle( wxIdleEvent
&event
)
475 static bool s_inOnIdle
= FALSE
;
477 // Avoid recursion (via ProcessEvent default case)
483 // Resend in the main thread events which have been prepared in other
485 ProcessPendingEvents();
487 // 'Garbage' collection of windows deleted with Close()
488 DeletePendingObjects();
490 // Send OnIdle events to all windows
491 bool needMore
= SendIdleEvents();
494 event
.RequestMore(TRUE
);
499 bool wxApp::SendIdleEvents()
501 bool needMore
= FALSE
;
503 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
506 wxWindow
* win
= node
->GetData();
507 if (SendIdleEvents(win
))
510 node
= node
->GetNext();
513 node
= wxTopLevelWindows
.GetFirst();
516 wxWindow
* win
= node
->GetData();
517 CallInternalIdle( win
);
519 node
= node
->GetNext();
524 bool wxApp::CallInternalIdle( wxWindow
* win
)
526 win
->OnInternalIdle();
528 wxNode
* node
= win
->GetChildren().First();
531 wxWindow
* win
= (wxWindow
*) node
->Data();
532 CallInternalIdle( win
);
540 bool wxApp::SendIdleEvents( wxWindow
* win
)
542 bool needMore
= FALSE
;
545 event
.SetEventObject(win
);
547 win
->GetEventHandler()->ProcessEvent(event
);
549 if (event
.MoreRequested())
552 wxNode
* node
= win
->GetChildren().First();
555 wxWindow
* win
= (wxWindow
*) node
->Data();
556 if (SendIdleEvents(win
))
565 int wxApp::MainLoop()
571 void wxApp::ExitMainLoop()
573 if (gtk_main_level() > 0)
577 bool wxApp::Initialized()
579 return m_initialized
;
582 bool wxApp::Pending()
584 return (gtk_events_pending() > 0);
587 void wxApp::Dispatch()
589 gtk_main_iteration();
592 void wxApp::DeletePendingObjects()
594 wxNode
*node
= wxPendingDelete
.First();
597 wxObject
*obj
= (wxObject
*)node
->Data();
601 if (wxPendingDelete
.Find(obj
))
604 node
= wxPendingDelete
.First();
608 bool wxApp::Initialize()
610 wxClassInfo::InitializeClasses();
613 wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
616 // GL: I'm annoyed ... I don't know where to put this and I don't want to
617 // create a module for that as it's part of the core.
619 wxPendingEvents
= new wxList();
620 wxPendingEventsLocker
= new wxCriticalSection();
623 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
624 wxTheColourDatabase
->Initialize();
626 wxInitializeStockLists();
627 wxInitializeStockObjects();
629 #if wxUSE_WX_RESOURCES
630 wxInitializeResourceSystem();
633 wxModule::RegisterModules();
634 if (!wxModule::InitializeModules()) return FALSE
;
639 void wxApp::CleanUp()
641 wxModule::CleanUpModules();
643 #if wxUSE_WX_RESOURCES
644 wxCleanUpResourceSystem();
647 delete wxTheColourDatabase
;
648 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
650 wxDeleteStockObjects();
652 wxDeleteStockLists();
655 wxTheApp
= (wxApp
*) NULL
;
657 wxClassInfo::CleanUpClasses();
660 delete wxPendingEvents
;
661 delete wxPendingEventsLocker
;
664 // check for memory leaks
665 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
666 if (wxDebugContext::CountObjectsLeft(TRUE
) > 0)
668 wxLogDebug(wxT("There were memory leaks.\n"));
669 wxDebugContext::Dump();
670 wxDebugContext::PrintStatistics();
675 // do this as the very last thing because everything else can log messages
676 wxLog::DontCreateOnDemand();
678 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
684 //-----------------------------------------------------------------------------
686 //-----------------------------------------------------------------------------
688 // NB: argc and argv may be changed here, pass by reference!
689 int wxEntryStart( int& argc
, char *argv
[] )
692 // GTK 1.2 up to version 1.2.3 has broken threads
693 if ((gtk_major_version
== 1) &&
694 (gtk_minor_version
== 2) &&
695 (gtk_micro_version
< 4))
697 printf( "wxWindows warning: GUI threading disabled due to outdated GTK version\n" );
707 // We should have the wxUSE_WCHAR_T test on the _outside_
709 #if defined(__WXGTK20__)
710 // gtk+ 2.0 supports Unicode through UTF-8 strings
711 wxConvCurrent
= &wxConvUTF8
;
713 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
716 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
721 gtk_init( &argc
, &argv
);
723 wxSetDetectableAutoRepeat( TRUE
);
725 if (!wxApp::Initialize())
739 if ( !wxTheApp
->OnInitGui() )
748 void wxEntryCleanup()
751 // flush the logged messages if any
752 wxLog
*log
= wxLog::GetActiveTarget();
753 if (log
!= NULL
&& log
->HasPendingMessages())
756 // continuing to use user defined log target is unsafe from now on because
757 // some resources may be already unavailable, so replace it by something
759 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);
770 int wxEntry( int argc
, char *argv
[] )
772 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
773 // This seems to be necessary since there are 'rogue'
774 // objects present at this point (perhaps global objects?)
775 // Setting a checkpoint will ignore them as far as the
776 // memory checking facility is concerned.
777 // Of course you may argue that memory allocated in globals should be
778 // checked, but this is a reasonable compromise.
779 wxDebugContext::SetCheckpoint();
781 int err
= wxEntryStart(argc
, argv
);
787 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
788 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
790 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
792 wxObject
*test_app
= app_ini();
794 wxTheApp
= (wxApp
*) test_app
;
797 wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") );
799 wxTheApp
->argc
= argc
;
801 wxTheApp
->argv
= new wxChar
*[argc
+1];
803 while (mb_argc
< argc
)
805 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
808 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
810 wxTheApp
->argv
= argv
;
813 wxString
name(wxFileNameFromPath(argv
[0]));
814 wxStripExtension( name
);
815 wxTheApp
->SetAppName( name
);
818 retValue
= wxEntryInitGui();
820 // Here frames insert themselves automatically into wxTopLevelWindows by
821 // getting created in OnInit().
824 if ( !wxTheApp
->OnInit() )
830 // Delete pending toplevel windows
831 wxTheApp
->DeletePendingObjects();
833 // When is the app not initialized ?
834 wxTheApp
->m_initialized
= TRUE
;
836 if (wxTheApp
->Initialized())
840 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
842 // Delete all pending windows if any
843 wxTheApp
->DeletePendingObjects();
847 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
849 retValue
= wxTheApp
->OnExit();
860 void wxApp::OnAssert(const wxChar
*file
, int line
, const wxChar
* cond
, const wxChar
*msg
)
864 wxAppBase::OnAssert(file
, line
, cond
, msg
);
866 m_isInAssert
= FALSE
;
869 #endif // __WXDEBUG__