]> git.saurik.com Git - wxWidgets.git/blob - src/motif/app.cpp
vsprintf() is ANSI so there is normally no need to test for it
[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 #include "wx/frame.h"
17 #include "wx/app.h"
18 #include "wx/utils.h"
19 #include "wx/gdicmn.h"
20 #include "wx/pen.h"
21 #include "wx/brush.h"
22 #include "wx/cursor.h"
23 #include "wx/icon.h"
24 #include "wx/palette.h"
25 #include "wx/dc.h"
26 #include "wx/dialog.h"
27 #include "wx/msgdlg.h"
28 #include "wx/log.h"
29 #include "wx/module.h"
30 #include "wx/memory.h"
31
32 #if wxUSE_WX_RESOURCES
33 #include "wx/resource.h"
34 #endif
35
36 #include <Xm/Xm.h>
37 #include <X11/Xlib.h>
38 #include <X11/Xutil.h>
39 #include <X11/Xresource.h>
40 #include <X11/Xatom.h>
41
42 #include "wx/motif/private.h"
43
44 #include <string.h>
45
46 extern char *wxBuffer;
47 extern wxList wxPendingDelete;
48
49 wxApp *wxTheApp = NULL;
50
51 wxHashTable *wxWidgetHashTable = NULL;
52
53 #if !USE_SHARED_LIBRARY
54 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
55 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
56 EVT_IDLE(wxApp::OnIdle)
57 END_EVENT_TABLE()
58 #endif
59
60 long wxApp::sm_lastMessageTime = 0;
61
62 bool wxApp::Initialize()
63 {
64 #ifdef __WXMSW__
65 wxBuffer = new char[1500];
66 #else
67 wxBuffer = new char[BUFSIZ + 512];
68 #endif
69
70 /* No longer used
71 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
72
73 streambuf* sBuf = new wxDebugStreamBuf;
74 ostream* oStr = new ostream(sBuf) ;
75 wxDebugContext::SetStream(oStr, sBuf);
76
77 #endif
78 */
79
80 wxClassInfo::InitializeClasses();
81
82 wxTheColourDatabase = new wxColourDatabase(wxKEY_STRING);
83 wxTheColourDatabase->Initialize();
84
85 wxInitializeStockLists();
86 wxInitializeStockObjects();
87
88 #if wxUSE_WX_RESOURCES
89 wxInitializeResourceSystem();
90 #endif
91
92 // For PostScript printing
93 #if wxUSE_POSTSCRIPT
94 /* Done using wxModule now
95 wxInitializePrintSetupData();
96 wxThePrintPaperDatabase = new wxPrintPaperDatabase;
97 wxThePrintPaperDatabase->CreateDatabase();
98 */
99 #endif
100
101 wxBitmap::InitStandardHandlers();
102
103 wxWidgetHashTable = new wxHashTable(wxKEY_INTEGER);
104
105 wxModule::RegisterModules();
106 wxASSERT( wxModule::InitializeModules() == TRUE );
107
108 return TRUE;
109 }
110
111 void wxApp::CleanUp()
112 {
113 delete wxWidgetHashTable;
114 wxWidgetHashTable = NULL;
115
116 wxModule::CleanUpModules();
117
118 #if wxUSE_WX_RESOURCES
119 wxCleanUpResourceSystem();
120 #endif
121
122 wxDeleteStockObjects() ;
123
124 // Destroy all GDI lists, etc.
125
126 delete wxTheBrushList;
127 wxTheBrushList = NULL;
128
129 delete wxThePenList;
130 wxThePenList = NULL;
131
132 delete wxTheFontList;
133 wxTheFontList = NULL;
134
135 delete wxTheBitmapList;
136 wxTheBitmapList = NULL;
137
138 delete wxTheColourDatabase;
139 wxTheColourDatabase = NULL;
140
141 #if wxUSE_POSTSCRIPT
142 /* Done using wxModule now
143 wxInitializePrintSetupData(FALSE);
144 delete wxThePrintPaperDatabase;
145 wxThePrintPaperDatabase = NULL;
146 */
147 #endif
148
149 wxBitmap::CleanUpHandlers();
150
151 delete[] wxBuffer;
152 wxBuffer = NULL;
153
154 wxClassInfo::CleanUpClasses();
155
156 delete wxTheApp;
157 wxTheApp = NULL;
158
159 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
160 // At this point we want to check if there are any memory
161 // blocks that aren't part of the wxDebugContext itself,
162 // as a special case. Then when dumping we need to ignore
163 // wxDebugContext, too.
164 if (wxDebugContext::CountObjectsLeft() > 0)
165 {
166 wxLogDebug("There were memory leaks.\n");
167 wxDebugContext::Dump();
168 wxDebugContext::PrintStatistics();
169 }
170 // wxDebugContext::SetStream(NULL, NULL);
171 #endif
172
173 // do it as the very last thing because everything else can log messages
174 wxLog::DontCreateOnDemand();
175 // do it as the very last thing because everything else can log messages
176 delete wxLog::SetActiveTarget(NULL);
177 }
178
179 int wxEntry( int argc, char *argv[] )
180 {
181 if (!wxApp::Initialize())
182 return FALSE;
183 if (!wxTheApp)
184 {
185 if (!wxApp::GetInitializerFunction())
186 {
187 printf( "wxWindows error: No initializer - use IMPLEMENT_APP macro.\n" );
188 return 0;
189 };
190
191 wxTheApp = (wxApp*) (* wxApp::GetInitializerFunction()) ();
192 };
193
194 if (!wxTheApp)
195 {
196 printf( "wxWindows error: wxTheApp == NULL\n" );
197 return 0;
198 };
199
200 wxTheApp->SetClassName(wxFileNameFromPath(argv[0]));
201 wxTheApp->SetAppName(wxFileNameFromPath(argv[0]));
202
203 wxTheApp->argc = argc;
204 wxTheApp->argv = argv;
205
206 // GUI-specific initialization, such as creating an app context.
207 wxTheApp->OnInitGui();
208
209 // Here frames insert themselves automatically
210 // into wxTopLevelWindows by getting created
211 // in OnInit().
212
213 if (!wxTheApp->OnInit()) return 0;
214
215 int retValue = 0;
216
217 if (wxTheApp->Initialized()) retValue = wxTheApp->OnRun();
218
219 // flush the logged messages if any
220 wxLog *pLog = wxLog::GetActiveTarget();
221 if ( pLog != NULL && pLog->HasPendingMessages() )
222 pLog->Flush();
223
224 delete wxLog::SetActiveTarget(new wxLogStderr); // So dialog boxes aren't used
225 // for further messages
226
227 if (wxTheApp->GetTopWindow())
228 {
229 delete wxTheApp->GetTopWindow();
230 wxTheApp->SetTopWindow(NULL);
231 }
232
233 wxTheApp->DeletePendingObjects();
234
235 wxTheApp->OnExit();
236
237
238 wxApp::CleanUp();
239
240 return retValue;
241 };
242
243 // Static member initialization
244 wxAppInitializerFunction wxApp::m_appInitFn = (wxAppInitializerFunction) NULL;
245
246 wxApp::wxApp()
247 {
248 m_topWindow = NULL;
249 wxTheApp = this;
250 m_className = "";
251 m_wantDebugOutput = TRUE ;
252 m_appName = "";
253 argc = 0;
254 argv = NULL;
255 m_printMode = wxPRINT_POSTSCRIPT;
256 m_exitOnFrameDelete = TRUE;
257 m_auto3D = TRUE;
258
259 m_mainColormap = (WXColormap) NULL;
260 m_appContext = (WXAppContext) NULL;
261 m_topLevelWidget = (WXWidget) NULL;
262 m_maxRequestSize = 0;
263 m_initialDisplay = (WXDisplay*) 0;
264 }
265
266 bool wxApp::Initialized()
267 {
268 if (GetTopWindow())
269 return TRUE;
270 else
271 return FALSE;
272 }
273
274 int wxApp::MainLoop()
275 {
276 m_keepGoing = TRUE;
277
278 /*
279 * Sit around forever waiting to process X-events. Property Change
280 * event are handled special, because they have to refer to
281 * the root window rather than to a widget. therefore we can't
282 * use an Xt-eventhandler.
283 */
284
285 XSelectInput(XtDisplay((Widget) wxTheApp->GetTopLevelWidget()),
286 XDefaultRootWindow(XtDisplay((Widget) wxTheApp->GetTopLevelWidget())),
287 PropertyChangeMask);
288
289 XEvent event;
290
291 // Use this flag to allow breaking the loop via wxApp::ExitMainLoop()
292 while (m_keepGoing)
293 {
294 XtAppNextEvent( (XtAppContext) wxTheApp->GetAppContext(), &event);
295
296 ProcessXEvent((WXEvent*) & event);
297 ProcessIdle();
298 }
299
300 return 0;
301 }
302
303 // Processes an X event.
304 void wxApp::ProcessXEvent(WXEvent* _event)
305 {
306 XEvent* event = (XEvent*) _event;
307
308 if ((event->type == KeyPress) && CheckForAccelerator(_event))
309 {
310 // Do nothing! We intercepted and processed the event as an accelerator.
311 return;
312 }
313 else if (event->type == PropertyNotify)
314 {
315 HandlePropertyChange(_event);
316 return;
317 }
318 else if (event->type == ResizeRequest)
319 {
320 /* Terry Gitnick <terryg@scientech.com> - 1/21/98
321 * If resize event, don't resize until the last resize event for this
322 * window is recieved. Prevents flicker as windows are resized.
323 */
324
325 Display *disp = XtDisplay((Widget) wxTheApp->GetTopLevelWidget());
326 Window win = event->xany.window;
327 XEvent report;
328
329 // to avoid flicker
330 report = * event;
331 while( XCheckTypedWindowEvent (disp, win, ResizeRequest, &report));
332
333 // TODO: when implementing refresh optimization, we can use
334 // XtAddExposureToRegion to expand the window's paint region.
335
336 XtDispatchEvent(event);
337 }
338 else
339 {
340 XtDispatchEvent(event);
341 }
342 }
343
344 // Returns TRUE if more time is needed.
345 bool wxApp::ProcessIdle()
346 {
347 wxIdleEvent event;
348 event.SetEventObject(this);
349 ProcessEvent(event);
350
351 return event.MoreRequested();
352 }
353
354 void wxApp::ExitMainLoop()
355 {
356 m_keepGoing = FALSE;
357 }
358
359 // Is a message/event pending?
360 bool wxApp::Pending()
361 {
362 XFlush(XtDisplay( (Widget) wxTheApp->GetTopLevelWidget() ));
363
364 // Fix by Doug from STI, to prevent a stall if non-X event
365 // is found.
366 return ((XtAppPending( (XtAppContext) GetAppContext() ) & XtIMXEvent) != 0) ;
367 }
368
369 // Dispatch a message.
370 void wxApp::Dispatch()
371 {
372 // XtAppProcessEvent( (XtAppContext) wxTheApp->GetAppContext(), XtIMAll);
373
374 XEvent event;
375 XtAppNextEvent((XtAppContext) GetAppContext(), &event);
376 ProcessXEvent((WXEvent*) & event);
377 }
378
379 // This should be redefined in a derived class for
380 // handling property change events for XAtom IPC.
381 void wxApp::HandlePropertyChange(WXEvent *event)
382 {
383 // by default do nothing special
384 XtDispatchEvent((XEvent*) event); /* let Motif do the work */
385 }
386
387 void wxApp::OnIdle(wxIdleEvent& event)
388 {
389 static bool inOnIdle = FALSE;
390
391 // Avoid recursion (via ProcessEvent default case)
392 if (inOnIdle)
393 return;
394
395 inOnIdle = TRUE;
396
397 // 'Garbage' collection of windows deleted with Close().
398 DeletePendingObjects();
399
400 // flush the logged messages if any
401 wxLog *pLog = wxLog::GetActiveTarget();
402 if ( pLog != NULL && pLog->HasPendingMessages() )
403 pLog->Flush();
404
405 // Send OnIdle events to all windows
406 bool needMore = SendIdleEvents();
407
408 if (needMore)
409 event.RequestMore(TRUE);
410
411 inOnIdle = FALSE;
412 }
413
414 // Send idle event to all top-level windows
415 bool wxApp::SendIdleEvents()
416 {
417 bool needMore = FALSE;
418 wxNode* node = wxTopLevelWindows.First();
419 while (node)
420 {
421 wxWindow* win = (wxWindow*) node->Data();
422 if (SendIdleEvents(win))
423 needMore = TRUE;
424
425 node = node->Next();
426 }
427 return needMore;
428 }
429
430 // Send idle event to window and all subwindows
431 bool wxApp::SendIdleEvents(wxWindow* win)
432 {
433 bool needMore = FALSE;
434
435 wxIdleEvent event;
436 event.SetEventObject(win);
437 win->ProcessEvent(event);
438
439 if (event.MoreRequested())
440 needMore = TRUE;
441
442 wxNode* node = win->GetChildren()->First();
443 while (node)
444 {
445 wxWindow* win = (wxWindow*) node->Data();
446 if (SendIdleEvents(win))
447 needMore = TRUE;
448
449 node = node->Next();
450 }
451 return needMore ;
452 }
453
454 void wxApp::DeletePendingObjects()
455 {
456 wxNode *node = wxPendingDelete.First();
457 while (node)
458 {
459 wxObject *obj = (wxObject *)node->Data();
460
461 delete obj;
462
463 if (wxPendingDelete.Member(obj))
464 delete node;
465
466 // Deleting one object may have deleted other pending
467 // objects, so start from beginning of list again.
468 node = wxPendingDelete.First();
469 }
470 }
471
472 wxLog* wxApp::CreateLogTarget()
473 {
474 return new wxLogGui;
475 }
476
477 wxWindow* wxApp::GetTopWindow() const
478 {
479 if (m_topWindow)
480 return m_topWindow;
481 else if (wxTopLevelWindows.Number() > 0)
482 return (wxWindow*) wxTopLevelWindows.First()->Data();
483 else
484 return NULL;
485 }
486
487 // Create an application context
488 bool wxApp::OnInitGui()
489 {
490 XtToolkitInitialize() ;
491 wxTheApp->m_appContext = (WXAppContext) XtCreateApplicationContext() ;
492 Display *dpy = XtOpenDisplay((XtAppContext) wxTheApp->m_appContext,(String)NULL,NULL,
493 (const char*) wxTheApp->GetClassName(), NULL,
494 # if XtSpecificationRelease < 5
495 0,(Cardinal*) &argc,argv) ;
496 # else
497 0,&argc,argv) ;
498 # endif
499 if (!dpy) {
500 cerr << "wxWindows could not open display for " << wxTheApp->GetClassName() << ": exiting.\n";
501 exit(-1);
502 }
503 m_initialDisplay = (WXDisplay*) dpy;
504
505 wxTheApp->m_topLevelWidget = (WXWidget) XtAppCreateShell((String)NULL, (const char*) wxTheApp->GetClassName(),
506 applicationShellWidgetClass,dpy,
507 NULL,0) ;
508
509 // Add general resize proc
510 XtActionsRec rec;
511 rec.string = "resize";
512 rec.proc = (XtActionProc)wxWidgetResizeProc;
513 XtAppAddActions((XtAppContext) wxTheApp->m_appContext, &rec, 1);
514
515 GetMainColormap(dpy);
516 m_maxRequestSize = XMaxRequestSize((Display*) dpy);
517
518 return TRUE;
519 }
520
521 WXColormap wxApp::GetMainColormap(WXDisplay* display)
522 {
523 if (!display) /* Must be called first with non-NULL display */
524 return m_mainColormap;
525
526 Colormap c =
527 DefaultColormapOfScreen(XScreenOfDisplay((Display*) display,
528 DefaultScreen((Display*) display)));
529
530 if (!m_mainColormap)
531 m_mainColormap = (WXColormap) c;
532
533 return (WXColormap) c;
534 }
535
536 // Returns TRUE if an accelerator has been processed
537 bool wxApp::CheckForAccelerator(WXEvent* event)
538 {
539 XEvent* xEvent = (XEvent*) event;
540 if (xEvent->xany.type == KeyPress)
541 {
542 // Find a wxWindow for this window
543 // TODO: should get display for the window, not the current display
544 Widget widget = XtWindowToWidget((Display*) wxGetDisplay(), xEvent->xany.window);
545 wxWindow* win = NULL;
546
547 // Find the first wxWindow that corresponds to this event window
548 while (widget && !(win = wxGetWindowFromTable(widget)))
549 widget = XtParent(widget);
550
551 if (!widget || !win)
552 return FALSE;
553
554 wxKeyEvent keyEvent(wxEVT_CHAR);
555 wxTranslateKeyEvent(keyEvent, win, (Widget) 0, xEvent);
556
557 // Now we have a wxKeyEvent and we have a wxWindow.
558 // Go up the hierarchy until we find a matching accelerator,
559 // or we get to the top.
560 while (win)
561 {
562 if (win->ProcessAccelerator(keyEvent))
563 return TRUE;
564 win = win->GetParent();
565 }
566 return FALSE;
567 }
568 return FALSE;
569 }
570
571 void wxExit()
572 {
573 int retValue = 0;
574 if (wxTheApp)
575 retValue = wxTheApp->OnExit();
576
577 wxApp::CleanUp();
578 /*
579 * Exit in some platform-specific way. Not recommended that the app calls this:
580 * only for emergencies.
581 */
582 exit(retValue);
583 }
584
585 // Yield to other processes
586 bool wxYield()
587 {
588 while (wxTheApp && wxTheApp->Pending())
589 wxTheApp->Dispatch();
590 return TRUE;
591 }
592