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