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
; 
  49 extern wxList 
*wxPendingEvents
; 
  50 extern wxCriticalSection 
*wxPendingEventsLocker
; 
  52 extern wxResourceCache 
*wxTheResourceCache
; 
  55 unsigned char g_palette
[64*3] = 
 123 //----------------------------------------------------------------------------- 
 125 //----------------------------------------------------------------------------- 
 127 extern void wxFlushResources(void); 
 129 //----------------------------------------------------------------------------- 
 131 //----------------------------------------------------------------------------- 
 138 /* forward declaration */ 
 139 gint 
wxapp_idle_callback( gpointer 
WXUNUSED(data
) ); 
 143     /* it's necessary to call ProcessIdle() to update the frames sizes which 
 144        might have been changed (it also will update other things set from 
 145        OnUpdateUI() which is a nice (and desired) side effect) */ 
 146     while (wxTheApp
->ProcessIdle()) { } 
 149     for ( wxWindowList::Node 
*node 
= wxTopLevelWindows
.GetFirst(); 
 151           node 
= node
->GetNext() ) 
 153         wxWindow 
*win 
= node
->GetData(); 
 154         win
->OnInternalIdle(); 
 158     if (wxTheApp
->m_idleTag
) 
 160         /* We need to temporarily remove idle callbacks or the loop will 
 162         gtk_idle_remove( wxTheApp
->m_idleTag 
); 
 163         wxTheApp
->m_idleTag 
= 0; 
 165         while (gtk_events_pending()) 
 166             gtk_main_iteration(); 
 168         /* re-add idle handler */ 
 169         wxTheApp
->m_idleTag 
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL 
); 
 173         while (gtk_events_pending()) 
 174             gtk_main_iteration(); 
 180 gint 
wxapp_idle_callback( gpointer 
WXUNUSED(data
) ) 
 182     if (!wxTheApp
) return TRUE
; 
 184 #if (GTK_MINOR_VERSION > 0) 
 185     /* when getting called from GDK's idle handler we 
 186        are no longer within GDK's grab on the GUI 
 187        thread so we must lock it here ourselves */ 
 188     GDK_THREADS_ENTER (); 
 191     /* sent idle event to all who request them */ 
 192     while (wxTheApp
->ProcessIdle()) { } 
 194     /* we don't want any more idle events until the next event is 
 196     gtk_idle_remove( wxTheApp
->m_idleTag 
); 
 197     wxTheApp
->m_idleTag 
= 0; 
 199     /* indicate that we are now in idle mode - even so deeply 
 200        in idle mode that we don't get any idle events anymore. 
 201        this is like wxMSW where an idle event is sent only 
 202        once each time after the event queue has been completely 
 206 #if (GTK_MINOR_VERSION > 0) 
 207     /* release lock again */ 
 208     GDK_THREADS_LEAVE (); 
 214 void wxapp_install_idle_handler() 
 216     wxASSERT_MSG( wxTheApp
->m_idleTag 
== 0, "attempt to install idle handler twice" ); 
 218     /* this routine gets called by all event handlers 
 219        indicating that the idle is over. */ 
 221     wxTheApp
->m_idleTag 
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL 
); 
 227 static gint 
wxapp_wakeup_timerout_callback( gpointer 
WXUNUSED(data
) ) 
 229     gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag 
); 
 230     wxTheApp
->m_wakeUpTimerTag 
= 0; 
 232 #if (GTK_MINOR_VERSION > 0) 
 233     /* when getting called from GDK's time-out handler  
 234        we are no longer within GDK's grab on the GUI 
 235        thread so we must lock it here ourselves */ 
 236     GDK_THREADS_ENTER (); 
 239     /* unblock other threads wishing to do some GUI things */ 
 242     /* wake up other threads */ 
 245     /* block other thread again  */ 
 248 #if (GTK_MINOR_VERSION > 0) 
 249     /* release lock again */ 
 250     GDK_THREADS_LEAVE (); 
 253     wxTheApp
