mirror of
https://github.com/touchHLE/touchHLE.git
synced 2026-01-31 01:25:24 +01:00
Support rendering and touch input for multiple windows
Change-Id: Ib4beb44f810247bee941edd0d757048527eb2304
This commit is contained in:
@@ -62,19 +62,11 @@ unsafe fn load_matrix(gles: &mut dyn GLES, matrix: Matrix<4>) {
|
||||
///
|
||||
/// Returns the time a recomposite is due, if any.
|
||||
pub fn recomposite_if_necessary(env: &mut Environment, force: bool) -> Option<Instant> {
|
||||
// Assumes the windows in the list are ordered back-to-front.
|
||||
// TODO: this is not correct once we support windowLevel.
|
||||
// FIXME: There can be windows smaller than the screen! We should draw all
|
||||
// of them!
|
||||
let windows = env.framework_state.uikit.ui_view.ui_window.windows.clone();
|
||||
let Some(top_window) = windows
|
||||
.into_iter()
|
||||
.rev()
|
||||
.find(|&window| !msg![env; window isHidden])
|
||||
else {
|
||||
log_dbg!("No visible window, skipping composition");
|
||||
if !windows.iter().any(|&window| !msg![env; window isHidden]) {
|
||||
log_dbg!("No visible windows, skipping composition");
|
||||
return None;
|
||||
};
|
||||
}
|
||||
|
||||
if find_fullscreen_eagl_layer(env) != nil {
|
||||
// No composition done, EAGLContext will present directly.
|
||||
@@ -126,10 +118,15 @@ pub fn recomposite_if_necessary(env: &mut Environment, force: bool) -> Option<In
|
||||
.composition
|
||||
.recomposite_next = new_recomposite_next;
|
||||
|
||||
let root_layer: id = msg![env; top_window layer];
|
||||
|
||||
// Ensure layer bitmaps are up to date.
|
||||
display_layers(env, root_layer);
|
||||
let window_layers: Vec<id> = windows
|
||||
.into_iter()
|
||||
.map(|window| {
|
||||
let layer: id = msg![env; window layer];
|
||||
// Ensure layer bitmaps are up to date.
|
||||
display_layers(env, layer);
|
||||
layer
|
||||
})
|
||||
.collect();
|
||||
|
||||
let screen_bounds: CGRect = {
|
||||
let screen: id = msg_class![env; UIScreen mainScreen];
|
||||
@@ -325,17 +322,21 @@ pub fn recomposite_if_necessary(env: &mut Environment, force: bool) -> Option<In
|
||||
gles.BindBuffer(gles11::ELEMENT_ARRAY_BUFFER, misc_gl_objects.index_buffer);
|
||||
}
|
||||
|
||||
// Here's where the actual drawing happens
|
||||
unsafe {
|
||||
composite_layer_recursive(
|
||||
gles,
|
||||
&mut env.objc,
|
||||
&env.mem,
|
||||
misc_gl_objects,
|
||||
root_layer,
|
||||
cumulative_transform,
|
||||
opacity,
|
||||
);
|
||||
// Assumes the windows in the list are ordered back-to-front.
|
||||
// TODO: this may not be correct once we support windowLevel.
|
||||
for root_layer in window_layers {
|
||||
// Here's where the actual drawing happens
|
||||
unsafe {
|
||||
composite_layer_recursive(
|
||||
gles,
|
||||
&mut env.objc,
|
||||
&env.mem,
|
||||
misc_gl_objects,
|
||||
root_layer,
|
||||
cumulative_transform,
|
||||
opacity,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up some GL state
|
||||
|
||||
@@ -124,18 +124,6 @@ pub fn handle_event(env: &mut Environment, event: Event) {
|
||||
}
|
||||
|
||||
fn handle_touches_down(env: &mut Environment, map: HashMap<FingerId, Coords>) {
|
||||
// Assumes the last window in the list is the one on top and that it
|
||||
// covers the whole screen. FIXME!
|
||||
let windows = env.framework_state.uikit.ui_view.ui_window.windows.clone();
|
||||
let Some(top_window) = windows
|
||||
.into_iter()
|
||||
.rev()
|
||||
.find(|&window| !msg![env; window isHidden])
|
||||
else {
|
||||
log!("No visible window, touch events ignored");
|
||||
return;
|
||||
};
|
||||
|
||||
// UIKit creates and drains autorelease pools when handling events.
|
||||
let pool: id = msg_class![env; NSAutoreleasePool new];
|
||||
|
||||
@@ -229,16 +217,31 @@ fn handle_touches_down(env: &mut Environment, map: HashMap<FingerId, Coords>) {
|
||||
let touch: id = msg![env; touches_arr objectAtIndex:i];
|
||||
let &UITouchHostObject { location, .. } = env.objc.borrow(touch);
|
||||
|
||||
// FIXME: handle possibly overlapping windows in hit testing.
|
||||
// Assumes the windows in the list are ordered back-to-front.
|
||||
// TODO: this may not be correct once we support windowLevel.
|
||||
let windows = env.framework_state.uikit.ui_view.ui_window.windows.clone();
|
||||
let Some((window, location_in_window)) = windows.into_iter().rev().find_map(|window| {
|
||||
let location_in_window: CGPoint =
|
||||
msg![env; window convertPoint:location fromWindow:nil];
|
||||
if msg![env; window pointInside:location_in_window withEvent:event] {
|
||||
Some((window, location_in_window))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) else {
|
||||
log!(
|
||||
"Couldn't find a window for touch at {:?}, discarding",
|
||||
location,
|
||||
);
|
||||
continue;
|
||||
};
|
||||
|
||||
let location_in_window: CGPoint =
|
||||
msg![env; top_window convertPoint:location fromWindow:nil];
|
||||
let view: id = msg![env; top_window hitTest:location_in_window withEvent:event];
|
||||
let view: id = msg![env; window hitTest:location_in_window withEvent:event];
|
||||
if view == nil {
|
||||
log!(
|
||||
"Couldn't find a view for touch at {:?} in window {:?}, discarding",
|
||||
location_in_window,
|
||||
top_window,
|
||||
window,
|
||||
);
|
||||
continue;
|
||||
} else {
|
||||
@@ -250,7 +253,7 @@ fn handle_touches_down(env: &mut Environment, map: HashMap<FingerId, Coords>) {
|
||||
f
|
||||
},
|
||||
location_in_window,
|
||||
top_window,
|
||||
window,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -291,11 +294,11 @@ fn handle_touches_down(env: &mut Environment, map: HashMap<FingerId, Coords>) {
|
||||
let _: () = msg![env; touches addObject:touch];
|
||||
|
||||
retain(env, view);
|
||||
retain(env, top_window);
|
||||
retain(env, window);
|
||||
{
|
||||
let new_touch = env.objc.borrow_mut::<UITouchHostObject>(touch);
|
||||
new_touch.view = view;
|
||||
new_touch.window = top_window;
|
||||
new_touch.window = window;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
UIView *ball;
|
||||
CGFloat ballXVelocity;
|
||||
CGFloat ballYVelocity;
|
||||
UIWindow *window2;
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
[super initWithFrame:frame];
|
||||
@@ -37,14 +38,23 @@ CGFloat ballYVelocity;
|
||||
[button1 addTarget:self
|
||||
action:@selector(goToCALayerTests)
|
||||
forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
[self addSubview:button1];
|
||||
|
||||
UIButton *button2 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
|
||||
[button2 setTitle:[NSString stringWithUTF8String:"Window 2"]
|
||||
forState:UIControlStateNormal];
|
||||
[button2 setFrame:CGRectMake(40, 140, 240, 40)];
|
||||
[button2 addTarget:self
|
||||
action:@selector(toggleWindow)
|
||||
forControlEvents:UIControlEventTouchUpInside];
|
||||
[self addSubview:button2];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[ball release];
|
||||
[window2 release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -84,4 +94,12 @@ CGFloat ballYVelocity;
|
||||
initWithFrame:[self frame]] autorelease]];
|
||||
}
|
||||
|
||||
- (void)toggleWindow {
|
||||
if (!window2) {
|
||||
window2 = [[UIWindow alloc] initWithFrame:CGRectMake(80, 0, 80, 80)];
|
||||
window2.backgroundColor = [UIColor magentaColor];
|
||||
}
|
||||
[window2 setHidden:![window2 isHidden]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -263,6 +263,8 @@ typedef enum {
|
||||
- (void)setBackgroundColor:(UIColor *)color;
|
||||
- (CGFloat)alpha;
|
||||
- (void)setAlpha:(CGFloat)alpha;
|
||||
- (BOOL)isHidden;
|
||||
- (void)setHidden:(BOOL)hidden;
|
||||
@end
|
||||
@interface UIWindow : UIView
|
||||
- (void)makeKeyAndVisible;
|
||||
|
||||
Reference in New Issue
Block a user