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 <vms_jackets.h> 
  19 #include "wx/gdicmn.h" 
  23 #include "wx/memory.h" 
  25 #include "wx/settings.h" 
  26 #include "wx/dialog.h" 
  28 #if wxUSE_WX_RESOURCES 
  29     #include "wx/resource.h" 
  32 #include "wx/module.h" 
  35 #ifdef __WXUNIVERSAL__ 
  36     #include "wx/univ/theme.h" 
  37     #include "wx/univ/renderer.h" 
  41     #include "wx/thread.h" 
  48 # include <sys/poll.h> 
  50 #include "wx/gtk/win_gtk.h" 
  55 //----------------------------------------------------------------------------- 
  57 //----------------------------------------------------------------------------- 
  59 wxApp 
*wxTheApp 
= (wxApp 
*)  NULL
; 
  60 wxAppInitializerFunction 
wxAppBase::m_appInitFn 
= (wxAppInitializerFunction
) NULL
; 
  62 bool   g_mainThreadLocked 
= FALSE
; 
  63 gint   g_pendingTag 
= 0; 
  65 static GtkWidget 
*gs_RootWindow 
= (GtkWidget
*) NULL
; 
  67 //----------------------------------------------------------------------------- 
  69 //----------------------------------------------------------------------------- 
  73 void wxapp_install_idle_handler(); 
  75 //----------------------------------------------------------------------------- 
  77 //----------------------------------------------------------------------------- 
  84 //----------------------------------------------------------------------------- 
  86 //----------------------------------------------------------------------------- 
  88 bool wxApp::Yield(bool onlyIfNeeded
) 
  91     static bool s_inYield 
= FALSE
; 
  97             wxFAIL_MSG( wxT("wxYield called recursively" ) ); 
 104     if ( !wxThread::IsMain() ) 
 106         // can't call gtk_main_iteration() from other threads like this 
 109 #endif // wxUSE_THREADS 
 115         // We need to remove idle callbacks or the loop will 
 117         gtk_idle_remove( m_idleTag 
); 
 122     // disable log flushing from here because a call to wxYield() shouldn't 
 123     // normally result in message boxes popping up &c 
 126     while (gtk_events_pending()) 
 127         gtk_main_iteration(); 
 129     // It's necessary to call ProcessIdle() to update the frames sizes which 
 130     // might have been changed (it also will update other things set from 
 131     // OnUpdateUI() which is a nice (and desired) side effect). But we  
 132     // call ProcessIdle() only once since this is not meant for longish 
 133     // background jobs (controlled by wxIdleEvent::RequestMore() and the 
 134     // return value of Processidle(). 
 137     // let the logs be flashed again 
 145 //----------------------------------------------------------------------------- 
 147 //----------------------------------------------------------------------------- 
 152     if (!wxThread::IsMain()) 
 157         wxapp_install_idle_handler(); 
 160     if (!wxThread::IsMain()) 
 165 //----------------------------------------------------------------------------- 
 167 //----------------------------------------------------------------------------- 
 169 // the callback functions must be extern "C" to comply with GTK+ declarations 
 173 static gint 
wxapp_pending_callback( gpointer 
WXUNUSED(data
) ) 
 175     if (!wxTheApp
) return TRUE
; 
 177     // When getting called from GDK's time-out handler 
 178     // we are no longer within GDK's grab on the GUI 
 179     // thread so we must lock it here ourselves. 
 182     // Sent idle event to all who request them. 
 183     wxTheApp
->ProcessPendingEvents(); 
 187     // Flush the logged messages if any. 
 189     wxLog::FlushActive(); 
 192     // Release lock again 
 195     // Return FALSE to indicate that no more idle events are 
 196     // to be sent (single shot instead of continuous stream) 
 200 static gint 
wxapp_idle_callback( gpointer 
WXUNUSED(data
) ) 
 206     // don't generate the idle events while the assert modal dialog is shown, 
 207     // this completely confuses the apps which don't expect to be reentered 
 208     // from some safely-looking functions 
 209     if ( wxTheApp
->IsInAssert() ) 
 213 #endif // __WXDEBUG__ 
 215     // When getting called from GDK's time-out handler 
 216     // we are no longer within GDK's grab on the GUI 
 217     // thread so we must lock it here ourselves. 
 220     // Indicate that we are now in idle mode and event handlers 
 221     // will have to reinstall the idle handler again. 
 223     wxTheApp
