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