]> git.saurik.com Git - wxWidgets.git/blob - src/x11/app.cpp
* SPACE -> TAB in filelist.txt
[wxWidgets.git] / src / x11 / 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 #include "wx/log.h"
32 #include "wx/intl.h"
33
34 #if wxUSE_THREADS
35 #include "wx/thread.h"
36 #endif
37
38 #if wxUSE_WX_RESOURCES
39 #include "wx/resource.h"
40 #endif
41
42 #ifdef __VMS__
43 #pragma message disable nosimpint
44 #endif
45 #include <X11/Xlib.h>
46 #include <X11/Xutil.h>
47 #include <X11/Xresource.h>
48 #include <X11/Xatom.h>
49 #ifdef __VMS__
50 #pragma message enable nosimpint
51 #endif
52
53 #include "wx/x11/private.h"
54
55 #include <string.h>
56
57 extern char *wxBuffer;
58 extern wxList wxPendingDelete;
59
60 wxApp *wxTheApp = NULL;
61
62 wxHashTable *wxWidgetHashTable = NULL;
63
64 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
65
66 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
67 EVT_IDLE(wxApp::OnIdle)
68 END_EVENT_TABLE()
69
70 #ifdef __WXDEBUG__
71 typedef int (*XErrorHandlerFunc)(Display *, XErrorEvent *);
72
73 XErrorHandlerFunc gs_pfnXErrorHandler = 0;
74
75 static int wxXErrorHandler(Display *dpy, XErrorEvent *xevent)
76 {
77 // just forward to the default handler for now
78 return gs_pfnXErrorHandler(dpy, xevent);
79 }
80 #endif // __WXDEBUG__
81
82 long wxApp::sm_lastMessageTime = 0;
83
84 bool wxApp::Initialize()
85 {
86 wxBuffer = new char[BUFSIZ + 512];
87
88 wxClassInfo::InitializeClasses();
89
90 // GL: I'm annoyed ... I don't know where to put this and I don't want to
91 // create a module for that as it's part of the core.
92 #if wxUSE_THREADS
93 wxPendingEventsLocker = new wxCriticalSection();
94 #endif
95
96 wxTheColourDatabase = new wxColourDatabase(wxKEY_STRING);
97 wxTheColourDatabase->Initialize();
98
99 wxInitializeStockLists();
100 wxInitializeStockObjects();
101
102 #if wxUSE_WX_RESOURCES
103 wxInitializeResourceSystem();
104 #endif
105
106 wxBitmap::InitStandardHandlers();
107
108 wxWidgetHashTable = new wxHashTable(wxKEY_INTEGER);
109
110 wxModule::RegisterModules();
111 if (!wxModule::InitializeModules()) return FALSE;
112
113 return TRUE;
114 }
115
116 void wxApp::CleanUp()
117 {
118 delete wxWidgetHashTable;
119 wxWidgetHashTable = NULL;
120
121 wxModule::CleanUpModules();
122
123 #if wxUSE_WX_RESOURCES
124 wxCleanUpResourceSystem();
125 #endif
126
127 wxDeleteStockObjects() ;
128
129 // Destroy all GDI lists, etc.
130
131 wxDeleteStockLists();
132
133 delete wxTheColourDatabase;
134 wxTheColourDatabase = NULL;
135
136 wxBitmap::CleanUpHandlers();
137
138 delete[] wxBuffer;
139 wxBuffer = NULL;
140
141 wxClassInfo::CleanUpClasses();
142
143 delete wxTheApp;
144 wxTheApp = NULL;
145
146 // GL: I'm annoyed ... I don't know where to put this and I don't want to
147 // create a module for that as it's part of the core.
148 #if wxUSE_THREADS
149 delete wxPendingEvents;
150 delete wxPendingEventsLocker;
151 #endif
152
153 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
154 // At this point we want to check if there are any memory
155 // blocks that aren't part of the wxDebugContext itself,
156 // as a special case. Then when dumping we need to ignore
157 // wxDebugContext, too.
158 if (wxDebugContext::CountObjectsLeft(TRUE) > 0)
159 {
160 wxLogDebug("There were memory leaks.\n");
161 wxDebugContext::Dump();
162 wxDebugContext::PrintStatistics();
163 }
164 #endif
165
166 // do it as the very last thing because everything else can log messages
167 wxLog::DontCreateOnDemand();
168 // do it as the very last thing because everything else can log messages
169 delete wxLog::SetActiveTarget(NULL);
170 }
171
172 int wxEntry( int argc, char *argv[] )
173 {
174 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
175 // This seems to be necessary since there are 'rogue'
176 // objects present at this point (perhaps global objects?)
177 // Setting a checkpoint will ignore them as far as the
178 // memory checking facility is concerned.
179 // Of course you may argue that memory allocated in globals should be
180 // checked, but this is a reasonable compromise.
181 wxDebugContext::SetCheckpoint();
182 #endif
183
184 if (!wxApp::Initialize())
185 return FALSE;
186
187 if (!wxTheApp)
188 {
189 if (!wxApp::GetInitializerFunction())
190 {
191 printf( "wxWindows error: No initializer - use IMPLEMENT_APP macro.\n" );
192 return 0;
193 };
194
195 wxTheApp = (wxApp*) (* wxApp::GetInitializerFunction()) ();
196 };
197
198 if (!wxTheApp)
199 {
200 printf( "wxWindows error: wxTheApp == NULL\n" );
201 return 0;
202 };
203
204 wxTheApp->SetClassName(wxFileNameFromPath(argv[0]));
205 wxTheApp->SetAppName(wxFileNameFromPath(argv[0]));
206
207 wxTheApp->argc = argc;
208 wxTheApp->argv = argv;
209
210 // GUI-specific initialization, such as creating an app context.
211 wxTheApp->OnInitGui();
212
213 // Here frames insert themselves automatically into wxTopLevelWindows by
214 // getting created in OnInit().
215
216 int retValue = 0;
217 if (wxTheApp->OnInit())
218 {
219 if (wxTheApp->Initialized()) retValue = wxTheApp->OnRun();
220 }
221
222 // flush the logged messages if any
223 wxLog *pLog = wxLog::GetActiveTarget();
224 if ( pLog != NULL && pLog->HasPendingMessages() )
225 pLog->Flush();
226
227 delete wxLog::SetActiveTarget(new wxLogStderr); // So dialog boxes aren't used
228 // for further messages
229
230 if (wxTheApp->GetTopWindow())
231 {
232 delete wxTheApp->GetTopWindow();
233 wxTheApp->SetTopWindow(NULL);
234 }
235
236 wxTheApp->DeletePendingObjects();
237
238 wxTheApp->OnExit();
239
240 wxApp::CleanUp();
241
242 return retValue;
243 };
244
245 // Static member initialization
246 wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL;
247
248 wxApp::wxApp()
249 {
250 m_topWindow = NULL;
251 wxTheApp = this;
252 m_className = "";
253 m_wantDebugOutput = TRUE ;
254 m_appName = "";
255 argc = 0;
256 argv = NULL;
257 m_exitOnFrameDelete = TRUE;
258 m_mainColormap = (WXColormap) NULL;
259 m_topLevelWidget = (WXWindow) NULL;
260 m_maxRequestSize = 0;
261 m_initialDisplay = (WXDisplay*) 0;
262 }
263
264 bool wxApp::Initialized()
265 {
266 if (GetTopWindow())
267 return TRUE;
268 else
269 return FALSE;
270 }
271
272 int wxApp::MainLoop()
273 {
274 m_keepGoing = TRUE;
275
276 /*
277 * Sit around forever waiting to process X-events. Property Change
278 * event are handled special, because they have to refer to
279 * the root window rather than to a widget. therefore we can't
280 * use an Xt-eventhandler.
281 */
282
283 XSelectInput(wxGetDisplay(),
284 XDefaultRootWindow(wxGetDisplay()),
285 PropertyChangeMask);
286
287 XEvent event;
288
289 // Use this flag to allow breaking the loop via wxApp::ExitMainLoop()
290 while (m_keepGoing)
291 {
292 XNextEvent(wxGetDisplay(), & event);
293
294 ProcessXEvent((WXEvent*) & event);
295
296 if (XtPending(wxGetDisplay()) == 0)
297 {
298 if (!ProcessIdle())
299 {
300 #if wxUSE_THREADS
301 // leave the main loop to give other threads a chance to
302 // perform their GUI work
303 wxMutexGuiLeave();
304 wxUsleep(20);
305 wxMutexGuiEnter();
306 #endif
307 }
308 }
309
310 }
311
312 return 0;
313 }
314
315 // Processes an X event.
316 void wxApp::ProcessXEvent(WXEvent* _event)
317 {
318 XEvent* event = (XEvent*) _event;
319
320 if (event->type == KeyPress)
321 {
322 if (CheckForAccelerator(_event))
323 {
324 // Do nothing! We intercepted and processed the event as an
325 // accelerator.
326 return;
327 }
328 #if 1
329 // It seemed before that this hack was redundant and
330 // key down events were being generated by wxCanvasInputEvent.
331 // But no longer - why ???
332 //
333 else if (CheckForKeyDown(_event))
334 {
335 // We intercepted and processed the key down event
336 return;
337 }
338 #endif
339 else
340 {
341 // TODO for X11 implementation -- the equivalent of XtDispatchEvent.
342 // Presumably, we need to form the wxEvents and
343 // and send them to the appropriate windows.
344 // XtDispatchEvent(event);
345 return;
346 }
347 }
348 else if (event->type == KeyRelease)
349 {
350 // TODO: work out why we still need this ! -michael
351 //
352 if (CheckForKeyUp(_event))
353 {
354 // We intercepted and processed the key up event
355 return;
356 }
357 else
358 {
359 // TODO: The X equivalent of XtDispatchEvent
360 // (see above)
361 // XtDispatchEvent(event);
362 return;
363 }
364 }
365 else if (event->type == PropertyNotify)
366 {
367 HandlePropertyChange(_event);
368 return;
369 }
370 else if (event->type == ResizeRequest)
371 {
372 /* Terry Gitnick <terryg@scientech.com> - 1/21/98
373 * If resize event, don't resize until the last resize event for this
374 * window is recieved. Prevents flicker as windows are resized.
375 */
376
377 Display *disp = wxGetDisplay();
378 Window win = event->xany.window;
379 XEvent report;
380
381 // to avoid flicker
382 report = * event;
383 while( XCheckTypedWindowEvent (disp, win, ResizeRequest, &report));
384
385 // TODO: when implementing refresh optimization, we can use
386 // XtAddExposureToRegion to expand the window's paint region.
387
388 // TODO: generate resize event
389 // XtDispatchEvent(event);
390 }
391 else
392 {
393 // TODO: generate all other events
394 // XtDispatchEvent(event);
395 }
396 }
397
398 // Returns TRUE if more time is needed.
399 bool wxApp::ProcessIdle()
400 {
401 wxIdleEvent event;
402 event.SetEventObject(this);
403 ProcessEvent(event);
404
405 return event.MoreRequested();
406 }
407
408 void wxApp::ExitMainLoop()
409 {
410 m_keepGoing = FALSE;
411 }
412
413 // Is a message/event pending?
414 bool wxApp::Pending()
415 {
416 XFlush(wxGetDisplay());
417
418 return (XPending(wxGetDisplay()) > 0);
419 }
420
421 // Dispatch a message.
422 void wxApp::Dispatch()
423 {
424 XEvent event;
425 XNextEvent(wxGetDisplay(), & event);
426 ProcessXEvent((WXEvent*) & event);
427 }
428
429 // This should be redefined in a derived class for
430 // handling property change events for XAtom IPC.
431 void wxApp::HandlePropertyChange(WXEvent *event)
432 {
433 // by default do nothing special
434 // TODO: what to do for X11
435 // XtDispatchEvent((XEvent*) event); /* let Motif do the work */
436 }
437
438 void wxApp::OnIdle(wxIdleEvent& event)
439 {
440 static bool inOnIdle = FALSE;
441
442 // Avoid recursion (via ProcessEvent default case)
443 if (inOnIdle)
444 return;
445
446 inOnIdle = TRUE;
447
448 // If there are pending events, we must process them: pending events
449 // are either events to the threads other than main or events posted
450 // with wxPostEvent() functions
451 // GRG: I have moved this here so that all pending events are processed
452 // before starting to delete any objects. This behaves better (in
453 // particular, wrt wxPostEvent) and is coherent with wxGTK's current
454 // behaviour. Also removed the '#if wxUSE_THREADS' around it.
455 // Changed Mar/2000 before 2.1.14
456
457 // Flush pending events.
458 ProcessPendingEvents();
459
460 // 'Garbage' collection of windows deleted with Close().
461 DeletePendingObjects();
462
463 // flush the logged messages if any
464 wxLog *pLog = wxLog::GetActiveTarget();
465 if ( pLog != NULL && pLog->HasPendingMessages() )
466 pLog->Flush();
467
468 // Send OnIdle events to all windows
469 bool needMore = SendIdleEvents();
470
471 if (needMore)
472 event.RequestMore(TRUE);
473
474 inOnIdle = FALSE;
475 }
476
477 void wxWakeUpIdle()
478 {
479 // **** please implement me! ****
480 // Wake up the idle handler processor, even if it is in another thread...
481 }
482
483
484 // Send idle event to all top-level windows
485 bool wxApp::SendIdleEvents()
486 {
487 bool needMore = FALSE;
488
489 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
490 while (node)
491 {
492 wxWindow* win = node->GetData();
493 if (SendIdleEvents(win))
494 needMore = TRUE;
495 node = node->GetNext();
496 }
497
498 return needMore;
499 }
500
501 // Send idle event to window and all subwindows
502 bool wxApp::SendIdleEvents(wxWindow* win)
503 {
504 bool needMore = FALSE;
505
506 wxIdleEvent event;
507 event.SetEventObject(win);
508 win->ProcessEvent(event);
509
510 if (event.MoreRequested())
511 needMore = TRUE;
512
513 wxNode* node = win->GetChildren().First();
514 while (node)
515 {
516 wxWindow* win = (wxWindow*) node->Data();
517 if (SendIdleEvents(win))
518 needMore = TRUE;
519
520 node = node->Next();
521 }
522 return needMore ;
523 }
524
525 void wxApp::DeletePendingObjects()
526 {
527 wxNode *node = wxPendingDelete.First();
528 while (node)
529 {
530 wxObject *obj = (wxObject *)node->Data();
531
532 delete obj;
533
534 if (wxPendingDelete.Member(obj))
535 delete node;
536
537 // Deleting one object may have deleted other pending
538 // objects, so start from beginning of list again.
539 node = wxPendingDelete.First();
540 }
541 }
542
543 // Create an application context
544 bool wxApp::OnInitGui()
545 {
546 // TODO: parse argv and get display to pass to XOpenDisplay
547 Display* dpy = XOpenDisplay(NULL);
548 m_initialDisplay = (WXDisplay*) dpy;
549
550 if (!dpy) {
551 wxString className(wxTheApp->GetClassName());
552 wxLogError(_("wxWindows could not open display for '%s': exiting."),
553 (const char*) className);
554 exit(-1);
555 }
556
557 #ifdef __WXDEBUG__
558 // install the X error handler
559 gs_pfnXErrorHandler = XSetErrorHandler(wxXErrorHandler);
560 #endif // __WXDEBUG__
561
562 // Do we need to create the top-level window initially?
563 #if 0
564 wxTheApp->m_topLevelWidget = (WXWidget) XtAppCreateShell((String)NULL, (const char*) wxTheApp->GetClassName(),
565 applicationShellWidgetClass,dpy,
566 NULL,0) ;
567 #endif
568
569 GetMainColormap(dpy);
570 m_maxRequestSize = XMaxRequestSize((Display*) dpy);
571
572 return TRUE;
573 }
574
575 WXColormap wxApp::GetMainColormap(WXDisplay* display)
576 {
577 if (!display) /* Must be called first with non-NULL display */
578 return m_mainColormap;
579
580 int defaultScreen = DefaultScreen((Display*) display);
581 Screen* screen = XScreenOfDisplay((Display*) display, defaultScreen);
582
583 Colormap c = DefaultColormapOfScreen(screen);
584
585 if (!m_mainColormap)
586 m_mainColormap = (WXColormap) c;
587
588 return (WXColormap) c;
589 }
590
591 static Window XGetParent(Window window)
592 {
593 Window parent, root = 0;
594 unsigned int noChildren = 0;
595 if (XQueryTree(wxGetDisplay(), window, & root, & parent,
596 NULL, & noChildren))
597 return parent;
598 else
599 return (Window) 0;
600 }
601
602 // Returns TRUE if an accelerator has been processed
603 bool wxApp::CheckForAccelerator(WXEvent* event)
604 {
605 XEvent* xEvent = (XEvent*) event;
606 if (xEvent->xany.type == KeyPress)
607 {
608 // Find a wxWindow for this window
609 // TODO: should get display for the window, not the current display
610 Window window = xEvent->xany.window;
611 wxWindow* win = NULL;
612
613 // Find the first wxWindow that corresponds to this event window
614 while (window && !(win = wxGetWindowFromTable(window)))
615 window = XGetParent(window);
616
617 if (!window || !win)
618 return FALSE;
619
620 wxKeyEvent keyEvent(wxEVT_CHAR);
621 wxTranslateKeyEvent(keyEvent, win, (Window) 0, xEvent);
622
623 // Now we have a wxKeyEvent and we have a wxWindow.
624 // Go up the hierarchy until we find a matching accelerator,
625 // or we get to the top.
626 while (win)
627 {
628 if (win->ProcessAccelerator(keyEvent))
629 return TRUE;
630 win = win->GetParent();
631 }
632 return FALSE;
633 }
634 return FALSE;
635 }
636
637 bool wxApp::CheckForKeyDown(WXEvent* event)
638 {
639 XEvent* xEvent = (XEvent*) event;
640 if (xEvent->xany.type == KeyPress)
641 {
642 Window window = xEvent->xany.window;
643 wxWindow* win = NULL;
644
645 // Find the first wxWindow that corresponds to this event window
646 while (window && !(win = wxGetWindowFromTable(window)))
647 window = XGetParent(window);
648
649 if (!window || !win)
650 return FALSE;
651
652 wxKeyEvent keyEvent(wxEVT_KEY_DOWN);
653 wxTranslateKeyEvent(keyEvent, win, (Window) 0, xEvent);
654
655 return win->ProcessEvent( keyEvent );
656 }
657
658 return FALSE;
659 }
660
661 bool wxApp::CheckForKeyUp(WXEvent* event)
662 {
663 XEvent* xEvent = (XEvent*) event;
664 if (xEvent->xany.type == KeyRelease)
665 {
666 Window window = xEvent->xany.window;
667 wxWindow* win = NULL;
668
669 // Find the first wxWindow that corresponds to this event window
670 while (window && !(win = wxGetWindowFromTable(window)))
671 window = XGetParent(window);
672
673 if (!window || !win)
674 return FALSE;
675
676 wxKeyEvent keyEvent(wxEVT_KEY_UP);
677 wxTranslateKeyEvent(keyEvent, win, (Window) 0, xEvent);
678
679 return win->ProcessEvent( keyEvent );
680 }
681
682 return FALSE;
683 }
684
685 void wxExit()
686 {
687 int retValue = 0;
688 if (wxTheApp)
689 retValue = wxTheApp->OnExit();
690
691 wxApp::CleanUp();
692 /*
693 * Exit in some platform-specific way. Not recommended that the app calls this:
694 * only for emergencies.
695 */
696 exit(retValue);
697 }
698
699 // Yield to other processes
700
701 bool wxApp::Yield(bool onlyIfNeeded)
702 {
703 bool s_inYield = FALSE;
704
705 if ( s_inYield )
706 {
707 if ( !onlyIfNeeded )
708 {
709 wxFAIL_MSG( wxT("wxYield called recursively" ) );
710 }
711
712 return FALSE;
713 }
714
715 s_inYield = TRUE;
716
717 while (wxTheApp && wxTheApp->Pending())
718 wxTheApp->Dispatch();
719
720 s_inYield = FALSE;
721
722 return TRUE;
723 }
724
725 // TODO use XmGetPixmap (?) to get the really standard icons!
726
727 // XPM hack: make the arrays const
728 #define static static const
729
730 #include "wx/generic/info.xpm"
731 #include "wx/generic/error.xpm"
732 #include "wx/generic/question.xpm"
733 #include "wx/generic/warning.xpm"
734
735 #undef static
736
737 wxIcon
738 wxApp::GetStdIcon(int which) const
739 {
740 switch(which)
741 {
742 case wxICON_INFORMATION:
743 return wxIcon(info_xpm);
744
745 case wxICON_QUESTION:
746 return wxIcon(question_xpm);
747
748 case wxICON_EXCLAMATION:
749 return wxIcon(warning_xpm);
750
751 default:
752 wxFAIL_MSG("requested non existent standard icon");
753 // still fall through
754
755 case wxICON_HAND:
756 return wxIcon(error_xpm);
757 }
758 }
759
760 // ----------------------------------------------------------------------------
761 // accessors for C modules
762 // ----------------------------------------------------------------------------
763
764 #if 0
765 extern "C" XtAppContext wxGetAppContext()
766 {
767 return (XtAppContext)wxTheApp->GetAppContext();
768 }
769 #endif