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" 
  27 #include "wx/msgdlg.h" 
  29 #include "wx/filename.h" 
  31 #if wxUSE_WX_RESOURCES 
  32     #include "wx/resource.h" 
  35 #include "wx/module.h" 
  38 #ifdef __WXUNIVERSAL__ 
  39     #include "wx/univ/theme.h" 
  40     #include "wx/univ/renderer.h" 
  44     #include "wx/thread.h" 
  53         // bug in the OpenBSD headers: at least in 3.1 there is no extern "C" 
  54         // in neither poll.h nor sys/poll.h which results in link errors later 
  67     // we implement poll() ourselves using select() which is supposed exist in 
  69     #include <sys/types.h> 
  72 #endif // HAVE_POLL/!HAVE_POLL 
  74 #include "wx/gtk/win_gtk.h" 
  79 //----------------------------------------------------------------------------- 
  81 //----------------------------------------------------------------------------- 
  83 wxApp 
*wxTheApp 
= (wxApp 
*)  NULL
; 
  84 wxAppInitializerFunction 
wxAppBase::m_appInitFn 
= (wxAppInitializerFunction
) NULL
; 
  86 bool   g_mainThreadLocked 
= FALSE
; 
  87 gint   g_pendingTag 
= 0; 
  89 static GtkWidget 
*gs_RootWindow 
= (GtkWidget
*) NULL
; 
  91 //----------------------------------------------------------------------------- 
  93 //----------------------------------------------------------------------------- 
  97 void wxapp_install_idle_handler(); 
  99 //----------------------------------------------------------------------------- 
 101 //----------------------------------------------------------------------------- 
 108 //----------------------------------------------------------------------------- 
 110 //----------------------------------------------------------------------------- 
 112 // not static because used by textctrl.cpp 
 115 bool wxIsInsideYield 
= FALSE
; 
 117 bool wxApp::Yield(bool onlyIfNeeded
) 
 119     if ( wxIsInsideYield 
) 
 123             wxFAIL_MSG( wxT("wxYield called recursively" ) ); 
 130     if ( !wxThread::IsMain() ) 
 132         // can't call gtk_main_iteration() from other threads like this 
 135 #endif // wxUSE_THREADS 
 137     wxIsInsideYield 
= TRUE
; 
 141         // We need to remove idle callbacks or the loop will 
 143         gtk_idle_remove( m_idleTag 
); 
 148     // disable log flushing from here because a call to wxYield() shouldn't 
 149     // normally result in message boxes popping up &c 
 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). But we 
 158     // call ProcessIdle() only once since this is not meant for longish 
 159     // background jobs (controlled by wxIdleEvent::RequestMore() and the 
 160     // return value of Processidle(). 
 163     // let the logs be flashed again 
 166     wxIsInsideYield 
= FALSE
; 
 171 //----------------------------------------------------------------------------- 
 173 //----------------------------------------------------------------------------- 
 178     if (!wxThread::IsMain()) 
 183         wxapp_install_idle_handler(); 
 186     if (!wxThread::IsMain()) 
 191 //----------------------------------------------------------------------------- 
 193 //----------------------------------------------------------------------------- 
 195 // the callback functions must be extern "C" to comply with GTK+ declarations 
 199 static gint 
wxapp_pending_callback( gpointer 
WXUNUSED(data
) ) 
 201     if (!wxTheApp
) return TRUE
; 
 203     // When getting called from GDK's time-out handler 
 204     // we are no longer within GDK's grab on the GUI 
 205     // thread so we must lock it here ourselves. 
 208     // Sent idle event to all who request them. 
 209     wxTheApp
->ProcessPendingEvents(); 
 213     // Flush the logged messages if any. 
 215     wxLog::FlushActive(); 
 218     // Release lock again 
 221     // Return FALSE to indicate that no more idle events are 
 222     // to be sent (single shot instead of continuous stream) 
 226 static gint 
