]> git.saurik.com Git - wxWidgets.git/blobdiff - src/dfb/window.cpp
include wx/thread.h in debug build which is needed after last change
[wxWidgets.git] / src / dfb / window.cpp
index 30e38e98276ff49450b2bdf8d0c1363e77421ca5..c115e67ab9d9b49e78933bf2f31414ed07b0a400 100644 (file)
 
 #ifndef WX_PRECOMP
     #include "wx/dcclient.h"
+    #include "wx/nonownedwnd.h"
 #endif
 
 #include "wx/caret.h"
+#include "wx/dynarray.h"
 
 #include "wx/dfb/private.h"
+#include "wx/private/overlay.h"
 
 #define TRACE_EVENTS _T("events")
 #define TRACE_PAINT  _T("paint")
@@ -53,6 +56,12 @@ static wxWindow *gs_toBeFocusedWindow = NULL;
 // the window that has mouse capture
 static wxWindowDFB *gs_mouseCapture = NULL;
 
+// ---------------------------------------------------------------------------
+// overlays support
+// ---------------------------------------------------------------------------
+
+WX_DEFINE_ARRAY_PTR(wxOverlayImpl*, wxDfbOverlaysList);
+
 // ---------------------------------------------------------------------------
 // event tables
 // ---------------------------------------------------------------------------
@@ -72,6 +81,7 @@ void wxWindowDFB::Init()
     m_isShown = true;
     m_frozenness = 0;
     m_tlw = NULL;
+    m_overlays = NULL;
 }
 
 // Destructor
@@ -104,7 +114,7 @@ wxWindowDFB::~wxWindowDFB()
 #endif
 
     if ( gs_focusedWindow == this )
-        KillFocus();
+        DFBKillFocus();
 
     DestroyChildren();
 }
@@ -173,6 +183,14 @@ wxIDirectFBSurfacePtr wxWindowDFB::GetDfbSurface()
 void wxWindowDFB::InvalidateDfbSurface()
 {
     m_surface = NULL;
+
+    // surfaces of the children are subsurfaces of this window's surface,
+    // so they must be invalidated as well:
+    wxWindowList& children = GetChildren();
+    for ( wxWindowList::iterator i = children.begin(); i != children.end(); ++i )
+    {
+        (*i)->InvalidateDfbSurface();
+    }
 }
 
 // ---------------------------------------------------------------------------
@@ -181,26 +199,29 @@ void wxWindowDFB::InvalidateDfbSurface()
 
 void wxWindowDFB::SetFocus()
 {
-    if ( gs_focusedWindow == this ) return;
+    if ( gs_focusedWindow == this )
+        return; // nothing to do, focused already
 
     wxWindowDFB *oldFocusedWindow = gs_focusedWindow;
 
     if ( gs_focusedWindow )
     {
         gs_toBeFocusedWindow = (wxWindow*)this;
-        gs_focusedWindow->KillFocus();
+        gs_focusedWindow->DFBKillFocus();
         gs_toBeFocusedWindow = NULL;
     }
 
-#warning "FIXME: implement in terms of DWET_{GOT,LOST}FOCUS"
-
-    wxIDirectFBWindowPtr dfbwin(m_tlw->GetDirectFBWindow());
-#warning "FIXME: RequestFocus() may only be called on visible TLW"
-    if ( !dfbwin->RequestFocus() )
-        return;
-
     gs_focusedWindow = this;
 
+    if ( IsShownOnScreen() )
+    {
+        m_tlw->SetDfbFocus();
+    }
+    // else: do nothing, because DirectFB windows cannot have focus if they
+    //       are hidden; when the TLW becomes visible, it will set the focus
+    //       to use from wxTLW::Show()
+
+    #warning "FIXME: implement in terms of DWET_{GOT,LOST}FOCUS"
     #warning "FIXME: keep this or not? not, think multiapp core"
 #if 0
     wxWindowDFB *active = wxGetTopLevelParent((wxWindow*)this);
@@ -220,6 +241,11 @@ void wxWindowDFB::SetFocus()
     }
 #endif
 
+    // notify the parent keeping track of focus for the kbd navigation
+    // purposes that we got it
+    wxChildFocusEvent eventFocus((wxWindow*)this);
+    GetEventHandler()->ProcessEvent(eventFocus);
+
     wxFocusEvent event(wxEVT_SET_FOCUS, GetId());
     event.SetEventObject(this);
     event.SetWindow((wxWindow*)oldFocusedWindow);
@@ -233,12 +259,15 @@ void wxWindowDFB::SetFocus()
 #endif // wxUSE_CARET
 }
 
