]> git.saurik.com Git - wxWidgets.git/blob - src/x11/app.cpp
Small fixes
[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 wxApp *wxTheApp = NULL;
53
54 // This is set within wxEntryStart -- too early on
55 // to put these in wxTheApp
56 static bool g_showIconic = FALSE;
57 static 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.
63 static wxWindow *g_nextFocus = NULL;
64 static wxWindow *g_prevFocus = NULL;
65
66 //------------------------------------------------------------------------
67 // X11 error handling
68 //------------------------------------------------------------------------
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 if (gs_pfnXErrorHandler)
79 return gs_pfnXErrorHandler(dpy, xevent);
80 else
81 return 0;
82 }
83 #endif // __WXDEBUG__
84
85 //------------------------------------------------------------------------
86 // wxApp
87 //------------------------------------------------------------------------
88
89 long wxApp::sm_lastMessageTime = 0;
90 WXDisplay *wxApp::ms_display = NULL;
91
92 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
93
94 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
95 EVT_IDLE(wxApp::OnIdle)
96 END_EVENT_TABLE()
97
98 bool 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
127 void 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!
173 int 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
257 int wxEntryInitGui()
258 {
259 int retValue = 0;
260
261 if ( !wxTheApp->OnInitGui() )
262 retValue = -1;
263
264 return retValue;
265 }
266
267
268 int 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
365 wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL;
366
367 wxApp::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
385 wxApp::~wxApp()
386 {
387 #if !wxUSE_NANOX
388 delete m_visualInfo;
389 #endif
390 }
391
392 bool wxApp::Initialized()
393 {
394 if (GetTopWindow())
395 return TRUE;
396 else
397 return FALSE;
398 }
399
400 int 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
417 struct wxExposeInfo
418 {
419 Window window;
420 Bool found_non_matching;
421 };
422
423 static 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
451 bool 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.
827 bool wxApp::ProcessIdle()
828 {
829 wxIdleEvent event;
830 event.SetEventObject(this);
831 ProcessEvent(event);
832
833 return event.MoreRequested();
834 }
835
836 void wxApp::ExitMainLoop()
837 {
838 if (m_mainLoop)
839 m_mainLoop->Exit(0);
840 }
841
842 // Is a message/event pending?
843 bool wxApp::Pending()
844 {
845 return wxEventLoop::GetActive()->Pending();
846 }
847
848 // Dispatch a message.
849 void 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.
856 bool 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
864 void 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
890 void 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
898 bool 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
915 bool 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
942 void 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
961 bool 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
989 PangoContext* 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
1019 WXColormap 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
1035 Window 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
1064 void 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
1080 bool 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
1138 void 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