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