Snapping an NSWindows in place while the user is moving it - objective-c

What would be the best way to snap an NSWindow to some location while the user is moving it?
I have tried using windowDidMove, for mouse down events, but this function is called for every single movement. I haven't been able to find anything equivalent to the old kEventWindowBoundsChanging with kWindowBoundsChangeUserDrag, which was exactly what was needed to do this. It needs to be available in 10.7 on up.
Any leads?

Generally the easiest way to do this is subclass NSWindow and implement -setFrame:, where you modify the NSRect argument and then pass it to super.

Related

Cocoa: Update views outside NSWindow's content view during live window resizing?

I have a standard NSWindow with a toolbar. One of the toolbar's items is a custom view -- specifically, an NSTextField. (More specifically, it's a timer app -- the timer's controls as well as the digital display are all within the toolbar, with other stuff in the window's content area. The NSTextField is the digital display.)
Ordinarily, I just update the timer every second by changing the 'stringValue' property of the NSTextField, which causes it to update itself. But during a live window resize, even though the code that updates the 'stringValue' property is running (which I have verified with NSLog), the NSTextField doesn't draw itself again until the window resizing is done. Meanwhile, the stuff inside the content area is updating itself just fine.
I've tried all the ways I know to tell the NSTextField to draw itself, but it just refuses to happen until the live resize is done. Any ideas? Obviously it must be possible somehow, as the toolbar gets resized along with the rest of the window -- so you'd think it would be possible to force it to redraw one or more of its subviews as it is moving them around. I'm assuming I can hack this together by subclassing something, but my Cocoa-fu is not yet strong enough to figure out the easiest/most proper way to do so.
Thanks in advance...
EDIT: I kind of figured out a solution -- it's not great but it mostly works for now. It's in my comments below.
Just invoke -[NSWindow displayIfNeeded] after marking the view as needing display. I encountered this problem when implementing the Mac driver for Wine (an open-source project for running Windows software on OS X and other Unix-like OSes).
http://source.winehq.org/source/dlls/winemac.drv/cocoa_window.m?v=wine-1.7.11#L1905
(That's LGPL code, so you want to consider before copying it. But you can learn implementation techniques from it without worry.)

Is it possible to observe -visibleRect

I would like to be notified whenever a certain NSView's - (NSRect)visibleRect changes because I want to do some fancy subview layout based on the visible rect. Frankly, right now I'm stumped; -visibleRect doesn't emit KVO notifications (which makes sense), and there doesn't seem to be way to find out if the visible rect changed or not without explicitly calling -visibleRect.
Is this at all possible? (or is it a terrible, terrible idea?)
I think you can either override -[NSView updateTrackingAreas] or listen for NSViewDidUpdateTrackingAreasNotification. Those may happen on more occasions than just a change of the visible rect, but they should happen for any change of the visible rect. I think.
That said, it may be a terrible idea. Hard to know. :)
Another option post 10.5 is the -viewWillDraw method which is called just prior to the view (and its subviews) being drawn. You can fetch the view's visible rectangle and perform layout prior to calling [super viewWillDraw].
Ken's suggestions of listening for the tracking area changes feels hacky but seems to work, although they only trigger after the resize is complete. If you need updates during resizing like I did, it overriding -[NSView resizeWithOldSuperviewSize:] will do that
The adjustTrackingArea solution does not appear viable in Mojave for NSScrollView at least.
Mojave does not appear to always call adjustTrackingArea while scrolling an NSScrollView.
Haven't tested other OS versions, other view types.

cocoa application changing mouse cursor?

I have a cocoa application that has a view which is clickable. I cannot figure out how to change the cursor when the user mouses over it. I want to do this so that the user knows that they can click on it. I know this should be very simple, but I have not been able to find anything via google or stackoverflow. Anyone have any ideas?
So, not this?
Cocoa: change cursor when it's over an NSButton
[yourButton addCursorRect:[yourButton bounds] cursor:[theCursorYouWant]];
(Quote from Mark)
This is a relatively simple thing to do using NSView's tracking areas methods in conjunction with the NSCursor class to change the cursor. In general, the way you do this is set up a tracking area for your view, and when you get mouseEntered and mouseExited updates from the tracking area, you can update the cursor.
Check out the NSView Class Reference and the NSCursor Class Reference for more information.

NSWindow with custom shadow

I want to draw a custom shadow on an NSWindow-Object.
Is there a way to do this by passing an own NSShadow-Object to NSWindow? Or a (private) method, where I can put my own drawing code?
Thanks,
Don't. You shouldn't alter the look of the window. Changing the look of UI is only allowed for Apple. Normal apps should use the standard one.
That said, there's a way, if you really insist on doing that. You can't just attach an NSShadow, unfortunately. Also, as far as I understand, there's no private method which draw the shadow. That's done by the Window Server, not by the app.
But you can ask the window server not to add the shadow. Have you noticed that in the Interface Builder, there's an option suppressing the shadow of a given window? That corresponds to the property hasShadow of an NSWindow.
After suppressing the shadow, you just need to draw everything by yourself. A nice sample code that does the custom window drawing is available at ADC, so have a look at it.

How to stop mouse drag events from moving entire window? [cocoa]

I think this should be a very easy one, but I cant find the answer on the docs.
I want to stop mouse dragging events which are in (or start in) my custom nsview subclass from causing the window to be dragged around the screen. How can I tell the window to stay still so i can interact with the view instead of dragging the whole window around? thanks.
In addition to the matter of whether you handle mouseDragged, you may need to override mouseDownCanMoveWindow to return NO, or override isOpaque to return YES.
You need to implement mouseDragged: in your view. As documented, NSView's implementation simply passes the message to the next responder, which means that it will end up hitting the window. (Why? See “The Responder Chain” in the Cocoa Event-Handling Guide.) Responding to the message yourself prevents that, as long as you don't call up to the superclass implementation.