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