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"
29 #if wxUSE_WX_RESOURCES
30 #include "wx/resource.h"
33 #include "wx/module.h"
36 #ifdef __WXUNIVERSAL__
37 #include "wx/univ/theme.h"
38 #include "wx/univ/renderer.h"
42 #include "wx/thread.h"
46 #if defined(__DARWIN__)
47 // FIXME: select must be used instead of poll (GD)
51 # include <sys/poll.h>
53 #include "wx/gtk/win_gtk.h"
58 //-----------------------------------------------------------------------------
60 //-----------------------------------------------------------------------------
62 wxApp
*wxTheApp
= (wxApp
*) NULL
;
63 wxAppInitializerFunction
wxAppBase::m_appInitFn
= (wxAppInitializerFunction
) NULL
;
65 bool g_mainThreadLocked
= FALSE
;
66 gint g_pendingTag
= 0;
68 static GtkWidget
*gs_RootWindow
= (GtkWidget
*) NULL
;
70 //-----------------------------------------------------------------------------
72 //-----------------------------------------------------------------------------
76 void wxapp_install_idle_handler();
78 //-----------------------------------------------------------------------------
80 //-----------------------------------------------------------------------------
87 //-----------------------------------------------------------------------------
89 //-----------------------------------------------------------------------------
91 // not static because used by textctrl.cpp
94 bool wxIsInsideYield
= FALSE
;
96 bool wxApp::Yield(bool onlyIfNeeded
)
98 if ( wxIsInsideYield
)
102 wxFAIL_MSG( wxT("wxYield called recursively" ) );
109 if ( !wxThread::IsMain() )
111 // can't call gtk_main_iteration() from other threads like this
114 #endif // wxUSE_THREADS
116 wxIsInsideYield
= TRUE
;
120 // We need to remove idle callbacks or the loop will
122 gtk_idle_remove( m_idleTag
);
127 // disable log flushing from here because a call to wxYield() shouldn't
128 // normally result in message boxes popping up &c
131 while (gtk_events_pending())
132 gtk_main_iteration();
134 // It's necessary to call ProcessIdle() to update the frames sizes which
135 // might have been changed (it also will update other things set from
136 // OnUpdateUI() which is a nice (and desired) side effect). But we
137 // call ProcessIdle() only once since this is not meant for longish
138 // background jobs (controlled by wxIdleEvent::RequestMore() and the
139 // return value of Processidle().
142 // let the logs be flashed again
145 wxIsInsideYield
= FALSE
;
150 //-----------------------------------------------------------------------------
152 //-----------------------------------------------------------------------------
157 if (!wxThread::IsMain())
162 wxapp_install_idle_handler();
165 if (!wxThread::IsMain())
170 //-----------------------------------------------------------------------------
172 //-----------------------------------------------------------------------------
174 // the callback functions must be extern "C" to comply with GTK+ declarations
178 static gint
wxapp_pending_callback( gpointer
WXUNUSED(data
) )
180 if (!wxTheApp
) return TRUE
;
182 // When getting called from GDK's time-out handler
183 // we are no longer within GDK's grab on the GUI
184 // thread so we must lock it here ourselves.
187 // Sent idle event to all who request them.
188 wxTheApp
->ProcessPendingEvents();
192 // Flush the logged messages if any.
194 wxLog::FlushActive();
197 // Release lock again
200 // Return FALSE to indicate that no more idle events are
201 // to be sent (single shot instead of continuous stream)
205 static gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
211 // don't generate the idle events while the assert modal dialog is shown,
212 // this completely confuses the apps which don't expect to be reentered
213 // from some safely-looking functions
214 if ( wxTheApp
->IsInAssert() )
216 // But repaint the assertion message if necessary
217 if (wxTopLevelWindows
.GetCount() > 0)
219 wxWindow
* win
= (wxWindow
*) wxTopLevelWindows
.Last()->Data();
220 if (win
->IsKindOf(CLASSINFO(wxGenericMessageDialog
)))
221 win
->OnInternalIdle();
225 #endif // __WXDEBUG__
227 // When getting called from GDK's time-out handler
228 // we are no longer within GDK's grab on the GUI
229 // thread so we must lock it here ourselves.
232 // Indicate that we are now in idle mode and event handlers
233 // will have to reinstall the idle handler again.
235 wxTheApp
->m_idleTag
= 0;
237 // Send idle event to all who request them as long as
238 // no events have popped up in the event queue.
239 while (wxTheApp
->ProcessIdle() && (gtk_events_pending() == 0))
242 // Release lock again
245 // Return FALSE to indicate that no more idle events are
246 // to be sent (single shot instead of continuous stream).
252 static gint
wxapp_poll_func( GPollFD
*ufds
, guint nfds
, gint timeout
)
258 g_mainThreadLocked
= TRUE
;
261 // FIXME: poll is not available under Darwin/Mac OS X and this needs
262 // to be implemented using select instead (GD)
263 // what about other BSD derived systems?
266 res
= poll( (struct pollfd
*) ufds
, nfds
, timeout
);
270 g_mainThreadLocked
= FALSE
;
277 #endif // wxUSE_THREADS
281 void wxapp_install_idle_handler()
283 wxASSERT_MSG( wxTheApp
->m_idleTag
== 0, wxT("attempt to install idle handler twice") );
287 if (g_pendingTag
== 0)
288 g_pendingTag
= gtk_idle_add_priority( 900, wxapp_pending_callback
, (gpointer
) NULL
);
290 // This routine gets called by all event handlers
291 // indicating that the idle is over. It may also
292 // get called from other thread for sending events
293 // to the main thread (and processing these in
294 // idle time). Very low priority.
295 wxTheApp
->m_idleTag
= gtk_idle_add_priority( 1000, wxapp_idle_callback
, (gpointer
) NULL
);
298 //-----------------------------------------------------------------------------
299 // Access to the root window global
300 //-----------------------------------------------------------------------------
302 GtkWidget
* wxGetRootWindow()
304 if (gs_RootWindow
== NULL
)
306 gs_RootWindow
= gtk_window_new( GTK_WINDOW_TOPLEVEL
);
307 gtk_widget_realize( gs_RootWindow
);
309 return gs_RootWindow
;
312 //-----------------------------------------------------------------------------
314 //-----------------------------------------------------------------------------
316 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
318 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
319 EVT_IDLE(wxApp::OnIdle
)
324 m_initialized
= FALSE
;
326 m_isInAssert
= FALSE
;
327 #endif // __WXDEBUG__
330 wxapp_install_idle_handler();
333 g_main_set_poll_func( wxapp_poll_func
);
336 m_colorCube
= (unsigned char*) NULL
;
338 // this is NULL for a "regular" wxApp, but is set (and freed) by a wxGLApp
339 m_glVisualInfo
= (void *) NULL
;
344 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
346 if (m_colorCube
) free(m_colorCube
);
349 bool wxApp::OnInitGui()
351 if ( !wxAppBase::OnInitGui() )
354 GdkVisual
*visual
= gdk_visual_get_system();
356 // if this is a wxGLApp (derived from wxApp), and we've already
357 // chosen a specific visual, then derive the GdkVisual from that
358 if (m_glVisualInfo
!= NULL
)
361 // seems gtk_widget_set_default_visual no longer exists?
362 GdkVisual
* vis
= gtk_widget_get_default_visual();
364 GdkVisual
* vis
= gdkx_visual_get(
365 ((XVisualInfo
*) m_glVisualInfo
) ->visualid
);
366 gtk_widget_set_default_visual( vis
);
369 GdkColormap
*colormap
= gdk_colormap_new( vis
, FALSE
);
370 gtk_widget_set_default_colormap( colormap
);
375 // On some machines, the default visual is just 256 colours, so
376 // we make sure we get the best. This can sometimes be wasteful.
379 if ((gdk_visual_get_best() != gdk_visual_get_system()) && (m_useBestVisual
))
382 /* seems gtk_widget_set_default_visual no longer exists? */
383 GdkVisual
* vis
= gtk_widget_get_default_visual();
385 GdkVisual
* vis
= gdk_visual_get_best();
386 gtk_widget_set_default_visual( vis
);
389 GdkColormap
*colormap
= gdk_colormap_new( vis
, FALSE
);
390 gtk_widget_set_default_colormap( colormap
);
395 // Nothing to do for 15, 16, 24, 32 bit displays
396 if (visual
->depth
> 8) return TRUE
;
398 // initialize color cube for 8-bit color reduction dithering
400 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
402 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
404 for (int r
= 0; r
< 32; r
++)
406 for (int g
= 0; g
< 32; g
++)
408 for (int b
= 0; b
< 32; b
++)
410 int rr
= (r
<< 3) | (r
>> 2);
411 int gg
= (g
<< 3) | (g
>> 2);
412 int bb
= (b
<< 3) | (b
>> 2);
416 GdkColor
*colors
= cmap
->colors
;
421 for (int i
= 0; i
< cmap
->size
; i
++)
423 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
424 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
425 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
426 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
429 index
= i
; max
= sum
;
435 // assume 8-bit true or static colors. this really exists
436 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
437 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
438 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
439 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
441 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
449 GdkVisual
*wxApp::GetGdkVisual()
451 GdkVisual
*visual
= NULL
;
454 visual
= gdkx_visual_get( ((XVisualInfo
*) m_glVisualInfo
)->visualid
);
456 visual
= gdk_window_get_visual( wxGetRootWindow()->window
);
463 bool wxApp::ProcessIdle()
466 event
.SetEventObject( this );
467 ProcessEvent( event
);
469 return event
.MoreRequested();
472 void wxApp::OnIdle( wxIdleEvent
&event
)
474 static bool s_inOnIdle
= FALSE
;
476 // Avoid recursion (via ProcessEvent default case)
482 // Resend in the main thread events which have been prepared in other
484 ProcessPendingEvents();
486 // 'Garbage' collection of windows deleted with Close()
487 DeletePendingObjects();
489 // Send OnIdle events to all windows
490 bool needMore
= SendIdleEvents();
493 event
.RequestMore(TRUE
);
498 bool wxApp::SendIdleEvents()
500 bool needMore
= FALSE
;
502 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
505 wxWindow
* win
= node
->GetData();
506 if (SendIdleEvents(win
))
509 node
= node
->GetNext();
512 node
= wxTopLevelWindows
.GetFirst();
515 wxWindow
* win
= node
->GetData();
516 CallInternalIdle( win
);
518 node
= node
->GetNext();
523 bool wxApp::CallInternalIdle( wxWindow
* win
)
525 win
->OnInternalIdle();
527 wxNode
* node
= win
->GetChildren().First();
530 wxWindow
* win
= (wxWindow
*) node
->Data();
531 CallInternalIdle( win
);
539 bool wxApp::SendIdleEvents( wxWindow
* win
)
541 bool needMore
= FALSE
;
544 event
.SetEventObject(win
);
546 win
->GetEventHandler()->ProcessEvent(event
);
548 if (event
.MoreRequested())
551 wxNode
* node
= win
->GetChildren().First();
554 wxWindow
* win
= (wxWindow
*) node
->Data();
555 if (SendIdleEvents(win
))
564 int wxApp::MainLoop()
570 void wxApp::ExitMainLoop()
572 if (gtk_main_level() > 0)
576 bool wxApp::Initialized()
578 return m_initialized
;
581 bool wxApp::Pending()
583 return (gtk_events_pending() > 0);
586 void wxApp::Dispatch()
588 gtk_main_iteration();
591 void wxApp::DeletePendingObjects()
593 wxNode
*node
= wxPendingDelete
.First();
596 wxObject
*obj
= (wxObject
*)node
->Data();
600 if (wxPendingDelete
.Find(obj
))
603 node
= wxPendingDelete
.First();
607 bool wxApp::Initialize()
609 wxClassInfo::InitializeClasses();
612 wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
615 // GL: I'm annoyed ... I don't know where to put this and I don't want to
616 // create a module for that as it's part of the core.
618 wxPendingEvents
= new wxList();
619 wxPendingEventsLocker
= new wxCriticalSection();
622 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
623 wxTheColourDatabase
->Initialize();
625 wxInitializeStockLists();
626 wxInitializeStockObjects();
628 #if wxUSE_WX_RESOURCES
629 wxInitializeResourceSystem();
632 wxModule::RegisterModules();
633 if (!wxModule::InitializeModules()) return FALSE
;
638 void wxApp::CleanUp()
640 wxModule::CleanUpModules();
642 #if wxUSE_WX_RESOURCES
643 wxCleanUpResourceSystem();
646 delete wxTheColourDatabase
;
647 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
649 wxDeleteStockObjects();
651 wxDeleteStockLists();
654 wxTheApp
= (wxApp
*) NULL
;
656 wxClassInfo::CleanUpClasses();
659 delete wxPendingEvents
;
660 delete wxPendingEventsLocker
;
663 // check for memory leaks
664 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
665 if (wxDebugContext::CountObjectsLeft(TRUE
) > 0)
667 wxLogDebug(wxT("There were memory leaks.\n"));
668 wxDebugContext::Dump();
669 wxDebugContext::PrintStatistics();
674 // do this as the very last thing because everything else can log messages
675 wxLog::DontCreateOnDemand();
677 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
683 //-----------------------------------------------------------------------------
685 //-----------------------------------------------------------------------------
687 // NB: argc and argv may be changed here, pass by reference!
688 int wxEntryStart( int& argc
, char *argv
[] )
691 // GTK 1.2 up to version 1.2.3 has broken threads
692 if ((gtk_major_version
== 1) &&
693 (gtk_minor_version
== 2) &&
694 (gtk_micro_version
< 4))
696 printf( "wxWindows warning: GUI threading disabled due to outdated GTK version\n" );
706 // We should have the wxUSE_WCHAR_T test on the _outside_
708 #if defined(__WXGTK20__)
709 // gtk+ 2.0 supports Unicode through UTF-8 strings
710 wxConvCurrent
= &wxConvUTF8
;
712 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
715 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
720 gtk_init( &argc
, &argv
);
722 wxSetDetectableAutoRepeat( TRUE
);
724 if (!wxApp::Initialize())
738 if ( !wxTheApp
->OnInitGui() )
747 void wxEntryCleanup()
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
);
769 int wxEntry( int argc
, char *argv
[] )
771 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
772 // This seems to be necessary since there are 'rogue'
773 // objects present at this point (perhaps global objects?)
774 // Setting a checkpoint will ignore them as far as the
775 // memory checking facility is concerned.
776 // Of course you may argue that memory allocated in globals should be
777 // checked, but this is a reasonable compromise.
778 wxDebugContext::SetCheckpoint();
780 int err
= wxEntryStart(argc
, argv
);
786 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
787 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
789 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
791 wxObject
*test_app
= app_ini();
793 wxTheApp
= (wxApp
*) test_app
;
796 wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") );
798 wxTheApp
->argc
= argc
;
800 wxTheApp
->argv
= new wxChar
*[argc
+1];
802 while (mb_argc
< argc
)
804 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
807 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
809 wxTheApp
->argv
= argv
;
812 wxString
name(wxFileNameFromPath(argv
[0]));
813 wxStripExtension( name
);
814 wxTheApp
->SetAppName( name
);
817 retValue
= wxEntryInitGui();
819 // Here frames insert themselves automatically into wxTopLevelWindows by
820 // getting created in OnInit().
823 if ( !wxTheApp
->OnInit() )
829 // Delete pending toplevel windows
830 wxTheApp
->DeletePendingObjects();
832 // When is the app not initialized ?
833 wxTheApp
->m_initialized
= TRUE
;
835 if (wxTheApp
->Initialized())
839 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
841 // Delete all pending windows if any
842 wxTheApp
->DeletePendingObjects();
846 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
848 retValue
= wxTheApp
->OnExit();
859 void wxApp::OnAssert(const wxChar
*file
, int line
, const wxChar
* cond
, const wxChar
*msg
)
863 wxAppBase::OnAssert(file
, line
, cond
, msg
);
865 m_isInAssert
= FALSE
;
868 #endif // __WXDEBUG__