1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  13 #pragma implementation "app.h" 
  19 #include "wx/gdicmn.h" 
  22 #include "wx/cursor.h" 
  24 #include "wx/palette.h" 
  26 #include "wx/dialog.h" 
  27 #include "wx/msgdlg.h" 
  29 #include "wx/module.h" 
  30 #include "wx/memory.h" 
  35     #include "wx/thread.h" 
  38 #if wxUSE_WX_RESOURCES 
  39     #include "wx/resource.h" 
  44 #include <X11/Xutil.h> 
  45 #include <X11/Xresource.h> 
  46 #include <X11/Xatom.h> 
  48 #include "wx/motif/private.h" 
  52 extern char *wxBuffer
; 
  53 extern wxList wxPendingDelete
; 
  56 extern wxList 
*wxPendingEvents
; 
  57 extern wxCriticalSection 
*wxPendingEventsLocker
; 
  58 #endif // wxUSE_THREADS 
  60 wxApp 
*wxTheApp 
= NULL
; 
  62 wxHashTable 
*wxWidgetHashTable 
= NULL
; 
  64 #if !USE_SHARED_LIBRARY 
  65 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
) 
  67 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
) 
  68     EVT_IDLE(wxApp::OnIdle
) 
  72 long wxApp::sm_lastMessageTime 
= 0; 
  74 bool wxApp::Initialize() 
  76     wxBuffer 
= new char[BUFSIZ 
+ 512]; 
  78     wxClassInfo::InitializeClasses(); 
  80     // GL: I'm annoyed ... I don't know where to put this and I don't want to  
  81     // create a module for that as it's part of the core. 
  83     wxPendingEvents 
= new wxList(); 
  84     wxPendingEventsLocker 
= new wxCriticalSection(); 
  87     wxTheColourDatabase 
= new wxColourDatabase(wxKEY_STRING
); 
  88     wxTheColourDatabase
