Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSWindow - borderless, transparent window - flickering shadow when animating window height

Here's another NSWindow question ... I've got borderless window, transparent, which is created in this way ...

- (id)initWithView:(NSView *)view anchorPoint:(NSPoint)anchorPoint position:(NSPoint)position distance:(CGFloat)distance {
  if ( !view ) {
    return nil;
  }

  NSSize size = view.intrinsicContentSize;
  NSRect contentRect = NSMakeRect( 0, 0, size.width, size.height );

  self = [super initWithContentRect:contentRect
                          styleMask:NSBorderlessWindowMask
                            backing:NSBackingStoreBuffered
                              defer:NO];

  if ( !self ) {
    return nil;
  }

  _windowView = view;
  _anchorPoint = anchorPoint;
  _position = position;
  _distance = distance;

  [self setContentView:_windowView];

  [self setExcludedFromWindowsMenu:YES];
  [self setMovableByWindowBackground:NO];

  [self setOpaque:NO];
  [self setBackgroundColor:[NSColor clearColor]];

  [self setHasShadow:YES];
  [self useOptimizedDrawing:YES];

  [self setReleasedWhenClosed:NO];

  [self setFrame:[self windowRectWithSize:contentRect.size] display:YES];

  [self setAnchorAttribute:NSLayoutAttributeTop forOrientation:NSLayoutConstraintOrientationVertical];
  [self setAnchorAttribute:NSLayoutAttributeCenterX forOrientation:NSLayoutConstraintOrientationHorizontal];

  [[NSNotificationCenter defaultCenter] addObserver:self
                                           selector:@selector(viewFrameDidChange:)
                                               name:NSViewFrameDidChangeNotification
                                             object:nil];

  return self;
}

... and viewFrameDidChange: is defined as ...

- (void)viewFrameDidChange:(NSNotification *)note {
  if ( note.object != self.contentView ) {
    return;
  }

  [self display];
  [self setHasShadow:NO];
  [self setHasShadow:YES];
}

... this is the only way to have proper NSWindow shadow. In other words, whenever window size changes, I have to call display, setHasShadow:NO and setHasShadow:YES otherwise the window shadow is crippled - it's not around the whole window - just part of the window, etc.

This does work until I start animating height. If height is animated, shadow is correctly recalculated and displayed, but the whole window & shadow is flickering and it's pretty ugly.

An idea why the shadow is flickering? I tried to replace display, setHasShadow:NO/YES with [self invalidateShadow], but it doesn't work at all and shadow is displayed in a wrong way.

How one should animate window height with shadow in borderless/transparent window to avoid flickering?

Here's the video of the flickering shadow. http://d.pr/v/lbkQ

like image 443
zrzka Avatar asked Apr 22 '13 08:04

zrzka


1 Answers

The shadow calculation and drawing is a very resource-consuming operation. So I wouldn't recommend you to invalidate and recalculate the shadow each time the frame changes. Besides, NSWindowDelegate has a –windowDidResize: method, so why using observer?

  1. How do you get your window resized? Maybe adding NSResizableWindowMask to the window's style mask will do the trick? You should give it a try.

  2. Another suggestion - check that the content of your window resizes correctly along with the window. You set your window to transparent. But if there is no content inside the window, no shadow is displayed. You can also try to add your view as a subview to the existing window's contentView instead of replacing it.

I have almost the same setup in my project and I can tell that window's shadow is displayed correctly when you resize the window.

P.S. A recommendation: do not rely on 'self' in the initialization method of the object. It may be yet not fully ready for use. Init with minimum, adjust the window after it was creater in your controller (for example, you cannot be sure that setFrame:display will do what you expect with correct sizes). The glitch you have might be related to this also.

like image 79
UJey Avatar answered Nov 15 '22 05:11

UJey