]> git.saurik.com Git - wxWidgets.git/blobdiff - src/dfb/window.cpp
[ 1572220 ] Show popup when wxComboCtrl image area clicked
[wxWidgets.git] / src / dfb / window.cpp
index f2b090be72e044f10191c960c1c71af2afdcb366..4839e08f65363f8e2d4a3f0e375fa5dd0174b7b0 100644 (file)
@@ -104,7 +104,7 @@ wxWindowDFB::~wxWindowDFB()
 #endif
 
     if ( gs_focusedWindow == this )
 #endif
 
     if ( gs_focusedWindow == this )
-        KillFocus();
+        DFBKillFocus();
 
     DestroyChildren();
 }
 
     DestroyChildren();
 }
@@ -173,6 +173,14 @@ wxIDirectFBSurfacePtr wxWindowDFB::GetDfbSurface()
 void wxWindowDFB::InvalidateDfbSurface()
 {
     m_surface = NULL;
 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 +189,29 @@ void wxWindowDFB::InvalidateDfbSurface()
 
 void wxWindowDFB::SetFocus()
 {
 
 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;
 
     wxWindowDFB *oldFocusedWindow = gs_focusedWindow;
 
     if ( gs_focusedWindow )
     {
         gs_toBeFocusedWindow = (wxWindow*)this;
-        gs_focusedWindow->KillFocus();
+        gs_focusedWindow->DFBKillFocus();
         gs_toBeFocusedWindow = NULL;
     }
 
         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;
 
     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);
     #warning "FIXME: keep this or not? not, think multiapp core"
 #if 0
     wxWindowDFB *active = wxGetTopLevelParent((wxWindow*)this);
@@ -220,6 +231,11 @@ void wxWindowDFB::SetFocus()
     }
 #endif
 
     }
 #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);
     wxFocusEvent event(wxEVT_SET_FOCUS, GetId());
     event.SetEventObject(this);
     event.SetWindow((wxWindow*)oldFocusedWindow);
@@ -233,12 +249,15 @@ void wxWindowDFB::SetFocus()
 #endif // wxUSE_CARET
 }
 
 #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;
 
     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
 
 #if wxUSE_CARET
     // caret needs to be informed about focus change
@@ -441,10 +460,21 @@ void wxWindowDFB::DoGetClientSize(int *x, int *y) const
 
 void wxWindowDFB::DoMoveWindow(int x, int y, int width, int height)
 {
 
 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);
     wxRect oldpos(m_rect);
+    oldpos.Offset(parentOrigin);
+
     wxRect newpos(x, y, width, height);
 
     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 = newpos;
+    m_rect.Offset(-parentOrigin);
 
     // window's position+size changed and so did the subsurface that covers it
     InvalidateDfbSurface();
 
     // window's position+size changed and so did the subsurface that covers it
     InvalidateDfbSurface();
@@ -453,9 +483,6 @@ 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();
     {
         // queue both former and new position of the window for repainting:
         wxWindow *parent = GetParent();
-        wxPoint origin(parent->GetClientAreaOrigin());
-        oldpos.Offset(origin);
-        newpos.Offset(origin);
         parent->RefreshRect(oldpos);
         parent->RefreshRect(newpos);
     }
         parent->RefreshRect(oldpos);
         parent->RefreshRect(newpos);
     }
@@ -489,8 +516,6 @@ void wxWindowDFB::DoSetSize(int x, int y, int width, int height, int sizeFlags)
         return;
     }
 
         return;
     }
 
-    AdjustForParentClientOrigin(x, y, sizeFlags);
-
     wxSize size(-1, -1);
     if ( width == -1 )
     {
     wxSize size(-1, -1);
     if ( width == -1 )
     {
@@ -538,6 +563,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 )
     {
     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);
         DoMoveWindow(x, y, width, height);
 
         wxSize newSize(width, height);
@@ -590,34 +616,56 @@ void wxWindowDFB::Clear()
     dc.Clear();
 }
 
     dc.Clear();
 }
 
