Implement basic windowing on Mac
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "MacPlatform.h"
|
||||
#include "MacWindow.h"
|
||||
#include "MacUtils.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Types/Guid.h"
|
||||
#include "Engine/Core/Types/String.h"
|
||||
@@ -41,6 +42,7 @@
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
#include <SystemConfiguration/SystemConfiguration.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include <dlfcn.h>
|
||||
#if CRASH_LOG_ENABLE
|
||||
#include <execinfo.h>
|
||||
@@ -50,8 +52,9 @@ CPUInfo MacCpu;
|
||||
Guid DeviceId;
|
||||
String UserLocale, ComputerName;
|
||||
double SecondsPerCycle;
|
||||
NSAutoreleasePool* AutoreleasePool = nullptr;
|
||||
|
||||
String ToString(CFStringRef str)
|
||||
String MacUtils::ToString(CFStringRef str)
|
||||
{
|
||||
String result;
|
||||
const int32 length = CFStringGetLength(str);
|
||||
@@ -64,17 +67,42 @@ String ToString(CFStringRef str)
|
||||
return result;
|
||||
}
|
||||
|
||||
CFStringRef ToString(const String& str)
|
||||
CFStringRef MacUtils::ToString(const String& str)
|
||||
{
|
||||
return CFStringCreateWithBytes(nullptr, (const UInt8*)str.Get(), str.Length() * sizeof(Char), kCFStringEncodingUTF16LE, false);
|
||||
}
|
||||
|
||||
Vector2 MacUtils::PosToCoca(const Vector2& pos)
|
||||
{
|
||||
// MacOS uses y-coordinate starting at the bottom of the screen
|
||||
Vector2 result = pos;
|
||||
result.Y *= -1;
|
||||
result += GetScreensOrigin();
|
||||
return result;
|
||||
}
|
||||
|
||||
Vector2 MacUtils::GetScreensOrigin()
|
||||
{
|
||||
Vector2 result = Vector2::Zero;
|
||||
NSArray* screenArray = [NSScreen screens];
|
||||
for (NSUInteger i = 0; i < [screenArray count]; i++)
|
||||
{
|
||||
NSRect rect = [[screenArray objectAtIndex:i] frame];
|
||||
Vector2 pos(rect.origin.x, rect.origin.y + rect.size.height);
|
||||
if (pos.X < result.X)
|
||||
result.X = pos.X;
|
||||
if (pos.Y > result.Y)
|
||||
result.Y = pos.Y;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
DialogResult MessageBox::Show(Window* parent, const StringView& text, const StringView& caption, MessageBoxButtons buttons, MessageBoxIcon icon)
|
||||
{
|
||||
if (CommandLine::Options.Headless)
|
||||
return DialogResult::None;
|
||||
CFStringRef textRef = ToString(text);
|
||||
CFStringRef captionRef = ToString(caption);
|
||||
CFStringRef textRef = MacUtils::ToString(text);
|
||||
CFStringRef captionRef = MacUtils::ToString(caption);
|
||||
CFOptionFlags flags = 0;
|
||||
switch (buttons)
|
||||
{
|
||||
@@ -309,7 +337,7 @@ bool MacPlatform::Init()
|
||||
io_registry_entry_t ioRegistryRoot = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/");
|
||||
CFStringRef deviceUuid = (CFStringRef)IORegistryEntryCreateCFProperty(ioRegistryRoot, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0);
|
||||
IOObjectRelease(ioRegistryRoot);
|
||||
String uuidStr = ToString(deviceUuid);
|
||||
String uuidStr = MacUtils::ToString(deviceUuid);
|
||||
Guid::Parse(uuidStr, DeviceId);
|
||||
CFRelease(deviceUuid);
|
||||
}
|
||||
@@ -319,8 +347,8 @@ bool MacPlatform::Init()
|
||||
CFLocaleRef locale = CFLocaleCopyCurrent();
|
||||
CFStringRef localeLang = (CFStringRef)CFLocaleGetValue(locale, kCFLocaleLanguageCode);
|
||||
CFStringRef localeCountry = (CFStringRef)CFLocaleGetValue(locale, kCFLocaleCountryCode);
|
||||
UserLocale = ToString(localeLang);
|
||||
String localeCountryStr = ToString(localeCountry);
|
||||
UserLocale = MacUtils::ToString(localeLang);
|
||||
String localeCountryStr = MacUtils::ToString(localeCountry);
|
||||
if (localeCountryStr.HasChars())
|
||||
UserLocale += TEXT("-") + localeCountryStr;
|
||||
CFRelease(locale);
|
||||
@@ -331,7 +359,7 @@ bool MacPlatform::Init()
|
||||
// Get computer name
|
||||
{
|
||||
CFStringRef computerName = SCDynamicStoreCopyComputerName(nullptr, nullptr);
|
||||
ComputerName = ToString(computerName);
|
||||
ComputerName = MacUtils::ToString(computerName);
|
||||
CFRelease(computerName);
|
||||
}
|
||||
|
||||
@@ -342,6 +370,13 @@ bool MacPlatform::Init()
|
||||
OnPlatformUserAdd(New<User>(username));
|
||||
}
|
||||
|
||||
// Init application
|
||||
[NSApplication sharedApplication];
|
||||
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
||||
NSMenu* mainMenu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
|
||||
[NSApp setMainMenu:mainMenu];
|
||||
AutoreleasePool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
Input::Mouse = New<MacMouse>();
|
||||
Input::Keyboard = New<MacKeyboard>();
|
||||
|
||||
@@ -365,10 +400,22 @@ void MacPlatform::LogInfo()
|
||||
|
||||
void MacPlatform::BeforeRun()
|
||||
{
|
||||
[NSApp finishLaunching];
|
||||
}
|
||||
|
||||
void MacPlatform::Tick()
|
||||
{
|
||||
// Process system events
|
||||
while (true)
|
||||
{
|
||||
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES];
|
||||
if (event == nil)
|
||||
break;
|
||||
[NSApp sendEvent:event];
|
||||
}
|
||||
|
||||
[AutoreleasePool drain];
|
||||
AutoreleasePool = [[NSAutoreleasePool alloc] init];
|
||||
}
|
||||
|
||||
void MacPlatform::BeforeExit()
|
||||
|
||||
15
Source/Engine/Platform/Mac/MacUtils.h
Normal file
15
Source/Engine/Platform/Mac/MacUtils.h
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Types/String.h"
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
class FLAXENGINE_API MacUtils
|
||||
{
|
||||
public:
|
||||
static String ToString(CFStringRef str);
|
||||
static CFStringRef ToString(const String& str);
|
||||
static Vector2 PosToCoca(const Vector2& pos);
|
||||
static Vector2 GetScreensOrigin();
|
||||
};
|
||||
@@ -3,31 +3,94 @@
|
||||
#if PLATFORM_MAC
|
||||
|
||||
#include "../Window.h"
|
||||
#include "MacUtils.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
#include <Cocoa/Cocoa.h>
|
||||
|
||||
@interface MacWindowImpl : NSWindow <NSWindowDelegate>
|
||||
{
|
||||
MacWindow* Window;
|
||||
}
|
||||
|
||||
- (void)setWindow:(MacWindow*)window;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MacWindowImpl
|
||||
|
||||
- (void)windowWillClose:(NSNotification*)notification
|
||||
{
|
||||
[self setDelegate: nil];
|
||||
Window->Close(ClosingReason::User);
|
||||
}
|
||||
|
||||
- (void)setWindow:(MacWindow*)window
|
||||
{
|
||||
Window = window;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
MacWindow::MacWindow(const CreateWindowSettings& settings)
|
||||
: WindowBase(settings)
|
||||
{
|
||||
int32 x = Math::TruncToInt(settings.Position.X);
|
||||
int32 y = Math::TruncToInt(settings.Position.Y);
|
||||
int32 clientWidth = Math::TruncToInt(settings.Size.X);
|
||||
int32 clientHeight = Math::TruncToInt(settings.Size.Y);
|
||||
int32 windowWidth = clientWidth;
|
||||
int32 windowHeight = clientHeight;
|
||||
_clientSize = Vector2((float)clientWidth, (float)clientHeight);
|
||||
_clientSize = Vector2(settings.Size.X, settings.Size.Y);
|
||||
Vector2 pos = MacUtils::PosToCoca(settings.Position);
|
||||
NSRect frame = NSMakeRect(pos.X, pos.Y - settings.Size.Y, settings.Size.X, settings.Size.Y);
|
||||
NSUInteger styleMask = NSWindowStyleMaskClosable;
|
||||
if (settings.IsRegularWindow)
|
||||
{
|
||||
styleMask |= NSWindowStyleMaskTitled | NSWindowStyleMaskFullSizeContentView;
|
||||
if (settings.AllowMinimize)
|
||||
styleMask |= NSWindowStyleMaskMiniaturizable;
|
||||
if (settings.HasSizingFrame || settings.AllowMaximize)
|
||||
styleMask |= NSWindowStyleMaskResizable;
|
||||
}
|
||||
else
|
||||
{
|
||||
styleMask |= NSWindowStyleMaskBorderless;
|
||||
}
|
||||
if (settings.HasBorder)
|
||||
{
|
||||
styleMask |= NSWindowStyleMaskTitled;
|
||||
styleMask &= ~NSWindowStyleMaskFullSizeContentView;
|
||||
}
|
||||
|
||||
// TODO: setup window
|
||||
MacWindowImpl* window = [[MacWindowImpl alloc] initWithContentRect:frame
|
||||
styleMask:(styleMask)
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:NO];
|
||||
window.title = (__bridge NSString*)MacUtils::ToString(settings.Title);
|
||||
[window setWindow:this];
|
||||
[window setReleasedWhenClosed:NO];
|
||||
[window setBackgroundColor:[NSColor blueColor]];
|
||||
[window setMinSize:NSMakeSize(settings.MinimumSize.X, settings.MinimumSize.Y)];
|
||||
[window setMaxSize:NSMakeSize(settings.MaximumSize.X, settings.MaximumSize.Y)];
|
||||
[window setOpaque:!settings.SupportsTransparency];
|
||||
[window setDelegate:window];
|
||||
_window = window;
|
||||
|
||||
// TODO: impl Parent for MacWindow
|
||||
// TODO: impl StartPosition for MacWindow
|
||||
// TODO: impl Fullscreen for MacWindow
|
||||
// TODO: impl ShowInTaskbar for MacWindow
|
||||
// TODO: impl ActivateWhenFirstShown for MacWindow
|
||||
// TODO: impl AllowInput for MacWindow
|
||||
// TODO: impl AllowDragAndDrop for MacWindow
|
||||
// TODO: impl IsTopmost for MacWindow
|
||||
}
|
||||
|
||||
MacWindow::~MacWindow()
|
||||
{
|
||||
// TODO: close window
|
||||
NSWindow* window = (NSWindow*)_window;
|
||||
[window close];
|
||||
[window release];
|
||||
_window = nullptr;
|
||||
}
|
||||
|
||||
void* MacWindow::GetNativePtr() const
|
||||
{
|
||||
// TODO: return window handle
|
||||
return nullptr;
|
||||
return _window;
|
||||
}
|
||||
|
||||
void MacWindow::Show()
|
||||
@@ -43,7 +106,10 @@ void MacWindow::Show()
|
||||
}
|
||||
|
||||
// Show
|
||||
// TODO: show window
|
||||
NSWindow* window = (NSWindow*)_window;
|
||||
[window makeKeyAndOrderFront:window];
|
||||
if (_settings.ActivateWhenFirstShown)
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
_focused = true;
|
||||
|
||||
// Base
|
||||
@@ -56,7 +122,8 @@ void MacWindow::Hide()
|
||||
if (_visible)
|
||||
{
|
||||
// Hide
|
||||
// TODO: hide window
|
||||
NSWindow* window = (NSWindow*)_window;
|
||||
[window orderOut:nil];
|
||||
|
||||
// Base
|
||||
WindowBase::Hide();
|
||||
@@ -65,22 +132,34 @@ void MacWindow::Hide()
|
||||
|
||||
void MacWindow::Minimize()
|
||||
{
|
||||
// TODO: Minimize
|
||||
if (!_settings.AllowMinimize)
|
||||
return;
|
||||
NSWindow* window = (NSWindow*)_window;
|
||||
if (!window.miniaturized)
|
||||
[window miniaturize:nil];
|
||||
}
|
||||
|
||||
void MacWindow::Maximize()
|
||||
{
|
||||
// TODO: Maximize
|
||||
if (!_settings.AllowMaximize)
|
||||
return;
|
||||
NSWindow* window = (NSWindow*)_window;
|
||||
if (!window.zoomed)
|
||||
[window zoom:nil];
|
||||
}
|
||||
|
||||
void MacWindow::Restore()
|
||||
{
|
||||
// TODO: Restore
|
||||
NSWindow* window = (NSWindow*)_window;
|
||||
if (window.miniaturized)
|
||||
[window deminiaturize:nil];
|
||||
else if (window.zoomed)
|
||||
[window zoom:nil];
|
||||
}
|
||||
|
||||
bool MacWindow::IsClosed() const
|
||||
{
|
||||
return false;
|
||||
return _window != nullptr;
|
||||
}
|
||||
|
||||
bool MacWindow::IsForegroundWindow() const
|
||||
@@ -88,8 +167,34 @@ bool MacWindow::IsForegroundWindow() const
|
||||
return Platform::GetHasFocus();
|
||||
}
|
||||
|
||||
void MacWindow::BringToFront(bool force)
|
||||
{
|
||||
NSWindow* window = (NSWindow*)_window;
|
||||
[window activateIgnoringOtherApps:force];
|
||||
}
|
||||
|
||||
void MacWindow::SetIsFullscreen(bool isFullscreen)
|
||||
{
|
||||
// TODO: fullscreen mode on Mac
|
||||
}
|
||||
|
||||
void MacWindow::SetOpacity(float opacity)
|
||||
{
|
||||
NSWindow* window = (NSWindow*)_window;
|
||||
[window setAlphaValue:opacity];
|
||||
}
|
||||
|
||||
void MacWindow::Focus()
|
||||
{
|
||||
NSWindow* window = (NSWindow*)_window;
|
||||
[window makeKeyAndOrderFront:window];
|
||||
}
|
||||
|
||||
void MacWindow::SetTitle(const StringView& title)
|
||||
{
|
||||
_title = title;
|
||||
NSWindow* window = (NSWindow*)_window;
|
||||
[window setTitle:(__bridge NSString*)MacUtils::ToString(_title)];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -15,6 +15,7 @@ class MacWindow : public WindowBase
|
||||
private:
|
||||
|
||||
Vector2 _clientSize;
|
||||
void* _window;
|
||||
|
||||
public:
|
||||
|
||||
@@ -32,7 +33,11 @@ public:
|
||||
void Restore() override;
|
||||
bool IsClosed() const override;
|
||||
bool IsForegroundWindow() const override;
|
||||
void BringToFront(bool force) override;
|
||||
void SetIsFullscreen(bool isFullscreen) override;
|
||||
void SetOpacity(float opacity) override;
|
||||
void Focus() override;
|
||||
void SetTitle(const StringView& title) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user