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"
31 #include "wx/thread.h"
39 #include "wx/gtk/win_gtk.h"
41 //-----------------------------------------------------------------------------
43 //-----------------------------------------------------------------------------
45 wxApp
*wxTheApp
= (wxApp
*) NULL
;
46 wxAppInitializerFunction
wxApp::m_appInitFn
= (wxAppInitializerFunction
) NULL
;
48 extern wxList wxPendingDelete
;
50 extern wxList
*wxPendingEvents
;
51 extern wxCriticalSection
*wxPendingEventsLocker
;
53 extern wxResourceCache
*wxTheResourceCache
;
56 unsigned char g_palette
[64*3] =
124 //-----------------------------------------------------------------------------
126 //-----------------------------------------------------------------------------
128 extern void wxFlushResources(void);
130 //-----------------------------------------------------------------------------
132 //-----------------------------------------------------------------------------
139 /* forward declaration */
140 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) );
144 // it's necessary to call ProcessIdle() to update the frames sizes which
145 // might have been changed (it also will update other things set from
146 // OnUpdateUI() which is a nice (and desired) side effect)
147 for ( wxWindowList::Node
*node
= wxTopLevelWindows
.GetFirst();
149 node
= node
->GetNext() )
151 wxWindow
*win
= node
->GetData();
152 win
->OnInternalIdle();
155 if (wxTheApp
->m_idleTag
)
157 /* We need to temporarily remove idle callbacks or the loop will
159 gtk_idle_remove( wxTheApp
->m_idleTag
);
160 wxTheApp
->m_idleTag
= 0;
162 while (gtk_events_pending())
163 gtk_main_iteration();
165 /* re-add idle handler */
166 wxTheApp
->m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
170 while (gtk_events_pending())
171 gtk_main_iteration();
177 gint
wxapp_idle_callback( gpointer
WXUNUSED(data
) )
179 if (!wxTheApp
) return TRUE
;
181 /* sent idle event to all who request them */
182 while (wxTheApp
->ProcessIdle()) { }
184 /* we don't want any more idle events until the next event is
186 gtk_idle_remove( wxTheApp
->m_idleTag
);
187 wxTheApp
->m_idleTag
= 0;
189 /* indicate that we are now in idle mode - even so deeply
190 in idle mode that we don't get any idle events anymore.
191 this is like wxMSW where an idle event is sent only
192 once each time after the event queue has been completely
196 /* wake up other threads */
204 void wxapp_install_idle_handler()
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
);
214 //-----------------------------------------------------------------------------
216 //-----------------------------------------------------------------------------
218 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
220 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
221 EVT_IDLE(wxApp::OnIdle
)
228 m_topWindow
= (wxWindow
*) NULL
;
229 m_exitOnFrameDelete
= TRUE
;
231 m_idleTag
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL
);
233 m_colorCube
= (unsigned char*) NULL
;
238 if (m_idleTag
) gtk_idle_remove( m_idleTag
);
240 if (m_colorCube
) free(m_colorCube
);
243 bool wxApp::OnInitGui()
245 /* Nothing to do for 15, 16, 24, 32 bit displays */
247 GdkVisual
*visual
= gdk_visual_get_system();
248 if (visual
->depth
> 8) return TRUE
;
250 /* this initiates the standard palette as defined by GdkImlib
251 in the GNOME libraries. it ensures that all GNOME applications
252 use the same 64 colormap entries on 8-bit displays so you
253 can use several rather graphics-heavy applications at the
255 NOTE: this doesn't really seem to work this way... */
258 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
260 for (int i = 0; i < 64; i++)
263 col.red = g_palette[i*3 + 0] << 8;
264 col.green = g_palette[i*3 + 1] << 8;
265 col.blue = g_palette[i*3 + 2] << 8;
268 gdk_color_alloc( cmap, &col );
271 gtk_widget_set_default_colormap( cmap );
274 /* initialize color cube for 8-bit color reduction dithering */
276 GdkColormap
*cmap
= gtk_widget_get_default_colormap();
278 m_colorCube
= (unsigned char*)malloc(32 * 32 * 32);
280 for (int r
= 0; r
< 32; r
++)
282 for (int g
= 0; g
< 32; g
++)
284 for (int b
= 0; b
< 32; b
++)
286 int rr
= (r
<< 3) | (r
>> 2);
287 int gg
= (g
<< 3) | (g
>> 2);
288 int bb
= (b
<< 3) | (b
>> 2);
290 GdkColor
*colors
= cmap
->colors
;
294 for (int i
= 0; i
< cmap
->size
; i
++)
296 int rdiff
= ((rr
<< 8) - colors
[i
].red
);
297 int gdiff
= ((gg
<< 8) - colors
[i
].green
);
298 int bdiff
= ((bb
<< 8) - colors
[i
].blue
);
299 int sum
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
);
300 if (sum
< max
) { index
= i
; max
= sum
; }
303 m_colorCube
[ (r
*1024) + (g
*32) + b
] = index
;
311 bool wxApp::ProcessIdle()
314 event
.SetEventObject( this );
315 ProcessEvent( event
);
317 return event
.MoreRequested();
320 void wxApp::OnIdle( wxIdleEvent
&event
)
322 static bool inOnIdle
= FALSE
;
324 /* Avoid recursion (via ProcessEvent default case) */
331 /* Resend in the main thread events which have been prepared in other
333 ProcessPendingEvents();
336 /* 'Garbage' collection of windows deleted with Close(). */
337 DeletePendingObjects();
339 /* flush the logged messages if any */
340 wxLog
*log
= wxLog::GetActiveTarget();
341 if (log
!= NULL
&& log
->HasPendingMessages())
344 /* Send OnIdle events to all windows */
345 bool needMore
= SendIdleEvents();
348 event
.RequestMore(TRUE
);
353 bool wxApp::SendIdleEvents()
355 bool needMore
= FALSE
;
357 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
360 wxWindow
* win
= node
->GetData();
361 if (SendIdleEvents(win
))
363 node
= node
->GetNext();
369 bool wxApp::SendIdleEvents( wxWindow
* win
)
371 bool needMore
= FALSE
;
374 event
.SetEventObject(win
);
376 win
->OnInternalIdle();
378 win
->ProcessEvent(event
);
380 if (event
.MoreRequested())
383 wxNode
* node
= win
->GetChildren().First();
386 wxWindow
* win
= (wxWindow
*) node
->Data();
387 if (SendIdleEvents(win
))
395 int wxApp::MainLoop()
401 void wxApp::ExitMainLoop()
406 bool wxApp::Initialized()
408 return m_initialized
;
411 bool wxApp::Pending()
413 return (gtk_events_pending() > 0);
416 void wxApp::Dispatch()
418 gtk_main_iteration();
422 void wxApp::ProcessPendingEvents()
424 wxNode
*node
= wxPendingEvents
->First();
425 wxCriticalSectionLocker
locker(*wxPendingEventsLocker
);
429 wxEvtHandler
*handler
= (wxEvtHandler
*)node
->Data();
431 handler
->ProcessPendingEvents();
435 node
= wxPendingEvents
->First();
438 #endif // wxUSE_THREADS
440 void wxApp::DeletePendingObjects()
442 wxNode
*node
= wxPendingDelete
.First();
445 wxObject
*obj
= (wxObject
*)node
->Data();
449 if (wxPendingDelete
.Member(obj
))
452 node
= wxPendingDelete
.First();
456 wxWindow
*wxApp::GetTopWindow()
460 else if (wxTopLevelWindows
.GetCount() > 0)
461 return wxTopLevelWindows
.GetFirst()->GetData();
466 void wxApp::SetTopWindow( wxWindow
*win
)
471 bool wxApp::Initialize()
473 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
475 wxClassInfo::InitializeClasses();
477 wxSystemSettings::Init();
479 // GL: I'm annoyed ... I don't know where to put this and I don't want to
480 // create a module for that as it's part of the core.
482 wxPendingEvents
= new wxList();
483 wxPendingEventsLocker
= new wxCriticalSection();
487 wxTheFontNameDirectory = new wxFontNameDirectory;
488 wxTheFontNameDirectory->Initialize();
491 wxTheColourDatabase
= new wxColourDatabase( wxKEY_STRING
);
492 wxTheColourDatabase
->Initialize();
494 wxInitializeStockLists();
495 wxInitializeStockObjects();
497 #if wxUSE_WX_RESOURCES
498 wxTheResourceCache
= new wxResourceCache( wxKEY_STRING
);
500 wxInitializeResourceSystem();
503 wxImage::InitStandardHandlers();
505 /* no global cursor under X
506 g_globalCursor = new wxCursor; */
508 wxModule::RegisterModules();
509 if (!wxModule::InitializeModules()) return FALSE
;
514 void wxApp::CleanUp()
516 wxModule::CleanUpModules();
518 #if wxUSE_WX_RESOURCES
521 if (wxTheResourceCache
)
522 delete wxTheResourceCache
;
523 wxTheResourceCache
= (wxResourceCache
*) NULL
;
525 wxCleanUpResourceSystem();
528 if (wxTheColourDatabase
)
529 delete wxTheColourDatabase
;
530 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
533 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
534 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
537 wxDeleteStockObjects();
539 wxDeleteStockLists();
541 wxImage::CleanUpHandlers();
544 wxTheApp
= (wxApp
*) NULL
;
546 // GL: I'm annoyed ... I don't know where to put this and I don't want to
547 // create a module for that as it's part of the core.
549 delete wxPendingEvents
;
550 delete wxPendingEventsLocker
;
553 wxSystemSettings::Done();
557 wxClassInfo::CleanUpClasses();
559 // check for memory leaks
560 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
561 if (wxDebugContext::CountObjectsLeft() > 0)
563 wxLogDebug(_T("There were memory leaks.\n"));
564 wxDebugContext::Dump();
565 wxDebugContext::PrintStatistics();
569 // do this as the very last thing because everything else can log messages
570 wxLog::DontCreateOnDemand();
572 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
577 wxLog
*wxApp::CreateLogTarget()
582 //-----------------------------------------------------------------------------
584 //-----------------------------------------------------------------------------
586 int wxEntry( int argc
, char *argv
[] )
590 gtk_init( &argc
, &argv
);
592 if (!wxApp::Initialize())
597 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
598 _T("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
600 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
602 wxObject
*test_app
= app_ini();
604 wxTheApp
= (wxApp
*) test_app
;
607 wxCHECK_MSG( wxTheApp
, -1, _T("wxWindows error: no application object") );
609 wxTheApp
->argc
= argc
;
610 wxTheApp
->argv
= argv
;
612 wxString
name(wxFileNameFromPath(argv
[0]));
613 wxStripExtension( name
);
614 wxTheApp
->SetAppName( name
);
618 if ( !wxTheApp
->OnInitGui() )
621 // Here frames insert themselves automatically into wxTopLevelWindows by
622 // getting created in OnInit().
625 if ( !wxTheApp
->OnInit() )
631 wxTheApp
->m_initialized
= wxTopLevelWindows
.GetCount() != 0;
633 if (wxTheApp
->Initialized())
634 retValue
= wxTheApp
->OnRun();
636 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
639 // Forcibly delete the window.
640 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
641 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
643 topWindow
->Close( TRUE
);
644 wxTheApp
->DeletePendingObjects();
649 wxTheApp
->SetTopWindow( (wxWindow
*) NULL
);
656 // flush the logged messages if any
657 wxLog
*log
= wxLog::GetActiveTarget();
658 if (log
!= NULL
&& log
->HasPendingMessages())
661 // continuing to use user defined log target is unsafe from now on because
662 // some resources may be already unavailable, so replace it by something
664 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);