// This file is part of Desktop App Toolkit, // a set of libraries for developing nice desktop applications. // // For license and copyright information please follow this link: // https://github.com/desktop-app/legal/blob/master/LEGAL // #include "ui/platform/mac/ui_utility_mac.h" #include "ui/integration.h" #include #include #include #include #ifndef OS_MAC_STORE extern "C" { void _dispatch_main_queue_callback_4CF(mach_msg_header_t *msg); } // extern "C" #endif // OS_MAC_STORE namespace Ui { namespace Platform { bool IsApplicationActive() { return [[NSApplication sharedApplication] isActive]; } void InitOnTopPanel(not_null panel) { Expects(!panel->windowHandle()); // Force creating windowHandle() without creating the platform window yet. panel->setAttribute(Qt::WA_NativeWindow, true); panel->windowHandle()->setProperty("_td_macNonactivatingPanelMask", QVariant(true)); panel->setAttribute(Qt::WA_NativeWindow, false); panel->createWinId(); auto platformWindow = [reinterpret_cast(panel->winId()) window]; Assert([platformWindow isKindOfClass:[NSPanel class]]); auto platformPanel = static_cast(platformWindow); [platformPanel setBackgroundColor:[NSColor clearColor]]; [platformPanel setLevel:NSModalPanelWindowLevel]; [platformPanel setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces|NSWindowCollectionBehaviorStationary|NSWindowCollectionBehaviorFullScreenAuxiliary|NSWindowCollectionBehaviorIgnoresCycle]; [platformPanel setHidesOnDeactivate:NO]; //[platformPanel setFloatingPanel:YES]; Integration::Instance().activationFromTopPanel(); } void DeInitOnTopPanel(not_null panel) { auto platformWindow = [reinterpret_cast(panel->winId()) window]; Assert([platformWindow isKindOfClass:[NSPanel class]]); auto platformPanel = static_cast(platformWindow); auto newBehavior = ([platformPanel collectionBehavior] & (~NSWindowCollectionBehaviorCanJoinAllSpaces)) | NSWindowCollectionBehaviorMoveToActiveSpace; [platformPanel setCollectionBehavior:newBehavior]; } void ReInitOnTopPanel(not_null panel) { auto platformWindow = [reinterpret_cast(panel->winId()) window]; Assert([platformWindow isKindOfClass:[NSPanel class]]); auto platformPanel = static_cast(platformWindow); auto newBehavior = ([platformPanel collectionBehavior] & (~NSWindowCollectionBehaviorMoveToActiveSpace)) | NSWindowCollectionBehaviorCanJoinAllSpaces; [platformPanel setCollectionBehavior:newBehavior]; } void ShowOverAll(not_null widget, bool canFocus) { NSWindow *wnd = [reinterpret_cast(widget->winId()) window]; [wnd setLevel:NSPopUpMenuWindowLevel]; if (!canFocus) { [wnd setStyleMask:NSWindowStyleMaskUtilityWindow | NSWindowStyleMaskNonactivatingPanel]; [wnd setCollectionBehavior:NSWindowCollectionBehaviorMoveToActiveSpace|NSWindowCollectionBehaviorStationary|NSWindowCollectionBehaviorFullScreenAuxiliary|NSWindowCollectionBehaviorIgnoresCycle]; } } void DrainMainQueue() { #ifndef OS_MAC_STORE _dispatch_main_queue_callback_4CF(nullptr); #endif // OS_MAC_STORE } void IgnoreAllActivation(not_null widget) { } void DisableSystemWindowResize(not_null widget, QSize ratio) { const auto winId = widget->winId(); if (const auto view = reinterpret_cast(winId)) { if (const auto window = [view window]) { window.styleMask &= ~NSWindowStyleMaskResizable; } } } std::optional IsOverlapped( not_null widget, const QRect &rect) { NSWindow *window = [reinterpret_cast(widget->winId()) window]; Assert(window != nullptr); if (![window isOnActiveSpace]) { return true; } const auto nativeRect = QRect( widget->mapToGlobal(rect.topLeft()), rect.size()).toCGRect(); CGWindowID windowId = (CGWindowID)[window windowNumber]; const CGWindowListOption options = kCGWindowListExcludeDesktopElements | kCGWindowListOptionOnScreenAboveWindow; CFArrayRef windows = CGWindowListCopyWindowInfo(options, windowId); if (!windows) { return std::nullopt; } const auto guard = gsl::finally([&] { CFRelease(windows); }); NSMutableArray *list = (__bridge NSMutableArray*)windows; for (NSDictionary *window in list) { NSNumber *alphaValue = [window objectForKey:@"kCGWindowAlpha"]; const auto alpha = alphaValue ? [alphaValue doubleValue] : 1.; if (alpha == 0.) { continue; } NSString *owner = [window objectForKey:@"kCGWindowOwnerName"]; NSNumber *layerValue = [window objectForKey:@"kCGWindowLayer"]; const auto layer = layerValue ? [layerValue intValue] : 0; if (owner && [owner isEqualToString:@"Dock"] && layer == 20) { // It is always full screen. continue; } CFDictionaryRef bounds = (__bridge CFDictionaryRef)[window objectForKey:@"kCGWindowBounds"]; if (!bounds) { continue; } CGRect rect; if (!CGRectMakeWithDictionaryRepresentation(bounds, &rect)) { continue; } else if (CGRectIntersectsRect(rect, nativeRect)) { return true; } } return false; } TitleControls::Layout TitleControlsLayout() { return TitleControls::Layout{ .left = { TitleControls::Control::Close, TitleControls::Control::Minimize, TitleControls::Control::Maximize, } }; } } // namespace Platform } // namespace Ui