~mterry/mir/session-for-surface

« back to all changes in this revision

Viewing changes to tests/acceptance-tests/test_client_input.cpp

  • Committer: Michael Terry
  • Date: 2013-07-29 17:51:51 UTC
  • mfrom: (832.1.58 trunk)
  • Revision ID: michael.terry@canonical.com-20130729175151-3thcnlepeihhzbb8
MergeĀ fromĀ trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 */
18
18
 
19
19
#include "mir/graphics/display.h"
20
 
#include "mir/graphics/viewable_area.h"
21
20
#include "mir/shell/surface_creation_parameters.h"
22
21
#include "mir/shell/placement_strategy.h"
23
22
#include "mir/shell/surface_factory.h"
34
33
#include "mir_test/fake_event_hub.h"
35
34
#include "mir_test/event_factory.h"
36
35
#include "mir_test/wait_condition.h"
 
36
#include "mir_test_framework/cross_process_sync.h"
37
37
#include "mir_test_framework/display_server_test_fixture.h"
38
38
#include "mir_test_framework/input_testing_server_configuration.h"
39
39
 
47
47
#include <functional>
48
48
#include <map>
49
49
 
 
50
#include <poll.h>
 
51
 
50
52
namespace mi = mir::input;
51
53
namespace mia = mi::android;
52
54
namespace mis = mi::synthesis;
120
122
 
121
123
struct InputClient : ClientConfig
122
124
{
123
 
    InputClient(std::string const& surface_name)
124
 
      : surface_name(surface_name)
 
125
    InputClient(const mtf::CrossProcessSync& input_cb_setup_fence, std::string const& surface_name)
 
126
            : input_cb_setup_fence(input_cb_setup_fence),
 
127
              surface_name(surface_name)
125
128
    {
126
129
    }
127
130
 
137
140
 
138
141
        // Set this in the callback, not main thread to avoid missing test events
139
142
        mir_surface_set_event_handler(surface, &event_delegate);
 
143
 
 
144
        try
 
145
        {
 
146
            input_cb_setup_fence.try_signal_ready_for(std::chrono::milliseconds(1000));
 
147
        } catch (const std::runtime_error& e)
 
148
        {
 
149
            std::cout << e.what() << std::endl;
 
150
        }
 
151
 
140
152
    }
141
153
 
142
154
    static void handle_input(MirSurface* /* surface */, MirEvent const* ev, void* context)
176
188
         auto request_params = parameters();
177
189
         mir_wait_for(mir_connection_create_surface(connection, &request_params, create_surface_callback, this));
178
190
 
179
 
         events_received.wait_for_at_most_seconds(60);
 
191
         events_received.wait_for_at_most_seconds(2);
180
192
 
181
193
         mir_surface_release_sync(surface);
182
194
 
190
202
    std::shared_ptr<MockInputHandler> handler;
191
203
    mt::WaitCondition events_received;
192
204
 
 
205
    mtf::CrossProcessSync input_cb_setup_fence;
193
206
    std::string const surface_name;
194
207
 
195
208
    static int const surface_width = 100;
295
308
    int const num_events_produced = 3;
296
309
    static std::string const test_client_name = "1";
297
310
 
 
311
    mtf::CrossProcessSync fence;
 
312
 
298
313
    struct ServerConfiguration : mtf::InputTestingServerConfiguration
299
314
    {
 
315
        mtf::CrossProcessSync input_cb_setup_fence;
 
316
 
 
317
        ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence) 
 
318
                : input_cb_setup_fence(input_cb_setup_fence)
 
319
        {
 
320
        }
 
321
        
300
322
        void inject_input()
301
323
        {
302
324
            wait_until_client_appears(test_client_name);
 
325
            input_cb_setup_fence.wait_for_signal_ready_for();
 
326
 
303
327
            for (int i = 0; i < num_events_produced; i++)
304
328
                fake_event_hub->synthesize_event(mis::a_key_down_event()
305
329
                                                 .of_scancode(KEY_ENTER));
306
330
        }
307
 
    } server_config;
 
331
    } server_config(fence);
308
332
    launch_server_process(server_config);
309
333
    
310
334
    struct KeyReceivingClient : InputClient
311
335
    {
312
 
        KeyReceivingClient() : InputClient(test_client_name) {}
 
336
        KeyReceivingClient(const mtf::CrossProcessSync& fence) : InputClient(fence, test_client_name) {}
313
337
        void expect_input(mt::WaitCondition& events_received) override
314
338
        {
315
339
            using namespace ::testing;
319
343
            EXPECT_CALL(*handler, handle_input(KeyDownEvent())).Times(1)
320
344
                .WillOnce(mt::WakeUp(&events_received));
321
345
        }
322
 
    } client_config;
 
