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