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