1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling, Julian Smart 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  11     #pragma implementation "appbase.h" 
  12     #pragma implementation "app.h" 
  16 #include "wx/gdicmn.h" 
  20 #include "wx/memory.h" 
  22 #include "wx/settings.h" 
  23 #include "wx/dialog.h" 
  25 #if wxUSE_WX_RESOURCES 
  26     #include "wx/resource.h" 
  29 #include "wx/module.h" 
  33 #include "wx/thread.h" 
  42 #include "wx/gtk/win_gtk.h" 
  44 //----------------------------------------------------------------------------- 
  46 //----------------------------------------------------------------------------- 
  48 wxApp 
*wxTheApp 
= (wxApp 
*)  NULL
; 
  49 wxAppInitializerFunction 
wxAppBase::m_appInitFn 
= (wxAppInitializerFunction
) NULL
; 
  51 extern wxResourceCache 
*wxTheResourceCache
; 
  54 unsigned char g_palette
[64*3] = 
 122 //----------------------------------------------------------------------------- 
 124 //----------------------------------------------------------------------------- 
 126 extern void wxFlushResources(); 
 128 //----------------------------------------------------------------------------- 
 130 //----------------------------------------------------------------------------- 
 137 /* forward declaration */ 
 138 gint 
wxapp_idle_callback( gpointer 
WXUNUSED(data
) ); 
 142     bool has_idle 
= (wxTheApp
->m_idleTag 
!= 0); 
 146         /* We need to temporarily remove idle callbacks or the loop will 
 148         gtk_idle_remove( wxTheApp
->m_idleTag 
); 
 149         wxTheApp
->m_idleTag 
= 0; 
 152     while (gtk_events_pending()) 
 153         gtk_main_iteration(); 
 155     /* it's necessary to call ProcessIdle() to update the frames sizes which 
 156        might have been changed (it also will update other things set from 
 157        OnUpdateUI() which is a nice (and desired) side effect) */ 
 158     while (wxTheApp
->ProcessIdle()) { } 
 162         /* re-add idle handler */ 
 163         wxTheApp
->m_idleTag 
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL 
); 
 169 gint 
wxapp_idle_callback( gpointer 
WXUNUSED(data
) ) 
 171     if (!wxTheApp
) return TRUE
; 
 173 #if (GTK_MINOR_VERSION > 0) 
 174     /* when getting called from GDK's idle handler we 
 175        are no longer within GDK's grab on the GUI 
 176        thread so we must lock it here ourselves */ 
 177     GDK_THREADS_ENTER (); 
 180     /* sent idle event to all who request them */ 
 181     while (wxTheApp
->ProcessIdle()) { } 
 183     /* we don't want any more idle events until the next event is 
 185     gtk_idle_remove( wxTheApp
->m_idleTag 
); 
 186     wxTheApp
->m_idleTag 
= 0; 
 188     /* indicate that we are now in idle mode - even so deeply 
 189        in idle mode that we don't get any idle events anymore. 
 190        this is like wxMSW where an idle event is sent only 
 191        once each time after the event queue has been completely 
 195 #if (GTK_MINOR_VERSION > 0) 
 196     /* release lock again */ 
 197     GDK_THREADS_LEAVE (); 
 203 void wxapp_install_idle_handler() 
 205     wxASSERT_MSG( wxTheApp
->m_idleTag 
== 0, wxT("attempt to install idle handler twice") ); 
 207     /* this routine gets called by all event handlers 
 208        indicating that the idle is over. */ 
 210     wxTheApp
->m_idleTag 
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL 
); 
 217 /* forward declaration */ 
 218 static gint 
wxapp_wakeup_timerout_callback( gpointer 
WXUNUSED(data
) ); 
 220 void wxapp_install_thread_wakeup() 
 222     if (wxTheApp
->m_wakeUpTimerTag
) return; 
 224     wxTheApp
->m_wakeUpTimerTag 
= gtk_timeout_add( 100, wxapp_wakeup_timerout_callback
, (gpointer
) NULL 
); 
 227 void wxapp_uninstall_thread_wakeup() 
 229     if (!wxTheApp
->m_wakeUpTimerTag
) return; 
 231     gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag 
); 
 232     wxTheApp
->m_wakeUpTimerTag 
= 0; 
 235 static gint 