wxapp_idle_callback( gpointer 
WXUNUSED(data
) ) 
 232     // don't generate the idle events while the assert modal dialog is shown, 
 233     // this completely confuses the apps which don't expect to be reentered 
 234     // from some safely-looking functions 
 235     if ( wxTheApp
->IsInAssert() ) 
 237         // But repaint the assertion message if necessary 
 238         if (wxTopLevelWindows
.GetCount() > 0) 
 240             wxWindow
* win 
= (wxWindow
*) wxTopLevelWindows
.Last()->Data(); 
 241             if (win
->IsKindOf(CLASSINFO(wxGenericMessageDialog
))) 
 242                 win
->OnInternalIdle(); 
 246 #endif // __WXDEBUG__ 
 248     // When getting called from GDK's time-out handler 
 249     // we are no longer within GDK's grab on the GUI 
 250     // thread so we must lock it here ourselves. 
 253     // Indicate that we are now in idle mode and event handlers 
 254     // will have to reinstall the idle handler again. 
 256     wxTheApp
->m_idleTag 
= 0; 
 258     // Send idle event to all who request them as long as 
 259     // no events have popped up in the event queue. 
 260     while (wxTheApp
->ProcessIdle() && (gtk_events_pending() == 0)) 
 263     // Release lock again 
 266     // Return FALSE to indicate that no more idle events are 
 267     // to be sent (single shot instead of continuous stream). 
 275     #define wxPollFd pollfd 
 278 typedef GPollFD wxPollFd
; 
 280 int wxPoll(wxPollFd 
*ufds
, unsigned int nfds
, int timeout
) 
 282     // convert timeout from ms to struct timeval (s/us) 
 284     tv_timeout
.tv_sec 
= timeout
/1000; 
 285     tv_timeout
.tv_usec 
= (timeout%1000
)*1000; 
 287     // remember the highest fd used here 
 290     // and fill the sets for select() 
 299     for ( i 
= 0; i 
< nfds
; i
++ ) 
 301         wxASSERT_MSG( ufds
[i
].fd 
< FD_SETSIZE
, _T("fd out of range") ); 
 303         if ( ufds
[i
].events 
& G_IO_IN 
) 
 304             FD_SET(ufds
[i
].fd
, &readfds
); 
 306         if ( ufds
[i
].events 
& G_IO_PRI 
) 
 307             FD_SET(ufds
[i
].fd
, &exceptfds
); 
 309         if ( ufds
[i
].events 
& G_IO_OUT 
) 
 310             FD_SET(ufds
[i
].fd
, &writefds
); 
 312         if ( ufds
[i
].fd 
> fdMax 
) 
 317     int res 
= select(fdMax
, &readfds
, &writefds
, &exceptfds
, &tv_timeout
); 
 319     // translate the results back 
 320     for ( i 
= 0; i 
< nfds
; i
++ ) 
 324         if ( FD_ISSET(ufds
[i
].fd
, &readfds 
) ) 
 325             ufds
[i
].revents 
|= G_IO_IN
; 
 327         if ( FD_ISSET(ufds
[i
].fd
, &exceptfds 
) ) 
 328             ufds
[i
].revents 
|= G_IO_PRI
; 
 330         if ( FD_ISSET(ufds
[i
].fd
, &writefds 
) ) 
 331             ufds
[i
].revents 
|= G_IO_OUT
; 
 337 #endif // HAVE_POLL/!HAVE_POLL 
 339 static gint 
wxapp_poll_func( GPollFD 
*ufds
, guint nfds
, gint timeout 
) 
 344     g_mainThreadLocked 
= TRUE
; 
 346     // we rely on the fact that glib GPollFD struct is really just pollfd but 
 347     // I wonder how wise is this in the long term (VZ) 
 348     gint res 
= wxPoll( (wxPollFd 
*) ufds
, nfds
, timeout 
); 
 351     g_mainThreadLocked 
