]> git.saurik.com Git - wxWidgets.git/blobdiff - src/dfb/toplevel.cpp
Avoid calling gtk_window_get_position() from "configure-event" handler, if possible.
[wxWidgets.git] / src / dfb / toplevel.cpp
index 5c042f3358a574ca434c80eb8c68f077927f7aed..dc3f425d06c156d589d85a411f9043d1a18d30c2 100644 (file)
@@ -3,7 +3,6 @@
 // Purpose:     Top level window, abstraction of wxFrame and wxDialog
 // Author:      Vaclav Slavik
 // Created:     2006-08-10
-// RCS-ID:      $Id$
 // Copyright:   (c) 2006 REA Elektronik GmbH
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
     #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 +30,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 +42,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,126 +60,23 @@ 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;
-
-    wxTopLevelWindows.DeleteObject(this);
-
-    if ( wxTheApp->GetTopWindow() == this )
-        wxTheApp->SetTopWindow(NULL);
-
-    if ( wxTopLevelWindows.empty() && wxTheApp->GetExitOnFrameDelete() )
-    {
-        wxTheApp->ExitMainLoop();
-    }
-
-    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
 // ----------------------------------------------------------------------------
 
-#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;
 
@@ -273,43 +106,6 @@ bool wxTopLevelWindowDFB::ShowFullScreen(bool show, long style)
     return true;
 }
 
-bool wxTopLevelWindowDFB::Show(bool show)
-{
-    if ( !wxTopLevelWindowBase::Show(show) )
-        return false;
-
-    // hide/show the window by setting its opacity to 0/full:
-    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)
-    if ( !m_sizeSet )
-    {
-        m_sizeSet = true;
-        wxSizeEvent event(GetSize(), GetId());
-        event.SetEventObject(this);
-        GetEventHandler()->ProcessEvent(event);
-    }
-
-    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() )
@@ -371,193 +167,39 @@ bool wxTopLevelWindowDFB::IsIconized() const
     return false;
 }
 
-
 // ----------------------------------------------------------------------------
-// surfaces and painting
+// focus handling
 // ----------------------------------------------------------------------------
 
-wxIDirectFBSurfacePtr wxTopLevelWindowDFB::ObtainDfbSurface() const
+void wxTopLevelWindowDFB::HandleFocusEvent(const wxDFBWindowEvent& event_)
 {
-    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;
-    }
+    const DFBWindowEvent& dfbevent = event_;
+    const bool activate = (dfbevent.type == DWET_GOTFOCUS);
 
-    // process queued paint requests:
-    wxRect winRect(wxPoint(0, 0), GetSize());
-    wxRect paintedRect;
+    wxLogTrace(TRACE_EVENTS,
+               "toplevel window %p ('%s') %s focus",
+               this, GetName(),
+               activate ? "got" : "lost");
 
-    // 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;
+    wxActivateEvent event(wxEVT_ACTIVATE, activate, GetId());
+    event.SetEventObject(this);
+    HandleWindowEvent(event);
 
-#ifdef __WXDEBUG__
-    int requestsCount = 0;
-#endif
-
-    wxRect request;
-    while ( m_toPaint->GetNext(request) )
+    // 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 )
     {
-#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()
-{
-    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_)
-{
-    const DFBWindowEvent& event = event_;
-
-    if ( gs_dfbWindowsMap.find(event.window_id) == gs_dfbWindowsMap.end() )
-    {
-        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();
 }