wxapp_wakeup_timerout_callback( gpointer 
WXUNUSED(data
) ) 
 237     wxapp_uninstall_thread_wakeup(); 
 239 #if (GTK_MINOR_VERSION > 0) 
 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 
 243     GDK_THREADS_ENTER (); 
 246     // unblock other threads wishing to do some GUI things 
 249     // wake up other threads 
 252     // block other thread again 
 255 #if (GTK_MINOR_VERSION > 0) 
 256     // release lock again 
 257     GDK_THREADS_LEAVE (); 
 260     wxapp_install_thread_wakeup(); 
 265 #endif // wxUSE_THREADS 
 267 //----------------------------------------------------------------------------- 
 269 //----------------------------------------------------------------------------- 
 271 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
) 
 273 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
) 
 274     EVT_IDLE(wxApp::OnIdle
) 
 281     m_topWindow 
= (wxWindow 
*) NULL
; 
 282     m_exitOnFrameDelete 
= TRUE
; 
 284     m_idleTag 
= gtk_idle_add( wxapp_idle_callback
, (gpointer
) NULL 
); 
 287     m_wakeUpTimerTag 
= 0; 
 288     wxapp_install_thread_wakeup(); 
 291     m_colorCube 
= (unsigned char*) NULL
; 
 296     if (m_idleTag
) gtk_idle_remove( m_idleTag 
); 
 299     wxapp_uninstall_thread_wakeup(); 
 302     if (m_colorCube
) free(m_colorCube
); 
 305 bool wxApp::OnInitGui() 
 307     GdkVisual 
*visual 
= gdk_visual_get_system(); 
 309     /* on some machines, the default visual is just 256 colours, so 
 310        we make sure we get the best. this can sometimes be wasteful, 
 311        of course, but what do these guys pay $30.000 for? */ 
 313     if (gdk_visual_get_best() != gdk_visual_get_system()) 
 315         GdkVisual* vis = gdk_visual_get_best(); 
 316         gtk_widget_set_default_visual( vis ); 
 318         GdkColormap *colormap = gdk_colormap_new( vis, FALSE ); 
 319         gtk_widget_set_default_colormap( colormap ); 
 325     /* Nothing to do for 15, 16, 24, 32 bit displays */ 
 326     if (visual
->depth 
> 8) return TRUE
; 
 328         /* this initiates the standard palette as defined by GdkImlib 
 329            in the GNOME libraries. it ensures that all GNOME applications 
 330            use the same 64 colormap entries on 8-bit displays so you 
 331            can use several rather graphics-heavy applications at the 
 333            NOTE: this doesn't really seem to work this way... */ 
 336         GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE ); 
 338         for (int i = 0; i < 64; i++) 
 341             col.red    = g_palette[i*3 + 0] << 8; 
 342             col.green  = g_palette[i*3 + 1] << 8; 
 343             col.blue   = g_palette[i*3 + 2] << 8; 
 346             gdk_color_alloc( cmap, &col ); 
 349         gtk_widget_set_default_colormap( cmap ); 
 352     /* initialize color cube for 8-bit color reduction dithering */ 
 354     GdkColormap 
*cmap 
= gtk_widget_get_default_colormap(); 
 356     m_colorCube 
= (unsigned char*)malloc(32 * 32 * 32); 
 358     for (int r 
= 0; r 
< 32; r
++) 
 360         for (int g 
= 0; g 
< 32; g
++) 
 362             for (int b 
= 0; b 
< 32; b
++) 
 364                 int rr 
= (r 
<< 3) | (r 
>> 2); 
 365                 int gg 
= (g 
<< 3) | (g 
>> 2); 
 366                 int bb 
= (b 
<< 3) | (b 
>> 2); 
 370                 GdkColor 
*colors 
= cmap
->colors
; 
 375                     for (int i 
= 0; i 
< cmap
->size
; i
++) 
 377                         int rdiff 
= ((rr 
<< 8) - colors
[i
].red
); 
 378                         int gdiff 
= ((gg 
<< 8) - colors
[i
].green
); 
 379                         int bdiff 
= ((bb 
<< 8) - colors
[i
].blue
); 
 380                         int sum 
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
); 
 383                             index 
= i
; max 
= sum
; 
 389 #if (GTK_MINOR_VERSION > 0) 
 390                     /* assume 8-bit true or static colors. this really 
 392                     GdkVisual
* vis 
= gdk_colormap_get_visual( cmap 
); 
 393                     index 
= (r 
>> (5 - vis
->red_prec
)) << vis
->red_shift
; 
 394                     index 
|= (g 
>> (5 - vis
->green_prec
)) << vis
->green_shift
; 
 395                     index 
|= (b 
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
; 
 397                     wxFAIL_MSG( wxT("Unsupported graphics hardware") ); 
 400                 m_colorCube
[ (r
*1024) + (g
*32) + b 
] = index
; 
 408 bool wxApp::ProcessIdle() 
 411     event
.SetEventObject( this ); 
 412     ProcessEvent( event 
); 
 414     return event
.MoreRequested(); 
 417 void wxApp::OnIdle( wxIdleEvent 
&event 
) 
 419     static bool s_inOnIdle 
= FALSE
; 
 421     /* Avoid recursion (via ProcessEvent default case) */ 
 427     /* Resend in the main thread events which have been prepared in other 
 429     ProcessPendingEvents(); 
 431     /* 'Garbage' collection of windows deleted with Close(). */ 
 432     DeletePendingObjects(); 
 434     /* flush the logged messages if any */ 
 436     wxLog 
