1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  13     #pragma implementation "app.h" 
  17 #define XtParent XTPARENT 
  18 #define XtDisplay XTDISPLAY 
  24 #include "wx/gdicmn.h" 
  27 #include "wx/cursor.h" 
  29 #include "wx/palette.h" 
  31 #include "wx/dialog.h" 
  32 #include "wx/msgdlg.h" 
  34 #include "wx/module.h" 
  35 #include "wx/memory.h" 
  40     #include "wx/thread.h" 
  43 #if wxUSE_WX_RESOURCES 
  44     #include "wx/resource.h" 
  48 #pragma message disable nosimpint 
  52 #include <X11/Xutil.h> 
  53 #include <X11/Xresource.h> 
  54 #include <X11/Xatom.h> 
  56 #pragma message enable nosimpint 
  59 #include "wx/motif/private.h" 
  63 extern char *wxBuffer
; 
  64 extern wxList wxPendingDelete
; 
  66 wxApp 
*wxTheApp 
= NULL
; 
  68 wxHashTable 
*wxWidgetHashTable 
= NULL
; 
  70 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
) 
  72 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
) 
  73     EVT_IDLE(wxApp::OnIdle
) 
  77     typedef int (*XErrorHandlerFunc
)(Display 
*, XErrorEvent 
*); 
  79     XErrorHandlerFunc gs_pfnXErrorHandler 
= 0; 
  81     static int wxXErrorHandler(Display 
*dpy
, XErrorEvent 
*xevent
) 
  83         // just forward to the default handler for now 
  84         return gs_pfnXErrorHandler(dpy
, xevent
); 
  88 long wxApp::sm_lastMessageTime 
= 0; 
  90 bool wxApp::Initialize() 
  92     wxBuffer 
= new char[BUFSIZ 
+ 512]; 
  94     wxClassInfo::InitializeClasses(); 
  96     // GL: I'm annoyed ... I don't know where to put this and I don't want to 
  97     // create a module for that as it's part of the core. 
  99     wxPendingEventsLocker 
= new wxCriticalSection(); 
 102     wxTheColourDatabase 
= new wxColourDatabase(wxKEY_STRING
); 
 103     wxTheColourDatabase