->m_idleTag 
= 0; 
 225     // Send idle event to all who request them as long as 
 226     // no events have popped up in the event queue. 
 227     while (wxTheApp
->ProcessIdle() && (gtk_events_pending() == 0)) 
 230     // Release lock again 
 233     // Return FALSE to indicate that no more idle events are 
 234     // to be sent (single shot instead of continuous stream). 
 240 static gint 
wxapp_poll_func( GPollFD 
*ufds
, guint nfds
, gint timeout 
) 
 246     g_mainThreadLocked 
= TRUE
; 
 248     res 
= poll( (struct pollfd
*) ufds
, nfds
, timeout 
); 
 251     g_mainThreadLocked 
= FALSE
; 
 258 #endif // wxUSE_THREADS 
 262 void wxapp_install_idle_handler() 
 264     wxASSERT_MSG( wxTheApp
->m_idleTag 
== 0, wxT("attempt to install idle handler twice") ); 
 268     if (g_pendingTag 
== 0) 
 269         g_pendingTag 
= gtk_idle_add_priority( 900, wxapp_pending_callback
, (gpointer
) NULL 
); 
 271     // This routine gets called by all event handlers 
 272     // indicating that the idle is over. It may also 
 273     // get called from other thread for sending events 
 274     // to the main thread (and processing these in 
 275     // idle time). Very low priority. 
 276     wxTheApp
->m_idleTag 
= gtk_idle_add_priority( 1000, wxapp_idle_callback
, (gpointer
) NULL 
); 
 279 //----------------------------------------------------------------------------- 
 280 // Access to the root window global 
 281 //----------------------------------------------------------------------------- 
 283 GtkWidget
* wxGetRootWindow() 
 285     if (gs_RootWindow 
== NULL
) 
 287         gs_RootWindow 
= gtk_window_new( GTK_WINDOW_TOPLEVEL 
); 
 288         gtk_widget_realize( gs_RootWindow 
); 
 290     return gs_RootWindow
; 
 293 //----------------------------------------------------------------------------- 
 295 //----------------------------------------------------------------------------- 
 297 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
) 
 299 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
) 
 300     EVT_IDLE(wxApp::OnIdle
) 
 305     m_initialized 
= FALSE
; 
 307     m_isInAssert 
= FALSE
; 
 308 #endif // __WXDEBUG__ 
 311     wxapp_install_idle_handler(); 
 314     g_main_set_poll_func( wxapp_poll_func 
); 
 317     m_colorCube 
= (unsigned char*) NULL
; 
 319     // this is NULL for a "regular" wxApp, but is set (and freed) by a wxGLApp 
 320     m_glVisualInfo 
= (void *) NULL
; 
 325     if (m_idleTag
) gtk_idle_remove( m_idleTag 
); 
 327     if (m_colorCube
) free(m_colorCube
); 
 330 bool wxApp::OnInitGui() 
 332     if ( !wxAppBase::OnInitGui() ) 
 335     GdkVisual 
*visual 
= gdk_visual_get_system(); 
 337     // if this is a wxGLApp (derived from wxApp), and we've already 
 338     // chosen a specific visual, then derive the GdkVisual from that 
 339     if (m_glVisualInfo 
!= NULL
) 
 342         // seems gtk_widget_set_default_visual no longer exists? 
 343         GdkVisual
* vis 
= gtk_widget_get_default_visual(); 
 345         GdkVisual
* vis 
= gdkx_visual_get(  
 346             ((XVisualInfo 
*) m_glVisualInfo
) ->visualid 
); 
 347         gtk_widget_set_default_visual( vis 
); 
 350         GdkColormap 
*colormap 
= gdk_colormap_new( vis
, FALSE 
); 
 351         gtk_widget_set_default_colormap( colormap 
); 
 356     // On some machines, the default visual is just 256 colours, so 
 357     // we make sure we get the best. This can sometimes be wasteful. 
 360     if ((gdk_visual_get_best() != gdk_visual_get_system()) && (m_useBestVisual
)) 
 363         /* seems gtk_widget_set_default_visual no longer exists? */ 
 364         GdkVisual
