NSPanel as HUD Panel - fullscreen makes strange empty space - objective-c

I have NSPanel window with style Utility panel (gray small title bar). I can fullscreen this window using standard MAC OS X fullscreen feature. But one strange thing happens - the content view of window doesn't use whole screen, there is small empty space, that is high as title bar.
This doesn't happen, when I change my window style to Regular panel (means higher titlebar).
NSPanel parameters designed in Interface builder:
Clipping of fullscreen view of this window. Note empty space - where red arrow points. This doesn't happen when I change Style to Regular panel.

Try using NSWindow instead of NSPanel
- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation {
if (self = [super initWithContentRect:contentRect
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered defer:deferCreation]) {
[self setOpaque:NO];
[self setExcludedFromWindowsMenu:NO];
}
return self;
}
This is a quazi related answer

Related

keyDown: Not Called on NSClipView Subclass

My app is not document based, and its sole window is managed by a custom, xib-based NSWindowController subclass that I instantiate within the app delegate code:
- (void) applicationDidFinishLaunching:(NSNotification*) aNotification
{
_mainWindowController = [MainWindowController new];
// (stored in ivar just to prevent deallocation)
//[_mainWindowController showWindow:self];
// ↕︎ Not sure about the difference between these two... both seem to work.
[[_mainWindowController window] makeKeyAndOrderFront:self];
}
I have subclassed NSClipView to "center content inside a scroll view" (instead of having it pegged to the lower left corner) when it is zoomed to a size smaller than the clip view, and also implement custom functionality on mouse drag etc.
My window does have a title bar.
My window isn't borderless (I think), so I am not subclassing NSWindow.
I have overriden -acceptsFirstResponder, -canBecomeKeyView and -becomeFirstResponder in my NSClipview subclass (all return YES).
The drag events do trigger -mouseDown: etc., and if I set a breakpoint there, the first responder at that point is the same as the window hosting my clip view: [self.window firstResponder] and [self window] give the same memory address.
What am I missing?
Update
I put together a minimal project reproducing my setup.
I discovered that if my custom view is the window's main view, -keyDown: is called without problems. But if I place a scroll view and replace its clip view by my custom view (to do that, I need to change the base class from NSView to NSClipView, of course!), -keyDown: is no longer triggered.
I assume it has something to do with how NSScrollView manages events (however, as I said before, -mouseDown:, -mouseDragged: etc. seem to be unaffected).
I also discovered that I can override -keyDown: in my window controller, and that seems to work, so I have decided to do just that (still open to an answer, though). Also, since I'm trying to detect the shift key alone (not as a modifier of another key), I'd rather use:
- (void) flagsChanged:(NSEvent *) event
{
if ([event modifierFlags] & NSShiftKeyMask) {
// Shift key is DOWN
}
else{
// Shift key is UP
}
}
...instead of -keyDown: / -keyUp: (taken from this answer).

NSTextView auto-scroll

Suppose there is a window with has a NSTextView which contains enough text to trigger the scrollbars. When I resize the window, the textview is automatically scrolled so that the line which contains the cursor appears in the middle of the textview.
For example, this can also be seen in TextEdit in MacOS: paste bunch of text in it, scroll almost to the top [1], place cursor into the first visible line and resize the window. Now the view should scroll its content so that the cursor lands in the middle of the view.
My question is, how do I turn off this behavior? That is, I would like the textview to never automatically scroll the cursor to the middle when the window gets resized..?
[1] The actual scroll position at which the said behavior happens may require some trial-and-error, as I was unable to find out a pattern at which this happens. In my testing it happened when the scrollbar is at 10% - 30% position of the total height (from the top).
You can do the tweak like this below:-
Create Custom Class of NSTextView and implement one delegate method for textview resizing and one method when click on textview. Refer below:-
.h file
#interface textView : NSTextView
#end
.m file
#import "textView.h"
#implementation textView
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
// Drawing code here.
}
//Below delegate method which will call when resize the textview. So just set your text view to be non editable.
- (void)viewDidEndLiveResize
{
[self setEditable:NO];
[self setSelectable:NO];
}
//Now when you click on the textview below method will called.
-(void)mouseDown:(NSEvent*) theEvent
{
[super mouseDown:theEvent];
[self setEditable:YES];
[self setSelectable:YES];
}
-(void)keyDown:(NSEvent *)theEvent
{
[super keyDown:theEvent];
[self setEditable:YES];
[self setSelectable:YES];
}
#end
Edit:-
Also, mention the custom class name in interface builder inside textview -> Custom Class

Exit fullscreen breaks in Mountain Lion after changing window's delegate

