X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/83df96d63a52ebb08b9e32549dc255354b4a18d0..61aa560b2d217d4ae0a6d5c35c22317a3f65fe5d:/src/x11/app.cpp diff --git a/src/x11/app.cpp b/src/x11/app.cpp index 8b019fdf6e..62cb336b78 100644 --- a/src/x11/app.cpp +++ b/src/x11/app.cpp @@ -13,11 +13,6 @@ #pragma implementation "app.h" #endif -#ifdef __VMS -#define XtParent XTPARENT -#define XtDisplay XTDISPLAY -#endif - #include "wx/frame.h" #include "wx/app.h" #include "wx/utils.h" @@ -26,8 +21,6 @@ #include "wx/brush.h" #include "wx/cursor.h" #include "wx/icon.h" -#include "wx/palette.h" -#include "wx/dc.h" #include "wx/dialog.h" #include "wx/msgdlg.h" #include "wx/log.h" @@ -35,6 +28,7 @@ #include "wx/memory.h" #include "wx/log.h" #include "wx/intl.h" +#include "wx/evtloop.h" #if wxUSE_THREADS #include "wx/thread.h" @@ -47,7 +41,6 @@ #ifdef __VMS__ #pragma message disable nosimpint #endif -#include #include #include #include @@ -56,7 +49,7 @@ #pragma message enable nosimpint #endif -#include "wx/motif/private.h" +#include "wx/x11/private.h" #include @@ -74,18 +67,19 @@ BEGIN_EVENT_TABLE(wxApp, wxEvtHandler) END_EVENT_TABLE() #ifdef __WXDEBUG__ - typedef int (*XErrorHandlerFunc)(Display *, XErrorEvent *); +typedef int (*XErrorHandlerFunc)(Display *, XErrorEvent *); - XErrorHandlerFunc gs_pfnXErrorHandler = 0; +XErrorHandlerFunc gs_pfnXErrorHandler = 0; - static int wxXErrorHandler(Display *dpy, XErrorEvent *xevent) - { - // just forward to the default handler for now - return gs_pfnXErrorHandler(dpy, xevent); - } +static int wxXErrorHandler(Display *dpy, XErrorEvent *xevent) +{ + // just forward to the default handler for now + return gs_pfnXErrorHandler(dpy, xevent); +} #endif // __WXDEBUG__ long wxApp::sm_lastMessageTime = 0; +WXDisplay *wxApp::ms_display = NULL; bool wxApp::Initialize() { @@ -109,17 +103,6 @@ bool wxApp::Initialize() wxInitializeResourceSystem(); #endif - // For PostScript printing -#if wxUSE_POSTSCRIPT - /* Done using wxModule now - wxInitializePrintSetupData(); - wxThePrintPaperDatabase = new wxPrintPaperDatabase; - wxThePrintPaperDatabase->CreateDatabase(); - */ -#endif - - wxBitmap::InitStandardHandlers(); - wxWidgetHashTable = new wxHashTable(wxKEY_INTEGER); wxModule::RegisterModules(); @@ -139,35 +122,21 @@ void wxApp::CleanUp() wxCleanUpResourceSystem(); #endif - wxDeleteStockObjects() ; - - // Destroy all GDI lists, etc. - - wxDeleteStockLists(); - delete wxTheColourDatabase; wxTheColourDatabase = NULL; -#if wxUSE_POSTSCRIPT - /* Done using wxModule now - wxInitializePrintSetupData(FALSE); - delete wxThePrintPaperDatabase; - wxThePrintPaperDatabase = NULL; - */ -#endif + wxDeleteStockObjects(); + + wxDeleteStockLists(); - wxBitmap::CleanUpHandlers(); + delete wxTheApp; + wxTheApp = NULL; delete[] wxBuffer; wxBuffer = NULL; wxClassInfo::CleanUpClasses(); - delete wxTheApp; - wxTheApp = NULL; - - // GL: I'm annoyed ... I don't know where to put this and I don't want to - // create a module for that as it's part of the core. #if wxUSE_THREADS delete wxPendingEvents; delete wxPendingEventsLocker; @@ -192,6 +161,46 @@ void wxApp::CleanUp() delete wxLog::SetActiveTarget(NULL); } +// NB: argc and argv may be changed here, pass by reference! +int wxEntryStart( int& argc, char *argv[] ) +{ +#ifdef __WXDEBUG__ + // install the X error handler + gs_pfnXErrorHandler = XSetErrorHandler( wxXErrorHandler ); +#endif // __WXDEBUG__ + + Display* xdisplay = XOpenDisplay(NULL); + + if (!xdisplay) + { + wxLogError( _("wxWindows could not open display. Exiting.") ); + return -1; + } + + wxApp::ms_display = (WXDisplay*) xdisplay; + + XSelectInput( xdisplay, XDefaultRootWindow(xdisplay), PropertyChangeMask); + +// wxSetDetectableAutoRepeat( TRUE ); + + if (!wxApp::Initialize()) + return -1; + + return 0; +} + + +int wxEntryInitGui() +{ + int retValue = 0; + + if ( !wxTheApp->OnInitGui() ) + retValue = -1; + + return retValue; +} + + int wxEntry( int argc, char *argv[] ) { #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT @@ -203,9 +212,9 @@ int wxEntry( int argc, char *argv[] ) // checked, but this is a reasonable compromise. wxDebugContext::SetCheckpoint(); #endif - - if (!wxApp::Initialize()) - return FALSE; + int err = wxEntryStart(argc, argv); + if (err) + return err; if (!wxTheApp) { @@ -230,14 +239,18 @@ int wxEntry( int argc, char *argv[] ) wxTheApp->argc = argc; wxTheApp->argv = argv; - // GUI-specific initialization, such as creating an app context. - wxTheApp->OnInitGui(); + int retValue; + retValue = wxEntryInitGui(); // Here frames insert themselves automatically into wxTopLevelWindows by // getting created in OnInit(). + if ( retValue == 0 ) + { + if ( !wxTheApp->OnInit() ) + retValue = -1; + } - int retValue = 0; - if (wxTheApp->OnInit()) + if ( retValue == 0 ) { if (wxTheApp->Initialized()) retValue = wxTheApp->OnRun(); } @@ -278,12 +291,10 @@ wxApp::wxApp() argc = 0; argv = NULL; m_exitOnFrameDelete = TRUE; - m_mainColormap = (WXColormap) NULL; - m_appContext = (WXAppContext) NULL; - m_topLevelWidget = (WXWidget) NULL; + m_topLevelWidget = (WXWindow) NULL; m_maxRequestSize = 0; - m_initialDisplay = (WXDisplay*) 0; + m_mainLoop = NULL; } bool wxApp::Initialized() @@ -296,45 +307,14 @@ bool wxApp::Initialized() int wxApp::MainLoop() { - m_keepGoing = TRUE; - - /* - * Sit around forever waiting to process X-events. Property Change - * event are handled special, because they have to refer to - * the root window rather than to a widget. therefore we can't - * use an Xt-eventhandler. - */ - - XSelectInput(XtDisplay((Widget) wxTheApp->GetTopLevelWidget()), - XDefaultRootWindow(XtDisplay((Widget) wxTheApp->GetTopLevelWidget())), - PropertyChangeMask); - - XEvent event; - - // Use this flag to allow breaking the loop via wxApp::ExitMainLoop() - while (m_keepGoing) - { - XtAppNextEvent( (XtAppContext) wxTheApp->GetAppContext(), &event); - - ProcessXEvent((WXEvent*) & event); - - if (XtAppPending( (XtAppContext) wxTheApp->GetAppContext() ) == 0) - { - if (!ProcessIdle()) - { -#if wxUSE_THREADS - // leave the main loop to give other threads a chance to - // perform their GUI work - wxMutexGuiLeave(); - wxUsleep(20); - wxMutexGuiEnter(); -#endif - } - } + int rt; + m_mainLoop = new wxEventLoop; - } + rt = m_mainLoop->Run(); - return 0; + delete m_mainLoop; + m_mainLoop = NULL; + return rt; } // Processes an X event. @@ -342,84 +322,190 @@ void wxApp::ProcessXEvent(WXEvent* _event) { XEvent* event = (XEvent*) _event; - if (event->type == KeyPress) - { -#if 0 // def __WXDEBUG__ - Widget widget = XtWindowToWidget(event->xany.display, event->xany.window); - wxLogDebug("Got key press event for 0x%08x (parent = 0x%08x)", - widget, XtParent(widget)); -#endif // DEBUG + wxWindow* win = NULL; + Window window = event->xany.window; + Window actualWindow = window; + + // Find the first wxWindow that corresponds to this event window + // TODO: may need to translate coordinates from actualWindow + // to window, if the receiving window != wxWindow window + // while (window && !(win = wxGetWindowFromTable(window))) + // window = wxGetWindowParent(window); + + // Because we're receiving events after a window + // has been destroyed, assume a 1:1 match between + // Window and wxWindow, so if it's not in the table, + // it must have been destroyed. + + win = wxGetWindowFromTable(window); + if (!win) + return; - if (CheckForAccelerator(_event)) + switch (event->type) { - // Do nothing! We intercepted and processed the event as an - // accelerator. + case KeyPress: + { + if (win && !win->IsEnabled()) + return; + + { + if (win) + { + wxKeyEvent keyEvent(wxEVT_KEY_DOWN); + wxTranslateKeyEvent(keyEvent, win, window, event); + + // We didn't process wxEVT_KEY_DOWN, so send + // wxEVT_CHAR + if (!win->GetEventHandler()->ProcessEvent( keyEvent )) + { + keyEvent.SetEventType(wxEVT_CHAR); + win->GetEventHandler()->ProcessEvent( keyEvent ); + } + + // We intercepted and processed the key down event + return; + } + } return; - } -#if 1 - // It seemed before that this hack was redundant and - // key down events were being generated by wxCanvasInputEvent. - // But no longer - why ??? - // - else if (CheckForKeyDown(_event)) - { - // We intercepted and processed the key down event + } + case KeyRelease: + { + if (win && !win->IsEnabled()) + return; + + if (win) + { + wxKeyEvent keyEvent(wxEVT_KEY_UP); + wxTranslateKeyEvent(keyEvent, win, window, event); + + win->GetEventHandler()->ProcessEvent( keyEvent ); + } return; - } -#endif - else - { - XtDispatchEvent(event); - return; - } - } - else if (event->type == KeyRelease) - { - // TODO: work out why we still need this ! -michael - // - if (CheckForKeyUp(_event)) - { - // We intercepted and processed the key up event - return; - } - else - { - XtDispatchEvent(event); - return; - } - } - else if (event->type == PropertyNotify) - { - HandlePropertyChange(_event); - return; - } - else if (event->type == ResizeRequest) - { - /* Terry Gitnick - 1/21/98 - * If resize event, don't resize until the last resize event for this - * window is recieved. Prevents flicker as windows are resized. - */ + } + case PropertyNotify: + { + HandlePropertyChange(_event); + return; + } + case ClientMessage: + { + Atom wm_delete_window = XInternAtom(wxGlobalDisplay(), "WM_DELETE_WINDOW", True);; + Atom wm_protocols = XInternAtom(wxGlobalDisplay(), "WM_PROTOCOLS", True);; - Display *disp = XtDisplay((Widget) wxTheApp->GetTopLevelWidget()); - Window win = event->xany.window; - XEvent report; + if (event->xclient.message_type == wm_protocols) + { + if ((Atom) (event->xclient.data.l[0]) == wm_delete_window) + { + if (win) + { + win->Close(FALSE); + } + } + } + return; + } + case ConfigureNotify: + { + if (win) + { + wxSizeEvent sizeEvent( wxSize(event->xconfigure.width,event->xconfigure.height), win->GetId() ); + sizeEvent.SetEventObject( win ); + + win->GetEventHandler()->ProcessEvent( sizeEvent ); + } + } + case ResizeRequest: + { + /* Terry Gitnick - 1/21/98 + * If resize event, don't resize until the last resize event for this + * window is recieved. Prevents flicker as windows are resized. + */ + + Display *disp = (Display*) wxGetDisplay(); + XEvent report; + + // to avoid flicker + report = * event; + while( XCheckTypedWindowEvent (disp, actualWindow, ResizeRequest, &report)); + + // TODO: when implementing refresh optimization, we can use + // XtAddExposureToRegion to expand the window's paint region. + + if (win) + { + wxSize sz = win->GetSize(); + wxSizeEvent sizeEvent(sz, win->GetId()); + sizeEvent.SetEventObject(win); - // to avoid flicker - report = * event; - while( XCheckTypedWindowEvent (disp, win, ResizeRequest, &report)); + win->GetEventHandler()->ProcessEvent( sizeEvent ); + } - // TODO: when implementing refresh optimization, we can use - // XtAddExposureToRegion to expand the window's paint region. + return; + } + case Expose: + { + if (win) + { + // Schedule update for later + win->GetUpdateRegion().Union( event->xexpose.x, event->xexpose.y, + event->xexpose.width, event->xexpose.height); + } - XtDispatchEvent(event); - } - else - { - XtDispatchEvent(event); + return; + } + case EnterNotify: + case LeaveNotify: + case ButtonPress: + case ButtonRelease: + case MotionNotify: + { + if (win && !win->IsEnabled()) + return; + + if (win) + { + wxMouseEvent wxevent; + wxTranslateMouseEvent(wxevent, win, window, event); + win->GetEventHandler()->ProcessEvent( wxevent ); + } + return; + } + case FocusIn: + { + if (win && event->xfocus.detail != NotifyPointer) + { + wxFocusEvent focusEvent(wxEVT_SET_FOCUS, win->GetId()); + focusEvent.SetEventObject(win); + win->GetEventHandler()->ProcessEvent(focusEvent); + } + break; + } + case FocusOut: + { + if (win && event->xfocus.detail != NotifyPointer) + { + wxFocusEvent focusEvent(wxEVT_KILL_FOCUS, win->GetId()); + focusEvent.SetEventObject(win); + win->GetEventHandler()->ProcessEvent(focusEvent); + } + break; + } + case DestroyNotify: + { + // Do we want to process this (for top-level windows)? + // But we want to be able to veto closes, anyway + break; + } + default: + { + break; + } } } // Returns TRUE if more time is needed. +// Note that this duplicates wxEventLoopImpl::SendIdleEvent +// but ProcessIdle may be needed by apps, so is kept. bool wxApp::ProcessIdle() { wxIdleEvent event; @@ -431,27 +517,20 @@ bool wxApp::ProcessIdle() void wxApp::ExitMainLoop() { - m_keepGoing = FALSE; + if (m_mainLoop) + m_mainLoop->Exit(0); } // Is a message/event pending? bool wxApp::Pending() { - XFlush(XtDisplay( (Widget) wxTheApp->GetTopLevelWidget() )); - - // Fix by Doug from STI, to prevent a stall if non-X event - // is found. - return ((XtAppPending( (XtAppContext) GetAppContext() ) & XtIMXEvent) != 0) ; + return wxEventLoop::GetActive()->Pending(); } // Dispatch a message. void wxApp::Dispatch() { - // XtAppProcessEvent( (XtAppContext) wxTheApp->GetAppContext(), XtIMAll); - - XEvent event; - XtAppNextEvent((XtAppContext) GetAppContext(), &event); - ProcessXEvent((WXEvent*) & event); + wxEventLoop::GetActive()->Dispatch(); } // This should be redefined in a derived class for @@ -459,46 +538,34 @@ void wxApp::Dispatch() void wxApp::HandlePropertyChange(WXEvent *event) { // by default do nothing special - XtDispatchEvent((XEvent*) event); /* let Motif do the work */ + // TODO: what to do for X11 + // XtDispatchEvent((XEvent*) event); /* let Motif do the work */ } void wxApp::OnIdle(wxIdleEvent& event) { - static bool inOnIdle = FALSE; + static bool s_inOnIdle = FALSE; // Avoid recursion (via ProcessEvent default case) - if (inOnIdle) + if (s_inOnIdle) return; - inOnIdle = TRUE; + s_inOnIdle = TRUE; - // If there are pending events, we must process them: pending events - // are either events to the threads other than main or events posted - // with wxPostEvent() functions - // GRG: I have moved this here so that all pending events are processed - // before starting to delete any objects. This behaves better (in - // particular, wrt wxPostEvent) and is coherent with wxGTK's current - // behaviour. Also removed the '#if wxUSE_THREADS' around it. - // Changed Mar/2000 before 2.1.14 - - // Flush pending events. + // Resend in the main thread events which have been prepared in other + // threads ProcessPendingEvents(); - // 'Garbage' collection of windows deleted with Close(). + // 'Garbage' collection of windows deleted with Close() DeletePendingObjects(); - // flush the logged messages if any - wxLog *pLog = wxLog::GetActiveTarget(); - if ( pLog != NULL && pLog->HasPendingMessages() ) - pLog->Flush(); - // Send OnIdle events to all windows bool needMore = SendIdleEvents(); if (needMore) event.RequestMore(TRUE); - inOnIdle = FALSE; + s_inOnIdle = FALSE; } void wxWakeUpIdle() @@ -532,7 +599,10 @@ bool wxApp::SendIdleEvents(wxWindow* win) wxIdleEvent event; event.SetEventObject(win); - win->ProcessEvent(event); + + win->GetEventHandler()->ProcessEvent(event); + + win->OnInternalIdle(); if (event.MoreRequested()) needMore = TRUE; @@ -546,7 +616,8 @@ bool wxApp::SendIdleEvents(wxWindow* win) node = node->Next(); } - return needMore ; + + return needMore; } void wxApp::DeletePendingObjects() @@ -570,42 +641,17 @@ void wxApp::DeletePendingObjects() // Create an application context bool wxApp::OnInitGui() { - XtToolkitInitialize() ; - wxTheApp->m_appContext = (WXAppContext) XtCreateApplicationContext() ; - Display *dpy = XtOpenDisplay((XtAppContext) wxTheApp->m_appContext,(String)NULL,NULL, - (const char*) wxTheApp->GetClassName(), NULL, 0, -# if XtSpecificationRelease < 5 - (Cardinal*) &argc, -# else - &argc, -# endif - argv); - - if (!dpy) { - wxString className(wxTheApp->GetClassName()); - wxLogError(_("wxWindows could not open display for '%s': exiting."), - (const char*) className); - exit(-1); - } - m_initialDisplay = (WXDisplay*) dpy; - -#ifdef __WXDEBUG__ - // install the X error handler - gs_pfnXErrorHandler = XSetErrorHandler(wxXErrorHandler); -#endif // __WXDEBUG__ - - wxTheApp->m_topLevelWidget = (WXWidget) XtAppCreateShell((String)NULL, (const char*) wxTheApp->GetClassName(), - applicationShellWidgetClass,dpy, - NULL,0) ; - - // Add general resize proc - XtActionsRec rec; - rec.string = "resize"; - rec.proc = (XtActionProc)wxWidgetResizeProc; - XtAppAddActions((XtAppContext) wxTheApp->m_appContext, &rec, 1); - - GetMainColormap(dpy); - m_maxRequestSize = XMaxRequestSize((Display*) dpy); + // Eventually this line will be removed, but for + // now we don't want to try popping up a dialog + // for error messages. + delete wxLog::SetActiveTarget(new wxLogStderr); + + if (!wxAppBase::OnInitGui()) + return FALSE; + + + GetMainColormap( wxApp::GetDisplay() ); + m_maxRequestSize = XMaxRequestSize( (Display*) wxApp::GetDisplay() ); return TRUE; } @@ -626,89 +672,19 @@ WXColormap wxApp::GetMainColormap(WXDisplay* display) return (WXColormap) c; } -// Returns TRUE if an accelerator has been processed -bool wxApp::CheckForAccelerator(WXEvent* event) -{ - XEvent* xEvent = (XEvent*) event; - if (xEvent->xany.type == KeyPress) - { - // Find a wxWindow for this window - // TODO: should get display for the window, not the current display - Widget widget = XtWindowToWidget((Display*) wxGetDisplay(), xEvent->xany.window); - wxWindow* win = NULL; - - // Find the first wxWindow that corresponds to this event window - while (widget && !(win = wxGetWindowFromTable(widget))) - widget = XtParent(widget); - - if (!widget || !win) - return FALSE; - - wxKeyEvent keyEvent(wxEVT_CHAR); - wxTranslateKeyEvent(keyEvent, win, (Widget) 0, xEvent); - - // Now we have a wxKeyEvent and we have a wxWindow. - // Go up the hierarchy until we find a matching accelerator, - // or we get to the top. - while (win) - { - if (win->ProcessAccelerator(keyEvent)) - return TRUE; - win = win->GetParent(); - } - return FALSE; - } - return FALSE; -} - -bool wxApp::CheckForKeyDown(WXEvent* event) +Window wxGetWindowParent(Window window) { - XEvent* xEvent = (XEvent*) event; - if (xEvent->xany.type == KeyPress) - { - Widget widget = XtWindowToWidget((Display*) wxGetDisplay(), - xEvent->xany.window); - wxWindow* win = NULL; - - // Find the first wxWindow that corresponds to this event window - while (widget && !(win = wxGetWindowFromTable(widget))) - widget = XtParent(widget); - - if (!widget || !win) - return FALSE; - - wxKeyEvent keyEvent(wxEVT_KEY_DOWN); - wxTranslateKeyEvent(keyEvent, win, (Widget) 0, xEvent); - - return win->ProcessEvent( keyEvent ); - } - - return FALSE; -} - -bool wxApp::CheckForKeyUp(WXEvent* event) -{ - XEvent* xEvent = (XEvent*) event; - if (xEvent->xany.type == KeyRelease) - { - Widget widget = XtWindowToWidget((Display*) wxGetDisplay(), - xEvent->xany.window); - wxWindow* win = NULL; - - // Find the first wxWindow that corresponds to this event window - while (widget && !(win = wxGetWindowFromTable(widget))) - widget = XtParent(widget); - - if (!widget || !win) - return FALSE; - - wxKeyEvent keyEvent(wxEVT_KEY_UP); - wxTranslateKeyEvent(keyEvent, win, (Widget) 0, xEvent); - - return win->ProcessEvent( keyEvent ); - } - - return FALSE; + Window parent, root = 0; + unsigned int noChildren = 0; + Window* children = NULL; + int res = XQueryTree((Display*) wxGetDisplay(), window, & root, & parent, + & children, & noChildren); + if (children) + XFree(children); + if (res) + return parent; + else + return (Window) 0; } void wxExit() @@ -786,11 +762,26 @@ wxApp::GetStdIcon(int which) const } } +void wxApp::OnAssert(const wxChar *file, int line, const wxChar *msg) +{ + // While the GUI isn't working that well, just print out the + // message. +#if 0 + wxAppBase::OnAssert(file, line, msg); +#else + wxString msg2; + msg2.Printf("At file %s:%d: %s", file, line, msg); + wxLogDebug(msg2); +#endif +} + // ---------------------------------------------------------------------------- // accessors for C modules // ---------------------------------------------------------------------------- +#if 0 extern "C" XtAppContext wxGetAppContext() { return (XtAppContext)wxTheApp->GetAppContext(); } +#endif