= FALSE
; 
 358 #endif // wxUSE_THREADS 
 362 void wxapp_install_idle_handler() 
 364     wxASSERT_MSG( wxTheApp
->m_idleTag 
== 0, wxT("attempt to install idle handler twice") ); 
 368     if (g_pendingTag 
== 0) 
 369         g_pendingTag 
= gtk_idle_add_priority( 900, wxapp_pending_callback
, (gpointer
) NULL 
); 
 371     // This routine gets called by all event handlers 
 372     // indicating that the idle is over. It may also 
 373     // get called from other thread for sending events 
 374     // to the main thread (and processing these in 
 375     // idle time). Very low priority. 
 376     wxTheApp
->m_idleTag 
= gtk_idle_add_priority( 1000, wxapp_idle_callback
, (gpointer
) NULL 
); 
 379 //----------------------------------------------------------------------------- 
 380 // Access to the root window global 
 381 //----------------------------------------------------------------------------- 
 383 GtkWidget
* wxGetRootWindow() 
 385     if (gs_RootWindow 
== NULL
) 
 387         gs_RootWindow 
= gtk_window_new( GTK_WINDOW_TOPLEVEL 
); 
 388         gtk_widget_realize( gs_RootWindow 
); 
 390     return gs_RootWindow
; 
 393 //----------------------------------------------------------------------------- 
 395 //----------------------------------------------------------------------------- 
 397 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
) 
 399 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
) 
 400     EVT_IDLE(wxApp::OnIdle
) 
 405     m_initialized 
= FALSE
; 
 407     m_isInAssert 
= FALSE
; 
 408 #endif // __WXDEBUG__ 
 411     wxapp_install_idle_handler(); 
 414     g_main_set_poll_func( wxapp_poll_func 
); 
 417     m_colorCube 
= (unsigned char*) NULL
; 
 419     // this is NULL for a "regular" wxApp, but is set (and freed) by a wxGLApp 
 420     m_glVisualInfo 
= (void *) NULL
; 
 425     if (m_idleTag
) gtk_idle_remove( m_idleTag 
); 
 427     if (m_colorCube
) free(m_colorCube
); 
 430 bool wxApp::OnInitGui() 
 432     if ( !wxAppBase::OnInitGui() ) 
 435     GdkVisual 
*visual 
= gdk_visual_get_system(); 
 437     // if this is a wxGLApp (derived from wxApp), and we've already 
 438     // chosen a specific visual, then derive the GdkVisual from that 
 439     if (m_glVisualInfo 
!= NULL
) 
 442         // seems gtk_widget_set_default_visual no longer exists? 
 443         GdkVisual
* vis 
= gtk_widget_get_default_visual(); 
 445         GdkVisual
* vis 
= gdkx_visual_get( 
 446             ((XVisualInfo 
*) m_glVisualInfo
) ->visualid 
); 
 447         gtk_widget_set_default_visual( vis 
); 
 450         GdkColormap 
*colormap 
= gdk_colormap_new( vis
, FALSE 
); 
 451         gtk_widget_set_default_colormap( colormap 
); 
 456     // On some machines, the default visual is just 256 colours, so 
 457     // we make sure we get the best. This can sometimes be wasteful. 
 460     if ((gdk_visual_get_best() != gdk_visual_get_system()) && (m_useBestVisual
)) 
 463         /* seems gtk_widget_set_default_visual no longer exists? */ 
 464         GdkVisual
* vis 
= gtk_widget_get_default_visual(); 
 466         GdkVisual
* vis 
= gdk_visual_get_best(); 
 467         gtk_widget_set_default_visual( vis 
); 
 470         GdkColormap 
*colormap 
= gdk_colormap_new( vis
, FALSE 
); 
 471         gtk_widget_set_default_colormap( colormap 
); 
 476     // Nothing to do for 15, 16, 24, 32 bit displays 
 477     if (visual
->depth 
> 8) return TRUE
; 
 479     // initialize color cube for 8-bit color reduction dithering 
 481     GdkColormap 
