]> git.saurik.com Git - wxWidgets.git/blob - src/dfb/window.cpp
Fix for handling of invalid gifs, patch 1587754 Noel Byron.
[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 parent->RefreshRect(oldpos);
496 parent->RefreshRect(newpos);
497 }
498 }
499
500 // set the size of the window: if the dimensions are positive, just use them,
501 // but if any of them is equal to -1, it means that we must find the value for
502 // it ourselves (unless sizeFlags contains wxSIZE_ALLOW_MINUS_ONE flag, in
503 // which case -1 is a valid value for x and y)
504 //
505 // If sizeFlags contains wxSIZE_AUTO_WIDTH/HEIGHT flags (default), we calculate
506 // the width/height to best suit our contents, otherwise we reuse the current
507 // width/height
508 void wxWindowDFB::DoSetSize(int x, int y, int width, int height, int sizeFlags)
509 {
510 // get the current size and position...
511 int currentX, currentY;
512 GetPosition(&currentX, &currentY);
513 int currentW,currentH;
514 GetSize(&currentW, &currentH);
515
516 if ( x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
517 x = currentX;
518 if ( y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
519 y = currentY;
520
521 // ... and don't do anything (avoiding flicker) if it's already ok
522 if ( x == currentX && y == currentY &&
523 width == currentW && height == currentH )
524 {
525 return;
526 }
527
528 wxSize size(-1, -1);
529 if ( width == -1 )
530 {
531 if ( sizeFlags & wxSIZE_AUTO_WIDTH )
532 {
533 size = DoGetBestSize();
534 width = size.x;
535 }
536 else
537 {
538 // just take the current one
539 width = currentW;
540 }
541 }
542
543 if ( height == -1 )
544 {
545 if ( sizeFlags & wxSIZE_AUTO_HEIGHT )
546 {
547 if ( size.x == -1 )
548 {
549 size = DoGetBestSize();
550 }
551 //else: already called DoGetBestSize() above
552
553 height = size.y;
554 }
555 else
556 {
557 // just take the current one
558 height = currentH;
559 }
560 }
561
562 int maxWidth = GetMaxWidth(),
563 minWidth = GetMinWidth(),
564 maxHeight = GetMaxHeight(),
565 minHeight = GetMinHeight();
566
567 if ( minWidth != -1 && width < minWidth ) width = minWidth;
568 if ( maxWidth != -1 && width > maxWidth ) width = maxWidth;
569 if ( minHeight != -1 && height < minHeight ) height = minHeight;
570 if ( maxHeight != -1 && height > maxHeight ) height = maxHeight;
571
572 if ( m_rect.x != x || m_rect.y != y ||
573 m_rect.width != width || m_rect.height != height )
574 {
575 AdjustForParentClientOrigin(x, y, sizeFlags);
576 DoMoveWindow(x, y, width, height);
577
578 wxSize newSize(width, height);
579 wxSizeEvent event(newSize, GetId());
580 event.SetEventObject(this);
581 GetEventHandler()->ProcessEvent(event);
582 }
583 }
584
585 void wxWindowDFB::DoSetClientSize(int width, int height)
586 {
587 SetSize(width, height);
588 }
589
590 // ---------------------------------------------------------------------------
591 // text metrics
592 // ---------------------------------------------------------------------------
593
594 int wxWindowDFB::GetCharHeight() const
595 {
596 wxWindowDC dc((wxWindow*)this);
597 return dc.GetCharHeight();
598 }
599
600 int wxWindowDFB::GetCharWidth() const
601 {
602 wxWindowDC dc((wxWindow*)this);
603 return dc.GetCharWidth();
604 }
605
606 void wxWindowDFB::GetTextExtent(const wxString& string,
607 int *x, int *y,
608 int *descent, int *externalLeading,
609 const wxFont *theFont) const
610 {
611 wxWindowDC dc((wxWindow*)this);
612 dc.GetTextExtent(string, x, y, descent, externalLeading, (wxFont*)theFont);
613 }
614
615
616 // ---------------------------------------------------------------------------
617 // painting
618 // ---------------------------------------------------------------------------
619
620 void wxWindowDFB::Clear()
621 {
622 wxClientDC dc((wxWindow *)this);
623 wxBrush brush(GetBackgroundColour(), wxSOLID);
624 dc.SetBackground(brush);
625 dc.Clear();
626 }
627
628 void wxWindowDFB::Refresh(bool WXUNUSED(eraseBack), const wxRect *rect)
629 {
630 if ( !IsShown() || IsFrozen() )
631 return;
632
633 // NB[1]: We intentionally ignore the eraseBack argument here. This is
634 // because of the way wxDFB's painting is implemented: the refresh
635 // request is propagated up to wxTLW, which is then painted in
636 // top-down order. This means that this window's area is first
637 // painted by its parent and this window is then painted over it, so
638 // it's not safe to not paint this window's background even if
639 // eraseBack=false.
640 // NB[2]: wxWindow::Refresh() takes the rectangle in client coords, but
641 // wxUniv translates it to window coords before passing it to
642 // wxWindowDFB::Refresh(), so we can directly pass the rect to
643 // DoRefreshRect (which takes window, not client, coords) here.
644 if ( rect )
645 DoRefreshRect(*rect);
646 else
647 DoRefreshWindow();
648 }
649
650 void wxWindowDFB::RefreshWindowRect(const wxRect& rect)
651 {
652 if ( !IsShown() || IsFrozen() )
653 return;
654
655 DoRefreshRect(rect);
656 }
657
658 void wxWindowDFB::DoRefreshWindow()
659 {
660 // NB: DoRefreshRect() takes window coords, not client, so this is correct
661 DoRefreshRect(wxRect(GetSize()));
662 }
663
664 void wxWindowDFB::DoRefreshRect(const wxRect& rect)
665 {
666 wxWindow *parent = GetParent();
667 wxCHECK_RET( parent, _T("no parent") );
668
669 // don't overlap outside of the window (NB: 'rect' is in window coords):
670 wxRect r(rect);
671 r.Intersect(wxRect(GetSize()));
672 if ( r.IsEmpty() )
673 return;
674
675 wxLogTrace(TRACE_PAINT,
676 _T("%p ('%s'): refresh rect [%i,%i,%i,%i]"),
677 this, GetName().c_str(),
678 rect.x, rect.y, rect.GetRight(), rect.GetBottom());
679
680 // convert the refresh rectangle to parent's coordinates and
681 // recursively refresh the parent:
682 r.Offset(GetPosition());
683 r.Offset(parent->GetClientAreaOrigin());
684
685 parent->DoRefreshRect(r);
686 }
687
688 void wxWindowDFB::Update()
689 {
690 if ( !IsShown() || IsFrozen() )
691 return;
692
693 GetParent()->Update();
694 }
695
696 void wxWindowDFB::Freeze()
697 {
698 m_frozenness++;
699 }
700
701 void wxWindowDFB::Thaw()
702 {
703 wxASSERT_MSG( IsFrozen(), _T("Thaw() without matching Freeze()") );
704
705 if ( --m_frozenness == 0 )
706 {
707 if ( IsShown() )
708 DoRefreshWindow();
709 }
710 }
711
712 void wxWindowDFB::PaintWindow(const wxRect& rect)
713 {
714 wxCHECK_RET( !IsFrozen() && IsShown(), _T("shouldn't be called") );
715
716 wxLogTrace(TRACE_PAINT,
717 _T("%p ('%s'): painting region [%i,%i,%i,%i]"),
718 this, GetName().c_str(),
719 rect.x, rect.y, rect.GetRight(), rect.GetBottom());
720
721 m_updateRegion = rect;
722
723 // FIXME_DFB: don't waste time rendering the area if it's fully covered
724 // by some children, go directly to rendering the children
725
726 // NB: unconditionally send wxEraseEvent, because our implementation of
727 // wxWindow::Refresh() ignores the eraseBack argument
728 wxWindowDC dc((wxWindow*)this);
729 wxEraseEvent eventEr(m_windowId, &dc);
730 eventEr.SetEventObject(this);
731 GetEventHandler()->ProcessEvent(eventEr);
732
733 wxRect clientRect(GetClientRect());
734
735 // only send wxNcPaintEvent if drawing at least part of nonclient area:
736 if ( !clientRect.Contains(rect) )
737 {
738 wxNcPaintEvent eventNc(GetId());
739 eventNc.SetEventObject(this);
740 GetEventHandler()->ProcessEvent(eventNc);
741 }
742 else
743 {
744 wxLogTrace(TRACE_PAINT, _T("%p ('%s'): not sending wxNcPaintEvent"),
745 this, GetName().c_str());
746 }
747
748 // only send wxPaintEvent if drawing at least part of client area:
749 if ( rect.Intersects(clientRect) )
750 {
751 wxPaintEvent eventPt(GetId());
752 eventPt.SetEventObject(this);
753 GetEventHandler()->ProcessEvent(eventPt);
754 }
755 else
756 {
757 wxLogTrace(TRACE_PAINT, _T("%p ('%s'): not sending wxPaintEvent"),
758 this, GetName().c_str());
759 }
760
761 // draw window's overlays on top of the painted window, if we have any:
762 PaintOverlays(rect);
763
764 m_updateRegion.Clear();
765
766 // paint the children:
767 wxPoint origin = GetClientAreaOrigin();
768 wxWindowList& children = GetChildren();
769 for ( wxWindowList::iterator i = children.begin();
770 i != children.end(); ++i )
771 {
772 wxWindow *child = *i;
773
774 if ( child->IsFrozen() || !child->IsShown() )
775 continue; // don't paint anything if the window is frozen or hidden
776
777 // compute child's area to repaint
778 wxRect childrect(child->GetRect());
779 childrect.Offset(origin);
780 childrect.Intersect(rect);
781 if ( childrect.IsEmpty() )
782 continue;
783
784 // and repaint it:
785 childrect.Offset(-child->GetPosition());
786 childrect.Offset(-origin);
787 child->PaintWindow(childrect);
788 }
789 }
790
791 void wxWindowDFB::PaintOverlays(const wxRect& rect)
792 {
793 if ( !m_overlays )
794 return;
795
796 for ( wxDfbOverlaysList::const_iterator i = m_overlays->begin();
797 i != m_overlays->end(); ++i )
798 {
799 wxOverlayImpl *overlay = *i;
800
801 wxRect orectOrig(overlay->GetRect());
802 wxRect orect(orectOrig);
803 orect.Intersect(rect);
804 if ( orect.IsEmpty() )
805 continue;
806
807 if ( overlay->IsEmpty() )
808 continue; // nothing to paint
809
810 DFBRectangle dfbRect = { orect.x - orectOrig.x, orect.y - orectOrig.y,
811 orect.width, orect.height };
812 GetDfbSurface()->Blit
813 (
814 overlay->GetDirectFBSurface(),
815 &dfbRect,
816 orect.x, orect.y
817 );
818 }
819 }
820
821 void wxWindowDFB::AddOverlay(wxOverlayImpl *overlay)
822 {
823 if ( !m_overlays )
824 m_overlays = new wxDfbOverlaysList;
825
826 m_overlays->Add(overlay);
827 }
828
829 void wxWindowDFB::RemoveOverlay(wxOverlayImpl *overlay)
830 {
831 wxCHECK_RET( m_overlays, _T("no overlays to remove") );
832
833 m_overlays->Remove(overlay);
834
835 if ( m_overlays->empty() )
836 {
837 wxDELETE(m_overlays);
838 }
839
840 if ( !m_isBeingDeleted )
841 RefreshWindowRect(overlay->GetRect());
842 }
843
844
845 // ---------------------------------------------------------------------------
846 // events handling
847 // ---------------------------------------------------------------------------
848
849 #define KEY(dfb, wx) \
850 case dfb: \
851 wxLogTrace(TRACE_EVENTS, \
852 _T("key " #dfb " mapped to " #wx)); \
853 return wx
854
855 // returns translated keycode, i.e. the one for KEYUP/KEYDOWN where 'a'..'z' is
856 // translated to 'A'..'Z'
857 static long GetTranslatedKeyCode(DFBInputDeviceKeyIdentifier key_id)
858 {
859 switch ( key_id )
860 {
861 KEY(DIKI_UNKNOWN, 0);
862
863 KEY(DIKI_A, 'A');
864 KEY(DIKI_B, 'B');
865 KEY(DIKI_C, 'C');
866 KEY(DIKI_D, 'D');
867 KEY(DIKI_E, 'E');
868 KEY(DIKI_F, 'F');
869 KEY(DIKI_G, 'G');
870 KEY(DIKI_H, 'H');
871 KEY(DIKI_I, 'I');
872 KEY(DIKI_J, 'J');
873 KEY(DIKI_K, 'K');
874 KEY(DIKI_L, 'L');
875 KEY(DIKI_M, 'M');
876 KEY(DIKI_N, 'N');
877 KEY(DIKI_O, 'O');
878 KEY(DIKI_P, 'P');
879 KEY(DIKI_Q, 'Q');
880 KEY(DIKI_R, 'R');
881 KEY(DIKI_S, 'S');
882 KEY(DIKI_T, 'T');
883 KEY(DIKI_U, 'U');
884 KEY(DIKI_V, 'V');
885 KEY(DIKI_W, 'W');
886 KEY(DIKI_X, 'X');
887 KEY(DIKI_Y, 'Y');
888 KEY(DIKI_Z, 'Z');
889
890 KEY(DIKI_0, '0');
891 KEY(DIKI_1, '1');
892 KEY(DIKI_2, '2');
893 KEY(DIKI_3, '3');
894 KEY(DIKI_4, '4');
895 KEY(DIKI_5, '5');
896 KEY(DIKI_6, '6');
897 KEY(DIKI_7, '7');
898 KEY(DIKI_8, '8');
899 KEY(DIKI_9, '9');
900
901 KEY(DIKI_F1, WXK_F1);
902 KEY(DIKI_F2, WXK_F2);
903 KEY(DIKI_F3, WXK_F3);
904 KEY(DIKI_F4, WXK_F4);
905 KEY(DIKI_F5, WXK_F5);
906 KEY(DIKI_F6, WXK_F6);
907 KEY(DIKI_F7, WXK_F7);
908 KEY(DIKI_F8, WXK_F8);
909 KEY(DIKI_F9, WXK_F9);
910 KEY(DIKI_F10, WXK_F10);
911 KEY(DIKI_F11, WXK_F11);
912 KEY(DIKI_F12, WXK_F12);
913
914 KEY(DIKI_SHIFT_L, WXK_SHIFT);
915 KEY(DIKI_SHIFT_R, WXK_SHIFT);
916 KEY(DIKI_CONTROL_L, WXK_CONTROL);
917 KEY(DIKI_CONTROL_R, WXK_CONTROL);
918 KEY(DIKI_ALT_L, WXK_ALT);
919 KEY(DIKI_ALT_R, WXK_ALT);
920 // this key was removed in 0.9.25 but include it for previous versions
921 // just to avoid gcc warnings about unhandled enum value in switch
922 #if !wxCHECK_DFB_VERSION(0, 9, 24)
923 KEY(DIKI_ALTGR, 0);
924 #endif
925 KEY(DIKI_META_L, 0);
926 KEY(DIKI_META_R, 0);
927 KEY(DIKI_SUPER_L, 0);
928 KEY(DIKI_SUPER_R, 0);
929 KEY(DIKI_HYPER_L, 0);
930 KEY(DIKI_HYPER_R, 0);
931
932 KEY(DIKI_CAPS_LOCK, 0);
933 KEY(DIKI_NUM_LOCK, WXK_NUMLOCK);
934 KEY(DIKI_SCROLL_LOCK, 0);
935
936 KEY(DIKI_ESCAPE, WXK_ESCAPE);
937 KEY(DIKI_LEFT, WXK_LEFT);
938 KEY(DIKI_RIGHT, WXK_RIGHT);
939 KEY(DIKI_UP, WXK_UP);
940 KEY(DIKI_DOWN, WXK_DOWN);
941 KEY(DIKI_TAB, WXK_TAB);
942 KEY(DIKI_ENTER, WXK_RETURN);
943 KEY(DIKI_SPACE, WXK_SPACE);
944 KEY(DIKI_BACKSPACE, WXK_BACK);
945 KEY(DIKI_INSERT, WXK_INSERT);
946 KEY(DIKI_DELETE, WXK_DELETE);
947 KEY(DIKI_HOME, WXK_HOME);
948 KEY(DIKI_END, WXK_END);
949 KEY(DIKI_PAGE_UP, WXK_PAGEUP);
950 KEY(DIKI_PAGE_DOWN, WXK_PAGEDOWN);
951 KEY(DIKI_PRINT, WXK_PRINT);
952 KEY(DIKI_PAUSE, WXK_PAUSE);
953
954 KEY(DIKI_QUOTE_LEFT, '`');
955 KEY(DIKI_MINUS_SIGN, '-');
956 KEY(DIKI_EQUALS_SIGN, '=');
957 KEY(DIKI_BRACKET_LEFT, '[');
958 KEY(DIKI_BRACKET_RIGHT, ']');
959 KEY(DIKI_BACKSLASH, '\\');
960 KEY(DIKI_SEMICOLON, ';');
961 KEY(DIKI_QUOTE_RIGHT, '\'');
962 KEY(DIKI_COMMA, ',');
963 KEY(DIKI_PERIOD, '.');
964 KEY(DIKI_SLASH, '/');
965
966 KEY(DIKI_LESS_SIGN, '<');
967
968 KEY(DIKI_KP_DIV, WXK_NUMPAD_DIVIDE);
969 KEY(DIKI_KP_MULT, WXK_NUMPAD_MULTIPLY);
970 KEY(DIKI_KP_MINUS, WXK_NUMPAD_SUBTRACT);
971 KEY(DIKI_KP_PLUS, WXK_NUMPAD_ADD);
972 KEY(DIKI_KP_ENTER, WXK_NUMPAD_ENTER);
973 KEY(DIKI_KP_SPACE, WXK_NUMPAD_SPACE);
974 KEY(DIKI_KP_TAB, WXK_NUMPAD_TAB);
975 KEY(DIKI_KP_F1, WXK_NUMPAD_F1);
976 KEY(DIKI_KP_F2, WXK_NUMPAD_F2);
977 KEY(DIKI_KP_F3, WXK_NUMPAD_F3);
978 KEY(DIKI_KP_F4, WXK_NUMPAD_F4);
979 KEY(DIKI_KP_EQUAL, WXK_NUMPAD_EQUAL);
980 KEY(DIKI_KP_SEPARATOR, WXK_NUMPAD_SEPARATOR);
981
982 KEY(DIKI_KP_DECIMAL, WXK_NUMPAD_DECIMAL);
983 KEY(DIKI_KP_0, WXK_NUMPAD0);
984 KEY(DIKI_KP_1, WXK_NUMPAD1);
985 KEY(DIKI_KP_2, WXK_NUMPAD2);
986 KEY(DIKI_KP_3, WXK_NUMPAD3);
987 KEY(DIKI_KP_4, WXK_NUMPAD4);
988 KEY(DIKI_KP_5, WXK_NUMPAD5);
989 KEY(DIKI_KP_6, WXK_NUMPAD6);
990 KEY(DIKI_KP_7, WXK_NUMPAD7);
991 KEY(DIKI_KP_8, WXK_NUMPAD8);
992 KEY(DIKI_KP_9, WXK_NUMPAD9);
993
994 case DIKI_KEYDEF_END:
995 case DIKI_NUMBER_OF_KEYS:
996 wxFAIL_MSG( _T("invalid key_id value") );
997 return 0;
998 }
999
1000 return 0; // silence compiler warnings
1001 }
1002
1003 // returns untranslated keycode, i.e. for EVT_CHAR, where characters are left in
1004 // the form they were entered (lowercase, diacritics etc.)
1005 static long GetUntraslatedKeyCode(DFBInputDeviceKeyIdentifier key_id,
1006 DFBInputDeviceKeySymbol key_symbol)
1007 {
1008 switch ( DFB_KEY_TYPE(key_symbol) )
1009 {
1010 case DIKT_UNICODE:
1011 #if wxUSE_UNICODE
1012 return key_symbol;
1013 #else
1014 if ( key_symbol < 128 )
1015 return key_symbol;
1016 else
1017 {
1018 #if wxUSE_WCHAR_T
1019 wchar_t chr = key_symbol;
1020 wxCharBuffer buf(wxConvUI->cWC2MB(&chr, 1, NULL));
1021 if ( buf )
1022 return *buf; // may be 0 if failed
1023 else
1024 #endif // wxUSE_WCHAR_T
1025 return 0;
1026 }
1027 #endif
1028
1029 default:
1030 return GetTranslatedKeyCode(key_id);
1031 }
1032 }
1033
1034 #undef KEY
1035
1036 void wxWindowDFB::HandleKeyEvent(const wxDFBWindowEvent& event_)
1037 {
1038 if ( !IsEnabled() )
1039 return;
1040
1041 const DFBWindowEvent& e = event_;
1042
1043 wxLogTrace(TRACE_EVENTS,
1044 _T("handling key %s event for window %p ('%s')"),
1045 e.type == DWET_KEYUP ? _T("up") : _T("down"),
1046 this, GetName().c_str());
1047
1048 // fill in wxKeyEvent fields:
1049 wxKeyEvent event;
1050 event.SetEventObject(this);
1051 event.SetTimestamp(wxDFB_EVENT_TIMESTAMP(e));
1052 event.m_rawCode = e.key_code;
1053 event.m_keyCode = GetTranslatedKeyCode(e.key_id);
1054 event.m_scanCode = 0; // not used by wx at all
1055 #if wxUSE_UNICODE
1056 event.m_uniChar = e.key_symbol;
1057 #endif
1058 event.m_shiftDown = ( e.modifiers & DIMM_SHIFT ) != 0;
1059 event.m_controlDown = ( e.modifiers & DIMM_CONTROL ) != 0;
1060 event.m_altDown = ( e.modifiers & DIMM_ALT ) != 0;
1061 event.m_metaDown = ( e.modifiers & DIMM_META ) != 0;
1062
1063 // translate coordinates from TLW-relative to this window-relative:
1064 event.m_x = e.x;
1065 event.m_y = e.y;
1066 GetTLW()->ClientToScreen(&event.m_x, &event.m_y);
1067 this->ScreenToClient(&event.m_x, &event.m_y);
1068
1069 if ( e.type == DWET_KEYUP )
1070 {
1071 event.SetEventType(wxEVT_KEY_UP);
1072 GetEventHandler()->ProcessEvent(event);
1073 }
1074 else
1075 {
1076 bool isTab = (event.m_keyCode == WXK_TAB);
1077
1078 event.SetEventType(wxEVT_KEY_DOWN);
1079
1080 if ( GetEventHandler()->ProcessEvent(event) )
1081 return;
1082
1083 // only send wxEVT_CHAR event if not processed yet:
1084 event.m_keyCode = GetUntraslatedKeyCode(e.key_id, e.key_symbol);
1085 if ( event.m_keyCode != 0 )
1086 {
1087 event.SetEventType(wxEVT_CHAR);
1088 if ( GetEventHandler()->ProcessEvent(event) )
1089 return;
1090 }
1091
1092 // Synthetize navigation key event, but do it only if the TAB key
1093 // wasn't handled yet:
1094 if ( isTab && GetParent() && GetParent()->HasFlag(wxTAB_TRAVERSAL) )
1095 {
1096 wxNavigationKeyEvent navEvent;
1097 navEvent.SetEventObject(GetParent());
1098 // Shift-TAB goes in reverse direction:
1099 navEvent.SetDirection(!event.m_shiftDown);
1100 // Ctrl-TAB changes the (parent) window, i.e. switch notebook page:
1101 navEvent.SetWindowChange(event.m_controlDown);
1102 navEvent.SetCurrentFocus(wxStaticCast(this, wxWindow));
1103 GetParent()->GetEventHandler()->ProcessEvent(navEvent);
1104 }
1105 }
1106 }
1107
1108 // ---------------------------------------------------------------------------
1109 // idle events processing
1110 // ---------------------------------------------------------------------------
1111
1112 void wxWindowDFB::OnInternalIdle()
1113 {
1114 if (wxUpdateUIEvent::CanUpdate(this))
1115 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
1116 }
1117
1118
1119 // Find the wxWindow at the current mouse position, returning the mouse
1120 // position.
1121 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
1122 {
1123 return wxFindWindowAtPoint(pt = wxGetMousePosition());
1124 }
1125
1126 wxWindow* wxFindWindowAtPoint(const wxPoint& pt)
1127 {
1128 wxFAIL_MSG( _T("wxFindWindowAtPoint not implemented") );
1129 return NULL;
1130 }