->Initialize(); 
  90     wxInitializeStockLists(); 
  91     wxInitializeStockObjects(); 
  93 #if wxUSE_WX_RESOURCES 
  94     wxInitializeResourceSystem(); 
  97     // For PostScript printing 
  99     /* Done using wxModule now 
 100     wxInitializePrintSetupData(); 
 101     wxThePrintPaperDatabase = new wxPrintPaperDatabase; 
 102     wxThePrintPaperDatabase->CreateDatabase(); 
 106     wxBitmap::InitStandardHandlers(); 
 108     wxWidgetHashTable 
= new wxHashTable(wxKEY_INTEGER
); 
 110     wxModule::RegisterModules(); 
 111     if (!wxModule::InitializeModules()) return FALSE
; 
 116 void wxApp::CleanUp() 
 118     delete wxWidgetHashTable
; 
 119     wxWidgetHashTable 
= NULL
; 
 121     wxModule::CleanUpModules(); 
 123 #if wxUSE_WX_RESOURCES 
 124     wxCleanUpResourceSystem(); 
 127     wxDeleteStockObjects() ; 
 129     // Destroy all GDI lists, etc. 
 131     delete wxTheBrushList
; 
 132     wxTheBrushList 
= NULL
; 
 137     delete wxTheFontList
; 
 138     wxTheFontList 
= NULL
; 
 140     delete wxTheBitmapList
; 
 141     wxTheBitmapList 
= NULL
; 
 143     delete wxTheColourDatabase
; 
 144     wxTheColourDatabase 
= NULL
; 
 147     /* Done using wxModule now 
 148     wxInitializePrintSetupData(FALSE); 
 149     delete wxThePrintPaperDatabase; 
 150     wxThePrintPaperDatabase = NULL; 
 154     wxBitmap::CleanUpHandlers(); 
 159     wxClassInfo::CleanUpClasses(); 
 164     // GL: I'm annoyed ... I don't know where to put this and I don't want to 
 165     // create a module for that as it's part of the core. 
 167     delete wxPendingEvents
; 
 168     delete wxPendingEventsLocker
; 
 171 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT 
 172     // At this point we want to check if there are any memory 
 173     // blocks that aren't part of the wxDebugContext itself, 
 174     // as a special case. Then when dumping we need to ignore 
 175     // wxDebugContext, too. 
 176     if (wxDebugContext::CountObjectsLeft(TRUE
) > 0) 
 178         wxLogDebug("There were memory leaks.\n"); 
 179         wxDebugContext::Dump(); 
 180         wxDebugContext::PrintStatistics(); 
 184     // do it as the very last thing because everything else can log messages 
 185     wxLog::DontCreateOnDemand(); 
 186     // do it as the very last thing because everything else can log messages 
 187     delete wxLog::SetActiveTarget(NULL
); 
 190 int wxEntry( int argc
, char *argv
[] ) 
 192 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT 
 193     // This seems to be necessary since there are 'rogue' 
 194     // objects present at this point (perhaps global objects?) 
 195     // Setting a checkpoint will ignore them as far as the 
 196     // memory checking facility is concerned. 
 197     // Of course you may argue that memory allocated in globals should be 
 198     // checked, but this is a reasonable compromise. 
 199     wxDebugContext::SetCheckpoint(); 
 202     if (!wxApp::Initialize()) 
 207         if (!wxApp::GetInitializerFunction()) 
 209             printf( "wxWindows error: No initializer - use IMPLEMENT_APP macro.\n" ); 
 213         wxTheApp 
= (wxApp
*) (* wxApp::GetInitializerFunction()) (); 
 218         printf( "wxWindows error: wxTheApp == NULL\n" ); 
 222     wxTheApp
->SetClassName(wxFileNameFromPath(argv
[0])); 
 223     wxTheApp
->SetAppName(wxFileNameFromPath(argv
[0])); 
 225     wxTheApp
->argc 
= argc
; 
 226     wxTheApp
->argv 
= argv
; 
 228     // GUI-specific initialization, such as creating an app context. 
 229     wxTheApp
->OnInitGui(); 
 231     // Here frames insert themselves automatically into wxTopLevelWindows by 
 232     // getting created in OnInit(). 
 235     if (wxTheApp
->OnInit()) 
 237         if (wxTheApp
->Initialized()) retValue 
= wxTheApp
->OnRun(); 
 240     // flush the logged messages if any 
 241     wxLog 
*pLog 
= wxLog::GetActiveTarget(); 
 242     if ( pLog 
!= NULL 
&& pLog
->HasPendingMessages() ) 
 245     delete wxLog::SetActiveTarget(new wxLogStderr
); // So dialog boxes aren't used 
 246     // for further messages 
 248     if (wxTheApp
->GetTopWindow()) 
 250         delete wxTheApp
->GetTopWindow(); 
 251         wxTheApp
->SetTopWindow(NULL
); 
 254     wxTheApp
->DeletePendingObjects(); 
 263 // Static member initialization 
 264 wxAppInitializerFunction 
wxApp::m_appInitFn 
= (wxAppInitializerFunction
) NULL
; 
 271     m_wantDebugOutput 
= TRUE 
; 
 275     m_printMode 
= wxPRINT_POSTSCRIPT
; 
 276     m_exitOnFrameDelete 
= TRUE
; 
 279     m_mainColormap 
= (WXColormap
) NULL
; 
 280     m_appContext 
= (WXAppContext
) NULL
; 
 281     m_topLevelWidget 
= (WXWidget
) NULL
; 
 282     m_maxRequestSize 
= 0; 
 283     m_initialDisplay 
= (WXDisplay
*) 0; 
 286 bool wxApp::Initialized() 
 294 int wxApp::MainLoop() 
 299     * Sit around forever waiting to process X-events. Property Change 
 300     * event are handled special, because they have to refer to 
 301     * the root window rather than to a widget. therefore we can't 
 302     * use an Xt-eventhandler. 
 305     XSelectInput(XtDisplay((Widget
) wxTheApp
->GetTopLevelWidget()), 
 306         XDefaultRootWindow(XtDisplay((Widget
) wxTheApp
->GetTopLevelWidget())), 
 311     // Use this flag to allow breaking the loop via wxApp::ExitMainLoop() 
 314         XtAppNextEvent( (XtAppContext
) wxTheApp
->GetAppContext(), &event
); 
 316         ProcessXEvent((WXEvent
*) & event
); 
 318         if (XtAppPending( (XtAppContext
) wxTheApp
->GetAppContext() ) == 0) 
 323                 // leave the main loop to give other threads a chance to 
 324                 // perform their GUI work 
 337 // Processes an X event. 
 338 void wxApp::ProcessXEvent(WXEvent
* _event
) 
 340     XEvent
* event 
= (XEvent
*) _event
; 
 342     if ((event
->type 
== KeyPress
) && CheckForAccelerator(_event
)) 
 344         // Do nothing! We intercepted and processed the event as an accelerator. 
 347     else if (event
->type 
== PropertyNotify
) 
 349         HandlePropertyChange(_event
); 
 352     else if (event
->type 
== ResizeRequest
) 
 354     /* Terry Gitnick <terryg@scientech.com> - 1/21/98 
 355     * If resize event, don't resize until the last resize event for this 
 356     * window is recieved. Prevents flicker as windows are resized. 
 359         Display 
*disp 
= XtDisplay((Widget
) wxTheApp
->GetTopLevelWidget()); 
 360         Window win 
= event
->xany
.window
; 
 365         while( XCheckTypedWindowEvent (disp
, win
, ResizeRequest
, &report
)); 
 367         // TODO: when implementing refresh optimization, we can use 
 368         // XtAddExposureToRegion to expand the window's paint region. 
 370         XtDispatchEvent(event
); 
 374         XtDispatchEvent(event
); 
 378 // Returns TRUE if more time is needed. 
 379 bool wxApp::ProcessIdle() 
 382     event
.SetEventObject(this); 
 385     return event
.MoreRequested(); 
 388 void wxApp::ExitMainLoop() 
 393 // Is a message/event pending? 
 394 bool wxApp::Pending() 
 396     XFlush(XtDisplay( (Widget
) wxTheApp
->GetTopLevelWidget() )); 
 398     // Fix by Doug from STI, to prevent a stall if non-X event 
 400     return ((XtAppPending( (XtAppContext
) GetAppContext() ) & XtIMXEvent
) != 0) ; 
 403 // Dispatch a message. 
 404 void wxApp::Dispatch() 
 406     //    XtAppProcessEvent( (XtAppContext) wxTheApp->GetAppContext(), XtIMAll); 
 409     XtAppNextEvent((XtAppContext
) GetAppContext(), &event
); 
 410     ProcessXEvent((WXEvent
*) & event
); 
 413 // This should be redefined in a derived class for 
 414 // handling property change events for XAtom IPC. 
 415 void wxApp::HandlePropertyChange(WXEvent 
*event
) 
 417     // by default do nothing special 
 418     XtDispatchEvent((XEvent
*) event
); /* let Motif do the work */ 
 421 void wxApp::OnIdle(wxIdleEvent
& event
) 
 423     static bool inOnIdle 
