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