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