avaudioplayer play music in background - xcode

I have a problem with AVAudioPlayer in background, everything works but when I have the controls in the lock screen and I click on the pause button the control receive the event but the lock screen with controls disappears. I want that lock screen remain with controls like Music app.
I put these lines in viewDidLoad:
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
and then :
-(void)viewDidAppear:(BOOL)animated{
[[UIApplication sharedApplication]beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
}
-(BOOL)canBecomeFirstResponder{ return YES; }
- (void)viewWillDisappear:(BOOL)animated {
//End recieving events
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];
[super viewWillDisappear:animated];
}
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
//if it is a remote control event handle it correctly
if (event.type == UIEventTypeRemoteControl) {
if (event.subtype == UIEventSubtypeRemoteControlPause) {
[self.playButton setBackgroundImage:[UIImage imageNamed:#"play_icon.png"]
forState:UIControlStateNormal];
[self.audioPlayer pauseAudio];
self.isPaused = FALSE;
}
else if (event.subtype == UIEventSubtypeRemoteControlPlay){
if (!self.isPaused) {
[self.playButton setBackgroundImage:[UIImage imageNamed:#"pause.png"]
forState:UIControlStateNormal];
//start a timer to update the time label display
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(updateTime:)
userInfo:nil
repeats:YES];
[self.audioPlayer playAudio];
self.isPaused = TRUE;
}
}
}
}