*log 
= wxLog::GetActiveTarget(); 
 437     if (log 
!= NULL 
&& log
->HasPendingMessages()) 
 441     /* Send OnIdle events to all windows */ 
 442     bool needMore 
= SendIdleEvents(); 
 445         event
.RequestMore(TRUE
); 
 450 bool wxApp::SendIdleEvents() 
 452     bool needMore 
= FALSE
; 
 454     wxWindowList::Node
* node 
= wxTopLevelWindows
.GetFirst(); 
 457         wxWindow
* win 
= node
->GetData(); 
 458         if (SendIdleEvents(win
)) 
 460         node 
= node
->GetNext(); 
 466 bool wxApp::SendIdleEvents( wxWindow
* win 
) 
 468     bool needMore 
= FALSE
; 
 471     event
.SetEventObject(win
); 
 473     win
->ProcessEvent(event
); 
 475     win
->OnInternalIdle(); 
 477     if (event
.MoreRequested()) 
 480     wxNode
* node 
= win
->GetChildren().First(); 
 483         wxWindow
* win 
= (wxWindow
*) node
->Data(); 
 484         if (SendIdleEvents(win
)) 
 492 int wxApp::MainLoop() 
 498 void wxApp::ExitMainLoop() 
 503 bool wxApp::Initialized() 
 505     return m_initialized
; 
 508 bool wxApp::Pending() 
 510     return (gtk_events_pending() > 0); 
 513 void wxApp::Dispatch() 
 515     gtk_main_iteration(); 
 518 void wxApp::ProcessPendingEvents() 
 521     wxCriticalSectionLocker 
locker(*wxPendingEventsLocker
); 
 522 #endif // wxUSE_THREADS 
 524     if ( !wxPendingEvents 
) 
 527     wxNode 
*node 
= wxPendingEvents
->First(); 
 530         wxEvtHandler 
*handler 
= (wxEvtHandler 
*)node
->Data(); 
 532         handler
->ProcessPendingEvents(); 
 536         node 
= wxPendingEvents
->First(); 
 540 void wxApp::DeletePendingObjects() 
 542     wxNode 
*node 
= wxPendingDelete
.First(); 
 545         wxObject 
*obj 
= (wxObject 
*)node
->Data(); 
 549         if (wxPendingDelete
.Find(obj
)) 
 552         node 
= wxPendingDelete
.First(); 
 556 bool wxApp::Initialize() 
 558     wxBuffer 
= new wxChar
[BUFSIZ 
+ 512]; 
 560     wxClassInfo::InitializeClasses(); 
 562     wxSystemSettings::Init(); 
 564     // GL: I'm annoyed ... I don't know where to put this and I don't want to 
 565     // create a module for that as it's part of the core. 
 567     wxPendingEvents 
= new wxList(); 
 568     wxPendingEventsLocker 
= new wxCriticalSection(); 
 572     wxTheFontNameDirectory =  new wxFontNameDirectory; 
 573     wxTheFontNameDirectory->Initialize(); 
 576     wxTheColourDatabase 
= new wxColourDatabase( wxKEY_STRING 
); 
 577     wxTheColourDatabase
->Initialize(); 
 579     wxInitializeStockLists(); 
 580     wxInitializeStockObjects(); 
 582 #if wxUSE_WX_RESOURCES 
 583     wxTheResourceCache 
= new wxResourceCache( wxKEY_STRING 
); 
 585     wxInitializeResourceSystem(); 
 588     wxModule::RegisterModules(); 
 589     if (!wxModule::InitializeModules()) return FALSE
; 
 594 void wxApp::CleanUp() 
 596     wxModule::CleanUpModules(); 
 598 #if wxUSE_WX_RESOURCES 
 601     if (wxTheResourceCache
) 
 602         delete wxTheResourceCache
; 
 603     wxTheResourceCache 
= (wxResourceCache
*) NULL
; 
 605     wxCleanUpResourceSystem(); 
 608     if (wxTheColourDatabase
) 
 609         delete wxTheColourDatabase
; 
 610     wxTheColourDatabase 
= (wxColourDatabase
*) NULL
; 
 613     if (wxTheFontNameDirectory) delete wxTheFontNameDirectory; 
 614     wxTheFontNameDirectory = (wxFontNameDirectory*) NULL; 
 617     wxDeleteStockObjects(); 
 619     wxDeleteStockLists(); 
 622     wxTheApp 
