X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/c2ff68d3fd238a3b943fa0638c88c30b9f2818af..6d9022fe3bb50a75b9b5eaf5cf32558e518ba310:/src/x11/app.cpp diff --git a/src/x11/app.cpp b/src/x11/app.cpp index 9dc4c4243b..1ca16bb8e2 100644 --- a/src/x11/app.cpp +++ b/src/x11/app.cpp @@ -25,10 +25,13 @@ #include "wx/log.h" #include "wx/intl.h" #include "wx/evtloop.h" +#include "wx/timer.h" #include "wx/univ/theme.h" #include "wx/univ/renderer.h" +#define ABS(a) (((a) < 0) ? -(a) : (a)) + #if wxUSE_THREADS #include "wx/thread.h" #endif @@ -48,6 +51,7 @@ extern wxList wxPendingDelete; wxHashTable *wxWidgetHashTable = NULL; +wxHashTable *wxClientWidgetHashTable = NULL; wxApp *wxTheApp = NULL; @@ -118,6 +122,7 @@ bool wxApp::Initialize() #endif wxWidgetHashTable = new wxHashTable(wxKEY_INTEGER); + wxClientWidgetHashTable = new wxHashTable(wxKEY_INTEGER); wxModule::RegisterModules(); if (!wxModule::InitializeModules()) return FALSE; @@ -133,6 +138,8 @@ void wxApp::CleanUp() delete wxWidgetHashTable; wxWidgetHashTable = NULL; + delete wxClientWidgetHashTable; + wxClientWidgetHashTable = NULL; wxModule::CleanUpModules(); @@ -144,7 +151,7 @@ void wxApp::CleanUp() wxTheColourDatabase = NULL; wxDeleteStockObjects(); - + wxDeleteStockLists(); delete wxTheApp; @@ -259,11 +266,11 @@ int wxEntryStart( int& argc, char *argv[] ) { XSynchronize(xdisplay, True); } - + wxApp::ms_display = (WXDisplay*) xdisplay; - + XSelectInput( xdisplay, XDefaultRootWindow(xdisplay), PropertyChangeMask); - + wxSetDetectableAutoRepeat( TRUE ); if (!wxApp::Initialize()) @@ -391,6 +398,22 @@ wxApp::wxApp() m_mainLoop = NULL; m_showIconic = FALSE; m_initialSize = wxDefaultSize; + +#if !wxUSE_NANOX + m_visualColormap = NULL; + m_colorCube = NULL; +#endif +} + +wxApp::~wxApp() +{ +#if !wxUSE_NANOX + if (m_colorCube) + free( m_colorCube ); + + if (m_visualColormap) + delete [] (XColor*)m_visualColormap; +#endif } bool wxApp::Initialized() @@ -403,7 +426,7 @@ bool wxApp::Initialized() int wxApp::MainLoop() { - int rt; + int rt; m_mainLoop = new wxEventLoop; rt = m_mainLoop->Run(); @@ -427,38 +450,40 @@ struct wxExposeInfo static Bool expose_predicate (Display *display, XEvent *xevent, XPointer arg) { wxExposeInfo *info = (wxExposeInfo*) arg; - + if (info->found_non_matching) return FALSE; - + if (xevent->xany.type != Expose) { info->found_non_matching = TRUE; return FALSE; } - + if (xevent->xexpose.window != info->window) { info->found_non_matching = TRUE; return FALSE; } - + return TRUE; } #endif // wxUSE_NANOX //----------------------------------------------------------------------- -// Processes an X event. +// Processes an X event, returning TRUE if the event was processed. //----------------------------------------------------------------------- -void wxApp::ProcessXEvent(WXEvent* _event) +bool wxApp::ProcessXEvent(WXEvent* _event) { XEvent* event = (XEvent*) _event; wxWindow* win = NULL; Window window = XEventGetWindow(event); +#if 0 Window actualWindow = window; +#endif // Find the first wxWindow that corresponds to this event window // Because we're receiving events after a window @@ -468,43 +493,144 @@ void wxApp::ProcessXEvent(WXEvent* _event) win = wxGetWindowFromTable(window); if (!win) - return; + { +#if wxUSE_TWO_WINDOWS + win = wxGetClientWindowFromTable(window); + if (!win) +#endif + return FALSE; + } #ifdef __WXDEBUG__ wxString windowClass = win->GetClassInfo()->GetClassName(); #endif - + switch (event->type) { + case Expose: + { +#if wxUSE_TWO_WINDOWS && !wxUSE_NANOX + if (event->xexpose.window != (Window)win->GetClientWindow()) + { + XEvent tmp_event; + wxExposeInfo info; + info.window = event->xexpose.window; + info.found_non_matching = FALSE; + while (XCheckIfEvent( wxGlobalDisplay(), &tmp_event, expose_predicate, (XPointer) &info )) + { + // Don't worry about optimizing redrawing the border etc. + } + win->NeedUpdateNcAreaInIdle(); + } + else +#endif + { + win->GetUpdateRegion().Union( XExposeEventGetX(event), XExposeEventGetY(event), + XExposeEventGetWidth(event), XExposeEventGetHeight(event)); + win->GetClearRegion().Union( XExposeEventGetX(event), XExposeEventGetY(event), + XExposeEventGetWidth(event), XExposeEventGetHeight(event)); + +#if !wxUSE_NANOX + XEvent tmp_event; + wxExposeInfo info; + info.window = event->xexpose.window; + info.found_non_matching = FALSE; + while (XCheckIfEvent( wxGlobalDisplay(), &tmp_event, expose_predicate, (XPointer) &info )) + { + win->GetUpdateRegion().Union( tmp_event.xexpose.x, tmp_event.xexpose.y, + tmp_event.xexpose.width, tmp_event.xexpose.height ); + + win->GetClearRegion().Union( tmp_event.xexpose.x, tmp_event.xexpose.y, + tmp_event.xexpose.width, tmp_event.xexpose.height ); + } +#endif + + // This simplifies the expose and clear areas to simple + // rectangles. + win->GetUpdateRegion() = win->GetUpdateRegion().GetBox(); + win->GetClearRegion() = win->GetClearRegion().GetBox(); + + // If we only have one X11 window, always indicate + // that borders might have to be redrawn. + if (win->GetMainWindow() == win->GetClientWindow()) + win->NeedUpdateNcAreaInIdle(); + + // Only erase background, paint in idle time. + win->SendEraseEvents(); + // win->Update(); + } + + return TRUE; + } + +#if !wxUSE_NANOX + case GraphicsExpose: + { + printf( "GraphicExpose event\n" ); + + // wxLogDebug( "GraphicsExpose from %s", win->GetName().c_str(), + // event->xgraphicsexpose.x, event->xgraphicsexpose.y, + // event->xgraphicsexpose.width, event->xgraphicsexpose.height); + + win->GetUpdateRegion().Union( event->xgraphicsexpose.x, event->xgraphicsexpose.y, + event->xgraphicsexpose.width, event->xgraphicsexpose.height); + + win->GetClearRegion().Union( event->xgraphicsexpose.x, event->xgraphicsexpose.y, + event->xgraphicsexpose.width, event->xgraphicsexpose.height); + + if (event->xgraphicsexpose.count == 0) + { + // Only erase background, paint in idle time. + win->SendEraseEvents(); + // win->Update(); + } + + return TRUE; + } +#endif + case KeyPress: { if (!win->IsEnabled()) - return; + return FALSE; wxKeyEvent keyEvent(wxEVT_KEY_DOWN); wxTranslateKeyEvent(keyEvent, win, window, event); - + // wxLogDebug( "OnKey from %s", win->GetName().c_str() ); - - // We didn't process wxEVT_KEY_DOWN, so send - // wxEVT_CHAR - if (!win->GetEventHandler()->ProcessEvent( keyEvent )) + + // We didn't process wxEVT_KEY_DOWN, so send wxEVT_CHAR + if (win->GetEventHandler()->ProcessEvent( keyEvent )) + return TRUE; + + keyEvent.SetEventType(wxEVT_CHAR); + if (win->GetEventHandler()->ProcessEvent( keyEvent )) + return TRUE; + + if ( (keyEvent.m_keyCode == WXK_TAB) && + win->GetParent() && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) ) { - keyEvent.SetEventType(wxEVT_CHAR); - win->GetEventHandler()->ProcessEvent( keyEvent ); + wxNavigationKeyEvent new_event; + new_event.SetEventObject( win->GetParent() ); + /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */ + new_event.SetDirection( (keyEvent.m_keyCode == WXK_TAB) ); + /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */ + new_event.SetWindowChange( keyEvent.ControlDown() ); + new_event.SetCurrentFocus( win ); + return win->GetParent()->GetEventHandler()->ProcessEvent( new_event ); } - return; + + return FALSE; } case KeyRelease: { if (!win->IsEnabled()) - return; + return FALSE; wxKeyEvent keyEvent(wxEVT_KEY_UP); wxTranslateKeyEvent(keyEvent, win, window, event); - - win->GetEventHandler()->ProcessEvent( keyEvent ); - return; + + return win->GetEventHandler()->ProcessEvent( keyEvent ); } case ConfigureNotify: { @@ -512,25 +638,39 @@ void wxApp::ProcessXEvent(WXEvent* _event) if (event->update.utype == GR_UPDATE_SIZE) #endif { - //wxLogDebug("ConfigureNotify: %s", windowClass.c_str()); - wxSizeEvent sizeEvent( wxSize(XConfigureEventGetWidth(event), XConfigureEventGetHeight(event)), win->GetId() ); - sizeEvent.SetEventObject( win ); - - win->GetEventHandler()->ProcessEvent( sizeEvent ); + if (win->IsTopLevel()) + { + wxTopLevelWindow *tlw = (wxTopLevelWindow*) win; + tlw->SetConfigureGeometry( XConfigureEventGetX(event), XConfigureEventGetY(event), + XConfigureEventGetWidth(event), XConfigureEventGetHeight(event) ); + } + + if (win->IsTopLevel() && win->IsShown()) + { + wxTopLevelWindowX11 *tlw = (wxTopLevelWindowX11 *) win; + tlw->SetNeedResizeInIdle(); + } + else + { + wxSizeEvent sizeEvent( wxSize(XConfigureEventGetWidth(event), XConfigureEventGetHeight(event)), win->GetId() ); + sizeEvent.SetEventObject( win ); + + return win->GetEventHandler()->ProcessEvent( sizeEvent ); + } } + return FALSE; break; } #if !wxUSE_NANOX case PropertyNotify: { //wxLogDebug("PropertyNotify: %s", windowClass.c_str()); - HandlePropertyChange(_event); - return; + return HandlePropertyChange(_event); } case ClientMessage: { if (!win->IsEnabled()) - return; + return FALSE; Atom wm_delete_window = XInternAtom(wxGlobalDisplay(), "WM_DELETE_WINDOW", True); Atom wm_protocols = XInternAtom(wxGlobalDisplay(), "WM_PROTOCOLS", True); @@ -540,96 +680,57 @@ void wxApp::ProcessXEvent(WXEvent* _event) if ((Atom) (event->xclient.data.l[0]) == wm_delete_window) { win->Close(FALSE); + return TRUE; } } - return; + return FALSE; + } +#if 0 + case DestroyNotify: + { + printf( "destroy from %s\n", win->GetName().c_str() ); + break; + } + case CreateNotify: + { + printf( "create from %s\n", win->GetName().c_str() ); + break; + } + case MapRequest: + { + printf( "map request from %s\n", win->GetName().c_str() ); + break; } case ResizeRequest: { - /* - * If resize event, don't resize until the last resize event for this - * window is recieved. Prevents flicker as windows are resized. - */ - + printf( "resize request from %s\n", win->GetName().c_str() ); + Display *disp = (Display*) wxGetDisplay(); XEvent report; - + // to avoid flicker report = * event; while( XCheckTypedWindowEvent (disp, actualWindow, ResizeRequest, &report)); - - if (win) - { - wxSize sz = win->GetSize(); - wxSizeEvent sizeEvent(sz, win->GetId()); - sizeEvent.SetEventObject(win); - win->GetEventHandler()->ProcessEvent( sizeEvent ); - } + wxSize sz = win->GetSize(); + wxSizeEvent sizeEvent(sz, win->GetId()); + sizeEvent.SetEventObject(win); - return; + return win->GetEventHandler()->ProcessEvent( sizeEvent ); } #endif +#endif #if wxUSE_NANOX case GR_EVENT_TYPE_CLOSE_REQ: { if (win) { win->Close(FALSE); + return TRUE; } + return FALSE; break; } -#endif - case Expose: - { - //wxLogDebug("Expose: %s", windowClass.c_str()); - win->GetUpdateRegion().Union( XExposeEventGetX(event), XExposeEventGetY(event), - XExposeEventGetWidth(event), XExposeEventGetHeight(event)); - - win->GetClearRegion().Union( XExposeEventGetX(event), XExposeEventGetY(event), - XExposeEventGetWidth(event), XExposeEventGetHeight(event)); - - -#if !wxUSE_NANOX - XEvent tmp_event; - wxExposeInfo info; - info.window = event->xexpose.window; - info.found_non_matching = FALSE; - while (XCheckIfEvent( wxGlobalDisplay(), &tmp_event, expose_predicate, (XPointer) &info )) - { - win->GetUpdateRegion().Union( tmp_event.xexpose.x, tmp_event.xexpose.y, - tmp_event.xexpose.width, tmp_event.xexpose.height ); - - win->GetClearRegion().Union( tmp_event.xexpose.x, tmp_event.xexpose.y, - tmp_event.xexpose.width, tmp_event.xexpose.height ); - } -#endif - - win->SendEraseEvents(); - - return; - } -#if !wxUSE_NANOX - case GraphicsExpose: - { - // wxLogDebug( "GraphicsExpose from %s", win->GetName().c_str(), - // event->xgraphicsexpose.x, event->xgraphicsexpose.y, - // event->xgraphicsexpose.width, event->xgraphicsexpose.height); - - win->GetUpdateRegion().Union( event->xgraphicsexpose.x, event->xgraphicsexpose.y, - event->xgraphicsexpose.width, event->xgraphicsexpose.height); - - win->GetClearRegion().Union( event->xgraphicsexpose.x, event->xgraphicsexpose.y, - event->xgraphicsexpose.width, event->xgraphicsexpose.height); - - if (event->xgraphicsexpose.count == 0) - { - // Only erase background, paint in idle time. - win->SendEraseEvents(); - } - - return; - } #endif case EnterNotify: case LeaveNotify: @@ -638,7 +739,7 @@ void wxApp::ProcessXEvent(WXEvent* _event) case MotionNotify: { if (!win->IsEnabled()) - return; + return FALSE; // Here we check if the top level window is // disabled, which is one aspect of modality. @@ -646,25 +747,32 @@ void wxApp::ProcessXEvent(WXEvent* _event) while (tlw && !tlw->IsTopLevel()) tlw = tlw->GetParent(); if (tlw && !tlw->IsEnabled()) - return; - + return FALSE; + if (event->type == ButtonPress) { if ((win != wxWindow::FindFocus()) && win->AcceptsFocus()) { // This might actually be done in wxWindow::SetFocus() - // and not here. + // and not here. TODO. g_prevFocus = wxWindow::FindFocus(); g_nextFocus = win; - + win->SetFocus(); } } +#if !wxUSE_NANOX + if (event->type == LeaveNotify || event->type == EnterNotify) + { + // Throw out NotifyGrab and NotifyUngrab + if (event->xcrossing.mode != NotifyNormal) + return FALSE; + } +#endif wxMouseEvent wxevent; wxTranslateMouseEvent(wxevent, win, window, event); - win->GetEventHandler()->ProcessEvent( wxevent ); - return; + return win->GetEventHandler()->ProcessEvent( wxevent ); } case FocusIn: { @@ -674,14 +782,15 @@ void wxApp::ProcessXEvent(WXEvent* _event) #endif { // wxLogDebug( "FocusIn from %s of type %s", win->GetName().c_str(), win->GetClassInfo()->GetClassName() ); - + wxFocusEvent focusEvent(wxEVT_SET_FOCUS, win->GetId()); focusEvent.SetEventObject(win); focusEvent.SetWindow( g_prevFocus ); g_prevFocus = NULL; - - win->GetEventHandler()->ProcessEvent(focusEvent); + + return win->GetEventHandler()->ProcessEvent(focusEvent); } + return FALSE; break; } case FocusOut: @@ -692,32 +801,27 @@ void wxApp::ProcessXEvent(WXEvent* _event) #endif { // wxLogDebug( "FocusOut from %s of type %s", win->GetName().c_str(), win->GetClassInfo()->GetClassName() ); - + wxFocusEvent focusEvent(wxEVT_KILL_FOCUS, win->GetId()); focusEvent.SetEventObject(win); focusEvent.SetWindow( g_nextFocus ); g_nextFocus = NULL; - win->GetEventHandler()->ProcessEvent(focusEvent); + return win->GetEventHandler()->ProcessEvent(focusEvent); } + return FALSE; break; } -#ifndef wxUSE_NANOX - case DestroyNotify: - { - // Do we want to process this (for top-level windows)? - // But we want to be able to veto closes, anyway - break; - } -#endif default: { #ifdef __WXDEBUG__ //wxString eventName = wxGetXEventName(XEvent& event); //wxLogDebug(wxT("Event %s not handled"), eventName.c_str()); #endif + return FALSE; break; } } + return FALSE; } // Returns TRUE if more time is needed. @@ -752,11 +856,12 @@ void wxApp::Dispatch() // This should be redefined in a derived class for // handling property change events for XAtom IPC. -void wxApp::HandlePropertyChange(WXEvent *event) +bool wxApp::HandlePropertyChange(WXEvent *event) { // by default do nothing special // TODO: what to do for X11 // XtDispatchEvent((XEvent*) event); + return FALSE; } void wxApp::OnIdle(wxIdleEvent& event) @@ -819,8 +924,6 @@ bool wxApp::SendIdleEvents(wxWindow* win) win->GetEventHandler()->ProcessEvent(event); - win->OnInternalIdle(); - if (event.MoreRequested()) needMore = TRUE; @@ -833,7 +936,9 @@ bool wxApp::SendIdleEvents(wxWindow* win) node = node->Next(); } - + + win->OnInternalIdle(); + return needMore; } @@ -855,6 +960,24 @@ void wxApp::DeletePendingObjects() } } +static void wxCalcPrecAndShift( unsigned long mask, int *shift, int *prec ) +{ + *shift = 0; + *prec = 0; + + while (!(mask & 0x1)) + { + (*shift)++; + mask >>= 1; + } + + while (mask & 0x1) + { + (*prec)++; + mask >>= 1; + } +} + // Create display, and other initialization bool wxApp::OnInitGui() { @@ -862,14 +985,110 @@ bool wxApp::OnInitGui() // now we don't want to try popping up a dialog // for error messages. delete wxLog::SetActiveTarget(new wxLogStderr); - + if (!wxAppBase::OnInitGui()) - return FALSE; - + return FALSE; + GetMainColormap( wxApp::GetDisplay() ); m_maxRequestSize = XMaxRequestSize( (Display*) wxApp::GetDisplay() ); +#if !wxUSE_NANOX + // Get info about the current visual. It is enough + // to do this once here unless we support different + // visuals, displays and screens. Given that wxX11 + // mostly for embedded things, that is no real + // limitation. + Display *xdisplay = (Display*) wxApp::GetDisplay(); + int xscreen = DefaultScreen(xdisplay); + Visual* xvisual = DefaultVisual(xdisplay,xscreen); + int xdepth = DefaultDepth(xdisplay, xscreen); + + XVisualInfo vinfo_template; + vinfo_template.visual = xvisual; + vinfo_template.visualid = XVisualIDFromVisual( xvisual ); + vinfo_template.depth = xdepth; + + int nitem = 0; + XVisualInfo *vi = XGetVisualInfo( xdisplay, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem ); + wxASSERT_MSG( vi, wxT("No visual info") ); + + m_visualType = vi->visual->c_class; + m_visualScreen = vi->screen; + + m_visualRedMask = vi->red_mask; + m_visualGreenMask = vi->green_mask; + m_visualBlueMask = vi->blue_mask; + + if (m_visualType != GrayScale && m_visualType != PseudoColor) + { + wxCalcPrecAndShift( m_visualRedMask, &m_visualRedShift, &m_visualRedPrec ); + wxCalcPrecAndShift( m_visualGreenMask, &m_visualGreenShift, &m_visualGreenPrec ); + wxCalcPrecAndShift( m_visualBlueMask, &m_visualBlueShift, &m_visualBluePrec ); + } + + m_visualDepth = xdepth; + if (xdepth == 16) + xdepth = m_visualRedPrec + m_visualGreenPrec + m_visualBluePrec; + + m_visualColormapSize = vi->colormap_size; + + XFree( vi ); + + if (m_visualDepth > 8) + return TRUE; + + m_visualColormap = new XColor[m_visualColormapSize]; + XColor* colors = (XColor*) m_visualColormap; + + for (int i = 0; i < m_visualColormapSize; i++) + colors[i].pixel = i; + + XQueryColors( xdisplay, DefaultColormap(xdisplay,xscreen), colors, m_visualColormapSize ); + + m_colorCube = (unsigned char*)malloc(32 * 32 * 32); + + for (int r = 0; r < 32; r++) + { + for (int g = 0; g < 32; g++) + { + for (int b = 0; b < 32; b++) + { + int rr = (r << 3) | (r >> 2); + int gg = (g << 3) | (g >> 2); + int bb = (b << 3) | (b >> 2); + + int index = -1; + + if (colors) + { + int max = 3 * 65536; + + for (int i = 0; i < m_visualColormapSize; i++) + { + int rdiff = ((rr << 8) - colors[i].red); + int gdiff = ((gg << 8) - colors[i].green); + int bdiff = ((bb << 8) - colors[i].blue); + int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff); + if (sum < max) + { + index = i; max = sum; + } + } + } + else + { + // assume 8-bit true or static colors. this really exists + index = (r >> (5 - m_visualRedPrec)) << m_visualRedShift; + index |= (g >> (5 - m_visualGreenPrec)) << m_visualGreenShift; + index |= (b >> (5 - m_visualBluePrec)) << m_visualBlueShift; + } + m_colorCube[ (r*1024) + (g*32) + b ] = index; + } + } + } +#endif + return TRUE; } @@ -892,7 +1111,7 @@ WXColormap wxApp::GetMainColormap(WXDisplay* display) Window wxGetWindowParent(Window window) { wxASSERT_MSG( window, "invalid window" ); - + return (Window) 0; Window parent, root = 0; @@ -903,13 +1122,13 @@ Window wxGetWindowParent(Window window) #endif Window* children = NULL; - // #define XQueryTree(d,w,r,p,c,nc) GrQueryTree(w,p,c,nc) + // #define XQueryTree(d,w,r,p,c,nc) GrQueryTree(w,p,c,nc) int res = 1; #if !wxUSE_NANOX res = #endif XQueryTree((Display*) wxGetDisplay(), window, & root, & parent, - & children, & noChildren); + & children, & noChildren); if (children) XFree(children); if (res) @@ -950,24 +1169,40 @@ bool wxApp::Yield(bool onlyIfNeeded) s_inYield = TRUE; + // Make sure we have an event loop object, + // or Pending/Dispatch will fail + wxEventLoop* eventLoop = wxEventLoop::GetActive(); + wxEventLoop* newEventLoop = NULL; + if (!eventLoop) + { + newEventLoop = new wxEventLoop; + wxEventLoop::SetActive(newEventLoop); + } + while (wxTheApp && wxTheApp->Pending()) wxTheApp->Dispatch(); +#if wxUSE_TIMER + wxTimer::NotifyTimers(); +#endif + ProcessIdle(); + + if (newEventLoop) + { + wxEventLoop::SetActive(NULL); + delete newEventLoop; + } + s_inYield = FALSE; return TRUE; } -wxIcon wxApp::GetStdIcon(int which) const -{ - return wxTheme::Get()->GetRenderer()->GetStdIcon(which); -} - 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 +#if 1 wxAppBase::OnAssert(file, line, msg); #else wxString msg2;