->Initialize(); 
 105     wxInitializeStockLists(); 
 106     wxInitializeStockObjects(); 
 108 #if wxUSE_WX_RESOURCES 
 109     wxInitializeResourceSystem(); 
 112     // For PostScript printing 
 114     /* Done using wxModule now 
 115     wxInitializePrintSetupData(); 
 116     wxThePrintPaperDatabase = new wxPrintPaperDatabase; 
 117     wxThePrintPaperDatabase->CreateDatabase(); 
 121     wxBitmap::InitStandardHandlers(); 
 123     wxWidgetHashTable 
= new wxHashTable(wxKEY_INTEGER
); 
 125     wxModule::RegisterModules(); 
 126     if (!wxModule::InitializeModules()) return FALSE
; 
 131 void wxApp::CleanUp() 
 133     delete wxWidgetHashTable
; 
 134     wxWidgetHashTable 
= NULL
; 
 136     wxModule::CleanUpModules(); 
 138 #if wxUSE_WX_RESOURCES 
 139     wxCleanUpResourceSystem(); 
 142     wxDeleteStockObjects() ; 
 144     // Destroy all GDI lists, etc. 
 146     wxDeleteStockLists(); 
 148     delete wxTheColourDatabase
; 
 149     wxTheColourDatabase 
= NULL
; 
 152     /* Done using wxModule now 
 153     wxInitializePrintSetupData(FALSE); 
 154     delete wxThePrintPaperDatabase; 
 155     wxThePrintPaperDatabase = NULL; 
 159     wxBitmap::CleanUpHandlers(); 
 164     wxClassInfo::CleanUpClasses(); 
 169     // GL: I'm annoyed ... I don't know where to put this and I don't want to 
 170     // create a module for that as it's part of the core. 
 172     delete wxPendingEvents
; 
 173     delete wxPendingEventsLocker
; 
 176 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT 
 177     // At this point we want to check if there are any memory 
 178     // blocks that aren't part of the wxDebugContext itself, 
 179     // as a special case. Then when dumping we need to ignore 
 180     // wxDebugContext, too. 
 181     if (wxDebugContext::CountObjectsLeft(TRUE
) > 0) 
 183         wxLogDebug("There were memory leaks.\n"); 
 184         wxDebugContext::Dump(); 
 185         wxDebugContext::PrintStatistics(); 
 189     // do it as the very last thing because everything else can log messages 
 190     wxLog::DontCreateOnDemand(); 
 191     // do it as the very last thing because everything else can log messages 
 192     delete wxLog::SetActiveTarget(NULL
); 
 195 int wxEntry( int argc
, char *argv
[] ) 
 197 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT 
 198     // This seems to be necessary since there are 'rogue' 
 199     // objects present at this point (perhaps global objects?) 
 200     // Setting a checkpoint will ignore them as far as the 
 201     // memory checking facility is concerned. 
 202     // Of course you may argue that memory allocated in globals should be 
 203     // checked, but this is a reasonable compromise. 
 204     wxDebugContext::SetCheckpoint(); 
 207     if (!wxApp::Initialize()) 
 212         if (!wxApp::GetInitializerFunction()) 
 214             printf( "wxWindows error: No initializer - use IMPLEMENT_APP macro.\n" ); 
 218         wxTheApp 
= (wxApp
*) (* wxApp::GetInitializerFunction()) (); 
 223         printf( "wxWindows error: wxTheApp == NULL\n" ); 
 227     wxTheApp
->SetClassName(wxFileNameFromPath(argv
[0])); 
 228     wxTheApp
->SetAppName(wxFileNameFromPath(argv
[0])); 
 230     wxTheApp
->argc 
= argc
; 
 231     wxTheApp
->argv 
= argv
; 
 233     // GUI-specific initialization, such as creating an app context. 
 234     wxTheApp
->OnInitGui(); 
 236     // Here frames insert themselves automatically into wxTopLevelWindows by 
 237     // getting created in OnInit(). 
 240     if (wxTheApp
->OnInit()) 
 242         if (wxTheApp
->Initialized()) retValue 
= wxTheApp
->OnRun(); 
 245     // flush the logged messages if any 
 246     wxLog 
*pLog 
= wxLog::GetActiveTarget(); 
 247     if ( pLog 
!= NULL 
&& pLog
->HasPendingMessages() ) 
 250     delete wxLog::SetActiveTarget(new wxLogStderr
); // So dialog boxes aren't used 
 251     // for further messages 
 253     if (wxTheApp
->GetTopWindow()) 
 255         delete wxTheApp
->GetTopWindow(); 
 256         wxTheApp
->SetTopWindow(NULL
); 
 259     wxTheApp
->DeletePendingObjects(); 
 268 // Static member initialization 
 269 wxAppInitializerFunction 
wxAppBase::m_appInitFn 
= (wxAppInitializerFunction
) NULL
; 
 276     m_wantDebugOutput 
= TRUE 
; 
 280     m_exitOnFrameDelete 
= TRUE
; 
 282     m_mainColormap 
= (WXColormap
) NULL
; 
 283     m_appContext 
= (WXAppContext
) NULL
; 
 284     m_topLevelWidget 
= (WXWidget
) NULL
; 
 285     m_maxRequestSize 
= 0; 
 286     m_initialDisplay 
= (WXDisplay
*) 0; 
 289 bool wxApp::Initialized() 
 297 int wxApp::MainLoop() 
 302     * Sit around forever waiting to process X-events. Property Change 
 303     * event are handled special, because they have to refer to 
 304     * the root window rather than to a widget. therefore we can't 
 305     * use an Xt-eventhandler. 
 308     XSelectInput(XtDisplay((Widget
) wxTheApp
->GetTopLevelWidget()), 
 309         XDefaultRootWindow(XtDisplay((Widget
) wxTheApp
->GetTopLevelWidget())), 
 314     // Use this flag to allow breaking the loop via wxApp::ExitMainLoop() 
 317         XtAppNextEvent( (XtAppContext
) wxTheApp
->GetAppContext(), &event
); 
 319         ProcessXEvent((WXEvent
*) & event
); 
 321         if (XtAppPending( (XtAppContext
) wxTheApp
->GetAppContext() ) == 0) 
 326                 // leave the main loop to give other threads a chance to 
 327                 // perform their GUI work 
 340 // Processes an X event. 
 341 void wxApp::ProcessXEvent(WXEvent
* _event
) 
 343     XEvent
* event 
= (XEvent
*) _event
; 
 345     if (event
->type 
== KeyPress
) 
 347 #if 0 // def __WXDEBUG__ 
 348         Widget widget 
= XtWindowToWidget(event
->xany
.display
, event
->xany
.window
); 
 349         wxLogDebug("Got key press event for 0x%08x (parent = 0x%08x)", 
 350                    widget
, XtParent(widget
)); 
 353     if (CheckForAccelerator(_event
)) 
 355             // Do nothing! We intercepted and processed the event as an 
 360         // It seemed before that this hack was redundant and 
 361         // key down events were being generated by wxCanvasInputEvent. 
 362         // But no longer - why ??? 
 364     else if (CheckForKeyDown(_event
)) 
 366             // We intercepted and processed the key down event 
 372             XtDispatchEvent(event
); 
 376     else if (event
->type 
== KeyRelease
) 
 378         // TODO: work out why we still need this !  -michael 
 380         if (CheckForKeyUp(_event
)) 
 382         // We intercepted and processed the key up event 
 387         XtDispatchEvent(event
); 
 391     else if (event
->type 
== PropertyNotify
) 
 393         HandlePropertyChange(_event
); 
 396     else if (event
->type 
== ResizeRequest
) 
 398         /* Terry Gitnick <terryg@scientech.com> - 1/21/98 
 399          * If resize event, don't resize until the last resize event for this 
 400          * window is recieved. Prevents flicker as windows are resized. 
 403         Display 
*disp 
= XtDisplay((Widget
) wxTheApp
->GetTopLevelWidget()); 
 404         Window win 
= event
->xany
.window
; 
 409         while( XCheckTypedWindowEvent (disp
, win
, ResizeRequest
, &report
)); 
 411         // TODO: when implementing refresh optimization, we can use 
 412         // XtAddExposureToRegion to expand the window's paint region. 
 414         XtDispatchEvent(event
); 
 418         XtDispatchEvent(event
); 
 422 // Returns TRUE if more time is needed. 
 423 bool wxApp::ProcessIdle() 
 426     event
.SetEventObject(this); 
 429     return event
.MoreRequested(); 
 432 void wxApp::ExitMainLoop() 
 437 // Is a message/event pending? 
 438 bool wxApp::Pending() 
 440     XFlush(XtDisplay( (Widget
) wxTheApp
->GetTopLevelWidget() )); 
 442     // Fix by Doug from STI, to prevent a stall if non-X event 
 444     return ((XtAppPending( (XtAppContext
) GetAppContext() ) & XtIMXEvent
) != 0) ; 
 447 // Dispatch a message. 
 448 void wxApp::Dispatch() 
 450     //    XtAppProcessEvent( (XtAppContext) wxTheApp->GetAppContext(), XtIMAll); 
 453     XtAppNextEvent((XtAppContext
) GetAppContext(), &event
); 
 454     ProcessXEvent((WXEvent
*) & event
); 
 457 // This should be redefined in a derived class for 
 458 // handling property change events for XAtom IPC. 
 459 void wxApp::HandlePropertyChange(WXEvent 
*event
) 
 461     // by default do nothing special 
 462     XtDispatchEvent((XEvent
*) event
); /* let Motif do the work */ 
 465 void wxApp::OnIdle(wxIdleEvent
& event
) 
 467     static bool inOnIdle 