= FALSE
; 
 425     // Avoid recursion (via ProcessEvent default case) 
 431     // 'Garbage' collection of windows deleted with Close(). 
 432     DeletePendingObjects(); 
 435     // Flush pending events. 
 436     ProcessPendingEvents(); 
 439     // flush the logged messages if any 
 440     wxLog 
*pLog 
= wxLog::GetActiveTarget(); 
 441     if ( pLog 
!= NULL 
&& pLog
->HasPendingMessages() ) 
 444     // Send OnIdle events to all windows 
 445     bool needMore 
= SendIdleEvents(); 
 448         event
.RequestMore(TRUE
); 
 453 // Send idle event to all top-level windows 
 454 bool wxApp::SendIdleEvents() 
 456     bool needMore 
= FALSE
; 
 458     wxWindowList::Node
* node 
= wxTopLevelWindows
.GetFirst(); 
 461         wxWindow
* win 
= node
->GetData(); 
 462         if (SendIdleEvents(win
)) 
 464         node 
= node
->GetNext(); 
 470 // Send idle event to window and all subwindows 
 471 bool wxApp::SendIdleEvents(wxWindow
* win
) 
 473     bool needMore 
= FALSE
; 
 476     event
.SetEventObject(win
); 
 477     win
->ProcessEvent(event
); 
 479     if (event
.MoreRequested()) 
 482     wxNode
* node 
= win
->GetChildren().First(); 
 485         wxWindow
* win 
= (wxWindow
*) node
->Data(); 
 486         if (SendIdleEvents(win
)) 
 494 void wxApp::DeletePendingObjects() 
 496     wxNode 
*node 
= wxPendingDelete
.First(); 
 499         wxObject 
*obj 
= (wxObject 
*)node
->Data(); 
 503         if (wxPendingDelete
.Member(obj
)) 
 506         // Deleting one object may have deleted other pending 
 507         // objects, so start from beginning of list again. 
 508         node 
= wxPendingDelete
.First(); 
 513 void wxApp::ProcessPendingEvents() 
 515     wxNode 
