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
; 
 364                     /* assume 8-bit true or static colors. this really 
 366                     GdkVisual
* vis 
= gdk_colormap_get_visual( cmap 
); 
 367                     index 
= (r 
>> (5 - vis
->red_prec
)) << vis
->red_shift
; 
 368                     index 
|= (g 
>> (5 - vis
->green_prec
)) << vis
->green_shift
; 
 369                     index 
|= (b 
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
; 
 372                 m_colorCube
[ (r
*1024) + (g
*32) + b 
] = index
; 
 380 bool wxApp::ProcessIdle() 
 383     event
.SetEventObject( this ); 
 384     ProcessEvent( event 
); 
 386     return event
.MoreRequested(); 
 389 void wxApp::OnIdle( wxIdleEvent 
&event 
) 
 391     static bool inOnIdle 
= FALSE
; 
 393     /* Avoid recursion (via ProcessEvent default case) */ 
 400     /* Resend in the main thread events which have been prepared in other 
 402     ProcessPendingEvents(); 
 405     /* 'Garbage' collection of windows deleted with Close(). */ 
 406     DeletePendingObjects(); 
 408     /* flush the logged messages if any */ 
 409     wxLog 
*log 
= wxLog::GetActiveTarget(); 
 410     if (log 
!= NULL 
&& log
->HasPendingMessages()) 
 413     /* Send OnIdle events to all windows */ 
 414     bool needMore 
= SendIdleEvents(); 
 417         event
.RequestMore(TRUE
); 
 422 bool wxApp::SendIdleEvents() 
 424     bool needMore 
= FALSE
; 
 426     wxWindowList::Node
* node 
= wxTopLevelWindows
.GetFirst(); 
 429         wxWindow
* win 
= node
->GetData(); 
 430         if (SendIdleEvents(win
)) 
 432         node 
= node
->GetNext(); 
 438 bool wxApp::SendIdleEvents( wxWindow
* win 
) 
 440     bool needMore 
= FALSE
; 
 443     event
.SetEventObject(win
); 
 445     win
->OnInternalIdle(); 
 447     win
->ProcessEvent(event
); 
 449     if (event
.MoreRequested()) 
 452     wxNode
* node 
= win
->GetChildren().First(); 
 455         wxWindow
* win 
= (wxWindow
*) node
->Data(); 
 456         if (SendIdleEvents(win
)) 
 464 int wxApp::MainLoop() 
 470 void wxApp::ExitMainLoop() 
 475 bool wxApp::Initialized() 
 477     return m_initialized
; 
 480 bool wxApp::Pending() 
 482     return (gtk_events_pending() > 0); 
 485 void wxApp::Dispatch() 
 487     gtk_main_iteration(); 
 491 void wxApp::ProcessPendingEvents() 
 493     wxNode 
*node 
= wxPendingEvents
->First(); 
 494     wxCriticalSectionLocker 
locker(*wxPendingEventsLocker
); 
 498         wxEvtHandler 
*handler 
= (wxEvtHandler 
*)node
->Data(); 
 500         handler
->ProcessPendingEvents(); 
 504         node 
= wxPendingEvents
->First(); 
 507 #endif // wxUSE_THREADS 
 509 void wxApp::DeletePendingObjects() 
 511     wxNode 
*node 
= wxPendingDelete
.First(); 
 514         wxObject 
*obj 
= (wxObject 
*)node
->Data(); 
 518         if (wxPendingDelete
.Find(obj
)) 
 521         node 
= wxPendingDelete
.First(); 
 525 wxWindow 
*wxApp::GetTopWindow() 
 529     else if (wxTopLevelWindows
.GetCount() > 0) 
 530         return wxTopLevelWindows
.GetFirst()->GetData(); 
 535 void wxApp::SetTopWindow( wxWindow 
*win 
) 
 540 bool wxApp::Initialize() 
 542     wxBuffer 
= new wxChar
[BUFSIZ 
+ 512]; 
 544     wxClassInfo::InitializeClasses(); 
 546     wxSystemSettings::Init(); 
 548     // GL: I'm annoyed ... I don't know where to put this and I don't want to 
 549     // create a module for that as it's part of the core. 
 551     wxPendingEvents 
= new wxList(); 
 552     wxPendingEventsLocker 
= new wxCriticalSection(); 
 556     wxTheFontNameDirectory =  new wxFontNameDirectory; 
 557     wxTheFontNameDirectory->Initialize(); 
 560     wxTheColourDatabase 
