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