1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "app.h"
19 #include "wx/gdicmn.h"
21 #include "wx/dialog.h"
23 #include "wx/module.h"
24 #include "wx/memory.h"
27 #include "wx/evtloop.h"
29 #include "wx/univ/theme.h"
30 #include "wx/univ/renderer.h"
33 #include "wx/thread.h"
36 #if wxUSE_WX_RESOURCES
37 #include "wx/resource.h"
41 #pragma message disable nosimpint
44 #include <X11/Xutil.h>
45 #include <X11/Xatom.h>
48 #pragma message enable nosimpint
51 #include "wx/x11/private.h"
55 extern wxList wxPendingDelete
;
57 wxApp
*wxTheApp
= NULL
;
59 wxHashTable
*wxWidgetHashTable
= NULL
;
61 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
)
63 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
64 EVT_IDLE(wxApp::OnIdle
)
68 typedef int (*XErrorHandlerFunc
)(Display
*, XErrorEvent
*);
70 XErrorHandlerFunc gs_pfnXErrorHandler
= 0;
72 static int wxXErrorHandler(Display
*dpy
, XErrorEvent
*xevent
)
74 // just forward to the default handler for now
75 if (gs_pfnXErrorHandler
)
76 return gs_pfnXErrorHandler(dpy
, xevent
);
82 long wxApp::sm_lastMessageTime
= 0;
83 WXDisplay
*wxApp::ms_display
= NULL
;
85 // This is set within wxEntryStart -- too early on
86 // to put these in wxTheApp
87 static int g_newArgc
= 0;
88 static wxChar
** g_newArgv
= NULL
;
89 static bool g_showIconic
= FALSE
;
90 static wxSize g_initialSize
= wxDefaultSize
;
92 bool wxApp::Initialize()
94 wxClassInfo::InitializeClasses();
96 // GL: I'm annoyed ... I don't know where to put this and I don't want to
97 // create a module for that as it's part of the core.
99 wxPendingEventsLocker
= new wxCriticalSection();
102 wxTheColourDatabase
= new wxColourDatabase(wxKEY_STRING
);
103 wxTheColourDatabase
->Initialize();
105 wxInitializeStockLists();
106 wxInitializeStockObjects();
108 #if wxUSE_WX_RESOURCES
109 wxInitializeResourceSystem();
112 wxWidgetHashTable
= new wxHashTable(wxKEY_INTEGER
);
114 wxModule::RegisterModules();
115 if (!wxModule::InitializeModules()) return FALSE
;
120 void wxApp::CleanUp()
126 delete wxWidgetHashTable
;
127 wxWidgetHashTable
= NULL
;
129 wxModule::CleanUpModules();
131 #if wxUSE_WX_RESOURCES
132 wxCleanUpResourceSystem();
135 delete wxTheColourDatabase
;
136 wxTheColourDatabase
= NULL
;
138 wxDeleteStockObjects();
140 wxDeleteStockLists();
145 wxClassInfo::CleanUpClasses();
148 delete wxPendingEvents
;
149 delete wxPendingEventsLocker
;
152 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
153 // At this point we want to check if there are any memory
154 // blocks that aren't part of the wxDebugContext itself,
155 // as a special case. Then when dumping we need to ignore
156 // wxDebugContext, too.
157 if (wxDebugContext::CountObjectsLeft(TRUE
) > 0)
159 wxLogDebug("There were memory leaks.");
160 wxDebugContext::Dump();
161 wxDebugContext::PrintStatistics();
165 // do it as the very last thing because everything else can log messages
166 wxLog::DontCreateOnDemand();
167 // do it as the very last thing because everything else can log messages
168 delete wxLog::SetActiveTarget(NULL
);
171 // NB: argc and argv may be changed here, pass by reference!
172 int wxEntryStart( int& argc
, char *argv
[] )
175 // install the X error handler
176 gs_pfnXErrorHandler
= XSetErrorHandler( wxXErrorHandler
);
177 #endif // __WXDEBUG__
179 wxString displayName
;
180 bool syncDisplay
= FALSE
;
182 // Parse the arguments.
183 // We can't use wxCmdLineParser or OnInitCmdLine and friends because
184 // we have to create the Display earlier. If we can find a way to
185 // use the wxAppBase API then I'll be quite happy to change it.
186 g_newArgv
= new wxChar
*[argc
];
189 for (i
= 0; i
< argc
; i
++)
191 wxString
arg(argv
[i
]);
192 if (arg
== wxT("-display"))
197 displayName
= argv
[i
];
201 else if (arg
== wxT("-geometry"))
206 wxString windowGeometry
= argv
[i
];
208 if (wxSscanf(windowGeometry
.c_str(), _T("%dx%d"), &w
, &h
) != 2)
210 wxLogError(_("Invalid geometry specification '%s'"), windowGeometry
.c_str());
214 g_initialSize
= wxSize(w
, h
);
219 else if (arg
== wxT("-sync"))
224 else if (arg
== wxT("-iconic"))
231 // Not eaten by wxWindows, so pass through
232 g_newArgv
[g_newArgc
] = argv
[i
];
236 Display
* xdisplay
= NULL
;
237 if (displayName
.IsEmpty())
238 xdisplay
= XOpenDisplay(NULL
);
240 xdisplay
= XOpenDisplay((char*) displayName
.c_str());
244 wxLogError( _("wxWindows could not open display. Exiting.") );
250 XSynchronize(xdisplay
, True
);
253 wxApp::ms_display
= (WXDisplay
*) xdisplay
;
255 XSelectInput( xdisplay
, XDefaultRootWindow(xdisplay
), PropertyChangeMask
);
257 wxSetDetectableAutoRepeat( TRUE
);
259 if (!wxApp::Initialize())
269 if ( !wxTheApp
->OnInitGui() )
276 int wxEntry( int argc
, char *argv
[] )
278 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
279 // This seems to be necessary since there are 'rogue'
280 // objects present at this point (perhaps global objects?)
281 // Setting a checkpoint will ignore them as far as the
282 // memory checking facility is concerned.
283 // Of course you may argue that memory allocated in globals should be
284 // checked, but this is a reasonable compromise.
285 wxDebugContext::SetCheckpoint();
287 int err
= wxEntryStart(argc
, argv
);
293 if (!wxApp::GetInitializerFunction())
295 printf( "wxWindows error: No initializer - use IMPLEMENT_APP macro.\n" );
299 wxTheApp
= (wxApp
*) (* wxApp::GetInitializerFunction()) ();
304 printf( "wxWindows error: wxTheApp == NULL\n" );
308 wxTheApp
->SetClassName(wxFileNameFromPath(argv
[0]));
309 wxTheApp
->SetAppName(wxFileNameFromPath(argv
[0]));
311 // The command line may have been changed
312 // by stripping out -display etc.
315 wxTheApp
->argc
= g_newArgc
;
316 wxTheApp
->argv
= g_newArgv
;
320 wxTheApp
->argc
= argc
;
321 wxTheApp
->argv
= argv
;
323 wxTheApp
->m_showIconic
= g_showIconic
;
324 wxTheApp
->m_initialSize
= g_initialSize
;
327 retValue
= wxEntryInitGui();
329 // Here frames insert themselves automatically into wxTopLevelWindows by
330 // getting created in OnInit().
333 if ( !wxTheApp
->OnInit() )
339 if (wxTheApp
->Initialized()) retValue
= wxTheApp
->OnRun();
342 // flush the logged messages if any
343 wxLog
*pLog
= wxLog::GetActiveTarget();
344 if ( pLog
!= NULL
&& pLog
->HasPendingMessages() )
347 delete wxLog::SetActiveTarget(new wxLogStderr
); // So dialog boxes aren't used
348 // for further messages
350 if (wxTheApp
->GetTopWindow())
352 delete wxTheApp
->GetTopWindow();
353 wxTheApp
->SetTopWindow(NULL
);
356 wxTheApp
->DeletePendingObjects();
365 // Static member initialization
366 wxAppInitializerFunction
wxAppBase::m_appInitFn
= (wxAppInitializerFunction
) NULL
;
373 m_wantDebugOutput
= TRUE
;
377 m_exitOnFrameDelete
= TRUE
;
378 m_mainColormap
= (WXColormap
) NULL
;
379 m_topLevelWidget
= (WXWindow
) NULL
;
380 m_maxRequestSize
= 0;
382 m_showIconic
= FALSE
;
383 m_initialSize
= wxDefaultSize
;
386 bool wxApp::Initialized()
394 int wxApp::MainLoop()
397 m_mainLoop
= new wxEventLoop
;
399 rt
= m_mainLoop
->Run();
406 // Processes an X event.
407 void wxApp::ProcessXEvent(WXEvent
* _event
)
409 XEvent
* event
= (XEvent
*) _event
;
411 wxWindow
* win
= NULL
;
412 Window window
= XEventGetWindow(event
);
413 Window actualWindow
= window
;
415 // Find the first wxWindow that corresponds to this event window
416 // Because we're receiving events after a window
417 // has been destroyed, assume a 1:1 match between
418 // Window and wxWindow, so if it's not in the table,
419 // it must have been destroyed.
421 win
= wxGetWindowFromTable(window
);
429 if (win
&& !win
->IsEnabled())
435 wxKeyEvent
keyEvent(wxEVT_KEY_DOWN
);
436 wxTranslateKeyEvent(keyEvent
, win
, window
, event
);
438 wxLogDebug( "OnKey from %s", win
->GetName().c_str() );
440 // We didn't process wxEVT_KEY_DOWN, so send
442 if (!win
->GetEventHandler()->ProcessEvent( keyEvent
))
444 keyEvent
.SetEventType(wxEVT_CHAR
);
445 win
->GetEventHandler()->ProcessEvent( keyEvent
);
448 // We intercepted and processed the key down event
456 if (win
&& !win
->IsEnabled())
461 wxKeyEvent
keyEvent(wxEVT_KEY_UP
);
462 wxTranslateKeyEvent(keyEvent
, win
, window
, event
);
464 win
->GetEventHandler()->ProcessEvent( keyEvent
);
468 case ConfigureNotify
:
472 && (event
->update
.utype
== GR_UPDATE_SIZE
)
476 wxSizeEvent
sizeEvent( wxSize(XConfigureEventGetWidth(event
), XConfigureEventGetHeight(event
)), win
->GetId() );
477 sizeEvent
.SetEventObject( win
);
479 win
->GetEventHandler()->ProcessEvent( sizeEvent
);
485 HandlePropertyChange(_event
);
490 if (win
&& !win
->IsEnabled())
493 Atom wm_delete_window
= XInternAtom(wxGlobalDisplay(), "WM_DELETE_WINDOW", True
);
494 Atom wm_protocols
= XInternAtom(wxGlobalDisplay(), "WM_PROTOCOLS", True
);
496 if (event
->xclient
.message_type
== wm_protocols
)
498 if ((Atom
) (event
->xclient
.data
.l
[0]) == wm_delete_window
)
511 * If resize event, don't resize until the last resize event for this
512 * window is recieved. Prevents flicker as windows are resized.
515 Display
*disp
= (Display
*) wxGetDisplay();
520 while( XCheckTypedWindowEvent (disp
, actualWindow
, ResizeRequest
, &report
));
524 wxSize sz
= win
->GetSize();
525 wxSizeEvent
sizeEvent(sz
, win
->GetId());
526 sizeEvent
.SetEventObject(win
);
528 win
->GetEventHandler()->ProcessEvent( sizeEvent
);
535 case GR_EVENT_TYPE_CLOSE_REQ
:
548 win
->GetUpdateRegion().Union( XExposeEventGetX(event
), XExposeEventGetY(event
),
549 XExposeEventGetWidth(event
), XExposeEventGetHeight(event
));
551 win
->GetClearRegion().Union( XExposeEventGetX(event
), XExposeEventGetY(event
),
552 XExposeEventGetWidth(event
), XExposeEventGetHeight(event
));
555 if (event
->xexpose
.count
== 0)
558 // Only erase background, paint in idle time.
559 win
->SendEraseEvents();
570 // wxLogDebug( "GraphicsExpose from %s", win->GetName().c_str(),
571 // event->xgraphicsexpose.x, event->xgraphicsexpose.y,
572 // event->xgraphicsexpose.width, event->xgraphicsexpose.height);
574 win
->GetUpdateRegion().Union( event
->xgraphicsexpose
.x
, event
->xgraphicsexpose
.y
,
575 event
->xgraphicsexpose
.width
, event
->xgraphicsexpose
.height
);
577 win
->GetClearRegion().Union( event
->xgraphicsexpose
.x
, event
->xgraphicsexpose
.y
,
578 event
->xgraphicsexpose
.width
, event
->xgraphicsexpose
.height
);
580 if (event
->xgraphicsexpose
.count
== 0)
582 // Only erase background, paint in idle time.
583 win
->SendEraseEvents();
599 if (!win
->IsEnabled())
603 if (event
->type
== ButtonPress
)
605 if ((win
!= wxWindow::FindFocus()) && win
->AcceptsFocus())
610 wxMouseEvent wxevent
;
611 wxTranslateMouseEvent(wxevent
, win
, window
, event
);
612 win
->GetEventHandler()->ProcessEvent( wxevent
);
618 if (win
&& event
->xfocus
.detail
!= NotifyPointer
)
621 wxLogDebug( "FocusIn from %s", win
->GetName().c_str() );
623 wxFocusEvent
focusEvent(wxEVT_SET_FOCUS
, win
->GetId());
624 focusEvent
.SetEventObject(win
);
625 win
->GetEventHandler()->ProcessEvent(focusEvent
);
632 if (win
&& event
->xfocus
.detail
!= NotifyPointer
)
635 wxLogDebug( "FocusOut from %s", win
->GetName().c_str() );
637 wxFocusEvent
focusEvent(wxEVT_KILL_FOCUS
, win
->GetId());
638 focusEvent
.SetEventObject(win
);
639 win
->GetEventHandler()->ProcessEvent(focusEvent
);
646 // Do we want to process this (for top-level windows)?
647 // But we want to be able to veto closes, anyway
654 //wxString eventName = wxGetXEventName(XEvent& event);
655 //wxLogDebug(wxT("Event %s not handled"), eventName.c_str());
662 // Returns TRUE if more time is needed.
663 // Note that this duplicates wxEventLoopImpl::SendIdleEvent
664 // but ProcessIdle may be needed by apps, so is kept.
665 bool wxApp::ProcessIdle()
668 event
.SetEventObject(this);
671 return event
.MoreRequested();
674 void wxApp::ExitMainLoop()
680 // Is a message/event pending?
681 bool wxApp::Pending()
683 return wxEventLoop::GetActive()->Pending();
686 // Dispatch a message.
687 void wxApp::Dispatch()
689 wxEventLoop::GetActive()->Dispatch();
692 // This should be redefined in a derived class for
693 // handling property change events for XAtom IPC.
694 void wxApp::HandlePropertyChange(WXEvent
*event
)
696 // by default do nothing special
697 // TODO: what to do for X11
698 // XtDispatchEvent((XEvent*) event);
701 void wxApp::OnIdle(wxIdleEvent
& event
)
703 static bool s_inOnIdle
= FALSE
;
705 // Avoid recursion (via ProcessEvent default case)
711 // Resend in the main thread events which have been prepared in other
713 ProcessPendingEvents();
715 // 'Garbage' collection of windows deleted with Close()
716 DeletePendingObjects();
718 // Send OnIdle events to all windows
719 bool needMore
= SendIdleEvents();
722 event
.RequestMore(TRUE
);
729 // **** please implement me! ****
730 // Wake up the idle handler processor, even if it is in another thread...
734 // Send idle event to all top-level windows
735 bool wxApp::SendIdleEvents()
737 bool needMore
= FALSE
;
739 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
742 wxWindow
* win
= node
->GetData();
743 if (SendIdleEvents(win
))
745 node
= node
->GetNext();
751 // Send idle event to window and all subwindows
752 bool wxApp::SendIdleEvents(wxWindow
* win
)
754 bool needMore
= FALSE
;
757 event
.SetEventObject(win
);
759 win
->GetEventHandler()->ProcessEvent(event
);
761 win
->OnInternalIdle();
763 if (event
.MoreRequested())
766 wxNode
* node
= win
->GetChildren().First();
769 wxWindow
* win
= (wxWindow
*) node
->Data();
770 if (SendIdleEvents(win
))
779 void wxApp::DeletePendingObjects()
781 wxNode
*node
= wxPendingDelete
.First();
784 wxObject
*obj
= (wxObject
*)node
->Data();
788 if (wxPendingDelete
.Member(obj
))
791 // Deleting one object may have deleted other pending
792 // objects, so start from beginning of list again.
793 node
= wxPendingDelete
.First();
797 // Create display, and other initialization
798 bool wxApp::OnInitGui()
800 // Eventually this line will be removed, but for
801 // now we don't want to try popping up a dialog
802 // for error messages.
803 delete wxLog::SetActiveTarget(new wxLogStderr
);
805 if (!wxAppBase::OnInitGui())
808 GetMainColormap( wxApp::GetDisplay() );
810 m_maxRequestSize
= XMaxRequestSize( (Display
*) wxApp::GetDisplay() );
815 WXColormap
wxApp::GetMainColormap(WXDisplay
* display
)
817 if (!display
) /* Must be called first with non-NULL display */
818 return m_mainColormap
;
820 int defaultScreen
= DefaultScreen((Display
*) display
);
821 Screen
* screen
= XScreenOfDisplay((Display
*) display
, defaultScreen
);
823 Colormap c
= DefaultColormapOfScreen(screen
);
826 m_mainColormap
= (WXColormap
) c
;
828 return (WXColormap
) c
;
831 Window
wxGetWindowParent(Window window
)
833 wxASSERT_MSG( window
, "invalid window" );
837 Window parent
, root
= 0;
841 unsigned int noChildren
= 0;
843 Window
* children
= NULL
;
845 // #define XQueryTree(d,w,r,p,c,nc) GrQueryTree(w,p,c,nc)
850 XQueryTree((Display
*) wxGetDisplay(), window
, & root
, & parent
,
851 & children
, & noChildren
);
864 retValue
= wxTheApp
->OnExit();
868 * Exit in some platform-specific way. Not recommended that the app calls this:
869 * only for emergencies.
874 // Yield to other processes
876 bool wxApp::Yield(bool onlyIfNeeded
)
878 bool s_inYield
= FALSE
;
884 wxFAIL_MSG( wxT("wxYield called recursively" ) );
892 while (wxTheApp
&& wxTheApp
->Pending())
893 wxTheApp
->Dispatch();
900 wxIcon
wxApp::GetStdIcon(int which
) const
902 return wxTheme::Get()->GetRenderer()->GetStdIcon(which
);
905 void wxApp::OnAssert(const wxChar
*file
, int line
, const wxChar
*msg
)
907 // While the GUI isn't working that well, just print out the
910 wxAppBase::OnAssert(file
, line
, msg
);
913 msg2
.Printf("At file %s:%d: %s", file
, line
, msg
);