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
; 
  52 bool   g_mainThreadLocked 
= FALSE
; 
  53 gint   g_pendingTag 
= 0; 
  55 static GtkWidget 
*gs_RootWindow 
= (GtkWidget
*) NULL
; 
  57 //----------------------------------------------------------------------------- 
  59 //----------------------------------------------------------------------------- 
  61 /* forward declaration */ 
  62 gint   
wxapp_idle_callback( gpointer 
WXUNUSED(data
) ); 
  63 gint   
wxapp_pending_callback( gpointer 
WXUNUSED(data
) ); 
  64 void   wxapp_install_idle_handler(); 
  67 gint   
wxapp_wakeup_timerout_callback( gpointer 
WXUNUSED(data
) ); 
  70 //----------------------------------------------------------------------------- 
  72 //----------------------------------------------------------------------------- 
  79 //----------------------------------------------------------------------------- 
  81 //----------------------------------------------------------------------------- 
  83 static bool gs_inYield 
= FALSE
; 
  88     if ( !wxThread::IsMain() ) 
  90         // can't call gtk_main_iteration() from other threads like this 
  93 #endif // wxUSE_THREADS 
  97         wxFAIL_MSG( wxT("wxYield called recursively" ) ); 
 104         // We need to remove idle callbacks or the loop will 
 106         gtk_idle_remove( wxTheApp
->m_idleTag 
); 
 107         wxTheApp
->m_idleTag 
= 0; 
 111     while (gtk_events_pending()) 
 112         gtk_main_iteration(); 
 114     // disable log flushing from here because a call to wxYield() shouldn't 
 115     // normally result in message boxes popping up &c 
 118     /* it's necessary to call ProcessIdle() to update the frames sizes which 
 119        might have been changed (it also will update other things set from 
 120        OnUpdateUI() which is a nice (and desired) side effect) */ 
 121     while (wxTheApp
->ProcessIdle()) { } 
 123     // let the logs be flashed again 
 131 //----------------------------------------------------------------------------- 
 133 // Like wxYield, but fails silently if the yield is recursive. 
 134 //----------------------------------------------------------------------------- 
 136 bool wxYieldIfNeeded() 
 144 //----------------------------------------------------------------------------- 
 146 //----------------------------------------------------------------------------- 
 151     if (!wxThread::IsMain()) 
 156         wxapp_install_idle_handler(); 
 159     if (!wxThread::IsMain()) 
 164 //----------------------------------------------------------------------------- 
 166 //----------------------------------------------------------------------------- 
 168 gint 
wxapp_pending_callback( gpointer 
WXUNUSED(data
) ) 
 170     if (!wxTheApp
) return TRUE
; 
 172     // when getting called from GDK's time-out handler 
 173     // we are no longer within GDK's grab on the GUI 
 174     // thread so we must lock it here ourselves 
 177     // Sent idle event to all who request them 
 178     wxTheApp
->ProcessPendingEvents(); 
 182     /* flush the logged messages if any */ 
 184     wxLog::FlushActive(); 
 187     // Release lock again 
 190     // Return FALSE to indicate that no more idle events are 
 191     // to be sent (single shot instead of continuous stream) 
 195 gint 
wxapp_idle_callback( gpointer 
WXUNUSED(data
) ) 
 197     if (!wxTheApp
) return TRUE
; 
 199     // when getting called from GDK's time-out handler 
 200     // we are no longer within GDK's grab on the GUI 
 201     // thread so we must lock it here ourselves 
 204     /* Indicate that we are now in idle mode - even so deeply 
 205        in idle mode that we don't get any idle events anymore. 
 206        this is like wxMSW where an idle event is sent only 
 207        once each time after the event queue has been completely 
 210     wxTheApp
->m_idleTag 
= 0; 
 212     // Sent idle event to all who request them 
 213     while (wxTheApp
->ProcessIdle()) { } 
 215     // Release lock again 
 218     // Return FALSE to indicate that no more idle events are 
 219     // to be sent (single shot instead of continuous stream) 
 223 void wxapp_install_idle_handler() 
 225     wxASSERT_MSG( wxTheApp
->m_idleTag 
== 0, wxT("attempt to install idle handler twice") ); 
 229     if (g_pendingTag 
== 0) 
 230         g_pendingTag 
= gtk_idle_add_priority( 900, wxapp_pending_callback
, (gpointer
) NULL 
); 
 232     /* This routine gets called by all event handlers 
 233        indicating that the idle is over. It may also 
 234        get called from other thread for sending events 
 235        to the main thread (and processing these in 
 236        idle time). Very low priority. */ 
 238     wxTheApp
