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