->m_wakeUpTimerTag 
= gtk_timeout_add( 10, wxapp_wakeup_timerout_callback
, (gpointer
) NULL 
); 
 259 //----------------------------------------------------------------------------- 
 261 //----------------------------------------------------------------------------- 
 263 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
) 
 265 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
) 
 266     EVT_IDLE(wxApp::OnIdle
) 
 273     m_topWindow 
= (wxWindow 
*) NULL
; 
 274     m_exitOnFrameDelete 
= TRUE
; 
 276     m_idleTag 
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL 
); 
 279     m_wakeUpTimerTag 
= gtk_timeout_add( 10, wxapp_wakeup_timerout_callback
, (gpointer
) NULL 
); 
 282     m_colorCube 
= (unsigned char*) NULL
; 
 287     if (m_idleTag
) gtk_idle_remove( m_idleTag 
); 
 290     if (m_wakeUpTimerTag
) gtk_timeout_remove( m_wakeUpTimerTag 
); 
 293     if (m_colorCube
) free(m_colorCube
); 
 296 bool wxApp::OnInitGui() 
 298     /* Nothing to do for 15, 16, 24, 32 bit displays */ 
 300     GdkVisual 
*visual 
= gdk_visual_get_system(); 
 301     if (visual
->depth 
> 8) return TRUE
; 
 303         /* this initiates the standard palette as defined by GdkImlib 
 304            in the GNOME libraries. it ensures that all GNOME applications 
 305            use the same 64 colormap entries on 8-bit displays so you 
 306            can use several rather graphics-heavy applications at the 
 308            NOTE: this doesn't really seem to work this way... */ 
 311         GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE ); 
 313         for (int i = 0; i < 64; i++) 
 316             col.red    = g_palette[i*3 + 0] << 8; 
 317             col.green  = g_palette[i*3 + 1] << 8; 
 318             col.blue   = g_palette[i*3 + 2] << 8; 
 321             gdk_color_alloc( cmap, &col ); 
 324         gtk_widget_set_default_colormap( cmap ); 
 327     /* initialize color cube for 8-bit color reduction dithering */ 
 329     GdkColormap 
*cmap 
= gtk_widget_get_default_colormap(); 
 331     m_colorCube 
= (unsigned char*)malloc(32 * 32 * 32); 
 333     for (int r 
= 0; r 
< 32; r
++) 
 335         for (int g 
= 0; g 
< 32; g
++) 
 337             for (int b 
= 0; b 
< 32; b
++) 
 339                 int rr 
= (r 
<< 3) | (r 
>> 2); 
 340                 int gg 
= (g 
<< 3) | (g 
>> 2); 
 341                 int bb 
= (b 
<< 3) | (b 
>> 2); 
 345                 GdkColor 
*colors 
= cmap
->colors
; 
 350                     for (int i 
= 0; i 
< cmap
->size
; i
++) 
 352                         int rdiff 
= ((rr 
<< 8) - colors
[i
].red
); 
 353                         int gdiff 
= ((gg 
<< 8) - colors
[i
].green
); 
 354                         int bdiff 
= ((bb 
<< 8) - colors
[i
].blue
); 
 355                         int sum 
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
); 
 358                             index 
= i
; max 
= sum
; 
 363                 m_colorCube
[ (r
*1024) + (g
*32) + b 
] = index
; 
 371 bool wxApp::ProcessIdle() 
 374     event
.SetEventObject( this ); 
 375     ProcessEvent( event 
); 
 377     return event
.MoreRequested(); 
 380 void wxApp::OnIdle( wxIdleEvent 
&event 
) 
 382     static bool inOnIdle 
= FALSE
; 
 384     /* Avoid recursion (via ProcessEvent default case) */ 
 391     /* Resend in the main thread events which have been prepared in other 
 393     ProcessPendingEvents(); 
 396     /* 'Garbage' collection of windows deleted with Close(). */ 
 397     DeletePendingObjects(); 
 399     /* flush the logged messages if any */ 
 400     wxLog 
*log 
= wxLog::GetActiveTarget(); 
 401     if (log 
!= NULL 
&& log
->HasPendingMessages()) 
 404     /* Send OnIdle events to all windows */ 
 405     bool needMore 