->m_idleTag 
= gtk_idle_add_priority( 1000, wxapp_idle_callback
, (gpointer
) NULL 
); 
 243 static int g_threadUninstallLevel 
= 0; 
 245 void wxapp_install_thread_wakeup() 
 247     g_threadUninstallLevel
++; 
 249     if (g_threadUninstallLevel 
!= 1) return; 
 251     if (wxTheApp
->m_wakeUpTimerTag
) return; 
 253     wxTheApp
->m_wakeUpTimerTag 
= gtk_timeout_add( 50, wxapp_wakeup_timerout_callback
, (gpointer
) NULL 
); 
 256 void wxapp_uninstall_thread_wakeup() 
 258     g_threadUninstallLevel
--; 
 260     if (g_threadUninstallLevel 
!= 0) return; 
 262     if (!wxTheApp
->m_wakeUpTimerTag
) return; 
 264     gtk_timeout_remove( wxTheApp
->m_wakeUpTimerTag 
); 
 265     wxTheApp
->m_wakeUpTimerTag 
= 0; 
 268 gint 
wxapp_wakeup_timerout_callback( gpointer 
WXUNUSED(data
) ) 
 270     // when getting called from GDK's time-out handler 
 271     // we are no longer within GDK's grab on the GUI 
 272     // thread so we must lock it here ourselves 
 275     wxapp_uninstall_thread_wakeup(); 
 277     // unblock other threads wishing to do some GUI things 
 280     g_mainThreadLocked 
= TRUE
; 
 282     // wake up other threads 
 285     // block other thread again 
 288     g_mainThreadLocked 
= FALSE
; 
 290     wxapp_install_thread_wakeup(); 
 292     // release lock again 
 298 #endif // wxUSE_THREADS 
 300 //----------------------------------------------------------------------------- 
 302 //----------------------------------------------------------------------------- 
 304 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
) 
 306 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
) 
 307     EVT_IDLE(wxApp::OnIdle
) 
 314     m_topWindow 
= (wxWindow 
*) NULL
; 
 315     m_exitOnFrameDelete 
= TRUE
; 
 318     wxapp_install_idle_handler(); 
 321     m_wakeUpTimerTag 
= 0; 
 322     wxapp_install_thread_wakeup(); 
 325     m_colorCube 
= (unsigned char*) NULL
; 
 327     m_useBestVisual 
= FALSE
; 
 332     if (m_idleTag
) gtk_idle_remove( m_idleTag 
); 
 335     wxapp_uninstall_thread_wakeup(); 
 338     if (m_colorCube
) free(m_colorCube
); 
 341 bool wxApp::OnInitGui() 
 343     GdkVisual 