= (wxApp
*) NULL
; 
 624     // GL: I'm annoyed ... I don't know where to put this and I don't want to 
 625     // create a module for that as it's part of the core. 
 627     delete wxPendingEvents
; 
 628     delete wxPendingEventsLocker
; 
 631     wxSystemSettings::Done(); 
 635     wxClassInfo::CleanUpClasses(); 
 637     // check for memory leaks 
 638 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT 
 639     if (wxDebugContext::CountObjectsLeft() > 0) 
 641         wxLogDebug(wxT("There were memory leaks.\n")); 
 642         wxDebugContext::Dump(); 
 643         wxDebugContext::PrintStatistics(); 
 648     // do this as the very last thing because everything else can log messages 
 649     wxLog::DontCreateOnDemand(); 
 651     wxLog 
*oldLog 
= wxLog::SetActiveTarget( (wxLog
*) NULL 
); 
 657 //----------------------------------------------------------------------------- 
 659 //----------------------------------------------------------------------------- 
 661 int wxEntry( int argc
, char *argv
[] ) 
 666     if (!wxOKlibc()) wxConvCurrent 
= &wxConvLocal
; 
 668     if (!wxOKlibc()) wxConvCurrent 
= (wxMBConv
*) NULL
; 
 671     gtk_init( &argc
, &argv 
); 
 673     wxSetDetectableAutoRepeat( TRUE 
); 
 675     if (!wxApp::Initialize()) 
 680         wxCHECK_MSG( wxApp::GetInitializerFunction(), -1, 
 681                      wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") ); 
 683         wxAppInitializerFunction app_ini 
= wxApp::GetInitializerFunction(); 
 685         wxObject 
*test_app 
= app_ini(); 
 687         wxTheApp 
= (wxApp
*) test_app
; 
 690     wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") ); 
 692     wxTheApp
->argc 
= argc
; 
 694     wxTheApp
->argv 
= new wxChar
*[argc
+1]; 
 696     while (mb_argc 
< argc
) { 
 697       wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
])); 
 700     wxTheApp
->argv
[mb_argc
] = (wxChar 
*)NULL
; 
 702     wxTheApp
->argv 
= argv
; 
 705     wxString 
name(wxFileNameFromPath(argv
[0])); 
 706     wxStripExtension( name 
); 
 707     wxTheApp
->SetAppName( name 
); 
 711     if ( !wxTheApp
->OnInitGui() ) 
 714     // Here frames insert themselves automatically into wxTopLevelWindows by 
 715     // getting created in OnInit(). 
 718         if ( !wxTheApp
->OnInit() ) 
 724         /* delete pending toplevel windows (typically a single 
 725            dialog) so that, if there isn't any left, we don't 
 727         wxTheApp
->DeletePendingObjects(); 
 729         wxTheApp
->m_initialized 
= wxTopLevelWindows
.GetCount() != 0; 
 731         if (wxTheApp
->Initialized()) 
 733             retValue 
= wxTheApp
->OnRun(); 
 735             wxWindow 
*topWindow 
= wxTheApp
->GetTopWindow(); 
 738                 /* Forcibly delete the window. */ 
 739                 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) || 
 740                     topWindow
->IsKindOf(CLASSINFO(wxDialog
)) ) 
 742                     topWindow
->Close( TRUE 
); 
 743                     wxTheApp
->DeletePendingObjects(); 
 748                     wxTheApp
->SetTopWindow( (wxWindow
*) NULL 
); 
 756     // flush the logged messages if any 
 757     wxLog 
*log 
= wxLog::GetActiveTarget(); 
 758     if (log 
!= NULL 
&& log
->HasPendingMessages()) 
 761     // continuing to use user defined log target is unsafe from now on because 
 762     // some resources may be already unavailable, so replace it by something 
 764     wxLog 
*oldlog 
= wxLog::SetActiveTarget(new wxLogStderr
); 
 774 #include "wx/gtk/info.xpm" 
 775 #include "wx/gtk/error.xpm" 
 776 #include "wx/gtk/question.xpm" 
 777 #include "wx/gtk/warning.xpm" 
 780 wxApp::GetStdIcon(int which
) const 
 784         case wxICON_INFORMATION
: 
 785             return wxIcon(info_xpm
); 
 787         case wxICON_QUESTION
: 
 788             return wxIcon(question_xpm
); 
 790         case wxICON_EXCLAMATION
: 
 791             return wxIcon(warning_xpm
); 
 794             wxFAIL_MSG(wxT("requested non existent standard icon")); 
 795             // still fall through 
 798             return wxIcon(error_xpm
);