346
    } client_config(fence);
323
347
    launch_client_process(client_config);
324
348
}
325
349
 
327
351
{
328
352
    using namespace ::testing;
329
353
    static std::string const test_client_name = "1";
330
 
    
 
354
    mtf::CrossProcessSync fence;
 
355
 
331
356
    struct ServerConfiguration : mtf::InputTestingServerConfiguration
332
357
    {
 
358
        mtf::CrossProcessSync input_cb_setup_fence;
 
359
 
 
360
        ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence) 
 
361
                : input_cb_setup_fence(input_cb_setup_fence)
 
362
        {
 
363
        }
 
364
 
333
365
        void inject_input()
334
366
        {
335
367
            wait_until_client_appears(test_client_name);
 
368
            input_cb_setup_fence.wait_for_signal_ready_for();
336
369
 
337
370
            fake_event_hub->synthesize_event(mis::a_key_down_event()
338
371
                                             .of_scancode(KEY_LEFTSHIFT));
340
373
                                             .of_scancode(KEY_4));
341
374
 
342
375
        }
343
 
    } server_config;
 
376
    } server_config{fence};
344
377
    launch_server_process(server_config);
345
378
    
346
379
    struct KeyReceivingClient : InputClient
347
380
    {
348
 
        KeyReceivingClient() : InputClient(test_client_name) {}
 
381
        KeyReceivingClient(const mtf::CrossProcessSync& fence) : InputClient(fence, test_client_name) {}
349
382
 
350
383
        void expect_input(mt::WaitCondition& events_received) override
351
384
        {
356
389
            EXPECT_CALL(*handler, handle_input(AllOf(KeyDownEvent(), KeyOfSymbol(XKB_KEY_dollar)))).Times(1)
357
390
                .WillOnce(mt::WakeUp(&events_received));
358
391
        }
359
 
    } client_config;
 
392
    } client_config{fence};
360
393
    launch_client_process(client_config);
361
394
}
362
395
 
364
397
{
365
398
    using namespace ::testing;
366
399
    static std::string const test_client_name = "1";
367
 
    
 
400
    mtf::CrossProcessSync fence;
 
401
 
368
402
    struct ServerConfiguration : public mtf::InputTestingServerConfiguration
369
403
    {
 
404
        mtf::CrossProcessSync input_cb_setup_fence;
 
405
 
 
406
        ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence) 
 
407
                : input_cb_setup_fence(input_cb_setup_fence)
 
408
        {
 
409
        }
 
410
 
370
411
        void inject_input()
371
412
        {
372
413
            wait_until_client_appears(test_client_name);
373
 
            
374
 
            fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(InputClient::surface_width,
375
 
                                                                                 InputClient::surface_height));
 
414
            input_cb_setup_fence.wait_for_signal_ready_for();
 
415
 
 
416
            fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(InputClient::surface_width - 1,
 
417
                                                                                 InputClient::surface_height - 1));
376
418
            fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(2,2));
377
419
        }
378
 
    } server_config;
 
420
    } server_config{fence};
379
421
    launch_server_process(server_config);
380
422
    
381
423
    struct MotionReceivingClient : InputClient
382
424
    {
383
 
        MotionReceivingClient() : InputClient(test_client_name) {}
 
425
        MotionReceivingClient(const mtf::CrossProcessSync& fence) : InputClient(fence, test_client_name) {}
384
426
 
385
427
        void expect_input(mt::WaitCondition& events_received) override
386
428
        {
391
433
            // We should see the cursor enter
392
434
            EXPECT_CALL(*handler, handle_input(HoverEnterEvent())).Times(1);
393
435
            EXPECT_CALL(*handler, handle_input(
394
 
                MotionEventWithPosition(InputClient::surface_width,
395
 
                                        InputClient::surface_height))).Times(1)
 
436
                MotionEventWithPosition(InputClient::surface_width - 1,
 
437
                                        InputClient::surface_height - 1))).Times(1)
396
438
                .WillOnce(mt::WakeUp(&events_received));
397
439
            // But we should not receive an event for the second movement outside of our surface!
398
440
        }
399
 
    } client_config;
 
441
    } client_config{fence};
400
442
    launch_client_process(client_config);
401
443
}
402
444
 
405
447
    using namespace ::testing;
406
448
    
407
449
    static std::string const test_client_name = "1";
408
 
    
 
450
    mtf::CrossProcessSync fence;
 
451
 
409
452
    struct ServerConfiguration : public mtf::InputTestingServerConfiguration