*cmap 
= gtk_widget_get_default_colormap(); 
 483     m_colorCube 
= (unsigned char*)malloc(32 * 32 * 32); 
 485     for (int r 
= 0; r 
< 32; r
++) 
 487         for (int g 
= 0; g 
< 32; g
++) 
 489             for (int b 
= 0; b 
< 32; b
++) 
 491                 int rr 
= (r 
<< 3) | (r 
>> 2); 
 492                 int gg 
= (g 
<< 3) | (g 
>> 2); 
 493                 int bb 
= (b 
<< 3) | (b 
>> 2); 
 497                 GdkColor 
*colors 
= cmap
->colors
; 
 502                     for (int i 
= 0; i 
< cmap
->size
; i
++) 
 504                         int rdiff 
= ((rr 
<< 8) - colors
[i
].red
); 
 505                         int gdiff 
= ((gg 
<< 8) - colors
[i
].green
); 
 506                         int bdiff 
= ((bb 
<< 8) - colors
[i
].blue
); 
 507                         int sum 
= ABS (rdiff
) + ABS (gdiff
) + ABS (bdiff
); 
 510                             index 
= i
; max 
= sum
; 
 516                     // assume 8-bit true or static colors. this really exists 
 517                     GdkVisual
* vis 
= gdk_colormap_get_visual( cmap 
); 
 518                     index 
= (r 
>> (5 - vis
->red_prec
)) << vis
->red_shift
; 
 519                     index 
|= (g 
>> (5 - vis
->green_prec
)) << vis
->green_shift
; 
 520                     index 
|= (b 
>> (5 - vis
->blue_prec
)) << vis
->blue_shift
; 
 522                 m_colorCube
[ (r
*1024) + (g
*32) + b 
] = index
; 
 530 GdkVisual 
*wxApp::GetGdkVisual() 
 532     GdkVisual 
*visual 
= NULL
; 
 535         visual 
= gdkx_visual_get( ((XVisualInfo 
*) m_glVisualInfo
)->visualid 
); 
 537         visual 
= gdk_window_get_visual( wxGetRootWindow()->window 
); 
 544 bool wxApp::ProcessIdle() 
 546     wxWindowList::Node
* node 
= wxTopLevelWindows
.GetFirst(); 
 547     node 
= wxTopLevelWindows
.GetFirst(); 
 550         wxWindow
* win 
= node
->GetData(); 
 551         CallInternalIdle( win 
); 
 553         node 
= node
->GetNext(); 
 557     event
.SetEventObject( this ); 
 558     ProcessEvent( event 
); 
 560     return event
.MoreRequested(); 
 563 void wxApp::OnIdle( wxIdleEvent 
&event 
) 
 565     static bool s_inOnIdle 
= FALSE
; 
 567     // Avoid recursion (via ProcessEvent default case) 
 573     // Resend in the main thread events which have been prepared in other 
 575     ProcessPendingEvents(); 
 577     // 'Garbage' collection of windows deleted with Close() 
 578     DeletePendingObjects(); 
 580     // Send OnIdle events to all windows 
 581     bool needMore 
= SendIdleEvents(); 
 584         event
.RequestMore(TRUE
); 
 589 bool wxApp::SendIdleEvents() 
 591     bool needMore 
= FALSE
; 
 593     wxWindowList::Node
* node 
= wxTopLevelWindows
.GetFirst(); 
 596         wxWindow
* win 
= node
->GetData(); 
 597         if (SendIdleEvents(win
)) 
 600         node 
= node
->GetNext(); 
 606 bool wxApp::CallInternalIdle( wxWindow
* win 
) 
 608     win
->OnInternalIdle(); 
 610     wxNode