* vis 
= gtk_widget_get_default_visual(); 
 366         GdkVisual
* vis 
= gdk_visual_get_best(); 
 367         gtk_widget_set_default_visual( vis 
); 
 370         GdkColormap 
*colormap 
= gdk_colormap_new( vis
, FALSE 
); 
 371         gtk_widget_set_default_colormap( colormap 
); 
 376     // Nothing to do for 15, 16, 24, 32 bit displays 
 377     if (visual
->depth 
> 8) return TRUE
; 
 379     // initialize color cube for 8-bit color reduction dithering 
 381     GdkColormap 
*cmap 
= gtk_widget_get_default_colormap(); 
 383     m_colorCube 
= (unsigned char*)malloc(32 * 32 * 32); 
 385     for (int r 
= 0; r 
< 32; r
++) 
 387         for (int g 
= 0; g 
< 32; g
++) 
 389             for (int b 
= 0; b 
< 32; b
++) 
 391                 int rr 
= (r 
<< 3) | (r 
>> 2); 
 392                 int gg 
= (g 
<< 3) | (g 
>> 2); 
 393                 int bb 
= (b 
<< 3) | (b 
>> 2); 
 397                 GdkColor 
*colors 
= cmap
->colors
; 
 402                     for (int i 
= 0; i 
< cmap
->size
; i
++) 
 404                         int rdiff 
= ((rr 
<< 8) - colors
[i
].red
); 
 405                         int gdiff 
= ((gg 
<< 8) - colors
[i
].green
); 
 406                         int bdiff 
= ((bb 
<< 8) - colors
[i
].blue
); 
 407                         int sum 
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
); 
 410                             index 
= i
; max 
= sum
; 
 416                     // assume 8-bit true or static colors. this really exists 
 417                     GdkVisual
* vis 
= gdk_colormap_get_visual( cmap 
); 
 418                     index 
= (r 
>> (5 - vis
->red_prec
)) << vis
->red_shift
; 
 419                     index 
|= (g 
>> (5 - vis
->green_prec
)) << vis
->green_shift
; 
 420                     index 
|= (b 
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
; 
 422                 m_colorCube
[ (r
*1024) + (g
*32) + b 
] = index
; 
 430 GdkVisual 
*wxApp::GetGdkVisual() 
 432     GdkVisual 
*visual 
= NULL
; 
 435         visual 
= gdkx_visual_get( ((XVisualInfo 
*) m_glVisualInfo
)->visualid 
); 
 437         visual 
= gdk_window_get_visual( wxGetRootWindow()->window 
); 
 444 bool wxApp::ProcessIdle() 
 447     event
.SetEventObject( this ); 
 448     ProcessEvent( event 
); 
 450     return event
.MoreRequested(); 
 453 void wxApp::OnIdle( wxIdleEvent 
&event 
) 
 455     static bool s_inOnIdle 
= FALSE
; 
 457     // Avoid recursion (via ProcessEvent default case) 
 463     // Resend in the main thread events which have been prepared in other 
 465     ProcessPendingEvents(); 
 467     // 'Garbage' collection of windows deleted with Close() 
 468     DeletePendingObjects(); 
 470     // Send OnIdle events to all windows 
 471     bool needMore 
= SendIdleEvents(); 
 474         event
.RequestMore(TRUE
); 
 479 bool wxApp::SendIdleEvents() 
 481     bool needMore 
= FALSE
; 
 483     wxWindowList::Node
* node 
= wxTopLevelWindows
.GetFirst(); 
 486         wxWindow
* win 
= node
->GetData(); 
 487         if (SendIdleEvents(win
)) 
 489         node 
= node
->GetNext(); 
 495 bool wxApp::SendIdleEvents( wxWindow
* win 
) 
 497     bool needMore 
= FALSE
; 
 500     event
.SetEventObject(win
); 
 502     win
->GetEventHandler()->ProcessEvent(event
); 
 504     win
->OnInternalIdle(); 
 506     if (event
.MoreRequested()) 
 509     wxNode
* node 
= win
->GetChildren().First(); 
 512         wxWindow
* win 
= (wxWindow
*) node
->Data(); 
 513         if (SendIdleEvents(win
)) 
 521 int wxApp::MainLoop() 
 527 void wxApp::ExitMainLoop() 
 529     if (gtk_main_level() > 0) 
 533 bool wxApp::Initialized() 
 535     return m_initialized
; 
 538 bool wxApp::Pending() 
 540     return (gtk_events_pending() > 0); 
 543 void wxApp::Dispatch() 
 545     gtk_main_iteration(); 
 548 void wxApp::DeletePendingObjects() 
 550     wxNode 
*node 
= wxPendingDelete
.First(); 
 553         wxObject 
*obj 
= (wxObject 
*)node
->Data(); 
 557         if (wxPendingDelete
.Find(obj
)) 
 560         node 
= wxPendingDelete
.First(); 
 564 bool wxApp::Initialize() 
 566     wxBuffer 
= new wxChar
[BUFSIZ 
+ 512]; 
 568     wxClassInfo::InitializeClasses(); 
 571     wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding()); 
 574     // GL: I'm annoyed ... I don't know where to put this and I don't want to 
 575     // create a module for that as it's part of the core. 
 577     wxPendingEvents 