*visual 
= gdk_visual_get_system(); 
 345     /* on some machines, the default visual is just 256 colours, so 
 346        we make sure we get the best. this can sometimes be wasteful, 
 347        of course, but what do these guys pay $30.000 for? */ 
 349     if ((gdk_visual_get_best() != gdk_visual_get_system()) && 
 353         /* seems gtk_widget_set_default_visual no longer exists? */ 
 354         GdkVisual
* vis 
= gtk_widget_get_default_visual(); 
 356         GdkVisual
* vis 
= gdk_visual_get_best(); 
 357         gtk_widget_set_default_visual( vis 
); 
 360         GdkColormap 
*colormap 
= gdk_colormap_new( vis
, FALSE 
); 
 361         gtk_widget_set_default_colormap( colormap 
); 
 366     /* Nothing to do for 15, 16, 24, 32 bit displays */ 
 367     if (visual
->depth 
> 8) return TRUE
; 
 369     /* initialize color cube for 8-bit color reduction dithering */ 
 371     GdkColormap 
*cmap 
= gtk_widget_get_default_colormap(); 
 373     m_colorCube 
= (unsigned char*)malloc(32 * 32 * 32); 
 375     for (int r 
= 0; r 
< 32; r
++) 
 377         for (int g 
= 0; g 
< 32; g
++) 
 379             for (int b 
= 0; b 
< 32; b
++) 
 381                 int rr 
= (r 
<< 3) | (r 
>> 2); 
 382                 int gg 
= (g 
<< 3) | (g 
>> 2); 
 383                 int bb 
= (b 
<< 3) | (b 
>> 2); 
 387                 GdkColor 
*colors 
= cmap
->colors
; 
 392                     for (int i 
= 0; i 
< cmap
->size
; i
++) 
 394                         int rdiff 
= ((rr 
<< 8) - colors
[i
].red
); 
 395                         int gdiff 
= ((gg 
<< 8) - colors
[i
].green
); 
 396                         int bdiff 
= ((bb 
<< 8) - colors
[i
].blue
); 
 397                         int sum 
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
); 
 400                             index 
= i
; max 
= sum
; 
 406 #if (GTK_MINOR_VERSION > 0) 
 407                     /* assume 8-bit true or static colors. this really 
 409                     GdkVisual
* vis 
= gdk_colormap_get_visual( cmap 
); 
 410                     index 
= (r 
>> (5 - vis
->red_prec
)) << vis
->red_shift
; 
 411                     index 
|= (g 
>> (5 - vis
->green_prec
)) << vis
->green_shift
; 
 412                     index 
|= (b 
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
; 
 414                     wxFAIL_MSG( wxT("Unsupported graphics hardware") ); 
 417                 m_colorCube
[ (r
*1024) + (g
*32) + b 
] = index
; 
 425 bool wxApp::ProcessIdle() 
 428     event
.SetEventObject( this ); 
 429     ProcessEvent( event 
); 
 431     return event
.MoreRequested(); 
 434 void wxApp::OnIdle( wxIdleEvent 
&event 
) 
 436     static bool s_inOnIdle 
= FALSE
; 
 438     /* Avoid recursion (via ProcessEvent default case) */ 
 444     /* Resend in the main thread events which have been prepared in other 
 446     ProcessPendingEvents(); 
 448     /* 'Garbage' collection of windows deleted with Close(). */ 
 449     DeletePendingObjects(); 
 451     /* Send OnIdle events to all windows */ 
 452     bool needMore 
= SendIdleEvents(); 
 455         event
.RequestMore(TRUE
); 
 460 bool wxApp::SendIdleEvents() 
 462     bool needMore 
= FALSE
; 
 464     wxWindowList::Node
* node 
= wxTopLevelWindows
.GetFirst(); 
 467         wxWindow
* win 
= node
->GetData(); 
 468         if (SendIdleEvents(win
)) 
 470         node 
= node
->GetNext(); 
 476 bool wxApp::SendIdleEvents( wxWindow
* win 
) 
 478     bool needMore 
= FALSE
; 
 481     event
.SetEventObject(win
); 
 483     win
->GetEventHandler()->ProcessEvent(event
); 
 485     win
->OnInternalIdle(); 
 487     if (event
.MoreRequested()) 
 490     wxNode
* node 
= win
->GetChildren().First(); 
 493         wxWindow
* win 
= (wxWindow
*) node
->Data(); 
 494         if (SendIdleEvents(win
)) 
 502 int wxApp::MainLoop() 
 508 void wxApp::ExitMainLoop() 
 510     if (gtk_main_level() > 0) 
 514 bool wxApp::Initialized() 
 516     return m_initialized
; 
 519 bool wxApp::Pending() 
 521     return (gtk_events_pending() > 0); 
 524 void wxApp::Dispatch() 
 526     gtk_main_iteration(); 
 529 void wxApp::DeletePendingObjects() 
 531     wxNode 
