summaryrefslogtreecommitdiffstats
path: root/platform/macos/display_server_macos.mm
diff options
context:
space:
mode:
Diffstat (limited to 'platform/macos/display_server_macos.mm')
-rw-r--r--platform/macos/display_server_macos.mm214
1 files changed, 209 insertions, 5 deletions
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index 7bcb6df18d..ce4c7b2e05 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -35,6 +35,7 @@
#include "godot_menu_delegate.h"
#include "godot_menu_item.h"
#include "godot_open_save_delegate.h"
+#include "godot_status_item.h"
#include "godot_window.h"
#include "godot_window_delegate.h"
#include "key_mapping_macos.h"
@@ -203,7 +204,7 @@ DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mod
} wpd;
#ifdef VULKAN_ENABLED
if (rendering_driver == "vulkan") {
- wpd.vulkan.view_ptr = &wd.window_view;
+ wpd.vulkan.layer_ptr = (CAMetalLayer *const *)&layer;
}
#endif
Error err = rendering_context->window_create(window_id_counter, &wpd);
@@ -698,10 +699,12 @@ DisplayServerMacOS::WindowData &DisplayServerMacOS::get_window(WindowID p_window
}
void DisplayServerMacOS::send_event(NSEvent *p_event) {
- // Special case handling of command-period, which is traditionally a special
- // shortcut in macOS and doesn't arrive at our regular keyDown handler.
+ // Special case handling of shortcuts that don't arrive at the regular keyDown handler
if ([p_event type] == NSEventTypeKeyDown) {
- if ((([p_event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask) == NSEventModifierFlagCommand) && [p_event keyCode] == 0x2f) {
+ NSEventModifierFlags flags = [p_event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
+
+ // Command-period
+ if ((flags == NSEventModifierFlagCommand) && [p_event keyCode] == 0x2f) {
Ref<InputEventKey> k;
k.instantiate();
@@ -714,6 +717,24 @@ void DisplayServerMacOS::send_event(NSEvent *p_event) {
k->set_echo([p_event isARepeat]);
Input::get_singleton()->parse_input_event(k);
+ return;
+ }
+
+ // Ctrl+Tab and Ctrl+Shift+Tab
+ if (((flags == NSEventModifierFlagControl) || (flags == (NSEventModifierFlagControl | NSEventModifierFlagShift))) && [p_event keyCode] == 0x30) {
+ Ref<InputEventKey> k;
+ k.instantiate();
+
+ get_key_modifier_state([p_event modifierFlags], k);
+ k->set_window_id(DisplayServerMacOS::INVALID_WINDOW_ID);
+ k->set_pressed(true);
+ k->set_keycode(Key::TAB);
+ k->set_physical_keycode(Key::TAB);
+ k->set_key_label(Key::TAB);
+ k->set_echo([p_event isARepeat]);
+
+ Input::get_singleton()->parse_input_event(k);
+ return;
}
}
}
@@ -838,6 +859,8 @@ bool DisplayServerMacOS::has_feature(Feature p_feature) const {
case FEATURE_TEXT_TO_SPEECH:
case FEATURE_EXTEND_TO_TITLE:
case FEATURE_SCREEN_CAPTURE:
+ case FEATURE_STATUS_INDICATOR:
+ case FEATURE_NATIVE_HELP:
return true;
default: {
}
@@ -849,6 +872,19 @@ String DisplayServerMacOS::get_name() const {
return "macOS";
}
+void DisplayServerMacOS::help_set_search_callbacks(const Callable &p_search_callback, const Callable &p_action_callback) {
+ help_search_callback = p_search_callback;
+ help_action_callback = p_action_callback;
+}
+
+Callable DisplayServerMacOS::_help_get_search_callback() const {
+ return help_search_callback;
+}
+
+Callable DisplayServerMacOS::_help_get_action_callback() const {
+ return help_action_callback;
+}
+
bool DisplayServerMacOS::_is_menu_opened(NSMenu *p_menu) const {
if (submenu_inv.has(p_menu)) {
const MenuData &md = submenu[submenu_inv[p_menu]];
@@ -2035,7 +2071,17 @@ bool DisplayServerMacOS::is_dark_mode() const {
Color DisplayServerMacOS::get_accent_color() const {
if (@available(macOS 10.14, *)) {
- NSColor *color = [[NSColor controlAccentColor] colorUsingColorSpace:[NSColorSpace genericRGBColorSpace]];
+ __block NSColor *color = nullptr;
+ if (@available(macOS 11.0, *)) {
+ [NSApp.effectiveAppearance performAsCurrentDrawingAppearance:^{
+ color = [[NSColor controlAccentColor] colorUsingColorSpace:[NSColorSpace genericRGBColorSpace]];
+ }];
+ } else {
+ NSAppearance *saved_appearance = [NSAppearance currentAppearance];
+ [NSAppearance setCurrentAppearance:[NSApp effectiveAppearance]];
+ color = [[NSColor controlAccentColor] colorUsingColorSpace:[NSColorSpace genericRGBColorSpace]];
+ [NSAppearance setCurrentAppearance:saved_appearance];
+ }
if (color) {
CGFloat components[4];
[color getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]];
@@ -2048,6 +2094,41 @@ Color DisplayServerMacOS::get_accent_color() const {
}
}
+Color DisplayServerMacOS::get_base_color() const {
+ if (@available(macOS 10.14, *)) {
+ __block NSColor *color = nullptr;
+ if (@available(macOS 11.0, *)) {
+ [NSApp.effectiveAppearance performAsCurrentDrawingAppearance:^{
+ color = [[NSColor controlColor] colorUsingColorSpace:[NSColorSpace genericRGBColorSpace]];
+ }];
+ } else {
+ NSAppearance *saved_appearance = [NSAppearance currentAppearance];
+ [NSAppearance setCurrentAppearance:[NSApp effectiveAppearance]];
+ color = [[NSColor controlColor] colorUsingColorSpace:[NSColorSpace genericRGBColorSpace]];
+ [NSAppearance setCurrentAppearance:saved_appearance];
+ }
+ if (color) {
+ CGFloat components[4];
+ [color getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]];
+ return Color(components[0], components[1], components[2], components[3]);
+ } else {
+ return Color(0, 0, 0, 0);
+ }
+ } else {
+ return Color(0, 0, 0, 0);
+ }
+}
+
+void DisplayServerMacOS::set_system_theme_change_callback(const Callable &p_callable) {
+ system_theme_changed = p_callable;
+}
+
+void DisplayServerMacOS::emit_system_theme_changed() {
+ if (system_theme_changed.is_valid()) {
+ system_theme_changed.call();
+ }
+}
+
Error DisplayServerMacOS::dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) {
_THREAD_SAFE_METHOD_
@@ -4301,6 +4382,124 @@ void DisplayServerMacOS::set_icon(const Ref<Image> &p_icon) {
}
}
+DisplayServer::IndicatorID DisplayServerMacOS::create_status_indicator(const Ref<Image> &p_icon, const String &p_tooltip, const Callable &p_callback) {
+ NSImage *nsimg = nullptr;
+ if (p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0) {
+ Ref<Image> img = p_icon->duplicate();
+ img->convert(Image::FORMAT_RGBA8);
+
+ NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc]
+ initWithBitmapDataPlanes:nullptr
+ pixelsWide:img->get_width()
+ pixelsHigh:img->get_height()
+ bitsPerSample:8
+ samplesPerPixel:4
+ hasAlpha:YES
+ isPlanar:NO
+ colorSpaceName:NSDeviceRGBColorSpace
+ bytesPerRow:img->get_width() * 4
+ bitsPerPixel:32];
+ if (imgrep) {
+ uint8_t *pixels = [imgrep bitmapData];
+
+ int len = img->get_width() * img->get_height();
+ const uint8_t *r = img->get_data().ptr();
+
+ /* Premultiply the alpha channel */
+ for (int i = 0; i < len; i++) {
+ uint8_t alpha = r[i * 4 + 3];
+ pixels[i * 4 + 0] = (uint8_t)(((uint16_t)r[i * 4 + 0] * alpha) / 255);
+ pixels[i * 4 + 1] = (uint8_t)(((uint16_t)r[i * 4 + 1] * alpha) / 255);
+ pixels[i * 4 + 2] = (uint8_t)(((uint16_t)r[i * 4 + 2] * alpha) / 255);
+ pixels[i * 4 + 3] = alpha;
+ }
+
+ nsimg = [[NSImage alloc] initWithSize:NSMakeSize(img->get_width(), img->get_height())];
+ if (nsimg) {
+ [nsimg addRepresentation:imgrep];
+ }
+ }
+ }
+
+ IndicatorData idat;
+
+ idat.item = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength];
+ idat.view = [[GodotStatusItemView alloc] init];
+
+ [idat.view setToolTip:[NSString stringWithUTF8String:p_tooltip.utf8().get_data()]];
+ [idat.view setImage:nsimg];
+ [idat.view setCallback:p_callback];
+ [idat.item setView:idat.view];
+
+ IndicatorID iid = indicator_id_counter++;
+ indicators[iid] = idat;
+
+ return iid;
+}
+
+void DisplayServerMacOS::status_indicator_set_icon(IndicatorID p_id, const Ref<Image> &p_icon) {
+ ERR_FAIL_COND(!indicators.has(p_id));
+
+ NSImage *nsimg = nullptr;
+ if (p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0) {
+ Ref<Image> img = p_icon->duplicate();
+ img->convert(Image::FORMAT_RGBA8);
+
+ NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc]
+ initWithBitmapDataPlanes:nullptr
+ pixelsWide:img->get_width()
+ pixelsHigh:img->get_height()
+ bitsPerSample:8
+ samplesPerPixel:4
+ hasAlpha:YES
+ isPlanar:NO
+ colorSpaceName:NSDeviceRGBColorSpace
+ bytesPerRow:img->get_width() * 4
+ bitsPerPixel:32];
+ if (imgrep) {
+ uint8_t *pixels = [imgrep bitmapData];
+
+ int len = img->get_width() * img->get_height();
+ const uint8_t *r = img->get_data().ptr();
+
+ /* Premultiply the alpha channel */
+ for (int i = 0; i < len; i++) {
+ uint8_t alpha = r[i * 4 + 3];
+ pixels[i * 4 + 0] = (uint8_t)(((uint16_t)r[i * 4 + 0] * alpha) / 255);
+ pixels[i * 4 + 1] = (uint8_t)(((uint16_t)r[i * 4 + 1] * alpha) / 255);
+ pixels[i * 4 + 2] = (uint8_t)(((uint16_t)r[i * 4 + 2] * alpha) / 255);
+ pixels[i * 4 + 3] = alpha;
+ }
+
+ nsimg = [[NSImage alloc] initWithSize:NSMakeSize(img->get_width(), img->get_height())];
+ if (nsimg) {
+ [nsimg addRepresentation:imgrep];
+ }
+ }
+ }
+
+ [indicators[p_id].view setImage:nsimg];
+}
+
+void DisplayServerMacOS::status_indicator_set_tooltip(IndicatorID p_id, const String &p_tooltip) {
+ ERR_FAIL_COND(!indicators.has(p_id));
+
+ [indicators[p_id].view setToolTip:[NSString stringWithUTF8String:p_tooltip.utf8().get_data()]];
+}
+
+void DisplayServerMacOS::status_indicator_set_callback(IndicatorID p_id, const Callable &p_callback) {
+ ERR_FAIL_COND(!indicators.has(p_id));
+
+ [indicators[p_id].view setCallback:p_callback];
+}
+
+void DisplayServerMacOS::delete_status_indicator(IndicatorID p_id) {
+ ERR_FAIL_COND(!indicators.has(p_id));
+
+ [[NSStatusBar systemStatusBar] removeStatusItem:indicators[p_id].item];
+ indicators.erase(p_id);
+}
+
DisplayServer *DisplayServerMacOS::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) {
DisplayServer *ds = memnew(DisplayServerMacOS(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, r_error));
if (r_error != OK) {
@@ -4705,6 +4904,11 @@ DisplayServerMacOS::~DisplayServerMacOS() {
screen_keep_on_assertion = kIOPMNullAssertionID;
}
+ // Destroy all status indicators.
+ for (HashMap<IndicatorID, IndicatorData>::Iterator E = indicators.begin(); E;) {
+ [[NSStatusBar systemStatusBar] removeStatusItem:E->value.item];
+ }
+
// Destroy all windows.
for (HashMap<WindowID, WindowData>::Iterator E = windows.begin(); E;) {
HashMap<WindowID, WindowData>::Iterator F = E;