= new wxList(); 
 578     wxPendingEventsLocker 
= new wxCriticalSection(); 
 581     wxTheColourDatabase 
= new wxColourDatabase( wxKEY_STRING 
); 
 582     wxTheColourDatabase
->Initialize(); 
 584     wxInitializeStockLists(); 
 585     wxInitializeStockObjects(); 
 587 #if wxUSE_WX_RESOURCES 
 588     wxInitializeResourceSystem(); 
 591     wxModule::RegisterModules(); 
 592     if (!wxModule::InitializeModules()) return FALSE
; 
 597 void wxApp::CleanUp() 
 599     wxModule::CleanUpModules(); 
 601 #if wxUSE_WX_RESOURCES 
 602     wxCleanUpResourceSystem(); 
 605     if (wxTheColourDatabase
) 
 606         delete wxTheColourDatabase
; 
 608     wxTheColourDatabase 
= (wxColourDatabase
*) NULL
; 
 610     wxDeleteStockObjects(); 
 612     wxDeleteStockLists(); 
 615     wxTheApp 
= (wxApp
*) NULL
; 
 617     // GL: I'm annoyed ... I don't know where to put this and I don't want to 
 618     // create a module for that as it's part of the core. 
 620     delete wxPendingEvents
; 
 621     delete wxPendingEventsLocker
; 
 626     wxClassInfo::CleanUpClasses(); 
 628     // check for memory leaks 
 629 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT 
 630     if (wxDebugContext::CountObjectsLeft(TRUE
) > 0) 
 632         wxLogDebug(wxT("There were memory leaks.\n")); 
 633         wxDebugContext::Dump(); 
 634         wxDebugContext::PrintStatistics(); 
 639     // do this as the very last thing because everything else can log messages 
 640     wxLog::DontCreateOnDemand(); 
 642     wxLog 
*oldLog 
= wxLog::SetActiveTarget( (wxLog
*) NULL 
); 
 648 //----------------------------------------------------------------------------- 
 650 //----------------------------------------------------------------------------- 
 652 // NB: argc and argv may be changed here, pass by reference! 
 653 int wxEntryStart( int& argc
, char *argv
[] ) 
 656     // GTK 1.2 up to version 1.2.3 has broken threads 
 657     if ((gtk_major_version 
== 1) && 
 658         (gtk_minor_version 
== 2) && 
 659         (gtk_micro_version 
< 4)) 
 661         printf( "wxWindows warning: GUI threading disabled due to outdated GTK version\n" ); 
 671     // We should have the wxUSE_WCHAR_T test on the _outside_ 
 673 #if defined(__WXGTK20__) 
 674     // gtk+ 2.0 supports Unicode through UTF-8 strings 
 675     wxConvCurrent 
= &wxConvUTF8
; 
 677     if (!wxOKlibc()) wxConvCurrent 
= &wxConvLocal
; 
 680     if (!wxOKlibc()) wxConvCurrent 
= (wxMBConv
*) NULL
; 
 685     gtk_init( &argc
, &argv 
); 
 687     wxSetDetectableAutoRepeat( TRUE 
); 
 689     if (!wxApp::Initialize()) 
 703     if ( !wxTheApp
->OnInitGui() ) 
 712 void wxEntryCleanup() 
 715     // flush the logged messages if any 
 716     wxLog 
