@@ -65,19 +65,58 @@ pub trait SurfaceProviderRegistration: Send {
65
65
fn clone ( & self ) -> Box < dyn SurfaceProviderRegistration > ;
66
66
}
67
67
68
+ ///
69
+ pub trait ContextMenuProvider : Send {
70
+ /// Open a context menu, return a way to poll for the result
71
+ fn open_context_menu ( & self ) -> Box < dyn ContextMenuFuture > ;
72
+ /// Clone self as a trait object
73
+ fn clone_object ( & self ) -> Box < dyn ContextMenuProvider > ;
74
+ }
75
+
76
+ /// A way to poll for the result of the context menu request
77
+ pub trait ContextMenuFuture {
78
+ fn poll ( & self ) -> ContextMenuResult ;
79
+ }
80
+
81
+ /// The result of polling on a context menu request
82
+ pub enum ContextMenuResult {
83
+ /// Session should exit
84
+ ExitSession ,
85
+ /// Dialog was dismissed
86
+ Dismissed ,
87
+ /// User has not acted on dialog
88
+ Pending ,
89
+ }
90
+
91
+ impl Drop for OpenXrDevice {
92
+ fn drop ( & mut self ) {
93
+ // This should be happening automatically in the destructors,
94
+ // but it isn't, presumably because there's an extra handle floating
95
+ // around somewhere
96
+ // XXXManishearth find out where that extra handle is
97
+ unsafe {
98
+ ( self . instance . fp ( ) . destroy_session ) ( self . session . as_raw ( ) ) ;
99
+ ( self . instance . fp ( ) . destroy_instance ) ( self . instance . as_raw ( ) ) ;
100
+ }
101
+ }
102
+ }
103
+
68
104
pub struct OpenXrDiscovery {
69
105
gl_thread : Box < dyn GlThread > ,
70
106
provider_registration : Box < dyn SurfaceProviderRegistration > ,
107
+ context_menu_provider : Box < dyn ContextMenuProvider > ,
71
108
}
72
109
73
110
impl OpenXrDiscovery {
74
111
pub fn new (
75
112
gl_thread : Box < dyn GlThread > ,
76
113
provider_registration : Box < dyn SurfaceProviderRegistration > ,
114
+ context_menu_provider : Box < dyn ContextMenuProvider > ,
77
115
) -> Self {
78
116
Self {
79
117
gl_thread,
80
118
provider_registration,
119
+ context_menu_provider,
81
120
}
82
121
}
83
122
}
@@ -132,13 +171,15 @@ impl DiscoveryAPI<SwapChains> for OpenXrDiscovery {
132
171
let provider_registration = self . provider_registration . clone ( ) ;
133
172
let granted_features = init. validate ( mode, & [ "local-floor" . into ( ) ] ) ?;
134
173
let id = xr. id ( ) ;
174
+ let context_menu_provider = self . context_menu_provider . clone_object ( ) ;
135
175
xr. spawn ( move || {
136
176
OpenXrDevice :: new (
137
177
gl_thread,
138
178
provider_registration,
139
179
instance,
140
180
granted_features,
141
181
id,
182
+ context_menu_provider,
142
183
)
143
184
} )
144
185
} else {
@@ -152,9 +193,9 @@ impl DiscoveryAPI<SwapChains> for OpenXrDiscovery {
152
193
}
153
194
154
195
struct OpenXrDevice {
196
+ session : Session < D3D11 > ,
155
197
instance : Instance ,
156
198
events : EventBuffer ,
157
- session : Session < D3D11 > ,
158
199
frame_waiter : FrameWaiter ,
159
200
shared_data : Arc < Mutex < SharedData > > ,
160
201
viewer_space : Space ,
@@ -167,6 +208,8 @@ struct OpenXrDevice {
167
208
right_hand : OpenXRInput ,
168
209
left_hand : OpenXRInput ,
169
210
granted_features : Vec < String > ,
211
+ context_menu_provider : Box < dyn ContextMenuProvider > ,
212
+ context_menu_future : Option < Box < dyn ContextMenuFuture > > ,
170
213
}
171
214
172
215
/// Data that is shared between the openxr thread and the
@@ -368,6 +411,7 @@ impl OpenXrDevice {
368
411
instance : Instance ,
369
412
granted_features : Vec < String > ,
370
413
id : SessionId ,
414
+ context_menu_provider : Box < dyn ContextMenuProvider > ,
371
415
) -> Result < OpenXrDevice , Error > {
372
416
let ( device_tx, device_rx) = crossbeam_channel:: unbounded ( ) ;
373
417
let ( provider_tx, provider_rx) = crossbeam_channel:: unbounded ( ) ;
@@ -538,6 +582,8 @@ impl OpenXrDevice {
538
582
right_hand,
539
583
left_hand,
540
584
granted_features,
585
+ context_menu_provider,
586
+ context_menu_future : None ,
541
587
} )
542
588
}
543
589
@@ -550,7 +596,8 @@ impl OpenXrDevice {
550
596
match event {
551
597
Some ( SessionStateChanged ( session_change) ) => match session_change. state ( ) {
552
598
openxr:: SessionState :: EXITING | openxr:: SessionState :: LOSS_PENDING => {
553
- break ;
599
+ self . events . callback ( Event :: SessionEnd ) ;
600
+ return false ;
554
601
}
555
602
openxr:: SessionState :: STOPPING => {
556
603
self . events
@@ -581,7 +628,8 @@ impl OpenXrDevice {
581
628
}
582
629
} ,
583
630
Some ( InstanceLossPending ( _) ) => {
584
- break ;
631
+ self . events . callback ( Event :: SessionEnd ) ;
632
+ return false ;
585
633
}
586
634
Some ( _) => {
587
635
// FIXME: Handle other events
@@ -657,6 +705,17 @@ impl DeviceAPI<Surface> for OpenXrDevice {
657
705
// Session is not running anymore.
658
706
return None ;
659
707
}
708
+ if let Some ( ref context_menu_future) = self . context_menu_future {
709
+ match context_menu_future. poll ( ) {
710
+ ContextMenuResult :: ExitSession => {
711
+ self . quit ( ) ;
712
+ return None ;
713
+ }
714
+ ContextMenuResult :: Dismissed => self . context_menu_future = None ,
715
+ ContextMenuResult :: Pending => ( ) ,
716
+ }
717
+ }
718
+
660
719
let mut data = self . shared_data . lock ( ) . unwrap ( ) ;
661
720
data. frame_state = self . frame_waiter . wait ( ) . expect ( "error waiting for frame" ) ;
662
721
let time_ns = time:: precise_time_ns ( ) ;
@@ -685,10 +744,10 @@ impl DeviceAPI<Surface> for OpenXrDevice {
685
744
686
745
self . session . sync_actions ( & [ active_action_set] ) . unwrap ( ) ;
687
746
688
- let ( right_input_frame, right_select, right_squeeze) =
747
+ let ( mut right_input_frame, mut right_select, mut right_squeeze, right_menu ) =
689
748
self . right_hand
690
749
. frame ( & self . session , & data. frame_state , & data. space ) ;
691
- let ( left_input_frame, left_select, left_squeeze) =
750
+ let ( mut left_input_frame, mut left_select, mut left_squeeze, left_menu ) =
692
751
self . left_hand
693
752
. frame ( & self . session , & data. frame_state , & data. space ) ;
694
753
@@ -701,6 +760,22 @@ impl DeviceAPI<Surface> for OpenXrDevice {
701
760
vec ! [ ]
702
761
} ;
703
762
763
+ if ( left_menu || right_menu) && self . context_menu_future . is_none ( ) {
764
+ self . context_menu_future = Some ( self . context_menu_provider . open_context_menu ( ) ) ;
765
+ }
766
+
767
+ // Do not surface input info whilst the context menu is open
768
+ if self . context_menu_future . is_some ( ) {
769
+ right_input_frame. target_ray_origin = None ;
770
+ right_input_frame. grip_origin = None ;
771
+ left_input_frame. target_ray_origin = None ;
772
+ left_input_frame. grip_origin = None ;
773
+ right_select = None ;
774
+ right_squeeze = None ;
775
+ left_select = None ;
776
+ left_squeeze = None ;
777
+ }
778
+
704
779
let frame = Frame {
705
780
transform,
706
781
inputs : vec ! [ right_input_frame, left_input_frame] ,
@@ -779,12 +854,33 @@ impl DeviceAPI<Surface> for OpenXrDevice {
779
854
780
855
fn quit ( & mut self ) {
781
856
self . session . request_exit ( ) . unwrap ( ) ;
857
+ loop {
858
+ let mut buffer = openxr:: EventDataBuffer :: new ( ) ;
859
+ let event = self . instance . poll_event ( & mut buffer) . unwrap ( ) ;
860
+ match event {
861
+ Some ( openxr:: Event :: SessionStateChanged ( session_change) ) => {
862
+ match session_change. state ( ) {
863
+ openxr:: SessionState :: EXITING => {
864
+ self . events . callback ( Event :: SessionEnd ) ;
865
+ break ;
866
+ }
867
+ openxr:: SessionState :: STOPPING => {
868
+ self . session
869
+ . end ( )
870
+ . expect ( "Session failed to end on STOPPING" ) ;
871
+ }
872
+ _ => ( ) ,
873
+ }
874
+ }
875
+ _ => ( ) ,
876
+ }
877
+ thread:: sleep ( Duration :: from_millis ( 30 ) ) ;
878
+ }
782
879
}
783
880
784
881
fn set_quitter ( & mut self , _: Quitter ) {
785
- // Glwindow currently doesn't have any way to end its own session
786
- // XXXManishearth add something for this that listens for the window
787
- // being closed
882
+ // the quitter is only needed if we have anything from outside the render
883
+ // thread that can signal a quit. We don't.
788
884
}
789
885
790
886
fn update_clip_planes ( & mut self , near : f32 , far : f32 ) {
0 commit comments