*node 
= wxPendingDelete
.First(); 
 534         wxObject 
*obj 
= (wxObject 
*)node
->Data(); 
 538         if (wxPendingDelete
.Find(obj
)) 
 541         node 
= wxPendingDelete
.First(); 
 545 bool wxApp::Initialize() 
 547     wxBuffer 
= new wxChar
[BUFSIZ 
+ 512]; 
 549     wxClassInfo::InitializeClasses(); 
 551     wxSystemSettings::Init(); 
 553     wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding()); 
 555     // GL: I'm annoyed ... I don't know where to put this and I don't want to 
 556     // create a module for that as it's part of the core. 
 558     wxPendingEvents 
= new wxList(); 
 559     wxPendingEventsLocker 
= new wxCriticalSection(); 
 562     wxTheColourDatabase 
= new wxColourDatabase( wxKEY_STRING 
); 
 563     wxTheColourDatabase
->Initialize(); 
 565     wxInitializeStockLists(); 
 566     wxInitializeStockObjects(); 
 568 #if wxUSE_WX_RESOURCES 
 569     wxInitializeResourceSystem(); 
 572     wxModule::RegisterModules(); 
 573     if (!wxModule::InitializeModules()) return FALSE
; 
 578 void wxApp::CleanUp() 
 580     wxModule::CleanUpModules(); 
 582 #if wxUSE_WX_RESOURCES 
 583     wxCleanUpResourceSystem(); 
 586     if (wxTheColourDatabase
) 
 587         delete wxTheColourDatabase
; 
 589     wxTheColourDatabase 
= (wxColourDatabase
*) NULL
; 
 591     wxDeleteStockObjects(); 
 593     wxDeleteStockLists(); 
 596     wxTheApp 
= (wxApp
*) NULL
; 
 598     // GL: I'm annoyed ... I don't know where to put this and I don't want to 
 599     // create a module for that as it's part of the core. 
 601     delete wxPendingEvents
; 
 602     delete wxPendingEventsLocker
; 
 605     wxSystemSettings::Done(); 
 609     wxClassInfo::CleanUpClasses(); 
 611     // check for memory leaks 
 612 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT 
 613     if (wxDebugContext::CountObjectsLeft(TRUE
) > 0) 
 615         wxLogDebug(wxT("There were memory leaks.\n")); 
 616         wxDebugContext::Dump(); 
 617         wxDebugContext::PrintStatistics(); 
 622     // do this as the very last thing because everything else can log messages 
 623     wxLog::DontCreateOnDemand(); 
 625     wxLog 
*oldLog 
= wxLog::SetActiveTarget( (wxLog
*) NULL 
); 
 631 //----------------------------------------------------------------------------- 
 632 // Access to the root window global 
 633 //----------------------------------------------------------------------------- 
 635 GtkWidget
