]> git.saurik.com Git - wxWidgets.git/blame - tests/events/propagation.cpp
Allow retrieving the descent and external leading of empty strings.
[wxWidgets.git] / tests / events / propagation.cpp
CommitLineData
1649d288
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: tests/events/propagation.cpp
3// Purpose: Test events propagation
4// Author: Vadim Zeitlin
5// Created: 2009-01-16
6// RCS-ID: $Id$
7// Copyright: (c) 2009 Vadim Zeitlin <vadim@wxwidgets.org>
8///////////////////////////////////////////////////////////////////////////////
9
10// ----------------------------------------------------------------------------
11// headers
12// ----------------------------------------------------------------------------
13
14#include "testprec.h"
15
16#ifdef __BORLANDC__
17 #pragma hdrstop
18#endif
19
20#ifndef WX_PRECOMP
c21dcf80
VZ
21 #include "wx/app.h"
22 #include "wx/event.h"
ce45133e 23 #include "wx/scrolwin.h"
c21dcf80 24 #include "wx/window.h"
1649d288
VZ
25#endif // WX_PRECOMP
26
a7c0de8a 27#include "wx/docmdi.h"
3bad8c39
VZ
28#include "wx/frame.h"
29#include "wx/menu.h"
bbde2164 30#include "wx/scopedptr.h"
1649d288 31#include "wx/scopeguard.h"
12ab6ad3 32#include "wx/toolbar.h"
dbd5b2ce 33#include "wx/uiaction.h"
1649d288 34
23366691
VZ
35// FIXME: Currently under OS X testing paint event doesn't work because neither
36// calling Refresh()+Update() nor even sending wxPaintEvent directly to
37// the window doesn't result in calls to its event handlers, so disable
38// some tests there. But this should be fixed and the tests reenabled
39// because wxPaintEvent propagation in wxScrolledWindow is a perfect
40// example of fragile code that could be broken under OS X.
41#ifndef __WXOSX__
42 #define CAN_TEST_PAINT_EVENTS
43#endif
44
1649d288
VZ
45namespace
46{
47
48// this string will record the execution of all handlers
49wxString g_str;
50
51// a custom event
52wxDEFINE_EVENT(TEST_EVT, wxCommandEvent);
53
ce45133e
VZ
54// a custom event handler tracing the propagation of the events of the
55// specified types
56template <class Event>
57class TestEvtHandlerBase : public wxEvtHandler
1649d288
VZ
58{
59public:
ce45133e
VZ
60 TestEvtHandlerBase(wxEventType evtType, char tag)
61 : m_evtType(evtType),
62 m_tag(tag)
1649d288 63 {
ce45133e
VZ
64 Connect(evtType,
65 static_cast<wxEventFunction>(&TestEvtHandlerBase::OnTest));
1649d288
VZ
66 }
67
68 // override ProcessEvent() to confirm that it is called for all event
69 // handlers in the chain
70 virtual bool ProcessEvent(wxEvent& event)
71 {
ce45133e 72 if ( event.GetEventType() == m_evtType )
1649d288
VZ
73 g_str += 'o'; // "o" == "overridden"
74
75 return wxEvtHandler::ProcessEvent(event);
76 }
77
78private:
ce45133e 79 void OnTest(wxEvent& event)
1649d288
VZ
80 {
81 g_str += m_tag;
82
83 event.Skip();
84 }
85
ce45133e 86 const wxEventType m_evtType;
1649d288
VZ
87 const char m_tag;
88
ce45133e
VZ
89 wxDECLARE_NO_COPY_TEMPLATE_CLASS(TestEvtHandlerBase, Event);
90};
91
92struct TestEvtHandler : TestEvtHandlerBase<wxCommandEvent>
93{
94 TestEvtHandler(char tag)
95 : TestEvtHandlerBase<wxCommandEvent>(TEST_EVT, tag)
96 {
97 }
98};
99
3bad8c39
VZ
100struct TestMenuEvtHandler : TestEvtHandlerBase<wxCommandEvent>
101{
102 TestMenuEvtHandler(char tag)
103 : TestEvtHandlerBase<wxCommandEvent>(wxEVT_MENU, tag)
104 {
105 }
106};
107
ce45133e
VZ
108struct TestPaintEvtHandler : TestEvtHandlerBase<wxPaintEvent>
109{
110 TestPaintEvtHandler(char tag)
111 : TestEvtHandlerBase<wxPaintEvent>(wxEVT_PAINT, tag)
112 {
113 }
1649d288
VZ
114};
115
a7c0de8a
VZ
116// Another custom event handler, suitable for use with Connect().
117struct TestEvtSink : wxEvtHandler
118{
119 TestEvtSink(char tag)
120 : m_tag(tag)
121 {
122 }
123
124 void Handle(wxEvent& event)
125 {
126 g_str += m_tag;
127
128 event.Skip();
129 }
130
131 const char m_tag;
132
133 wxDECLARE_NO_COPY_CLASS(TestEvtSink);
134};
135
1649d288
VZ
136// a window handling the test event
137class TestWindow : public wxWindow
138{
139public:
140 TestWindow(wxWindow *parent, char tag)
141 : wxWindow(parent, wxID_ANY),
142 m_tag(tag)
143 {
144 Connect(TEST_EVT, wxCommandEventHandler(TestWindow::OnTest));
145 }
146
147private:
148 void OnTest(wxCommandEvent& event)
149 {
150 g_str += m_tag;
151
152 event.Skip();
153 }
154
155 const char m_tag;
156
157 DECLARE_NO_COPY_CLASS(TestWindow)
158};
159
ce45133e
VZ
160// a scroll window handling paint event: we want to have a special test case
161// for this because the event propagation is complicated even further than
162// usual here by the presence of wxScrollHelperEvtHandler in the event handlers
163// chain and the fact that OnDraw() virtual method must be called if EVT_PAINT
164// is not handled
165class TestScrollWindow : public wxScrolledWindow
166{
167public:
168 TestScrollWindow(wxWindow *parent)
169 : wxScrolledWindow(parent, wxID_ANY)
170 {
171 Connect(wxEVT_PAINT, wxPaintEventHandler(TestScrollWindow::OnPaint));
172 }
173
23366691
VZ
174 void GeneratePaintEvent()
175 {
176#ifdef __WXGTK__
177 // We need to map the window, otherwise we're not going to get any
178 // paint events for it.
179 wxYield();
180
181 // Ignore events generated during the initial mapping.
182 g_str.clear();
183#endif // __WXGTK__
184
185 Refresh();
186 Update();
187 }
188
ce45133e
VZ
189 virtual void OnDraw(wxDC& WXUNUSED(dc))
190 {
191 g_str += 'D'; // draw
192 }
193
194private:
195 void OnPaint(wxPaintEvent& event)
196 {
197 g_str += 'P'; // paint
198 event.Skip();
199 }
200
201 wxDECLARE_NO_COPY_CLASS(TestScrollWindow);
202};
203
1649d288
VZ
204int DoFilterEvent(wxEvent& event)
205{
3bad8c39
VZ
206 if ( event.GetEventType() == TEST_EVT ||
207 event.GetEventType() == wxEVT_MENU )
1649d288
VZ
208 g_str += 'a';
209
210 return -1;
211}
212
213bool DoProcessEvent(wxEvent& event)
214{
3bad8c39
VZ
215 if ( event.GetEventType() == TEST_EVT ||
216 event.GetEventType() == wxEVT_MENU )
1649d288
VZ
217 g_str += 'A';
218
219 return false;
220}
221
222} // anonymous namespace
223
224// --------------------------------------------------------------------------
225// test class
226// --------------------------------------------------------------------------
227
228class EventPropagationTestCase : public CppUnit::TestCase
229{
230public:
231 EventPropagationTestCase() {}
232
233 virtual void setUp();
234 virtual void tearDown();
235
236private:
237 CPPUNIT_TEST_SUITE( EventPropagationTestCase );
238 CPPUNIT_TEST( OneHandler );
239 CPPUNIT_TEST( TwoHandlers );
240 CPPUNIT_TEST( WindowWithoutHandler );
241 CPPUNIT_TEST( WindowWithHandler );
bbdee10d 242 CPPUNIT_TEST( ForwardEvent );
ce45133e
VZ
243 CPPUNIT_TEST( ScrollWindowWithoutHandler );
244 CPPUNIT_TEST( ScrollWindowWithHandler );
3bad8c39 245 CPPUNIT_TEST( MenuEvent );
a7c0de8a 246 CPPUNIT_TEST( DocView );
dbd5b2ce 247 WXUISIM_TEST( ContextMenuEvent );
1649d288
VZ
248 CPPUNIT_TEST_SUITE_END();
249
250 void OneHandler();
251 void TwoHandlers();
252 void WindowWithoutHandler();
253 void WindowWithHandler();
bbdee10d 254 void ForwardEvent();
ce45133e
VZ
255 void ScrollWindowWithoutHandler();
256 void ScrollWindowWithHandler();
3bad8c39 257 void MenuEvent();
a7c0de8a 258 void DocView();
dbd5b2ce 259 void ContextMenuEvent();
1649d288
VZ
260
261 DECLARE_NO_COPY_CLASS(EventPropagationTestCase)
262};
263
264// register in the unnamed registry so that these tests are run by default
265CPPUNIT_TEST_SUITE_REGISTRATION( EventPropagationTestCase );
266
e3778b4d 267// also include in its own registry so that these tests can be run alone
1649d288
VZ
268CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( EventPropagationTestCase, "EventPropagationTestCase" );
269
270void EventPropagationTestCase::setUp()
271{
272 SetFilterEventFunc(DoFilterEvent);
273 SetProcessEventFunc(DoProcessEvent);
274
275 g_str.clear();
276}
277
278void EventPropagationTestCase::tearDown()
279{
280 SetFilterEventFunc(NULL);
281 SetProcessEventFunc(NULL);
282}
283
284void EventPropagationTestCase::OneHandler()
285{
286 wxCommandEvent event(TEST_EVT);
287 TestEvtHandler h1('1');
288 h1.ProcessEvent(event);
289 CPPUNIT_ASSERT_EQUAL( "oa1A", g_str );
290}
291
292void EventPropagationTestCase::TwoHandlers()
293{
294 wxCommandEvent event(TEST_EVT);
295 TestEvtHandler h1('1');
296 TestEvtHandler h2('2');
297 h1.SetNextHandler(&h2);
298 h2.SetPreviousHandler(&h1);
299 h1.ProcessEvent(event);
300 CPPUNIT_ASSERT_EQUAL( "oa1o2A", g_str );
301}
302
303void EventPropagationTestCase::WindowWithoutHandler()
304{
305 wxCommandEvent event(TEST_EVT);
306 TestWindow * const parent = new TestWindow(wxTheApp->GetTopWindow(), 'p');
307 wxON_BLOCK_EXIT_OBJ0( *parent, wxWindow::Destroy );
308
309 TestWindow * const child = new TestWindow(parent, 'c');
310
004867db 311 child->GetEventHandler()->ProcessEvent(event);
1649d288
VZ
312 CPPUNIT_ASSERT_EQUAL( "acpA", g_str );
313}
314
315void EventPropagationTestCase::WindowWithHandler()
316{
317 wxCommandEvent event(TEST_EVT);
318 TestWindow * const parent = new TestWindow(wxTheApp->GetTopWindow(), 'p');
319 wxON_BLOCK_EXIT_OBJ0( *parent, wxWindow::Destroy );
320
321 TestWindow * const child = new TestWindow(parent, 'c');
322
323 TestEvtHandler h1('1');
324 child->PushEventHandler(&h1);
9ebfc963 325 wxON_BLOCK_EXIT_OBJ1( *child, wxWindow::PopEventHandler, false );
1649d288
VZ
326 TestEvtHandler h2('2');
327 child->PushEventHandler(&h2);
9ebfc963 328 wxON_BLOCK_EXIT_OBJ1( *child, wxWindow::PopEventHandler, false );
1649d288
VZ
329
330 child->HandleWindowEvent(event);
331 CPPUNIT_ASSERT_EQUAL( "oa2o1cpA", g_str );
332}
333
bbdee10d
VZ
334void EventPropagationTestCase::ForwardEvent()
335{
336 // The idea of this test is to check that the events explicitly forwarded
337 // to another event handler still get pre/post-processed as usual as this
338 // used to be broken by the fixes trying to avoid duplicate processing.
339 TestWindow * const win = new TestWindow(wxTheApp->GetTopWindow(), 'w');
340 wxON_BLOCK_EXIT_OBJ0( *win, wxWindow::Destroy );
341
342 TestEvtHandler h1('1');
343 win->PushEventHandler(&h1);
344 wxON_BLOCK_EXIT_OBJ1( *win, wxWindow::PopEventHandler, false );
345
346 class ForwardEvtHandler : public wxEvtHandler
347 {
348 public:
349 ForwardEvtHandler(wxEvtHandler& h) : m_h(&h) { }
350
351 virtual bool ProcessEvent(wxEvent& event)
352 {
353 g_str += 'f';
354
355 return m_h->ProcessEvent(event);
356 }
357
358 private:
359 wxEvtHandler *m_h;
360 } f(h1);
361
362 // First send the event directly to f.
363 wxCommandEvent event1(TEST_EVT);
364 f.ProcessEvent(event1);
365 CPPUNIT_ASSERT_EQUAL( "foa1wA", g_str );
366 g_str.clear();
367
368 // And then also test sending it to f indirectly.
369 wxCommandEvent event2(TEST_EVT);
370 TestEvtHandler h2('2');
371 h2.SetNextHandler(&f);
372 h2.ProcessEvent(event2);
373 CPPUNIT_ASSERT_EQUAL( "oa2fo1wAA", g_str );
374}
375
ce45133e
VZ
376void EventPropagationTestCase::ScrollWindowWithoutHandler()
377{
52212bcb
VZ
378 TestWindow * const parent = new TestWindow(wxTheApp->GetTopWindow(), 'p');
379 wxON_BLOCK_EXIT_OBJ0( *parent, wxWindow::Destroy );
380
381 TestScrollWindow * const win = new TestScrollWindow(parent);
ce45133e 382
23366691
VZ
383#ifdef CAN_TEST_PAINT_EVENTS
384 win->GeneratePaintEvent();
ce45133e 385 CPPUNIT_ASSERT_EQUAL( "PD", g_str );
f009da6e 386#endif
23366691 387
52212bcb
VZ
388 g_str.clear();
389 wxCommandEvent eventCmd(TEST_EVT);
390 win->HandleWindowEvent(eventCmd);
391 CPPUNIT_ASSERT_EQUAL( "apA", g_str );
ce45133e
VZ
392}
393
394void EventPropagationTestCase::ScrollWindowWithHandler()
395{
52212bcb
VZ
396 TestWindow * const parent = new TestWindow(wxTheApp->GetTopWindow(), 'p');
397 wxON_BLOCK_EXIT_OBJ0( *parent, wxWindow::Destroy );
398
399 TestScrollWindow * const win = new TestScrollWindow(parent);
ce45133e 400
23366691 401#ifdef CAN_TEST_PAINT_EVENTS
ce45133e
VZ
402 TestPaintEvtHandler h('h');
403 win->PushEventHandler(&h);
404 wxON_BLOCK_EXIT_OBJ1( *win, wxWindow::PopEventHandler, false );
405
23366691 406 win->GeneratePaintEvent();
ce45133e 407 CPPUNIT_ASSERT_EQUAL( "ohPD", g_str );
15536294 408#endif
52212bcb
VZ
409
410 g_str.clear();
411 wxCommandEvent eventCmd(TEST_EVT);
412 win->HandleWindowEvent(eventCmd);
413 CPPUNIT_ASSERT_EQUAL( "apA", g_str );
ce45133e
VZ
414}
415
bbde2164
VZ
416// Create a menu bar with a single menu containing wxID_APPLY menu item and
417// attach it to the specified frame.
418wxMenu* CreateTestMenu(wxFrame* frame)
419{
420 wxMenu* const menu = new wxMenu;
421 menu->Append(wxID_APPLY);
422 wxMenuBar* const mb = new wxMenuBar;
423 mb->Append(menu, "&Menu");
424 frame->SetMenuBar(mb);
425
426 return menu;
427}
428
3bad8c39
VZ
429// Helper for checking that the menu event processing resulted in the expected
430// output from the handlers.
9fe94219
VZ
431//
432// Notice that this is supposed to be used with ASSERT_MENU_EVENT_RESULT()
433// macro to make the file name and line number of the caller appear in the
434// failure messages.
435void
436CheckMenuEvent(wxMenu* menu, const char* result, CppUnit::SourceLine sourceLine)
3bad8c39
VZ
437{
438 g_str.clear();
439
440 // Trigger the menu event: this is more reliable than using
441 // wxUIActionSimulator and currently works in all ports as they all call
442 // wxMenuBase::SendEvent() from their respective menu event handlers.
bbde2164 443 menu->SendEvent(wxID_APPLY);
3bad8c39 444
9fe94219 445 CPPUNIT_NS::assertEquals( result, g_str, sourceLine, "" );
3bad8c39
VZ
446}
447
9fe94219
VZ
448#define ASSERT_MENU_EVENT_RESULT(menu, result) \
449 CheckMenuEvent((menu), (result), CPPUNIT_SOURCELINE())
450
3bad8c39
VZ
451void EventPropagationTestCase::MenuEvent()
452{
3bad8c39 453 wxFrame* const frame = static_cast<wxFrame*>(wxTheApp->GetTopWindow());
bbde2164
VZ
454
455 // Create a minimal menu bar.
456 wxMenu* const menu = CreateTestMenu(frame);
457 wxMenuBar* const mb = menu->GetMenuBar();
458 wxScopedPtr<wxMenuBar> ensureMenuBarDestruction(mb);
3bad8c39
VZ
459 wxON_BLOCK_EXIT_OBJ1( *frame, wxFrame::SetMenuBar, (wxMenuBar*)NULL );
460
461 // Check that wxApp gets the event exactly once.
9fe94219 462 ASSERT_MENU_EVENT_RESULT( menu, "aA" );
3bad8c39
VZ
463
464
465 // Check that the menu event handler is called.
466 TestMenuEvtHandler hm('m'); // 'm' for "menu"
467 menu->SetNextHandler(&hm);
468 wxON_BLOCK_EXIT_OBJ1( *menu,
469 wxEvtHandler::SetNextHandler, (wxEvtHandler*)NULL );
9fe94219 470 ASSERT_MENU_EVENT_RESULT( menu, "aomA" );
3bad8c39
VZ
471
472
4ed3f4ab
VZ
473 // Test that the event handler associated with the menu bar gets the event.
474 TestMenuEvtHandler hb('b'); // 'b' for "menu Bar"
475 mb->PushEventHandler(&hb);
476 wxON_BLOCK_EXIT_OBJ1( *mb, wxWindow::PopEventHandler, false );
477
9fe94219 478 ASSERT_MENU_EVENT_RESULT( menu, "aomobA" );
4ed3f4ab
VZ
479
480
3bad8c39
VZ
481 // Also test that the window to which the menu belongs gets the event.
482 TestMenuEvtHandler hw('w'); // 'w' for "Window"
483 frame->PushEventHandler(&hw);
484 wxON_BLOCK_EXIT_OBJ1( *frame, wxWindow::PopEventHandler, false );
485
9fe94219 486 ASSERT_MENU_EVENT_RESULT( menu, "aomobowA" );
3bad8c39 487}
a7c0de8a
VZ
488
489// Minimal viable implementations of wxDocument and wxView.
490class EventTestDocument : public wxDocument
491{
492public:
493 EventTestDocument() { }
494
495 wxDECLARE_DYNAMIC_CLASS(EventTestDocument);
496};
497
498class EventTestView : public wxView
499{
500public:
501 EventTestView() { }
502
503 virtual void OnDraw(wxDC*) { }
504
505 wxDECLARE_DYNAMIC_CLASS(EventTestView);
506};
507
508wxIMPLEMENT_DYNAMIC_CLASS(EventTestDocument, wxDocument);
509wxIMPLEMENT_DYNAMIC_CLASS(EventTestView, wxView);
510
511void EventPropagationTestCase::DocView()
512{
513 // Set up the parent frame and its menu bar.
514 wxDocManager docManager;
515
516 wxScopedPtr<wxDocMDIParentFrame>
517 parent(new wxDocMDIParentFrame(&docManager, NULL, wxID_ANY, "Parent"));
518
519 wxMenu* const menu = CreateTestMenu(parent.get());
520
521
522 // Set up the event handlers.
523 TestEvtSink sinkDM('m');
524 docManager.Connect(wxEVT_MENU,
525 wxEventHandler(TestEvtSink::Handle), NULL, &sinkDM);
526
527 TestEvtSink sinkParent('p');
528 parent->Connect(wxEVT_MENU,
529 wxEventHandler(TestEvtSink::Handle), NULL, &sinkParent);
530
531
532 // Check that wxDocManager and wxFrame get the event in order.
533 ASSERT_MENU_EVENT_RESULT( menu, "ampA" );
534
535
536 // Now check what happens if we have an active document.
537 wxDocTemplate docTemplate(&docManager, "Test", "", "", "",
538 "Test Document", "Test View",
539 wxCLASSINFO(EventTestDocument),
540 wxCLASSINFO(EventTestView));
541 wxDocument* const doc = docTemplate.CreateDocument("");
542 wxView* const view = doc->GetFirstView();
543
ada25b6e 544 wxScopedPtr<wxMDIChildFrame>
a7c0de8a
VZ
545 child(new wxDocMDIChildFrame(doc, view, parent.get(), wxID_ANY, "Child"));
546
547 wxMenu* const menuChild = CreateTestMenu(child.get());
548
ada25b6e
VZ
549 // Ensure that the child that we've just created is the active one.
550 child->Activate();
551
a7c0de8a
VZ
552#ifdef __WXGTK__
553 // There are a lot of hacks related to child frame menu bar handling in
554 // wxGTK and, in particular, the code in src/gtk/mdi.cpp relies on getting
555 // idle events to really put everything in place. Moreover, as wxGTK uses
556 // GtkNotebook as its MDI pages container, the frame must be shown for all
557 // this to work as gtk_notebook_set_current_page() doesn't do anything if
558 // called for a hidden window (this incredible fact cost me quite some time
559 // to find empirically -- only to notice its confirmation in GTK+
560 // documentation immediately afterwards). So just do whatever it takes to
561 // make things work "as usual".
562 child->Show();
563 parent->Show();
564 wxYield();
565#endif // __WXGTK__
566
567 TestEvtSink sinkDoc('d');
568 doc->Connect(wxEVT_MENU,
569 wxEventHandler(TestEvtSink::Handle), NULL, &sinkDoc);
570
571 TestEvtSink sinkView('v');
572 view->Connect(wxEVT_MENU,
573 wxEventHandler(TestEvtSink::Handle), NULL, &sinkView);
574
575 TestEvtSink sinkChild('c');
576 child->Connect(wxEVT_MENU,
577 wxEventHandler(TestEvtSink::Handle), NULL, &sinkChild);
578
579 // Check that wxDocument, wxView, wxDocManager, child frame and the parent
580 // get the event in order.
581 ASSERT_MENU_EVENT_RESULT( menuChild, "advmcpA" );
12ab6ad3
VZ
582
583
584#if wxUSE_TOOLBAR
585 // Also check that toolbar events get forwarded to the active child.
586 wxToolBar* const tb = parent->CreateToolBar(wxTB_NOICONS);
587 tb->AddTool(wxID_APPLY, "Apply", wxNullBitmap);
588 tb->Realize();
589
590 // As in CheckMenuEvent(), use toolbar method actually sending the event
591 // instead of bothering with wxUIActionSimulator which would have been
592 // trickier.
593 g_str.clear();
594 tb->OnLeftClick(wxID_APPLY, true /* doesn't matter */);
595
596 CPPUNIT_ASSERT_EQUAL( "advmcpA", g_str );
597#endif // wxUSE_TOOLBAR
a7c0de8a 598}
dbd5b2ce
VZ
599
600#if wxUSE_UIACTIONSIMULATOR
601
602class ContextMenuTestWindow : public wxWindow
603{
604public:
605 ContextMenuTestWindow(wxWindow *parent, char tag)
606 : wxWindow(parent, wxID_ANY),
607 m_tag(tag)
608 {
609 Connect(wxEVT_CONTEXT_MENU,
610 wxContextMenuEventHandler(ContextMenuTestWindow::OnMenu));
611 }
612
613private:
614 void OnMenu(wxContextMenuEvent& event)
615 {
616 g_str += m_tag;
617
618 event.Skip();
619 }
620
621 const char m_tag;
622
623 wxDECLARE_NO_COPY_CLASS(ContextMenuTestWindow);
624};
625
626void EventPropagationTestCase::ContextMenuEvent()
627{
628 ContextMenuTestWindow * const
629 parent = new ContextMenuTestWindow(wxTheApp->GetTopWindow(), 'p');
630 wxON_BLOCK_EXIT_OBJ0( *parent, wxWindow::Destroy );
631
632 ContextMenuTestWindow * const
633 child = new ContextMenuTestWindow(parent, 'c');
634 parent->SetSize(100, 100);
635 child->SetSize(0, 0, 50, 50);
636 child->SetFocus();
637
638 wxUIActionSimulator sim;
639 const wxPoint origin = parent->ClientToScreen(wxPoint(0, 0));
640
641 // Right clicking in the child should generate an event for it and the
642 // parent.
643 g_str.clear();
644 sim.MouseMove(origin + wxPoint(10, 10));
645 sim.MouseClick(wxMOUSE_BTN_RIGHT);
646
647 // At least with MSW, for WM_CONTEXTMENU to be synthesized by the system
648 // from the right mouse click event, we must dispatch the mouse messages.
649 wxYield();
650
651 CPPUNIT_ASSERT_EQUAL( "cp", g_str );
652
653 // Right clicking outside the child should generate the event just in the
654 // parent.
655 g_str.clear();
656 sim.MouseMove(origin + wxPoint(60, 60));
657 sim.MouseClick(wxMOUSE_BTN_RIGHT);
658 wxYield();
659 CPPUNIT_ASSERT_EQUAL( "p", g_str );
660}
661
662#endif // wxUSE_UIACTIONSIMULATOR