410
453
    {
 
454
        mtf::CrossProcessSync input_cb_setup_fence;
 
455
 
 
456
        ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence) 
 
457
                : input_cb_setup_fence(input_cb_setup_fence)
 
458
        {
 
459
        }
 
460
 
411
461
        void inject_input()
412
462
        {
413
463
            wait_until_client_appears(test_client_name);
 
464
            input_cb_setup_fence.wait_for_signal_ready_for();
 
465
 
414
466
            fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down));
415
467
        }
416
 
    } server_config;
 
468
    } server_config{fence};
417
469
    launch_server_process(server_config);
418
470
    
419
471
    struct ButtonReceivingClient : InputClient
420
472
    {
421
 
        ButtonReceivingClient() : InputClient(test_client_name) {}
 
473
        ButtonReceivingClient(const mtf::CrossProcessSync& fence) : InputClient(fence, test_client_name) {}
422
474
 
423
475
        void expect_input(mt::WaitCondition& events_received) override
424
476
        {
430
482
            EXPECT_CALL(*handler, handle_input(ButtonDownEvent(0, 0))).Times(1)
431
483
                .WillOnce(mt::WakeUp(&events_received));
432
484
        }
433
 
    } client_config;
 
485
    } client_config{fence};
434
486
    launch_client_process(client_config);
435
487
}
436
488
 
437
489
namespace
438
490
{
439
 
typedef std::map<std::string, geom::Rectangle> GeometryList;
 
491
typedef std::map<std::string, geom::Rectangle> GeometryMap;
 
492
typedef std::map<std::string, ms::DepthId> DepthMap;
440
493
 
441
494
struct StaticPlacementStrategy : public msh::PlacementStrategy
442
495
{
443
 
    StaticPlacementStrategy(GeometryList const& positions)
444
 
        : surface_geometry_by_name(positions)
 
496
    StaticPlacementStrategy(GeometryMap const& positions,
 
497
                            DepthMap const& depths)
 
498
        : surface_geometry_by_name(positions),
 
499
          surface_depths_by_name(depths)
 
500
    {
 
501
    }
 
502
 
 
503
    StaticPlacementStrategy(GeometryMap const& positions)
 
504
        : StaticPlacementStrategy(positions, DepthMap())
445
505
    {
446
506
    }
447
507
 
448
508
    msh::SurfaceCreationParameters place(msh::SurfaceCreationParameters const& request_parameters)
449
509
    {
450
510
        auto placed = request_parameters;
451
 
        auto geometry = surface_geometry_by_name[request_parameters.name];
 
511
        auto const& name = request_parameters.name;
 
512
        auto geometry = surface_geometry_by_name[name];
452
513
 
453
514
        placed.top_left = geometry.top_left;
454
515
        placed.size = geometry.size;
 
516
        placed.depth = surface_depths_by_name[name];
455
517
        
456
518
        return placed;
457
519
    }
458
 
    GeometryList surface_geometry_by_name;
 
520
    GeometryMap surface_geometry_by_name;
 
521
    DepthMap surface_depths_by_name;
459
522
};
460
523
 
461
524
}
470
533
    static int const client_width = screen_width/2;
471
534
    static std::string const test_client_1 = "1";
472
535
    static std::string const test_client_2 = "2";
473
 
    
 
536
    mtf::CrossProcessSync fence;
 
537
 
474
538
    struct ServerConfiguration : mtf::InputTestingServerConfiguration
475
539
    {
 
540
        mtf::CrossProcessSync input_cb_setup_fence;
 
541
 
 
542
        ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence) 
 
543
                : input_cb_setup_fence(input_cb_setup_fence)
 
544
        {
 
545
        }
 
546
 
476
547
        std::shared_ptr<msh::PlacementStrategy> the_shell_placement_strategy() override
477
548
        {
478
 
            static GeometryList positions;
 
549
            static GeometryMap positions;
479
550
            positions[test_client_1] = geom::Rectangle{geom::Point{0, 0},
480
551
                geom::Size{client_width, client_height}};
481
552
            positions[test_client_2] = geom::Rectangle{geom::Point{screen_width/2, screen_height/2},
484
555
            return std::make_shared<StaticPlacementStrategy>(positions);
485
556
        }
486
557
        
487
 
        geom::Rectangle the_screen_geometry() override
488
 
        {
489
 
            return geom::Rectangle{geom::Point{0, 0}, geom::Size{screen_width, screen_height}};
490
 
        }
491
 
 
492
558
        void inject_input() override
493
559
        {
494
560
            wait_until_client_appears(test_client_1);
 
561
            EXPECT_EQ(1, input_cb_setup_fence.wait_for_signal_ready_for());
495
562
            wait_until_client_appears(test_client_2);
 
563
            EXPECT_EQ(2, input_cb_setup_fence.wait_for_signal_ready_for());
 
564
 
496
565
            // In the bounds of the first surface
497
566
            fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(screen_width/2-1, screen_height/2-1));
498
567
            // In the bounds of the second surface
499
568
            fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(screen_width/2, screen_height/2));
