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 //-----------------------------------------------------------------------------
129 //-----------------------------------------------------------------------------
136 /* forward declaration */
137 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) );
141 bool has_idle
= (wxTheApp
->m_idleTag
!= 0);
145 /* We need to temporarily remove idle callbacks or the loop will
147 gtk_idle_remove( wxTheApp
->m_idleTag
);
148 wxTheApp
->m_idleTag
= 0;
151 while (gtk_events_pending())
152 gtk_main_iteration();
154 /* it's necessary to call ProcessIdle() to update the frames sizes which
155 might have been changed (it also will update other things set from
156 OnUpdateUI() which is a nice (and desired) side effect) */
157 while (wxTheApp
->ProcessIdle()) { }
161 /* re-add idle handler */
162 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
168 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
170 if (!wxTheApp
) return TRUE
;
172 #if (GTK_MINOR_VERSION > 0)
173 /* when getting called from GDK's idle handler we
174 are no longer within GDK's grab on the GUI
175 thread so we must lock it here ourselves */
176 GDK_THREADS_ENTER ();
179 /* sent idle event to all who request them */
180 while (wxTheApp
->ProcessIdle()) { }
182 /* we don't want any more idle events until the next event is
184 gtk_idle_remove( wxTheApp
->m_idleTag
);
185 wxTheApp
->m_idleTag
= 0;
187 /* indicate that we are now in idle mode - even so deeply
188 in idle mode that we don't get any idle events anymore.
189 this is like wxMSW where an idle event is sent only
190 once each time after the event queue has been completely
194 #if (GTK_MINOR_VERSION > 0)
195 /* release lock again */
196 GDK_THREADS_LEAVE ();
202 void wxapp_install_idle_handler()
204 wxASSERT_MSG( wxTheApp
->m_idleTag
== 0, wxT("attempt to install idle handler twice") );
206 /* this routine gets called by all event handlers
207 indicating that the idle is over. */
209 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
216 /* forward declaration */
217 static gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) );
219 void wxapp_install_thread_wakeup()
221 if (wxTheApp
->m_wakeUpTimerTag
) return;
223 wxTheApp
->m_wakeUpTimerTag
= gtk_timeout_add( 100, wxapp_wakeup_timerout_callback
, (gpointer
) NULL
);
226 void wxapp_uninstall_thread_wakeup()
228 if (!wxTheApp
->m_wakeUpTimerTag
) return;
230 gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag
);
231 wxTheApp
->m_wakeUpTimerTag
= 0;
234 static gint
wxapp_wakeup_timerout_callback( gpointer
WXUNUSED(data
) )
236 wxapp_uninstall_thread_wakeup();
238 #if (GTK_MINOR_VERSION > 0)
239 // when getting called from GDK's time-out handler
240 // we are no longer within GDK's grab on the GUI
241 // thread so we must lock it here ourselves
242 GDK_THREADS_ENTER ();
245 // unblock other threads wishing to do some GUI things
248 // wake up other threads
251 // block other thread again
254 #if (GTK_MINOR_VERSION > 0)
255 // release lock again
256 GDK_THREADS_LEAVE ();
259 wxapp_install_thread_wakeup();
264 #endif // wxUSE_THREADS
266 //-----------------------------------------------------------------------------
268 //-----------------------------------------------------------------------------
270 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
272 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
273 EVT_IDLE(wxApp::OnIdle
)
280 m_topWindow
= (wxWindow
*) NULL
;
281 m_exitOnFrameDelete
= TRUE
;
283 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
286 m_wakeUpTimerTag
= 0;
287 wxapp_install_thread_wakeup();
290 m_colorCube
= (unsigned char*) NULL
;
295 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
298 wxapp_uninstall_thread_wakeup();
301 if (m_colorCube
) free(m_colorCube
);
304 bool wxApp::OnInitGui()
306 GdkVisual
*visual
= gdk_visual_get_system();
308 /* on some machines, the default visual is just 256 colours, so
309 we make sure we get the best. this can sometimes be wasteful,
310 of course, but what do these guys pay $30.000 for? */
312 if (gdk_visual_get_best() != gdk_visual_get_system())
314 GdkVisual* vis = gdk_visual_get_best();
315 gtk_widget_set_default_visual( vis );
317 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
318 gtk_widget_set_default_colormap( colormap );
324 /* Nothing to do for 15, 16, 24, 32 bit displays */
325 if (visual
->depth
> 8) return TRUE
;
327 /* this initiates the standard palette as defined by GdkImlib
328 in the GNOME libraries. it ensures that all GNOME applications
329 use the same 64 colormap entries on 8-bit displays so you
330 can use several rather graphics-heavy applications at the
332 NOTE: this doesn't really seem to work this way... */
335 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
337 for (int i = 0; i < 64; i++)
340 col.red = g_palette[i*3 + 0] << 8;
341 col.green = g_palette[i*3 + 1] << 8;
342 col.blue = g_palette[i*3 + 2] << 8;
345 gdk_color_alloc( cmap, &col );
348 gtk_widget_set_default_colormap( cmap );
351 /* initialize color cube for 8-bit color reduction dithering */
353 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
355 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
357 for (int r
= 0; r
< 32; r
++)
359 for (int g
= 0; g
< 32; g
++)
361 for (int b
= 0; b
< 32; b
++)
363 int rr
= (r
<< 3) | (r
>> 2);
364 int gg
= (g
<< 3) | (g
>> 2);
365 int bb
= (b
<< 3) | (b
>> 2);
369 GdkColor
*colors
= cmap
->colors
;
374 for (int i
= 0; i
< cmap
->size
; i
++)
376 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
377 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
378 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
379 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
382 index
= i
; max
= sum
;
388 #if (GTK_MINOR_VERSION > 0)
389 /* assume 8-bit true or static colors. this really
391 GdkVisual
* vis
= gdk_colormap_get_visual( cmap
);
392 index
= (r
>> (5 - vis
->red_prec
)) << vis
->red_shift
;
393 index
|= (g
>> (5 - vis
->green_prec
)) << vis
->green_shift
;
394 index
|= (b
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
;
396 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
399 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
407 bool wxApp::ProcessIdle()
410 event
.SetEventObject( this );
411 ProcessEvent( event
);
413 return event
.MoreRequested();
416 void wxApp::OnIdle( wxIdleEvent
&event
)
418 static bool s_inOnIdle
= FALSE
;
420 /* Avoid recursion (via ProcessEvent default case) */
426 /* Resend in the main thread events which have been prepared in other
428 ProcessPendingEvents();
430 /* 'Garbage' collection of windows deleted with Close(). */
431 DeletePendingObjects();
433 /* flush the logged messages if any */
435 wxLog
*log
= wxLog::GetActiveTarget();
436 if (log
!= NULL
&& log
->HasPendingMessages())
440 /* Send OnIdle events to all windows */
441 bool needMore
= SendIdleEvents();
444 event
.RequestMore(TRUE
);
449 bool wxApp::SendIdleEvents()
451 bool needMore
= FALSE
;
453 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
456 wxWindow
* win
= node
->GetData();
457 if (SendIdleEvents(win
))
459 node
= node
->GetNext();
465 bool wxApp::SendIdleEvents( wxWindow
* win
)
467 bool needMore
= FALSE
;
470 event
.SetEventObject(win
);
472 win
->ProcessEvent(event
);
474 win
->OnInternalIdle();
476 if (event
.MoreRequested())
479 wxNode
* node
= win
->GetChildren().First();
482 wxWindow
* win
= (wxWindow
*) node
->Data();
483 if (SendIdleEvents(win
))
491 int wxApp::MainLoop()
497 void wxApp::ExitMainLoop()
502 bool wxApp::Initialized()
504 return m_initialized
;
507 bool wxApp::Pending()
509 return (gtk_events_pending() > 0);
512 void wxApp::Dispatch()
514 gtk_main_iteration();
517 void wxApp::DeletePendingObjects()
519 wxNode
*node
= wxPendingDelete
.First();
522 wxObject
*obj
= (wxObject
*)node
->Data();
526 if (wxPendingDelete
.Find(obj
))
529 node
= wxPendingDelete
.First();
533 bool wxApp::Initialize()
535 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
537 wxClassInfo::InitializeClasses();
539 wxSystemSettings::Init();
541 // GL: I'm annoyed ... I don't know where to put this and I don't want to
542 // create a module for that as it's part of the core.
544 wxPendingEvents
= new wxList();
545 wxPendingEventsLocker
= new wxCriticalSection();
549 wxTheFontNameDirectory = new wxFontNameDirectory;
550 wxTheFontNameDirectory->Initialize();
553 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
554 wxTheColourDatabase
->Initialize();
556 wxInitializeStockLists();
557 wxInitializeStockObjects();
559 #if wxUSE_WX_RESOURCES
560 wxTheResourceCache
= new wxResourceCache( wxKEY_STRING
);
562 wxInitializeResourceSystem();
565 wxModule::RegisterModules();
566 if (!wxModule::InitializeModules()) return FALSE
;
571 void wxApp::CleanUp()
573 wxModule::CleanUpModules();
575 #if wxUSE_WX_RESOURCES
578 if (wxTheResourceCache
)
579 delete wxTheResourceCache
;
580 wxTheResourceCache
= (wxResourceCache
*) NULL
;
582 wxCleanUpResourceSystem();
585 if (wxTheColourDatabase
)
586 delete wxTheColourDatabase
;
587 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
590 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
591 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
594 wxDeleteStockObjects();
596 wxDeleteStockLists();
599 wxTheApp
= (wxApp
*) NULL
;
601 // GL: I'm annoyed ... I don't know where to put this and I don't want to
602 // create a module for that as it's part of the core.
604 delete wxPendingEvents
;
605 delete wxPendingEventsLocker
;
608 wxSystemSettings::Done();
612 wxClassInfo::CleanUpClasses();
614 // check for memory leaks
615 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
616 if (wxDebugContext::CountObjectsLeft() > 0)
618 wxLogDebug(wxT("There were memory leaks.\n"));
619 wxDebugContext::Dump();
620 wxDebugContext::PrintStatistics();
625 // do this as the very last thing because everything else can log messages
626 wxLog::DontCreateOnDemand();
628 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
634 //-----------------------------------------------------------------------------
636 //-----------------------------------------------------------------------------
638 int wxEntry( int argc
, char *argv
[] )
643 if (!wxOKlibc()) wxConvCurrent
= &wxConvLocal
;
645 if (!wxOKlibc()) wxConvCurrent
= (wxMBConv
*) NULL
;
648 gtk_init( &argc
, &argv
);
650 wxSetDetectableAutoRepeat( TRUE
);
652 if (!wxApp::Initialize())
657 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
658 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
660 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
662 wxObject
*test_app
= app_ini();
664 wxTheApp
= (wxApp
*) test_app
;
667 wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") );
669 wxTheApp
->argc
= argc
;
671 wxTheApp
->argv
= new wxChar
*[argc
+1];
673 while (mb_argc
< argc
) {
674 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
677 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
679 wxTheApp
->argv
= argv
;
682 wxString
name(wxFileNameFromPath(argv
[0]));
683 wxStripExtension( name
);
684 wxTheApp
->SetAppName( name
);
688 if ( !wxTheApp
->OnInitGui() )
691 // Here frames insert themselves automatically into wxTopLevelWindows by
692 // getting created in OnInit().
695 if ( !wxTheApp
->OnInit() )
701 /* delete pending toplevel windows (typically a single
702 dialog) so that, if there isn't any left, we don't
704 wxTheApp
->DeletePendingObjects();
706 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
708 if (wxTheApp
->Initialized())
710 retValue
= wxTheApp
->OnRun();
712 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
715 /* Forcibly delete the window. */
716 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
717 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
719 topWindow
->Close( TRUE
);
720 wxTheApp
->DeletePendingObjects();
725 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
733 // flush the logged messages if any
734 wxLog
*log
= wxLog::GetActiveTarget();
735 if (log
!= NULL
&& log
->HasPendingMessages())
738 // continuing to use user defined log target is unsafe from now on because
739 // some resources may be already unavailable, so replace it by something
741 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);
751 #include "wx/gtk/info.xpm"
752 #include "wx/gtk/error.xpm"
753 #include "wx/gtk/question.xpm"
754 #include "wx/gtk/warning.xpm"
757 wxApp::GetStdIcon(int which
) const
761 case wxICON_INFORMATION
:
762 return wxIcon(info_xpm
);
764 case wxICON_QUESTION
:
765 return wxIcon(question_xpm
);
767 case wxICON_EXCLAMATION
:
768 return wxIcon(warning_xpm
);
771 wxFAIL_MSG(wxT("requested non existent standard icon"));
772 // still fall through
775 return wxIcon(error_xpm
);