-void wxWindowDFB::Refresh(bool eraseBack, const wxRect *rect)
+void wxWindowDFB::Refresh(bool WXUNUSED(eraseBack), const wxRect *rect)
 {
     if ( !IsShown() || IsFrozen() )
         return;
 
 {
     if ( !IsShown() || IsFrozen() )
         return;
 
+    // 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
+    //        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
+    //        eraseBack=false.
+    // NB[2]: wxWindow::Refresh() takes the rectangle in client coords, but
+    //        wxUniv translates it to window coords before passing it to
+    //        wxWindowDFB::Refresh(), so we can directly pass the rect to
+    //        DoRefreshRect (which takes window, not client, coords) here.
     if ( rect )
     if ( rect )
-        DoRefreshRect(*rect, eraseBack);
+        DoRefreshRect(*rect);
     else
     else
-        DoRefreshWindow(eraseBack);
+        DoRefreshWindow();
 }
 
 }
 
-void wxWindowDFB::DoRefreshWindow(bool eraseBack)
+void wxWindowDFB::DoRefreshWindow()
 {
 {
-    DoRefreshRect(wxRect(wxPoint(0, 0), GetSize()), eraseBack);
+    // NB: DoRefreshRect() takes window coords, not client, so this is correct
+    DoRefreshRect(wxRect(GetSize()));
 }
 
 }
 
-void wxWindowDFB::DoRefreshRect(const wxRect& rect, bool eraseBack)
+void wxWindowDFB::DoRefreshRect(const wxRect& rect)
 {
     wxWindow *parent = GetParent();
     wxCHECK_RET( parent, _T("no parent") );
 
 {
     wxWindow *parent = GetParent();
     wxCHECK_RET( parent, _T("no parent") );
 
+    // 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'): refresh rect [%i,%i,%i,%i]"),
+               this, GetName().c_str(),
+               rect.x, rect.y, rect.GetRight(), rect.GetBottom());
+
     // convert the refresh rectangle to parent's coordinates and
     // recursively refresh the parent:
     // convert the refresh rectangle to parent's coordinates and
     // recursively refresh the parent:
-    wxRect r(rect);
     r.Offset(GetPosition());
     r.Offset(parent->GetClientAreaOrigin());
 
     r.Offset(GetPosition());
     r.Offset(parent->GetClientAreaOrigin());
 
-    parent->DoRefreshRect(r, eraseBack);
+    parent->DoRefreshRect(r);
 }
 
 void wxWindowDFB::Update()
 }
 
 void wxWindowDFB::Update()
@@ -640,52 +688,80 @@ void wxWindowDFB::Thaw()
     if ( --m_frozenness == 0 )
     {
         if ( IsShown() )
     if ( --m_frozenness == 0 )
     {
         if ( IsShown() )
-            Refresh();
+            DoRefreshWindow();
     }
 }
 
     }
 }
 