I created my project from the Xcode template for non-document based Cocoa Application.
I have a custom NSWindowController that, after being instantiated on startup, takes possession of the default window (defined in MainMenu.xib).
If I leave the app delegate's window as it is, I can toggle fullscreen mode with command-F (set to -toggleFullscreen: in a menu item), or I can exit from fullscreen by pressing ESC.
Once I set my window controller as the window's delegate (I need this to do some OpenGL adjustments on enter/exit fullscreen, etc.), I can still enter fullscreen by pressing command+F, but I can no longer exit fullscreen (save for command+tab to another app, or command+Q).
Also, the Apple docs mention setting the menu action to -toggleFullscreen: and the target to nil. How is this last part done in Interface Builder? (I connected the action to First Responder's -toggleFullscreen:)
What should I do?
So, I found the problem (posting the question in SO seems to be a condition to finding the solution, always...)
The offending line was not setting the delegate, but what I was doing to the window after entering fullscreen mode. In particular, as soon as I commented out the following line
[window setStyleMask:NSBorderlessWindowMask]; in the code below:
- (void) windowDidEnterFullScreen:(NSNotification*) notification
{
NSWindow* window = [self window];
NSRect mainDisplayRect = [[NSScreen mainScreen] frame];
[window setStyleMask:NSBorderlessWindowMask];
[window setContentSize:mainDisplayRect.size];
[window setLevel:NSMainMenuWindowLevel + 1];
[window makeKeyAndOrderFront:self];
NSRect windowFrame = [window frame];
windowFrame.origin.x = 0;
windowFrame.origin.y = 0;
[window setFrame:windowFrame display:YES];
}
...the expected enter/exit fullscreen mode behaviour was fixed.

Unexpected behavior of NSTextView (because of titlebar-less NSWindow?)

I have a NSWindow (my main window) and a child window (positioned NSWindowBelow the main window) that has a NSTextView. The child window doesn't have a title bar, nor shadow and its transparent.
Here's the code I use to set up my child window to make it transparent:
- (id) initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag{
if (![super initWithContentRect: contentRect styleMask:NSBorderlessWindowMask backing: bufferingType defer:NO]) return nil;
[self setBackgroundColor: [NSColor clearColor]];
[self setOpaque:NO];
return self;
}
But when I try to select the text in it, here's what happens (the black stuff above the child window is the main window):
It looks like the NSTextView is not focused, because the selection is not blue. I've tried calling: [[_childWindow textView] becomeFirstResponder]; but the outcome is the same. Another thing, is that when I scroll it, sometimes it's very laggy and "breaky".
Do you guys have any ideas on whats causing this and how to fix it? I suspect it's because the window doesn't have a title bar, but I'm not sure.
Thanks!
From the NSWindow docs:
canBecomeKeyWindow
Indicates whether the window can become the key window.
- (BOOL)canBecomeKeyWindow
Return Value
YES if the window can become the key window, otherwise, NO.
Discussion
Attempts to make the window the key window are abandoned if this method returns
NO. The NSWindow implementation returns YES if the window has a title bar or a
resize bar, or NO otherwise.
Try overriding -canBecomeKeyWindow and returning YES.

How to custom draw window title bar in Objective-C?

I'd like to customize the way I draw the window title bar on OS X. Specifically, I'd like to do something like the Twitterrific app where there is a custom close button, no min/max buttons, and the window title text is right-justified. Unlike Twitterrific, I'm not looking to custom draw the entire window (though I'm not completely opposed to that either).
I've already seen the RoundWindow sample on Cocoa With Love as well as the RoundTransparentWindow example Apple provides, but neither seems appropriate.
If you don't want to use a borderless window class then you can do a couple of things.
First, you can customize the close/min/max buttons buy using -[NSWindow standardWindowButton:]. Once you get the button you can position it/remove it/etc...
You can customize the title by setting the title to #"". Then you can add a NSTextField to draw your own title by doing the following [[[NSWindow contentView] superview] addSubview:textField].
This is probably the easiest way to do things.
Another way to do this is to customize the view that draws all the window title bar, etc...
NSWindow's content view's is inside a "theme view". You can subclass the theme view and do your own drawing. The only problem is that the theme view is a private class so you'll have to be careful.
cocoadev provides some more detail on how best to implement your own NSWindow subclass, complete with a description of most of the common pitfalls.
The gist of it is to create a subclass of NSWindow, and set its styleMask to NSBorderlessWindowMask in the init method:
- (id) initWithContentRect: (NSRect) contentRect
styleMask: (unsigned int) aStyle
backing: (NSBackingStoreType) bufferingType
defer: (BOOL) flag
{
if ((self = [super initWithContentRect: contentRect
styleMask: NSBorderlessWindowMask
backing: bufferingType
defer: flag]) == nil) { return nil; }
[super setMovableByWindowBackground:YES];
[super setLevel:NSNormalWindowLevel];
[super setHasShadow:YES];
// etc.
return self;
}
Note that you should probably return YES for canbecomeKeyWindow in order to make your window behave like a normal window.
- (BOOL) canBecomeKeyWindow
{
return YES;
}
You can then create a custom NSView subclass, fill the entire window with an instance of said class, and then perform all of the appropriate window drawing from within that custom view.
The whole thing can get a bit painful. You will have to re-implement most of the normal window behaviours such as resizing by dragging the bottom right corner.
There's an example of a custom window implementation in the CoreData Stickies sample project.