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

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.

Related

Added NSWindow as child of another window, but not persisting

My goal is to position an NSWindow relative to another NSWindow, such that when the parent is dragged around, the child moves along with it.
When I poke around with the debugger, I can see the NSWindow parenting relationship getting established correctly. However, in a later part of my code, that same NSWindow returns nil when I try to fetch the parent. I figured only an explicit call to removeChildWindow would eliminate the parenting, unless there's something else going on here like I'm setting up the parenting incorrectly. Are there other ways for an NSWindow to lose its parent/child relationship?
someFunction(NSWindow* parentWindow) {
NSWindow* wnd = [[NSWindow alloc] initWithContentRect:frame
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO];
[parentWindow addChildWindow:wnd ordered:NSWindowAbove];
}
later:
anotherFunction(NSWindow* window) {
NSWindow* parentWindow = [window parentWindow]; // debugger shows nil
}
It seems I had a call to change the window visibility to false:
[wnd setIsVisible:false];
And when I tried reading its parent again, that ends up being nil. Who would have guessed it, this doesn't appear to be documented.

Cast NSWindow to NSPanel

I am accessing a Virtual keyboard (external application - in Adobe Flex).
I want that keyboard should be non focusable. So I have to apply
styleMask:NSNonactivatingPanelMask
But am accessing the keyboard as
NSWindow *myMainWindow = [[[NSApplication sharedApplication] windows] objectAtIndex:0];
as NSNonactivatingPanelMask can only be applied to the NSPanel only
If I can type cast the NSWindow to NSPanel (?) then it possible.
----------My Previous question------------
Return focus to Editor after clicking a button in floating window of MAC
An NSPanel is an NSWindow, the reverse is not true - inheritance doesn't work both ways!
Furthermore casting an object reference from one type to another does not change the actual type of the reference object, so even if you cast an A * to a B * then invoking a method gets you exactly the same method as without the cast - the cast serves to inform the compiler that you know the actual object referenced is a different type and so quietens the compiler when you invoke a B method.
Even if you could get past all that, you state you want the keyboard to be non-focusable, which is not the same as non-activating - the former is about being an applications main window, the latter is about accepting input without activating an application.
The main window of an application is the one which is focussed, its frame highlighted in some way, etc. The key window of an application is the one which is accepting user input. They are often the same window, but need not be. It sounds like you want your keyboard to by the key window without being the main window - i.e. behave like a panel.
NSWindow has methods canBecomeMainWindow and canBecomeKeyWindow which determine whether a window can become main or key respectively. While you cannot change what these return for an NSWindow instance you can subclass NSWindow and override these methods - this is what NSPanel does - see the NSWindow documentation for these methods. So if you, say, define KeyboardWindow as an NSWindow subclass and override canBecomeMainWindow to return NO. Do this and you have a window which will not become main (focussed) but can accept input.
HTH
AS provided by #ashirbad
NSWindow *mainWindow = [[NSApp windows] objectAtIndex: 0];
NSView *mainContentView = [mainWindow contentView];
NSPanel *mainPanel = [[NSPanel alloc] initWithContentRect:[mainContentView frame]
styleMask:NSBorderlessWindowMask | NSNonactivatingPanelMask
backing:NSBackingStoreBuffered defer:YES];
[mainPanel setContentView:mainContentView];
[mainPanel setLevel:NSScreenSaverWindowLevel];
[mainPanel makeKeyAndOrderFront:nil];
[mainContentView orderOut:nil]; //error
This solved my problem.
But I'm getting an error orderOut is not defined in NSView.
If the top app is a Mac application then it's ok But if it is a flex app (in this case). The application not responding at this line.
[mainPanel setContentView:mainContentView];

NSPanel not receiving mousedragged event

I have a borderless NSPanel, when I first launch it and it has focus I can drag it around and the mousedragged method gets triggered correctly, however when I switch focus to another app and then return to the NSPanel (which is set with an NSNonactivatingPanelMask) I no longer receive the mousedragged events.
I do still receive mouseup and mousedown events, so I'm at a loss of why the mousedragged event isn't executed.
Any ideas?
Here's how it gets initialized:
_panel = [[MyPanel alloc] initWithContentRect:frame
styleMask:NSBorderlessWindowMask | NSNonactivatingPanelMask
backing:NSBackingStoreBuffered
defer:NO];
I've also tried adding all these methods to my panel class:
- (BOOL)canBecomeKeyWindow {
return YES;
}
- (BOOL)canBecomeMainWindow
{
return YES;
}
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (BOOL)acceptsFirstResponder
{
return YES;
}
- (BOOL)acceptsFirstMouse
{
return YES;
}
And making it first responder in the mouse down (which it still receives):
- (void)mouseDown:(NSEvent *)theEvent
{
[self makeFirstResponder:self];
[self makeKeyWindow];
[self setBackgroundColor:[NSColor redColor]];
[self display];
}
The mousedragged simply contains this:
- (void)mouseDragged:(NSEvent *)theEvent
{
[self setBackgroundColor:[NSColor greenColor]];
[self display];
NSLog(#"dragged");
}
I do not want the window to get focus. (The focus should remain on the third party app below).
Update: I've added a sample project, download here: http://users.telenet.be/prullen/MovingPanel.zip
As you will see, when you first run the app, and drag it will output "dragged" in the console.log continuously (and the background color will be green). If you then switch to another app and then back to the movingpanel app, dragging will not output anything any more. (and the background color will be red, which is set in the mousedown event handler).
Without the NSNonactivatingPanelMask this works as it should, but it is vital that the window below my panel remains active. If there is another way to accomplish this, please do share.
One thing I have also noticed, if you double click on the panel (fast), and then drag, it turns green (so the mousedragged: is being called), but it's not moving... Not sure what to think of that.
I also noticed that if I do [self setMovableByWindowBackground:NO]; then it will also work correctly. I am betting that the way setMovableByWindowBackground works is interfering with the mouseDragged being called. It's probably a bug that it is called at all.
I would guess one possible solution would be to implement your own window dragging.
If what you are really interested in is responding to when the window is moving, this question and answer may provide what you need.
How to receive notifications when moving Window by mouse?

NSPanel as HUD Panel - fullscreen makes strange empty space

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

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.