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