]> git.saurik.com Git - wxWidgets.git/blame - src/dfb/window.cpp
Fix for handling of invalid gifs, patch 1587754 Noel Byron.
[wxWidgets.git] / src / dfb / window.cpp
CommitLineData
b3c86150
VS
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"
30c841c8 34#include "wx/dynarray.h"
b3c86150
VS
35
36#include "wx/dfb/private.h"
30c841c8 37#include "wx/private/overlay.h"
b3c86150
VS
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:
51static wxWindowDFB *gs_focusedWindow = NULL;
52// the window that is about to be focused after currently focused
53// one looses focus:
54static wxWindow *gs_toBeFocusedWindow = NULL;
55// the window that has mouse capture
56static wxWindowDFB *gs_mouseCapture = NULL;
57
30c841c8
VS
58// ---------------------------------------------------------------------------
59// overlays support
60// ---------------------------------------------------------------------------
61
62WX_DEFINE_ARRAY_PTR(wxOverlayImpl*, wxDfbOverlaysList);
63
b3c86150
VS
64// ---------------------------------------------------------------------------
65// event tables
66// ---------------------------------------------------------------------------
67
68// in wxUniv this class is abstract because it doesn't have DoPopupMenu()
69IMPLEMENT_ABSTRACT_CLASS(wxWindowDFB, wxWindowBase)
70
71BEGIN_EVENT_TABLE(wxWindowDFB, wxWindowBase)
72END_EVENT_TABLE()
73
74// ----------------------------------------------------------------------------
75// constructors and such
76// ----------------------------------------------------------------------------
77
78void wxWindowDFB::Init()
79{
80 m_isShown = true;
81 m_frozenness = 0;
82 m_tlw = NULL;
30c841c8 83 m_overlays = NULL;
b3c86150
VS
84}
85
86// Destructor
87wxWindowDFB::~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 )
4ff28c37 116 DFBKillFocus();
b3c86150
VS
117
118 DestroyChildren();
119}
120
121// real construction (Init() must have been called before!)
122bool 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
dbbdd346
VS
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
b3c86150
VS
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
52c8d32a 157wxIDirectFBSurfacePtr wxWindowDFB::ObtainDfbSurface() const
b3c86150
VS
158{
159 wxCHECK_MSG( m_parent, NULL, _T("parentless window?") );
160
52c8d32a 161 wxIDirectFBSurfacePtr parentSurface(m_parent->GetDfbSurface());
b3c86150
VS
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
52c8d32a 168 return parentSurface->GetSubSurface(&rect);
b3c86150
VS
169}
170
52c8d32a 171wxIDirectFBSurfacePtr wxWindowDFB::GetDfbSurface()
b3c86150
VS
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
182void wxWindowDFB::InvalidateDfbSurface()
183{
184 m_surface = NULL;
7807a2b4
VS
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 }
b3c86150
VS
193}
194
195// ---------------------------------------------------------------------------
196// basic operations
197// ---------------------------------------------------------------------------
198
199void wxWindowDFB::SetFocus()
200{
4ff28c37
VS
201 if ( gs_focusedWindow == this )
202 return; // nothing to do, focused already
b3c86150
VS
203
204 wxWindowDFB *oldFocusedWindow = gs_focusedWindow;
205
206 if ( gs_focusedWindow )
207 {
208 gs_toBeFocusedWindow = (wxWindow*)this;
4ff28c37 209 gs_focusedWindow->DFBKillFocus();
b3c86150
VS
210 gs_toBeFocusedWindow = NULL;
211 }
212
b3c86150
VS
213 gs_focusedWindow = this;
214
4ff28c37
VS
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"
b3c86150
VS
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
4ff28c37
VS
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
b3c86150
VS
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
4ff28c37 261void wxWindowDFB::DFBKillFocus()
b3c86150 262{
4ff28c37
VS
263 wxCHECK_RET( gs_focusedWindow == this,
264 _T("killing focus on window that doesn't have it") );
265
b3c86150
VS
266 gs_focusedWindow = NULL;
267
4ff28c37
VS
268 if ( m_isBeingDeleted )
269 return; // don't send any events from dtor
b3c86150
VS
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// ----------------------------------------------------------------------------
288wxWindow *wxWindowBase::DoFindFocus()
289{
290 return (wxWindow*)gs_focusedWindow;
291}
292
293bool 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
331void wxWindowDFB::Raise()
332{
333 wxFAIL_MSG( _T("Raise() not implemented") );
334}
335
336// Lower the window to the bottom of the Z order
337void wxWindowDFB::Lower()
338{
339 wxFAIL_MSG( _T("Lower() not implemented") );
340}
341
342void 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
355void 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
371bool 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
390void 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
a5b31f4e 401 wxIDirectFBDisplayLayerPtr layer(wxIDirectFB::Get()->GetDisplayLayer());
b3c86150
VS
402 wxCHECK_RET( layer, _T("no display layer") );
403
52c8d32a 404 layer->WarpCursor(x, y);
b3c86150
VS
405}
406
407// Set this window to be the child of 'parent'.
408bool 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
424void wxWindowDFB::DoGetSize(int *x, int *y) const
425{
426 if (x) *x = m_rect.width;
427 if (y) *y = m_rect.height;
428}
429
430void wxWindowDFB::DoGetPosition(int *x, int *y) const
431{
432 if (x) *x = m_rect.x;
433 if (y) *y = m_rect.y;
434}
435
436static 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
448void 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
456void 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.
465void wxWindowDFB::DoGetClientSize(int *x, int *y) const
466{
467 DoGetSize(x, y);
468}
469
470void wxWindowDFB::DoMoveWindow(int x, int y, int width, int height)
471{
6f7eb299
VS
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
b3c86150 479 wxRect oldpos(m_rect);
6f7eb299
VS
480 oldpos.Offset(parentOrigin);
481
b3c86150
VS
482 wxRect newpos(x, y, width, height);
483
6f7eb299 484 // input [x,y] is in window coords, but we store client coords in m_rect:
b3c86150 485 m_rect = newpos;
6f7eb299 486 m_rect.Offset(-parentOrigin);
b3c86150
VS
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();
b3c86150
VS
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
508void 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
b3c86150
VS
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 {
6f7eb299 575 AdjustForParentClientOrigin(x, y, sizeFlags);
b3c86150
VS
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
585void wxWindowDFB::DoSetClientSize(int width, int height)
586{
587 SetSize(width, height);
588}
589
590// ---------------------------------------------------------------------------
591// text metrics
592// ---------------------------------------------------------------------------
593
594int wxWindowDFB::GetCharHeight() const
595{
596 wxWindowDC dc((wxWindow*)this);
597 return dc.GetCharHeight();
598}
599
600int wxWindowDFB::GetCharWidth() const
601{
602 wxWindowDC dc((wxWindow*)this);
603 return dc.GetCharWidth();
604}
605
606void 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
620void wxWindowDFB::Clear()
621{
622 wxClientDC dc((wxWindow *)this);
623 wxBrush brush(GetBackgroundColour(), wxSOLID);
624 dc.SetBackground(brush);
625 dc.Clear();
626}
627
20671963 628void wxWindowDFB::Refresh(bool WXUNUSED(eraseBack), const wxRect *rect)
b3c86150
VS
629{
630 if ( !IsShown() || IsFrozen() )
631 return;
632
20671963
VS
633 // NB[1]: We intentionally ignore the eraseBack argument here. This is
634 // because of the way wxDFB's painting is implemented: the refresh
30c841c8 635 // request is propagated up to wxTLW, which is then painted in
20671963
VS
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.
b3c86150 644 if ( rect )
20671963 645 DoRefreshRect(*rect);
b3c86150 646 else
20671963 647 DoRefreshWindow();
b3c86150
VS
648}
649
30c841c8
VS
650void wxWindowDFB::RefreshWindowRect(const wxRect& rect)
651{
652 if ( !IsShown() || IsFrozen() )
653 return;
654
655 DoRefreshRect(rect);
656}
657
20671963 658void wxWindowDFB::DoRefreshWindow()
b3c86150 659{
20671963
VS
660 // NB: DoRefreshRect() takes window coords, not client, so this is correct
661 DoRefreshRect(wxRect(GetSize()));
b3c86150
VS
662}
663
20671963 664void wxWindowDFB::DoRefreshRect(const wxRect& rect)
b3c86150
VS
665{
666 wxWindow *parent = GetParent();
667 wxCHECK_RET( parent, _T("no parent") );
668
20671963
VS
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
b3c86150
VS
680 // convert the refresh rectangle to parent's coordinates and
681 // recursively refresh the parent:
b3c86150
VS
682 r.Offset(GetPosition());
683 r.Offset(parent->GetClientAreaOrigin());
684
20671963 685 parent->DoRefreshRect(r);
b3c86150
VS
686}
687
688void wxWindowDFB::Update()
689{
690 if ( !IsShown() || IsFrozen() )
691 return;
692
693 GetParent()->Update();
694}
695
696void wxWindowDFB::Freeze()
697{
698 m_frozenness++;
699}
700
701void wxWindowDFB::Thaw()
702{
703 wxASSERT_MSG( IsFrozen(), _T("Thaw() without matching Freeze()") );
704
705 if ( --m_frozenness == 0 )
706 {
707 if ( IsShown() )
20671963 708 DoRefreshWindow();
b3c86150
VS
709 }
710}
711
20671963 712void wxWindowDFB::PaintWindow(const wxRect& rect)
b3c86150 713{
14ac4e3a 714 wxCHECK_RET( !IsFrozen() && IsShown(), _T("shouldn't be called") );
b3c86150
VS
715
716 wxLogTrace(TRACE_PAINT,
20671963 717 _T("%p ('%s'): painting region [%i,%i,%i,%i]"),
b3c86150 718 this, GetName().c_str(),
20671963 719 rect.x, rect.y, rect.GetRight(), rect.GetBottom());
b3c86150 720
224175a5
VS
721 m_updateRegion = rect;
722
20671963
VS
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:
22a35096 736 if ( !clientRect.Contains(rect) )
b3c86150 737 {
20671963
VS
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());
b3c86150
VS
746 }
747
20671963
VS
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 }
b3c86150 760
30c841c8
VS
761 // draw window's overlays on top of the painted window, if we have any:
762 PaintOverlays(rect);
224175a5 763
30c841c8 764 m_updateRegion.Clear();
b3c86150 765
20671963 766 // paint the children:
b3c86150
VS
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
14ac4e3a
VS
774 if ( child->IsFrozen() || !child->IsShown() )
775 continue; // don't paint anything if the window is frozen or hidden
776
b3c86150
VS
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:
20671963
VS
785 childrect.Offset(-child->GetPosition());
786 childrect.Offset(-origin);
787 child->PaintWindow(childrect);
b3c86150 788 }
b3c86150
VS
789}
790
30c841c8
VS
791void 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
821void wxWindowDFB::AddOverlay(wxOverlayImpl *overlay)
822{
823 if ( !m_overlays )
824 m_overlays = new wxDfbOverlaysList;
825
826 m_overlays->Add(overlay);
827}
828
829void 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
b3c86150
VS
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'
857static 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);
7de1afbf
VZ
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
b3c86150
VS
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.)
1005static 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
1036void 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
1112void 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.
1121wxWindow* wxFindWindowAtPointer(wxPoint& pt)
1122{
1123 return wxFindWindowAtPoint(pt = wxGetMousePosition());
1124}
1125
1126wxWindow* wxFindWindowAtPoint(const wxPoint& pt)
1127{
1128 wxFAIL_MSG( _T("wxFindWindowAtPoint not implemented") );
1129 return NULL;
1130}