diff options
Diffstat (limited to 'platform/macos/display_server_macos.mm')
-rw-r--r-- | platform/macos/display_server_macos.mm | 214 |
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; |