*node 
= wxPendingEvents
->First(); 
 516     wxCriticalSectionLocker 
locker(*wxPendingEventsLocker
); 
 520         wxEvtHandler 
*handler 
= (wxEvtHandler 
*)node
->Data(); 
 522         handler
->ProcessPendingEvents(); 
 525         node 
= wxPendingEvents
->First(); 
 528 #endif // wxUSE_THREADS 
 530 wxLog
* wxApp::CreateLogTarget() 
 535 wxWindow
* wxApp::GetTopWindow() const 
 539     else if (wxTopLevelWindows
.GetCount() > 0) 
 540         return wxTopLevelWindows
.GetFirst()->GetData(); 
 545 // Create an application context 
 546 bool wxApp::OnInitGui() 
 548     XtToolkitInitialize() ; 
 549     wxTheApp
->m_appContext 
= (WXAppContext
) XtCreateApplicationContext() ; 
 550     Display 
*dpy 
= XtOpenDisplay((XtAppContext
) wxTheApp
->m_appContext
,(String
)NULL
,NULL
, 
 551         (const char*) wxTheApp
->GetClassName(), NULL
, 0, 
 552 # if XtSpecificationRelease < 5 
 560         wxString 
className(wxTheApp
->GetClassName()); 
 561         wxLogError(_("wxWindows could not open display for '%s': exiting."), 
 562                    (const char*) className
); 
 565     m_initialDisplay 
= (WXDisplay
*) dpy
; 
 567     wxTheApp
->m_topLevelWidget 
= (WXWidget
) XtAppCreateShell((String
)NULL
, (const char*) wxTheApp
->GetClassName(), 
 568         applicationShellWidgetClass
,dpy
, 
 571     // Add general resize proc 
 573     rec
.string 
= "resize"; 
 574     rec
.proc 
= (XtActionProc
)wxWidgetResizeProc
; 
 575     XtAppAddActions((XtAppContext
) wxTheApp
->m_appContext
, &rec
, 1); 
 577     GetMainColormap(dpy
); 
 578     m_maxRequestSize 
= XMaxRequestSize((Display
*) dpy
); 
 583 WXColormap 
wxApp::GetMainColormap(WXDisplay
* display
) 
 585     if (!display
) /* Must be called first with non-NULL display */ 
 586         return m_mainColormap
; 
 588     int defaultScreen 
= DefaultScreen((Display
*) display
); 
 589     Screen
* screen 
= XScreenOfDisplay((Display
*) display
, defaultScreen
); 
 591     Colormap c 
= DefaultColormapOfScreen(screen
); 
 594         m_mainColormap 
= (WXColormap
) c
; 
 596     return (WXColormap
) c
; 
 599 // Returns TRUE if an accelerator has been processed 
 600 bool wxApp::CheckForAccelerator(WXEvent
* event
) 
 602     XEvent
* xEvent 
= (XEvent
*) event
; 
 603     if (xEvent
->xany
.type 
== KeyPress
) 
 605         // Find a wxWindow for this window 
 606         // TODO: should get display for the window, not the current display 
 607         Widget widget 
= XtWindowToWidget((Display
*) wxGetDisplay(), xEvent
->xany
.window
); 
 608         wxWindow
* win 
= NULL
; 
 610         // Find the first wxWindow that corresponds to this event window 
 611         while (widget 
&& !(win 
= wxGetWindowFromTable(widget
))) 
 612             widget 
= XtParent(widget
); 
 617         wxKeyEvent 
keyEvent(wxEVT_CHAR
); 
 618         wxTranslateKeyEvent(keyEvent
, win
, (Widget
) 0, xEvent
); 
 620         // Now we have a wxKeyEvent and we have a wxWindow. 
 621         // Go up the hierarchy until we find a matching accelerator, 
 622         // or we get to the top. 
 625             if (win
->ProcessAccelerator(keyEvent
)) 
 627             win 
= win
->GetParent(); 
 638         retValue 
= wxTheApp
->OnExit(); 
 642     * Exit in some platform-specific way. Not recommended that the app calls this: 
 643     * only for emergencies. 
 648 // Yield to other processes 
 651     while (wxTheApp 
&& wxTheApp
->Pending()) 
 652         wxTheApp
->Dispatch(); 
 654     // VZ: is it the same as this (taken from old wxExecute)? 
 656     XtAppProcessEvent((XtAppContext
) wxTheApp
->GetAppContext(), XtIMAll
);