blob: 9a4923f5f0ce4f73e98a965c13a61a4273548815 [file] [log] [blame] [edit]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import <UIKit/UIKit.h>
#include "base/apple/foundation_util.h"
#include "base/check.h"
#include "base/notimplemented.h"
#include "base/task/single_thread_task_runner.h"
#include "build/ios_buildflags.h"
#include "ui/display/display.h"
#include "ui/display/display_features.h"
#include "ui/display/screen_base.h"
#include "ui/display/util/display_util.h"
#include "ui/gfx/native_ui_types.h"
namespace display {
namespace {
class ScreenNotification {
public:
virtual void ScreenChanged() = 0;
};
} // namespace
} // namespace display
@interface ScreenObserver : NSObject {
raw_ptr<display::ScreenNotification, DanglingUntriaged> _notifier;
}
- (void)mainScreenChanged;
@end
@implementation ScreenObserver
- (instancetype)initWithNotifier:(display::ScreenNotification*)notifier {
if ((self = [super init])) {
_notifier = notifier;
NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
#if !BUILDFLAG(IS_IOS_TVOS)
[defaultCenter addObserver:self
selector:@selector(mainScreenChanged)
name:UIDeviceOrientationDidChangeNotification
object:nil];
#endif
[defaultCenter addObserver:self
selector:@selector(mainScreenChanged)
name:UIWindowDidBecomeKeyNotification
object:nil];
}
return self;
}
- (void)mainScreenChanged {
if (!base::SingleThreadTaskRunner::HasCurrentDefault()) {
return;
}
// This notification comes before UIScreen can change its bounds so post a
// task so the update occurs after the UIScreen has been updated.
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(&display::ScreenNotification::ScreenChanged,
base::Unretained(_notifier)));
}
@end
namespace display {
namespace {
class ScreenIos : public ScreenBase, public ScreenNotification {
public:
ScreenIos() {
observer_ = [[ScreenObserver alloc] initWithNotifier:this];
ScreenChanged();
}
ScreenIos(const ScreenIos&) = delete;
ScreenIos& operator=(const ScreenIos&) = delete;
void ScreenChanged() override {
UIScreen* screen = GetAllActiveScreens().firstObject;
if (!screen) {
return;
}
const int64_t display_id = 0;
Display display(display_id, gfx::Rect(screen.bounds));
CGFloat scale = [screen scale];
if (Display::HasForceDeviceScaleFactor()) {
scale = Display::GetForcedDeviceScaleFactor();
}
display.set_device_scale_factor(scale);
#if !BUILDFLAG(IS_IOS_TVOS)
Display::Rotation rotation = Display::ROTATE_0;
switch (UIDevice.currentDevice.orientation) {
case UIDeviceOrientationPortrait:
case UIDeviceOrientationFaceUp:
case UIDeviceOrientationFaceDown:
case UIDeviceOrientationUnknown:
rotation = Display::ROTATE_0;
break;
case UIDeviceOrientationPortraitUpsideDown:
rotation = Display::ROTATE_180;
break;
case UIDeviceOrientationLandscapeLeft:
rotation = Display::ROTATE_90;
break;
case UIDeviceOrientationLandscapeRight:
rotation = Display::ROTATE_270;
break;
}
display.set_rotation(rotation);
display.set_touch_support(Display::TouchSupport::AVAILABLE);
display.set_accelerometer_support(Display::AccelerometerSupport::AVAILABLE);
AddInternalDisplayId(display_id);
#endif
ProcessDisplayChanged(display, true /* is_primary */);
}
gfx::Point GetCursorScreenPoint() override {
NOTIMPLEMENTED();
return gfx::Point(0, 0);
}
bool IsWindowUnderCursor(gfx::NativeWindow window) override {
NOTIMPLEMENTED();
return false;
}
gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) override {
NOTIMPLEMENTED();
return gfx::NativeWindow();
}
int GetNumDisplays() const override {
return std::max(static_cast<int>([GetAllActiveScreens() count]), 1);
}
private:
// Return all screens associated with scenes of the application.
NSArray<UIScreen*>* GetAllActiveScreens() const {
#if BUILDFLAG(IS_IOS_APP_EXTENSION)
return [NSArray<UIScreen*> array];
#else
NSMutableSet<UIScreen*>* screens = [NSMutableSet set];
for (UIScene* scene in UIApplication.sharedApplication.connectedScenes) {
UIWindowScene* windowScene =
base::apple::ObjCCastStrict<UIWindowScene>(scene);
UIScreen* screen = windowScene.keyWindow.screen;
if (screen) {
[screens addObject:screen];
}
}
return [screens allObjects];
#endif
}
ScreenObserver* __strong observer_;
};
} // namespace
// static
gfx::NativeWindow Screen::GetWindowForView(gfx::NativeView view) {
return gfx::NativeWindow(view.Get().window);
}
Screen* CreateNativeScreen() {
return new ScreenIos;
}
float GetInternalDisplayDeviceScaleFactor() {
#if BUILDFLAG(IS_IOS_APP_EXTENSION)
return 1.0f;
#else
for (UIScene* scene in UIApplication.sharedApplication.connectedScenes) {
UIWindowScene* windowScene =
base::apple::ObjCCastStrict<UIWindowScene>(scene);
UIScreen* screen = windowScene.keyWindow.screen;
if (screen) {
return [screen scale];
}
}
return 1.0f;
#endif
}
} // namespace display