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