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
;
53 gint g_pendingTag
= 0;
55 GtkWidget
*wxRootWindow
= (GtkWidget
*) NULL
;
57 //-----------------------------------------------------------------------------
59 //-----------------------------------------------------------------------------
61 /* forward declaration */
62 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) );
63 gint
wxapp_pending_callback( gpointer
WXUNUSED(data
) );
64 void wxapp_install_idle_handler();
67 gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) );
70 //-----------------------------------------------------------------------------
72 //-----------------------------------------------------------------------------
79 //-----------------------------------------------------------------------------
81 //-----------------------------------------------------------------------------
85 bool has_idle
= (wxTheApp
->m_idleTag
!= 0);
89 /* We need to temporarily remove idle callbacks or the loop will
91 gtk_idle_remove( wxTheApp
->m_idleTag
);
92 wxTheApp
->m_idleTag
= 0;
95 while (gtk_events_pending())
100 /* re-add idle handler (very low priority) */
101 wxTheApp
->m_idleTag
= gtk_idle_add_priority( 1000, wxapp_idle_callback
, (gpointer
) NULL
);
104 // disable log flushing from here because a call to wxYield() shouldn't
105 // normally result in message boxes popping up &c
108 /* it's necessary to call ProcessIdle() to update the frames sizes which
109 might have been changed (it also will update other things set from
110 OnUpdateUI() which is a nice (and desired) side effect) */
111 while (wxTheApp
->ProcessIdle()) { }
113 // let the logs be flashed again
119 //-----------------------------------------------------------------------------
121 //-----------------------------------------------------------------------------
126 if (!wxThread::IsMain())
131 wxapp_install_idle_handler();
134 if (!wxThread::IsMain())
139 //-----------------------------------------------------------------------------
141 //-----------------------------------------------------------------------------
143 gint
wxapp_pending_callback( gpointer
WXUNUSED(data
) )
145 if (!wxTheApp
) return TRUE
;
147 // when getting called from GDK's time-out handler
148 // we are no longer within GDK's grab on the GUI
149 // thread so we must lock it here ourselves
152 // Sent idle event to all who request them
153 wxTheApp
->ProcessPendingEvents();
157 // Release lock again
160 // Return FALSE to indicate that no more idle events are
161 // to be sent (single shot instead of continuous stream)
165 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
167 if (!wxTheApp
) return TRUE
;
169 // when getting called from GDK's time-out handler
170 // we are no longer within GDK's grab on the GUI
171 // thread so we must lock it here ourselves
174 // Sent idle event to all who request them
175 while (wxTheApp
->ProcessIdle()) { }
177 /* Indicate that we are now in idle mode - even so deeply
178 in idle mode that we don't get any idle events anymore.
179 this is like wxMSW where an idle event is sent only
180 once each time after the event queue has been completely
183 wxTheApp
->m_idleTag
= 0;
185 // Release lock again
188 // Return FALSE to indicate that no more idle events are
189 // to be sent (single shot instead of continuous stream)
193 void wxapp_install_idle_handler()
195 wxASSERT_MSG( wxTheApp
->m_idleTag
== 0, wxT("attempt to install idle handler twice") );
197 if (g_pendingTag
== 0)
198 g_pendingTag
= gtk_idle_add_priority( 900, wxapp_pending_callback
, (gpointer
) NULL
);
200 /* This routine gets called by all event handlers
201 indicating that the idle is over. It may also
202 get called from other thread for sending events
203 to the main thread (and processing these in
204 idle time). Very low priority. */
206 wxTheApp
->m_idleTag
= gtk_idle_add_priority( 1000, wxapp_idle_callback
, (gpointer
) NULL
);
213 static int g_threadUninstallLevel
= 0;
215 void wxapp_install_thread_wakeup()
217 g_threadUninstallLevel
++;
219 if (g_threadUninstallLevel
!= 1) return;
221 if (wxTheApp
->m_wakeUpTimerTag
) return;
223 wxTheApp
->m_wakeUpTimerTag
= gtk_timeout_add( 50, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
226 void wxapp_uninstall_thread_wakeup()
228 g_threadUninstallLevel
--;
230 if (g_threadUninstallLevel
!= 0) return;
232 if (!wxTheApp
->m_wakeUpTimerTag
) return;
234 gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag
);
235 wxTheApp
->m_wakeUpTimerTag
= 0;
238 gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) )
240 // when getting called from GDK's time-out handler
241 // we are no longer within GDK's grab on the GUI
242 // thread so we must lock it here ourselves
245 wxapp_uninstall_thread_wakeup();
247 // unblock other threads wishing to do some GUI things
250 g_mainThreadLocked
= TRUE
;
252 // wake up other threads
255 // block other thread again
258 g_mainThreadLocked
= FALSE
;
260 wxapp_install_thread_wakeup();
262 // release lock again
268 #endif // wxUSE_THREADS
270 //-----------------------------------------------------------------------------
272 //-----------------------------------------------------------------------------
274 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
276 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
277 EVT_IDLE(wxApp::OnIdle
)
284 m_topWindow
= (wxWindow
*) NULL
;
285 m_exitOnFrameDelete
= TRUE
;
287 m_idleTag
= gtk_idle_add_priority( 1000, wxapp_idle_callback
, (gpointer
) NULL
);
290 m_wakeUpTimerTag
= 0;
291 wxapp_install_thread_wakeup();
294 m_colorCube
= (unsigned char*) NULL
;
296 m_useBestVisual
= FALSE
;
301 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
304 wxapp_uninstall_thread_wakeup();
307 if (m_colorCube
) free(m_colorCube
);
310 bool wxApp::OnInitGui()
312 GdkVisual
*visual
= gdk_visual_get_system();
314 /* on some machines, the default visual is just 256 colours, so
315 we make sure we get the best. this can sometimes be wasteful,
316 of course, but what do these guys pay $30.000 for? */
318 if ((gdk_visual_get_best() != gdk_visual_get_system()) &&
322 /* seems gtk_widget_set_default_visual no longer exists? */
323 GdkVisual
* vis
= gtk_widget_get_default_visual();
325 GdkVisual
* vis
= gdk_visual_get_best();
326 gtk_widget_set_default_visual( vis
);
329 GdkColormap
*colormap
= gdk_colormap_new( vis
, FALSE
);
330 gtk_widget_set_default_colormap( colormap
);
335 /* Nothing to do for 15, 16, 24, 32 bit displays */
336 if (visual
->depth
> 8) return TRUE
;
338 /* initialize color cube for 8-bit color reduction dithering */
340 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
342 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
344 for (int r
= 0; r
< 32; r
++)
346 for (int g
= 0; g
< 32; g
++)
348 for (int b
= 0; b
< 32; b
++)
350 int rr
= (r
<< 3) | (r
>> 2);
351 int gg
= (g
<< 3) | (g
>> 2);
352 int bb
= (b
<< 3) | (b
>> 2);
356 GdkColor
*colors
= cmap
->colors
;
361 for (int i
= 0; i
< cmap
->size
; i
++)
363 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
364 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
365 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
366 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
369 index
= i
; max
= sum
;
375 #if (GTK_MINOR_VERSION > 0)
376 /* assume 8-bit true or static colors. this really
378 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
379 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
380 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
381 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
383 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
386 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
394 bool wxApp::ProcessIdle()
397 event
.SetEventObject( this );
398 ProcessEvent( event
);
400 return event
.MoreRequested();
403 void wxApp::OnIdle( wxIdleEvent
&event
)
405 static bool s_inOnIdle
= FALSE
;
407 /* Avoid recursion (via ProcessEvent default case) */
413 /* Resend in the main thread events which have been prepared in other
415 ProcessPendingEvents();
417 /* 'Garbage' collection of windows deleted with Close(). */
418 DeletePendingObjects();
420 /* Send OnIdle events to all windows */
421 bool needMore
= SendIdleEvents();
424 event
.RequestMore(TRUE
);
428 /* flush the logged messages if any */
430 wxLog::FlushActive();
434 bool wxApp::SendIdleEvents()
436 bool needMore
= FALSE
;
438 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
441 wxWindow
* win
= node
->GetData();
442 if (SendIdleEvents(win
))
444 node
= node
->GetNext();
450 bool wxApp::SendIdleEvents( wxWindow
* win
)
452 bool needMore
= FALSE
;
455 event
.SetEventObject(win
);
457 win
->GetEventHandler()->ProcessEvent(event
);
459 win
->OnInternalIdle();
461 if (event
.MoreRequested())
464 wxNode
* node
= win
->GetChildren().First();
467 wxWindow
* win
= (wxWindow
*) node
->Data();
468 if (SendIdleEvents(win
))
476 int wxApp::MainLoop()
482 void wxApp::ExitMainLoop()
484 if (gtk_main_level() > 0)
488 bool wxApp::Initialized()
490 return m_initialized
;
493 bool wxApp::Pending()
495 return (gtk_events_pending() > 0);
498 void wxApp::Dispatch()
500 gtk_main_iteration();
503 void wxApp::DeletePendingObjects()
505 wxNode
*node
= wxPendingDelete
.First();
508 wxObject
*obj
= (wxObject
*)node
->Data();
512 if (wxPendingDelete
.Find(obj
))
515 node
= wxPendingDelete
.First();
519 bool wxApp::Initialize()
521 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
523 wxClassInfo::InitializeClasses();
525 wxSystemSettings::Init();
527 // GL: I'm annoyed ... I don't know where to put this and I don't want to
528 // create a module for that as it's part of the core.
530 wxPendingEvents
= new wxList();
531 wxPendingEventsLocker
= new wxCriticalSection();
534 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
535 wxTheColourDatabase
->Initialize();
537 wxInitializeStockLists();
538 wxInitializeStockObjects();
540 #if wxUSE_WX_RESOURCES
541 wxInitializeResourceSystem();
544 wxModule::RegisterModules();
545 if (!wxModule::InitializeModules()) return FALSE
;
550 void wxApp::CleanUp()
552 wxModule::CleanUpModules();
554 #if wxUSE_WX_RESOURCES
555 wxCleanUpResourceSystem();
558 if (wxTheColourDatabase
)
559 delete wxTheColourDatabase
;
561 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
563 wxDeleteStockObjects();
565 wxDeleteStockLists();
568 wxTheApp
= (wxApp
*) NULL
;
570 // GL: I'm annoyed ... I don't know where to put this and I don't want to
571 // create a module for that as it's part of the core.
573 delete wxPendingEvents
;
574 delete wxPendingEventsLocker
;
577 wxSystemSettings::Done();
581 wxClassInfo::CleanUpClasses();
583 // check for memory leaks
584 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
585 if (wxDebugContext::CountObjectsLeft(TRUE
) > 0)
587 wxLogDebug(wxT("There were memory leaks.\n"));
588 wxDebugContext::Dump();
589 wxDebugContext::PrintStatistics();
594 // do this as the very last thing because everything else can log messages
595 wxLog::DontCreateOnDemand();
597 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
603 //-----------------------------------------------------------------------------
605 //-----------------------------------------------------------------------------
608 int wxEntryStart( int argc
, char *argv
[] )
611 /* GTK 1.2 up to version 1.2.3 has broken threads */
613 if ((vms_gtk_major_version() == 1) &&
614 (vms_gtk_minor_version() == 2) &&
615 (vms_gtk_micro_version() < 4))
617 if ((gtk_major_version
== 1) &&
618 (gtk_minor_version
== 2) &&
619 (gtk_micro_version
< 4))
622 printf( "wxWindows warning: GUI threading disabled due to outdated GTK version\n" );
632 #if defined(__WXGTK20__)
633 // gtk+ 2.0 supports Unicode through UTF-8 strings
634 wxConvCurrent
= &wxConvUTF8
;
636 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
638 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
643 gtk_init( &argc
, &argv
);
645 wxSetDetectableAutoRepeat( TRUE
);
647 if (!wxApp::Initialize())
661 if ( !wxTheApp
->OnInitGui() )
664 wxRootWindow
= gtk_window_new( GTK_WINDOW_TOPLEVEL
);
665 gtk_widget_realize( wxRootWindow
);
671 void wxEntryCleanup()
674 // flush the logged messages if any
675 wxLog
*log
= wxLog::GetActiveTarget();
676 if (log
!= NULL
&& log
->HasPendingMessages())
679 // continuing to use user defined log target is unsafe from now on because
680 // some resources may be already unavailable, so replace it by something
682 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);
694 int wxEntry( int argc
, char *argv
[] )
696 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
697 // This seems to be necessary since there are 'rogue'
698 // objects present at this point (perhaps global objects?)
699 // Setting a checkpoint will ignore them as far as the
700 // memory checking facility is concerned.
701 // Of course you may argue that memory allocated in globals should be
702 // checked, but this is a reasonable compromise.
703 wxDebugContext::SetCheckpoint();
705 int err
= wxEntryStart(argc
, argv
);
711 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
712 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
714 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
716 wxObject
*test_app
= app_ini();
718 wxTheApp
= (wxApp
*) test_app
;
721 wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") );
723 wxTheApp
->argc
= argc
;
725 wxTheApp
->argv
= new wxChar
*[argc
+1];
727 while (mb_argc
< argc
)
729 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
732 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
734 wxTheApp
->argv
= argv
;
737 wxString
name(wxFileNameFromPath(argv
[0]));
738 wxStripExtension( name
);
739 wxTheApp
->SetAppName( name
);
742 retValue
= wxEntryInitGui();
744 // Here frames insert themselves automatically into wxTopLevelWindows by
745 // getting created in OnInit().
748 if ( !wxTheApp
->OnInit() )
754 /* delete pending toplevel windows (typically a single
755 dialog) so that, if there isn't any left, we don't
757 wxTheApp
->DeletePendingObjects();
759 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
761 if (wxTheApp
->Initialized())
765 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
768 /* Forcibly delete the window. */
769 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
770 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
772 topWindow
->Close( TRUE
);
773 wxTheApp
->DeletePendingObjects();
778 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
782 retValue
= wxTheApp
->OnExit();
791 #include "wx/gtk/info.xpm"
792 #include "wx/gtk/error.xpm"
793 #include "wx/gtk/question.xpm"
794 #include "wx/gtk/warning.xpm"
797 wxApp::GetStdIcon(int which
) const
801 case wxICON_INFORMATION
:
802 return wxIcon(info_xpm
);
804 case wxICON_QUESTION
:
805 return wxIcon(question_xpm
);
807 case wxICON_EXCLAMATION
:
808 return wxIcon(warning_xpm
);
811 wxFAIL_MSG(wxT("requested non existent standard icon"));
812 // still fall through
815 return wxIcon(error_xpm
);