9

I am drawing a custom window by setting a custom content view for the window. When I draw the custom view I give it rounded corners and a nice outline to mimic a proper window.

However, I see another 1 px outline around the window which strays from the edge at the corners. I have found that if I turn off the shadow it goes away, but obviously as this wants to act like a window I need the shadow. Here's what I mean about the 1px outline:

enter image description here

How can I prevent this?


EDIT

Code for drawing the custom window's content view:

    NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:[self bounds] cornerRadius:5];

    NSGradient* aGradient = [[[NSGradient alloc] initWithColorsAndLocations:
                              [NSColor colorWithDeviceRed:0.5569 green:0.5137 blue:0.4588 alpha:1.0000], 0.0,
                              [NSColor colorWithDeviceRed:0.5569 green:0.5137 blue:0.4588 alpha:1.0000], 1.0,
                              nil] autorelease];

    [aGradient drawInBezierPath:path angle:90];

    [path setLineWidth:4];
    [[NSColor colorWithDeviceRed:0.4235 green:0.3922 blue:0.3451 alpha:0.9000] setStroke];
    [path strokeInside];

    [path setLineWidth:3];
    [[NSColor colorWithDeviceRed:0.8431 green:0.8314 blue:0.8078 alpha:1.0000] setStroke];
    [path strokeInside];

    [path setLineWidth:1];
    [[NSColor colorWithDeviceRed:0.4235 green:0.3922 blue:0.3451 alpha:0.9000] setStroke];
    [path strokeInside];
Joshua
  • 15,200
  • 21
  • 100
  • 172

5 Answers5

3

Don't ask me how I got this, but this will solve your problem.

Define a category for NSWindow with the following content:

@implementation NSWindow(NoShadowRim)

- (id)_shadowRimInfo {
  return @{
    @"kCUIMeasureWindowFrameRimDensity": [NSNumber numberWithInt:0]
  };
}

@end

DISCLAIMER: This overrides the internal method of NSWindow, so use it at your own risk. It may break with any OS X update.

  • 1
    Looking back at this old project I no longer see the exact same issue occurring on OS X Yosemite so unfortunately can't confirm if this fixes the original issue. I can however confirm that this does indeed affect the shadow rim in such a way it will remove the rim entirely. Thank you! – Joshua Sep 06 '15 at 19:33
1

You need to tell the window to recompute its shadow by sending it -invalidateShadow.

al45tair
  • 4,405
  • 23
  • 30
1

Try:

[[self window] display];
[[self window] setHasShadow:NO];
[[self window] setHasShadow:YES];
Olof
  • 5,348
  • 4
  • 25
  • 27
  • 1
    Where should I put this code? If I put it in `drawRect:` it simply creates an infinite loop due to it constantly calling `display`. – Joshua Mar 09 '12 at 07:11
  • 1
    Yes put it outside of drawRect. I use it whenever I´ve updated my customView but I would guess inside awakeFromNib or windowDidLoad should work. – Olof Mar 10 '12 at 10:19
  • Tried that, still doesn't fix the problem unfortunately. – Joshua Mar 12 '12 at 17:22
0

As I understand correctly, shadows are drawn by windows server. When you draw custom NSWindow with rounded corners or other not rectangular shapes, window server don't count those transparent pixels and dont drop shadow under them.

I developed some hack to avoid such behavior. Just drop additional shadow under your path, something like this:

NSShadow *headShadow = [[NSShadow alloc] init];
[headShadow setShadowColor:[NSColor colorWithSRGBRed:0.0 
                                               green:0.0 
                                                blue:0.0 
                                               alpha:0.16]];
[headShadow setShadowBlurRadius:0.0f];
[headShadow setShadowOffset:NSMakeSize(0.0f, 0.0f)];
[headShadow set];

Ideally for perfect result i fink shadow must be equal to window servers.

Vadim
  • 167
  • 1
  • 12
  • I've put that code before what I have in the question and it does not make any difference. However I am not sure if I am doing everything that you have said correctly. – Joshua May 23 '12 at 15:38
  • Try to add such code before yours: `NSShadow *shadow = [[NSShadow alloc] init]; [shadow setShadowColor:[NSColor colorWithSRGBRed:1.0 green:0.0 blue:0.0 alpha:1.0]]; [shadow setShadowBlurRadius:0.0f]; [shadow setShadowOffset:NSMakeSize(0.0, 0.0)]; [shadow set];` It seems there are some transparent pixels between fill an stroke. – Vadim May 31 '12 at 15:20
0

This line contouring the window area is drawn automatically. I have a window which has this line running accurately around bottom rounded corners. You have to setup the window as non-opaque and the background color to transparent:

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

The somewhere in the contentView -drawRect: you do

  [NSGraphicsContext saveGraphicsState];
  [pathWithBottomRoundedCorner addClip];
  // your drawing here...
  [NSGraphicsContext restoreGraphicsState];

That should work.

febeling
  • 1,390
  • 1
  • 12
  • 29
  • Nope still no luck. Here's the code I'm using https://gist.github.com/1082923 plus the 1st block of code in my `NSWindow` subclass. – Joshua Jul 14 '11 at 17:17
  • Sorry, I think I read your question the wrong way around. You _do_ have the outline twice, and want to get rid of the system one? Isn't it possibly an easy solution to _not_ draw an outline in you own drawRect: ? It looks like an outline is always added around the clipping path when a window shadow is configured. – febeling Jul 14 '11 at 19:50
  • I need to draw a different outline because it needs to be a different color so that it looks good. And even without me drawing the outline it still looks incorrect, http://cl.ly/8Tq8. Might there be a way to turn off the system outline? – Joshua Jul 15 '11 at 05:53
  • Sorry, I can't tell you. I looked at quite a number of windows, including funky ones, but those with shadow also have this outline/stroke/contour line around them. – febeling Jul 15 '11 at 08:08