removed duplicate wxTheApp and m_appInitFn definitions from all ports, not just MSW
[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/icon.h"
21 #include "wx/dialog.h"
22 #include "wx/log.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/timer.h"
29 #include "wx/filename.h"
30 #include "wx/hash.h"
31
32 #include "wx/univ/theme.h"
33 #include "wx/univ/renderer.h"
34
35 #if wxUSE_THREADS
36 #include "wx/thread.h"
37 #endif
38
39 #include "wx/x11/private.h"
40
41 #include <string.h>
42
43 //------------------------------------------------------------------------
44 // global data
45 //------------------------------------------------------------------------
46
47 extern wxList wxPendingDelete;
48
49 wxHashTable *wxWidgetHashTable = NULL;
50 wxHashTable *wxClientWidgetHashTable = NULL;
51
52 // This is set within wxEntryStart -- too early on
53 // to put these in wxTheApp
54 static bool g_showIconic = FALSE;
55 static wxSize g_initialSize = wxDefaultSize;
56
57 // This is required for wxFocusEvent::SetWindow(). It will only
58 // work for focus events which we provoke ourselves (by calling
59 // SetFocus()). It will not work for those events, which X11
60 // generates itself.
61 static wxWindow *g_nextFocus = NULL;
62 static wxWindow *g_prevFocus = NULL;
63
64 //------------------------------------------------------------------------
65 // X11 error handling
66 //------------------------------------------------------------------------
67
68 #ifdef __WXDEBUG__
69 typedef int (*XErrorHandlerFunc)(Display *, XErrorEvent *);
70
71 XErrorHandlerFunc gs_pfnXErrorHandler = 0;
72
73 static int wxXErrorHandler(Display *dpy, XErrorEvent *xevent)
74 {
75 // just forward to the default handler for now
76 if (gs_pfnXErrorHandler)
77 return gs_pfnXErrorHandler(dpy, xevent);
78 else
79 return 0;
80 }
81 #endif // __WXDEBUG__
82
83 //------------------------------------------------------------------------
84 // wxApp
85 //------------------------------------------------------------------------
86
87 long wxApp::sm_lastMessageTime = 0;
88 WXDisplay *wxApp::ms_display = NULL;
89
90 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
91
92 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
93 EVT_IDLE(wxApp::OnIdle)
94 END_EVENT_TABLE()
95
96 bool wxApp::Initialize()
97 {
98 wxClassInfo::InitializeClasses();
99
100 #if wxUSE_INTL
101 wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
102 #endif
103
104 // GL: I'm annoyed ... I don't know where to put this and I don't want to
105 // create a module for that as it's part of the core.
106 #if wxUSE_THREADS
107 wxPendingEventsLocker = new wxCriticalSection();
108 #endif
109
110 wxTheColourDatabase = new wxColourDatabase(wxKEY_STRING);
111 wxTheColourDatabase->Initialize();
112
113 wxInitializeStockLists();
114 wxInitializeStockObjects();
115
116 wxWidgetHashTable = new wxHashTable(wxKEY_INTEGER);
117 wxClientWidgetHashTable = new wxHashTable(wxKEY_INTEGER);
118
119 wxModule::RegisterModules();
120 if (!wxModule::InitializeModules()) return FALSE;
121
122 return TRUE;
123 }
124
125 void wxApp::CleanUp()
126 {
127 delete wxWidgetHashTable;
128 wxWidgetHashTable = NULL;
129 delete wxClientWidgetHashTable;
130 wxClientWidgetHashTable = NULL;
131
132 wxModule::CleanUpModules();
133
134 delete wxTheColourDatabase;
135 wxTheColourDatabase = NULL;
136
137 wxDeleteStockObjects();
138
139 wxDeleteStockLists();
140
141 delete wxTheApp;
142 wxTheApp = NULL;
143
144 wxClassInfo::CleanUpClasses();
145
146 #if wxUSE_THREADS
147 delete wxPendingEvents;
148 delete wxPendingEventsLocker;
149 #endif
150
151 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
152 // At this point we want to check if there are any memory
153 // blocks that aren't part of the wxDebugContext itself,
154 // as a special case. Then when dumping we need to ignore
155 // wxDebugContext, too.
156 if (wxDebugContext::CountObjectsLeft(TRUE) > 0)
157 {
158 wxLogDebug("There were memory leaks.");
159 wxDebugContext::Dump();
160 wxDebugContext::PrintStatistics();
161 }
162 #endif
163
164 // do it as the very last thing because everything else can log messages
165 wxLog::DontCreateOnDemand();
166 // do it as the very last thing because everything else can log messages
167 delete wxLog::SetActiveTarget(NULL);
168 }
169
170 // NB: argc and argv may be changed here, pass by reference!
171 int wxEntryStart( int& argc, char *argv[] )
172 {
173 #ifdef __WXDEBUG__
174 #if !wxUSE_NANOX
175 // install the X error handler
176 gs_pfnXErrorHandler = XSetErrorHandler( wxXErrorHandler );
177 #endif
178 #endif // __WXDEBUG__
179
180 char *displayName = NULL;
181 bool syncDisplay = FALSE;
182
183 int i;
184 for (i = 0; i < argc; i++)
185 {
186 if (strcmp( argv[i], "-display") == 0)
187 {
188 if (i < (argc - 1))
189 {
190 i ++;
191 displayName = argv[i];
192 continue;
193 }
194 }
195 else if (strcmp( argv[i], "-geometry") == 0)
196 {
197 if (i < (argc - 1))
198 {
199 i ++;
200 int w, h;
201 if (sscanf(argv[i], "%dx%d", &w, &h) != 2)
202 {
203 wxLogError( _("Invalid geometry specification '%s'"), wxString::FromAscii(argv[i]).c_str() );
204 }
205 else
206 {
207 g_initialSize = wxSize(w, h);
208 }
209 continue;
210 }
211 }
212 else if (strcmp( argv[i], "-sync") == 0)
213 {
214 syncDisplay = TRUE;
215 continue;
216 }
217 else if (strcmp( argv[i], "-iconic") == 0)
218 {
219 g_showIconic = TRUE;
220
221 continue;
222 }
223
224 }
225
226 // X11 display stuff
227 Display* xdisplay = XOpenDisplay( displayName );
228 if (!xdisplay)
229 {
230 wxLogError( _("wxWindows could not open display. Exiting.") );
231 return -1;
232 }
233
234 if (syncDisplay)
235 XSynchronize(xdisplay, True);
236
237 wxApp::ms_display = (WXDisplay*) xdisplay;
238
239 XSelectInput( xdisplay, XDefaultRootWindow(xdisplay), PropertyChangeMask);
240
241 // Misc.
242 wxSetDetectableAutoRepeat( TRUE );
243
244 #if wxUSE_UNICODE
245 // Glib's type system required by Pango
246 g_type_init();
247 #endif
248
249 if (!wxApp::Initialize())
250 return -1;
251
252 return 0;
253 }
254
255 int wxEntryInitGui()
256 {
257 int retValue = 0;
258
259 if ( !wxTheApp->OnInitGui() )
260 retValue = -1;
261
262 return retValue;
263 }
264
265
266 int wxEntry( int argc, char *argv[] )
267 {
268 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
269 // This seems to be necessary since there are 'rogue'
270 // objects present at this point (perhaps global objects?)
271 // Setting a checkpoint will ignore them as far as the
272 // memory checking facility is concerned.
273 // Of course you may argue that memory allocated in globals should be
274 // checked, but this is a reasonable compromise.
275 wxDebugContext::SetCheckpoint();
276 #endif
277 int err = wxEntryStart(argc, argv);
278 if (err)
279 return err;
280
281 if (!wxTheApp)
282 {
283 if (!wxApp::GetInitializerFunction())
284 {
285 printf( "wxWindows error: No initializer - use IMPLEMENT_APP macro.\n" );
286 return 0;
287 }
288
289 wxTheApp = (wxApp*) (* wxApp::GetInitializerFunction()) ();
290 }
291
292 if (!wxTheApp)
293 {
294 printf( "wxWindows error: wxTheApp == NULL\n" );
295 return 0;
296 }
297
298 // Command line argument stuff
299 wxTheApp->argc = argc;
300 #if wxUSE_UNICODE
301 wxTheApp->argv = new wxChar*[argc+1];
302 int mb_argc = 0;
303 while (mb_argc < argc)
304 {
305 wxString tmp = wxString::FromAscii( argv[mb_argc] );
306 wxTheApp->argv[mb_argc] = wxStrdup( tmp.c_str() );
307 mb_argc++;
308 }
309 wxTheApp->argv[mb_argc] = (wxChar *)NULL;
310 #else
311 wxTheApp->argv = argv;
312 #endif
313
314 if (wxTheApp->argc > 0)
315 {
316 wxFileName fname( wxTheApp->argv[0] );
317 wxTheApp->SetAppName( fname.GetName() );
318 }
319
320 wxTheApp->m_showIconic = g_showIconic;
321 wxTheApp->m_initialSize = g_initialSize;
322
323 int retValue;
324 retValue = wxEntryInitGui();
325
326 // Here frames insert themselves automatically into wxTopLevelWindows by
327 // getting created in OnInit().
328 if ( retValue == 0 )
329 {
330 if ( !wxTheApp->OnInit() )
331 retValue = -1;
332 }
333
334 if ( retValue == 0 )
335 {
336 if (wxTheApp->Initialized()) retValue = wxTheApp->OnRun();
337 }
338
339 // flush the logged messages if any
340 wxLog *pLog = wxLog::GetActiveTarget();
341 if ( pLog != NULL && pLog->HasPendingMessages() )
342 pLog->Flush();
343
344 delete wxLog::SetActiveTarget(new wxLogStderr); // So dialog boxes aren't used
345 // for further messages
346
347 if (wxTheApp->GetTopWindow())
348 {
349 delete wxTheApp->GetTopWindow();
350 wxTheApp->SetTopWindow(NULL);
351 }
352
353 wxTheApp->DeletePendingObjects();
354
355 wxTheApp->OnExit();
356
357 wxApp::CleanUp();
358
359 return retValue;
360 };
361
362 wxApp::wxApp()
363 {
364 // TODO: parse the command line
365 argc = 0;
366 argv = NULL;
367
368 m_mainColormap = (WXColormap) NULL;
369 m_topLevelWidget = (WXWindow) NULL;
370 m_maxRequestSize = 0;
371 m_mainLoop = NULL;
372 m_showIconic = FALSE;
373 m_initialSize = wxDefaultSize;
374
375 #if !wxUSE_NANOX
376 m_visualInfo = NULL;
377 #endif
378 }
379
380 wxApp::~wxApp()
381 {
382 #if !wxUSE_NANOX
383 delete m_visualInfo;
384 #endif
385 }
386
387 bool wxApp::Initialized()
388 {
389 if (GetTopWindow())
390 return TRUE;
391 else
392 return FALSE;
393 }
394
395 int wxApp::MainLoop()
396 {
397 int rt;
398 m_mainLoop = new wxEventLoop;
399
400 rt = m_mainLoop->Run();
401
402 delete m_mainLoop;
403 m_mainLoop = NULL;
404 return rt;
405 }
406
407 #if !wxUSE_NANOX
408 //-----------------------------------------------------------------------
409 // X11 predicate function for exposure compression
410 //-----------------------------------------------------------------------
411
412 struct wxExposeInfo
413 {
414 Window window;
415 Bool found_non_matching;
416 };
417
418 static Bool expose_predicate (Display *display, XEvent *xevent, XPointer arg)
419 {
420 wxExposeInfo *info = (wxExposeInfo*) arg;
421
422 if (info->found_non_matching)
423 return FALSE;
424
425 if (xevent->xany.type != Expose)
426 {
427 info->found_non_matching = TRUE;
428 return FALSE;
429 }
430
431 if (xevent->xexpose.window != info->window)
432 {
433 info->found_non_matching = TRUE;
434 return FALSE;
435 }
436
437 return TRUE;
438 }
439 #endif
440 // wxUSE_NANOX
441
442 //-----------------------------------------------------------------------
443 // Processes an X event, returning TRUE if the event was processed.
444 //-----------------------------------------------------------------------
445
446 bool wxApp::ProcessXEvent(WXEvent* _event)
447 {
448 XEvent* event = (XEvent*) _event;
449
450 wxWindow* win = NULL;
451 Window window = XEventGetWindow(event);
452 #if 0
453 Window actualWindow = window;
454 #endif
455
456 // Find the first wxWindow that corresponds to this event window
457 // Because we're receiving events after a window
458 // has been destroyed, assume a 1:1 match between
459 // Window and wxWindow, so if it's not in the table,
460 // it must have been destroyed.
461
462 win = wxGetWindowFromTable(window);
463 if (!win)
464 {
465 #if wxUSE_TWO_WINDOWS
466 win = wxGetClientWindowFromTable(window);
467 if (!win)
468 #endif
469 return FALSE;
470 }
471
472 #ifdef __WXDEBUG__
473 wxString windowClass = win->GetClassInfo()->GetClassName();
474 #endif
475
476 switch (event->type)
477 {
478 case Expose:
479 {
480 #if wxUSE_TWO_WINDOWS && !wxUSE_NANOX
481 if (event->xexpose.window != (Window)win->GetClientAreaWindow())
482 {
483 XEvent tmp_event;
484 wxExposeInfo info;
485 info.window = event->xexpose.window;
486 info.found_non_matching = FALSE;
487 while (XCheckIfEvent( wxGlobalDisplay(), &tmp_event, expose_predicate, (XPointer) &info ))
488 {
489 // Don't worry about optimizing redrawing the border etc.
490 }
491 win->NeedUpdateNcAreaInIdle();
492 }
493 else
494 #endif
495 {
496 win->GetUpdateRegion().Union( XExposeEventGetX(event), XExposeEventGetY(event),
497 XExposeEventGetWidth(event), XExposeEventGetHeight(event));
498 win->GetClearRegion().Union( XExposeEventGetX(event), XExposeEventGetY(event),
499 XExposeEventGetWidth(event), XExposeEventGetHeight(event));
500
501 #if !wxUSE_NANOX
502 XEvent tmp_event;
503 wxExposeInfo info;
504 info.window = event->xexpose.window;
505 info.found_non_matching = FALSE;
506 while (XCheckIfEvent( wxGlobalDisplay(), &tmp_event, expose_predicate, (XPointer) &info ))
507 {
508 win->GetUpdateRegion().Union( tmp_event.xexpose.x, tmp_event.xexpose.y,
509 tmp_event.xexpose.width, tmp_event.xexpose.height );
510
511 win->GetClearRegion().Union( tmp_event.xexpose.x, tmp_event.xexpose.y,
512 tmp_event.xexpose.width, tmp_event.xexpose.height );
513 }
514 #endif
515
516 // This simplifies the expose and clear areas to simple
517 // rectangles.
518 win->GetUpdateRegion() = win->GetUpdateRegion().GetBox();
519 win->GetClearRegion() = win->GetClearRegion().GetBox();
520
521 // If we only have one X11 window, always indicate
522 // that borders might have to be redrawn.
523 if (win->GetMainWindow() == win->GetClientAreaWindow())
524 win->NeedUpdateNcAreaInIdle();
525
526 // Only erase background, paint in idle time.
527 win->SendEraseEvents();
528
529 // EXPERIMENT
530 //win->Update();
531 }
532
533 return TRUE;
534 }
535
536 #if !wxUSE_NANOX
537 case GraphicsExpose:
538 {
539 printf( "GraphicExpose event\n" );
540
541 wxLogTrace( _T("expose"), _T("GraphicsExpose from %s"), win->GetName().c_str());
542
543 win->GetUpdateRegion().Union( event->xgraphicsexpose.x, event->xgraphicsexpose.y,
544 event->xgraphicsexpose.width, event->xgraphicsexpose.height);
545
546 win->GetClearRegion().Union( event->xgraphicsexpose.x, event->xgraphicsexpose.y,
547 event->xgraphicsexpose.width, event->xgraphicsexpose.height);
548
549 if (event->xgraphicsexpose.count == 0)
550 {
551 // Only erase background, paint in idle time.
552 win->SendEraseEvents();
553 // win->Update();
554 }
555
556 return TRUE;
557 }
558 #endif
559
560 case KeyPress:
561 {
562 if (!win->IsEnabled())
563 return FALSE;
564
565 wxKeyEvent keyEvent(wxEVT_KEY_DOWN);
566 wxTranslateKeyEvent(keyEvent, win, window, event);
567
568 // wxLogDebug( "OnKey from %s", win->GetName().c_str() );
569
570 // We didn't process wxEVT_KEY_DOWN, so send wxEVT_CHAR
571 if (win->GetEventHandler()->ProcessEvent( keyEvent ))
572 return TRUE;
573
574 keyEvent.SetEventType(wxEVT_CHAR);
575 // Do the translation again, retaining the ASCII
576 // code.
577 wxTranslateKeyEvent(keyEvent, win, window, event, TRUE);
578 if (win->GetEventHandler()->ProcessEvent( keyEvent ))
579 return TRUE;
580
581 if ( (keyEvent.m_keyCode == WXK_TAB) &&
582 win->GetParent() && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
583 {
584 wxNavigationKeyEvent new_event;
585 new_event.SetEventObject( win->GetParent() );
586 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
587 new_event.SetDirection( (keyEvent.m_keyCode == WXK_TAB) );
588 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
589 new_event.SetWindowChange( keyEvent.ControlDown() );
590 new_event.SetCurrentFocus( win );
591 return win->GetParent()->GetEventHandler()->ProcessEvent( new_event );
592 }
593
594 return FALSE;
595 }
596 case KeyRelease:
597 {
598 if (!win->IsEnabled())
599 return FALSE;
600
601 wxKeyEvent keyEvent(wxEVT_KEY_UP);
602 wxTranslateKeyEvent(keyEvent, win, window, event);
603
604 return win->GetEventHandler()->ProcessEvent( keyEvent );
605 }
606 case ConfigureNotify:
607 {
608 #if wxUSE_NANOX
609 if (event->update.utype == GR_UPDATE_SIZE)
610 #endif
611 {
612 if (win->IsTopLevel())
613 {
614 wxTopLevelWindow *tlw = (wxTopLevelWindow*) win;
615 tlw->SetConfigureGeometry( XConfigureEventGetX(event), XConfigureEventGetY(event),
616 XConfigureEventGetWidth(event), XConfigureEventGetHeight(event) );
617 }
618
619 if (win->IsTopLevel() && win->IsShown())
620 {
621 wxTopLevelWindowX11 *tlw = (wxTopLevelWindowX11 *) win;
622 tlw->SetNeedResizeInIdle();
623 }
624 else
625 {
626 wxSizeEvent sizeEvent( wxSize(XConfigureEventGetWidth(event), XConfigureEventGetHeight(event)), win->GetId() );
627 sizeEvent.SetEventObject( win );
628
629 return win->GetEventHandler()->ProcessEvent( sizeEvent );
630 }
631 }
632 return FALSE;
633 break;
634 }
635 #if !wxUSE_NANOX
636 case PropertyNotify:
637 {
638 //wxLogDebug("PropertyNotify: %s", windowClass.c_str());
639 return HandlePropertyChange(_event);
640 }
641 case ClientMessage:
642 {
643 if (!win->IsEnabled())
644 return FALSE;
645
646 Atom wm_delete_window = XInternAtom(wxGlobalDisplay(), "WM_DELETE_WINDOW", True);
647 Atom wm_protocols = XInternAtom(wxGlobalDisplay(), "WM_PROTOCOLS", True);
648
649 if (event->xclient.message_type == wm_protocols)
650 {
651 if ((Atom) (event->xclient.data.l[0]) == wm_delete_window)
652 {
653 win->Close(FALSE);
654 return TRUE;
655 }
656 }
657 return FALSE;
658 }
659 #if 0
660 case DestroyNotify:
661 {
662 printf( "destroy from %s\n", win->GetName().c_str() );
663 break;
664 }
665 case CreateNotify:
666 {
667 printf( "create from %s\n", win->GetName().c_str() );
668 break;
669 }
670 case MapRequest:
671 {
672 printf( "map request from %s\n", win->GetName().c_str() );
673 break;
674 }
675 case ResizeRequest:
676 {
677 printf( "resize request from %s\n", win->GetName().c_str() );
678
679 Display *disp = (Display*) wxGetDisplay();
680 XEvent report;
681
682 // to avoid flicker
683 report = * event;
684 while( XCheckTypedWindowEvent (disp, actualWindow, ResizeRequest, &report));
685
686 wxSize sz = win->GetSize();
687 wxSizeEvent sizeEvent(sz, win->GetId());
688 sizeEvent.SetEventObject(win);
689
690 return win->GetEventHandler()->ProcessEvent( sizeEvent );
691 }
692 #endif
693 #endif
694 #if wxUSE_NANOX
695 case GR_EVENT_TYPE_CLOSE_REQ:
696 {
697 if (win)
698 {
699 win->Close(FALSE);
700 return TRUE;
701 }
702 return FALSE;
703 break;
704 }
705 #endif
706 case EnterNotify:
707 case LeaveNotify:
708 case ButtonPress:
709 case ButtonRelease:
710 case MotionNotify:
711 {
712 if (!win->IsEnabled())
713 return FALSE;
714
715 // Here we check if the top level window is
716 // disabled, which is one aspect of modality.
717 wxWindow *tlw = win;
718 while (tlw && !tlw->IsTopLevel())
719 tlw = tlw->GetParent();
720 if (tlw && !tlw->IsEnabled())
721 return FALSE;
722
723 if (event->type == ButtonPress)
724 {
725 if ((win != wxWindow::FindFocus()) && win->AcceptsFocus())
726 {
727 // This might actually be done in wxWindow::SetFocus()
728 // and not here. TODO.
729 g_prevFocus = wxWindow::FindFocus();
730 g_nextFocus = win;
731
732 wxLogTrace( _T("focus"), _T("About to call SetFocus on %s of type %s due to button press"), win->GetName().c_str(), win->GetClassInfo()->GetClassName() );
733
734 // Record the fact that this window is
735 // getting the focus, because we'll need to
736 // check if its parent is getting a bogus
737 // focus and duly ignore it.
738 // TODO: may need to have this code in SetFocus, too.
739 extern wxWindow* g_GettingFocus;
740 g_GettingFocus = win;
741 win->SetFocus();
742 }
743 }
744
745 #if !wxUSE_NANOX
746 if (event->type == LeaveNotify || event->type == EnterNotify)
747 {
748 // Throw out NotifyGrab and NotifyUngrab
749 if (event->xcrossing.mode != NotifyNormal)
750 return FALSE;
751 }
752 #endif
753 wxMouseEvent wxevent;
754 wxTranslateMouseEvent(wxevent, win, window, event);
755 return win->GetEventHandler()->ProcessEvent( wxevent );
756 }
757 case FocusIn:
758 {
759 #if !wxUSE_NANOX
760 if ((event->xfocus.detail != NotifyPointer) &&
761 (event->xfocus.mode == NotifyNormal))
762 #endif
763 {
764 wxLogTrace( _T("focus"), _T("FocusIn from %s of type %s"), win->GetName().c_str(), win->GetClassInfo()->GetClassName() );
765
766 extern wxWindow* g_GettingFocus;
767 if (g_GettingFocus && g_GettingFocus->GetParent() == win)
768 {
769 // Ignore this, this can be a spurious FocusIn
770 // caused by a child having its focus set.
771 g_GettingFocus = NULL;
772 wxLogTrace( _T("focus"), _T("FocusIn from %s of type %s being deliberately ignored"), win->GetName().c_str(), win->GetClassInfo()->GetClassName() );
773 return TRUE;
774 }
775 else
776 {
777 wxFocusEvent focusEvent(wxEVT_SET_FOCUS, win->GetId());
778 focusEvent.SetEventObject(win);
779 focusEvent.SetWindow( g_prevFocus );
780 g_prevFocus = NULL;
781
782 return win->GetEventHandler()->ProcessEvent(focusEvent);
783 }
784 }
785 return FALSE;
786 break;
787 }
788 case FocusOut:
789 {
790 #if !wxUSE_NANOX
791 if ((event->xfocus.detail != NotifyPointer) &&
792 (event->xfocus.mode == NotifyNormal))
793 #endif
794 {
795 wxLogTrace( _T("focus"), _T("FocusOut from %s of type %s"), win->GetName().c_str(), win->GetClassInfo()->GetClassName() );
796
797 wxFocusEvent focusEvent(wxEVT_KILL_FOCUS, win->GetId());
798 focusEvent.SetEventObject(win);
799 focusEvent.SetWindow( g_nextFocus );
800 g_nextFocus = NULL;
801 return win->GetEventHandler()->ProcessEvent(focusEvent);
802 }
803 return FALSE;
804 break;
805 }
806 default:
807 {
808 #ifdef __WXDEBUG__
809 //wxString eventName = wxGetXEventName(XEvent& event);
810 //wxLogDebug(wxT("Event %s not handled"), eventName.c_str());
811 #endif
812 return FALSE;
813 break;
814 }
815 }
816 return FALSE;
817 }
818
819 // Returns TRUE if more time is needed.
820 // Note that this duplicates wxEventLoopImpl::SendIdleEvent
821 // but ProcessIdle may be needed by apps, so is kept.
822 bool wxApp::ProcessIdle()
823 {
824 wxIdleEvent event;
825 event.SetEventObject(this);
826 ProcessEvent(event);
827
828 return event.MoreRequested();
829 }
830
831 void wxApp::ExitMainLoop()
832 {
833 if (m_mainLoop)
834 m_mainLoop->Exit(0);
835 }
836
837 // Is a message/event pending?
838 bool wxApp::Pending()
839 {
840 return wxEventLoop::GetActive()->Pending();
841 }
842
843 // Dispatch a message.
844 void wxApp::Dispatch()
845 {
846 wxEventLoop::GetActive()->Dispatch();
847 }
848
849 // This should be redefined in a derived class for
850 // handling property change events for XAtom IPC.
851 bool wxApp::HandlePropertyChange(WXEvent *event)
852 {
853 // by default do nothing special
854 // TODO: what to do for X11
855 // XtDispatchEvent((XEvent*) event);
856 return FALSE;
857 }
858
859 void wxApp::OnIdle(wxIdleEvent& event)
860 {
861 static bool s_inOnIdle = FALSE;
862
863 // Avoid recursion (via ProcessEvent default case)
864 if (s_inOnIdle)
865 return;
866
867 s_inOnIdle = TRUE;
868
869 // Resend in the main thread events which have been prepared in other
870 // threads
871 ProcessPendingEvents();
872
873 // 'Garbage' collection of windows deleted with Close()
874 DeletePendingObjects();
875
876 // Send OnIdle events to all windows
877 bool needMore = SendIdleEvents();
878
879 if (needMore)
880 event.RequestMore(TRUE);
881
882 s_inOnIdle = FALSE;
883 }
884
885 void wxApp::WakeUpIdle()
886 {
887 // TODO: use wxMotif implementation?
888
889 // Wake up the idle handler processor, even if it is in another thread...
890 }
891
892
893 // Send idle event to all top-level windows
894 bool wxApp::SendIdleEvents()
895 {
896 bool needMore = FALSE;
897
898 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
899 while (node)
900 {
901 wxWindow* win = node->GetData();
902 if (SendIdleEvents(win))
903 needMore = TRUE;
904 node = node->GetNext();
905 }
906
907 return needMore;
908 }
909
910 // Send idle event to window and all subwindows
911 bool wxApp::SendIdleEvents(wxWindow* win)
912 {
913 bool needMore = FALSE;
914
915 wxIdleEvent event;
916 event.SetEventObject(win);
917
918 win->GetEventHandler()->ProcessEvent(event);
919
920 if (event.MoreRequested())
921 needMore = TRUE;
922
923 wxWindowListNode* node = win->GetChildren().GetFirst();
924 while (node)
925 {
926 wxWindow* win = (wxWindow*) node->GetData();
927 if (SendIdleEvents(win))
928 needMore = TRUE;
929
930 node = node->GetNext();
931 }
932
933 win->OnInternalIdle();
934
935 return needMore;
936 }
937
938 void wxApp::DeletePendingObjects()
939 {
940 wxNode *node = wxPendingDelete.GetFirst();
941 while (node)
942 {
943 wxObject *obj = (wxObject *)node->GetData();
944
945 delete obj;
946
947 if (wxPendingDelete.Member(obj))
948 delete node;
949
950 // Deleting one object may have deleted other pending
951 // objects, so start from beginning of list again.
952 node = wxPendingDelete.GetFirst();
953 }
954 }
955
956 // Create display, and other initialization
957 bool wxApp::OnInitGui()
958 {
959 // Eventually this line will be removed, but for
960 // now we don't want to try popping up a dialog
961 // for error messages.
962 delete wxLog::SetActiveTarget(new wxLogStderr);
963
964 if (!wxAppBase::OnInitGui())
965 return FALSE;
966
967 GetMainColormap( wxApp::GetDisplay() );
968
969 m_maxRequestSize = XMaxRequestSize( (Display*) wxApp::GetDisplay() );
970
971 #if !wxUSE_NANOX
972 m_visualInfo = new wxXVisualInfo;
973 wxFillXVisualInfo( m_visualInfo, (Display*) wxApp::GetDisplay() );
974 #endif
975
976 return TRUE;
977 }
978
979 #if wxUSE_UNICODE
980
981 #include <pango/pango.h>
982 #include <pango/pangox.h>
983 #include <pango/pangoxft.h>
984
985 PangoContext* wxApp::GetPangoContext()
986 {
987 static PangoContext *ret = NULL;
988 if (ret)
989 return ret;
990
991 Display *xdisplay = (Display*) wxApp::GetDisplay();
992
993 #if 1
994 int xscreen = DefaultScreen(xdisplay);
995 static int use_xft = -1;
996 if (use_xft == -1)
997 {
998 wxString val = wxGetenv( L"GDK_USE_XFT" );
999 use_xft = (val == L"1");
1000 }
1001
1002 if (use_xft)
1003 ret = pango_xft_get_context( xdisplay, xscreen );
1004 else
1005 #endif
1006 ret = pango_x_get_context( xdisplay );
1007
1008 if (!PANGO_IS_CONTEXT(ret))
1009 wxLogError( wxT("No pango context.") );
1010
1011 return ret;
1012 }
1013 #endif
1014
1015 WXColormap wxApp::GetMainColormap(WXDisplay* display)
1016 {
1017 if (!display) /* Must be called first with non-NULL display */
1018 return m_mainColormap;
1019
1020 int defaultScreen = DefaultScreen((Display*) display);
1021 Screen* screen = XScreenOfDisplay((Display*) display, defaultScreen);
1022
1023 Colormap c = DefaultColormapOfScreen(screen);
1024
1025 if (!m_mainColormap)
1026 m_mainColormap = (WXColormap) c;
1027
1028 return (WXColormap) c;
1029 }
1030
1031 Window wxGetWindowParent(Window window)
1032 {
1033 wxASSERT_MSG( window, "invalid window" );
1034
1035 return (Window) 0;
1036
1037 Window parent, root = 0;
1038 #if wxUSE_NANOX
1039 int noChildren = 0;
1040 #else
1041 unsigned int noChildren = 0;
1042 #endif
1043 Window* children = NULL;
1044
1045 // #define XQueryTree(d,w,r,p,c,nc) GrQueryTree(w,p,c,nc)
1046 int res = 1;
1047 #if !wxUSE_NANOX
1048 res =
1049 #endif
1050 XQueryTree((Display*) wxGetDisplay(), window, & root, & parent,
1051 & children, & noChildren);
1052 if (children)
1053 XFree(children);
1054 if (res)
1055 return parent;
1056 else
1057 return (Window) 0;
1058 }
1059
1060 void wxApp::Exit()
1061 {
1062 wxApp::CleanUp();
1063
1064 wxAppConsole::Exit();
1065 }
1066
1067 // Yield to other processes
1068
1069 bool wxApp::Yield(bool onlyIfNeeded)
1070 {
1071 // Sometimes only 2 yields seem
1072 // to do the trick, e.g. in the
1073 // progress dialog
1074 int i;
1075 for (i = 0; i < 2; i++)
1076 {
1077 bool s_inYield = FALSE;
1078
1079 if ( s_inYield )
1080 {
1081 if ( !onlyIfNeeded )
1082 {
1083 wxFAIL_MSG( wxT("wxYield called recursively" ) );
1084 }
1085
1086 return FALSE;
1087 }
1088
1089 s_inYield = TRUE;
1090
1091 // Make sure we have an event loop object,
1092 // or Pending/Dispatch will fail
1093 wxEventLoop* eventLoop = wxEventLoop::GetActive();
1094 wxEventLoop* newEventLoop = NULL;
1095 if (!eventLoop)
1096 {
1097 newEventLoop = new wxEventLoop;
1098 wxEventLoop::SetActive(newEventLoop);
1099 }
1100
1101 // Call dispatch at least once so that sockets
1102 // can be tested
1103 wxTheApp->Dispatch();
1104
1105 while (wxTheApp && wxTheApp->Pending())
1106 wxTheApp->Dispatch();
1107
1108 #if wxUSE_TIMER
1109 wxTimer::NotifyTimers();
1110 #endif
1111 ProcessIdle();
1112
1113 if (newEventLoop)
1114 {
1115 wxEventLoop::SetActive(NULL);
1116 delete newEventLoop;
1117 }
1118
1119 s_inYield = FALSE;
1120 }
1121
1122 return TRUE;
1123 }
1124
1125 #ifdef __WXDEBUG__
1126
1127 void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
1128 {
1129 // While the GUI isn't working that well, just print out the
1130 // message.
1131 #if 1
1132 wxAppBase::OnAssert(file, line, cond, msg);
1133 #else
1134 wxString msg2;
1135 msg2.Printf("At file %s:%d: %s", file, line, msg);
1136 wxLogDebug(msg2);
1137 #endif
1138 }
1139
1140 #endif // __WXDEBUG__
1141