X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/0881232f66855042d84f969ac97ea631589f8631..b0bcc78732fb2ecef1fbfcf6c6ca5afbac4a29b6:/src/dfb/toplevel.cpp?ds=inline diff --git a/src/dfb/toplevel.cpp b/src/dfb/toplevel.cpp index bb1620b49a..8963419683 100644 --- a/src/dfb/toplevel.cpp +++ b/src/dfb/toplevel.cpp @@ -17,65 +17,9 @@ #include "wx/app.h" #endif // WX_PRECOMP -#include "wx/hashmap.h" -#include "wx/evtloop.h" #include "wx/dfb/private.h" -#define TRACE_EVENTS _T("events") -#define TRACE_PAINT _T("paint") - -// ============================================================================ -// globals -// ============================================================================ - -// mapping of DirectFB windows to wxTLWs: -WX_DECLARE_HASH_MAP(DFBWindowID, wxTopLevelWindowDFB*, - wxIntegerHash, wxIntegerEqual, - wxDfbWindowsMap); -static wxDfbWindowsMap gs_dfbWindowsMap; - -// ============================================================================ -// helpers -// ============================================================================ - -// Queue of paint requests -class wxDfbQueuedPaintRequests -{ -public: - ~wxDfbQueuedPaintRequests() { Clear(); } - - // Adds paint request to the queue - 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_invalidated.IsEmpty(); } - - // Empties the queue - void Clear() { m_invalidated = wxRect(); } - - // 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: - // currently invalidated region - wxRect m_invalidated; -}; +#define TRACE_EVENTS "events" // ============================================================================ // wxTopLevelWindowDFB @@ -87,13 +31,8 @@ private: void wxTopLevelWindowDFB::Init() { - m_isShown = false; m_isMaximized = false; m_fsIsShowing = false; - m_sizeSet = false; - m_opacity = 255; - m_toPaint = new wxDfbQueuedPaintRequests; - m_isPainting = false; } bool wxTopLevelWindowDFB::Create(wxWindow *parent, @@ -104,8 +43,6 @@ bool wxTopLevelWindowDFB::Create(wxWindow *parent, long style, const wxString &name) { - m_tlw = this; - // always create a frame of some reasonable, even if arbitrary, size (at // least for MSW compatibility) wxSize size(sizeOrig); @@ -124,113 +61,15 @@ bool wxTopLevelWindowDFB::Create(wxWindow *parent, if ( pos.y == wxDefaultCoord ) pos.y = 0; - // create DirectFB window: - wxIDirectFBDisplayLayerPtr layer(wxIDirectFB::Get()->GetDisplayLayer()); - wxCHECK_MSG( layer, false, _T("no display layer") ); - - DFBWindowDescription desc; - desc.flags = (DFBWindowDescriptionFlags) - (DWDESC_CAPS | - DWDESC_WIDTH | DWDESC_HEIGHT | DWDESC_POSX | DWDESC_POSY); - desc.caps = DWCAPS_DOUBLEBUFFER; - desc.posx = pos.x; - desc.posy = pos.y; - desc.width = size.x; - desc.height = size.y; - m_dfbwin = layer->CreateWindow(&desc); - if ( !m_dfbwin ) - return false; - - // add the new TLW to DFBWindowID->wxTLW map: - DFBWindowID winid; - if ( !m_dfbwin->GetID(&winid) ) + if ( !wxNonOwnedWindow::Create(parent, id, pos, size, style, name) ) return false; - gs_dfbWindowsMap[winid] = this; - - // TLWs are created initially hidden: - if ( !m_dfbwin->SetOpacity(wxALPHA_TRANSPARENT) ) - return false; - - if ( !wxWindow::Create(NULL, id, pos, size, style, name) ) - return false; - - SetParent(parent); - if ( parent ) - parent->AddChild(this); wxTopLevelWindows.Append(this); m_title = title; - if ( style & (wxSTAY_ON_TOP | wxPOPUP_WINDOW) ) - { - m_dfbwin->SetStackingClass(DWSC_UPPER); - } - - // direct events in this window to the global event buffer: - m_dfbwin->AttachEventBuffer(wxEventLoop::GetDirectFBEventBuffer()); - return true; } -wxTopLevelWindowDFB::~wxTopLevelWindowDFB() -{ - m_isBeingDeleted = true; - - // destroy all children before we destroy the underlying DirectFB window, - // so that if any of them does something with the TLW, it will still work: - DestroyChildren(); - - // it's safe to delete the underlying DirectFB window now: - wxDELETE(m_toPaint); - - if ( !m_dfbwin ) - return; - - // remove the TLW from DFBWindowID->wxTLW map: - DFBWindowID winid; - if ( m_dfbwin->GetID(&winid) ) - gs_dfbWindowsMap.erase(winid); - - m_dfbwin->Destroy(); - m_dfbwin.Reset(); -} - -// ---------------------------------------------------------------------------- -// window size & position -// ---------------------------------------------------------------------------- - -void wxTopLevelWindowDFB::DoGetPosition(int *x, int *y) const -{ - m_dfbwin->GetPosition(x, y); -} - -void wxTopLevelWindowDFB::DoGetSize(int *width, int *height) const -{ - m_dfbwin->GetSize(width, height); -} - -void wxTopLevelWindowDFB::DoMoveWindow(int x, int y, int width, int height) -{ - wxPoint curpos = GetPosition(); - if ( curpos.x != x || curpos.y != y ) - { - m_dfbwin->MoveTo(x, y); - } - - 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: - if ( IsShown() ) - DoRefreshWindow(); - } -} - // ---------------------------------------------------------------------------- // showing and hiding // ---------------------------------------------------------------------------- @@ -238,7 +77,8 @@ void wxTopLevelWindowDFB::DoMoveWindow(int x, int y, int width, int height) #warning "FIXME: the rest of this file is almost same as for MGL, merge it" bool wxTopLevelWindowDFB::ShowFullScreen(bool show, long style) { - if (show == m_fsIsShowing) return false; // return what? + if ( show == m_fsIsShowing ) + return true; m_fsIsShowing = show; @@ -268,53 +108,6 @@ bool wxTopLevelWindowDFB::ShowFullScreen(bool show, long style) return true; } -bool wxTopLevelWindowDFB::Show(bool show) -{ - // NB: this calls wxWindow::Show() and so ensures DoRefreshWindow() is - // called on the window -- we'll need that below - if ( !wxTopLevelWindowBase::Show(show) ) - return false; - - // 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) - if ( !m_sizeSet ) - { - m_sizeSet = true; - wxSizeEvent event(GetSize(), GetId()); - event.SetEventObject(this); - GetEventHandler()->ProcessEvent(event); - } - - // make sure the window is fully painted, with all pending updates, before - // DFB WM shows it, otherwise it would attempt to show either empty (= - // black) window surface (if shown for the first time) or it would show - // window with outdated content; note that the window was already refreshed - // in the wxTopLevelWindowBase::Show() call above: - if ( show ) - Update(); - - // hide/show the window by setting its opacity to 0/full: - m_dfbwin->SetOpacity(show ? m_opacity : 0); - - 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; -} - bool wxTopLevelWindowDFB::SetTransparent(wxByte alpha) { if ( IsShown() ) @@ -376,193 +169,39 @@ bool wxTopLevelWindowDFB::IsIconized() const return false; } - // ---------------------------------------------------------------------------- -// surfaces and painting +// focus handling // ---------------------------------------------------------------------------- -wxIDirectFBSurfacePtr wxTopLevelWindowDFB::ObtainDfbSurface() const -{ - return m_dfbwin->GetSurface(); -} - -void wxTopLevelWindowDFB::HandleQueuedPaintRequests() -{ - 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; - } - - // process queued paint requests: - wxRect winRect(wxPoint(0, 0), GetSize()); - wxRect paintedRect; - - // 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; - -#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 - - 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() ) - paintedRect = clipped; - else - 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. 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()->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) -{ - // 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() -{ - HandleQueuedPaintRequests(); -} - -// --------------------------------------------------------------------------- -// events handling -// --------------------------------------------------------------------------- - -void wxTopLevelWindowDFB::SetDfbFocus() +void wxTopLevelWindowDFB::HandleFocusEvent(const wxDFBWindowEvent& event_) { - wxCHECK_RET( IsShown(), _T("cannot set focus to hidden window") ); - wxASSERT_MSG( FindFocus() && FindFocus()->GetTLW() == this, - _T("setting DirectFB focus to unexpected window") ); + const DFBWindowEvent& dfbevent = event_; + const bool activate = (dfbevent.type == DWET_GOTFOCUS); - GetDirectFBWindow()->RequestFocus(); -} + wxLogTrace(TRACE_EVENTS, + "toplevel window %p ('%s') %s focus", + this, GetName(), + activate ? "got" : "lost"); -/* static */ -void wxTopLevelWindowDFB::HandleDFBWindowEvent(const wxDFBWindowEvent& event_) -{ - const DFBWindowEvent& event = event_; + wxActivateEvent event(wxEVT_ACTIVATE, activate, GetId()); + event.SetEventObject(this); + HandleWindowEvent(event); - if ( gs_dfbWindowsMap.find(event.window_id) == gs_dfbWindowsMap.end() ) + // if a frame that doesn't have wx focus inside it just got focus, we + // need to set focus to it (or its child): + if ( activate ) { - wxLogTrace(TRACE_EVENTS, - _T("received event for unknown DirectFB window, ignoring")); - return; - } - - wxTopLevelWindowDFB *tlw = gs_dfbWindowsMap[event.window_id]; - wxWindow *recipient = NULL; - void (wxWindow::*handlerFunc)(const wxDFBWindowEvent&) = NULL; - - switch ( event.type ) - { - case DWET_KEYDOWN: - case DWET_KEYUP: - { - recipient = wxWindow::FindFocus(); - handlerFunc = &wxWindowDFB::HandleKeyEvent; - break; - } - - case DWET_NONE: - case DWET_ALL: + wxWindow *focused = wxWindow::FindFocus(); + if ( !focused || focused->GetTLW() != this ) { - wxFAIL_MSG( _T("invalid event type") ); - break; + wxLogTrace(TRACE_EVENTS, + "setting wx focus to toplevel window %p ('%s')", + this, GetName()); + + if ( CanAcceptFocus() ) + SetFocus(); + else + wxLogTrace(TRACE_EVENTS, "...which doesn't accept it"); } - - default: - // we're not interested in them here - break; } - - if ( !recipient ) - { - wxLogTrace(TRACE_EVENTS, _T("ignoring event: no recipient window")); - return; - } - - wxCHECK_RET( recipient && recipient->GetTLW() == tlw, - _T("event recipient not in TLW which received the event") ); - - // process the event: - (recipient->*handlerFunc)(event_); -} - -// --------------------------------------------------------------------------- -// idle events processing -// --------------------------------------------------------------------------- - -void wxTopLevelWindowDFB::OnInternalIdle() -{ - wxTopLevelWindowBase::OnInternalIdle(); - HandleQueuedPaintRequests(); }