-void wxWindowDFB::KillFocus()
+void wxWindowDFB::DFBKillFocus()
 {
-    if ( gs_focusedWindow != this ) return;
+    wxCHECK_RET( gs_focusedWindow == this,
+                 _T("killing focus on window that doesn't have it") );
+
     gs_focusedWindow = NULL;
 
-    if ( m_isBeingDeleted ) return;
+    if ( m_isBeingDeleted )
+        return; // don't send any events from dtor
 
 #if wxUSE_CARET
     // caret needs to be informed about focus change
@@ -441,10 +470,21 @@ void wxWindowDFB::DoGetClientSize(int *x, int *y) const
 
 void wxWindowDFB::DoMoveWindow(int x, int y, int width, int height)
 {
+    // NB: [x,y] arguments are in (parent's) window coordinates, while
+    //     m_rect.{x,y} are in (parent's) client coordinates. That's why we
+    //     offset by parentOrigin in some places below
+
+    wxPoint parentOrigin(0, 0);
+    AdjustForParentClientOrigin(parentOrigin.x, parentOrigin.y);
+
     wxRect oldpos(m_rect);
+    oldpos.Offset(parentOrigin);
+
     wxRect newpos(x, y, width, height);
 
+    // input [x,y] is in window coords, but we store client coords in m_rect:
     m_rect = newpos;
+    m_rect.Offset(-parentOrigin);
 
     // window's position+size changed and so did the subsurface that covers it
     InvalidateDfbSurface();
@@ -453,9 +493,15 @@ void wxWindowDFB::DoMoveWindow(int x, int y, int width, int height)
     {
         // queue both former and new position of the window for repainting:
         wxWindow *parent = GetParent();
-        wxPoint origin(parent->GetClientAreaOrigin());
-        oldpos.Offset(origin);
-        newpos.Offset(origin);
+
+        // only refresh the visible parts:
+        if ( !CanBeOutsideClientArea() )
+        {
+            wxRect parentClient(parent->GetClientSize());
+            oldpos.Intersect(parentClient);
+            newpos.Intersect(parentClient);
+        }
+
         parent->RefreshRect(oldpos);
         parent->RefreshRect(newpos);
     }
@@ -489,8 +535,6 @@ void wxWindowDFB::DoSetSize(int x, int y, int width, int height, int sizeFlags)
         return;
     }
 
-    AdjustForParentClientOrigin(x, y, sizeFlags);
-
     wxSize size(-1, -1);
     if ( width == -1 )
     {
@@ -538,6 +582,7 @@ void wxWindowDFB::DoSetSize(int x, int y, int width, int height, int sizeFlags)
     if ( m_rect.x != x || m_rect.y != y ||
          m_rect.width != width || m_rect.height != height )
     {
+        AdjustForParentClientOrigin(x, y, sizeFlags);
         DoMoveWindow(x, y, width, height);
 
         wxSize newSize(width, height);
@@ -597,7 +642,7 @@ void wxWindowDFB::Refresh(bool WXUNUSED(eraseBack), const wxRect *rect)
 
     // NB[1]: We intentionally ignore the eraseBack argument here. This is
     //        because of the way wxDFB's painting is implemented: the refresh
-    //        request is probagated up to wxTLW, which is then painted in
+    //        request is propagated up to wxTLW, which is then painted in
     //        top-down order. This means that this window's area is first
     //        painted by its parent and this window is then painted over it, so
     //        it's not safe to not paint this window's background even if
@@ -612,6 +657,14 @@ void wxWindowDFB::Refresh(bool WXUNUSED(eraseBack), const wxRect *rect)
         DoRefreshWindow();
 }
 
+void wxWindowDFB::RefreshWindowRect(const wxRect& rect)
+{
+    if ( !IsShown() || IsFrozen() )
+        return;
+
+    DoRefreshRect(rect);
+}
+
 void wxWindowDFB::DoRefreshWindow()
 {
     // NB: DoRefreshRect() takes window coords, not client, so this is correct
@@ -639,6 +692,11 @@ void wxWindowDFB::DoRefreshRect(const wxRect& rect)
     r.Offset(GetPosition());
     r.Offset(parent->GetClientAreaOrigin());
 
+    // normal windows cannot extend out of its parent's client area, so don't
+    // refresh any hidden parts:
+    if ( !CanBeOutsideClientArea() )
+        r.Intersect(parent->GetClientRect());
+
     parent->DoRefreshRect(r);
 }
 
@@ -677,13 +735,6 @@ void wxWindowDFB::PaintWindow(const wxRect& rect)
 
     m_updateRegion = rect;
 
-#if wxUSE_CARET
-    // must hide caret temporarily, otherwise we'd get rendering artifacts
-    wxCaret *caret = GetCaret();
-    if ( caret )
-        caret->Hide();
-#endif // wxUSE_CARET
-
     // FIXME_DFB: don't waste time rendering the area if it's fully covered
     //            by some children, go directly to rendering the children
 
@@ -697,7 +748,7 @@ void wxWindowDFB::PaintWindow(const wxRect& rect)
     wxRect clientRect(GetClientRect());
 
     // only send wxNcPaintEvent if drawing at least part of nonclient area:
-    if ( !clientRect.Inside(rect) )
+    if ( !clientRect.Contains(rect) )
     {
         wxNcPaintEvent eventNc(GetId());
         eventNc.SetEventObject(this);
@@ -722,13 +773,15 @@ void wxWindowDFB::PaintWindow(const wxRect& rect)
                    this, GetName().c_str());
     }
 
-#if wxUSE_CARET
-    if ( caret )
-        caret->Show();
-#endif // wxUSE_CARET
+    // draw window's overlays on top of the painted window, if we have any:
+    PaintOverlays(rect);
 
     m_updateRegion.Clear();
 
+    // client area portion of 'rect':
+    wxRect rectClientOnly(rect);
+    rectClientOnly.Intersect(clientRect);
+
     // paint the children:
     wxPoint origin = GetClientAreaOrigin();
     wxWindowList& children = GetChildren();
@@ -743,7 +796,12 @@ void wxWindowDFB::PaintWindow(const wxRect& rect)
         // compute child's area to repaint
         wxRect childrect(child->GetRect());
         childrect.Offset(origin);
-        childrect.Intersect(rect);
+
+        if ( child->CanBeOutsideClientArea() )
+            childrect.Intersect(rect);
+        else
+            childrect.Intersect(rectClientOnly);
+
         if ( childrect.IsEmpty() )
             continue;
 
@@ -754,6 +812,59 @@ void wxWindowDFB::PaintWindow(const wxRect& rect)
     }
 }
 