500
569
        }
501
 
    } server_config;
 
570
    } server_config{fence};
502
571
    
503
572
    launch_server_process(server_config);
504
573
    
505
574
    struct InputClientOne : InputClient
506
575
    {
507
 
        InputClientOne()
508
 
           : InputClient(test_client_1)
 
576
        InputClientOne(const mtf::CrossProcessSync& fence)
 
577
                : InputClient(fence, test_client_1)
509
578
        {
510
579
        }
511
580
        
517
586
            EXPECT_CALL(*handler, handle_input(HoverExitEvent())).Times(1)
518
587
                .WillOnce(mt::WakeUp(&events_received));
519
588
        }
520
 
    } client_1;
 
589
    } client_1{fence};
521
590
 
522
591
    struct InputClientTwo : InputClient
523
592
    {
524
 
        InputClientTwo()
525
 
            : InputClient(test_client_2)
 
593
        InputClientTwo(const mtf::CrossProcessSync& fence)
 
594
                : InputClient(fence, test_client_2)
526
595
        {
527
596
        }
528
597
        
533
602
            EXPECT_CALL(*handler, handle_input(MotionEventWithPosition(client_width - 1, client_height - 1))).Times(1)
534
603
                .WillOnce(mt::WakeUp(&events_received));
535
604
        }
536
 
    } client_2;
 
605
    } client_2{fence};
537
606
 
538
607
    launch_client_process(client_1);
539
608
    launch_client_process(client_2);
570
639
{
571
640
    using namespace ::testing;
572
641
    static std::string const test_client_name = "1";
573
 
    
 
642
    mtf::CrossProcessSync fence;
 
643
 
574
644
    static int const screen_width = 100;
575
645
    static int const screen_height = 100;
576
646
    
584
654
 
585
655
    struct ServerConfiguration : mtf::InputTestingServerConfiguration
586
656
    {
 
657
        mtf::CrossProcessSync input_cb_setup_fence;
 
658
 
 
659
        ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence) 
 
660
                : input_cb_setup_fence(input_cb_setup_fence)
 
661
        {
 
662
        }
 
663
 
587
664
        std::shared_ptr<msh::PlacementStrategy> the_shell_placement_strategy() override
588
665
        {
589
 
            static GeometryList positions;
 
666
            static GeometryMap positions;
590
667
            positions[test_client_name] = screen_geometry;
591
668
            
592
669
            return std::make_shared<StaticPlacementStrategy>(positions);
596
673
            return std::make_shared<RegionApplyingSurfaceFactory>(InputTestingServerConfiguration::the_shell_surface_factory(),
597
674
                client_input_regions);
598
675
        }
599
 
        geom::Rectangle the_screen_geometry() override
600
 
        {
601
 
            return screen_geometry;
602
 
        }
603
676
        
604
677
        void inject_input() override
605
678
        {
606
679
            wait_until_client_appears(test_client_name);
 
680
            input_cb_setup_fence.wait_for_signal_ready_for();
607
681
            
608
682
            // First we will move the cursor in to the input region on the left side of the window. We should see a click here
609
683
            fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1, 1));
618
692
            fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down));
619
693
            fake_event_hub->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT));
620
694
        }
621
 
    } server_config;
 
695
    } server_config{fence};
622
696
    
623
697
    launch_server_process(server_config);
624
698
 
625
699
    struct ClientConfig : InputClient
626
700
    {
627
 
        ClientConfig()
628
 
            : InputClient(test_client_name)
 
701
        ClientConfig(const mtf::CrossProcessSync& fence)
 
702
                : InputClient(fence, test_client_name)
629
703
        {
630
704
        }
631
705
 
646
720
                    .WillOnce(mt::WakeUp(&events_received));
647
721
            }
648
722
        }
649
 
    } client_config;
 
723
    } client_config{fence};
650
724
    launch_client_process(client_config);
651
725
}
652
726
 
653
 
namespace
654
 