* wxGetRootWindow() 
 637     if (gs_RootWindow 
== NULL
) { 
 638         gs_RootWindow 
= gtk_window_new( GTK_WINDOW_TOPLEVEL 
); 
 639         gtk_widget_realize( gs_RootWindow 
); 
 641     return gs_RootWindow
; 
 644 //----------------------------------------------------------------------------- 
 646 //----------------------------------------------------------------------------- 
 649 int wxEntryStart( int argc
, char *argv
[] ) 
 652     /* GTK 1.2 up to version 1.2.3 has broken threads */ 
 653    if ((gtk_major_version 
== 1) && 
 654         (gtk_minor_version 
== 2) && 
 655         (gtk_micro_version 
< 4)) 
 657         printf( "wxWindows warning: GUI threading disabled due to outdated GTK version\n" ); 
 667     // We should have the wxUSE_WCHAR_T test on the _outside_ 
 669 #if defined(__WXGTK20__) 
 670     // gtk+ 2.0 supports Unicode through UTF-8 strings 
 671     wxConvCurrent 
= &wxConvUTF8
; 
 673     if (!wxOKlibc()) wxConvCurrent 
= &wxConvLocal
; 
 676     if (!wxOKlibc()) wxConvCurrent 
= (wxMBConv
*) NULL
; 
 681     gtk_init( &argc
, &argv 
); 
 683     wxSetDetectableAutoRepeat( TRUE 
); 
 685     if (!wxApp::Initialize()) 
 699     if ( !wxTheApp
->OnInitGui() ) 
 708 void wxEntryCleanup() 
 711     // flush the logged messages if any 
 712     wxLog 
*log 
= wxLog::GetActiveTarget(); 
 713     if (log 
!= NULL 
&& log
->HasPendingMessages()) 
 716     // continuing to use user defined log target is unsafe from now on because 
 717     // some resources may be already unavailable, so replace it by something 
 719     wxLog 
*oldlog 
= wxLog::SetActiveTarget(new wxLogStderr
); 
 731 int wxEntry( int argc
, char *argv
[] ) 
 733 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT 
 734     // This seems to be necessary since there are 'rogue' 
 735     // objects present at this point (perhaps global objects?) 
 736     // Setting a checkpoint will ignore them as far as the 
 737     // memory checking facility is concerned. 
 738     // Of course you may argue that memory allocated in globals should be 
 739     // checked, but this is a reasonable compromise. 
 740     wxDebugContext::SetCheckpoint(); 
 742     int err 
= wxEntryStart(argc
, argv
); 
 748         wxCHECK_MSG( wxApp::GetInitializerFunction(), -1, 
 749                      wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") ); 
 751         wxAppInitializerFunction app_ini 
= wxApp::GetInitializerFunction(); 
 753         wxObject 
*test_app 
= app_ini(); 
 755         wxTheApp 
= (wxApp
*) test_app
; 
 758     wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") ); 
 760     wxTheApp
->argc 
= argc
; 
 762     wxTheApp
->argv 
= new wxChar
*[argc
+1]; 
 764     while (mb_argc 
< argc
) 
 766         wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
])); 
 769     wxTheApp
->argv
[mb_argc
] = (wxChar 
*)NULL
; 
 771     wxTheApp
->argv 
= argv
; 
 774     wxString 
name(wxFileNameFromPath(argv
[0])); 
 775     wxStripExtension( name 
); 
 776     wxTheApp
->SetAppName( name 
); 
 779     retValue 
= wxEntryInitGui(); 
 781     // Here frames insert themselves automatically into wxTopLevelWindows by 
 782     // getting created in OnInit(). 
 785         if ( !wxTheApp
->OnInit() ) 
 791         /* delete pending toplevel windows (typically a single 
 792            dialog) so that, if there isn't any left, we don't 
 794         wxTheApp
->DeletePendingObjects(); 
 796         wxTheApp
->m_initialized 
= wxTopLevelWindows
.GetCount() != 0; 
 798         if (wxTheApp
->Initialized()) 
 802             wxWindow 
*topWindow 
= wxTheApp
->GetTopWindow(); 
 805                 /* Forcibly delete the window. */ 
 806                 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) || 
 807                     topWindow
->IsKindOf(CLASSINFO(wxDialog
)) ) 
 809                     topWindow
->Close( TRUE 
); 
 810                     wxTheApp
->DeletePendingObjects(); 
 815                     wxTheApp
->SetTopWindow( (wxWindow
*) NULL 
); 
 819             retValue 
= wxTheApp
->OnExit(); 
 828 #include "wx/gtk/info.xpm" 
 829 #include "wx/gtk/error.xpm" 
 830 #include "wx/gtk/question.xpm" 
 831 #include "wx/gtk/warning.xpm" 
 834 wxApp::GetStdIcon(int which
) const 
 838         case wxICON_INFORMATION
: 
 839             return wxIcon(info_xpm
); 
 841         case wxICON_QUESTION
: 
 842             return wxIcon(question_xpm
); 
 844         case wxICON_EXCLAMATION
: 
 845             return wxIcon(warning_xpm
); 
 848             wxFAIL_MSG(wxT("requested non existent standard icon")); 
 849             // still fall through 
 852             return wxIcon(error_xpm
);