* node 
= win
->GetChildren().First(); 
 613         wxWindow
* win 
= (wxWindow
*) node
->Data(); 
 614         CallInternalIdle( win 
); 
 622 bool wxApp::SendIdleEvents( wxWindow
* win 
) 
 624     bool needMore 
= FALSE
; 
 627     event
.SetEventObject(win
); 
 629     win
->GetEventHandler()->ProcessEvent(event
); 
 631     if (event
.MoreRequested()) 
 634     wxNode
* node 
= win
->GetChildren().First(); 
 637         wxWindow
* win 
= (wxWindow
*) node
->Data(); 
 638         if (SendIdleEvents(win
)) 
 647 int wxApp::MainLoop() 
 653 void wxApp::ExitMainLoop() 
 655     if (gtk_main_level() > 0) 
 659 bool wxApp::Initialized() 
 661     return m_initialized
; 
 664 bool wxApp::Pending() 
 666     return (gtk_events_pending() > 0); 
 669 void wxApp::Dispatch() 
 671     gtk_main_iteration(); 
 674 void wxApp::DeletePendingObjects() 
 676     wxNode 
*node 
= wxPendingDelete
.First(); 
 679         wxObject 
*obj 
= (wxObject 
*)node
->Data(); 
 683         if (wxPendingDelete
.Find(obj
)) 
 686         node 
= wxPendingDelete
.First(); 
 690 bool wxApp::Initialize() 
 692     wxClassInfo::InitializeClasses(); 
 694     // GL: I'm annoyed ... I don't know where to put this and I don't want to 
 695     // create a module for that as it's part of the core. 
 697     wxPendingEvents 
= new wxList(); 
 698     wxPendingEventsLocker 
= new wxCriticalSection(); 
 701     wxTheColourDatabase 
= new wxColourDatabase( wxKEY_STRING 
); 
 702     wxTheColourDatabase
->Initialize(); 
 704     wxInitializeStockLists(); 
 705     wxInitializeStockObjects(); 
 707 #if wxUSE_WX_RESOURCES 
 708     wxInitializeResourceSystem(); 
 711     wxModule::RegisterModules(); 
 712     if (!wxModule::InitializeModules()) 
 716     wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding()); 
 722 void wxApp::CleanUp() 
 724     wxModule::CleanUpModules(); 
 726 #if wxUSE_WX_RESOURCES 
 727     wxCleanUpResourceSystem(); 
 730     delete wxTheColourDatabase
; 
 731     wxTheColourDatabase 
= (wxColourDatabase
*) NULL
; 
 733     wxDeleteStockObjects(); 
 735     wxDeleteStockLists(); 
 738     wxTheApp 
= (wxApp
*) NULL
; 
 740     wxClassInfo::CleanUpClasses(); 
 743     delete wxPendingEvents
; 
 744     delete wxPendingEventsLocker
; 
 747     // check for memory leaks 
 748 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT 
 749     if (wxDebugContext::CountObjectsLeft(TRUE
) > 0) 
 751         wxLogDebug(wxT("There were memory leaks.\n")); 
 752         wxDebugContext::Dump(); 
 753         wxDebugContext::PrintStatistics(); 
 758     // do this as the very last thing because everything else can log messages 
 759     wxLog::DontCreateOnDemand(); 
 761     wxLog 
*oldLog 
= wxLog::SetActiveTarget( (wxLog
*) NULL 
); 
 767 //----------------------------------------------------------------------------- 
 769 //----------------------------------------------------------------------------- 
 771 // NB: argc and argv may be changed here, pass by reference! 
 772 int wxEntryStart( int& argc
, char *argv
[] ) 
 775     // GTK 1.2 up to version 1.2.3 has broken threads 
 776     if ((gtk_major_version 
== 1) && 
 777         (gtk_minor_version 
== 2) && 
 778         (gtk_micro_version 
< 4)) 
 780         printf( "wxWindows warning: GUI threading disabled due to outdated GTK version\n" ); 
 790     // We should have the wxUSE_WCHAR_T test on the _outside_ 
 792 #if defined(__WXGTK20__) 
 793     // gtk+ 2.0 supports Unicode through UTF-8 strings 
 794     wxConvCurrent 