{
655
 
typedef std::map<std::string, ms::DepthId> DepthList;
656
 
 
657
 
struct StackingSurfaceController : public ms::SurfaceController
658
 
{
659
 
    StackingSurfaceController(std::shared_ptr<ms::SurfaceStackModel> const& surface_stack_model, DepthList const& depths)
660
 
        : SurfaceController(surface_stack_model),
661
 
          surface_depths_by_name(depths)
662
 
    {
663
 
    }
664
 
    
665
 
    std::weak_ptr<ms::Surface> create_surface(msh::Session*, msh::SurfaceCreationParameters const& params) override
666
 
    {
667
 
        return surface_stack->create_surface(params, surface_depths_by_name[params.name]);
668
 
    }
669
 
    
670
 
    DepthList surface_depths_by_name;
671
 
};
672
 
}
673
 
 
674
727
TEST_F(TestClientInput, surfaces_obscure_motion_events_by_stacking)
675
728
{
676
729
    using namespace ::testing;
677
730
    
678
731
    static std::string const test_client_name_1 = "1";
679
732
    static std::string const test_client_name_2 = "2";
 
733
    mtf::CrossProcessSync fence;
680
734
 
681
735
    static int const screen_width = 100;
682
736
    static int const screen_height = 100;
684
738
    static geom::Rectangle const screen_geometry{geom::Point{0, 0},
685
739
        geom::Size{screen_width, screen_height}};
686
740
 
687
 
    struct ServerConiguration : mtf::InputTestingServerConfiguration
 
741
    struct ServerConfiguration : mtf::InputTestingServerConfiguration
688
742
    {
 
743
        mtf::CrossProcessSync input_cb_setup_fence;
 
744
 
 
745
        ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence) 
 
746
                : input_cb_setup_fence(input_cb_setup_fence)
 
747
        {
 
748
        }
 
749
 
689
750
        std::shared_ptr<msh::PlacementStrategy> the_shell_placement_strategy() override
690
751
        {
691
 
            static GeometryList positions;
 
752
            static GeometryMap positions;
692
753
            positions[test_client_name_1] = screen_geometry;
693
754
            
694
755
            auto smaller_geometry = screen_geometry;
695
756
            smaller_geometry.size.width = geom::Width{screen_width/2};
696
757
            positions[test_client_name_2] = smaller_geometry;
697
758
            
698
 
            return std::make_shared<StaticPlacementStrategy>(positions);
699
 
       }
700
 
        
701
 
        std::shared_ptr<msh::SurfaceBuilder> the_surface_builder() override
702
 
        {
703
 
            static DepthList depths;
 
759
            static DepthMap depths;
704
760
            depths[test_client_name_1] = ms::DepthId{0};
705
761
            depths[test_client_name_2] = ms::DepthId{1};
706
762
            
707
 
            return std::make_shared<StackingSurfaceController>(the_surface_stack_model(), depths);
 
763
            return std::make_shared<StaticPlacementStrategy>(positions, depths);
708
764
        }
709
765
        
710
766
        void inject_input() override
711
767
        {
712
768
            wait_until_client_appears(test_client_name_1);
 
769
            input_cb_setup_fence.wait_for_signal_ready_for();
713
770
            wait_until_client_appears(test_client_name_2);
714
 
            
 
771
            input_cb_setup_fence.wait_for_signal_ready_for();
 
772
 
715
773
            // First we will move the cursor in to the region where client 2 obscures client 1
716
774
            fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1, 1));
717
775
            fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down));
721
779
            fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down));
722
780
            fake_event_hub->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT));
723
781
        }
724
 
    } server_config;
 
782
    } server_config{fence};
725
783
    
726
784
    launch_server_process(server_config);
727
785
 
728
786
    struct ClientConfigOne : InputClient
729
787
    {
730
 
        ClientConfigOne()
731
 
            : InputClient(test_client_name_1)
 
788
        ClientConfigOne(const mtf::CrossProcessSync& fence)
 
789
                : InputClient(fence, test_client_name_1)
732
790
        {
733
791
        }
734
792
 
746
804
                    .WillOnce(mt::WakeUp(&events_received));
747
805
            }
748
806
        }
749
 
    } client_config_1;
 
807
    } client_config_1{fence};
750
808
    launch_client_process(client_config_1);
751
809
 
752
810
    struct ClientConfigTwo : InputClient
753
811
    {
754
 
        ClientConfigTwo()
755
 
            : InputClient(test_client_name_2)
 
812
        ClientConfigTwo(const mtf::CrossProcessSync& fence)
 
813
                : InputClient(fence, test_client_name_2)
756
814
        {
757
815
        }
758
816
 
770
828
                  .WillOnce(mt::WakeUp(&events_received));
771
829
            }
772
830
        }
773
 
    } client_config_2;
 
831
    } client_config_2{fence};
774
832
    launch_client_process(client_config_2);
775
833
}