Отверстия в NSView или NSWindow

Возможно ли вырезать части NSWindow или NSView и сделать их видимыми? У меня NSWindow с NSView, и я хочу либо:

A) сделать отверстие в NSWindow, чтобы иметь возможность увидеть его или

B) установите для фона NSWindow четкий цвет, а затем сделайте NSView сверху и установите определенную часть непрозрачности NSViews, чтобы иметь возможность видеть на рабочем столе.

Это эффект, который я пытаюсь создать:

enter image description here

Ответ 1

Да, это возможно, и на самом деле не так сложно.

В вашем подклассе окна, вы должны установить прозрачный цвет фона окна

self.backgroundColor = NSColor.clearColor;

и скажите движку композитинга, что части вашего окна прозрачны и должны быть перерисованы при перемещении окна

[self setOpaque:NO];

В ранних версиях macOS установка цвета фона не требовалась, и во многих ответах этот факт не упоминается. Я проверял, что, по крайней мере, начиная с macOS 10.11, это необходимо.

В вашем подклассе NSView вы должны визуализировать новый фон с цветом по вашему выбору (в противном случае окно будет полностью прозрачным, и будет отображаться только строка заголовка), а затем визуализировать дыру в представлении с

NSRectFillUsingOperation(NSMakeRect(50, 50, 100, 100), NSCompositingOperationClear);

Это дает желаемый эффект, а также работает в темном режиме Мохаве и т.д.

window with hole in dark mode

Полный код:

@interface MyWindow : NSWindow
    - (id)initWithContentRect:(NSRect)contentRect styleMask:( unsigned    int)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag;
@end

@implementation MyWindow
   - (id)initWithContentRect:(NSRect)contentRect styleMask:( unsigned   int)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag {
        self = [super initWithContentRect:contentRect styleMask : aStyle backing :bufferingType defer:flag ];
        if (self)
        {
            self.backgroundColor = NSColor.clearColor;
            [self setOpaque:NO];
            [self setHasShadow:NO];
        }
        return self;
}
@end

@interface MyView : NSView
- (void)drawRect:(NSRect)rect;
@end

@implementation MyView
- (void)drawRect:(NSRect)rect
{
    [[NSColor windowBackgroundColor] set];
    NSRectFill(self.bounds);
    NSRectFillUsingOperation(NSMakeRect(50, 50, 100, 100), NSCompositingOperationClear);
}
@end