]> git.saurik.com Git - wxWidgets.git/blame - src/x11/app.cpp
Use wxBitmapBase in wxCocoa
[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();
09a1dffa
JS
552
553 // EXPERIMENT
554 //win->Update();
ab6b6b15 555 }
2f12683e
RR
556
557 return TRUE;
558 }
e2386592 559
2f12683e
RR
560#if !wxUSE_NANOX
561 case GraphicsExpose:
562 {
4175e952
RR
563 printf( "GraphicExpose event\n" );
564
89cd4125 565 wxLogTrace( _T("expose"), _T("GraphicsExpose from %s"), win->GetName().c_str());
e2386592 566
2f12683e
RR
567 win->GetUpdateRegion().Union( event->xgraphicsexpose.x, event->xgraphicsexpose.y,
568 event->xgraphicsexpose.width, event->xgraphicsexpose.height);
e2386592 569
2f12683e
RR
570 win->GetClearRegion().Union( event->xgraphicsexpose.x, event->xgraphicsexpose.y,
571 event->xgraphicsexpose.width, event->xgraphicsexpose.height);
e2386592 572
2f12683e
RR
573 if (event->xgraphicsexpose.count == 0)
574 {
575 // Only erase background, paint in idle time.
576 win->SendEraseEvents();
c2c0dabf 577 // win->Update();
2f12683e
RR
578 }
579
580 return TRUE;
581 }
582#endif
583
1b0fb34b 584 case KeyPress:
83df96d6 585 {
9d2cef1c 586 if (!win->IsEnabled())
086fd560 587 return FALSE;
b513212d 588
9d2cef1c
RR
589 wxKeyEvent keyEvent(wxEVT_KEY_DOWN);
590 wxTranslateKeyEvent(keyEvent, win, window, event);
e2386592 591
9d2cef1c 592 // wxLogDebug( "OnKey from %s", win->GetName().c_str() );
e2386592 593
120b822d
RR
594 // We didn't process wxEVT_KEY_DOWN, so send wxEVT_CHAR
595 if (win->GetEventHandler()->ProcessEvent( keyEvent ))
596 return TRUE;
e2386592 597
120b822d 598 keyEvent.SetEventType(wxEVT_CHAR);
2b5f62a0
VZ
599 // Do the translation again, retaining the ASCII
600 // code.
601 wxTranslateKeyEvent(keyEvent, win, window, event, TRUE);
120b822d
RR
602 if (win->GetEventHandler()->ProcessEvent( keyEvent ))
603 return TRUE;
e2386592 604
120b822d
RR
605 if ( (keyEvent.m_keyCode == WXK_TAB) &&
606 win->GetParent() && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
9d2cef1c 607 {
120b822d
RR
608 wxNavigationKeyEvent new_event;
609 new_event.SetEventObject( win->GetParent() );
610 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
611 new_event.SetDirection( (keyEvent.m_keyCode == WXK_TAB) );
612 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
613 new_event.SetWindowChange( keyEvent.ControlDown() );
614 new_event.SetCurrentFocus( win );
615 return win->GetParent()->GetEventHandler()->ProcessEvent( new_event );
1b0fb34b 616 }
120b822d
RR
617
618 return FALSE;
83df96d6 619 }
1b0fb34b 620 case KeyRelease:
7eaac9f5 621 {
9d2cef1c 622 if (!win->IsEnabled())
086fd560 623 return FALSE;
b513212d 624
9d2cef1c
RR
625 wxKeyEvent keyEvent(wxEVT_KEY_UP);
626 wxTranslateKeyEvent(keyEvent, win, window, event);
e2386592 627
086fd560 628 return win->GetEventHandler()->ProcessEvent( keyEvent );
7eaac9f5 629 }
256d631a
JS
630 case ConfigureNotify:
631 {
c79a329d 632#if wxUSE_NANOX
9d2cef1c 633 if (event->update.utype == GR_UPDATE_SIZE)
c79a329d 634#endif
256d631a 635 {
c2c0dabf
RR
636 if (win->IsTopLevel())
637 {
638 wxTopLevelWindow *tlw = (wxTopLevelWindow*) win;
639 tlw->SetConfigureGeometry( XConfigureEventGetX(event), XConfigureEventGetY(event),
640 XConfigureEventGetWidth(event), XConfigureEventGetHeight(event) );
641 }
e2386592 642
2f12683e 643 if (win->IsTopLevel() && win->IsShown())
77df2fbc
RR
644 {
645 wxTopLevelWindowX11 *tlw = (wxTopLevelWindowX11 *) win;
646 tlw->SetNeedResizeInIdle();
647 }
648 else
649 {
650 wxSizeEvent sizeEvent( wxSize(XConfigureEventGetWidth(event), XConfigureEventGetHeight(event)), win->GetId() );
651 sizeEvent.SetEventObject( win );
e2386592 652
77df2fbc
RR
653 return win->GetEventHandler()->ProcessEvent( sizeEvent );
654 }
256d631a 655 }
086fd560 656 return FALSE;
c2ff68d3 657 break;
256d631a
JS
658 }
659#if !wxUSE_NANOX
1b0fb34b 660 case PropertyNotify:
7eaac9f5 661 {
0b5c0e1a 662 //wxLogDebug("PropertyNotify: %s", windowClass.c_str());
086fd560 663 return HandlePropertyChange(_event);
7eaac9f5 664 }
b513212d 665 case ClientMessage:
3a0b23eb 666 {
9d2cef1c 667 if (!win->IsEnabled())
086fd560 668 return FALSE;
3a0b23eb 669
7e4501ee
RR
670 Atom wm_delete_window = XInternAtom(wxGlobalDisplay(), "WM_DELETE_WINDOW", True);
671 Atom wm_protocols = XInternAtom(wxGlobalDisplay(), "WM_PROTOCOLS", True);
b513212d
JS
672
673 if (event->xclient.message_type == wm_protocols)
674 {
6a44bffd 675 if ((Atom) (event->xclient.data.l[0]) == wm_delete_window)
b513212d 676 {
9d2cef1c 677 win->Close(FALSE);
086fd560 678 return TRUE;
b513212d
JS
679 }
680 }
086fd560 681 return FALSE;
b513212d 682 }
2f12683e
RR
683#if 0
684 case DestroyNotify:
685 {
686 printf( "destroy from %s\n", win->GetName().c_str() );
687 break;
688 }
689 case CreateNotify:
690 {
691 printf( "create from %s\n", win->GetName().c_str() );
692 break;
693 }
694 case MapRequest:
695 {
696 printf( "map request from %s\n", win->GetName().c_str() );
697 break;
698 }
1b0fb34b 699 case ResizeRequest:
7eaac9f5 700 {
2f12683e 701 printf( "resize request from %s\n", win->GetName().c_str() );
e2386592 702
7266b672 703 Display *disp = (Display*) wxGetDisplay();
1b0fb34b 704 XEvent report;
e2386592 705
1b0fb34b
JS
706 // to avoid flicker
707 report = * event;
708 while( XCheckTypedWindowEvent (disp, actualWindow, ResizeRequest, &report));
e2386592 709
b1633d20
RR
710 wxSize sz = win->GetSize();
711 wxSizeEvent sizeEvent(sz, win->GetId());
712 sizeEvent.SetEventObject(win);
1b0fb34b 713
b1633d20 714 return win->GetEventHandler()->ProcessEvent( sizeEvent );
7eaac9f5 715 }
256d631a 716#endif
b1633d20 717#endif
256d631a
JS
718#if wxUSE_NANOX
719 case GR_EVENT_TYPE_CLOSE_REQ:
720 {
721 if (win)
722 {
723 win->Close(FALSE);
086fd560 724 return TRUE;
256d631a 725 }
086fd560 726 return FALSE;
256d631a
JS
727 break;
728 }
c79a329d 729#endif
1b0fb34b
JS
730 case EnterNotify:
731 case LeaveNotify:
732 case ButtonPress:
733 case ButtonRelease:
734 case MotionNotify:
7eaac9f5 735 {
7e4501ee 736 if (!win->IsEnabled())
086fd560 737 return FALSE;
366e8ae6 738
9691c806
RR
739 // Here we check if the top level window is
740 // disabled, which is one aspect of modality.
741 wxWindow *tlw = win;
742 while (tlw && !tlw->IsTopLevel())
743 tlw = tlw->GetParent();
744 if (tlw && !tlw->IsEnabled())
086fd560 745 return FALSE;
e2386592 746
7e4501ee 747 if (event->type == ButtonPress)
1b0fb34b 748 {
7e4501ee 749 if ((win != wxWindow::FindFocus()) && win->AcceptsFocus())
9d2cef1c
RR
750 {
751 // This might actually be done in wxWindow::SetFocus()
ea1ad04b 752 // and not here. TODO.
9d2cef1c
RR
753 g_prevFocus = wxWindow::FindFocus();
754 g_nextFocus = win;
e2386592 755
58ec2255
JS
756 wxLogTrace( _T("focus"), _T("About to call SetFocus on %s of type %s due to button press"), win->GetName().c_str(), win->GetClassInfo()->GetClassName() );
757
758 // Record the fact that this window is
759 // getting the focus, because we'll need to
760 // check if its parent is getting a bogus
761 // focus and duly ignore it.
762 // TODO: may need to have this code in SetFocus, too.
763 extern wxWindow* g_GettingFocus;
764 g_GettingFocus = win;
9d2cef1c
RR
765 win->SetFocus();
766 }
1b0fb34b 767 }
e2386592 768
ea1ad04b
RR
769#if !wxUSE_NANOX
770 if (event->type == LeaveNotify || event->type == EnterNotify)
771 {
772 // Throw out NotifyGrab and NotifyUngrab
773 if (event->xcrossing.mode != NotifyNormal)
086fd560 774 return FALSE;
ea1ad04b
RR
775 }
776#endif
7e4501ee
RR
777 wxMouseEvent wxevent;
778 wxTranslateMouseEvent(wxevent, win, window, event);
086fd560 779 return win->GetEventHandler()->ProcessEvent( wxevent );
7eaac9f5 780 }
1b0fb34b
JS
781 case FocusIn:
782 {
256d631a 783#if !wxUSE_NANOX
9d2cef1c
RR
784 if ((event->xfocus.detail != NotifyPointer) &&
785 (event->xfocus.mode == NotifyNormal))
256d631a 786#endif
1b0fb34b 787 {
58ec2255 788 wxLogTrace( _T("focus"), _T("FocusIn from %s of type %s"), win->GetName().c_str(), win->GetClassInfo()->GetClassName() );
366e8ae6 789
58ec2255
JS
790 extern wxWindow* g_GettingFocus;
791 if (g_GettingFocus && g_GettingFocus->GetParent() == win)
792 {
793 // Ignore this, this can be a spurious FocusIn
794 // caused by a child having its focus set.
795 g_GettingFocus = NULL;
796 wxLogTrace( _T("focus"), _T("FocusIn from %s of type %s being deliberately ignored"), win->GetName().c_str(), win->GetClassInfo()->GetClassName() );
797 return TRUE;
798 }
799 else
800 {
801 wxFocusEvent focusEvent(wxEVT_SET_FOCUS, win->GetId());
802 focusEvent.SetEventObject(win);
803 focusEvent.SetWindow( g_prevFocus );
804 g_prevFocus = NULL;
805
806 return win->GetEventHandler()->ProcessEvent(focusEvent);
807 }
1b0fb34b 808 }
086fd560 809 return FALSE;
1b0fb34b
JS
810 break;
811 }
812 case FocusOut:
813 {
256d631a 814#if !wxUSE_NANOX
9d2cef1c
RR
815 if ((event->xfocus.detail != NotifyPointer) &&
816 (event->xfocus.mode == NotifyNormal))
256d631a 817#endif
1b0fb34b 818 {
58ec2255 819 wxLogTrace( _T("focus"), _T("FocusOut from %s of type %s"), win->GetName().c_str(), win->GetClassInfo()->GetClassName() );
e2386592 820
1b0fb34b
JS
821 wxFocusEvent focusEvent(wxEVT_KILL_FOCUS, win->GetId());
822 focusEvent.SetEventObject(win);
9d2cef1c
RR
823 focusEvent.SetWindow( g_nextFocus );
824 g_nextFocus = NULL;
086fd560 825 return win->GetEventHandler()->ProcessEvent(focusEvent);
1b0fb34b 826 }
086fd560 827 return FALSE;
1b0fb34b
JS
828 break;
829 }
830 default:
831 {
45ff6421
JS
832#ifdef __WXDEBUG__
833 //wxString eventName = wxGetXEventName(XEvent& event);
834 //wxLogDebug(wxT("Event %s not handled"), eventName.c_str());
835#endif
086fd560 836 return FALSE;
1b0fb34b
JS
837 break;
838 }
83df96d6 839 }
086fd560 840 return FALSE;
83df96d6
JS
841}
842
843// Returns TRUE if more time is needed.
1b0fb34b
JS
844// Note that this duplicates wxEventLoopImpl::SendIdleEvent
845// but ProcessIdle may be needed by apps, so is kept.
83df96d6
JS
846bool wxApp::ProcessIdle()
847{
848 wxIdleEvent event;
849 event.SetEventObject(this);
850 ProcessEvent(event);
851
852 return event.MoreRequested();
853}
854
855void wxApp::ExitMainLoop()
856{
1b0fb34b
JS
857 if (m_mainLoop)
858 m_mainLoop->Exit(0);
83df96d6
JS
859}
860
861// Is a message/event pending?
862bool wxApp::Pending()
863{
1b0fb34b 864 return wxEventLoop::GetActive()->Pending();
83df96d6
JS
865}
866
867// Dispatch a message.
868void wxApp::Dispatch()
869{
1b0fb34b 870 wxEventLoop::GetActive()->Dispatch();
83df96d6
JS
871}
872
873// This should be redefined in a derived class for
874// handling property change events for XAtom IPC.
086fd560 875bool wxApp::HandlePropertyChange(WXEvent *event)
83df96d6
JS
876{
877 // by default do nothing special
7eaac9f5 878 // TODO: what to do for X11
256d631a 879 // XtDispatchEvent((XEvent*) event);
086fd560 880 return FALSE;
83df96d6
JS
881}
882
883void wxApp::OnIdle(wxIdleEvent& event)
884{
0d1dff01 885 static bool s_inOnIdle = FALSE;
83df96d6
JS
886
887 // Avoid recursion (via ProcessEvent default case)
0d1dff01 888 if (s_inOnIdle)
83df96d6
JS
889 return;
890
0d1dff01 891 s_inOnIdle = TRUE;
83df96d6 892
0d1dff01
RR
893 // Resend in the main thread events which have been prepared in other
894 // threads
83df96d6
JS
895 ProcessPendingEvents();
896
0d1dff01 897 // 'Garbage' collection of windows deleted with Close()
83df96d6
JS
898 DeletePendingObjects();
899
83df96d6
JS
900 // Send OnIdle events to all windows
901 bool needMore = SendIdleEvents();
902
903 if (needMore)
904 event.RequestMore(TRUE);
905
0d1dff01 906 s_inOnIdle = FALSE;
83df96d6
JS
907}
908
909void wxWakeUpIdle()
910{
911 // **** please implement me! ****
912 // Wake up the idle handler processor, even if it is in another thread...
913}
914
915
916// Send idle event to all top-level windows
917bool wxApp::SendIdleEvents()
918{
919 bool needMore = FALSE;
920
921 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
922 while (node)
923 {
924 wxWindow* win = node->GetData();
925 if (SendIdleEvents(win))
926 needMore = TRUE;
927 node = node->GetNext();
928 }
929
930 return needMore;
931}
932
933// Send idle event to window and all subwindows
934bool wxApp::SendIdleEvents(wxWindow* win)
935{
936 bool needMore = FALSE;
937
938 wxIdleEvent event;
939 event.SetEventObject(win);
0d1dff01
RR
940
941 win->GetEventHandler()->ProcessEvent(event);
942
83df96d6
JS
943 if (event.MoreRequested())
944 needMore = TRUE;
945
09a1dffa 946 wxWindowListNode* node = win->GetChildren().GetFirst();
83df96d6
JS
947 while (node)
948 {
09a1dffa 949 wxWindow* win = (wxWindow*) node->GetData();
83df96d6
JS
950 if (SendIdleEvents(win))
951 needMore = TRUE;
952
09a1dffa 953 node = node->GetNext();
83df96d6 954 }
e2386592 955
193e19cf
RR
956 win->OnInternalIdle();
957
0d1dff01 958 return needMore;
83df96d6
JS
959}
960
961void wxApp::DeletePendingObjects()
962{
09a1dffa 963 wxNode *node = wxPendingDelete.GetFirst();
83df96d6
JS
964 while (node)
965 {
09a1dffa 966 wxObject *obj = (wxObject *)node->GetData();
83df96d6
JS
967
968 delete obj;
969
970 if (wxPendingDelete.Member(obj))
971 delete node;
972
973 // Deleting one object may have deleted other pending
974 // objects, so start from beginning of list again.
09a1dffa 975 node = wxPendingDelete.GetFirst();
83df96d6
JS
976 }
977}
978
dc4025af
RR
979static void wxCalcPrecAndShift( unsigned long mask, int *shift, int *prec )
980{
981 *shift = 0;
982 *prec = 0;
983
984 while (!(mask & 0x1))
985 {
986 (*shift)++;
987 mask >>= 1;
988 }
989
990 while (mask & 0x1)
991 {
992 (*prec)++;
993 mask >>= 1;
994 }
995}
996
256d631a 997// Create display, and other initialization
83df96d6
JS
998bool wxApp::OnInitGui()
999{
ca7497c2
JS
1000 // Eventually this line will be removed, but for
1001 // now we don't want to try popping up a dialog
1002 // for error messages.
1003 delete wxLog::SetActiveTarget(new wxLogStderr);
e2386592 1004
ea596687 1005 if (!wxAppBase::OnInitGui())
dc4025af 1006 return FALSE;
e2386592 1007
a11672a4 1008 GetMainColormap( wxApp::GetDisplay() );
256d631a 1009
a11672a4 1010 m_maxRequestSize = XMaxRequestSize( (Display*) wxApp::GetDisplay() );
83df96d6 1011
8601b2e1 1012#if !wxUSE_NANOX
dc4025af
RR
1013 // Get info about the current visual. It is enough
1014 // to do this once here unless we support different
1015 // visuals, displays and screens. Given that wxX11
1016 // mostly for embedded things, that is no real
1017 // limitation.
1018 Display *xdisplay = (Display*) wxApp::GetDisplay();
1019 int xscreen = DefaultScreen(xdisplay);
1020 Visual* xvisual = DefaultVisual(xdisplay,xscreen);
1021 int xdepth = DefaultDepth(xdisplay, xscreen);
1022
1023 XVisualInfo vinfo_template;
1024 vinfo_template.visual = xvisual;
1025 vinfo_template.visualid = XVisualIDFromVisual( xvisual );
1026 vinfo_template.depth = xdepth;
366e8ae6 1027
dc4025af
RR
1028 int nitem = 0;
1029 XVisualInfo *vi = XGetVisualInfo( xdisplay, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
1030 wxASSERT_MSG( vi, wxT("No visual info") );
366e8ae6 1031
dc4025af
RR
1032 m_visualType = vi->visual->c_class;
1033 m_visualScreen = vi->screen;
366e8ae6 1034
dc4025af
RR
1035 m_visualRedMask = vi->red_mask;
1036 m_visualGreenMask = vi->green_mask;
1037 m_visualBlueMask = vi->blue_mask;
366e8ae6 1038
dc4025af
RR
1039 if (m_visualType != GrayScale && m_visualType != PseudoColor)
1040 {
1041 wxCalcPrecAndShift( m_visualRedMask, &m_visualRedShift, &m_visualRedPrec );
1042 wxCalcPrecAndShift( m_visualGreenMask, &m_visualGreenShift, &m_visualGreenPrec );
1043 wxCalcPrecAndShift( m_visualBlueMask, &m_visualBlueShift, &m_visualBluePrec );
1044 }
366e8ae6 1045
dc4025af
RR
1046 m_visualDepth = xdepth;
1047 if (xdepth == 16)
1048 xdepth = m_visualRedPrec + m_visualGreenPrec + m_visualBluePrec;
366e8ae6 1049
dc4025af 1050 m_visualColormapSize = vi->colormap_size;
366e8ae6 1051
dc4025af 1052 XFree( vi );
366e8ae6 1053
dc4025af
RR
1054 if (m_visualDepth > 8)
1055 return TRUE;
366e8ae6 1056
dc4025af
RR
1057 m_visualColormap = new XColor[m_visualColormapSize];
1058 XColor* colors = (XColor*) m_visualColormap;
366e8ae6 1059
dc4025af
RR
1060 for (int i = 0; i < m_visualColormapSize; i++)
1061 colors[i].pixel = i;
1062
1063 XQueryColors( xdisplay, DefaultColormap(xdisplay,xscreen), colors, m_visualColormapSize );
366e8ae6 1064
dc4025af
RR
1065 m_colorCube = (unsigned char*)malloc(32 * 32 * 32);
1066
1067 for (int r = 0; r < 32; r++)
1068 {
1069 for (int g = 0; g < 32; g++)
1070 {
1071 for (int b = 0; b < 32; b++)
1072 {
1073 int rr = (r << 3) | (r >> 2);
1074 int gg = (g << 3) | (g >> 2);
1075 int bb = (b << 3) | (b >> 2);
1076
1077 int index = -1;
1078
1079 if (colors)
1080 {
1081 int max = 3 * 65536;
1082
1083 for (int i = 0; i < m_visualColormapSize; i++)
1084 {
1085 int rdiff = ((rr << 8) - colors[i].red);
1086 int gdiff = ((gg << 8) - colors[i].green);
1087 int bdiff = ((bb << 8) - colors[i].blue);
1088 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
1089 if (sum < max)
1090 {
1091 index = i; max = sum;
1092 }
1093 }
1094 }
1095 else
1096 {
1097 // assume 8-bit true or static colors. this really exists
1098 index = (r >> (5 - m_visualRedPrec)) << m_visualRedShift;
1099 index |= (g >> (5 - m_visualGreenPrec)) << m_visualGreenShift;
1100 index |= (b >> (5 - m_visualBluePrec)) << m_visualBlueShift;
1101 }
1102 m_colorCube[ (r*1024) + (g*32) + b ] = index;
1103 }
1104 }
1105 }
8601b2e1 1106#endif
366e8ae6 1107
83df96d6
JS
1108 return TRUE;
1109}
1110
2b5f62a0
VZ
1111#if wxUSE_UNICODE
1112
1113#include <pango/pango.h>
1114#include <pango/pangox.h>
1115#include <pango/pangoxft.h>
1116
1117PangoContext* wxApp::GetPangoContext()
1118{
1119 static PangoContext *ret = NULL;
1120 if (ret)
1121 return ret;
1122
1123 Display *xdisplay = (Display*) wxApp::GetDisplay();
1124
1125#if 1
1126 int xscreen = DefaultScreen(xdisplay);
1127 static int use_xft = -1;
1128 if (use_xft == -1)
1129 {
1130 wxString val = wxGetenv( L"GDK_USE_XFT" );
1131 use_xft = (val == L"1");
1132 }
1133
1134 if (use_xft)
1135 ret = pango_xft_get_context( xdisplay, xscreen );
1136 else
1137#endif
1138 ret = pango_x_get_context( xdisplay );
1139
1140 if (!PANGO_IS_CONTEXT(ret))
1141 wxLogError( wxT("No pango context.") );
1142
1143 return ret;
1144}
1145#endif
1146
83df96d6
JS
1147WXColormap wxApp::GetMainColormap(WXDisplay* display)
1148{
1149 if (!display) /* Must be called first with non-NULL display */
1150 return m_mainColormap;
1151
1152 int defaultScreen = DefaultScreen((Display*) display);
1153 Screen* screen = XScreenOfDisplay((Display*) display, defaultScreen);
1154
1155 Colormap c = DefaultColormapOfScreen(screen);
1156
1157 if (!m_mainColormap)
1158 m_mainColormap = (WXColormap) c;
1159
1160 return (WXColormap) c;
1161}
1162
8354aa92 1163Window wxGetWindowParent(Window window)
7eaac9f5 1164{
86fd8bda 1165 wxASSERT_MSG( window, "invalid window" );
e2386592 1166
86fd8bda
RR
1167 return (Window) 0;
1168
7eaac9f5 1169 Window parent, root = 0;
c79a329d
JS
1170#if wxUSE_NANOX
1171 int noChildren = 0;
1172#else
7eaac9f5 1173 unsigned int noChildren = 0;
c79a329d 1174#endif
ea596687 1175 Window* children = NULL;
c79a329d 1176
ee351013 1177 // #define XQueryTree(d,w,r,p,c,nc) GrQueryTree(w,p,c,nc)
c79a329d
JS
1178 int res = 1;
1179#if !wxUSE_NANOX
1180 res =
1181#endif
1182 XQueryTree((Display*) wxGetDisplay(), window, & root, & parent,
ee351013 1183 & children, & noChildren);
ea596687
JS
1184 if (children)
1185 XFree(children);
1186 if (res)
7eaac9f5
JS
1187 return parent;
1188 else
1189 return (Window) 0;
1190}
1191
83df96d6
JS
1192void wxExit()
1193{
1194 int retValue = 0;
1195 if (wxTheApp)
1196 retValue = wxTheApp->OnExit();
1197
1198 wxApp::CleanUp();
1199 /*
1200 * Exit in some platform-specific way. Not recommended that the app calls this:
1201 * only for emergencies.
1202 */
1203 exit(retValue);
1204}
1205
1206// Yield to other processes
1207
1208bool wxApp::Yield(bool onlyIfNeeded)
1209{
bbcd408a
JS
1210 // Sometimes only 2 yields seem
1211 // to do the trick, e.g. in the
1212 // progress dialog
1213 int i;
1214 for (i = 0; i < 2; i++)
83df96d6 1215 {
bbcd408a
JS
1216 bool s_inYield = FALSE;
1217
1218 if ( s_inYield )
83df96d6 1219 {
bbcd408a
JS
1220 if ( !onlyIfNeeded )
1221 {
1222 wxFAIL_MSG( wxT("wxYield called recursively" ) );
1223 }
83df96d6 1224
bbcd408a
JS
1225 return FALSE;
1226 }
83df96d6 1227
bbcd408a 1228 s_inYield = TRUE;
83df96d6 1229
bbcd408a
JS
1230 // Make sure we have an event loop object,
1231 // or Pending/Dispatch will fail
1232 wxEventLoop* eventLoop = wxEventLoop::GetActive();
1233 wxEventLoop* newEventLoop = NULL;
1234 if (!eventLoop)
1235 {
1236 newEventLoop = new wxEventLoop;
1237 wxEventLoop::SetActive(newEventLoop);
1238 }
df0e1b64 1239
2b5f62a0
VZ
1240 // Call dispatch at least once so that sockets
1241 // can be tested
1242 wxTheApp->Dispatch();
1243
bbcd408a
JS
1244 while (wxTheApp && wxTheApp->Pending())
1245 wxTheApp->Dispatch();
83df96d6 1246
868741e9 1247#if wxUSE_TIMER
bbcd408a 1248 wxTimer::NotifyTimers();
868741e9 1249#endif
bbcd408a 1250 ProcessIdle();
868741e9 1251
bbcd408a
JS
1252 if (newEventLoop)
1253 {
1254 wxEventLoop::SetActive(NULL);
1255 delete newEventLoop;
1256 }
df0e1b64 1257
bbcd408a
JS
1258 s_inYield = FALSE;
1259 }
83df96d6
JS
1260
1261 return TRUE;
1262}
1263
d715d419
VZ
1264#ifdef __WXDEBUG__
1265
5968a0dc 1266void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
7edcafa4
JS
1267{
1268 // While the GUI isn't working that well, just print out the
1269 // message.
193e19cf 1270#if 1
5968a0dc 1271 wxAppBase::OnAssert(file, line, cond, msg);
7edcafa4
JS
1272#else
1273 wxString msg2;
1274 msg2.Printf("At file %s:%d: %s", file, line, msg);
1275 wxLogDebug(msg2);
1276#endif
1277}
1278
d715d419
VZ
1279#endif // __WXDEBUG__
1280