= SendIdleEvents(); 
 408         event
.RequestMore(TRUE
); 
 413 bool wxApp::SendIdleEvents() 
 415     bool needMore 
= FALSE
; 
 417     wxWindowList::Node
* node 
= wxTopLevelWindows
.GetFirst(); 
 420         wxWindow
* win 
= node
->GetData(); 
 421         if (SendIdleEvents(win
)) 
 423         node 
= node
->GetNext(); 
 429 bool wxApp::SendIdleEvents( wxWindow
* win 
) 
 431     bool needMore 
= FALSE
; 
 434     event
.SetEventObject(win
); 
 436     win
->OnInternalIdle(); 
 438     win
->ProcessEvent(event
); 
 440     if (event
.MoreRequested()) 
 443     wxNode
* node 
= win
->GetChildren().First(); 
 446         wxWindow
* win 
= (wxWindow
*) node
->Data(); 
 447         if (SendIdleEvents(win
)) 
 455 int wxApp::MainLoop() 
 461 void wxApp::ExitMainLoop() 
 466 bool wxApp::Initialized() 
 468     return m_initialized
; 
 471 bool wxApp::Pending() 
 473     return (gtk_events_pending() > 0); 
 476 void wxApp::Dispatch() 
 478     gtk_main_iteration(); 
 482 void wxApp::ProcessPendingEvents() 
 484     wxNode 
*node 
= wxPendingEvents
->First(); 
 485     wxCriticalSectionLocker 
locker(*wxPendingEventsLocker
); 
 489         wxEvtHandler 
*handler 
= (wxEvtHandler 
*)node
->Data(); 
 491         handler
->ProcessPendingEvents(); 
 495         node 
= wxPendingEvents
->First(); 
 498 #endif // wxUSE_THREADS 
 500 void wxApp::DeletePendingObjects() 
 502     wxNode 
*node 
= wxPendingDelete
.First(); 
 505         wxObject 
*obj 
= (wxObject 
*)node
->Data(); 
 509         if (wxPendingDelete
.Find(obj
)) 
 512         node 
= wxPendingDelete
.First(); 
 516 wxWindow 
*wxApp::GetTopWindow() 
 520     else if (wxTopLevelWindows
.GetCount() > 0) 
 521         return wxTopLevelWindows
.GetFirst()->GetData(); 
 526 void wxApp::SetTopWindow( wxWindow 
*win 
) 
 531 bool wxApp::Initialize() 
 533     wxBuffer 
= new wxChar
[BUFSIZ 
+ 512]; 
 535     wxClassInfo::InitializeClasses(); 
 537     wxSystemSettings::Init(); 
 539     // GL: I'm annoyed ... I don't know where to put this and I don't want to 
 540     // create a module for that as it's part of the core. 
 542     wxPendingEvents 
= new wxList(); 
 543     wxPendingEventsLocker 
= new wxCriticalSection(); 
 547     wxTheFontNameDirectory =  new wxFontNameDirectory; 
 548     wxTheFontNameDirectory->Initialize(); 
 551     wxTheColourDatabase 
= new wxColourDatabase( wxKEY_STRING 
); 
 552     wxTheColourDatabase
->Initialize(); 
 554     wxInitializeStockLists(); 
 555     wxInitializeStockObjects(); 
 557 #if wxUSE_WX_RESOURCES 
 558     wxTheResourceCache 
= new wxResourceCache( wxKEY_STRING 
); 
 560     wxInitializeResourceSystem(); 
 563     wxImage::InitStandardHandlers(); 
 565     /* no global cursor under X 
 566        g_globalCursor = new wxCursor; */ 
 568     wxModule::RegisterModules(); 
 569     if (!wxModule::InitializeModules()) return FALSE
; 
 574 void wxApp::CleanUp() 
 576     wxModule::CleanUpModules(); 
 578 #if wxUSE_WX_RESOURCES 
 581     if (wxTheResourceCache
) 
 582         delete wxTheResourceCache
; 
 583     wxTheResourceCache 
= (wxResourceCache
*) NULL
; 
 585     wxCleanUpResourceSystem(); 
 588     if (wxTheColourDatabase
) 
 589         delete wxTheColourDatabase
