1/////////////////////////////////////////////////////////////////////////////
2// Name:        src/dfb/window.cpp
3// Purpose:     wxWindow
4// Author:      Vaclav Slavik
5//              (based on GTK, MSW, MGL implementations)
6// Created:     2006-80-10
7// RCS-ID:      $Id: window.cpp 54750 2008-07-21 17:05:14Z VZ $
8// Copyright:   (c) 2006 REA Elektronik GmbH
9// Licence:     wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ===========================================================================
13// declarations
14// ===========================================================================
15
16// ---------------------------------------------------------------------------
17// headers
18// ---------------------------------------------------------------------------
19
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24    #pragma hdrstop
25#endif
26
27#include "wx/window.h"
28
29#ifndef WX_PRECOMP
30    #include "wx/dcclient.h"
31    #include "wx/toplevel.h"
32#endif
33
34#include "wx/caret.h"
35#include "wx/dynarray.h"
36
37#include "wx/dfb/private.h"
38#include "wx/private/overlay.h"
39
40#define TRACE_EVENTS _T("events")
41#define TRACE_PAINT  _T("paint")
42
43// ===========================================================================
44// implementation
45// ===========================================================================
46
47// ---------------------------------------------------------------------------
48// global variables
49// ---------------------------------------------------------------------------
50
51// the window that has keyboard focus:
52static wxWindowDFB *gs_focusedWindow = NULL;
53// the window that is about to be focused after currently focused
54// one looses focus:
55static wxWindow *gs_toBeFocusedWindow = NULL;
56// the window that has mouse capture
57static wxWindowDFB *gs_mouseCapture = NULL;
58
59// ---------------------------------------------------------------------------
60// overlays support
61// ---------------------------------------------------------------------------
62
63WX_DEFINE_ARRAY_PTR(wxOverlayImpl*, wxDfbOverlaysList);
64
65// ---------------------------------------------------------------------------
66// event tables
67// ---------------------------------------------------------------------------
68
69// in wxUniv this class is abstract because it doesn't have DoPopupMenu()
70IMPLEMENT_ABSTRACT_CLASS(wxWindowDFB, wxWindowBase)
71
72BEGIN_EVENT_TABLE(wxWindowDFB, wxWindowBase)
73END_EVENT_TABLE()
74
75// ----------------------------------------------------------------------------
76// constructors and such
77// ----------------------------------------------------------------------------
78
79void wxWindowDFB::Init()
80{
81    m_isShown = true;
82    m_frozenness = 0;
83    m_tlw = NULL;
84    m_overlays = NULL;
85}
86
87// Destructor
88wxWindowDFB::~wxWindowDFB()
89{
90    SendDestroyEvent();
91
92    m_isBeingDeleted = true;
93
94    if ( gs_mouseCapture == this )
95        ReleaseMouse();
96
97#warning "FIXME: what to do with gs_activeFrame here and elsewhere?"
98#if 0
99    if (gs_activeFrame == this)
100    {
101        gs_activeFrame = NULL;
102        // activate next frame in Z-order:
103        if ( m_wnd->prev )
104        {
105            wxWindowDFB *win = (wxWindowDFB*)m_wnd->prev->userData;
106            win->SetFocus();
107        }
108        else if ( m_wnd->next )
109        {
110            wxWindowDFB *win = (wxWindowDFB*)m_wnd->next->userData;
111            win->SetFocus();
112        }
113    }
114#endif
115
116    if ( gs_focusedWindow == this )
117        DFBKillFocus();
118
119    DestroyChildren();
120}
121
122// real construction (Init() must have been called before!)
123bool wxWindowDFB::Create(wxWindow *parent,
124                         wxWindowID id,
125                         const wxPoint& pos,
126                         const wxSize& size,
127                         long style,
128                         const wxString& name)
129{
130    if ( !m_tlw && parent )
131        m_tlw = parent->GetTLW();
132
133    if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) )
134        return false;
135
136    if ( parent )
137        parent->AddChild(this);
138
139    // set the size to something bogus initially, in case some code tries to
140    // create wxWindowDC before SetSize() is called below:
141    m_rect.width = m_rect.height = 1;
142
143    int x, y, w, h;
144    x = pos.x, y = pos.y;
145    if ( x == -1  ) x = 0;
146    if ( y == -1 ) y = 0;
147    w = WidthDefault(size.x);
148    h = HeightDefault(size.y);
149    SetSize(x, y, w, h);
150
151    return true;
152}
153
154// ---------------------------------------------------------------------------
155// surface access
156// ---------------------------------------------------------------------------
157
158wxIDirectFBSurfacePtr wxWindowDFB::ObtainDfbSurface() const
159{
160    wxCHECK_MSG( m_parent, NULL, _T("parentless window?") );
161
162    wxIDirectFBSurfacePtr parentSurface(m_parent->GetDfbSurface());
163    wxCHECK_MSG( parentSurface, NULL, _T("invalid parent surface") );
164
165    wxRect r(GetRect());
166    AdjustForParentClientOrigin(r.x, r.y, 0);
167    DFBRectangle rect = { r.x, r.y, r.width, r.height };
168
169    return parentSurface->GetSubSurface(&rect);
170}
171
172wxIDirectFBSurfacePtr wxWindowDFB::GetDfbSurface()
173{
174    if ( !m_surface )
175    {
176        m_surface = ObtainDfbSurface();
177        wxASSERT_MSG( m_surface, _T("invalid DirectFB surface") );
178    }
179
180    return m_surface;
181}
182
183void wxWindowDFB::InvalidateDfbSurface()
184{
185    m_surface = NULL;
186
187    // surfaces of the children are subsurfaces of this window's surface,
188    // so they must be invalidated as well:
189    wxWindowList& children = GetChildren();
190    for ( wxWindowList::iterator i = children.begin(); i != children.end(); ++i )
191    {
192        (*i)->InvalidateDfbSurface();
193    }
194}
195
196// ---------------------------------------------------------------------------
197// basic operations
198// ---------------------------------------------------------------------------
199
200void wxWindowDFB::SetFocus()
201{
202    if ( gs_focusedWindow == this )
203        return; // nothing to do, focused already
204
205    wxWindowDFB *oldFocusedWindow = gs_focusedWindow;
206
207    if ( gs_focusedWindow )
208    {
209        gs_toBeFocusedWindow = (wxWindow*)this;
210        gs_focusedWindow->DFBKillFocus();
211        gs_toBeFocusedWindow = NULL;
212    }
213
214    gs_focusedWindow = this;
215
216    if ( IsShownOnScreen() )
217    {
218        m_tlw->SetDfbFocus();
219    }
220    // else: do nothing, because DirectFB windows cannot have focus if they
221    //       are hidden; when the TLW becomes visible, it will set the focus
222    //       to use from wxTLW::Show()
223
224    #warning "FIXME: implement in terms of DWET_{GOT,LOST}FOCUS"
225    #warning "FIXME: keep this or not? not, think multiapp core"
226#if 0
227    wxWindowDFB *active = wxGetTopLevelParent((wxWindow*)this);
228    if ( !(m_windowStyle & wxPOPUP_WINDOW) && active != gs_activeFrame )
229    {
230        if ( gs_activeFrame )
231        {
232            wxActivateEvent event(wxEVT_ACTIVATE, false, gs_activeFrame->GetId());
233            event.SetEventObject(gs_activeFrame);
234            gs_activeFrame->GetEventHandler()->ProcessEvent(event);
235        }
236
237        gs_activeFrame = active;
238        wxActivateEvent event(wxEVT_ACTIVATE, true, gs_activeFrame->GetId());
239        event.SetEventObject(gs_activeFrame);
240        gs_activeFrame->GetEventHandler()->ProcessEvent(event);
241    }
242#endif
243
244    // notify the parent keeping track of focus for the kbd navigation
245    // purposes that we got it
246    wxChildFocusEvent eventFocus((wxWindow*)this);
247    GetEventHandler()->ProcessEvent(eventFocus);
248
249    wxFocusEvent event(wxEVT_SET_FOCUS, GetId());
250    event.SetEventObject(this);
251    event.SetWindow((wxWindow*)oldFocusedWindow);
252    GetEventHandler()->ProcessEvent(event);
253
254#if wxUSE_CARET
255    // caret needs to be informed about focus change
256    wxCaret *caret = GetCaret();
257    if ( caret )
258        caret->OnSetFocus();
259#endif // wxUSE_CARET
260}
261
262void wxWindowDFB::DFBKillFocus()
263{
264    wxCHECK_RET( gs_focusedWindow == this,
265                 _T("killing focus on window that doesn't have it") );
266
267    gs_focusedWindow = NULL;
268
269    if ( m_isBeingDeleted )
270        return; // don't send any events from dtor
271
272#if wxUSE_CARET
273    // caret needs to be informed about focus change
274    wxCaret *caret = GetCaret();
275    if ( caret )
276        caret->OnKillFocus();
277#endif // wxUSE_CARET
278
279    wxFocusEvent event(wxEVT_KILL_FOCUS, GetId());
280    event.SetEventObject(this);
281    event.SetWindow(gs_toBeFocusedWindow);
282    GetEventHandler()->ProcessEvent(event);
283}
284
285// ----------------------------------------------------------------------------
286// this wxWindowBase function is implemented here (in platform-specific file)
287// because it is static and so couldn't be made virtual
288// ----------------------------------------------------------------------------
289wxWindow *wxWindowBase::DoFindFocus()
290{
291    return (wxWindow*)gs_focusedWindow;
292}
293
294bool wxWindowDFB::Show(bool show)
295{
296    if ( !wxWindowBase::Show(show) )
297        return false;
298
299    // Unlike Refresh(), DoRefreshWindow() doesn't check visibility, so
300    // call it to force refresh of either this window (if showing) or its
301    // parent area at the place of this window (if hiding):
302    DoRefreshWindow();
303
304#warning "FIXME: all of this must be implemented for DFB"
305#if 0
306    DFB_wmShowWindow(m_wnd, show);
307
308    if (!show && gs_activeFrame == this)
309    {
310        // activate next frame in Z-order:
311        if ( m_wnd->prev )
312        {
313            wxWindowDFB *win = (wxWindowDFB*)m_wnd->prev->userData;
314            win->SetFocus();
315        }
316        else if ( m_wnd->next )
317        {
318            wxWindowDFB *win = (wxWindowDFB*)m_wnd->next->userData;
319            win->SetFocus();
320        }
321        else
322        {
323            gs_activeFrame = NULL;
324        }
325    }
326#endif
327
328    return true;
329}
330
331// Raise the window to the top of the Z order
332void wxWindowDFB::Raise()
333{
334    wxFAIL_MSG( _T("Raise() not implemented") );
335}
336
337// Lower the window to the bottom of the Z order
338void wxWindowDFB::Lower()
339{
340    wxFAIL_MSG( _T("Lower() not implemented") );
341}
342
343void wxWindowDFB::DoCaptureMouse()
344{
345#warning "implement this"
346#if 0
347    if ( gs_mouseCapture )
348        DFB_wmUncaptureEvents(gs_mouseCapture->m_wnd, wxDFB_CAPTURE_MOUSE);
349#endif
350    gs_mouseCapture = this;
351#if 0
352    DFB_wmCaptureEvents(m_wnd, EVT_MOUSEEVT, wxDFB_CAPTURE_MOUSE);
353#endif
354}
355
356void wxWindowDFB::DoReleaseMouse()
357{
358    wxASSERT_MSG( gs_mouseCapture == this, wxT("attempt to release mouse, but this window hasn't captured it") );
359
360#warning "implement this"
361#if 0
362    DFB_wmUncaptureEvents(m_wnd, wxDFB_CAPTURE_MOUSE);
363#endif
364    gs_mouseCapture = NULL;
365}
366
367/* static */ wxWindow *wxWindowBase::GetCapture()
368{
369    return (wxWindow*)gs_mouseCapture;
370}
371
372bool wxWindowDFB::SetCursor(const wxCursor& cursor)
373{
374    if ( !wxWindowBase::SetCursor(cursor) )
375    {
376        // no change
377        return false;
378    }
379
380#warning "implement this"
381#if 0
382    if ( m_cursor.Ok() )
383        DFB_wmSetWindowCursor(m_wnd, *m_cursor.GetDFBCursor());
384    else
385        DFB_wmSetWindowCursor(m_wnd, *wxSTANDARD_CURSOR->GetDFBCursor());
386#endif
387
388    return true;
389}
390
391void wxWindowDFB::WarpPointer(int x, int y)
392{
393    int w, h;
394    wxDisplaySize(&w, &h);
395
396    ClientToScreen(&x, &y);
397    if ( x < 0 ) x = 0;
398    if ( y < 0 ) y = 0;
399    if ( x >= w ) x = w-1;
400    if ( y >= h ) y = h-1;
401
402    wxIDirectFBDisplayLayerPtr layer(wxIDirectFB::Get()->GetDisplayLayer());
403    wxCHECK_RET( layer, _T("no display layer") );
404
405    layer->WarpCursor(x, y);
406}
407
408// Set this window to be the child of 'parent'.
409bool wxWindowDFB::Reparent(wxWindowBase *parent)
410{
411    if ( !wxWindowBase::Reparent(parent) )
412        return false;
413
414#warning "implement this"
415    wxFAIL_MSG( _T("reparenting not yet implemented") );
416
417    return true;
418}
419
420// ---------------------------------------------------------------------------
421// moving and resizing
422// ---------------------------------------------------------------------------
423
424// Get total size
425void wxWindowDFB::DoGetSize(int *x, int *y) const
426{
427    if (x) *x = m_rect.width;
428    if (y) *y = m_rect.height;
429}
430
431void wxWindowDFB::DoGetPosition(int *x, int *y) const
432{
433    if (x) *x = m_rect.x;
434    if (y) *y = m_rect.y;
435}
436
437static wxPoint GetScreenPosOfClientOrigin(const wxWindowDFB *win)
438{
439    wxCHECK_MSG( win, wxPoint(0, 0), _T("no window provided") );
440
441    wxPoint pt(win->GetPosition() + win->GetClientAreaOrigin());
442
443    if ( !win->IsTopLevel() )
444        pt += GetScreenPosOfClientOrigin(win->GetParent());
445
446    return pt;
447}
448
449void wxWindowDFB::DoScreenToClient(int *x, int *y) const
450{
451    wxPoint o = GetScreenPosOfClientOrigin(this);
452
453    if (x) *x -= o.x;
454    if (y) *y -= o.y;
455}
456
457void wxWindowDFB::DoClientToScreen(int *x, int *y) const
458{
459    wxPoint o = GetScreenPosOfClientOrigin(this);
460
461    if (x) *x += o.x;
462    if (y) *y += o.y;
463}
464
465// Get size *available for subwindows* i.e. excluding menu bar etc.
466void wxWindowDFB::DoGetClientSize(int *x, int *y) const
467{
468    DoGetSize(x, y);
469}
470
471void wxWindowDFB::DoMoveWindow(int x, int y, int width, int height)
472{
473    // NB: [x,y] arguments are in (parent's) window coordinates, while
474    //     m_rect.{x,y} are in (parent's) client coordinates. That's why we
475    //     offset by parentOrigin in some places below
476
477    wxPoint parentOrigin(0, 0);
478    AdjustForParentClientOrigin(parentOrigin.x, parentOrigin.y);
479
480    wxRect oldpos(m_rect);
481    oldpos.Offset(parentOrigin);
482
483    wxRect newpos(x, y, width, height);
484
485    // input [x,y] is in window coords, but we store client coords in m_rect:
486    m_rect = newpos;
487    m_rect.Offset(-parentOrigin);
488
489    // window's position+size changed and so did the subsurface that covers it
490    InvalidateDfbSurface();
491
492    if ( IsShown() )
493    {
494        // queue both former and new position of the window for repainting:
495        wxWindow *parent = GetParent();
496        parent->RefreshRect(oldpos);
497        parent->RefreshRect(newpos);
498    }
499}
500
501// set the size of the window: if the dimensions are positive, just use them,
502// but if any of them is equal to -1, it means that we must find the value for
503// it ourselves (unless sizeFlags contains wxSIZE_ALLOW_MINUS_ONE flag, in
504// which case -1 is a valid value for x and y)
505//
506// If sizeFlags contains wxSIZE_AUTO_WIDTH/HEIGHT flags (default), we calculate
507// the width/height to best suit our contents, otherwise we reuse the current
508// width/height
509void wxWindowDFB::DoSetSize(int x, int y, int width, int height, int sizeFlags)
510{
511    // get the current size and position...
512    int currentX, currentY;
513    GetPosition(&currentX, &currentY);
514    int currentW,currentH;
515    GetSize(&currentW, &currentH);
516
517    if ( x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
518        x = currentX;
519    if ( y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
520        y = currentY;
521
522    // ... and don't do anything (avoiding flicker) if it's already ok
523    if ( x == currentX && y == currentY &&
524         width == currentW && height == currentH )
525    {
526        return;
527    }
528
529    wxSize size(-1, -1);
530    if ( width == -1 )
531    {
532        if ( sizeFlags & wxSIZE_AUTO_WIDTH )
533        {
534            size = DoGetBestSize();
535            width = size.x;
536        }
537        else
538        {
539            // just take the current one
540            width = currentW;
541        }
542    }
543
544    if ( height == -1 )
545    {
546        if ( sizeFlags & wxSIZE_AUTO_HEIGHT )
547        {
548            if ( size.x == -1 )
549            {
550                size = DoGetBestSize();
551            }
552            //else: already called DoGetBestSize() above
553
554            height = size.y;
555        }
556        else
557        {
558            // just take the current one
559            height = currentH;
560        }
561    }
562
563    int maxWidth = GetMaxWidth(),
564        minWidth = GetMinWidth(),
565        maxHeight = GetMaxHeight(),
566        minHeight = GetMinHeight();
567
568    if ( minWidth != -1 && width < minWidth ) width = minWidth;
569    if ( maxWidth != -1 && width > maxWidth ) width = maxWidth;
570    if ( minHeight != -1 && height < minHeight ) height = minHeight;
571    if ( maxHeight != -1 && height > maxHeight ) height = maxHeight;
572
573    if ( m_rect.x != x || m_rect.y != y ||
574         m_rect.width != width || m_rect.height != height )
575    {
576        AdjustForParentClientOrigin(x, y, sizeFlags);
577        DoMoveWindow(x, y, width, height);
578
579        wxSize newSize(width, height);
580        wxSizeEvent event(newSize, GetId());
581        event.SetEventObject(this);
582        GetEventHandler()->ProcessEvent(event);
583    }
584}
585
586void wxWindowDFB::DoSetClientSize(int width, int height)
587{
588    SetSize(width, height);
589}
590
591// ---------------------------------------------------------------------------
592// text metrics
593// ---------------------------------------------------------------------------
594
595int wxWindowDFB::GetCharHeight() const
596{
597    wxWindowDC dc((wxWindow*)this);
598    return dc.GetCharHeight();
599}
600
601int wxWindowDFB::GetCharWidth() const
602{
603    wxWindowDC dc((wxWindow*)this);
604    return dc.GetCharWidth();
605}
606
607void wxWindowDFB::GetTextExtent(const wxString& string,
608                             int *x, int *y,
609                             int *descent, int *externalLeading,
610                             const wxFont *theFont) const
611{
612    wxWindowDC dc((wxWindow*)this);
613    dc.GetTextExtent(string, x, y, descent, externalLeading, (wxFont*)theFont);
614}
615
616
617// ---------------------------------------------------------------------------
618// painting
619// ---------------------------------------------------------------------------
620
621void wxWindowDFB::Clear()
622{
623    wxClientDC dc((wxWindow *)this);
624    wxBrush brush(GetBackgroundColour(), wxSOLID);
625    dc.SetBackground(brush);
626    dc.Clear();
627}
628
629void wxWindowDFB::Refresh(bool WXUNUSED(eraseBack), const wxRect *rect)
630{
631    if ( !IsShown() || IsFrozen() )
632        return;
633
634    // NB[1]: We intentionally ignore the eraseBack argument here. This is
635    //        because of the way wxDFB's painting is implemented: the refresh
636    //        request is propagated up to wxTLW, which is then painted in
637    //        top-down order. This means that this window's area is first
638    //        painted by its parent and this window is then painted over it, so
639    //        it's not safe to not paint this window's background even if
640    //        eraseBack=false.
641    // NB[2]: wxWindow::Refresh() takes the rectangle in client coords, but
642    //        wxUniv translates it to window coords before passing it to
643    //        wxWindowDFB::Refresh(), so we can directly pass the rect to
644    //        DoRefreshRect (which takes window, not client, coords) here.
645    if ( rect )
646        DoRefreshRect(*rect);
647    else
648        DoRefreshWindow();
649}
650
651void wxWindowDFB::RefreshWindowRect(const wxRect& rect)
652{
653    if ( !IsShown() || IsFrozen() )
654        return;
655
656    DoRefreshRect(rect);
657}
658
659void wxWindowDFB::DoRefreshWindow()
660{
661    // NB: DoRefreshRect() takes window coords, not client, so this is correct
662    DoRefreshRect(wxRect(GetSize()));
663}
664
665void wxWindowDFB::DoRefreshRect(const wxRect& rect)
666{
667    wxWindow *parent = GetParent();
668    wxCHECK_RET( parent, _T("no parent") );
669
670    // don't overlap outside of the window (NB: 'rect' is in window coords):
671    wxRect r(rect);
672    r.Intersect(wxRect(GetSize()));
673    if ( r.IsEmpty() )
674        return;
675
676    wxLogTrace(TRACE_PAINT,
677               _T("%p ('%s'): refresh rect [%i,%i,%i,%i]"),
678               this, GetName().c_str(),
679               rect.x, rect.y, rect.GetRight(), rect.GetBottom());
680
681    // convert the refresh rectangle to parent's coordinates and
682    // recursively refresh the parent:
683    r.Offset(GetPosition());
684    r.Offset(parent->GetClientAreaOrigin());
685
686    parent->DoRefreshRect(r);
687}
688
689void wxWindowDFB::Update()
690{
691    if ( !IsShown() || IsFrozen() )
692        return;
693
694    GetParent()->Update();
695}
696
697void wxWindowDFB::Freeze()
698{
699    m_frozenness++;
700}
701
702void wxWindowDFB::Thaw()
703{
704    wxASSERT_MSG( IsFrozen(), _T("Thaw() without matching Freeze()") );
705
706    if ( --m_frozenness == 0 )
707    {
708        if ( IsShown() )
709            DoRefreshWindow();
710    }
711}
712
713void wxWindowDFB::PaintWindow(const wxRect& rect)
714{
715    wxCHECK_RET( !IsFrozen() && IsShown(), _T("shouldn't be called") );
716
717    wxLogTrace(TRACE_PAINT,
718               _T("%p ('%s'): painting region [%i,%i,%i,%i]"),
719               this, GetName().c_str(),
720               rect.x, rect.y, rect.GetRight(), rect.GetBottom());
721
722    m_updateRegion = rect;
723
724    // FIXME_DFB: don't waste time rendering the area if it's fully covered
725    //            by some children, go directly to rendering the children
726
727    // NB: unconditionally send wxEraseEvent, because our implementation of
728    //     wxWindow::Refresh() ignores the eraseBack argument
729    wxWindowDC dc((wxWindow*)this);
730    wxEraseEvent eventEr(m_windowId, &dc);
731    eventEr.SetEventObject(this);
732    GetEventHandler()->ProcessEvent(eventEr);
733
734    wxRect clientRect(GetClientRect());
735
736    // only send wxNcPaintEvent if drawing at least part of nonclient area:
737    if ( !clientRect.Contains(rect) )
738    {
739        wxNcPaintEvent eventNc(GetId());
740        eventNc.SetEventObject(this);
741        GetEventHandler()->ProcessEvent(eventNc);
742    }
743    else
744    {
745        wxLogTrace(TRACE_PAINT, _T("%p ('%s'): not sending wxNcPaintEvent"),
746                   this, GetName().c_str());
747    }
748
749    // only send wxPaintEvent if drawing at least part of client area:
750    if ( rect.Intersects(clientRect) )
751    {
752        wxPaintEvent eventPt(GetId());
753        eventPt.SetEventObject(this);
754        GetEventHandler()->ProcessEvent(eventPt);
755    }
756    else
757    {
758        wxLogTrace(TRACE_PAINT, _T("%p ('%s'): not sending wxPaintEvent"),
759                   this, GetName().c_str());
760    }
761
762    // draw window's overlays on top of the painted window, if we have any:
763    PaintOverlays(rect);
764
765    m_updateRegion.Clear();
766
767    // paint the children:
768    wxPoint origin = GetClientAreaOrigin();
769    wxWindowList& children = GetChildren();
770    for ( wxWindowList::iterator i = children.begin();
771          i != children.end(); ++i )
772    {
773        wxWindow *child = *i;
774
775        if ( child->IsFrozen() || !child->IsShown() )
776            continue; // don't paint anything if the window is frozen or hidden
777
778        // compute child's area to repaint
779        wxRect childrect(child->GetRect());
780        childrect.Offset(origin);
781        childrect.Intersect(rect);
782        if ( childrect.IsEmpty() )
783            continue;
784
785        // and repaint it:
786        childrect.Offset(-child->GetPosition());
787        childrect.Offset(-origin);
788        child->PaintWindow(childrect);
789    }
790}
791
792void wxWindowDFB::PaintOverlays(const wxRect& rect)
793{
794    if ( !m_overlays )
795        return;
796
797    for ( wxDfbOverlaysList::const_iterator i = m_overlays->begin();
798          i != m_overlays->end(); ++i )
799    {
800        // the cast is necessary in STL build because of bug in const_iterator
801        // operator*() return value
802        const wxOverlayImpl * const
803            overlay = wx_static_cast(const wxOverlayImpl *, *i);
804
805        wxRect orectOrig(overlay->GetRect());
806        wxRect orect(orectOrig);
807        orect.Intersect(rect);
808        if ( orect.IsEmpty() )
809            continue;
810
811        if ( overlay->IsEmpty() )
812            continue; // nothing to paint
813
814        DFBRectangle dfbRect = { orect.x - orectOrig.x, orect.y - orectOrig.y,
815                                 orect.width, orect.height };
816        GetDfbSurface()->Blit
817                         (
818                           overlay->GetDirectFBSurface(),
819                           &dfbRect,
820                           orect.x, orect.y
821                         );
822    }
823}
824
825void wxWindowDFB::AddOverlay(wxOverlayImpl *overlay)
826{
827    if ( !m_overlays )
828        m_overlays = new wxDfbOverlaysList;
829
830    m_overlays->Add(overlay);
831}
832
833void wxWindowDFB::RemoveOverlay(wxOverlayImpl *overlay)
834{
835    wxCHECK_RET( m_overlays, _T("no overlays to remove") );
836
837    m_overlays->Remove(overlay);
838
839    if ( m_overlays->empty() )
840    {
841        wxDELETE(m_overlays);
842    }
843
844    if ( !m_isBeingDeleted )
845        RefreshWindowRect(overlay->GetRect());
846}
847
848
849// ---------------------------------------------------------------------------
850// events handling
851// ---------------------------------------------------------------------------
852
853#define KEY(dfb, wx)                                                \
854    case dfb:                                                       \
855          wxLogTrace(TRACE_EVENTS,                                  \
856                     _T("key " #dfb " mapped to " #wx));            \
857          return wx
858
859// returns translated keycode, i.e. the one for KEYUP/KEYDOWN where 'a'..'z' is
860// translated to 'A'..'Z'
861static long GetTranslatedKeyCode(DFBInputDeviceKeyIdentifier key_id)
862{
863    switch ( key_id )
864    {
865        KEY(DIKI_UNKNOWN,           0);
866
867        KEY(DIKI_A,                 'A');
868        KEY(DIKI_B,                 'B');
869        KEY(DIKI_C,                 'C');
870        KEY(DIKI_D,                 'D');
871        KEY(DIKI_E,                 'E');
872        KEY(DIKI_F,                 'F');
873        KEY(DIKI_G,                 'G');
874        KEY(DIKI_H,                 'H');
875        KEY(DIKI_I,                 'I');
876        KEY(DIKI_J,                 'J');
877        KEY(DIKI_K,                 'K');
878        KEY(DIKI_L,                 'L');
879        KEY(DIKI_M,                 'M');
880        KEY(DIKI_N,                 'N');
881        KEY(DIKI_O,                 'O');
882        KEY(DIKI_P,                 'P');
883        KEY(DIKI_Q,                 'Q');
884        KEY(DIKI_R,                 'R');
885        KEY(DIKI_S,                 'S');
886        KEY(DIKI_T,                 'T');
887        KEY(DIKI_U,                 'U');
888        KEY(DIKI_V,                 'V');
889        KEY(DIKI_W,                 'W');
890        KEY(DIKI_X,                 'X');
891        KEY(DIKI_Y,                 'Y');
892        KEY(DIKI_Z,                 'Z');
893
894        KEY(DIKI_0,                 '0');
895        KEY(DIKI_1,                 '1');
896        KEY(DIKI_2,                 '2');
897        KEY(DIKI_3,                 '3');
898        KEY(DIKI_4,                 '4');
899        KEY(DIKI_5,                 '5');
900        KEY(DIKI_6,                 '6');
901        KEY(DIKI_7,                 '7');
902        KEY(DIKI_8,                 '8');
903        KEY(DIKI_9,                 '9');
904
905        KEY(DIKI_F1,                WXK_F1);
906        KEY(DIKI_F2,                WXK_F2);
907        KEY(DIKI_F3,                WXK_F3);
908        KEY(DIKI_F4,                WXK_F4);
909        KEY(DIKI_F5,                WXK_F5);
910        KEY(DIKI_F6,                WXK_F6);
911        KEY(DIKI_F7,                WXK_F7);
912        KEY(DIKI_F8,                WXK_F8);
913        KEY(DIKI_F9,                WXK_F9);
914        KEY(DIKI_F10,               WXK_F10);
915        KEY(DIKI_F11,               WXK_F11);
916        KEY(DIKI_F12,               WXK_F12);
917
918        KEY(DIKI_SHIFT_L,           WXK_SHIFT);
919        KEY(DIKI_SHIFT_R,           WXK_SHIFT);
920        KEY(DIKI_CONTROL_L,         WXK_CONTROL);
921        KEY(DIKI_CONTROL_R,         WXK_CONTROL);
922        KEY(DIKI_ALT_L,             WXK_ALT);
923        KEY(DIKI_ALT_R,             WXK_ALT);
924        // this key was removed in 0.9.25 but include it for previous versions
925        // just to avoid gcc warnings about unhandled enum value in switch
926#if !wxCHECK_DFB_VERSION(0, 9, 24)
927        KEY(DIKI_ALTGR,             0);
928#endif
929        KEY(DIKI_META_L,            0);
930        KEY(DIKI_META_R,            0);
931        KEY(DIKI_SUPER_L,           0);
932        KEY(DIKI_SUPER_R,           0);
933        KEY(DIKI_HYPER_L,           0);
934        KEY(DIKI_HYPER_R,           0);
935
936        KEY(DIKI_CAPS_LOCK,         0);
937        KEY(DIKI_NUM_LOCK,          WXK_NUMLOCK);
938        KEY(DIKI_SCROLL_LOCK,       0);
939
940        KEY(DIKI_ESCAPE,            WXK_ESCAPE);
941        KEY(DIKI_LEFT,              WXK_LEFT);
942        KEY(DIKI_RIGHT,             WXK_RIGHT);
943        KEY(DIKI_UP,                WXK_UP);
944        KEY(DIKI_DOWN,              WXK_DOWN);
945        KEY(DIKI_TAB,               WXK_TAB);
946        KEY(DIKI_ENTER,             WXK_RETURN);
947        KEY(DIKI_SPACE,             WXK_SPACE);
948        KEY(DIKI_BACKSPACE,         WXK_BACK);
949        KEY(DIKI_INSERT,            WXK_INSERT);
950        KEY(DIKI_DELETE,            WXK_DELETE);
951        KEY(DIKI_HOME,              WXK_HOME);
952        KEY(DIKI_END,               WXK_END);
953        KEY(DIKI_PAGE_UP,           WXK_PAGEUP);
954        KEY(DIKI_PAGE_DOWN,         WXK_PAGEDOWN);
955        KEY(DIKI_PRINT,             WXK_PRINT);
956        KEY(DIKI_PAUSE,             WXK_PAUSE);
957
958        KEY(DIKI_QUOTE_LEFT,        '`');
959        KEY(DIKI_MINUS_SIGN,        '-');
960        KEY(DIKI_EQUALS_SIGN,       '=');
961        KEY(DIKI_BRACKET_LEFT,      '[');
962        KEY(DIKI_BRACKET_RIGHT,     ']');
963        KEY(DIKI_BACKSLASH,         '\\');
964        KEY(DIKI_SEMICOLON,         ';');
965        KEY(DIKI_QUOTE_RIGHT,       '\'');
966        KEY(DIKI_COMMA,             ',');
967        KEY(DIKI_PERIOD,            '.');
968        KEY(DIKI_SLASH,             '/');
969
970        KEY(DIKI_LESS_SIGN,         '<');
971
972        KEY(DIKI_KP_DIV,            WXK_NUMPAD_DIVIDE);
973        KEY(DIKI_KP_MULT,           WXK_NUMPAD_MULTIPLY);
974        KEY(DIKI_KP_MINUS,          WXK_NUMPAD_SUBTRACT);
975        KEY(DIKI_KP_PLUS,           WXK_NUMPAD_ADD);
976        KEY(DIKI_KP_ENTER,          WXK_NUMPAD_ENTER);
977        KEY(DIKI_KP_SPACE,          WXK_NUMPAD_SPACE);
978        KEY(DIKI_KP_TAB,            WXK_NUMPAD_TAB);
979        KEY(DIKI_KP_F1,             WXK_NUMPAD_F1);
980        KEY(DIKI_KP_F2,             WXK_NUMPAD_F2);
981        KEY(DIKI_KP_F3,             WXK_NUMPAD_F3);
982        KEY(DIKI_KP_F4,             WXK_NUMPAD_F4);
983        KEY(DIKI_KP_EQUAL,          WXK_NUMPAD_EQUAL);
984        KEY(DIKI_KP_SEPARATOR,      WXK_NUMPAD_SEPARATOR);
985
986        KEY(DIKI_KP_DECIMAL,        WXK_NUMPAD_DECIMAL);
987        KEY(DIKI_KP_0,              WXK_NUMPAD0);
988        KEY(DIKI_KP_1,              WXK_NUMPAD1);
989        KEY(DIKI_KP_2,              WXK_NUMPAD2);
990        KEY(DIKI_KP_3,              WXK_NUMPAD3);
991        KEY(DIKI_KP_4,              WXK_NUMPAD4);
992        KEY(DIKI_KP_5,              WXK_NUMPAD5);
993        KEY(DIKI_KP_6,              WXK_NUMPAD6);
994        KEY(DIKI_KP_7,              WXK_NUMPAD7);
995        KEY(DIKI_KP_8,              WXK_NUMPAD8);
996        KEY(DIKI_KP_9,              WXK_NUMPAD9);
997
998        case DIKI_KEYDEF_END:
999        case DIKI_NUMBER_OF_KEYS:
1000            wxFAIL_MSG( _T("invalid key_id value") );
1001            return 0;
1002    }
1003
1004    return 0; // silence compiler warnings
1005}
1006
1007// returns untranslated keycode, i.e. for EVT_CHAR, where characters are left in
1008// the form they were entered (lowercase, diacritics etc.)
1009static long GetUntraslatedKeyCode(DFBInputDeviceKeyIdentifier key_id,
1010                                  DFBInputDeviceKeySymbol key_symbol)
1011{
1012    switch ( DFB_KEY_TYPE(key_symbol) )
1013    {
1014        case DIKT_UNICODE:
1015#if wxUSE_UNICODE
1016            return key_symbol;
1017#else
1018            if ( key_symbol < 128 )
1019                return key_symbol;
1020            else
1021            {
1022#if wxUSE_WCHAR_T
1023                wchar_t chr = key_symbol;
1024                wxCharBuffer buf(wxConvUI->cWC2MB(&chr, 1, NULL));
1025                if ( buf )
1026                    return *buf; // may be 0 if failed
1027                else
1028#endif // wxUSE_WCHAR_T
1029                    return 0;
1030            }
1031#endif
1032
1033        default:
1034            return GetTranslatedKeyCode(key_id);
1035    }
1036}
1037
1038#undef KEY
1039
1040void wxWindowDFB::HandleKeyEvent(const wxDFBWindowEvent& event_)
1041{
1042    if ( !IsEnabled() )
1043        return;
1044
1045    const DFBWindowEvent& e = event_;
1046
1047    wxLogTrace(TRACE_EVENTS,
1048               _T("handling key %s event for window %p ('%s')"),
1049               e.type == DWET_KEYUP ? _T("up") : _T("down"),
1050               this, GetName().c_str());
1051
1052    // fill in wxKeyEvent fields:
1053    wxKeyEvent event;
1054    event.SetEventObject(this);
1055    event.SetTimestamp(wxDFB_EVENT_TIMESTAMP(e));
1056    event.m_rawCode = e.key_code;
1057    event.m_keyCode = GetTranslatedKeyCode(e.key_id);
1058    event.m_scanCode = 0; // not used by wx at all
1059#if wxUSE_UNICODE
1060    event.m_uniChar = e.key_symbol;
1061#endif
1062    event.m_shiftDown = ( e.modifiers & DIMM_SHIFT ) != 0;
1063    event.m_controlDown = ( e.modifiers & DIMM_CONTROL ) != 0;
1064    event.m_altDown = ( e.modifiers & DIMM_ALT ) != 0;
1065    event.m_metaDown = ( e.modifiers & DIMM_META ) != 0;
1066
1067    // translate coordinates from TLW-relative to this window-relative:
1068    event.m_x = e.x;
1069    event.m_y = e.y;
1070    GetTLW()->ClientToScreen(&event.m_x, &event.m_y);
1071    this->ScreenToClient(&event.m_x, &event.m_y);
1072
1073    if ( e.type == DWET_KEYUP )
1074    {
1075        event.SetEventType(wxEVT_KEY_UP);
1076        GetEventHandler()->ProcessEvent(event);
1077    }
1078    else
1079    {
1080        bool isTab = (event.m_keyCode == WXK_TAB);
1081
1082        event.SetEventType(wxEVT_KEY_DOWN);
1083
1084        if ( GetEventHandler()->ProcessEvent(event) )
1085            return;
1086
1087        // only send wxEVT_CHAR event if not processed yet:
1088        event.m_keyCode = GetUntraslatedKeyCode(e.key_id, e.key_symbol);
1089        if ( event.m_keyCode != 0 )
1090        {
1091            event.SetEventType(wxEVT_CHAR);
1092            if ( GetEventHandler()->ProcessEvent(event) )
1093                return;
1094        }
1095
1096        // Synthetize navigation key event, but do it only if the TAB key
1097        // wasn't handled yet:
1098        if ( isTab && GetParent() && GetParent()->HasFlag(wxTAB_TRAVERSAL) )
1099        {
1100            wxNavigationKeyEvent navEvent;
1101            navEvent.SetEventObject(GetParent());
1102            // Shift-TAB goes in reverse direction:
1103            navEvent.SetDirection(!event.m_shiftDown);
1104            // Ctrl-TAB changes the (parent) window, i.e. switch notebook page:
1105            navEvent.SetWindowChange(event.m_controlDown);
1106            navEvent.SetCurrentFocus(wxStaticCast(this, wxWindow));
1107            GetParent()->GetEventHandler()->ProcessEvent(navEvent);
1108        }
1109    }
1110}
1111
1112// ---------------------------------------------------------------------------
1113// idle events processing
1114// ---------------------------------------------------------------------------
1115
1116void wxWindowDFB::OnInternalIdle()
1117{
1118    if (wxUpdateUIEvent::CanUpdate(this) && IsShown())
1119        UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
1120}
1121
1122
1123// Find the wxWindow at the current mouse position, returning the mouse
1124// position.
1125wxWindow* wxFindWindowAtPointer(wxPoint& pt)
1126{
1127    return wxFindWindowAtPoint(pt = wxGetMousePosition());
1128}
1129
1130wxWindow* wxFindWindowAtPoint(const wxPoint& pt)
1131{
1132    wxFAIL_MSG( _T("wxFindWindowAtPoint not implemented") );
1133    return NULL;
1134}
1135