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