= new wxColourDatabase( wxKEY_STRING 
); 
 561     wxTheColourDatabase
->Initialize(); 
 563     wxInitializeStockLists(); 
 564     wxInitializeStockObjects(); 
 566 #if wxUSE_WX_RESOURCES 
 567     wxTheResourceCache 
= new wxResourceCache( wxKEY_STRING 
); 
 569     wxInitializeResourceSystem(); 
 572     wxImage::InitStandardHandlers(); 
 574     /* no global cursor under X 
 575        g_globalCursor = new wxCursor; */ 
 577     wxModule::RegisterModules(); 
 578     if (!wxModule::InitializeModules()) return FALSE
; 
 583 void wxApp::CleanUp() 
 585     wxModule::CleanUpModules(); 
 587 #if wxUSE_WX_RESOURCES 
 590     if (wxTheResourceCache
) 
 591         delete wxTheResourceCache
; 
 592     wxTheResourceCache 
= (wxResourceCache
*) NULL
; 
 594     wxCleanUpResourceSystem(); 
 597     if (wxTheColourDatabase
) 
 598         delete wxTheColourDatabase
; 
 599     wxTheColourDatabase 
= (wxColourDatabase
*) NULL
; 
 602     if (wxTheFontNameDirectory) delete wxTheFontNameDirectory; 
 603     wxTheFontNameDirectory = (wxFontNameDirectory*) NULL; 
 606     wxDeleteStockObjects(); 
 608     wxDeleteStockLists(); 
 610     wxImage::CleanUpHandlers(); 
 613     wxTheApp 
= (wxApp
*) NULL
; 
 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     delete wxPendingEvents
; 
 619     delete wxPendingEventsLocker
; 
 622     wxSystemSettings::Done(); 
 626     wxClassInfo::CleanUpClasses(); 
 628     // check for memory leaks 
 629 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT 
 630     if (wxDebugContext::CountObjectsLeft() > 0) 
 632         wxLogDebug(_T("There were memory leaks.\n")); 
 633         wxDebugContext::Dump(); 
 634         wxDebugContext::PrintStatistics(); 
 638     // do this as the very last thing because everything else can log messages 
 639     wxLog::DontCreateOnDemand(); 
 641     wxLog 
*oldLog 
= wxLog::SetActiveTarget( (wxLog
*) NULL 
); 
 646 wxLog 
*wxApp::CreateLogTarget() 
 651 //----------------------------------------------------------------------------- 
 653 //----------------------------------------------------------------------------- 
 655 int wxEntry( int argc
, char *argv
[] ) 
 659     gtk_init( &argc
, &argv 
); 
 661     wxSetDetectableAutoRepeat( TRUE 
); 
 663     if (!wxApp::Initialize()) 
 668         wxCHECK_MSG( wxApp::GetInitializerFunction(), -1, 
 669                      _T("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") ); 
 671         wxAppInitializerFunction app_ini 
= wxApp::GetInitializerFunction(); 
 673         wxObject 
*test_app 
= app_ini(); 
 675         wxTheApp 
= (wxApp
*) test_app
; 
 678     wxCHECK_MSG( wxTheApp
, -1, _T("wxWindows error: no application object") ); 
 680     wxTheApp
->argc 
= argc
; 
 681     wxTheApp
->argv 
= argv
; 
 683     wxString 
name(wxFileNameFromPath(argv
[0])); 
 684     wxStripExtension( name 
); 
 685     wxTheApp
->SetAppName( name 
); 
 689     if ( !wxTheApp
->OnInitGui() ) 
 692     // Here frames insert themselves automatically into wxTopLevelWindows by 
 693     // getting created in OnInit(). 
 696         if ( !wxTheApp
->OnInit() ) 
 702         /* delete pending toplevel windows (typically a single 
 703            dialog) so that, if there isn't any left, we don't 
 705         wxTheApp
->DeletePendingObjects(); 
 707         wxTheApp
->m_initialized 
= wxTopLevelWindows
.GetCount() != 0; 
 709         if (wxTheApp
->Initialized()) 
 711             retValue 
= wxTheApp
->OnRun(); 
 713             wxWindow 
*topWindow 
= wxTheApp
->GetTopWindow(); 
 716                 /* Forcibly delete the window. */ 
 717                 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) || 
 718                     topWindow
->IsKindOf(CLASSINFO(wxDialog
)) ) 
 720                     topWindow
->Close( TRUE 
); 
 721                     wxTheApp
->DeletePendingObjects(); 
 726                     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
);