]> git.saurik.com Git - wxWidgets.git/blame - src/common/popupcmn.cpp
No real changes, just refactor wxControlContainer code a little.
[wxWidgets.git] / src / common / popupcmn.cpp
CommitLineData
c02ee97f 1///////////////////////////////////////////////////////////////////////////////
670f9935 2// Name: src/common/popupcmn.cpp
c02ee97f
VZ
3// Purpose: implementation of wxPopupTransientWindow
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 06.01.01
7// RCS-ID: $Id$
8// Copyright: (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
526954c5 9// Licence: wxWindows licence
c02ee97f
VZ
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
c02ee97f
VZ
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
833a51f6 27#if wxUSE_POPUPWIN
c02ee97f
VZ
28
29#include "wx/popupwin.h"
30
31#ifndef WX_PRECOMP
a57d600f 32 #include "wx/combobox.h" // wxComboCtrl
6a0fab3a 33 #include "wx/app.h" // wxPostEvent
ee351013 34 #include "wx/log.h"
c02ee97f
VZ
35#endif //WX_PRECOMP
36
2ac51e16 37#include "wx/display.h"
1295f134
VZ
38#include "wx/recguard.h"
39
c02ee97f
VZ
40#ifdef __WXUNIVERSAL__
41 #include "wx/univ/renderer.h"
76fa9e02 42 #include "wx/scrolbar.h"
c02ee97f
VZ
43#endif // __WXUNIVERSAL__
44
537a0880
RR
45#ifdef __WXGTK__
46 #include <gtk/gtk.h>
04e40451
PC
47 #if GTK_CHECK_VERSION(2,0,0)
48 #include "wx/gtk/private/gtk2-compat.h"
49 #else
50 #define gtk_widget_get_window(x) x->window
51 #endif
ac52d2b0
VZ
52#elif defined(__WXMSW__)
53 #include "wx/msw/private.h"
54#elif defined(__WXX11__)
55 #include "wx/x11/private.h"
c51c4752 56#endif
eb729cd3 57
537a0880 58IMPLEMENT_DYNAMIC_CLASS(wxPopupWindow, wxWindow)
6c3422e9 59IMPLEMENT_DYNAMIC_CLASS(wxPopupTransientWindow, wxPopupWindow)
761df41e
VZ
60
61#if wxUSE_COMBOBOX && defined(__WXUNIVERSAL__)
62 IMPLEMENT_DYNAMIC_CLASS(wxPopupComboWindow, wxPopupTransientWindow)
63#endif
6c3422e9 64
c02ee97f
VZ
65// ----------------------------------------------------------------------------
66// private classes
67// ----------------------------------------------------------------------------
68
69// event handlers which we use to intercept events which cause the popup to
70// disappear
71class wxPopupWindowHandler : public wxEvtHandler
72{
73public:
276612f7 74 wxPopupWindowHandler(wxPopupTransientWindow *popup) : m_popup(popup) {}
c02ee97f
VZ
75
76protected:
77 // event handlers
78 void OnLeftDown(wxMouseEvent& event);
0419fee9 79 void OnCaptureLost(wxMouseCaptureLostEvent& event);
c02ee97f
VZ
80
81private:
82 wxPopupTransientWindow *m_popup;
83
84 DECLARE_EVENT_TABLE()
c0c133e1 85 wxDECLARE_NO_COPY_CLASS(wxPopupWindowHandler);
c02ee97f
VZ
86};
87
88class wxPopupFocusHandler : public wxEvtHandler
89{
90public:
276612f7 91 wxPopupFocusHandler(wxPopupTransientWindow *popup) : m_popup(popup) {}
c02ee97f
VZ
92
93protected:
c02ee97f 94 void OnKillFocus(wxFocusEvent& event);
ffe42ca6 95 void OnChar(wxKeyEvent& event);
c02ee97f
VZ
96
97private:
98 wxPopupTransientWindow *m_popup;
99
100 DECLARE_EVENT_TABLE()
c0c133e1 101 wxDECLARE_NO_COPY_CLASS(wxPopupFocusHandler);
c02ee97f
VZ
102};
103
104// ----------------------------------------------------------------------------
105// event tables
106// ----------------------------------------------------------------------------
107
108BEGIN_EVENT_TABLE(wxPopupWindowHandler, wxEvtHandler)
109 EVT_LEFT_DOWN(wxPopupWindowHandler::OnLeftDown)
0419fee9 110 EVT_MOUSE_CAPTURE_LOST(wxPopupWindowHandler::OnCaptureLost)
c02ee97f
VZ
111END_EVENT_TABLE()
112
113BEGIN_EVENT_TABLE(wxPopupFocusHandler, wxEvtHandler)
114 EVT_KILL_FOCUS(wxPopupFocusHandler::OnKillFocus)
ffe42ca6 115 EVT_CHAR(wxPopupFocusHandler::OnChar)
c02ee97f
VZ
116END_EVENT_TABLE()
117
414f2513 118BEGIN_EVENT_TABLE(wxPopupTransientWindow, wxPopupWindow)
b7005dfd 119#if defined(__WXMSW__) || (defined(__WXMAC__) && wxOSX_USE_COCOA_OR_CARBON)
414f2513
RD
120 EVT_IDLE(wxPopupTransientWindow::OnIdle)
121#endif
122END_EVENT_TABLE()
123
c02ee97f
VZ
124// ============================================================================
125// implementation
126// ============================================================================
127
128// ----------------------------------------------------------------------------
129// wxPopupWindowBase
130// ----------------------------------------------------------------------------
131
799ea011
GD
132wxPopupWindowBase::~wxPopupWindowBase()
133{
134 // this destructor is required for Darwin
135}
136
c02ee97f
VZ
137bool wxPopupWindowBase::Create(wxWindow* WXUNUSED(parent), int WXUNUSED(flags))
138{
7e548f6b 139 return true;
c02ee97f
VZ
140}
141
142void wxPopupWindowBase::Position(const wxPoint& ptOrigin,
143 const wxSize& size)
144{
2ac51e16
VZ
145 // determine the position and size of the screen we clamp the popup to
146 wxPoint posScreen;
147 wxSize sizeScreen;
148
149 const int displayNum = wxDisplay::GetFromPoint(ptOrigin);
150 if ( displayNum != wxNOT_FOUND )
151 {
152 const wxRect rectScreen = wxDisplay(displayNum).GetGeometry();
153 posScreen = rectScreen.GetPosition();
154 sizeScreen = rectScreen.GetSize();
155 }
156 else // outside of any display?
157 {
158 // just use the primary one then
159 posScreen = wxPoint(0, 0);
160 sizeScreen = wxGetDisplaySize();
161 }
162
163
164 const wxSize sizeSelf = GetSize();
c02ee97f
VZ
165
166 // is there enough space to put the popup below the window (where we put it
167 // by default)?
168 wxCoord y = ptOrigin.y + size.y;
247f310d 169 if ( y + sizeSelf.y > posScreen.y + sizeScreen.y )
c02ee97f
VZ
170 {
171 // check if there is enough space above
172 if ( ptOrigin.y > sizeSelf.y )
173 {
174 // do position the control above the window
175 y -= size.y + sizeSelf.y;
176 }
177 //else: not enough space below nor above, leave below
178 }
179
180 // now check left/right too
d2aa263f 181 wxCoord x = ptOrigin.x;
2ac51e16 182
d2aa263f
VZ
183 if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft )
184 {
185 // shift the window to the left instead of the right.
186 x -= size.x;
187 x -= sizeSelf.x; // also shift it by window width.
188 }
189 else
190 x += size.x;
191
2ac51e16 192
247f310d 193 if ( x + sizeSelf.x > posScreen.x + sizeScreen.x )
c02ee97f
VZ
194 {
195 // check if there is enough space to the left
196 if ( ptOrigin.x > sizeSelf.x )
197 {
198 // do position the control to the left
199 x -= size.x + sizeSelf.x;
200 }
201 //else: not enough space there neither, leave in default position
202 }
203
204 Move(x, y, wxSIZE_NO_ADJUSTMENTS);
205}
206
207// ----------------------------------------------------------------------------
208// wxPopupTransientWindow
209// ----------------------------------------------------------------------------
210
211void wxPopupTransientWindow::Init()
212{
213 m_child =
d3b9f782 214 m_focus = NULL;
d7cff34d
VZ
215
216 m_handlerFocus = NULL;
217 m_handlerPopup = NULL;
c02ee97f
VZ
218}
219
758bce95 220wxPopupTransientWindow::wxPopupTransientWindow(wxWindow *parent, int style)
c02ee97f
VZ
221{
222 Init();
223
758bce95 224 (void)Create(parent, style);
c02ee97f
VZ
225}
226
227wxPopupTransientWindow::~wxPopupTransientWindow()
228{
0bf16170
MW
229 if (m_handlerPopup && m_handlerPopup->GetNextHandler())
230 PopHandlers();
17a1ebd1 231
0bf16170
MW
232 wxASSERT(!m_handlerFocus || !m_handlerFocus->GetNextHandler());
233 wxASSERT(!m_handlerPopup || !m_handlerPopup->GetNextHandler());
234
235 delete m_handlerFocus;
236 delete m_handlerPopup;
c02ee97f
VZ
237}
238
239void wxPopupTransientWindow::PopHandlers()
240{
241 if ( m_child )
242 {
0bf16170 243 if ( !m_child->RemoveEventHandler(m_handlerPopup) )
d7cff34d
VZ
244 {
245 // something is very wrong and someone else probably deleted our
246 // handler - so don't risk deleting it second time
247 m_handlerPopup = NULL;
248 }
414f2513 249 if (m_child->HasCapture())
17a1ebd1 250 {
414f2513
RD
251 m_child->ReleaseMouse();
252 }
c02ee97f
VZ
253 m_child = NULL;
254 }
255
256 if ( m_focus )
257 {
0bf16170 258 if ( !m_focus->RemoveEventHandler(m_handlerFocus) )
d7cff34d
VZ
259 {
260 // see above
261 m_handlerFocus = NULL;
262 }
c02ee97f 263 }
537a0880 264 m_focus = NULL;
c02ee97f
VZ
265}
266
267void wxPopupTransientWindow::Popup(wxWindow *winFocus)
268{
269 const wxWindowList& children = GetChildren();
270 if ( children.GetCount() )
271 {
272 m_child = children.GetFirst()->GetData();
273 }
274 else
275 {
276 m_child = this;
277 }
278
e4606ed9 279 Show();
e4606ed9 280
c9737636 281 // There is a problem if these are still in use
0bf16170
MW
282 wxASSERT(!m_handlerFocus || !m_handlerFocus->GetNextHandler());
283 wxASSERT(!m_handlerPopup || !m_handlerPopup->GetNextHandler());
276612f7 284
0bf16170
MW
285 if (!m_handlerPopup)
286 m_handlerPopup = new wxPopupWindowHandler(this);
d7cff34d 287
d7cff34d 288 m_child->PushEventHandler(m_handlerPopup);
c02ee97f 289
582699e1
JS
290#if defined(__WXMSW__)
291 // Focusing on child of popup window does not work on MSW unless WS_POPUP
292 // style is set. We do not even want to try to set the focus, as it may
293 // provoke errors on some Windows versions (Vista and later).
294 if ( ::GetWindowLong(GetHwnd(), GWL_STYLE) & WS_POPUP )
295#endif
296 {
297 m_focus = winFocus ? winFocus : this;
298 m_focus->SetFocus();
299 }
60178eb4 300
b7005dfd 301#if defined( __WXMSW__ ) || (defined( __WXMAC__) && wxOSX_USE_COCOA_OR_CARBON)
d7cff34d
VZ
302 // MSW doesn't allow to set focus to the popup window, but we need to
303 // subclass the window which has the focus, and not winFocus passed in or
304 // otherwise everything else breaks down
516cdd54 305 m_focus = FindFocus();
8c624a14 306#elif defined(__WXGTK__)
0bf16170
MW
307 // GTK+ catches the activate events from the popup
308 // window, not the focus events from the child window
309 m_focus = this;
310#endif
311
60178eb4
VZ
312 if ( m_focus )
313 {
0bf16170
MW
314 if (!m_handlerFocus)
315 m_handlerFocus = new wxPopupFocusHandler(this);
d7cff34d
VZ
316
317 m_focus->PushEventHandler(m_handlerFocus);
60178eb4 318 }
537a0880
RR
319}
320
321bool wxPopupTransientWindow::Show( bool show )
322{
323#ifdef __WXGTK__
324 if (!show)
f4bb632c 325 {
1897abe1
PC
326#ifdef __WXGTK3__
327 GdkDisplay* display = gtk_widget_get_display(m_widget);
328 GdkDeviceManager* manager = gdk_display_get_device_manager(display);
329 GdkDevice* device = gdk_device_manager_get_client_pointer(manager);
330 gdk_device_ungrab(device, unsigned(GDK_CURRENT_TIME));
331#else
f4bb632c 332 gdk_pointer_ungrab( (guint32)GDK_CURRENT_TIME );
1897abe1 333#endif
2997ca30 334
537a0880 335 gtk_grab_remove( m_widget );
f4bb632c 336 }
537a0880
RR
337#endif
338
c51c4752
RR
339#ifdef __WXX11__
340 if (!show)
341 {
342 XUngrabPointer( wxGlobalDisplay(), CurrentTime );
343 }
344#endif
345
9a890937 346#if defined( __WXMSW__ ) || defined( __WXMAC__)
414f2513 347 if (!show && m_child && m_child->HasCapture())
17a1ebd1 348 {
414f2513
RD
349 m_child->ReleaseMouse();
350 }
351#endif
17a1ebd1 352
537a0880 353 bool ret = wxPopupWindow::Show( show );
2997ca30 354
537a0880
RR
355#ifdef __WXGTK__
356 if (show)
f4bb632c 357 {
537a0880 358 gtk_grab_add( m_widget );
2997ca30 359
1897abe1
PC
360 const GdkEventMask mask = GdkEventMask(
361 GDK_BUTTON_PRESS_MASK |
362 GDK_BUTTON_RELEASE_MASK |
363 GDK_POINTER_MOTION_HINT_MASK |
364 GDK_POINTER_MOTION_MASK);
365 GdkWindow* window = gtk_widget_get_window(m_widget);
366#ifdef __WXGTK3__
367 GdkDisplay* display = gdk_window_get_display(window);
368 GdkDeviceManager* manager = gdk_display_get_device_manager(display);
369 GdkDevice* device = gdk_device_manager_get_client_pointer(manager);
370 gdk_device_grab(device, window,
371 GDK_OWNERSHIP_NONE, false, mask, NULL, unsigned(GDK_CURRENT_TIME));
372#else
373 gdk_pointer_grab( window, true,
374 mask,
d3b9f782
VZ
375 NULL,
376 NULL,
f4bb632c 377 (guint32)GDK_CURRENT_TIME );
1897abe1 378#endif
f4bb632c 379 }
537a0880
RR
380#endif
381
c51c4752
RR
382#ifdef __WXX11__
383 if (show)
384 {
385 Window xwindow = (Window) m_clientWindow;
2997ca30 386
c51c4752
RR
387 /* int res =*/ XGrabPointer(wxGlobalDisplay(), xwindow,
388 True,
389 ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask,
390 GrabModeAsync,
391 GrabModeAsync,
392 None,
393 None,
394 CurrentTime );
395 }
396#endif
414f2513 397
9a890937 398#if defined( __WXMSW__ ) || defined( __WXMAC__)
414f2513
RD
399 if (show && m_child)
400 {
401 // Assume that the mouse is outside the popup to begin with
402 m_child->CaptureMouse();
403 }
404#endif
405
537a0880 406 return ret;
c02ee97f
VZ
407}
408
f9e19204
VZ
409bool wxPopupTransientWindow::Destroy()
410{
411 // The popup window can be deleted at any moment, even while some events
412 // are still being processed for it, so delay its real destruction until
413 // the next idle time when we're sure that it's safe to really destroy it.
414
415 wxCHECK_MSG( !wxPendingDelete.Member(this), false,
416 wxS("Shouldn't destroy the popup twice.") );
417
418 wxPendingDelete.Append(this);
419
420 return true;
421}
422
c02ee97f
VZ
423void wxPopupTransientWindow::Dismiss()
424{
c02ee97f 425 Hide();
414f2513 426 PopHandlers();
c02ee97f
VZ
427}
428
429void wxPopupTransientWindow::DismissAndNotify()
430{
431 Dismiss();
c02ee97f
VZ
432 OnDismiss();
433}
434
435void wxPopupTransientWindow::OnDismiss()
436{
437 // nothing to do here - but it may be interesting for derived class
438}
439
440bool wxPopupTransientWindow::ProcessLeftDown(wxMouseEvent& WXUNUSED(event))
441{
442 // no special processing here
7e548f6b 443 return false;
c02ee97f
VZ
444}
445
b7005dfd 446#if defined(__WXMSW__) ||(defined(__WXMAC__) && wxOSX_USE_COCOA_OR_CARBON)
414f2513
RD
447void wxPopupTransientWindow::OnIdle(wxIdleEvent& event)
448{
449 event.Skip();
450
451 if (IsShown() && m_child)
452 {
453 wxPoint pos = ScreenToClient(wxGetMousePosition());
80797568 454 wxRect rect(GetSize());
414f2513 455
22a35096 456 if ( rect.Contains(pos) )
414f2513
RD
457 {
458 if ( m_child->HasCapture() )
459 {
460 m_child->ReleaseMouse();
461 }
462 }
463 else
464 {
465 if ( !m_child->HasCapture() )
466 {
467 m_child->CaptureMouse();
468 }
17a1ebd1 469 }
414f2513
RD
470 }
471}
0419fee9 472#endif // wxOSX/Carbon
414f2513
RD
473
474
a8132cd4 475#if wxUSE_COMBOBOX && defined(__WXUNIVERSAL__)
c02ee97f
VZ
476
477// ----------------------------------------------------------------------------
478// wxPopupComboWindow
479// ----------------------------------------------------------------------------
480
e0c83227
VZ
481BEGIN_EVENT_TABLE(wxPopupComboWindow, wxPopupTransientWindow)
482 EVT_KEY_DOWN(wxPopupComboWindow::OnKeyDown)
483END_EVENT_TABLE()
484
a57d600f 485wxPopupComboWindow::wxPopupComboWindow(wxComboCtrl *parent)
c02ee97f
VZ
486 : wxPopupTransientWindow(parent)
487{
488 m_combo = parent;
489}
490
a57d600f 491bool wxPopupComboWindow::Create(wxComboCtrl *parent)
c02ee97f
VZ
492{
493 m_combo = parent;
494
495 return wxPopupWindow::Create(parent);
496}
497
498void wxPopupComboWindow::PositionNearCombo()
499{
500 // the origin point must be in screen coords
c47addef 501 wxPoint ptOrigin = m_combo->ClientToScreen(wxPoint(0,0));
c02ee97f 502
89e7a223 503#if 0 //def __WXUNIVERSAL__
c02ee97f
VZ
504 // account for the fact that (0, 0) is not the top left corner of the
505 // window: there is also the border
506 wxRect rectBorders = m_combo->GetRenderer()->
507 GetBorderDimensions(m_combo->GetBorder());
508 ptOrigin.x -= rectBorders.x;
509 ptOrigin.y -= rectBorders.y;
510#endif // __WXUNIVERSAL__
511
512 // position below or above the combobox: the width is 0 to put it exactly
513 // below us, not to the left or to the right
514 Position(ptOrigin, wxSize(0, m_combo->GetSize().y));
515}
516
517void wxPopupComboWindow::OnDismiss()
518{
5d8a7943 519 m_combo->OnPopupDismiss(true);
c02ee97f
VZ
520}
521
e0c83227
VZ
522void wxPopupComboWindow::OnKeyDown(wxKeyEvent& event)
523{
3b7fa206 524 m_combo->ProcessWindowEvent(event);
e0c83227
VZ
525}
526
a8132cd4 527#endif // wxUSE_COMBOBOX && defined(__WXUNIVERSAL__)
c02ee97f
VZ
528
529// ----------------------------------------------------------------------------
530// wxPopupWindowHandler
531// ----------------------------------------------------------------------------
532
533void wxPopupWindowHandler::OnLeftDown(wxMouseEvent& event)
534{
535 // let the window have it first (we're the first event handler in the chain
536 // of handlers for this window)
537 if ( m_popup->ProcessLeftDown(event) )
538 {
539 return;
540 }
326c7ea8 541
c02ee97f
VZ
542 wxPoint pos = event.GetPosition();
543
af5c81b3 544 // in non-Univ ports the system manages scrollbars for us
9a6384ca 545#if defined(__WXUNIVERSAL__) && wxUSE_SCROLLBAR
3103e8a9 546 // scrollbar on which the click occurred
c02ee97f 547 wxWindow *sbar = NULL;
9a6384ca 548#endif // __WXUNIVERSAL__ && wxUSE_SCROLLBAR
c02ee97f
VZ
549
550 wxWindow *win = (wxWindow *)event.GetEventObject();
326c7ea8 551
c02ee97f
VZ
552 switch ( win->HitTest(pos.x, pos.y) )
553 {
554 case wxHT_WINDOW_OUTSIDE:
326c7ea8
VZ
555 {
556 // do the coords translation now as after DismissAndNotify()
557 // m_popup may be destroyed
558 wxMouseEvent event2(event);
559
560 m_popup->ClientToScreen(&event2.m_x, &event2.m_y);
561
562 // clicking outside a popup dismisses it
563 m_popup->DismissAndNotify();
564
565 // dismissing a tooltip shouldn't waste a click, i.e. you
566 // should be able to dismiss it and press the button with the
567 // same click, so repost this event to the window beneath us
17a1ebd1
VZ
568 wxWindow *winUnder = wxFindWindowAtPoint(event2.GetPosition());
569 if ( winUnder )
326c7ea8
VZ
570 {
571 // translate the event coords to the ones of the window
572 // which is going to get the event
17a1ebd1 573 winUnder->ScreenToClient(&event2.m_x, &event2.m_y);
326c7ea8 574
17a1ebd1 575 event2.SetEventObject(winUnder);
6aab9279 576 wxPostEvent(winUnder->GetEventHandler(), event2);
326c7ea8
VZ
577 }
578 }
c02ee97f
VZ
579 break;
580
9a6384ca 581#if defined(__WXUNIVERSAL__) && wxUSE_SCROLLBAR
c02ee97f
VZ
582 case wxHT_WINDOW_HORZ_SCROLLBAR:
583 sbar = win->GetScrollbar(wxHORIZONTAL);
584 break;
585
586 case wxHT_WINDOW_VERT_SCROLLBAR:
587 sbar = win->GetScrollbar(wxVERTICAL);
588 break;
9a6384ca 589#endif // __WXUNIVERSAL__ && wxUSE_SCROLLBAR
c02ee97f
VZ
590
591 default:
592 // forgot to update the switch after adding a new hit test code?
9a83f860 593 wxFAIL_MSG( wxT("unexpected HitTest() return value") );
c02ee97f
VZ
594 // fall through
595
596 case wxHT_WINDOW_CORNER:
597 // don't actually know if this one is good for anything, but let it
598 // pass just in case
599
600 case wxHT_WINDOW_INSIDE:
601 // let the normal processing take place
602 event.Skip();
603 break;
604 }
605
9a6384ca 606#if defined(__WXUNIVERSAL__) && wxUSE_SCROLLBAR
c02ee97f
VZ
607 if ( sbar )
608 {
609 // translate the event coordinates to the scrollbar ones
610 pos = sbar->ScreenToClient(win->ClientToScreen(pos));
611
612 // and give the event to it
613 wxMouseEvent event2 = event;
614 event2.m_x = pos.x;
615 event2.m_y = pos.y;
616
617 (void)sbar->GetEventHandler()->ProcessEvent(event2);
618 }
9a6384ca 619#endif // __WXUNIVERSAL__ && wxUSE_SCROLLBAR
c02ee97f
VZ
620}
621
0419fee9
VZ
622void
623wxPopupWindowHandler::OnCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event))
624{
625 m_popup->DismissAndNotify();
626
627 // There is no need to skip the event here, normally we've already dealt
628 // with the focus loss.
629}
630
c02ee97f
VZ
631// ----------------------------------------------------------------------------
632// wxPopupFocusHandler
633// ----------------------------------------------------------------------------
634
635void wxPopupFocusHandler::OnKillFocus(wxFocusEvent& event)
636{
60178eb4
VZ
637 // when we lose focus we always disappear - unless it goes to the popup (in
638 // which case we don't really lose it)
36a56c65
VS
639 wxWindow *win = event.GetWindow();
640 while ( win )
641 {
642 if ( win == m_popup )
643 return;
644 win = win->GetParent();
645 }
326c7ea8 646
36a56c65 647 m_popup->DismissAndNotify();
60178eb4 648}
54800df8 649
ffe42ca6 650void wxPopupFocusHandler::OnChar(wxKeyEvent& event)
60178eb4 651{
1295f134
VZ
652 // we can be associated with the popup itself in which case we should avoid
653 // infinite recursion
654 static int s_inside;
655 wxRecursionGuard guard(s_inside);
656 if ( guard.IsInside() )
657 {
658 event.Skip();
659 return;
660 }
661
60178eb4 662 // let the window have it first, it might process the keys
06077aaf 663 if ( !m_popup->GetEventHandler()->ProcessEvent(event) )
60178eb4
VZ
664 {
665 // by default, dismiss the popup
54800df8 666 m_popup->DismissAndNotify();
60178eb4 667 }
c02ee97f
VZ
668}
669
670#endif // wxUSE_POPUPWIN