X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b3c861501a451503b31c075ccb59d16b0ae01e99..8930b2ed1ebff50797843db75744c6963287dbe7:/src/dfb/toplevel.cpp diff --git a/src/dfb/toplevel.cpp b/src/dfb/toplevel.cpp index 98b77b9ea2..b607ecc863 100644 --- a/src/dfb/toplevel.cpp +++ b/src/dfb/toplevel.cpp @@ -41,16 +41,36 @@ static wxDfbWindowsMap gs_dfbWindowsMap; 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) {} + wxDfbPaintRequest(const wxRect& rect) : m_rect(rect) {} + wxDfbPaintRequest(const wxDfbPaintRequest& r) : m_rect(r.m_rect) {} wxRect m_rect; - bool m_eraseBackground; }; -WX_DEFINE_ARRAY_PTR(wxDfbPaintRequest*, wxDfbQueuedPaintRequests); +WX_DEFINE_ARRAY_PTR(wxDfbPaintRequest*, wxDfbQueuedPaintRequestsList); + +// Queue of paint requests +class wxDfbQueuedPaintRequests +{ +public: + ~wxDfbQueuedPaintRequests() { Clear(); } + + // Adds paint request to the queue + void Add(const wxRect& rect) + { m_queue.push_back(new wxDfbPaintRequest(rect)); } + + // Is the queue empty? + bool IsEmpty() const { return m_queue.empty(); } + + // Empties the queue + void Clear() { WX_CLEAR_ARRAY(m_queue); } + + // Gets requests in the queue + const wxDfbQueuedPaintRequestsList& GetRequests() const { return m_queue; } + +private: + wxDfbQueuedPaintRequestsList m_queue; +}; // ============================================================================ // wxTopLevelWindowDFB @@ -68,6 +88,7 @@ void wxTopLevelWindowDFB::Init() m_sizeSet = false; m_opacity = 255; m_toPaint = new wxDfbQueuedPaintRequests; + m_isPainting = false; } bool wxTopLevelWindowDFB::Create(wxWindow *parent, @@ -99,7 +120,7 @@ bool wxTopLevelWindowDFB::Create(wxWindow *parent, pos.y = 0; // create DirectFB window: - IDirectFBDisplayLayerPtr layer = wxDfbGetDisplayLayer(); + wxIDirectFBDisplayLayerPtr layer(wxIDirectFB::Get()->GetDisplayLayer()); wxCHECK_MSG( layer, false, _T("no display layer") ); DFBWindowDescription desc; @@ -111,20 +132,22 @@ bool wxTopLevelWindowDFB::Create(wxWindow *parent, desc.posy = pos.y; desc.width = size.x; desc.height = size.y; - if ( !DFB_CALL( layer->CreateWindow(layer, &desc, &m_dfbwin) ) ) + m_dfbwin = layer->CreateWindow(&desc); + if ( !layer ) return false; // add the new TLW to DFBWindowID->wxTLW map: DFBWindowID winid; - if ( !DFB_CALL( m_dfbwin->GetID(m_dfbwin, &winid) ) ) + if ( !m_dfbwin->GetID(&winid) ) return false; gs_dfbWindowsMap[winid] = this; // TLWs are created initially hidden: - if ( !DFB_CALL( m_dfbwin->SetOpacity(m_dfbwin, 0) ) ) + 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 ) @@ -135,12 +158,11 @@ bool wxTopLevelWindowDFB::Create(wxWindow *parent, if ( style & (wxSTAY_ON_TOP | wxPOPUP_WINDOW) ) { - DFB_CALL( m_dfbwin->SetStackingClass(m_dfbwin, DWSC_UPPER) ); + m_dfbwin->SetStackingClass(DWSC_UPPER); } // direct events in this window to the global event buffer: - DFB_CALL( m_dfbwin->AttachEventBuffer( - m_dfbwin, wxEventLoop::GetDirectFBEventBuffer()) ); + m_dfbwin->AttachEventBuffer(wxEventLoop::GetDirectFBEventBuffer()); return true; } @@ -159,12 +181,11 @@ wxTopLevelWindowDFB::~wxTopLevelWindowDFB() wxTheApp->ExitMainLoop(); } - WX_CLEAR_ARRAY(*m_toPaint); wxDELETE(m_toPaint); // remove the TLW from DFBWindowID->wxTLW map: DFBWindowID winid; - if ( DFB_CALL( m_dfbwin->GetID(m_dfbwin, &winid) ) ) + if ( m_dfbwin->GetID(&winid) ) gs_dfbWindowsMap.erase(winid); } @@ -174,12 +195,12 @@ wxTopLevelWindowDFB::~wxTopLevelWindowDFB() void wxTopLevelWindowDFB::DoGetPosition(int *x, int *y) const { - DFB_CALL( m_dfbwin->GetPosition(m_dfbwin, x, y) ); + m_dfbwin->GetPosition(x, y); } void wxTopLevelWindowDFB::DoGetSize(int *width, int *height) const { - DFB_CALL( m_dfbwin->GetSize(m_dfbwin, width, height) ); + m_dfbwin->GetSize(width, height); } void wxTopLevelWindowDFB::DoMoveWindow(int x, int y, int width, int height) @@ -187,15 +208,16 @@ void wxTopLevelWindowDFB::DoMoveWindow(int x, int y, int width, int height) wxPoint curpos = GetPosition(); if ( curpos.x != x || curpos.y != y ) { - DFB_CALL( m_dfbwin->MoveTo(m_dfbwin, x, y) ); + m_dfbwin->MoveTo(x, y); } wxSize cursize = GetSize(); if ( cursize.x != width || cursize.y != height ) { - DFB_CALL( m_dfbwin->Resize(m_dfbwin, width, height) ); + m_dfbwin->Resize(width, height); // we must repaint the window after it changed size: - Refresh(); + if ( IsShown() ) + DoRefreshWindow(); } } @@ -242,7 +264,7 @@ bool wxTopLevelWindowDFB::Show(bool show) return false; // hide/show the window by setting its opacity to 0/full: - DFB_CALL( m_dfbwin->SetOpacity(m_dfbwin, show ? m_opacity : 0) ); + m_dfbwin->SetOpacity(show ? m_opacity : 0); // If this is the first time Show was called, send size event, // so that the frame can adjust itself (think auto layout or single child) @@ -266,7 +288,7 @@ bool wxTopLevelWindowDFB::SetTransparent(wxByte alpha) { if ( IsShown() ) { - if ( !DFB_CALL( m_dfbwin->SetOpacity(m_dfbwin, alpha) ) ) + if ( !m_dfbwin->SetOpacity(alpha) ) return false; } @@ -328,40 +350,55 @@ bool wxTopLevelWindowDFB::IsIconized() const // surfaces and painting // ---------------------------------------------------------------------------- -IDirectFBSurfacePtr wxTopLevelWindowDFB::ObtainDfbSurface() const +wxIDirectFBSurfacePtr wxTopLevelWindowDFB::ObtainDfbSurface() const { - IDirectFBSurfacePtr surface; - DFB_CALL( m_dfbwin->GetSurface(m_dfbwin, &surface) ); - return surface; + return m_dfbwin->GetSurface(); } void wxTopLevelWindowDFB::HandleQueuedPaintRequests() { - wxDfbQueuedPaintRequests& toPaint = *m_toPaint; - if ( toPaint.empty() ) + if ( m_toPaint->IsEmpty() ) return; // nothing to do + if ( IsFrozen() || !IsShown() ) + { + // nothing to do if the window is frozen or hidden; clear the queue + // and return (note that it's OK to clear the queue even if the window + // is frozen, because Thaw() calls Refresh()): + m_toPaint->Clear(); + return; + } + + const wxDfbQueuedPaintRequestsList& requests = m_toPaint->GetRequests(); + // process queued paint requests: wxRect winRect(wxPoint(0, 0), GetSize()); wxRect paintedRect; - size_t cnt = toPaint.size(); + // 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; + + size_t cnt = requests.size(); + wxLogTrace(TRACE_PAINT, _T("%p ('%s'): processing %i paint requests"), + this, GetName().c_str(), cnt); + for ( size_t i = 0; i < cnt; ++i ) { - const wxDfbPaintRequest& request = *toPaint[i]; + const wxDfbPaintRequest& request = *requests[i]; 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); - 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() ) @@ -370,24 +407,53 @@ void wxTopLevelWindowDFB::HandleQueuedPaintRequests() paintedRect.Union(clipped); } - WX_CLEAR_ARRAY(toPaint); + 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; - IDirectFBSurfacePtr surface(GetDfbSurface()); - DFB_CALL( surface->Flip(surface, rptr, DSFLIP_NONE) ); + GetDfbSurface()->FlipToFront(rptr); + + wxLogTrace(TRACE_PAINT, + _T("%p ('%s'): flipped surface: [%i,%i,%i,%i]"), + this, GetName().c_str(), + paintedRect.x, paintedRect.y, + paintedRect.GetRight(), paintedRect.GetBottom()); } -void wxTopLevelWindowDFB::DoRefreshRect(const wxRect& rect, bool eraseBack) +void wxTopLevelWindowDFB::DoRefreshRect(const wxRect& rect) { - // defer paiting until idle time or until Update() is called: - m_toPaint->push_back(new wxDfbPaintRequest(rect, eraseBack)); + // 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); } void wxTopLevelWindowDFB::Update()