= FALSE
; 
 469     // Avoid recursion (via ProcessEvent default case) 
 475     // If there are pending events, we must process them: pending events 
 476     // are either events to the threads other than main or events posted 
 477     // with wxPostEvent() functions 
 478     // GRG: I have moved this here so that all pending events are processed 
 479     //   before starting to delete any objects. This behaves better (in 
 480     //   particular, wrt wxPostEvent) and is coherent with wxGTK's current 
 481     //   behaviour. Also removed the '#if wxUSE_THREADS' around it. 
 482     //  Changed Mar/2000 before 2.1.14 
 484     // Flush pending events. 
 485     ProcessPendingEvents(); 
 487     // 'Garbage' collection of windows deleted with Close(). 
 488     DeletePendingObjects(); 
 490     // flush the logged messages if any 
 491     wxLog 
*pLog 
= wxLog::GetActiveTarget(); 
 492     if ( pLog 
!= NULL 
&& pLog
->HasPendingMessages() ) 
 495     // Send OnIdle events to all windows 
 496     bool needMore 
= SendIdleEvents(); 
 499         event
.RequestMore(TRUE
); 
 506     // **** please implement me! **** 
 507     // Wake up the idle handler processor, even if it is in another thread... 
 511 // Send idle event to all top-level windows 
 512 bool wxApp::SendIdleEvents() 
 514     bool needMore 