= &wxConvUTF8
; 
 796     if (!wxOKlibc()) wxConvCurrent 
= &wxConvLocal
; 
 799     if (!wxOKlibc()) wxConvCurrent 
= (wxMBConv
*) NULL
; 
 804     gtk_init( &argc
, &argv 
); 
 806     wxSetDetectableAutoRepeat( TRUE 
); 
 808     if (!wxApp::Initialize()) 
 822     if ( !wxTheApp
->OnInitGui() ) 
 831 void wxEntryCleanup() 
 834     // flush the logged messages if any 
 835     wxLog 
*log 
= wxLog::GetActiveTarget(); 
 836     if (log 
!= NULL 
&& log
->HasPendingMessages()) 
 839     // continuing to use user defined log target is unsafe from now on because 
 840     // some resources may be already unavailable, so replace it by something 
 842     wxLog 
*oldlog 
= wxLog::SetActiveTarget(new wxLogStderr
); 
 853 int wxEntry( int argc
, char *argv
[] ) 
 855 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT 
 856     // This seems to be necessary since there are 'rogue' 
 857     // objects present at this point (perhaps global objects?) 
 858     // Setting a checkpoint will ignore them as far as the 
 859     // memory checking facility is concerned. 
 860     // Of course you may argue that memory allocated in globals should be 
 861     // checked, but this is a reasonable compromise. 
 862     wxDebugContext::SetCheckpoint(); 
 864     int err 
= wxEntryStart(argc
, argv
); 
 870         wxCHECK_MSG( wxApp::GetInitializerFunction(), -1, 
 871                      wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") ); 
 873         wxAppInitializerFunction app_ini 
= wxApp::GetInitializerFunction(); 
 875         wxObject 
*test_app 
= app_ini(); 
 877         wxTheApp 
= (wxApp
*) test_app
; 
 880     wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") ); 
 882     wxTheApp
->argc 
= argc
; 
 884     wxTheApp
->argv 
= new wxChar
*[argc
+1]; 
 886     while (mb_argc 
< argc
) 
 888         wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
])); 
 891     wxTheApp
->argv
[mb_argc
] = (wxChar 
*)NULL
; 
 893     wxTheApp
->argv 
= argv
; 
 896     if (wxTheApp
->argc 
> 0) 
 898         wxFileName 
fname( wxTheApp
->argv
[0] ); 
 899         wxTheApp
->SetAppName( fname
.GetName() ); 
 903     retValue 
= wxEntryInitGui(); 
 905     // Here frames insert themselves automatically into wxTopLevelWindows by 
 906     // getting created in OnInit(). 
 909         if ( !wxTheApp
->OnInit() ) 
 915         // Delete pending toplevel windows 
 916         wxTheApp
->DeletePendingObjects(); 
 918         // When is the app not initialized ? 
 919         wxTheApp
->m_initialized 
= TRUE
; 
 921         if (wxTheApp
->Initialized()) 
 925             wxWindow 
*topWindow 
= wxTheApp
->GetTopWindow(); 
 927             // Delete all pending windows if any 
 928             wxTheApp
->DeletePendingObjects(); 
 932                 wxTheApp
->SetTopWindow( (wxWindow
*) NULL 
); 
 934             retValue 
= wxTheApp
->OnExit(); 
 945 void wxApp::OnAssert(const wxChar 
*file
, int line
, const wxChar
* cond
, const wxChar 
*msg
) 
 949     wxAppBase::OnAssert(file
, line
, cond
, msg
); 
 951     m_isInAssert 
= FALSE
; 
 954 #endif // __WXDEBUG__