-void wxWindowDFB::PaintWindow(const wxRect& rect, bool eraseBackground)
+void wxWindowDFB::PaintWindow(const wxRect& rect)
 {
     wxCHECK_RET( !IsFrozen() && IsShown(), _T("shouldn't be called") );
 
     wxLogTrace(TRACE_PAINT,
 {
     wxCHECK_RET( !IsFrozen() && IsShown(), _T("shouldn't be called") );
 
     wxLogTrace(TRACE_PAINT,
-               _T("%p ('%s'): painting region [x=%i,y=%i,w=%i,h=%i]"),
+               _T("%p ('%s'): painting region [%i,%i,%i,%i]"),
                this, GetName().c_str(),
                this, GetName().c_str(),
-               rect.x, rect.y, rect.width, rect.height);
-
-    m_updateRegion = rect;
-
-    // FIXME_DFB: don't waste time rendering the area if it's fully covered
-    //            by some children, go directly to rendering the children
+               rect.x, rect.y, rect.GetRight(), rect.GetBottom());
 
 #if wxUSE_CARET
 
 #if wxUSE_CARET
+    // FIXME: we're doing this before setting m_updateRegion because wxDFB
+    //        clips all DCs for this window to it, but this results in flicker,
+    //        it should be fixed by using overlays for the caret
+
     // must hide caret temporarily, otherwise we'd get rendering artifacts
     wxCaret *caret = GetCaret();
     if ( caret )
         caret->Hide();
 #endif // wxUSE_CARET
 
     // must hide caret temporarily, otherwise we'd get rendering artifacts
     wxCaret *caret = GetCaret();
     if ( caret )
         caret->Hide();
 #endif // wxUSE_CARET
 
-    if ( eraseBackground )
+    m_updateRegion = rect;
+
+    // FIXME_DFB: don't waste time rendering the area if it's fully covered
+    //            by some children, go directly to rendering the children
+
+    // NB: unconditionally send wxEraseEvent, because our implementation of
+    //     wxWindow::Refresh() ignores the eraseBack argument
+    wxWindowDC dc((wxWindow*)this);
+    wxEraseEvent eventEr(m_windowId, &dc);
+    eventEr.SetEventObject(this);
+    GetEventHandler()->ProcessEvent(eventEr);
+
+    wxRect clientRect(GetClientRect());
+
+    // only send wxNcPaintEvent if drawing at least part of nonclient area:
+    if ( !clientRect.Contains(rect) )
     {
     {
-        wxWindowDC dc((wxWindow*)this);
-        wxEraseEvent eventEr(m_windowId, &dc);
-        eventEr.SetEventObject(this);
-        GetEventHandler()->ProcessEvent(eventEr);
+        wxNcPaintEvent eventNc(GetId());
+        eventNc.SetEventObject(this);
+        GetEventHandler()->ProcessEvent(eventNc);
+    }
+    else
+    {
+        wxLogTrace(TRACE_PAINT, _T("%p ('%s'): not sending wxNcPaintEvent"),
+                   this, GetName().c_str());
     }
 
     }
 
-    wxNcPaintEvent eventNc(GetId());
-    eventNc.SetEventObject(this);
-    GetEventHandler()->ProcessEvent(eventNc);
+    // only send wxPaintEvent if drawing at least part of client area:
+    if ( rect.Intersects(clientRect) )
+    {
+        wxPaintEvent eventPt(GetId());
+        eventPt.SetEventObject(this);
+        GetEventHandler()->ProcessEvent(eventPt);
+    }
+    else
+    {
+        wxLogTrace(TRACE_PAINT, _T("%p ('%s'): not sending wxPaintEvent"),
+                   this, GetName().c_str());
+    }
 
 
-    wxPaintEvent eventPt(GetId());
-    eventPt.SetEventObject(this);
-    GetEventHandler()->ProcessEvent(eventPt);
+    m_updateRegion.Clear();
 
 #if wxUSE_CARET
 
 #if wxUSE_CARET
+    // FIXME: this should be ideally done before m_updateRegion.Clear() or not
+    //        at all, see the comment where the caret is hidden
     if ( caret )
         caret->Show();
 #endif // wxUSE_CARET
 
     if ( caret )
         caret->Show();
 #endif // wxUSE_CARET
 
+    // paint the children:
     wxPoint origin = GetClientAreaOrigin();
     wxWindowList& children = GetChildren();
     for ( wxWindowList::iterator i = children.begin();
     wxPoint origin = GetClientAreaOrigin();
     wxWindowList& children = GetChildren();
     for ( wxWindowList::iterator i = children.begin();
@@ -704,13 +780,10 @@ void wxWindowDFB::PaintWindow(const wxRect& rect, bool eraseBackground)
             continue;
 
         // and repaint it:
             continue;
 
         // and repaint it:
-        wxPoint childpos(child->GetPosition());
-        childrect.Offset(-childpos.x, -childpos.y);
-        childrect.Offset(-origin.x, -origin.y);
-        child->PaintWindow(childrect, eraseBackground);
+        childrect.Offset(-child->GetPosition());
+        childrect.Offset(-origin);
+        child->PaintWindow(childrect);
     }
     }
-
-    m_updateRegion.Clear();
 }
 
 
 }
 
 
@@ -789,6 +862,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);
         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);
         KEY(DIKI_META_L,            0);
         KEY(DIKI_META_R,            0);
         KEY(DIKI_SUPER_L,           0);