= FALSE
; 
 516     wxWindowList::Node
* node 
= wxTopLevelWindows
.GetFirst(); 
 519         wxWindow
* win 
= node
->GetData(); 
 520         if (SendIdleEvents(win
)) 
 522         node 
= node
->GetNext(); 
 528 // Send idle event to window and all subwindows 
 529 bool wxApp::SendIdleEvents(wxWindow
* win
) 
 531     bool needMore 
= FALSE
; 
 534     event
.SetEventObject(win
); 
 535     win
->ProcessEvent(event
); 
 537     if (event
.MoreRequested()) 
 540     wxNode
* node 
= win
->GetChildren().First(); 
 543         wxWindow
* win 
= (wxWindow
*) node
->Data(); 
 544         if (SendIdleEvents(win
)) 
 552 void wxApp::DeletePendingObjects() 
 554     wxNode 
*node 
= wxPendingDelete
.First(); 
 557         wxObject 
*obj 
= (wxObject 
*)node
->Data(); 
 561         if (wxPendingDelete
.Member(obj
)) 
 564         // Deleting one object may have deleted other pending 
 565         // objects, so start from beginning of list again. 
 566         node 
= wxPendingDelete
.First(); 
 570 // Create an application context 
 571 bool wxApp::OnInitGui() 
 573     XtToolkitInitialize() ; 
 574     wxTheApp
->m_appContext 
= (WXAppContext
) XtCreateApplicationContext() ; 
 575     Display 
