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