]> git.saurik.com Git - wxWidgets.git/blame - src/x11/app.cpp
make more wxImage methods const
[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"
20#include "wx/pen.h"
21#include "wx/brush.h"
22#include "wx/cursor.h"
23#include "wx/icon.h"
24#include "wx/palette.h"
25#include "wx/dc.h"
26#include "wx/dialog.h"
27#include "wx/msgdlg.h"
28#include "wx/log.h"
29#include "wx/module.h"
30#include "wx/memory.h"
31#include "wx/log.h"
32#include "wx/intl.h"
33
34#if wxUSE_THREADS
35 #include "wx/thread.h"
36#endif
37
38#if wxUSE_WX_RESOURCES
39 #include "wx/resource.h"
40#endif
41
42#ifdef __VMS__
43#pragma message disable nosimpint
44#endif
83df96d6
JS
45#include <X11/Xlib.h>
46#include <X11/Xutil.h>
47#include <X11/Xresource.h>
48#include <X11/Xatom.h>
49#ifdef __VMS__
50#pragma message enable nosimpint
51#endif
52
7eaac9f5 53#include "wx/x11/private.h"
83df96d6
JS
54
55#include <string.h>
56
57extern char *wxBuffer;
58extern wxList wxPendingDelete;
59
60wxApp *wxTheApp = NULL;
61
62wxHashTable *wxWidgetHashTable = NULL;
63
64IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
65
66BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
67 EVT_IDLE(wxApp::OnIdle)
68END_EVENT_TABLE()
69
70#ifdef __WXDEBUG__
71 typedef int (*XErrorHandlerFunc)(Display *, XErrorEvent *);
72
73 XErrorHandlerFunc gs_pfnXErrorHandler = 0;
74
75 static int wxXErrorHandler(Display *dpy, XErrorEvent *xevent)
76 {
77 // just forward to the default handler for now
78 return gs_pfnXErrorHandler(dpy, xevent);
79 }
80#endif // __WXDEBUG__
81
82long wxApp::sm_lastMessageTime = 0;
83
84bool wxApp::Initialize()
85{
86 wxBuffer = new char[BUFSIZ + 512];
87
88 wxClassInfo::InitializeClasses();
89
90 // GL: I'm annoyed ... I don't know where to put this and I don't want to
91 // create a module for that as it's part of the core.
92#if wxUSE_THREADS
93 wxPendingEventsLocker = new wxCriticalSection();
94#endif
95
96 wxTheColourDatabase = new wxColourDatabase(wxKEY_STRING);
97 wxTheColourDatabase->Initialize();
98
99 wxInitializeStockLists();
100 wxInitializeStockObjects();
101
102#if wxUSE_WX_RESOURCES
103 wxInitializeResourceSystem();
104#endif
105
83df96d6
JS
106 wxBitmap::InitStandardHandlers();
107
108 wxWidgetHashTable = new wxHashTable(wxKEY_INTEGER);
109
110 wxModule::RegisterModules();
111 if (!wxModule::InitializeModules()) return FALSE;
112
113 return TRUE;
114}
115
116void wxApp::CleanUp()
117{
118 delete wxWidgetHashTable;
119 wxWidgetHashTable = NULL;
120
121 wxModule::CleanUpModules();
122
123#if wxUSE_WX_RESOURCES
124 wxCleanUpResourceSystem();
125#endif
126
127 wxDeleteStockObjects() ;
128
129 // Destroy all GDI lists, etc.
130
131 wxDeleteStockLists();
132
133 delete wxTheColourDatabase;
134 wxTheColourDatabase = NULL;
135
83df96d6
JS
136 wxBitmap::CleanUpHandlers();
137
138 delete[] wxBuffer;
139 wxBuffer = NULL;
140
141 wxClassInfo::CleanUpClasses();
142
143 delete wxTheApp;
144 wxTheApp = NULL;
145
146 // GL: I'm annoyed ... I don't know where to put this and I don't want to
147 // create a module for that as it's part of the core.
148#if wxUSE_THREADS
149 delete wxPendingEvents;
150 delete wxPendingEventsLocker;
151#endif
152
153#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
154 // At this point we want to check if there are any memory
155 // blocks that aren't part of the wxDebugContext itself,
156 // as a special case. Then when dumping we need to ignore
157 // wxDebugContext, too.
158 if (wxDebugContext::CountObjectsLeft(TRUE) > 0)
159 {
160 wxLogDebug("There were memory leaks.\n");
161 wxDebugContext::Dump();
162 wxDebugContext::PrintStatistics();
163 }
164#endif
165
166 // do it as the very last thing because everything else can log messages
167 wxLog::DontCreateOnDemand();
168 // do it as the very last thing because everything else can log messages
169 delete wxLog::SetActiveTarget(NULL);
170}
171
172int wxEntry( int argc, char *argv[] )
173{
174#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
175 // This seems to be necessary since there are 'rogue'
176 // objects present at this point (perhaps global objects?)
177 // Setting a checkpoint will ignore them as far as the
178 // memory checking facility is concerned.
179 // Of course you may argue that memory allocated in globals should be
180 // checked, but this is a reasonable compromise.
181 wxDebugContext::SetCheckpoint();
182#endif
183
184 if (!wxApp::Initialize())
185 return FALSE;
186
187 if (!wxTheApp)
188 {
189 if (!wxApp::GetInitializerFunction())
190 {
191 printf( "wxWindows error: No initializer - use IMPLEMENT_APP macro.\n" );
192 return 0;
193 };
194
195 wxTheApp = (wxApp*) (* wxApp::GetInitializerFunction()) ();
196 };
197
198 if (!wxTheApp)
199 {
200 printf( "wxWindows error: wxTheApp == NULL\n" );
201 return 0;
202 };
203
204 wxTheApp->SetClassName(wxFileNameFromPath(argv[0]));
205 wxTheApp->SetAppName(wxFileNameFromPath(argv[0]));
206
207 wxTheApp->argc = argc;
208 wxTheApp->argv = argv;
209
210 // GUI-specific initialization, such as creating an app context.
211 wxTheApp->OnInitGui();
212
213 // Here frames insert themselves automatically into wxTopLevelWindows by
214 // getting created in OnInit().
215
216 int retValue = 0;
217 if (wxTheApp->OnInit())
218 {
219 if (wxTheApp->Initialized()) retValue = wxTheApp->OnRun();
220 }
221
222 // flush the logged messages if any
223 wxLog *pLog = wxLog::GetActiveTarget();
224 if ( pLog != NULL && pLog->HasPendingMessages() )
225 pLog->Flush();
226
227 delete wxLog::SetActiveTarget(new wxLogStderr); // So dialog boxes aren't used
228 // for further messages
229
230 if (wxTheApp->GetTopWindow())
231 {
232 delete wxTheApp->GetTopWindow();
233 wxTheApp->SetTopWindow(NULL);
234 }
235
236 wxTheApp->DeletePendingObjects();
237
238 wxTheApp->OnExit();
239
240 wxApp::CleanUp();
241
242 return retValue;
243};
244
245// Static member initialization
246wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL;
247
248wxApp::wxApp()
249{
250 m_topWindow = NULL;
251 wxTheApp = this;
252 m_className = "";
253 m_wantDebugOutput = TRUE ;
254 m_appName = "";
255 argc = 0;
256 argv = NULL;
257 m_exitOnFrameDelete = TRUE;
83df96d6 258 m_mainColormap = (WXColormap) NULL;
7eaac9f5 259 m_topLevelWidget = (WXWindow) NULL;
83df96d6
JS
260 m_maxRequestSize = 0;
261 m_initialDisplay = (WXDisplay*) 0;
262}
263
264bool wxApp::Initialized()
265{
266 if (GetTopWindow())
267 return TRUE;
268 else
269 return FALSE;
270}
271
272int wxApp::MainLoop()
273{
274 m_keepGoing = TRUE;
275
276 /*
277 * Sit around forever waiting to process X-events. Property Change
278 * event are handled special, because they have to refer to
279 * the root window rather than to a widget. therefore we can't
280 * use an Xt-eventhandler.
281 */
282
7eaac9f5
JS
283 XSelectInput(wxGetDisplay(),
284 XDefaultRootWindow(wxGetDisplay()),
83df96d6
JS
285 PropertyChangeMask);
286
287 XEvent event;
288
289 // Use this flag to allow breaking the loop via wxApp::ExitMainLoop()
290 while (m_keepGoing)
291 {
7eaac9f5 292 XNextEvent(wxGetDisplay(), & event);
83df96d6
JS
293
294 ProcessXEvent((WXEvent*) & event);
295
7eaac9f5 296 if (XtPending(wxGetDisplay()) == 0)
83df96d6
JS
297 {
298 if (!ProcessIdle())
299 {
300#if wxUSE_THREADS
301 // leave the main loop to give other threads a chance to
302 // perform their GUI work
303 wxMutexGuiLeave();
304 wxUsleep(20);
305 wxMutexGuiEnter();
306#endif
307 }
308 }
309
310 }
311
312 return 0;
313}
314
315// Processes an X event.
316void wxApp::ProcessXEvent(WXEvent* _event)
317{
318 XEvent* event = (XEvent*) _event;
7eaac9f5 319
83df96d6
JS
320 if (event->type == KeyPress)
321 {
7eaac9f5
JS
322 if (CheckForAccelerator(_event))
323 {
83df96d6
JS
324 // Do nothing! We intercepted and processed the event as an
325 // accelerator.
326 return;
7eaac9f5 327 }
83df96d6
JS
328#if 1
329 // It seemed before that this hack was redundant and
330 // key down events were being generated by wxCanvasInputEvent.
331 // But no longer - why ???
332 //
7eaac9f5
JS
333 else if (CheckForKeyDown(_event))
334 {
83df96d6
JS
335 // We intercepted and processed the key down event
336 return;
7eaac9f5 337 }
83df96d6 338#endif
7eaac9f5
JS
339 else
340 {
341 // TODO for X11 implementation -- the equivalent of XtDispatchEvent.
342 // Presumably, we need to form the wxEvents and
343 // and send them to the appropriate windows.
344 // XtDispatchEvent(event);
345 return;
346 }
83df96d6
JS
347 }
348 else if (event->type == KeyRelease)
349 {
350 // TODO: work out why we still need this ! -michael
351 //
352 if (CheckForKeyUp(_event))
7eaac9f5
JS
353 {
354 // We intercepted and processed the key up event
355 return;
356 }
357 else
358 {
359 // TODO: The X equivalent of XtDispatchEvent
360 // (see above)
361 // XtDispatchEvent(event);
362 return;
363 }
83df96d6
JS
364 }
365 else if (event->type == PropertyNotify)
366 {
367 HandlePropertyChange(_event);
368 return;
369 }
370 else if (event->type == ResizeRequest)
371 {
7eaac9f5
JS
372 /* Terry Gitnick <terryg@scientech.com> - 1/21/98
373 * If resize event, don't resize until the last resize event for this
374 * window is recieved. Prevents flicker as windows are resized.
375 */
376
377 Display *disp = wxGetDisplay();
83df96d6
JS
378 Window win = event->xany.window;
379 XEvent report;
7eaac9f5 380
83df96d6
JS
381 // to avoid flicker
382 report = * event;
383 while( XCheckTypedWindowEvent (disp, win, ResizeRequest, &report));
7eaac9f5 384
83df96d6
JS
385 // TODO: when implementing refresh optimization, we can use
386 // XtAddExposureToRegion to expand the window's paint region.
7eaac9f5
JS
387
388 // TODO: generate resize event
389 // XtDispatchEvent(event);
83df96d6
JS
390 }
391 else
392 {
7eaac9f5
JS
393 // TODO: generate all other events
394 // XtDispatchEvent(event);
83df96d6
JS
395 }
396}
397
398// Returns TRUE if more time is needed.
399bool wxApp::ProcessIdle()
400{
401 wxIdleEvent event;
402 event.SetEventObject(this);
403 ProcessEvent(event);
404
405 return event.MoreRequested();
406}
407
408void wxApp::ExitMainLoop()
409{
410 m_keepGoing = FALSE;
411}
412
413// Is a message/event pending?
414bool wxApp::Pending()
415{
7eaac9f5 416 XFlush(wxGetDisplay());
83df96d6 417
7eaac9f5 418 return (XPending(wxGetDisplay()) > 0);
83df96d6
JS
419}
420
421// Dispatch a message.
422void wxApp::Dispatch()
423{
83df96d6 424 XEvent event;
7eaac9f5 425 XNextEvent(wxGetDisplay(), & event);
83df96d6
JS
426 ProcessXEvent((WXEvent*) & event);
427}
428
429// This should be redefined in a derived class for
430// handling property change events for XAtom IPC.
431void wxApp::HandlePropertyChange(WXEvent *event)
432{
433 // by default do nothing special
7eaac9f5
JS
434 // TODO: what to do for X11
435 // XtDispatchEvent((XEvent*) event); /* let Motif do the work */
83df96d6
JS
436}
437
438void wxApp::OnIdle(wxIdleEvent& event)
439{
440 static bool inOnIdle = FALSE;
441
442 // Avoid recursion (via ProcessEvent default case)
443 if (inOnIdle)
444 return;
445
446 inOnIdle = TRUE;
447
448 // If there are pending events, we must process them: pending events
449 // are either events to the threads other than main or events posted
450 // with wxPostEvent() functions
451 // GRG: I have moved this here so that all pending events are processed
452 // before starting to delete any objects. This behaves better (in
453 // particular, wrt wxPostEvent) and is coherent with wxGTK's current
454 // behaviour. Also removed the '#if wxUSE_THREADS' around it.
455 // Changed Mar/2000 before 2.1.14
456
457 // Flush pending events.
458 ProcessPendingEvents();
459
460 // 'Garbage' collection of windows deleted with Close().
461 DeletePendingObjects();
462
463 // flush the logged messages if any
464 wxLog *pLog = wxLog::GetActiveTarget();
465 if ( pLog != NULL && pLog->HasPendingMessages() )
466 pLog->Flush();
467
468 // Send OnIdle events to all windows
469 bool needMore = SendIdleEvents();
470
471 if (needMore)
472 event.RequestMore(TRUE);
473
474 inOnIdle = FALSE;
475}
476
477void wxWakeUpIdle()
478{
479 // **** please implement me! ****
480 // Wake up the idle handler processor, even if it is in another thread...
481}
482
483
484// Send idle event to all top-level windows
485bool wxApp::SendIdleEvents()
486{
487 bool needMore = FALSE;
488
489 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
490 while (node)
491 {
492 wxWindow* win = node->GetData();
493 if (SendIdleEvents(win))
494 needMore = TRUE;
495 node = node->GetNext();
496 }
497
498 return needMore;
499}
500
501// Send idle event to window and all subwindows
502bool wxApp::SendIdleEvents(wxWindow* win)
503{
504 bool needMore = FALSE;
505
506 wxIdleEvent event;
507 event.SetEventObject(win);
508 win->ProcessEvent(event);
509
510 if (event.MoreRequested())
511 needMore = TRUE;
512
513 wxNode* node = win->GetChildren().First();
514 while (node)
515 {
516 wxWindow* win = (wxWindow*) node->Data();
517 if (SendIdleEvents(win))
518 needMore = TRUE;
519
520 node = node->Next();
521 }
522 return needMore ;
523}
524
525void wxApp::DeletePendingObjects()
526{
527 wxNode *node = wxPendingDelete.First();
528 while (node)
529 {
530 wxObject *obj = (wxObject *)node->Data();
531
532 delete obj;
533
534 if (wxPendingDelete.Member(obj))
535 delete node;
536
537 // Deleting one object may have deleted other pending
538 // objects, so start from beginning of list again.
539 node = wxPendingDelete.First();
540 }
541}
542
543// Create an application context
544bool wxApp::OnInitGui()
545{
7eaac9f5
JS
546 // TODO: parse argv and get display to pass to XOpenDisplay
547 Display* dpy = XOpenDisplay(NULL);
548 m_initialDisplay = (WXDisplay*) dpy;
83df96d6
JS
549
550 if (!dpy) {
551 wxString className(wxTheApp->GetClassName());
552 wxLogError(_("wxWindows could not open display for '%s': exiting."),
7eaac9f5 553 (const char*) className);
83df96d6
JS
554 exit(-1);
555 }
83df96d6
JS
556
557#ifdef __WXDEBUG__
558 // install the X error handler
559 gs_pfnXErrorHandler = XSetErrorHandler(wxXErrorHandler);
560#endif // __WXDEBUG__
561
7eaac9f5
JS
562 // Do we need to create the top-level window initially?
563#if 0
83df96d6
JS
564 wxTheApp->m_topLevelWidget = (WXWidget) XtAppCreateShell((String)NULL, (const char*) wxTheApp->GetClassName(),
565 applicationShellWidgetClass,dpy,
566 NULL,0) ;
7eaac9f5 567#endif
83df96d6
JS
568
569 GetMainColormap(dpy);
570 m_maxRequestSize = XMaxRequestSize((Display*) dpy);
571
572 return TRUE;
573}
574
575WXColormap wxApp::GetMainColormap(WXDisplay* display)
576{
577 if (!display) /* Must be called first with non-NULL display */
578 return m_mainColormap;
579
580 int defaultScreen = DefaultScreen((Display*) display);
581 Screen* screen = XScreenOfDisplay((Display*) display, defaultScreen);
582
583 Colormap c = DefaultColormapOfScreen(screen);
584
585 if (!m_mainColormap)
586 m_mainColormap = (WXColormap) c;
587
588 return (WXColormap) c;
589}
590
7eaac9f5
JS
591static Window XGetParent(Window window)
592{
593 Window parent, root = 0;
594 unsigned int noChildren = 0;
595 if (XQueryTree(wxGetDisplay(), window, & root, & parent,
596 NULL, & noChildren))
597 return parent;
598 else
599 return (Window) 0;
600}
601
83df96d6
JS
602// Returns TRUE if an accelerator has been processed
603bool wxApp::CheckForAccelerator(WXEvent* event)
604{
605 XEvent* xEvent = (XEvent*) event;
606 if (xEvent->xany.type == KeyPress)
607 {
608 // Find a wxWindow for this window
609 // TODO: should get display for the window, not the current display
7eaac9f5 610 Window window = xEvent->xany.window;
83df96d6
JS
611 wxWindow* win = NULL;
612
613 // Find the first wxWindow that corresponds to this event window
7eaac9f5
JS
614 while (window && !(win = wxGetWindowFromTable(window)))
615 window = XGetParent(window);
83df96d6 616
7eaac9f5 617 if (!window || !win)
83df96d6
JS
618 return FALSE;
619
620 wxKeyEvent keyEvent(wxEVT_CHAR);
7eaac9f5 621 wxTranslateKeyEvent(keyEvent, win, (Window) 0, xEvent);
83df96d6
JS
622
623 // Now we have a wxKeyEvent and we have a wxWindow.
624 // Go up the hierarchy until we find a matching accelerator,
625 // or we get to the top.
626 while (win)
627 {
628 if (win->ProcessAccelerator(keyEvent))
629 return TRUE;
630 win = win->GetParent();
631 }
632 return FALSE;
633 }
634 return FALSE;
635}
636
637bool wxApp::CheckForKeyDown(WXEvent* event)
638{
639 XEvent* xEvent = (XEvent*) event;
640 if (xEvent->xany.type == KeyPress)
641 {
7eaac9f5
JS
642 Window window = xEvent->xany.window;
643 wxWindow* win = NULL;
644
645 // Find the first wxWindow that corresponds to this event window
646 while (window && !(win = wxGetWindowFromTable(window)))
647 window = XGetParent(window);
648
649 if (!window || !win)
83df96d6 650 return FALSE;
7eaac9f5
JS
651
652 wxKeyEvent keyEvent(wxEVT_KEY_DOWN);
653 wxTranslateKeyEvent(keyEvent, win, (Window) 0, xEvent);
654
655 return win->ProcessEvent( keyEvent );
83df96d6 656 }
7eaac9f5 657
83df96d6
JS
658 return FALSE;
659}
660
661bool wxApp::CheckForKeyUp(WXEvent* event)
662{
663 XEvent* xEvent = (XEvent*) event;
664 if (xEvent->xany.type == KeyRelease)
665 {
7eaac9f5 666 Window window = xEvent->xany.window;
83df96d6 667 wxWindow* win = NULL;
7eaac9f5 668
83df96d6 669 // Find the first wxWindow that corresponds to this event window
7eaac9f5
JS
670 while (window && !(win = wxGetWindowFromTable(window)))
671 window = XGetParent(window);
672
673 if (!window || !win)
674 return FALSE;
675
83df96d6 676 wxKeyEvent keyEvent(wxEVT_KEY_UP);
7eaac9f5
JS
677 wxTranslateKeyEvent(keyEvent, win, (Window) 0, xEvent);
678
83df96d6
JS
679 return win->ProcessEvent( keyEvent );
680 }
681
682 return FALSE;
683}
684
685void wxExit()
686{
687 int retValue = 0;
688 if (wxTheApp)
689 retValue = wxTheApp->OnExit();
690
691 wxApp::CleanUp();
692 /*
693 * Exit in some platform-specific way. Not recommended that the app calls this:
694 * only for emergencies.
695 */
696 exit(retValue);
697}
698
699// Yield to other processes
700
701bool wxApp::Yield(bool onlyIfNeeded)
702{
703 bool s_inYield = FALSE;
704
705 if ( s_inYield )
706 {
707 if ( !onlyIfNeeded )
708 {
709 wxFAIL_MSG( wxT("wxYield called recursively" ) );
710 }
711
712 return FALSE;
713 }
714
715 s_inYield = TRUE;
716
717 while (wxTheApp && wxTheApp->Pending())
718 wxTheApp->Dispatch();
719
720 s_inYield = FALSE;
721
722 return TRUE;
723}
724
725// TODO use XmGetPixmap (?) to get the really standard icons!
726
727// XPM hack: make the arrays const
728#define static static const
729
730#include "wx/generic/info.xpm"
731#include "wx/generic/error.xpm"
732#include "wx/generic/question.xpm"
733#include "wx/generic/warning.xpm"
734
735#undef static
736
737wxIcon
738wxApp::GetStdIcon(int which) const
739{
740 switch(which)
741 {
742 case wxICON_INFORMATION:
743 return wxIcon(info_xpm);
744
745 case wxICON_QUESTION:
746 return wxIcon(question_xpm);
747
748 case wxICON_EXCLAMATION:
749 return wxIcon(warning_xpm);
750
751 default:
752 wxFAIL_MSG("requested non existent standard icon");
753 // still fall through
754
755 case wxICON_HAND:
756 return wxIcon(error_xpm);
757 }
758}
759
760// ----------------------------------------------------------------------------
761// accessors for C modules
762// ----------------------------------------------------------------------------
763
7eaac9f5 764#if 0
83df96d6
JS
765extern "C" XtAppContext wxGetAppContext()
766{
767 return (XtAppContext)wxTheApp->GetAppContext();
768}
7eaac9f5 769#endif