X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/a5b31f4e11c860fa5d9949c8694a7499793c3b98..4913272f9cdead94a6d1470e51d6fb14946b50e0:/src/dfb/toplevel.cpp diff --git a/src/dfb/toplevel.cpp b/src/dfb/toplevel.cpp index 41b05ce9b1..c7f23b52df 100644 --- a/src/dfb/toplevel.cpp +++ b/src/dfb/toplevel.cpp @@ -15,7 +15,6 @@ #ifndef WX_PRECOMP #include "wx/app.h" - #include "wx/dynarray.h" #endif // WX_PRECOMP #include "wx/hashmap.h" @@ -39,19 +38,6 @@ static wxDfbWindowsMap gs_dfbWindowsMap; // helpers // ============================================================================ -struct wxDfbPaintRequest -{ - wxDfbPaintRequest(const wxRect& rect, bool eraseBackground) - : m_rect(rect), m_eraseBackground(eraseBackground) {} - wxDfbPaintRequest(const wxDfbPaintRequest& r) - : m_rect(r.m_rect), m_eraseBackground(r.m_eraseBackground) {} - - wxRect m_rect; - bool m_eraseBackground; -}; - -WX_DEFINE_ARRAY_PTR(wxDfbPaintRequest*, wxDfbQueuedPaintRequestsList); - // Queue of paint requests class wxDfbQueuedPaintRequests { @@ -59,20 +45,36 @@ public: ~wxDfbQueuedPaintRequests() { Clear(); } // Adds paint request to the queue - void Add(const wxRect& rect, bool eraseBack) - { m_queue.push_back(new wxDfbPaintRequest(rect, eraseBack)); } + void Add(const wxRect& rect) + { + // We use a simple implementation here for now: all refresh requests + // are merged together into single rectangle that is superset of + // all the requested rectangles. This wastes some blitting and painting + // time, but OTOH, EVT_PAINT handler is called only once per window. + m_invalidated.Union(rect); + } // Is the queue empty? - bool IsEmpty() const { return m_queue.empty(); } + bool IsEmpty() const { return m_invalidated.IsEmpty(); } // Empties the queue - void Clear() { WX_CLEAR_ARRAY(m_queue); } + void Clear() { m_invalidated = wxRect(); } - // Gets requests in the queue - const wxDfbQueuedPaintRequestsList& GetRequests() const { return m_queue; } + // Gets the next request in the queue, returns true if there was one, + // false if the queue was empty + bool GetNext(wxRect& rect) + { + if ( m_invalidated.IsEmpty() ) + return false; + + rect = m_invalidated; + Clear(); // there's only one item in the queue + return true; + } private: - wxDfbQueuedPaintRequestsList m_queue; + // currently invalidated region + wxRect m_invalidated; }; // ============================================================================ @@ -91,6 +93,7 @@ void wxTopLevelWindowDFB::Init() m_sizeSet = false; m_opacity = 255; m_toPaint = new wxDfbQueuedPaintRequests; + m_isPainting = false; } bool wxTopLevelWindowDFB::Create(wxWindow *parent, @@ -148,7 +151,8 @@ bool wxTopLevelWindowDFB::Create(wxWindow *parent, if ( !m_dfbwin->SetOpacity(wxALPHA_TRANSPARENT) ) return false; - wxWindow::Create(NULL, id, pos, size, style, name); + if ( !wxWindow::Create(NULL, id, pos, size, style, name) ) + return false; SetParent(parent); if ( parent ) @@ -215,9 +219,14 @@ void wxTopLevelWindowDFB::DoMoveWindow(int x, int y, int width, int height) wxSize cursize = GetSize(); if ( cursize.x != width || cursize.y != height ) { + // changing window's size changes its surface: + InvalidateDfbSurface(); + m_dfbwin->Resize(width, height); + // we must repaint the window after it changed size: - Refresh(); + if ( IsShown() ) + DoRefreshWindow(); } } @@ -276,10 +285,21 @@ bool wxTopLevelWindowDFB::Show(bool show) GetEventHandler()->ProcessEvent(event); } - // FIXME_DFB: do this at all? - if ( show && AcceptsFocus() ) - SetFocus(); - // FIXME_DFB -- don't do this for popup windows? + if ( show ) + { + wxWindow *focused = wxWindow::FindFocus(); + if ( focused && focused->GetTLW() == this ) + { + SetDfbFocus(); + } + else if ( AcceptsFocus() ) + { + // FIXME: we should probably always call SetDfbFocus instead + // and call SetFocus() from wxActivateEvent/DWET_GOTFOCUS + // handler + SetFocus(); + } + } return true; } @@ -369,29 +389,36 @@ void wxTopLevelWindowDFB::HandleQueuedPaintRequests() return; } - const wxDfbQueuedPaintRequestsList& requests = m_toPaint->GetRequests(); - // process queued paint requests: wxRect winRect(wxPoint(0, 0), GetSize()); wxRect paintedRect; - size_t cnt = requests.size(); - for ( size_t i = 0; i < cnt; ++i ) - { - const wxDfbPaintRequest& request = *requests[i]; + // important note: all DCs created from now until m_isPainting is reset to + // false will not update the front buffer as this flag indicates that we'll + // blit the entire back buffer to front soon + m_isPainting = true; - wxRect clipped(request.m_rect); - - wxLogTrace(TRACE_PAINT, - _T("%p ('%s'): processing paint request [x=%i,y=%i,w=%i,h=%i]"), - this, GetName().c_str(), - clipped.x, clipped.y, clipped.width, clipped.height); +#ifdef __WXDEBUG__ + int requestsCount = 0; +#endif + wxRect request; + while ( m_toPaint->GetNext(request) ) + { +#ifdef __WXDEBUG__ + requestsCount++; +#endif + wxRect clipped(request); clipped.Intersect(winRect); if ( clipped.IsEmpty() ) continue; // nothing to refresh - PaintWindow(clipped, request.m_eraseBackground); + wxLogTrace(TRACE_PAINT, + _T("%p ('%s'): processing paint request [%i,%i,%i,%i]"), + this, GetName().c_str(), + clipped.x, clipped.y, clipped.GetRight(), clipped.GetBottom()); + + PaintWindow(clipped); // remember rectangle covering all repainted areas: if ( paintedRect.IsEmpty() ) @@ -400,23 +427,54 @@ void wxTopLevelWindowDFB::HandleQueuedPaintRequests() paintedRect.Union(clipped); } + m_isPainting = false; + m_toPaint->Clear(); if ( paintedRect.IsEmpty() ) return; // no painting occurred, no need to flip - // flip the surface to make the changes visible: + // Flip the surface to make the changes visible. Note that the rectangle we + // flip is *superset* of the union of repainted rectangles (created as + // "rectangles union" by wxRect::Union) and so some parts of the back + // buffer that we didn't touch in this HandleQueuedPaintRequests call will + // be copied to the front buffer as well. This is safe/correct thing to do + // *only* because wx always use wxIDirectFBSurface::FlipToFront() and so + // the back and front buffers contain the same data. + // + // Note that we do _not_ split m_toPaint into disjoint rectangles and + // do FlipToFront() for each of them, because that could result in visible + // updating of the screen; instead, we prefer to flip everything at once. + DFBRegion r = {paintedRect.GetLeft(), paintedRect.GetTop(), paintedRect.GetRight(), paintedRect.GetBottom()}; DFBRegion *rptr = (winRect == paintedRect) ? NULL : &r; - GetDfbSurface()->Flip(rptr, DSFLIP_NONE); + GetDfbSurface()->FlipToFront(rptr); + + wxLogTrace(TRACE_PAINT, + _T("%p ('%s'): processed %i paint requests, flipped surface: [%i,%i,%i,%i]"), + this, GetName().c_str(), + requestsCount, + paintedRect.x, paintedRect.y, + paintedRect.GetRight(), paintedRect.GetBottom()); } -void wxTopLevelWindowDFB::DoRefreshRect(const wxRect& rect, bool eraseBack) +void wxTopLevelWindowDFB::DoRefreshRect(const wxRect& rect) { + // don't overlap outside of the window (NB: 'rect' is in window coords): + wxRect r(rect); + r.Intersect(wxRect(GetSize())); + if ( r.IsEmpty() ) + return; + + wxLogTrace(TRACE_PAINT, + _T("%p ('%s'): [TLW] refresh rect [%i,%i,%i,%i]"), + this, GetName().c_str(), + rect.x, rect.y, rect.GetRight(), rect.GetBottom()); + // defer painting until idle time or until Update() is called: - m_toPaint->Add(rect, eraseBack); + m_toPaint->Add(rect); } void wxTopLevelWindowDFB::Update() @@ -428,6 +486,15 @@ void wxTopLevelWindowDFB::Update() // events handling // --------------------------------------------------------------------------- +void wxTopLevelWindowDFB::SetDfbFocus() +{ + wxCHECK_RET( IsShown(), _T("cannot set focus to hidden window") ); + wxASSERT_MSG( FindFocus() && FindFocus()->GetTLW() == this, + _T("setting DirectFB focus to unexpected window") ); + + GetDirectFBWindow()->RequestFocus(); +} + /* static */ void wxTopLevelWindowDFB::HandleDFBWindowEvent(const wxDFBWindowEvent& event_) { @@ -460,6 +527,10 @@ void wxTopLevelWindowDFB::HandleDFBWindowEvent(const wxDFBWindowEvent& event_) wxFAIL_MSG( _T("invalid event type") ); break; } + + default: + // we're not interested in them here + break; } if ( !recipient )