; 
 590     wxTheColourDatabase 
= (wxColourDatabase
*) NULL
; 
 593     if (wxTheFontNameDirectory) delete wxTheFontNameDirectory; 
 594     wxTheFontNameDirectory = (wxFontNameDirectory*) NULL; 
 597     wxDeleteStockObjects(); 
 599     wxDeleteStockLists(); 
 601     wxImage::CleanUpHandlers(); 
 604     wxTheApp 
= (wxApp
*) NULL
; 
 606     // GL: I'm annoyed ... I don't know where to put this and I don't want to 
 607     // create a module for that as it's part of the core. 
 609     delete wxPendingEvents
; 
 610     delete wxPendingEventsLocker
; 
 613     wxSystemSettings::Done(); 
 617     wxClassInfo::CleanUpClasses(); 
 619     // check for memory leaks 
 620 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT 
 621     if (wxDebugContext::CountObjectsLeft() > 0) 
 623         wxLogDebug(_T("There were memory leaks.\n")); 
 624         wxDebugContext::Dump(); 
 625         wxDebugContext::PrintStatistics(); 
 629     // do this as the very last thing because everything else can log messages 
 630     wxLog::DontCreateOnDemand(); 
 632     wxLog 
*oldLog 
= wxLog::SetActiveTarget( (wxLog
*) NULL 
); 
 637 wxLog 
*wxApp::CreateLogTarget() 
 642 //----------------------------------------------------------------------------- 
 644 //----------------------------------------------------------------------------- 
 646 int wxEntry( int argc
, char *argv
[] ) 
 650     gtk_init( &argc
, &argv 
); 
 652     wxSetDetectableAutoRepeat( TRUE 
); 
 654     if (!wxApp::Initialize()) 
 659         wxCHECK_MSG( wxApp::GetInitializerFunction(), -1, 
 660                      _T("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") ); 
 662         wxAppInitializerFunction app_ini 
= wxApp::GetInitializerFunction(); 
 664         wxObject 
*test_app 
= app_ini(); 
 666         wxTheApp 
= (wxApp
*) test_app
; 
 669     wxCHECK_MSG( wxTheApp
, -1, _T("wxWindows error: no application object") ); 
 671     wxTheApp
->argc 
= argc
; 
 672     wxTheApp
->argv 
= argv
; 
 674     wxString 
name(wxFileNameFromPath(argv
[0])); 
 675     wxStripExtension( name 
); 
 676     wxTheApp
->SetAppName( name 
); 
 680     if ( !wxTheApp
->OnInitGui() ) 
 683     // Here frames insert themselves automatically into wxTopLevelWindows by 
 684     // getting created in OnInit(). 
 687         if ( !wxTheApp
->OnInit() ) 
 693         /* delete pending toplevel windows (typically a single 
 694            dialog) so that, if there isn't any left, we don't 
 696         wxTheApp
->DeletePendingObjects(); 
 698         wxTheApp
->m_initialized 
= wxTopLevelWindows
.GetCount() != 0; 
 700         if (wxTheApp
->Initialized()) 
 702             retValue 
= wxTheApp
->OnRun(); 
 704             wxWindow 
*topWindow 
= wxTheApp
->GetTopWindow(); 
 707                 /* Forcibly delete the window. */ 
 708                 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) || 
 709                     topWindow
->IsKindOf(CLASSINFO(wxDialog
)) ) 
 711                     topWindow
->Close( TRUE 
); 
 712                     wxTheApp
->DeletePendingObjects(); 
 717                     wxTheApp
->SetTopWindow( (wxWindow
*) NULL 
); 
 724     // flush the logged messages if any 
 725     wxLog 
*log 
= wxLog::GetActiveTarget(); 
 726     if (log 
!= NULL 
&& log
->HasPendingMessages()) 
 729     // continuing to use user defined log target is unsafe from now on because 
 730     // some resources may be already unavailable, so replace it by something 
 732     wxLog 
*oldlog 
= wxLog::SetActiveTarget(new wxLogStderr
);