Removed some deprecated usage
[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 #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
53 extern wxList wxPendingDelete;
54
55 wxHashTable *wxWidgetHashTable = NULL;
56 wxHashTable *wxClientWidgetHashTable = NULL;
57
58 wxApp *wxTheApp = NULL;
59
60 // This is set within wxEntryStart -- too early on
61 // to put these in wxTheApp
62 static bool g_showIconic = FALSE;
63 static 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.
69 static wxWindow *g_nextFocus = NULL;
70 static wxWindow *g_prevFocus = NULL;
71
72 //------------------------------------------------------------------------
73 // X11 error handling
74 //------------------------------------------------------------------------
75
76 #ifdef __WXDEBUG__
77 typedef int (*XErrorHandlerFunc)(Display *, XErrorEvent *);
78
79 XErrorHandlerFunc gs_pfnXErrorHandler = 0;
80
81 static 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
95 long wxApp::sm_lastMessageTime = 0;
96 WXDisplay *wxApp::ms_display = NULL;
97
98 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
99
100 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
101 EVT_IDLE(wxApp::OnIdle)
102 END_EVENT_TABLE()
103
104 bool 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
137 void 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!
187 int 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
271 int wxEntryInitGui()
272 {
273 int retValue = 0;
274
275 if ( !wxTheApp->OnInitGui() )
276 retValue = -1;
277
278 return retValue;
279 }
280
281
282 int 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
379 wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL;
380
381 wxApp::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
400 wxApp::~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
411 bool wxApp::Initialized()
412 {
413 if (GetTopWindow())
414 return TRUE;
415 else
416 return FALSE;
417 }
418
419 int 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
436 struct wxExposeInfo
437 {
438 Window window;
439 Bool found_non_matching;
440 };
441
442 static 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
470 bool 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
553 // EXPERIMENT
554 //win->Update();
555 }
556
557 return TRUE;
558 }
559
560 #if !wxUSE_NANOX
561 case GraphicsExpose:
562 {
563 printf( "GraphicExpose event\n" );
564
565 wxLogTrace( _T("expose"), _T("GraphicsExpose from %s"), win->GetName().c_str());
566
567 win->GetUpdateRegion().Union( event->xgraphicsexpose.x, event->xgraphicsexpose.y,
568 event->xgraphicsexpose.width, event->xgraphicsexpose.height);
569
570 win->GetClearRegion().Union( event->xgraphicsexpose.x, event->xgraphicsexpose.y,
571 event->xgraphicsexpose.width, event->xgraphicsexpose.height);
572
573 if (event->xgraphicsexpose.count == 0)
574 {
575 // Only erase background, paint in idle time.
576 win->SendEraseEvents();
577 // win->Update();
578 }
579
580 return TRUE;
581 }
582 #endif
583
584 case KeyPress:
585 {
586 if (!win->IsEnabled())
587 return FALSE;
588
589 wxKeyEvent keyEvent(wxEVT_KEY_DOWN);
590 wxTranslateKeyEvent(keyEvent, win, window, event);
591
592 // wxLogDebug( "OnKey from %s", win->GetName().c_str() );
593
594 // We didn't process wxEVT_KEY_DOWN, so send wxEVT_CHAR
595 if (win->GetEventHandler()->ProcessEvent( keyEvent ))
596 return TRUE;
597
598 keyEvent.SetEventType(wxEVT_CHAR);
599 // Do the translation again, retaining the ASCII
600 // code.
601 wxTranslateKeyEvent(keyEvent, win, window, event, TRUE);
602 if (win->GetEventHandler()->ProcessEvent( keyEvent ))
603 return TRUE;
604
605 if ( (keyEvent.m_keyCode == WXK_TAB) &&
606 win->GetParent() && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
607 {
608 wxNavigationKeyEvent new_event;
609 new_event.SetEventObject( win->GetParent() );
610 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
611 new_event.SetDirection( (keyEvent.m_keyCode == WXK_TAB) );
612 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
613 new_event.SetWindowChange( keyEvent.ControlDown() );
614 new_event.SetCurrentFocus( win );
615 return win->GetParent()->GetEventHandler()->ProcessEvent( new_event );
616 }
617
618 return FALSE;
619 }
620 case KeyRelease:
621 {
622 if (!win->IsEnabled())
623 return FALSE;
624
625 wxKeyEvent keyEvent(wxEVT_KEY_UP);
626 wxTranslateKeyEvent(keyEvent, win, window, event);
627
628 return win->GetEventHandler()->ProcessEvent( keyEvent );
629 }
630 case ConfigureNotify:
631 {
632 #if wxUSE_NANOX
633 if (event->update.utype == GR_UPDATE_SIZE)
634 #endif
635 {
636 if (win->IsTopLevel())
637 {
638 wxTopLevelWindow *tlw = (wxTopLevelWindow*) win;
639 tlw->SetConfigureGeometry( XConfigureEventGetX(event), XConfigureEventGetY(event),
640 XConfigureEventGetWidth(event), XConfigureEventGetHeight(event) );
641 }
642
643 if (win->IsTopLevel() && win->IsShown())
644 {
645 wxTopLevelWindowX11 *tlw = (wxTopLevelWindowX11 *) win;
646 tlw->SetNeedResizeInIdle();
647 }
648 else
649 {
650 wxSizeEvent sizeEvent( wxSize(XConfigureEventGetWidth(event), XConfigureEventGetHeight(event)), win->GetId() );
651 sizeEvent.SetEventObject( win );
652
653 return win->GetEventHandler()->ProcessEvent( sizeEvent );
654 }
655 }
656 return FALSE;
657 break;
658 }
659 #if !wxUSE_NANOX
660 case PropertyNotify:
661 {
662 //wxLogDebug("PropertyNotify: %s", windowClass.c_str());
663 return HandlePropertyChange(_event);
664 }
665 case ClientMessage:
666 {
667 if (!win->IsEnabled())
668 return FALSE;
669
670 Atom wm_delete_window = XInternAtom(wxGlobalDisplay(), "WM_DELETE_WINDOW", True);
671 Atom wm_protocols = XInternAtom(wxGlobalDisplay(), "WM_PROTOCOLS", True);
672
673 if (event->xclient.message_type == wm_protocols)
674 {
675 if ((Atom) (event->xclient.data.l[0]) == wm_delete_window)
676 {
677 win->Close(FALSE);
678 return TRUE;
679 }
680 }
681 return FALSE;
682 }
683 #if 0
684 case DestroyNotify:
685 {
686 printf( "destroy from %s\n", win->GetName().c_str() );
687 break;
688 }
689 case CreateNotify:
690 {
691 printf( "create from %s\n", win->GetName().c_str() );
692 break;
693 }
694 case MapRequest:
695 {
696 printf( "map request from %s\n", win->GetName().c_str() );
697 break;
698 }
699 case ResizeRequest:
700 {
701 printf( "resize request from %s\n", win->GetName().c_str() );
702
703 Display *disp = (Display*) wxGetDisplay();
704 XEvent report;
705
706 // to avoid flicker
707 report = * event;
708 while( XCheckTypedWindowEvent (disp, actualWindow, ResizeRequest, &report));
709
710 wxSize sz = win->GetSize();
711 wxSizeEvent sizeEvent(sz, win->GetId());
712 sizeEvent.SetEventObject(win);
713
714 return win->GetEventHandler()->ProcessEvent( sizeEvent );
715 }
716 #endif
717 #endif
718 #if wxUSE_NANOX
719 case GR_EVENT_TYPE_CLOSE_REQ:
720 {
721 if (win)
722 {
723 win->Close(FALSE);
724 return TRUE;
725 }
726 return FALSE;
727 break;
728 }
729 #endif
730 case EnterNotify:
731 case LeaveNotify:
732 case ButtonPress:
733 case ButtonRelease:
734 case MotionNotify:
735 {
736 if (!win->IsEnabled())
737 return FALSE;
738
739 // Here we check if the top level window is
740 // disabled, which is one aspect of modality.
741 wxWindow *tlw = win;
742 while (tlw && !tlw->IsTopLevel())
743 tlw = tlw->GetParent();
744 if (tlw && !tlw->IsEnabled())
745 return FALSE;
746
747 if (event->type == ButtonPress)
748 {
749 if ((win != wxWindow::FindFocus()) && win->AcceptsFocus())
750 {
751 // This might actually be done in wxWindow::SetFocus()
752 // and not here. TODO.
753 g_prevFocus = wxWindow::FindFocus();
754 g_nextFocus = win;
755
756 wxLogTrace( _T("focus"), _T("About to call SetFocus on %s of type %s due to button press"), win->GetName().c_str(), win->GetClassInfo()->GetClassName() );
757
758 // Record the fact that this window is
759 // getting the focus, because we'll need to
760 // check if its parent is getting a bogus
761 // focus and duly ignore it.
762 // TODO: may need to have this code in SetFocus, too.
763 extern wxWindow* g_GettingFocus;
764 g_GettingFocus = win;
765 win->SetFocus();
766 }
767 }
768
769 #if !wxUSE_NANOX
770 if (event->type == LeaveNotify || event->type == EnterNotify)
771 {
772 // Throw out NotifyGrab and NotifyUngrab
773 if (event->xcrossing.mode != NotifyNormal)
774 return FALSE;
775 }
776 #endif
777 wxMouseEvent wxevent;
778 wxTranslateMouseEvent(wxevent, win, window, event);
779 return win->GetEventHandler()->ProcessEvent( wxevent );
780 }
781 case FocusIn:
782 {
783 #if !wxUSE_NANOX
784 if ((event->xfocus.detail != NotifyPointer) &&
785 (event->xfocus.mode == NotifyNormal))
786 #endif
787 {
788 wxLogTrace( _T("focus"), _T("FocusIn from %s of type %s"), win->GetName().c_str(), win->GetClassInfo()->GetClassName() );
789
790 extern wxWindow* g_GettingFocus;
791 if (g_GettingFocus && g_GettingFocus->GetParent() == win)
792 {
793 // Ignore this, this can be a spurious FocusIn
794 // caused by a child having its focus set.
795 g_GettingFocus = NULL;
796 wxLogTrace( _T("focus"), _T("FocusIn from %s of type %s being deliberately ignored"), win->GetName().c_str(), win->GetClassInfo()->GetClassName() );
797 return TRUE;
798 }
799 else
800 {
801 wxFocusEvent focusEvent(wxEVT_SET_FOCUS, win->GetId());
802 focusEvent.SetEventObject(win);
803 focusEvent.SetWindow( g_prevFocus );
804 g_prevFocus = NULL;
805
806 return win->GetEventHandler()->ProcessEvent(focusEvent);
807 }
808 }
809 return FALSE;
810 break;
811 }
812 case FocusOut:
813 {
814 #if !wxUSE_NANOX
815 if ((event->xfocus.detail != NotifyPointer) &&
816 (event->xfocus.mode == NotifyNormal))
817 #endif
818 {
819 wxLogTrace( _T("focus"), _T("FocusOut from %s of type %s"), win->GetName().c_str(), win->GetClassInfo()->GetClassName() );
820
821 wxFocusEvent focusEvent(wxEVT_KILL_FOCUS, win->GetId());
822 focusEvent.SetEventObject(win);
823 focusEvent.SetWindow( g_nextFocus );
824 g_nextFocus = NULL;
825 return win->GetEventHandler()->ProcessEvent(focusEvent);
826 }
827 return FALSE;
828 break;
829 }
830 default:
831 {
832 #ifdef __WXDEBUG__
833 //wxString eventName = wxGetXEventName(XEvent& event);
834 //wxLogDebug(wxT("Event %s not handled"), eventName.c_str());
835 #endif
836 return FALSE;
837 break;
838 }
839 }
840 return FALSE;
841 }
842
843 // Returns TRUE if more time is needed.
844 // Note that this duplicates wxEventLoopImpl::SendIdleEvent
845 // but ProcessIdle may be needed by apps, so is kept.
846 bool wxApp::ProcessIdle()
847 {
848 wxIdleEvent event;
849 event.SetEventObject(this);
850 ProcessEvent(event);
851
852 return event.MoreRequested();
853 }
854
855 void wxApp::ExitMainLoop()
856 {
857 if (m_mainLoop)
858 m_mainLoop->Exit(0);
859 }
860
861 // Is a message/event pending?
862 bool wxApp::Pending()
863 {
864 return wxEventLoop::GetActive()->Pending();
865 }
866
867 // Dispatch a message.
868 void wxApp::Dispatch()
869 {
870 wxEventLoop::GetActive()->Dispatch();
871 }
872
873 // This should be redefined in a derived class for
874 // handling property change events for XAtom IPC.
875 bool wxApp::HandlePropertyChange(WXEvent *event)
876 {
877 // by default do nothing special
878 // TODO: what to do for X11
879 // XtDispatchEvent((XEvent*) event);
880 return FALSE;
881 }
882
883 void wxApp::OnIdle(wxIdleEvent& event)
884 {
885 static bool s_inOnIdle = FALSE;
886
887 // Avoid recursion (via ProcessEvent default case)
888 if (s_inOnIdle)
889 return;
890
891 s_inOnIdle = TRUE;
892
893 // Resend in the main thread events which have been prepared in other
894 // threads
895 ProcessPendingEvents();
896
897 // 'Garbage' collection of windows deleted with Close()
898 DeletePendingObjects();
899
900 // Send OnIdle events to all windows
901 bool needMore = SendIdleEvents();
902
903 if (needMore)
904 event.RequestMore(TRUE);
905
906 s_inOnIdle = FALSE;
907 }
908
909 void wxWakeUpIdle()
910 {
911 // **** please implement me! ****
912 // Wake up the idle handler processor, even if it is in another thread...
913 }
914
915
916 // Send idle event to all top-level windows
917 bool wxApp::SendIdleEvents()
918 {
919 bool needMore = FALSE;
920
921 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
922 while (node)
923 {
924 wxWindow* win = node->GetData();
925 if (SendIdleEvents(win))
926 needMore = TRUE;
927 node = node->GetNext();
928 }
929
930 return needMore;
931 }
932
933 // Send idle event to window and all subwindows
934 bool wxApp::SendIdleEvents(wxWindow* win)
935 {
936 bool needMore = FALSE;
937
938 wxIdleEvent event;
939 event.SetEventObject(win);
940
941 win->GetEventHandler()->ProcessEvent(event);
942
943 if (event.MoreRequested())
944 needMore = TRUE;
945
946 wxWindowListNode* node = win->GetChildren().GetFirst();
947 while (node)
948 {
949 wxWindow* win = (wxWindow*) node->GetData();
950 if (SendIdleEvents(win))
951 needMore = TRUE;
952
953 node = node->GetNext();
954 }
955
956 win->OnInternalIdle();
957
958 return needMore;
959 }
960
961 void wxApp::DeletePendingObjects()
962 {
963 wxNode *node = wxPendingDelete.GetFirst();
964 while (node)
965 {
966 wxObject *obj = (wxObject *)node->GetData();
967
968 delete obj;
969
970 if (wxPendingDelete.Member(obj))
971 delete node;
972
973 // Deleting one object may have deleted other pending
974 // objects, so start from beginning of list again.
975 node = wxPendingDelete.GetFirst();
976 }
977 }
978
979 static void wxCalcPrecAndShift( unsigned long mask, int *shift, int *prec )
980 {
981 *shift = 0;
982 *prec = 0;
983
984 while (!(mask & 0x1))
985 {
986 (*shift)++;
987 mask >>= 1;
988 }
989
990 while (mask & 0x1)
991 {
992 (*prec)++;
993 mask >>= 1;
994 }
995 }
996
997 // Create display, and other initialization
998 bool wxApp::OnInitGui()
999 {
1000 // Eventually this line will be removed, but for
1001 // now we don't want to try popping up a dialog
1002 // for error messages.
1003 delete wxLog::SetActiveTarget(new wxLogStderr);
1004
1005 if (!wxAppBase::OnInitGui())
1006 return FALSE;
1007
1008 GetMainColormap( wxApp::GetDisplay() );
1009
1010 m_maxRequestSize = XMaxRequestSize( (Display*) wxApp::GetDisplay() );
1011
1012 #if !wxUSE_NANOX
1013 // Get info about the current visual. It is enough
1014 // to do this once here unless we support different
1015 // visuals, displays and screens. Given that wxX11
1016 // mostly for embedded things, that is no real
1017 // limitation.
1018 Display *xdisplay = (Display*) wxApp::GetDisplay();
1019 int xscreen = DefaultScreen(xdisplay);
1020 Visual* xvisual = DefaultVisual(xdisplay,xscreen);
1021 int xdepth = DefaultDepth(xdisplay, xscreen);
1022
1023 XVisualInfo vinfo_template;
1024 vinfo_template.visual = xvisual;
1025 vinfo_template.visualid = XVisualIDFromVisual( xvisual );
1026 vinfo_template.depth = xdepth;
1027
1028 int nitem = 0;
1029 XVisualInfo *vi = XGetVisualInfo( xdisplay, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
1030 wxASSERT_MSG( vi, wxT("No visual info") );
1031
1032 m_visualType = vi->visual->c_class;
1033 m_visualScreen = vi->screen;
1034
1035 m_visualRedMask = vi->red_mask;
1036 m_visualGreenMask = vi->green_mask;
1037 m_visualBlueMask = vi->blue_mask;
1038
1039 if (m_visualType != GrayScale && m_visualType != PseudoColor)
1040 {
1041 wxCalcPrecAndShift( m_visualRedMask, &m_visualRedShift, &m_visualRedPrec );
1042 wxCalcPrecAndShift( m_visualGreenMask, &m_visualGreenShift, &m_visualGreenPrec );
1043 wxCalcPrecAndShift( m_visualBlueMask, &m_visualBlueShift, &m_visualBluePrec );
1044 }
1045
1046 m_visualDepth = xdepth;
1047 if (xdepth == 16)
1048 xdepth = m_visualRedPrec + m_visualGreenPrec + m_visualBluePrec;
1049
1050 m_visualColormapSize = vi->colormap_size;
1051
1052 XFree( vi );
1053
1054 if (m_visualDepth > 8)
1055 return TRUE;
1056
1057 m_visualColormap = new XColor[m_visualColormapSize];
1058 XColor* colors = (XColor*) m_visualColormap;
1059
1060 for (int i = 0; i < m_visualColormapSize; i++)
1061 colors[i].pixel = i;
1062
1063 XQueryColors( xdisplay, DefaultColormap(xdisplay,xscreen), colors, m_visualColormapSize );
1064
1065 m_colorCube = (unsigned char*)malloc(32 * 32 * 32);
1066
1067 for (int r = 0; r < 32; r++)
1068 {
1069 for (int g = 0; g < 32; g++)
1070 {
1071 for (int b = 0; b < 32; b++)
1072 {
1073 int rr = (r << 3) | (r >> 2);
1074 int gg = (g << 3) | (g >> 2);
1075 int bb = (b << 3) | (b >> 2);
1076
1077 int index = -1;
1078
1079 if (colors)
1080 {
1081 int max = 3 * 65536;
1082
1083 for (int i = 0; i < m_visualColormapSize; i++)
1084 {
1085 int rdiff = ((rr << 8) - colors[i].red);
1086 int gdiff = ((gg << 8) - colors[i].green);
1087 int bdiff = ((bb << 8) - colors[i].blue);
1088 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
1089 if (sum < max)
1090 {
1091 index = i; max = sum;
1092 }
1093 }
1094 }
1095 else
1096 {
1097 // assume 8-bit true or static colors. this really exists
1098 index = (r >> (5 - m_visualRedPrec)) << m_visualRedShift;
1099 index |= (g >> (5 - m_visualGreenPrec)) << m_visualGreenShift;
1100 index |= (b >> (5 - m_visualBluePrec)) << m_visualBlueShift;
1101 }
1102 m_colorCube[ (r*1024) + (g*32) + b ] = index;
1103 }
1104 }
1105 }
1106 #endif
1107
1108 return TRUE;
1109 }
1110
1111 #if wxUSE_UNICODE
1112
1113 #include <pango/pango.h>
1114 #include <pango/pangox.h>
1115 #include <pango/pangoxft.h>
1116
1117 PangoContext* wxApp::GetPangoContext()
1118 {
1119 static PangoContext *ret = NULL;
1120 if (ret)
1121 return ret;
1122
1123 Display *xdisplay = (Display*) wxApp::GetDisplay();
1124
1125 #if 1
1126 int xscreen = DefaultScreen(xdisplay);
1127 static int use_xft = -1;
1128 if (use_xft == -1)
1129 {
1130 wxString val = wxGetenv( L"GDK_USE_XFT" );
1131 use_xft = (val == L"1");
1132 }
1133
1134 if (use_xft)
1135 ret = pango_xft_get_context( xdisplay, xscreen );
1136 else
1137 #endif
1138 ret = pango_x_get_context( xdisplay );
1139
1140 if (!PANGO_IS_CONTEXT(ret))
1141 wxLogError( wxT("No pango context.") );
1142
1143 return ret;
1144 }
1145 #endif
1146
1147 WXColormap wxApp::GetMainColormap(WXDisplay* display)
1148 {
1149 if (!display) /* Must be called first with non-NULL display */
1150 return m_mainColormap;
1151
1152 int defaultScreen = DefaultScreen((Display*) display);
1153 Screen* screen = XScreenOfDisplay((Display*) display, defaultScreen);
1154
1155 Colormap c = DefaultColormapOfScreen(screen);
1156
1157 if (!m_mainColormap)
1158 m_mainColormap = (WXColormap) c;
1159
1160 return (WXColormap) c;
1161 }
1162
1163 Window wxGetWindowParent(Window window)
1164 {
1165 wxASSERT_MSG( window, "invalid window" );
1166
1167 return (Window) 0;
1168
1169 Window parent, root = 0;
1170 #if wxUSE_NANOX
1171 int noChildren = 0;
1172 #else
1173 unsigned int noChildren = 0;
1174 #endif
1175 Window* children = NULL;
1176
1177 // #define XQueryTree(d,w,r,p,c,nc) GrQueryTree(w,p,c,nc)
1178 int res = 1;
1179 #if !wxUSE_NANOX
1180 res =
1181 #endif
1182 XQueryTree((Display*) wxGetDisplay(), window, & root, & parent,
1183 & children, & noChildren);
1184 if (children)
1185 XFree(children);
1186 if (res)
1187 return parent;
1188 else
1189 return (Window) 0;
1190 }
1191
1192 void wxExit()
1193 {
1194 int retValue = 0;
1195 if (wxTheApp)
1196 retValue = wxTheApp->OnExit();
1197
1198 wxApp::CleanUp();
1199 /*
1200 * Exit in some platform-specific way. Not recommended that the app calls this:
1201 * only for emergencies.
1202 */
1203 exit(retValue);
1204 }
1205
1206 // Yield to other processes
1207
1208 bool wxApp::Yield(bool onlyIfNeeded)
1209 {
1210 // Sometimes only 2 yields seem
1211 // to do the trick, e.g. in the
1212 // progress dialog
1213 int i;
1214 for (i = 0; i < 2; i++)
1215 {
1216 bool s_inYield = FALSE;
1217
1218 if ( s_inYield )
1219 {
1220 if ( !onlyIfNeeded )
1221 {
1222 wxFAIL_MSG( wxT("wxYield called recursively" ) );
1223 }
1224
1225 return FALSE;
1226 }
1227
1228 s_inYield = TRUE;
1229
1230 // Make sure we have an event loop object,
1231 // or Pending/Dispatch will fail
1232 wxEventLoop* eventLoop = wxEventLoop::GetActive();
1233 wxEventLoop* newEventLoop = NULL;
1234 if (!eventLoop)
1235 {
1236 newEventLoop = new wxEventLoop;
1237 wxEventLoop::SetActive(newEventLoop);
1238 }
1239
1240 // Call dispatch at least once so that sockets
1241 // can be tested
1242 wxTheApp->Dispatch();
1243
1244 while (wxTheApp && wxTheApp->Pending())
1245 wxTheApp->Dispatch();
1246
1247 #if wxUSE_TIMER
1248 wxTimer::NotifyTimers();
1249 #endif
1250 ProcessIdle();
1251
1252 if (newEventLoop)
1253 {
1254 wxEventLoop::SetActive(NULL);
1255 delete newEventLoop;
1256 }
1257
1258 s_inYield = FALSE;
1259 }
1260
1261 return TRUE;
1262 }
1263
1264 #ifdef __WXDEBUG__
1265
1266 void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
1267 {
1268 // While the GUI isn't working that well, just print out the
1269 // message.
1270 #if 1
1271 wxAppBase::OnAssert(file, line, cond, msg);
1272 #else
1273 wxString msg2;
1274 msg2.Printf("At file %s:%d: %s", file, line, msg);
1275 wxLogDebug(msg2);
1276 #endif
1277 }
1278
1279 #endif // __WXDEBUG__
1280