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