Is there a way (without using any undocumented API) to figure out if ANY window (not just the application from which the code is running from) is being dragged?
I can use
[NSEvent addGlobalMonitorForEventsMatchingMask:]
but this is just for general dragging and there's no way to tell if a window is beign dragged or not.
Thanks!
Update: I think the answer might lie with these two functions:
CGSGetWindowBounds
CGSNewRegionWithData
If someone can tell me what these functions do and where I can find the documentation for them, it would be great! Thanks.
Your only viable, system-supported API is the Accessibility Framework. You can get notifications this way for other applications' windows but access to read/modify is limited to position/size.
I'm not sure if there's a better approach, but here's one way to do it:
Create an BOOL ivar that tracks whether a window is being moved or not. Then register for the NSWindowWillMoveNotification and NSWindowDidMoveNotication notifications:
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:#selector(windowWillMove:) name:NSWindowWillMoveNotification object:nil];
[nc addObserver:self selector:#selector(windowDidMove:) name:NSWindowDidMoveNotification object:nil];
Then handle the notifications and set the ivar appropriately:
- (void)windowWillMove:(NSNotification*)notification
{
windowBeingDragged = YES;
}
- (void)windowDidMove:(NSNotification*)notification
{
windowBeingDragged = NO;
}
Now you can just check the value of the ivar (windowBeingDragged in this case, to check if a window is being dragged).
Related
I have a Mac application where I would like to save some values when the window closes. However, I can't figure out how to do this. I have the application delegate controlling the main window (which may not be the way you are supposed to do it, and I probably shouldn't have done it this way if what I've read previously is correct) and I can't figure out for the life of me how to do this! I believe it can be done using a NSWindowController, but can you do it in the app delegate? Thanks!
Use NSWindowWillCloseNotification.
- (void)applicationWillFinishLaunching:(NSNotification *)notification {
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:#selector(windowWillClose:) name:NSWindowWillCloseNotification object:window];
}
- (void)windowWillClose:(NSNotification *)notification {
// Your code for saving data
}
I am trying to make a toolbar that is always above the keyboard, pretty much like in Apple's native Messages app. If you take a closer look at that app on the iPad, try undocking the keyboard and the dragging it around by holding than button in its bottom right. You will notice that Apple's toolbar tracks the keyboard's position quite nicely.
Trying to replicate that behavior, I subscribed to both the keyboard-will-change-frame and keyboard-did-change-frame notifications. However, to my disappointment I found that the first one is sent when the user starts the dragging, and the latter is sent when the keyboard snaps to its final position, but there are no notifications I could find that are sent in between. Am I missing something? Here's what I am talking about:
This is the code I use to subscribe to notifications:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidChangeFrame:) name:UIKeyboardDidChangeFrameNotification object:nil];
These are my listener functions:
- (void)keyboardWillChangeFrame:(NSNotification *)notification{
NSLog(#"will change");
// [self alignToolbarForKeyboard:notification action:#"will_change_frame"];
}
- (void)keyboardDidChangeFrame:(NSNotification *)notification{
NSLog(#"did change");
// [self alignToolbarForKeyboard:notification action:#"did_change_frame"];
}
I commented out the call both listener functions make to make sure it's not blocking anything. Is there a notification type I do not know of? I did look at the UIWindow reference but couldn't find anything beyond what I already have. Just to make sure, I also checked whether the show/hide notifications are sent during the movement. They aren't.
Any ideas? Thanks!
Given this code in the viewDidLoad:
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:#selector(keyboardWillShow:) name:
UIKeyboardWillShowNotification object:nil];
[nc addObserver:self selector:#selector(keyboardWillHide:) name:
UIKeyboardWillHideNotification object:nil];
I'm asking myself if I need to delete the observers when I unload the view (or something similar).
It looks a bit like this question, but that question does not discuss if dealloc is deprecated since the use of ARC (edit: see comments in accepted answer).
But since ios updates all the time and I have no clue if you still would need to call dealloc and I've never seen a piece of code how to do this (delete the observers that is), some help would be appreciated :)
Yes, you do. Override dealloc in your view controller like so:
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
In general, you should remove an observer from a notification center when the observer is no longer needed -- either you don't need it to continue observing, or the object itself is being deallocated. You don't need to remove an object observing UIKeyboardWillHideNotification simply because the keyboard is going away, but you do need to remove it if you're getting rid of the object itself.
Consider what would happen if you didn't remove the observer before it was deallocated: if the notification it was watching for ever occurred, the notification center would try to send a message to that object. That would cause either a crash or some behavior that you don't expect, since the pointer the notification center used to send the message no longer points to the object that's supposed to observe the notification.
It is always good to have your notification observer's unregistered while they are not required.
Since your observer deals with Keyboard which is a visual element, have it unregistered, i.e. removed from observer on viewDidDisappear and have it re-register in viewWillAppear (something which i follow.).
This is required coz, in case you are pushing a new view controller over the one you are using, the observer will still be registered and can cause erroneous behaviour, and sometimes, if your view controller get deallocated, the notification will still have the observer registered and can lead to crash. Coz notification centre defaultCenter is a singleton instance for process and will be there for its lifetime.
Post iOS 6.0 you can call it in viewDidUnload. But iOS 6.0 that is deprecated.
I am using Cocos2d game development framework for iPhone.
Let's focus on the battle scene:
The battle scene has as children: battlers layer, HUD layer, menu layer, background layer, etc...
Sometimes, it is necessary that my battlers layer "contacts" my HUD layer (like call a function within it).
I find this hard. Basically, my battlers layer needs some kind of.. instance or reference of the HUD layer in order to call a function within it, right? But I don't know how to have such thing.
Currently, this is what I do:
The battlers layer will run a function in the scene (its parent), and, inside such function, I will "locate" the HUD layer child, and call the function I need in it.
Now, that is kind of inconvenient. What would you do in such situation?
It sounds to me that you may have over-designed this. What I might do is something like this.
I'd have an IScene. Each of my scene classes implements this IScene. IScene has a property called "HUD", another called "Menu", etc.
The current IScene is set into a global static instance ::CurrentScene
When the current scene needs to contact the menu, I say: ::CurrentScene->Menu->SomeFuncion().
Would that work for you?
I'd suggest you take a look at Cocoa's NSNotificationCenter and related classes. Apple has a guide to the subject here.
It might work something like this.
In your HUD layer, you subscribe to notifications with the name #"battleLayerStuff":
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(doThisWhenSomethingHappens:)
name:#"battleLayerStuff"
object:nil];
And in your battle layer, when something happens, you post a notification with the same name:
[[NSNotificationCenter defaultCenter] postNotificationName:#"battleLayerStuff"
object:battleObject];
The object part is optional, but can be helpful if you want to send more information than just "something happened".
If you want to extract information from the object you send you do this in the doThisWhenSomethingHappens: method:
- (void)doThisWhenSomethingHappens:(NSNotification *)notification
{
BattleObject *battleObject = (BattleObject *) notification.object;
// Do stuff with object
}
You could use NSNotification Center. This allows you to send messages in one object and have multiple other objects react to them.
// The object that wants to receive the message registers with NSNotificationcenter
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(receiveScoreUpdateEvent:)
name:#"scoreUpdateEvent"
object:nil ];
In the same object you need to define the method that your selector points to:
- (void)startLocating:(NSNotification *)notification {
NSNumber *scoreObject = [[notification userInfo] objectForKey:#"score"];
// Do something with the new score
}
Another object can then send a message with the updated score at any time and your HUD would react to it:
[[NSNotificationCenter defaultCenter] postNotificationName:#"scoreUpdateEvent"
object:self userInfo:[NSNumber numberWithInt:5345] forKey:#"score"]];
I developed a Menu Extra (menulet) for the Mac but I'd like to know if the machine using the Menu Extra has gone to sleep. I implemented a snooze function but since it's a time-based method it's rather unreliable. Any hints or advice would be greatly appreciated!
Thanks!
You probably want to check out NSWorkspaceWillSleepNotification in NSWorkspace.
The trick is, you need to register for the notifications on NSWorkspace's notificationCenter, not the default one. See Technical Q&A QA1340.
Sample code:
- (void) receiveSleepNote: (NSNotification*) note
{
NSLog(#"receiveSleepNote: %#", [note name]);
}
- (void) fileNotifications
{
// These notifications are filed on NSWorkspace's notification center, not the default
// notification center. You will not receive sleep/wake notifications if you file
// with the default notification center.
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
selector:#selector(receiveSleepNote:)
name: NSWorkspaceWillSleepNotification object:nil];
}