Window Fade in and Out - objective-c

how do I fade a window in when it's opened and out when closed?
This should probably be done in Objective C. This has to be part of an AppleScript-Objective-C project. I'm using a property linked to the window, and doing makeKeyAndOrderFront on it...
Any help would be appreciated!

Subclass (or add a category to) NSWindow and add:
- (void)fadeInAndMakeKeyAndOrderFront:(BOOL)orderFront {
[self setAlphaValue:0.0];
if (orderFront) {
[self makeKeyAndOrderFront:nil];
}
[[self animator] setAlphaValue:1.0];
}
- (void)fadeOutAndOrderOut:(BOOL)orderOut {
if (orderOut) {
NSTimeInterval delay = [[NSAnimationContext currentContext] duration] + 0.1;
[self performSelector:#selector(orderOut:) withObject:nil afterDelay:delay];
}
[[self animator] setAlphaValue:0.0];
}
This allows you to fade in/out windows programmatically.
To have a window fade out when its close button gets pushed, add this to the window's delegate:
- (BOOL)windowShouldClose:(id)sender {
[window fadeOutAndOrderOut:YES];
return NO;
}
To show a window with fade-in call [window fadeInAndMakeKeyAndOrderFront:YES]; instead of what you'd call otherwise.

Related

How can I make a fullscreen overlay on the OS X desktop?

I want to make some kind of drawable surface that exists beneath the mouse cursor but above everything else rendered on the desktop. I am trying to create a "trail" behind the mouse.
How can I do this in Cocoa and Objective-C?
You need to subclass NSWindow to create a borderless window and set its window level to something like NSScreenSaverWindowLevel - 1.
- (id)initWithContentRect:(NSRect)contentRect
styleMask:(NSUInteger)aStyle
backing:(NSBackingStoreType)bufferingType
defer:(BOOL)flag
{
self=[super initWithContentRect:contentRect
styleMask:NSBorderlessWindowMask
backing:bufferingType
defer:flag];
if(self!=nil)
{
[self setHasShadow:NO];
[self setOpaque:NO];
[self setBackgroundColor:[NSColor clearColor]];
[self setLevel:NSScreenSaverWindowLevel - 1];
}
return self;
}

Losing focus of NSView after setFrame of NSWindow

I am switching my NSWindow from normal mode to fullscreen, by setting its frame (I know there is a method for the view to go fullscreen, but it needs to be this way)
In my NSOpenGLView I am tracking the onMouseMove event...
After switching to fullscreen (or back), I have to click the view (inside window), to receive the mouseMove event. It looks like it is going out of focus, but I don't understand why (I am just using setFrame) and how to make it focused again, without the user needing to click the window.
Code in my NSOpenGLView (NSView):
if (!fullscreenOn) {
//!switch to fullscreen mode
NSRect mainDisplayRect = [[[self window] screen] frame];
[[self window] setStyleMask:NSBorderlessWindowMask];
[[self window] setFrame:[[self window] frameRectForContentRect:mainDisplayRect] display:YES animate:NO];
[[NSApplication sharedApplication] setPresentationOptions: NSApplicationPresentationAutoHideMenuBar | NSApplicationPresentationAutoHideDock];
fullscreenOn = YES;
} else {
[[self window] setStyleMask:NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSTexturedBackgroundWindowMask];
[[NSApplication sharedApplication] setPresentationOptions: NSApplicationPresentationDefault];
... some code for the right size ...
[[self window] setFrame:frame display: YES animate: YES];
fullscreenOn = NO;
}
the problem was with setting [[self window] setStyleMask:NSBorderlessWindowMask]; which cause this behaviour... making the window borderless by default fixed the problem

NSWindow windowDidResignKey not getting invoked after redisplaying window

I have a custom NSWindow subclass that the user can toggle the display of with the click of a button. I'd also like the window to disappear when the window resigns key status (e.g. by the user clicking outside the window).
I have a delegate that implements windowDidResignKey: but I find that this delegate method is only invoked the first time the window resigns key.
Here's how I toggle the display of the window (via user action or windowDidResignKey):
- (void) toggleWindowAtPoint:(NSPoint)point
{
// Attach/detach window.
if (!attachedWindow)
{
attachedWindow = [[CustomWindow alloc] attachedToPoint:point];
attachedWindow.delegate = self;
[attachedWindow setLevel:NSMainMenuWindowLevel+1]; // show window in front of all other apps on desktop
[attachedWindow makeKeyAndOrderFront:self];
}
else
{
attachedWindow.delegate = nil;
[attachedWindow orderOut:self];
[attachedWindow release];
attachedWindow = nil;
}
}
Here's my implementation of windowDidResignKey:
- (void) windowDidResignKey:(NSNotification *)note
{
[self toggleWindowAtPoint:NSMakePoint(0, 0)];
}
I'm finding that the first time the custom window is displayed, windowDidResignKey: gets called. Every time the custom window is re-displayed after that, windowDidResignKey: is not getting invoked.
The issue was that in some cases, the custom window was not actually becoming the key window after calling [attachedWindow makeKeyAndOrderFront:self].
I fixed this by adding the following line before re-creating the window:
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
In the context of the code snippet above:
- (void) toggleWindowAtPoint:(NSPoint)point
{
// Attach/detach window.
if (!attachedWindow)
{
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
attachedWindow = [[CustomWindow alloc] attachedToPoint:point];
....
Have you tried calling [attachedWindow makeFirstResponder:attachedWindow] in your toggle method?
If you want to activate a window without using activateIgnoringOtherApps: you should use a NSPanel with a NSNonactivatingPanelMask:
[[CustomPanel alloc]
initWithContentRect: NSZeroRect
styleMask: NSNonactivatingPanelMask
backing: NSBackingStoreBuffered
defer: NO];

Fade in/Fade out for MAAttachedWindow

I'm using Matt Gemmell's MAAttachedWindow (http://mattgemmell.com/source) with an NSStatusItem to display a custom view in the menu bar. I'm confused as to how to get it to fade in and fade out. Normally I'd do something like this:
[window makeKeyAndOrderFront:self];
[[window animator] setAlphaValue:1.0];
and to fade out:
[[window animator] setAlphaValue:0.0];
However this code seems to have no effect with MAAttachedWindow. Any ideas?
Thanks
Sorry to drudge up an old post, but I thought it worthwhile mentioning that it works just fine for me to set the alpha value directly, with no need to add accessors/getters.
Simply doing (depending on your setup, or course):
[[self window] addChildWindow:attachedWindow ordered:NSWindowAbove];
[attachedWindow setAlphaValue:0.0];
[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:0.5];
[attachedWindow makeKeyAndOrderFront:self];
[[attachedWindow animator] setAlphaValue:1.0];
[NSAnimationContext endGrouping];
Works just fine.
I'm not especially well versed in CoreAnimation and the usage of implicit animations. However, I was able to get the MAAttachedWindow to fade in by adding an explicit alphaValue property to the MAAttachedWindow class:
#interface MAAttachedWindow : NSWindow {
CGFloat _alphaValue;
...
}
-(CGFloat) alphaValue;
-(void) setAlphaValue:(CGFloat)windowAlpha;
...
#implementation MAAttachedWindow
- (CGFloat) alphaValue {
return _alphaValue;
}
- (void) setAlphaValue:(CGFloat)windowAlpha {
_alpha = windowAlpha;
[super setAlphaValue:windowAlpha];
}
...
By adding that, I was able to get the implicit animation for setAlphaValue to work:
(below code cribbed from Matt's Sample "NSStatusItemTest" code)
- (void)toggleAttachedWindowAtPoint:(NSPoint)pt
{
...
[attachedWindow makeKeyAndOrderFront:self];
[[attachedWindow animator] setAlphaValue:1.0];
I am not sure why explicitly defining the alphaValue property works. I would expect the inherited version from NSWindow would be invoked for the implicit animation. It doesn't appear to though.

Is there a way to make a custom NSWindow work with Spaces

I'm writing an app that has a custom, transparent NSWindow created using a NSWindow subclass with the following:
- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag
{
self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:bufferingType defer:flag];
if (self)
{
[self setOpaque:NO];
[self setBackgroundColor:[NSColor clearColor]];
}
return self;
}
- (BOOL)canBecomeKeyWindow
{
return YES;
}
- (BOOL)canBecomeMainWindow
{
return YES;
}
I have everything working perfectly, including dragging and resizing, except the window doesn't work with Spaces. I cannot move the window to another space by either holding the window while switching spaces via keyboard shortcut, or by dragging to the bottom/top/left/right of the window. Is there anyway to have a custom window behave exactly like a normal window with regards to Spaces?
After a long time I found a solution to this annoying problem.
Indeed [window setMovableByWindowBackground:YES]; conflicts with my own resizing methods, the window trembles, it looks awful!
But overriding mouse event methods like below solved the problem in my case :)
- (void)mouseMoved:(NSEvent *)event
{
//set movableByWindowBackground to YES **ONLY** when the mouse is on the title bar
NSPoint mouseLocation = [event locationInWindow];
if (NSPointInRect(mouseLocation, [titleBar frame])){
[self setMovableByWindowBackground:YES];
}else{
[self setMovableByWindowBackground:NO];
}
//This is a good place to set the appropriate cursor too
}
- (void)mouseDown:(NSEvent *)event
{
//Just in case there was no mouse movement before the click AND
//is inside the title bar frame then setMovableByWindowBackground:YES
NSPoint mouseLocation = [event locationInWindow];
if (NSPointInRect(mouseLocation, [titleBar frame])){
[self setMovableByWindowBackground:YES];
}else if (NSPointInRect(mouseLocation, bottomRightResizingCornerRect)){
[self doBottomRightResize:event];
}//... do all other resizings here. There are 6 more in OSX 10.7!
}
- (void)mouseUp:(NSEvent *)event
{
//movableByBackground must be set to YES **ONLY**
//when the mouse is inside the titlebar.
//Disable it here :)
[self setMovableByWindowBackground:NO];
}
All my resizing methods start in mouseDown:
- (void)doBottomRightResize:(NSEvent *)event {
//This is a good place to push the appropriate cursor
NSRect r = [self frame];
while ([event type] != NSLeftMouseUp) {
event = [self nextEventMatchingMask:(NSLeftMouseDraggedMask | NSLeftMouseUpMask)];
//do a little bit of maths and adjust rect r
[self setFrame:r display:YES];
}
//This is a good place to pop the cursor :)
//Dispatch unused NSLeftMouseUp event object
if ([event type] == NSLeftMouseUp) {
[self mouseUp:event];
}
}
Now I have my Custom window and plays nice with Spaces :)
Two things here.
You need to set the window to allow dragging by background, [window setMovableByWindowBackground:YES];
And If your custom window areas you expect to be draggable are custom NSView subclasses, you must override the method - (BOOL)mouseDownCanMoveWindow to return YES in any NSView subclass that needs to be able to move the window by dragging.
Did you override isMovable?
The Apple documentation says, that it changes Spaces behavior:
If a window returns NO, that means it
can only be dragged between spaces in
F8 mode, ...
Another method that might be related:
NSWindow setCollectionBehavior