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