I find the solution !!
Using this property :
#property MPNowPlayingInfoCenter* nowPlayingInfo;
I have to add these lines on my viewDidLoad :
[MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo=[NSDictionary dictionaryWithObject:#1.0f forKey:MPNowPlayingInfoPropertyPlaybackRate];

Related

Expected identifier or "(" error

EDITED: Thanks to your help I am closing in on the solution to my problem. I have fixed the missing "#end error", and am left with just one "Expected identifier or "("" error.
This is the code, the error is noted:
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] \
compare:v options:NSNumericSearch] == NSOrderedAscending)
#import "WViewController.h"
#import <SkillzSDK-iOS/Skillz.h>
#interface WViewController ()
#end
#implementation WViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//create backdrop image
NSMutableString *imgFile = [[NSMutableString alloc] init];
if (![globalBackgroundImage isEqualToString:#""]) [imgFile setString:globalBackgroundImage]; //falls back to first image setting for all devices;
if ((IS_WIDESCREEN_PHONE)&&(![widescreenBackgroundImage isEqualToString:#""])) [imgFile setString:widescreenBackgroundImage]; //you can specify a different image for
if ((IS_IPAD)&&(![iPadBackgroundImage isEqualToString:#""])) [imgFile setString:iPadBackgroundImage]; //widescreen phones & for iPad
if (![imgFile isEqualToString:#""]) {
UIImage *img = [[UIImage imageNamed:imgFile] retain];
CGSize imgSz = [img size];
CGSize screenSz = [[UIScreen mainScreen] bounds].size;
float imgWH = imgSz.width/imgSz.height;
float screenWH = screenSz.width/screenSz.height;
CGRect backdropFrame;
if (imgWH>=screenWH) backdropFrame = CGRectMake((screenSz.width/2)-((screenSz.height*imgWH)/2), 0, screenSz.height*imgWH, screenSz.height); //image wider than screen
else backdropFrame = CGRectMake(0, ((screenSz.height/2)-((screenSz.width/imgWH)/2)), screenSz.width, screenSz.width/imgWH);
UIImageView *backdropImageView = [[UIImageView alloc] initWithFrame:backdropFrame];
[backdropImageView setImage:img];
[backdropImageView setAlpha:backgroundImageOpacity];
[self.view addSubview:backdropImageView];
}
[self.view setBackgroundColor:globalBackgroundColor];
//init GameCenter
[[GameCenterManager sharedManager] setupManager];
[[GameCenterManager sharedManager] setDelegate:self];
//initialize the view for when the player is in the game
gameView = [[WgameView alloc] initWithFrame:[[UIScreen mainScreen] bounds] fromViewController:self];
[gameView setHidden:YES];
[self.view addSubview:gameView];
//initialize the view for then the player is on the home screen
homeView = [[WhomeView alloc] initWithFrame:[[UIScreen mainScreen] bounds] fromViewController:self];
[homeView setHidden:YES];
[self.view addSubview:homeView];
}
- (void) viewDidAppear:(BOOL)animated {
//go to home screen right away
[self goHome];
//show a RevMob fullscreen ad if we're supposed to
if (revMobActive) {
if (showRevMobFullscreenOnLaunch) {
[[RevMobAds session] showFullscreen];
}
}
//show a Chartboost ad if we're supposed to
if (chartboostActive) {
if (showChartboostOnLaunch) {
[[Chartboost sharedChartboost] showInterstitial:CBLocationHomeScreen];
}
}
}
#pragma mark game flow
-(void) multiplayerButtonPressed:(id)sender
{
NSLog(#"Multiplayer button pressed, launching Skillz!");
// Launching Skillz in landscape mode
[[Skillz skillzInstance] launchSkillzForOrientation:SkillzLandscape
launchHasCompleted:^{
// This code is called after the Skillz UI launches.
NSLog(#"Skillz just launched.");
} tournamentWillBegin:^(NSDictionary *gameRules) {
// This code is called when a player starts a game in the Skillz portal.
NSLog(#"Tournament with rules: %#", gameRules);
NSLog(#"Now starting a game…");
// INCLUDE CODE HERE TO START YOUR GAME
// …..
// …..
// …..
// END OF CODE TO START GAME
} skillzWillExit:^{
// This code is called when exiting the Skillz portal
//back to the normal game.
NSLog(#"Skillz exited.");
}];
}
- (void) startGame:(UIButton*)sender {
//hide RevMob banner ad if we're supposed to
if (revMobActive) {
if (showRevMobBannerOnHomeScreen) {
[[RevMobAds session] hideBanner];
}
}
//starts game in the mode corresponding to which button was tapped
[[WGameModeEngine sharedInstance] setCurrentGameMode:sender.titleLabel.text];
[gameView startGame];
[homeView setHidden:YES];
[gameView setHidden:NO];
//init timer if timed game
if ([[WGameModeEngine sharedInstance] isTimedGame]) {
timedGameTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(decrementTime) userInfo:nil repeats:YES] retain];
}
//notify game engine to play sound if configured
[[WGameModeEngine sharedInstance] soundEventDidHappen:#"BeginGame"];
}
- (void) goHomeButtonPressed {
[self stopGame];
[self goHome];
}
- (void) stopGame {
//stop timer if this was a timed game
if (timedGameTimer) {
[timedGameTimer invalidate];
[timedGameTimer release];
timedGameTimer=nil;
}
}
- (void) goHome {
[gameView setHidden:YES];
[homeView setHidden:NO];
//show a RevMob banner ad if we're supposed to
if (revMobActive) {
if (showRevMobBannerOnHomeScreen) {
[[RevMobAds session] showBanner];
}
}
}
- (void) decrementTime {
[[WGameModeEngine sharedInstance] timeDecreased]; //report to our game model that time has decreased
if ([[WGameModeEngine sharedInstance] timeLeft]<=0) { //if 0 seconds left,
[self timedGameEnded]; //game has ended
}
if (([[WGameModeEngine sharedInstance] timeLeft]<6)&&([[WGameModeEngine sharedInstance] timeLeft]>0)) {
//notify game engine to play sound if configured
[[WGameModeEngine sharedInstance] soundEventDidHappen:#"FiveSecondCountdown"];
}
[gameView updateLabels]; //update gameView's score and time labels
}
- (void) timedGameEnded {
//game over!
[self stopGame];
//notify game engine to play sound if configured
[[WGameModeEngine sharedInstance] soundEventDidHappen:#"GameOver"];
//show an alert with score and list of words found (if you want, you can add a whole separate screen for this instead of simple alert!)
UIAlertView *alert = [[UIAlertView alloc] initWithTitle: #"Game Over" message:[NSString stringWithFormat:#"You scored %d points!\n\nWords found:\n%#",[[WGameModeEngine sharedInstance] getScore],[[[WGameModeEngine sharedInstance] getWordsFound] componentsJoinedByString:#" "]] delegate: nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert setDelegate:self];
[alert show];
[alert release];
//report score to GameCenter
int sc = [[WGameModeEngine sharedInstance] getScore];
if (sc>0) [self reportScore:sc forCategory:[[[[WGameModeEngine sharedInstance] getCurrentGameMode] componentsSeparatedByString:#" "] componentsJoinedByString:#"_"]];
[#"com.bundle.appname" stringByAppendingString:[[[[[WGameModeEngine sharedInstance] getCurrentGameMode] lowercaseString] componentsSeparatedByString:#" "] componentsJoinedByString:#""]];
}
- (void) alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
//share latest score on Facebook if we're supposed to
if (FacebookShareEnabled) {[self facebookShare];}
//go to home screen
[self goHome];
//show a RevMob fullscreen ad if we're supposed to
if (revMobActive) {
if (showRevMobFullscreenWhenGameOver) {
[[RevMobAds session] showFullscreen];
}
}
//show a Chartboost ad if we're supposed to
if (chartboostActive) {
if (showChartboostWhenGameOver) {
[[Chartboost sharedChartboost] showInterstitial:CBLocationHomeScreen];
}
}
}
#pragma mark GameCenter
- (void)gameCenterManager:(GameCenterManager *)manager authenticateUser:(UIViewController *)gameCenterLoginController {
if (revMobActive) {
if (showRevMobBannerOnHomeScreen) {
[[RevMobAds session] hideBanner];
}
}
[self presentViewController:gameCenterLoginController animated:YES completion:^(void)
{if (revMobActive) {
if (showRevMobBannerOnHomeScreen) {
[[RevMobAds session] showBanner];
}}}];
}
if (isGameOver) {<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<ERROR IS HERE>>>>>>>>>>>>>>>
if ([[Skillz skillzInstance] tournamentIsInProgress]) {
// The game ended and it was in a Skillz tournament,
// so report the score and go back to Skillz.
[[Skillz skillzInstance] completeTurnWithGameData:gameData
playerScore:playerScore
playerCurrentTotalScore:playerCurrentTotalScore
opponentCurrentTotalScore:opponentCurrentTotalScore
roundOutcome:turnOutcome
matchOutcome:matchOutcome
withCompletion:^{
// Code in this block is called when exiting to Skillz
// and reporting the score.
NSLog(#"Reporting score to Skillz…");
}];
} else {
// Otherwise single player game, so take the normal action
}
}
- (void) reportScore: (int64_t) score forCategory: (NSString*) category
ORIGINAL QUESTION:
I am really new to coding and hoping that someone can help me with what I am sure is a very simple problem. I have looked at a lot of other answers regarding this error, but they don't seem to apply to my situation.
The following code is part of a game app I am working on using Xcode, trying to integrate it with a third party system called SKILLZ. I did not write any of the code and am trying to understand it as I proceed with the integration.
I have noted within the code where I am getting the error:
#import "WAppDelegate.h"
#import "WViewController.h"
#import <SkillzSDK-iOS/Skillz.h>
#implementation WAppDelegate
- (void)dealloc
{
[_window release];
[_viewController release];
[super dealloc];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//initialize language engine
[WLanguageEngine sharedInstance];
//initialize game mode engine
[WGameModeEngine sharedInstance];
//initialize RevMob
if (revMobActive) {
[RevMobAds startSessionWithAppID:RevMobAppID];
}
if (revMobActive&&revMobTestingMode) {
[RevMobAds session].testingMode = RevMobAdsTestingModeWithAds;
// or
//[RevMobAds session].testingMode = RevMobAdsTestingModeWithoutAds;
}
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
self.viewController = [[[WViewController alloc] initWithNibName:#"WViewController" bundle:nil] autorelease];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
{<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<**<<EXPECTED IDENTIFIER OR "(">> ERROR OCCURS HERE**
// INITIALIZE SKILLZ HERE
// 940 is the game ID that was given to us by the Skillz Developer Portal.
// SkillzSandbox specifies that we will use the sandbox server since we
// are still developing the game.
// SkillzProduction specifies that we will use the production server since
// the game is ready for release to the AppStore
[[Skillz skillzInstance] skillzInitForGameId:#"940"
environment:SkillzSandbox];
I am getting a second occurrence of this error in a different part of the app code, but am hoping that if I can sort this one out that it will help me to understand the other.
Hoping that this is not off-topic or too specific, and that someone might be able to help.
Cheers
Jen
{<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<> ERROR OCCURS HERE
// INITIALIZE SKILLZ HERE
// 940 is the game ID that was given to us by the Skillz Developer Portal.
// SkillzSandbox specifies that we will use the sandbox server since we
// are still developing the game.
// SkillzProduction specifies that we will use the production server since
// the game is ready for release to the AppStore
[[Skillz skillzInstance] skillzInitForGameId:#"940"
environment:SkillzSandbox];
return YES;
}
This block is outside of - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
Perhaps you forgot a declaration or added an extraneous } somewhere

UIImagePickerController crashes on launch

I present a viewcontroller to the user with a view that shows a UIButton to record a video. When the user presses the button, my app crashes with the following error:
Terminating app due to uncaught exception 'UIApplicationInvalidInterfaceOrientation', reason: 'preferredInterfaceOrientationForPresentation must return a supported interface orientation!'
My app only supports portrait orientation and the info.plist file reflects properly. I use the same code in another app, found on Ray Wenderlich's site, and it works great. The code for the .h and .m files is below. Any help would be appreciated.
.h
#import <MediaPlayer/MediaPlayer.h>
#import <MobileCoreServices/UTCoreTypes.h>
#import <AssetsLibrary/AssetsLibrary.h>
#interface RecordSwingViewController: UIViewController
-(BOOL)startCameraControllerFromViewController:(UIViewController*)controller
usingDelegate:(id )delegate;
-(void)video:(NSString *)videoPath didFinishSavingWithError:(NSError *)error contextInfo:(void*)contextInfo;
#property (weak, nonatomic) IBOutlet UIButton *record;
- (IBAction)recordSwing:(id)sender;
#end
.m
#import "RecordSwingViewController.h"
#interface RecordSwingViewController ()
#end
#implementation RecordSwingViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)recordSwing:(id)sender {
[self startCameraControllerFromViewController:self usingDelegate:self];
}
-(BOOL)shouldAutorotate
{
return NO;
}
-(BOOL)startCameraControllerFromViewController:(UIViewController*)controller
usingDelegate:(id )delegate {
// 1 - Validattions
if (([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] == NO)
|| (delegate == nil)
|| (controller == nil)) {
return NO;
}
// 2 - Get image picker
UIImagePickerController *cameraUI = [[UIImagePickerController alloc] init];
cameraUI.sourceType = UIImagePickerControllerSourceTypeCamera;
// Displays a control that allows the user to choose movie capture
cameraUI.mediaTypes = [[NSArray alloc] initWithObjects:(NSString *)kUTTypeMovie, nil];
// Hides the controls for moving & scaling pictures, or for
// trimming movies. To instead show the controls, use YES.
cameraUI.allowsEditing = NO;
cameraUI.delegate = delegate;
// 3 - Display image picker
[controller presentViewController: cameraUI animated: YES completion:nil];
return YES;
}
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSString *mediaType = [info objectForKey: UIImagePickerControllerMediaType];
[self dismissViewControllerAnimated:NO completion:nil];
// Handle a movie capture
if (CFStringCompare ((__bridge_retained CFStringRef) mediaType, kUTTypeMovie, 0) == kCFCompareEqualTo) {
NSString *moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] path];
if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(moviePath)) {
UISaveVideoAtPathToSavedPhotosAlbum(moviePath, self,
#selector(video:didFinishSavingWithError:contextInfo:), nil);
}
}
}
-(void)video:(NSString*)videoPath didFinishSavingWithError:(NSError*)error contextInfo:(void*)contextInfo {
if (error) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Video Saving Failed"
delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
} else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Video Saved" message:#"Saved To Photo Album"
delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
}
#end
Ok, here is the answer, finally.
https://stackoverflow.com/a/12570501/2133494
Basically I needed to add a category to my UIImagePickerController. I tried a lot of other fixes but this worked.
You have implemented the bool for autorotation, but did not specify if it does not auto rotate what else it should do. Try the following after autorotate method.
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
}
Please remove any of the masks you don't need from the method above and see if this works for you.

UISegmentedControl setTint for UISegments only works after clicking

Xcode, Obj-c, iOS 5.2 iOS 6.0
I have a UISegmentedControl which is being inserted into the bottom toolbar using something like this:
-(void) makeSegmentedControl {
self.SegControl = [[UISegmentedControl alloc] initWithItems:#[#"Title1",#"Title2"]];
self.SegControl.segmentedControlStyle = UISegmentedControlStyleBar;
[self.SegControl setTarget:self action:#selector(handleSegment) forControlEvents:UIControlEventValueChanged]
[self.SegControl setSelectedSegmentIndex:0];
}
-(void) AddSegmentedControlToToolbar {
UIBarButtonItem *tmp = [UIBarButtonItem new];
[tmp setCustomView:self.SegControl];
[self.navigationController.toolbar setItems#[tmp]];
}
-(void) tintSegmentedControl {
for (int i = 0; i< [self.SegControl.subviews count]; i++) {
[[self.SegControl.subviews objectAtIndex:i] setTint:[UIcolor greenColor];
}
NSArray * sortedViews = [self.SegControl.subviews sortArrayUsingFunction:sortFunction];
[[sortedViews objectAtIndex:self.SegControl.selectedSegmentIndex] setTintColor:[UIColor lightGreenColor]];
for (id view in self.SegControl.subviews) {
[view removeFromSuperView];
}
for (id view in sortedViews) {
[self.SegControl addSubview:view];
}
}
-(void)viewDidLoad {
[self makeSegmentedControl];
[self addSegmentedControlToToobar];
[self tintSegmentedControl];
}
-(void) handleSegment {
[self tintSegmentedControl];
}
When I run the similar code in our app it shows a very BLUE UISegmentedController which turns GREEN on clicking. I've tried a few things and it seems that the tint on the UISegments just refuses to stick until after the view has finished loading. Any idea what's happening here?
Edit
So, it turns out I was actually using the iOS 6.0 simulator and there is a restriction in iOS 6 that you can't tint a UISegmentedController before ViewDidAppear:Animated: has run. I think that this was the problem, because when I make this change:
-(void)viewDidLoad {
[self makeSegmentedControl];
[self addSegmentedControlToToobar];
}
-(void)viewDidAppear {
[NSTimer timerWithTimeInterval:0 target:self selector:#selector(tintSegmentedControl) userInfo:nil repeats:NO];
}
it works. Not 100% sure what's going on. Is there an easier way?
try this code
-(void) tintSegmentedControl {
[self.SegControl setTintColor:[UIColor greenColor];
NSArray * sortedViews = [self.SegControl.subviews sortArrayUsingFunction:sortFunction];
[[sortedViews objectAtIndex:self.SegControl.selectedSegmentIndex] setTintColor:[UIColor lightGreenColor]];
for (id view in self.SegControl.subviews) {
[view removeFromSuperView];
}
for (id view in sortedViews) {
[self.SegControl addSubview:view];
}
}
So, it turns out there is a restriction in iOS 6 that you can't tint a UISegmentedController before ViewDidAppear:Animated: has run. To circumvent it I made this code change (as you can see in the edit).
-(void)viewDidLoad {
[self makeSegmentedControl];
[self addSegmentedControlToToobar];
}
-(void)viewDidAppear {
[NSTimer timerWithTimeInterval:0 target:self selector:#selector(tintSegmentedControl) userInfo:nil repeats:NO];
}

Calling keyDown: for items in an NSCollectionView

I have a problem to make the keyDown: method run for each item in an NSCollectionView when I press a key from the keyboard.
Edit: I have the next code in my NSCollectionViewItem but does't work, how can I do that specially make work the acceptsFirstResponder:
- (BOOL)acceptsFirstResponder
{
[[[self view] window] makeFirstResponder:self];
return YES;
}
- (void)keyDown:(NSEvent*)event
{
NSString *chars = [event characters];
unichar character = [chars characterAtIndex: 0];
if(!sound){
sound = [[NSSound alloc] initWithContentsOfFile:textFile.stringValue byReference:YES];
}
if ([checkButton state]==1) {
[sound setLoops:YES];
}else{
[sound setLoops:NO];
}
if(character == (int)'w'){
if ([sound isPlaying]){
[sound stop];
[sound release];
sound = nil;
} else {
[sound play];
}
}
}
(Sorry for make a lot of changes is first question here)

Cocoa nextEventMatchingMask not receiving NSMouseMoved event

I created a local event loop and showed up a borderless window (derived from NSPanel),
I found in the event loop there's no NSMouseMoved event received, although I can receive Mouse button down/up events.
What should I do to get the NSMouseMoved events? I found making the float window as key window can receive the NSMouseMoved events, but I don't want to change key window. And it appears this is possible, because I found after clicking the test App Icon in System Dock Bar, I can receive the mousemoved events, and the key window/mainwindow are unchanged.
Here's the my test code: (Create a Cocoa App project names FloatWindowTest, and put a button to link with the onClick: IBAction).
Thanks in advance!
-Jonny
#import "FloatWindowTestAppDelegate.h"
#interface FloatWindow : NSPanel
#end
#interface FloatWindowContentView : NSView
#end
#implementation FloatWindowTestAppDelegate
#synthesize window;
- (void)delayedAction:(id)sender
{
// What does this function do?
// 1. create a float window
// 2. create a local event loop
// 3. print out the events got from nextEventMatchingMask.
// 4. send it to float window.
// What is the problem?
// In local event loop, althrough the event mask has set NSMouseMovedMask
// there's no mouse moved messages received.
//
FloatWindow* floatWindow = [[FloatWindow alloc] init];
NSEvent* event = [NSApp currentEvent];
NSPoint screenOrigin = [[self window] convertBaseToScreen:[event locationInWindow]];
[floatWindow setFrameTopLeftPoint:screenOrigin];
[floatWindow orderFront:nil];
//Making the float window as Key window will work, however
//change active window is not anticipated.
//[floatWindow makeKeyAndOrderFront:nil];
BOOL done = NO;
while (!done)
{
NSAutoreleasePool* pool = [NSAutoreleasePool new];
NSUInteger eventMask = NSLeftMouseDownMask|
NSLeftMouseUpMask|
NSMouseMovedMask|
NSMouseEnteredMask|
NSMouseExitedMask|
NSLeftMouseDraggedMask;
NSEvent* event = [NSApp nextEventMatchingMask:eventMask
untilDate:[NSDate distantFuture]
inMode:NSDefaultRunLoopMode
dequeue:YES];
//why I cannot get NSMouseMoved event??
NSLog(#"new event %#", [event description]);
[floatWindow sendEvent:event];
[pool drain];
}
[floatWindow release];
return;
}
-(IBAction)onClick:(id)sender
{
//Tried to postpone the local event loop
//after return from button's mouse tracking loop.
//but not fixes this problem.
[[NSRunLoop currentRunLoop]
performSelector:#selector(delayedAction:)
target:self
argument:nil
order:0
modes:[NSArray arrayWithObject:NSDefaultRunLoopMode]];
}
#end
#implementation FloatWindow
- (id)init
{
NSRect contentRect = NSMakeRect(200,300,200,300);
self = [super initWithContentRect:contentRect
styleMask:NSTitledWindowMask
backing:NSBackingStoreBuffered
defer:YES];
if (self) {
[self setLevel:NSFloatingWindowLevel];
NSRect frameRect = [self frameRectForContentRect:contentRect];
NSView* view = [[[FloatWindowContentView alloc]
initWithFrame:frameRect] autorelease];
[self setContentView:view];
[self setAcceptsMouseMovedEvents:YES];
[self setIgnoresMouseEvents:NO];
}
return self;
}
- (BOOL)becomesKeyOnlyIfNeeded
{
return YES;
}
- (void)becomeMainWindow
{
NSLog(#"becomeMainWindow");
[super becomeMainWindow];
}
- (void)becomeKeyWindow
{
NSLog(#"becomeKeyWindow");
[super becomeKeyWindow];
}
#end
#implementation FloatWindowContentView
- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
{
return YES;
}
- (BOOL)acceptsFirstResponder
{
return YES;
}
- (id)initWithFrame:(NSRect)frameRect
{
self = [super initWithFrame:frameRect];
if (self) {
NSTrackingArea* area;
area = [[NSTrackingArea alloc] initWithRect:frameRect
options:NSTrackingActiveAlways|
NSTrackingMouseMoved|
NSTrackingMouseEnteredAndExited
owner:self
userInfo:nil];
[self addTrackingArea:area];
[area release];
}
return self;
}
- (void)drawRect:(NSRect)rect
{
[[NSColor redColor] set];
NSRectFill([self bounds]);
}
- (BOOL)becomeFirstResponder
{
NSLog(#"becomeFirstResponder");
return [super becomeFirstResponder];
}
#end
I think I find the right answer. This is somehow related to tell NSWindow to accept MouseMoved event. but what to my surprise is, The window should accept mouseMoved events isn't the Floating Window, but the current Key window. So the solution is simple, just enable key window to accept mouse moved events before starting tracking, and revert the switch after ending tracking.

Resources