*log 
= wxLog::GetActiveTarget(); 
 717     if (log 
!= NULL 
&& log
->HasPendingMessages()) 
 720     // continuing to use user defined log target is unsafe from now on because 
 721     // some resources may be already unavailable, so replace it by something 
 723     wxLog 
*oldlog 
= wxLog::SetActiveTarget(new wxLogStderr
); 
 734 int wxEntry( int argc
, char *argv
[] ) 
 736 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT 
 737     // This seems to be necessary since there are 'rogue' 
 738     // objects present at this point (perhaps global objects?) 
 739     // Setting a checkpoint will ignore them as far as the 
 740     // memory checking facility is concerned. 
 741     // Of course you may argue that memory allocated in globals should be 
 742     // checked, but this is a reasonable compromise. 
 743     wxDebugContext::SetCheckpoint(); 
 745     int err 
= wxEntryStart(argc
, argv
); 
 751         wxCHECK_MSG( wxApp::GetInitializerFunction(), -1, 
 752                      wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") ); 
 754         wxAppInitializerFunction app_ini 
= wxApp::GetInitializerFunction(); 
 756         wxObject 
*test_app 
= app_ini(); 
 758         wxTheApp 
= (wxApp
*) test_app
; 
 761     wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") ); 
 763     wxTheApp
->argc 
= argc
; 
 765     wxTheApp
->argv 
= new wxChar
*[argc
+1]; 
 767     while (mb_argc 
< argc
) 
 769         wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
])); 
 772     wxTheApp
->argv
[mb_argc
] = (wxChar 
*)NULL
; 
 774     wxTheApp
->argv 
= argv
; 
 777     wxString 
name(wxFileNameFromPath(argv
[0])); 
 778     wxStripExtension( name 
); 
 779     wxTheApp
->SetAppName( name 
); 
 782     retValue 
= wxEntryInitGui(); 
 784     // Here frames insert themselves automatically into wxTopLevelWindows by 
 785     // getting created in OnInit(). 
 788         if ( !wxTheApp
->OnInit() ) 
 794         /* delete pending toplevel windows (typically a single 
 795            dialog) so that, if there isn't any left, we don't 
 797         wxTheApp
->DeletePendingObjects(); 
 799         wxTheApp
->m_initialized 
= wxTopLevelWindows
.GetCount() != 0; 
 801         if (wxTheApp
->Initialized()) 
 805             wxWindow 
*topWindow 
= wxTheApp
->GetTopWindow(); 
 808                 /* Forcibly delete the window. */ 
 809                 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) || 
 810                     topWindow
->IsKindOf(CLASSINFO(wxDialog
)) ) 
 812                     topWindow
->Close( TRUE 
); 
 813                     wxTheApp
->DeletePendingObjects(); 
 818                     wxTheApp
->SetTopWindow( (wxWindow
*) NULL 
); 
 822             retValue 
= wxTheApp
->OnExit(); 
 831 #ifndef __WXUNIVERSAL__ 
 833 // XPM hack: make the arrays const 
 834 #define static static const 
 836 #include "wx/gtk/info.xpm" 
 837 #include "wx/gtk/error.xpm" 
 838 #include "wx/gtk/question.xpm" 
 839 #include "wx/gtk/warning.xpm" 
 843 wxIcon 
wxApp::GetStdIcon(int which
) const 
 847         case wxICON_INFORMATION
: 
 848             return wxIcon(info_xpm
); 
 850         case wxICON_QUESTION
: 
 851             return wxIcon(question_xpm
); 
 853         case wxICON_EXCLAMATION
: 
 854             return wxIcon(warning_xpm
); 
 857             wxFAIL_MSG(wxT("requested non existent standard icon")); 
 858             // still fall through 
 861             return wxIcon(error_xpm
); 
 865 wxIcon 
wxApp::GetStdIcon(int which
) const 
 867     return wxTheme::Get()->GetRenderer()->GetStdIcon(which
); 
 869 #endif // !__WXUNIVERSAL__ 
 874 void wxApp::OnAssert(const wxChar 
*file
, int line
, const wxChar 
*msg
) 
 878     wxAppBase::OnAssert(file
, line
, msg
); 
 880     m_isInAssert 
= FALSE
; 
 883 #endif // __WXDEBUG__