*dpy 
= XtOpenDisplay((XtAppContext
) wxTheApp
->m_appContext
,(String
)NULL
,NULL
, 
 576         (const char*) wxTheApp
->GetClassName(), NULL
, 0, 
 577 # if XtSpecificationRelease < 5 
 585         wxString 
className(wxTheApp
->GetClassName()); 
 586         wxLogError(_("wxWindows could not open display for '%s': exiting."), 
 587                    (const char*) className
); 
 590     m_initialDisplay 
= (WXDisplay
*) dpy
; 
 593     // install the X error handler 
 594     gs_pfnXErrorHandler 
= XSetErrorHandler(wxXErrorHandler
); 
 595 #endif // __WXDEBUG__ 
 597     wxTheApp
->m_topLevelWidget 
= (WXWidget
) XtAppCreateShell((String
)NULL
, (const char*) wxTheApp
->GetClassName(), 
 598         applicationShellWidgetClass
,dpy
, 
 601     // Add general resize proc 
 603     rec
.string 
= "resize"; 
 604     rec
.proc 
= (XtActionProc
)wxWidgetResizeProc
; 
 605     XtAppAddActions((XtAppContext
) wxTheApp
->m_appContext
, &rec
, 1); 
 607     GetMainColormap(dpy
); 
 608     m_maxRequestSize 
= XMaxRequestSize((Display
*) dpy
); 
 613 WXColormap 
wxApp::GetMainColormap(WXDisplay
* display
) 
 615     if (!display
) /* Must be called first with non-NULL display */ 
 616         return m_mainColormap
; 
 618     int defaultScreen 
= DefaultScreen((Display
*) display
); 
 619     Screen
* screen 
= XScreenOfDisplay((Display
*) display
, defaultScreen
); 
 621     Colormap c 
= DefaultColormapOfScreen(screen
); 
 624         m_mainColormap 
= (WXColormap
) c
; 
 626     return (WXColormap
) c
; 
 629 // Returns TRUE if an accelerator has been processed 
 630 bool wxApp::CheckForAccelerator(WXEvent
* event
) 
 632     XEvent
* xEvent 
= (XEvent
*) event
; 
 633     if (xEvent
->xany
.type 
== KeyPress
) 
 635         // Find a wxWindow for this window 
 636         // TODO: should get display for the window, not the current display 
 637         Widget widget 
= XtWindowToWidget((Display
*) wxGetDisplay(), xEvent
->xany
.window
); 
 638         wxWindow
* win 
= NULL
; 
 640         // Find the first wxWindow that corresponds to this event window 
 641         while (widget 
&& !(win 
= wxGetWindowFromTable(widget
))) 
 642             widget 
= XtParent(widget
); 
 647         wxKeyEvent 
keyEvent(wxEVT_CHAR
); 
 648         wxTranslateKeyEvent(keyEvent
, win
, (Widget
) 0, xEvent
); 
 650         // Now we have a wxKeyEvent and we have a wxWindow. 
 651         // Go up the hierarchy until we find a matching accelerator, 
 652         // or we get to the top. 
 655             if (win
->ProcessAccelerator(keyEvent
)) 
 657             win 
= win
->GetParent(); 
 664 bool wxApp::CheckForKeyDown(WXEvent
* event
) 
 666     XEvent
* xEvent 
= (XEvent
*) event
; 
 667     if (xEvent
->xany
.type 
== KeyPress
) 
 669         Widget widget 
= XtWindowToWidget((Display
*) wxGetDisplay(), 
 670                      xEvent
->xany
.window
); 
 671     wxWindow
* win 
= NULL
; 
 673     // Find the first wxWindow that corresponds to this event window 
 674     while (widget 
&& !(win 
= wxGetWindowFromTable(widget
))) 
 675             widget 
= XtParent(widget
); 
 680     wxKeyEvent 
keyEvent(wxEVT_KEY_DOWN
); 
 681     wxTranslateKeyEvent(keyEvent
, win
, (Widget
) 0, xEvent
); 
 683     return win
->ProcessEvent( keyEvent 
); 
 689 bool wxApp::CheckForKeyUp(WXEvent
* event
) 
 691     XEvent
* xEvent 
= (XEvent
*) event
; 
 692     if (xEvent
->xany
.type 
== KeyRelease
) 
 694         Widget widget 
= XtWindowToWidget((Display
*) wxGetDisplay(), 
 695                          xEvent
->xany
.window
); 
 696         wxWindow
* win 
= NULL
; 
 698         // Find the first wxWindow that corresponds to this event window 
 699         while (widget 
&& !(win 
= wxGetWindowFromTable(widget
))) 
 700                 widget 
= XtParent(widget
); 
 705         wxKeyEvent 
keyEvent(wxEVT_KEY_UP
); 
 706         wxTranslateKeyEvent(keyEvent
, win
, (Widget
) 0, xEvent
); 
 708         return win
->ProcessEvent( keyEvent 
); 
 718         retValue 
= wxTheApp
->OnExit(); 
 722     * Exit in some platform-specific way. Not recommended that the app calls this: 
 723     * only for emergencies. 
 728 // Yield to other processes 
 730 bool wxApp::Yield(bool onlyIfNeeded
) 
 732     bool s_inYield 
= FALSE
; 
 738             wxFAIL_MSG( wxT("wxYield called recursively" ) ); 
 746     while (wxTheApp 
&& wxTheApp
->Pending()) 
 747         wxTheApp
->Dispatch(); 
 754 // TODO use XmGetPixmap (?) to get the really standard icons! 
 756 #include "wx/generic/info.xpm" 
 757 #include "wx/generic/error.xpm" 
 758 #include "wx/generic/question.xpm" 
 759 #include "wx/generic/warning.xpm" 
 762 wxApp::GetStdIcon(int which
) const 
 766         case wxICON_INFORMATION
: 
 767             return wxIcon(info_xpm
); 
 769         case wxICON_QUESTION
: 
 770             return wxIcon(question_xpm
); 
 772         case wxICON_EXCLAMATION
: 
 773             return wxIcon(warning_xpm
); 
 776             wxFAIL_MSG("requested non existent standard icon"); 
 777             // still fall through 
 780             return wxIcon(error_xpm
); 
 784 // ---------------------------------------------------------------------------- 
 785 // accessors for C modules 
 786 // ---------------------------------------------------------------------------- 
 788 extern "C" XtAppContext 
wxGetAppContext() 
 790     return (XtAppContext
)wxTheApp
->GetAppContext();