]> git.saurik.com Git - wxWidgets.git/blob - src/motif/app.cpp
extracted common initialization/cleanup functions in common/init.cpp; standardized...
[wxWidgets.git] / src / motif / app.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: app.cpp
3 // Purpose: wxApp
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 17/09/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "app.h"
14 #endif
15
16 #ifdef __VMS
17 #define XtParent XTPARENT
18 #define XtDisplay XTDISPLAY
19 #endif
20
21 #include "wx/app.h"
22 #include "wx/utils.h"
23 #include "wx/module.h"
24 #include "wx/memory.h"
25 #include "wx/log.h"
26 #include "wx/intl.h"
27 #include "wx/evtloop.h"
28 #include "wx/hash.h"
29 #include "wx/hashmap.h"
30
31 #if wxUSE_THREADS
32 #include "wx/thread.h"
33 #endif
34
35 #ifdef __VMS__
36 #pragma message disable nosimpint
37 #endif
38 #include <Xm/Xm.h>
39 #include <X11/Xlib.h>
40 #include <X11/Xutil.h>
41 #include <X11/Xresource.h>
42 #include <X11/Xatom.h>
43 #ifdef __VMS__
44 #pragma message enable nosimpint
45 #endif
46
47 #include "wx/motif/private.h"
48
49 #include <string.h>
50
51 struct wxPerDisplayData
52 {
53 wxPerDisplayData()
54 { m_visualInfo = NULL; m_topLevelWidget = NULL; }
55
56 wxXVisualInfo* m_visualInfo;
57 Widget m_topLevelWidget;
58 };
59
60 WX_DECLARE_VOIDPTR_HASH_MAP( wxPerDisplayData, wxPerDisplayDataMap );
61
62 static void wxTLWidgetDestroyCallback(Widget w, XtPointer clientData,
63 XtPointer ptr);
64 static WXWidget wxCreateTopLevelWidget( WXDisplay* display );
65
66 extern wxList wxPendingDelete;
67 extern bool wxAddIdleCallback();
68
69 wxHashTable *wxWidgetHashTable = NULL;
70
71 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
72
73 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
74 EVT_IDLE(wxApp::OnIdle)
75 END_EVENT_TABLE()
76
77 #ifdef __WXDEBUG__
78 typedef int (*XErrorHandlerFunc)(Display *, XErrorEvent *);
79
80 XErrorHandlerFunc gs_pfnXErrorHandler = 0;
81
82 static int wxXErrorHandler(Display *dpy, XErrorEvent *xevent)
83 {
84 // just forward to the default handler for now
85 return gs_pfnXErrorHandler(dpy, xevent);
86 }
87 #endif // __WXDEBUG__
88
89 bool wxApp::Initialize(int argc, wxChar **argv)
90 {
91 if ( !wxAppBase::Initialize(argc, argv) )
92 return false;
93
94 wxWidgetHashTable = new wxHashTable(wxKEY_INTEGER);
95
96 return true;
97 }
98
99 void wxApp::CleanUp()
100 {
101 delete wxWidgetHashTable;
102 wxWidgetHashTable = NULL;
103
104 wxAppBase::CleanUp();
105 }
106
107 void wxApp::Exit()
108 {
109 wxApp::CleanUp();
110
111 wxAppConsole::Exit();
112 }
113
114 // ============================================================================
115 // wxEntry*
116 // ============================================================================
117
118 int wxEntryStart( int argc, char* argv[] )
119 {
120 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
121 // This seems to be necessary since there are 'rogue'
122 // objects present at this point (perhaps global objects?)
123 // Setting a checkpoint will ignore them as far as the
124 // memory checking facility is concerned.
125 // Of course you may argue that memory allocated in globals should be
126 // checked, but this is a reasonable compromise.
127 wxDebugContext::SetCheckpoint();
128 #endif
129
130 if (!wxApp::Initialize())
131 return -1;
132
133 return 0;
134 }
135
136 int wxEntryInitGui()
137 {
138 int retValue = 0;
139
140 // GUI-specific initialization, such as creating an app context.
141 if (!wxTheApp->OnInitGui())
142 retValue = -1;
143
144 return retValue;
145 }
146
147 void wxEntryCleanup()
148 {
149 // So dialog boxes aren't used for further messages
150 delete wxLog::SetActiveTarget(new wxLogStderr);
151
152 // flush the logged messages if any
153 wxLog *pLog = wxLog::GetActiveTarget();
154 if ( pLog != NULL && pLog->HasPendingMessages() )
155 pLog->Flush();
156
157 wxApp::CleanUp();
158 }
159
160 int wxEntry( int argc, char *argv[] )
161 {
162 int retValue = 0;
163
164 retValue = wxEntryStart( argc, argv );
165 if (retValue) return retValue;
166
167 if (!wxTheApp)
168 {
169 if (!wxApp::GetInitializerFunction())
170 {
171 printf( "wxWindows error: No initializer - use IMPLEMENT_APP macro.\n" );
172 return 0;
173 };
174
175 wxTheApp = (wxApp*) (* wxApp::GetInitializerFunction()) ();
176 };
177
178 if (!wxTheApp)
179 {
180 printf( "wxWindows error: wxTheApp == NULL\n" );
181 return 0;
182 };
183
184 wxTheApp->SetClassName(wxFileNameFromPath(argv[0]));
185 wxTheApp->SetAppName(wxFileNameFromPath(argv[0]));
186
187 wxTheApp->argc = argc;
188 wxTheApp->argv = argv;
189
190 // GUI-specific initialization, such as creating an app context.
191 retValue = wxEntryInitGui();
192 if (retValue) return retValue;
193
194 // Here frames insert themselves automatically into wxTopLevelWindows by
195 // getting created in OnInit().
196
197 if (wxTheApp->OnInit())
198 {
199 if (wxTheApp->Initialized())
200 wxTheApp->OnRun();
201 }
202
203 if (wxTheApp->GetTopWindow())
204 {
205 delete wxTheApp->GetTopWindow();
206 wxTheApp->SetTopWindow(NULL);
207 }
208
209 wxTheApp->DeletePendingObjects();
210
211 retValue = wxTheApp->OnExit();
212
213 wxEntryCleanup();
214
215 return retValue;
216 }
217
218 wxApp::wxApp()
219 {
220 argc = 0;
221 argv = NULL;
222
223 m_eventLoop = new wxEventLoop;
224 m_mainColormap = (WXColormap) NULL;
225 m_appContext = (WXAppContext) NULL;
226 m_initialDisplay = (WXDisplay*) 0;
227 m_perDisplayData = new wxPerDisplayDataMap;
228 }
229
230 wxApp::~wxApp()
231 {
232 delete m_eventLoop;
233
234 for( wxPerDisplayDataMap::iterator it = m_perDisplayData->begin(),
235 end = m_perDisplayData->end();
236 it != end; ++it )
237 {
238 delete it->second.m_visualInfo;
239 XtDestroyWidget( it->second.m_topLevelWidget );
240 }
241
242 delete m_perDisplayData;
243
244 wxTheApp = NULL;
245 }
246
247 bool wxApp::Initialized()
248 {
249 if (GetTopWindow())
250 return TRUE;
251 else
252 return FALSE;
253 }
254
255 int wxApp::MainLoop()
256 {
257 /*
258 * Sit around forever waiting to process X-events. Property Change
259 * event are handled special, because they have to refer to
260 * the root window rather than to a widget. therefore we can't
261 * use an Xt-eventhandler.
262 */
263
264 XSelectInput(XtDisplay((Widget) wxTheApp->GetTopLevelWidget()),
265 XDefaultRootWindow(XtDisplay((Widget) wxTheApp->GetTopLevelWidget())),
266 PropertyChangeMask);
267
268 m_eventLoop->Run();
269
270 return 0;
271 }
272
273 // Processes an idle event.
274 // Returns TRUE if more time is needed.
275 bool wxApp::ProcessIdle()
276 {
277 wxIdleEvent event;
278
279 return ProcessEvent(event) && event.MoreRequested();
280 }
281
282 void wxApp::ExitMainLoop()
283 {
284 if( m_eventLoop->IsRunning() )
285 m_eventLoop->Exit();
286 }
287
288 // Is a message/event pending?
289 bool wxApp::Pending()
290 {
291 return m_eventLoop->Pending();
292 #if 0
293 XFlush(XtDisplay( (Widget) wxTheApp->GetTopLevelWidget() ));
294
295 // Fix by Doug from STI, to prevent a stall if non-X event
296 // is found.
297 return ((XtAppPending( (XtAppContext) GetAppContext() ) & XtIMXEvent) != 0) ;
298 #endif
299 }
300
301 // Dispatch a message.
302 void wxApp::Dispatch()
303 {
304 m_eventLoop->Dispatch();
305 }
306
307 // This should be redefined in a derived class for
308 // handling property change events for XAtom IPC.
309 void wxApp::HandlePropertyChange(WXEvent *event)
310 {
311 // by default do nothing special
312 XtDispatchEvent((XEvent*) event); /* let Motif do the work */
313 }
314
315 void wxApp::OnIdle(wxIdleEvent& event)
316 {
317 static bool inOnIdle = FALSE;
318
319 // Avoid recursion (via ProcessEvent default case)
320 if (inOnIdle)
321 return;
322
323 inOnIdle = TRUE;
324
325 // If there are pending events, we must process them: pending events
326 // are either events to the threads other than main or events posted
327 // with wxPostEvent() functions
328 // GRG: I have moved this here so that all pending events are processed
329 // before starting to delete any objects. This behaves better (in
330 // particular, wrt wxPostEvent) and is coherent with wxGTK's current
331 // behaviour. Also removed the '#if wxUSE_THREADS' around it.
332 // Changed Mar/2000 before 2.1.14
333
334 // Flush pending events.
335 ProcessPendingEvents();
336
337 // 'Garbage' collection of windows deleted with Close().
338 DeletePendingObjects();
339
340 // flush the logged messages if any
341 wxLog *pLog = wxLog::GetActiveTarget();
342 if ( pLog != NULL && pLog->HasPendingMessages() )
343 pLog->Flush();
344
345 // Send OnIdle events to all windows
346 bool needMore = SendIdleEvents();
347
348 if (needMore)
349 event.RequestMore(TRUE);
350
351 inOnIdle = FALSE;
352 }
353
354 // Send idle event to all top-level windows
355 bool wxApp::SendIdleEvents()
356 {
357 bool needMore = FALSE;
358
359 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
360 while (node)
361 {
362 wxWindow* win = node->GetData();
363 if (SendIdleEvents(win))
364 needMore = TRUE;
365 node = node->GetNext();
366 }
367
368 return needMore;
369 }
370
371 // Send idle event to window and all subwindows
372 bool wxApp::SendIdleEvents(wxWindow* win)
373 {
374 bool needMore = FALSE;
375
376 wxIdleEvent event;
377 event.SetEventObject(win);
378 win->GetEventHandler()->ProcessEvent(event);
379
380 if (event.MoreRequested())
381 needMore = TRUE;
382
383 wxWindowList::Node* node = win->GetChildren().GetFirst();
384 while (node)
385 {
386 wxWindow* win = node->GetData();
387 if (SendIdleEvents(win))
388 needMore = TRUE;
389
390 node = node->GetNext();
391 }
392 return needMore ;
393 }
394
395 static char *fallbackResources[] = {
396 "*menuBar.marginHeight: 0",
397 "*menuBar.shadowThickness: 1",
398 "*background: #c0c0c0",
399 "*foreground: black",
400 NULL
401 };
402
403 // Create an application context
404 bool wxApp::OnInitGui()
405 {
406 if( !wxAppBase::OnInitGui() )
407 return FALSE;
408
409 XtToolkitInitialize() ;
410 wxTheApp->m_appContext = (WXAppContext) XtCreateApplicationContext();
411 XtAppSetFallbackResources((XtAppContext) wxTheApp->m_appContext, fallbackResources);
412
413 Display *dpy = XtOpenDisplay((XtAppContext) wxTheApp->m_appContext,(String)NULL,NULL,
414 wxTheApp->GetClassName().c_str(), NULL, 0,
415 # if XtSpecificationRelease < 5
416 (Cardinal*) &argc,
417 # else
418 &argc,
419 # endif
420 argv);
421
422 if (!dpy) {
423 // if you don't log to stderr, nothing will be shown...
424 delete wxLog::SetActiveTarget(new wxLogStderr);
425 wxString className(wxTheApp->GetClassName());
426 wxLogError(_("wxWindows could not open display for '%s': exiting."),
427 className.c_str());
428 exit(-1);
429 }
430 m_initialDisplay = (WXDisplay*) dpy;
431
432 #ifdef __WXDEBUG__
433 // install the X error handler
434 gs_pfnXErrorHandler = XSetErrorHandler(wxXErrorHandler);
435 #endif // __WXDEBUG__
436
437 // Add general resize proc
438 XtActionsRec rec;
439 rec.string = "resize";
440 rec.proc = (XtActionProc)wxWidgetResizeProc;
441 XtAppAddActions((XtAppContext) wxTheApp->m_appContext, &rec, 1);
442
443 GetMainColormap(dpy);
444
445 wxAddIdleCallback();
446
447 return TRUE;
448 }
449
450 WXColormap wxApp::GetMainColormap(WXDisplay* display)
451 {
452 if (!display) /* Must be called first with non-NULL display */
453 return m_mainColormap;
454
455 int defaultScreen = DefaultScreen((Display*) display);
456 Screen* screen = XScreenOfDisplay((Display*) display, defaultScreen);
457
458 Colormap c = DefaultColormapOfScreen(screen);
459
460 if (!m_mainColormap)
461 m_mainColormap = (WXColormap) c;
462
463 return (WXColormap) c;
464 }
465
466 wxXVisualInfo* wxApp::GetVisualInfo( WXDisplay* display )
467 {
468 wxPerDisplayDataMap::iterator it = m_perDisplayData->find( display );
469
470 if( it != m_perDisplayData->end() && it->second.m_visualInfo )
471 return it->second.m_visualInfo;
472
473 wxXVisualInfo* vi = new wxXVisualInfo;
474 wxFillXVisualInfo( vi, (Display*)display );
475
476 (*m_perDisplayData)[display].m_visualInfo = vi;
477
478 return vi;
479 }
480
481 static void wxTLWidgetDestroyCallback(Widget w, XtPointer clientData,
482 XtPointer ptr)
483 {
484 if( wxTheApp )
485 wxTheApp->SetTopLevelWidget( (WXDisplay*)XtDisplay(w),
486 (WXWidget)NULL );
487 }
488
489 WXWidget wxCreateTopLevelWidget( WXDisplay* display )
490 {
491 Widget tlw = XtAppCreateShell( (String)NULL,
492 wxTheApp->GetClassName().c_str(),
493 applicationShellWidgetClass,
494 (Display*)display,
495 NULL, 0 );
496 XtSetMappedWhenManaged( tlw, False );
497 XtRealizeWidget( tlw );
498
499 XtAddCallback( tlw, XmNdestroyCallback,
500 (XtCallbackProc)wxTLWidgetDestroyCallback,
501 (XtPointer)NULL );
502
503 return (WXWidget)tlw;
504 }
505
506 WXWidget wxApp::GetTopLevelWidget()
507 {
508 WXDisplay* display = wxGetDisplay();
509 wxPerDisplayDataMap::iterator it = m_perDisplayData->find( display );
510
511 if( it != m_perDisplayData->end() && it->second.m_topLevelWidget )
512 return (WXWidget)it->second.m_topLevelWidget;
513
514 WXWidget tlw = wxCreateTopLevelWidget( display );
515 SetTopLevelWidget( display, tlw );
516
517 return tlw;
518 }
519
520 void wxApp::SetTopLevelWidget(WXDisplay* display, WXWidget widget)
521 {
522 (*m_perDisplayData)[display].m_topLevelWidget = (Widget)widget;
523 }
524
525 // Yield to other processes
526
527 bool wxApp::Yield(bool onlyIfNeeded)
528 {
529 bool s_inYield = FALSE;
530
531 if ( s_inYield )
532 {
533 if ( !onlyIfNeeded )
534 {
535 wxFAIL_MSG( wxT("wxYield called recursively" ) );
536 }
537
538 return FALSE;
539 }
540
541 s_inYield = TRUE;
542
543 while (wxTheApp && wxTheApp->Pending())
544 wxTheApp->Dispatch();
545
546 s_inYield = FALSE;
547
548 return TRUE;
549 }
550
551 // ----------------------------------------------------------------------------
552 // accessors for C modules
553 // ----------------------------------------------------------------------------
554
555 extern "C" XtAppContext wxGetAppContext()
556 {
557 return (XtAppContext)wxTheApp->GetAppContext();
558 }