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"
33 #include "wx/thread.h"
36 #if wxUSE_WX_RESOURCES
37 #include "wx/resource.h"
42 #include <X11/Xutil.h>
43 #include <X11/Xresource.h>
44 #include <X11/Xatom.h>
46 #include "wx/motif/private.h"
50 extern char *wxBuffer
;
51 extern wxList wxPendingDelete
;
54 extern wxList wxPendingEvents
;
55 extern wxCriticalSection wxPendingEventsLocker
;
56 #endif // wxUSE_THREADS
58 wxApp
*wxTheApp
= NULL
;
60 wxHashTable
*wxWidgetHashTable
= NULL
;
62 #if !USE_SHARED_LIBRARY
63 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
)
65 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
66 EVT_IDLE(wxApp::OnIdle
)
70 long wxApp::sm_lastMessageTime
= 0;
72 bool wxApp::Initialize()
74 wxBuffer
= new char[BUFSIZ
+ 512];
76 wxClassInfo::InitializeClasses();
78 wxTheColourDatabase
= new wxColourDatabase(wxKEY_STRING
);
79 wxTheColourDatabase
->Initialize();
81 wxInitializeStockLists();
82 wxInitializeStockObjects();
84 #if wxUSE_WX_RESOURCES
85 wxInitializeResourceSystem();
88 // For PostScript printing
90 /* Done using wxModule now
91 wxInitializePrintSetupData();
92 wxThePrintPaperDatabase = new wxPrintPaperDatabase;
93 wxThePrintPaperDatabase->CreateDatabase();
97 wxBitmap::InitStandardHandlers();
99 wxWidgetHashTable
= new wxHashTable(wxKEY_INTEGER
);
101 wxModule::RegisterModules();
102 if (!wxModule::InitializeModules()) return FALSE
;
107 void wxApp::CleanUp()
109 delete wxWidgetHashTable
;
110 wxWidgetHashTable
= NULL
;
112 wxModule::CleanUpModules();
114 #if wxUSE_WX_RESOURCES
115 wxCleanUpResourceSystem();
118 wxDeleteStockObjects() ;
120 // Destroy all GDI lists, etc.
122 delete wxTheBrushList
;
123 wxTheBrushList
= NULL
;
128 delete wxTheFontList
;
129 wxTheFontList
= NULL
;
131 delete wxTheBitmapList
;
132 wxTheBitmapList
= NULL
;
134 delete wxTheColourDatabase
;
135 wxTheColourDatabase
= NULL
;
138 /* Done using wxModule now
139 wxInitializePrintSetupData(FALSE);
140 delete wxThePrintPaperDatabase;
141 wxThePrintPaperDatabase = NULL;
145 wxBitmap::CleanUpHandlers();
150 wxClassInfo::CleanUpClasses();
155 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
156 // At this point we want to check if there are any memory
157 // blocks that aren't part of the wxDebugContext itself,
158 // as a special case. Then when dumping we need to ignore
159 // wxDebugContext, too.
160 if (wxDebugContext::CountObjectsLeft(TRUE
) > 0)
162 wxLogDebug("There were memory leaks.\n");
163 wxDebugContext::Dump();
164 wxDebugContext::PrintStatistics();
168 // do it as the very last thing because everything else can log messages
169 wxLog::DontCreateOnDemand();
170 // do it as the very last thing because everything else can log messages
171 delete wxLog::SetActiveTarget(NULL
);
174 int wxEntry( int argc
, char *argv
[] )
176 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
177 // This seems to be necessary since there are 'rogue'
178 // objects present at this point (perhaps global objects?)
179 // Setting a checkpoint will ignore them as far as the
180 // memory checking facility is concerned.
181 // Of course you may argue that memory allocated in globals should be
182 // checked, but this is a reasonable compromise.
183 wxDebugContext::SetCheckpoint();
186 if (!wxApp::Initialize())
191 if (!wxApp::GetInitializerFunction())
193 printf( "wxWindows error: No initializer - use IMPLEMENT_APP macro.\n" );
197 wxTheApp
= (wxApp
*) (* wxApp::GetInitializerFunction()) ();
202 printf( "wxWindows error: wxTheApp == NULL\n" );
206 wxTheApp
->SetClassName(wxFileNameFromPath(argv
[0]));
207 wxTheApp
->SetAppName(wxFileNameFromPath(argv
[0]));
209 wxTheApp
->argc
= argc
;
210 wxTheApp
->argv
= argv
;
212 // GUI-specific initialization, such as creating an app context.
213 wxTheApp
->OnInitGui();
215 // Here frames insert themselves automatically into wxTopLevelWindows by
216 // getting created in OnInit().
219 if (wxTheApp
->OnInit())
221 if (wxTheApp
->Initialized()) retValue
= wxTheApp
->OnRun();
224 // flush the logged messages if any
225 wxLog
*pLog
= wxLog::GetActiveTarget();
226 if ( pLog
!= NULL
&& pLog
->HasPendingMessages() )
229 delete wxLog::SetActiveTarget(new wxLogStderr
); // So dialog boxes aren't used
230 // for further messages
232 if (wxTheApp
->GetTopWindow())
234 delete wxTheApp
->GetTopWindow();
235 wxTheApp
->SetTopWindow(NULL
);
238 wxTheApp
->DeletePendingObjects();
247 // Static member initialization
248 wxAppInitializerFunction
wxApp::m_appInitFn
= (wxAppInitializerFunction
) NULL
;
255 m_wantDebugOutput
= TRUE
;
259 m_printMode
= wxPRINT_POSTSCRIPT
;
260 m_exitOnFrameDelete
= TRUE
;
263 m_mainColormap
= (WXColormap
) NULL
;
264 m_appContext
= (WXAppContext
) NULL
;
265 m_topLevelWidget
= (WXWidget
) NULL
;
266 m_maxRequestSize
= 0;
267 m_initialDisplay
= (WXDisplay
*) 0;
270 bool wxApp::Initialized()
278 int wxApp::MainLoop()
283 * Sit around forever waiting to process X-events. Property Change
284 * event are handled special, because they have to refer to
285 * the root window rather than to a widget. therefore we can't
286 * use an Xt-eventhandler.
289 XSelectInput(XtDisplay((Widget
) wxTheApp
->GetTopLevelWidget()),
290 XDefaultRootWindow(XtDisplay((Widget
) wxTheApp
->GetTopLevelWidget())),
295 // Use this flag to allow breaking the loop via wxApp::ExitMainLoop()
298 XtAppNextEvent( (XtAppContext
) wxTheApp
->GetAppContext(), &event
);
300 ProcessXEvent((WXEvent
*) & event
);
302 if (XtAppPending( (XtAppContext
) wxTheApp
->GetAppContext() ) == 0)
307 // leave the main loop to give other threads a chance to
308 // perform their GUI work
321 // Processes an X event.
322 void wxApp::ProcessXEvent(WXEvent
* _event
)
324 XEvent
* event
= (XEvent
*) _event
;
326 if ((event
->type
== KeyPress
) && CheckForAccelerator(_event
))
328 // Do nothing! We intercepted and processed the event as an accelerator.
331 else if (event
->type
== PropertyNotify
)
333 HandlePropertyChange(_event
);
336 else if (event
->type
== ResizeRequest
)
338 /* Terry Gitnick <terryg@scientech.com> - 1/21/98
339 * If resize event, don't resize until the last resize event for this
340 * window is recieved. Prevents flicker as windows are resized.
343 Display
*disp
= XtDisplay((Widget
) wxTheApp
->GetTopLevelWidget());
344 Window win
= event
->xany
.window
;
349 while( XCheckTypedWindowEvent (disp
, win
, ResizeRequest
, &report
));
351 // TODO: when implementing refresh optimization, we can use
352 // XtAddExposureToRegion to expand the window's paint region.
354 XtDispatchEvent(event
);
358 XtDispatchEvent(event
);
362 // Returns TRUE if more time is needed.
363 bool wxApp::ProcessIdle()
366 event
.SetEventObject(this);
369 return event
.MoreRequested();
372 void wxApp::ExitMainLoop()
377 // Is a message/event pending?
378 bool wxApp::Pending()
380 XFlush(XtDisplay( (Widget
) wxTheApp
->GetTopLevelWidget() ));
382 // Fix by Doug from STI, to prevent a stall if non-X event
384 return ((XtAppPending( (XtAppContext
) GetAppContext() ) & XtIMXEvent
) != 0) ;
387 // Dispatch a message.
388 void wxApp::Dispatch()
390 // XtAppProcessEvent( (XtAppContext) wxTheApp->GetAppContext(), XtIMAll);
393 XtAppNextEvent((XtAppContext
) GetAppContext(), &event
);
394 ProcessXEvent((WXEvent
*) & event
);
397 // This should be redefined in a derived class for
398 // handling property change events for XAtom IPC.
399 void wxApp::HandlePropertyChange(WXEvent
*event
)
401 // by default do nothing special
402 XtDispatchEvent((XEvent
*) event
); /* let Motif do the work */
405 void wxApp::OnIdle(wxIdleEvent
& event
)
407 static bool inOnIdle
= FALSE
;
409 // Avoid recursion (via ProcessEvent default case)
415 // 'Garbage' collection of windows deleted with Close().
416 DeletePendingObjects();
419 // Flush pending events.
420 ProcessPendingEvents();
423 // flush the logged messages if any
424 wxLog
*pLog
= wxLog::GetActiveTarget();
425 if ( pLog
!= NULL
&& pLog
->HasPendingMessages() )
428 // Send OnIdle events to all windows
429 bool needMore
= SendIdleEvents();
432 event
.RequestMore(TRUE
);
437 // Send idle event to all top-level windows
438 bool wxApp::SendIdleEvents()
440 bool needMore
= FALSE
;
442 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
445 wxWindow
* win
= node
->GetData();
446 if (SendIdleEvents(win
))
448 node
= node
->GetNext();
454 // Send idle event to window and all subwindows
455 bool wxApp::SendIdleEvents(wxWindow
* win
)
457 bool needMore
= FALSE
;
460 event
.SetEventObject(win
);
461 win
->ProcessEvent(event
);
463 if (event
.MoreRequested())
466 wxNode
* node
= win
->GetChildren().First();
469 wxWindow
* win
= (wxWindow
*) node
->Data();
470 if (SendIdleEvents(win
))
478 void wxApp::DeletePendingObjects()
480 wxNode
*node
= wxPendingDelete
.First();
483 wxObject
*obj
= (wxObject
*)node
->Data();
487 if (wxPendingDelete
.Member(obj
))
490 // Deleting one object may have deleted other pending
491 // objects, so start from beginning of list again.
492 node
= wxPendingDelete
.First();
497 void wxApp::ProcessPendingEvents()
499 wxNode
*node
= wxPendingEvents
.First();
500 wxCriticalSectionLocker
locker(wxPendingEventsLocker
);
504 wxEvtHandler
*handler
= (wxEvtHandler
*)node
->Data();
506 handler
->ProcessPendingEvents();
509 node
= wxPendingEvents
.First();
512 #endif // wxUSE_THREADS
514 wxLog
* wxApp::CreateLogTarget()
519 wxWindow
* wxApp::GetTopWindow() const
523 else if (wxTopLevelWindows
.GetCount() > 0)
524 return wxTopLevelWindows
.GetFirst()->GetData();
529 // Create an application context
530 bool wxApp::OnInitGui()
532 XtToolkitInitialize() ;
533 wxTheApp
->m_appContext
= (WXAppContext
) XtCreateApplicationContext() ;
534 Display
*dpy
= XtOpenDisplay((XtAppContext
) wxTheApp
->m_appContext
,(String
)NULL
,NULL
,
535 (const char*) wxTheApp
->GetClassName(), NULL
, 0,
536 # if XtSpecificationRelease < 5
544 wxString
className(wxTheApp
->GetClassName());
545 wxLogError(_("wxWindows could not open display for '%s': exiting."),
546 (const char*) className
);
549 m_initialDisplay
= (WXDisplay
*) dpy
;
551 wxTheApp
->m_topLevelWidget
= (WXWidget
) XtAppCreateShell((String
)NULL
, (const char*) wxTheApp
->GetClassName(),
552 applicationShellWidgetClass
,dpy
,
555 // Add general resize proc
557 rec
.string
= "resize";
558 rec
.proc
= (XtActionProc
)wxWidgetResizeProc
;
559 XtAppAddActions((XtAppContext
) wxTheApp
->m_appContext
, &rec
, 1);
561 GetMainColormap(dpy
);
562 m_maxRequestSize
= XMaxRequestSize((Display
*) dpy
);
567 WXColormap
wxApp::GetMainColormap(WXDisplay
* display
)
569 if (!display
) /* Must be called first with non-NULL display */
570 return m_mainColormap
;
572 int defaultScreen
= DefaultScreen((Display
*) display
);
573 Screen
* screen
= XScreenOfDisplay((Display
*) display
, defaultScreen
);
575 Colormap c
= DefaultColormapOfScreen(screen
);
578 m_mainColormap
= (WXColormap
) c
;
580 return (WXColormap
) c
;
583 // Returns TRUE if an accelerator has been processed
584 bool wxApp::CheckForAccelerator(WXEvent
* event
)
586 XEvent
* xEvent
= (XEvent
*) event
;
587 if (xEvent
->xany
.type
== KeyPress
)
589 // Find a wxWindow for this window
590 // TODO: should get display for the window, not the current display
591 Widget widget
= XtWindowToWidget((Display
*) wxGetDisplay(), xEvent
->xany
.window
);
592 wxWindow
* win
= NULL
;
594 // Find the first wxWindow that corresponds to this event window
595 while (widget
&& !(win
= wxGetWindowFromTable(widget
)))
596 widget
= XtParent(widget
);
601 wxKeyEvent
keyEvent(wxEVT_CHAR
);
602 wxTranslateKeyEvent(keyEvent
, win
, (Widget
) 0, xEvent
);
604 // Now we have a wxKeyEvent and we have a wxWindow.
605 // Go up the hierarchy until we find a matching accelerator,
606 // or we get to the top.
609 if (win
->ProcessAccelerator(keyEvent
))
611 win
= win
->GetParent();
622 retValue
= wxTheApp
->OnExit();
626 * Exit in some platform-specific way. Not recommended that the app calls this:
627 * only for emergencies.
632 // Yield to other processes
635 while (wxTheApp
&& wxTheApp
->Pending())
636 wxTheApp
->Dispatch();
638 // VZ: is it the same as this (taken from old wxExecute)?
640 XtAppProcessEvent((XtAppContext
) wxTheApp
->GetAppContext(), XtIMAll
);