+void wxWindowDFB::PaintOverlays(const wxRect& rect)
+{
+    if ( !m_overlays )
+        return;
+
+    for ( wxDfbOverlaysList::const_iterator i = m_overlays->begin();
+          i != m_overlays->end(); ++i )
+    {
+        wxOverlayImpl *overlay = *i;
+
+        wxRect orectOrig(overlay->GetRect());
+        wxRect orect(orectOrig);
+        orect.Intersect(rect);
+        if ( orect.IsEmpty() )
+            continue;
+
+        if ( overlay->IsEmpty() )
+            continue; // nothing to paint
+
+        DFBRectangle dfbRect = { orect.x - orectOrig.x, orect.y - orectOrig.y,
+                                 orect.width, orect.height };
+        GetDfbSurface()->Blit
+                         (
+                           overlay->GetDirectFBSurface(),
+                           &dfbRect,
+                           orect.x, orect.y
+                         );
+    }
+}
+
+void wxWindowDFB::AddOverlay(wxOverlayImpl *overlay)
+{
+    if ( !m_overlays )
+        m_overlays = new wxDfbOverlaysList;
+
+    m_overlays->Add(overlay);
+}
+
+void wxWindowDFB::RemoveOverlay(wxOverlayImpl *overlay)
+{
+    wxCHECK_RET( m_overlays, _T("no overlays to remove") );
+
+    m_overlays->Remove(overlay);
+
+    if ( m_overlays->empty() )
+    {
+        wxDELETE(m_overlays);
+    }
+
+    if ( !m_isBeingDeleted )
+        RefreshWindowRect(overlay->GetRect());
+}
+
 
 // ---------------------------------------------------------------------------
 // events handling
@@ -830,6 +941,11 @@ static long GetTranslatedKeyCode(DFBInputDeviceKeyIdentifier key_id)
         KEY(DIKI_CONTROL_R,         WXK_CONTROL);
         KEY(DIKI_ALT_L,             WXK_ALT);
         KEY(DIKI_ALT_R,             WXK_ALT);
+        // this key was removed in 0.9.25 but include it for previous versions
+        // just to avoid gcc warnings about unhandled enum value in switch
+#if !wxCHECK_DFB_VERSION(0, 9, 24)
+        KEY(DIKI_ALTGR,             0);
+#endif
         KEY(DIKI_META_L,            0);
         KEY(DIKI_META_R,            0);
         KEY(DIKI_SUPER_L,           0);