#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")
// the window that has mouse capture
static wxWindowDFB *gs_mouseCapture = NULL;
+// ---------------------------------------------------------------------------
+// overlays support
+// ---------------------------------------------------------------------------
+
+WX_DEFINE_ARRAY_PTR(wxOverlayImpl*, wxDfbOverlaysList);
+
// ---------------------------------------------------------------------------
// event tables
// ---------------------------------------------------------------------------
m_isShown = true;
m_frozenness = 0;
m_tlw = NULL;
+ m_overlays = NULL;
}
// Destructor
#endif
if ( gs_focusedWindow == this )
- KillFocus();
+ DFBKillFocus();
DestroyChildren();
}
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();
+ }
}
// ---------------------------------------------------------------------------
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);
}
#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);
#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
if ( x >= w ) x = w-1;
if ( y >= h ) y = h-1;
- wxIDirectFBDisplayLayerPtr layer(wxDfbGetDisplayLayer());
+ wxIDirectFBDisplayLayerPtr layer(wxIDirectFB::Get()->GetDisplayLayer());
wxCHECK_RET( layer, _T("no display layer") );
layer->WarpCursor(x, y);
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();
{
// 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);
}
return;
}
- AdjustForParentClientOrigin(x, y, sizeFlags);
-
wxSize size(-1, -1);
if ( width == -1 )
{
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);
dc.Clear();
}
-void wxWindowDFB::Refresh(bool eraseBack, const wxRect *rect)
+void wxWindowDFB::Refresh(bool WXUNUSED(eraseBack), const wxRect *rect)
{
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 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
+ // 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 )
- DoRefreshRect(*rect, eraseBack);
+ DoRefreshRect(*rect);
else
- DoRefreshWindow(eraseBack);
+ DoRefreshWindow();
}
-void wxWindowDFB::DoRefreshWindow(bool eraseBack)
+void wxWindowDFB::RefreshWindowRect(const wxRect& rect)
{
- DoRefreshRect(wxRect(wxPoint(0, 0), GetSize()), eraseBack);
+ if ( !IsShown() || IsFrozen() )
+ return;
+
+ DoRefreshRect(rect);
}
-void wxWindowDFB::DoRefreshRect(const wxRect& rect, bool eraseBack)
+void wxWindowDFB::DoRefreshWindow()
+{
+ // NB: DoRefreshRect() takes window coords, not client, so this is correct
+ DoRefreshRect(wxRect(GetSize()));
+}
+
+void wxWindowDFB::DoRefreshRect(const wxRect& rect)
{
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:
- wxRect r(rect);
r.Offset(GetPosition());
r.Offset(parent->GetClientAreaOrigin());
- parent->DoRefreshRect(r, eraseBack);
+ // 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);
}
void wxWindowDFB::Update()
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,
- _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(),
- rect.x, rect.y, rect.width, rect.height);
+ rect.x, rect.y, rect.GetRight(), rect.GetBottom());
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
-#if wxUSE_CARET
- // must hide caret temporarily, otherwise we'd get rendering artifacts
- wxCaret *caret = GetCaret();
- if ( caret )
- caret->Hide();
-#endif // wxUSE_CARET
+ // 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());
- if ( eraseBackground )
+ // only send wxNcPaintEvent if drawing at least part of nonclient area:
+ if ( !clientRect.Contains(rect) )
+ {
+ wxNcPaintEvent eventNc(GetId());
+ eventNc.SetEventObject(this);
+ GetEventHandler()->ProcessEvent(eventNc);
+ }
+ else
{
- wxWindowDC dc((wxWindow*)this);
- wxEraseEvent eventEr(m_windowId, &dc);
- eventEr.SetEventObject(this);
- GetEventHandler()->ProcessEvent(eventEr);
+ 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);
+ // draw window's overlays on top of the painted window, if we have any:
+ PaintOverlays(rect);
-#if wxUSE_CARET
- if ( caret )
- caret->Show();
-#endif // wxUSE_CARET
+ m_updateRegion.Clear();
+
+ // client area portion of 'rect':
+ wxRect rectClientOnly(rect);
+ rectClientOnly.Intersect(clientRect);
+ // paint the children:
wxPoint origin = GetClientAreaOrigin();
wxWindowList& children = GetChildren();
for ( wxWindowList::iterator i = children.begin();
// 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;
// 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();
+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());
}
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);