// Name: src/dfb/window.cpp
// Purpose: wxWindow
// Author: Vaclav Slavik
-// (based on GTK, MSW, MGL implementations)
+// (based on GTK, MSW implementations)
// Created: 2006-80-10
// RCS-ID: $Id$
// Copyright: (c) 2006 REA Elektronik GmbH
#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")
+#define TRACE_EVENTS "events"
+#define TRACE_PAINT "paint"
// ===========================================================================
// implementation
// the window that has mouse capture
static wxWindowDFB *gs_mouseCapture = NULL;
+// ---------------------------------------------------------------------------
+// overlays support
+// ---------------------------------------------------------------------------
+
+WX_DEFINE_ARRAY_PTR(wxOverlayImpl*, wxDfbOverlaysList);
+
// ---------------------------------------------------------------------------
// event tables
// ---------------------------------------------------------------------------
BEGIN_EVENT_TABLE(wxWindowDFB, wxWindowBase)
END_EVENT_TABLE()
+//-----------------------------------------------------------------------------
+// global functions
+//-----------------------------------------------------------------------------
+
+wxWindow *wxGetActiveWindow()
+{
+ return wxWindow::FindFocus();
+}
+
// ----------------------------------------------------------------------------
// constructors and such
// ----------------------------------------------------------------------------
void wxWindowDFB::Init()
{
m_isShown = true;
- m_frozenness = 0;
m_tlw = NULL;
+ m_overlays = NULL;
}
// Destructor
{
SendDestroyEvent();
- m_isBeingDeleted = true;
-
if ( gs_mouseCapture == this )
ReleaseMouse();
-#warning "FIXME: what to do with gs_activeFrame here and elsewhere?"
-#if 0
- if (gs_activeFrame == this)
- {
- gs_activeFrame = NULL;
- // activate next frame in Z-order:
- if ( m_wnd->prev )
- {
- wxWindowDFB *win = (wxWindowDFB*)m_wnd->prev->userData;
- win->SetFocus();
- }
- else if ( m_wnd->next )
- {
- wxWindowDFB *win = (wxWindowDFB*)m_wnd->next->userData;
- win->SetFocus();
- }
- }
-#endif
-
if ( gs_focusedWindow == this )
- KillFocus();
+ DFBKillFocus();
DestroyChildren();
}
wxIDirectFBSurfacePtr wxWindowDFB::ObtainDfbSurface() const
{
- wxCHECK_MSG( m_parent, NULL, _T("parentless window?") );
+ wxCHECK_MSG( m_parent, NULL, "parentless window?" );
wxIDirectFBSurfacePtr parentSurface(m_parent->GetDfbSurface());
- wxCHECK_MSG( parentSurface, NULL, _T("invalid parent surface") );
+ wxCHECK_MSG( parentSurface, NULL, "invalid parent surface" );
wxRect r(GetRect());
AdjustForParentClientOrigin(r.x, r.y, 0);
if ( !m_surface )
{
m_surface = ObtainDfbSurface();
- wxASSERT_MSG( m_surface, _T("invalid DirectFB surface") );
+ wxASSERT_MSG( m_surface, "invalid DirectFB surface" );
}
return m_surface;
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;
- #warning "FIXME: keep this or not? not, think multiapp core"
-#if 0
- wxWindowDFB *active = wxGetTopLevelParent((wxWindow*)this);
- if ( !(m_windowStyle & wxPOPUP_WINDOW) && active != gs_activeFrame )
+ if ( IsShownOnScreen() &&
+ (!oldFocusedWindow || oldFocusedWindow->GetTLW() != m_tlw) )
{
- if ( gs_activeFrame )
- {
- wxActivateEvent event(wxEVT_ACTIVATE, false, gs_activeFrame->GetId());
- event.SetEventObject(gs_activeFrame);
- gs_activeFrame->GetEventHandler()->ProcessEvent(event);
- }
-
- gs_activeFrame = active;
- wxActivateEvent event(wxEVT_ACTIVATE, true, gs_activeFrame->GetId());
- event.SetEventObject(gs_activeFrame);
- gs_activeFrame->GetEventHandler()->ProcessEvent(event);
+ m_tlw->SetDfbFocus();
}
-#endif
+ // 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()
+
+ // notify the parent keeping track of focus for the kbd navigation
+ // purposes that we got it
+ wxChildFocusEvent eventFocus((wxWindow*)this);
+ HandleWindowEvent(eventFocus);
wxFocusEvent event(wxEVT_SET_FOCUS, GetId());
event.SetEventObject(this);
event.SetWindow((wxWindow*)oldFocusedWindow);
- GetEventHandler()->ProcessEvent(event);
+ HandleWindowEvent(event);
#if wxUSE_CARET
// caret needs to be informed about focus change
#endif // wxUSE_CARET
}
-void wxWindowDFB::KillFocus()
+void wxWindowDFB::DFBKillFocus()
{
- if ( gs_focusedWindow != this ) return;
+ wxCHECK_RET( gs_focusedWindow == this,
+ "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
wxFocusEvent event(wxEVT_KILL_FOCUS, GetId());
event.SetEventObject(this);
event.SetWindow(gs_toBeFocusedWindow);
- GetEventHandler()->ProcessEvent(event);
+ HandleWindowEvent(event);
}
// ----------------------------------------------------------------------------
// parent area at the place of this window (if hiding):
DoRefreshWindow();
-#warning "FIXME: all of this must be implemented for DFB"
-#if 0
- DFB_wmShowWindow(m_wnd, show);
-
- if (!show && gs_activeFrame == this)
- {
- // activate next frame in Z-order:
- if ( m_wnd->prev )
- {
- wxWindowDFB *win = (wxWindowDFB*)m_wnd->prev->userData;
- win->SetFocus();
- }
- else if ( m_wnd->next )
- {
- wxWindowDFB *win = (wxWindowDFB*)m_wnd->next->userData;
- win->SetFocus();
- }
- else
- {
- gs_activeFrame = NULL;
- }
- }
-#endif
-
return true;
}
// Raise the window to the top of the Z order
void wxWindowDFB::Raise()
{
- wxFAIL_MSG( _T("Raise() not implemented") );
+ wxFAIL_MSG( "Raise() not implemented" );
}
// Lower the window to the bottom of the Z order
void wxWindowDFB::Lower()
{
- wxFAIL_MSG( _T("Lower() not implemented") );
+ wxFAIL_MSG( "Lower() not implemented" );
}
void wxWindowDFB::DoCaptureMouse()
#warning "implement this"
#if 0
- if ( m_cursor.Ok() )
+ if ( m_cursor.IsOk() )
DFB_wmSetWindowCursor(m_wnd, *m_cursor.GetDFBCursor());
else
DFB_wmSetWindowCursor(m_wnd, *wxSTANDARD_CURSOR->GetDFBCursor());
if ( y >= h ) y = h-1;
wxIDirectFBDisplayLayerPtr layer(wxIDirectFB::Get()->GetDisplayLayer());
- wxCHECK_RET( layer, _T("no display layer") );
+ wxCHECK_RET( layer, "no display layer" );
layer->WarpCursor(x, y);
}
return false;
#warning "implement this"
- wxFAIL_MSG( _T("reparenting not yet implemented") );
+ wxFAIL_MSG( "reparenting not yet implemented" );
return true;
}
static wxPoint GetScreenPosOfClientOrigin(const wxWindowDFB *win)
{
- wxCHECK_MSG( win, wxPoint(0, 0), _T("no window provided") );
+ wxCHECK_MSG( win, wxPoint(0, 0), "no window provided" );
wxPoint pt(win->GetPosition() + win->GetClientAreaOrigin());
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);
wxSizeEvent event(newSize, GetId());
event.SetEventObject(this);
- GetEventHandler()->ProcessEvent(event);
+ HandleWindowEvent(event);
}
}
return dc.GetCharWidth();
}
-void wxWindowDFB::GetTextExtent(const wxString& string,
- int *x, int *y,
- int *descent, int *externalLeading,
- const wxFont *theFont) const
+void wxWindowDFB::DoGetTextExtent(const wxString& string,
+ int *x, int *y,
+ int *descent,
+ int *externalLeading,
+ const wxFont *theFont) const
{
wxWindowDC dc((wxWindow*)this);
dc.GetTextExtent(string, x, y, descent, externalLeading, (wxFont*)theFont);
// painting
// ---------------------------------------------------------------------------
-void wxWindowDFB::Clear()
-{
- wxClientDC dc((wxWindow *)this);
- wxBrush brush(GetBackgroundColour(), wxSOLID);
- dc.SetBackground(brush);
- dc.Clear();
-}
-
void wxWindowDFB::Refresh(bool WXUNUSED(eraseBack), const wxRect *rect)
{
if ( !IsShown() || IsFrozen() )
// 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
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
void wxWindowDFB::DoRefreshRect(const wxRect& rect)
{
wxWindow *parent = GetParent();
- wxCHECK_RET( parent, _T("no parent") );
+ wxCHECK_RET( parent, "no parent" );
// don't overlap outside of the window (NB: 'rect' is in window coords):
wxRect r(rect);
return;
wxLogTrace(TRACE_PAINT,
- _T("%p ('%s'): refresh rect [%i,%i,%i,%i]"),
+ "%p ('%s'): refresh rect [%i,%i,%i,%i]",
this, GetName().c_str(),
rect.x, rect.y, rect.GetRight(), rect.GetBottom());
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);
}
GetParent()->Update();
}
-void wxWindowDFB::Freeze()
-{
- m_frozenness++;
-}
-
-void wxWindowDFB::Thaw()
+void wxWindowDFB::DoThaw()
{
- wxASSERT_MSG( IsFrozen(), _T("Thaw() without matching Freeze()") );
-
- if ( --m_frozenness == 0 )
- {
- if ( IsShown() )
- DoRefreshWindow();
- }
+ if ( IsShown() )
+ DoRefreshWindow();
}
void wxWindowDFB::PaintWindow(const wxRect& rect)
{
- wxCHECK_RET( !IsFrozen() && IsShown(), _T("shouldn't be called") );
+ wxCHECK_RET( !IsFrozen() && IsShown(), "shouldn't be called" );
wxLogTrace(TRACE_PAINT,
- _T("%p ('%s'): painting region [%i,%i,%i,%i]"),
+ "%p ('%s'): painting region [%i,%i,%i,%i]",
this, GetName().c_str(),
rect.x, rect.y, rect.GetRight(), rect.GetBottom());
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
+ // (unless some child has HasTransparentBackground()=true!)
// 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);
+ HandleWindowEvent(eventEr);
wxRect clientRect(GetClientRect());
{
wxNcPaintEvent eventNc(GetId());
eventNc.SetEventObject(this);
- GetEventHandler()->ProcessEvent(eventNc);
+ HandleWindowEvent(eventNc);
}
else
{
- wxLogTrace(TRACE_PAINT, _T("%p ('%s'): not sending wxNcPaintEvent"),
+ wxLogTrace(TRACE_PAINT, "%p ('%s'): not sending wxNcPaintEvent",
this, GetName().c_str());
}
{
wxPaintEvent eventPt(GetId());
eventPt.SetEventObject(this);
- GetEventHandler()->ProcessEvent(eventPt);
+ HandleWindowEvent(eventPt);
}
else
{
- wxLogTrace(TRACE_PAINT, _T("%p ('%s'): not sending wxPaintEvent"),
+ wxLogTrace(TRACE_PAINT, "%p ('%s'): not sending wxPaintEvent",
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();
// 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;
}
}
+void wxWindowDFB::PaintOverlays(const wxRect& rect)
+{
+ if ( !m_overlays )
+ return;
+
+ for ( wxDfbOverlaysList::const_iterator i = m_overlays->begin();
+ i != m_overlays->end(); ++i )
+ {
+ const wxOverlayImpl * const 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, "no overlays to remove" );
+
+ m_overlays->Remove(overlay);
+
+ if ( m_overlays->empty() )
+ {
+ wxDELETE(m_overlays);
+ }
+
+ if ( !m_isBeingDeleted )
+ RefreshWindowRect(overlay->GetRect());
+}
+
// ---------------------------------------------------------------------------
// events handling
#define KEY(dfb, wx) \
case dfb: \
wxLogTrace(TRACE_EVENTS, \
- _T("key " #dfb " mapped to " #wx)); \
+ wxT("key " #dfb " mapped to " #wx)); \
return wx
// returns translated keycode, i.e. the one for KEYUP/KEYDOWN where 'a'..'z' is
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);
case DIKI_KEYDEF_END:
case DIKI_NUMBER_OF_KEYS:
- wxFAIL_MSG( _T("invalid key_id value") );
+ wxFAIL_MSG( "invalid key_id value" );
return 0;
}
return key_symbol;
else
{
-#if wxUSE_WCHAR_T
wchar_t chr = key_symbol;
wxCharBuffer buf(wxConvUI->cWC2MB(&chr, 1, NULL));
if ( buf )
return *buf; // may be 0 if failed
else
-#endif // wxUSE_WCHAR_T
return 0;
}
#endif
const DFBWindowEvent& e = event_;
wxLogTrace(TRACE_EVENTS,
- _T("handling key %s event for window %p ('%s')"),
- e.type == DWET_KEYUP ? _T("up") : _T("down"),
+ "handling key %s event for window %p ('%s')",
+ e.type == DWET_KEYUP ? "up" : "down",
this, GetName().c_str());
// fill in wxKeyEvent fields:
event.SetTimestamp(wxDFB_EVENT_TIMESTAMP(e));
event.m_rawCode = e.key_code;
event.m_keyCode = GetTranslatedKeyCode(e.key_id);
- event.m_scanCode = 0; // not used by wx at all
#if wxUSE_UNICODE
event.m_uniChar = e.key_symbol;
#endif
if ( e.type == DWET_KEYUP )
{
event.SetEventType(wxEVT_KEY_UP);
- GetEventHandler()->ProcessEvent(event);
+ HandleWindowEvent(event);
}
else
{
event.SetEventType(wxEVT_KEY_DOWN);
- if ( GetEventHandler()->ProcessEvent(event) )
+ if ( HandleWindowEvent(event) )
return;
// only send wxEVT_CHAR event if not processed yet:
if ( event.m_keyCode != 0 )
{
event.SetEventType(wxEVT_CHAR);
- if ( GetEventHandler()->ProcessEvent(event) )
+ if ( HandleWindowEvent(event) )
return;
}
// Ctrl-TAB changes the (parent) window, i.e. switch notebook page:
navEvent.SetWindowChange(event.m_controlDown);
navEvent.SetCurrentFocus(wxStaticCast(this, wxWindow));
- GetParent()->GetEventHandler()->ProcessEvent(navEvent);
+ GetParent()->HandleWindowEvent(navEvent);
}
}
}
-// ---------------------------------------------------------------------------
-// idle events processing
-// ---------------------------------------------------------------------------
-
-void wxWindowDFB::OnInternalIdle()
-{
- if (wxUpdateUIEvent::CanUpdate(this))
- UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
-}
-
-
// Find the wxWindow at the current mouse position, returning the mouse
// position.
wxWindow* wxFindWindowAtPointer(wxPoint& pt)
return wxFindWindowAtPoint(pt = wxGetMousePosition());
}
-wxWindow* wxFindWindowAtPoint(const wxPoint& pt)
+wxWindow* wxFindWindowAtPoint(const wxPoint& WXUNUSED(pt))
{
- wxFAIL_MSG( _T("wxFindWindowAtPoint not implemented") );
+ wxFAIL_MSG( "wxFindWindowAtPoint not implemented" );
return NULL;
}