NSOpenPanel breaks my SDL/OpenGL app - cocoa

I'm making a small SDL/OpenGL game, in which the user can select a map/level by using the cocoa open file-dialog (NSOpenPanel). However, when doing so, I get the error "invalid frame-buffer operation" upon every glClear. When I get the status of the frame buffer (using glCheckFramebufferStatus) it's GL_FRAMEBUFFER_UNDEFINED (0x8219). I also noticed that I do not need to present the open panel (using runModal), but only to create it, for the error to occur. It is possible to create it before the SDL_SetVideoMode, but not thereafter. Strangely, the NSSavePanel doesn't cause these issues at all. Any ideas?
Edit: Added some code to show a stripped down test-init method:
SDL_Init( SDL_INIT_VIDEO );
m_pScreen = SDL_SetVideoMode( 800, 600, 32, SDL_OPENGL );
// this section causes the problem. Works well if I change the NSOpenPanel to a NSSavePanel
#autoreleasepool {
NSOpenPanel *openPanel = [[NSOpenPanel openPanel] retain];
[openPanel runModal];
[openPanel release];
}
int number = glCheckFramebufferStatus(GL_FRAMEBUFFER);
assert(number == GL_FRAMEBUFFER_COMPLETE); // crash here

This usually happens because there's no current context. The OS-supplied code like NSOpenPanel can sometimes change the current OpenGL context, or leave the current context as undefined. You must make sure that you set the context back to the one you're drawing to when this happens. I hit this same problem in some code I'm working on last week! :-)

After some more testing (and reading the previous answers) I found a solution which works for me:
#autoreleasepool {
NSOpenGLContext *foo = [NSOpenGLContext currentContext];
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
[openPanel runModal];
[foo makeCurrentContext];
}

To work around this oddity I had to reset my view with SDL_SetVideoMode if frame buffer status != GL_FRAMEBUFFER_COMPLETE

Related

MAC Cocoa - Programmatically set window size

I have a one window application that has some checkboxes on the screen.
I use NSUserDefaults to store not only the state of the checkboxes but also the main window width, height, and position (x/y).
My issue is to find the right event to read and set the window properties.
Currently I do it at:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// read preferences
UserPreferences *userPrefs = [[UserPreferences alloc] init];
NSRect oldFrame = [window frame];
if( [userPrefs MainWindowWidth] > 0)
oldFrame.size.width = [userPrefs MainWindowWidth];
if( [userPrefs MainWindowHeight] > 0)
oldFrame.size.height = [userPrefs MainWindowHeight];
if( [userPrefs MainWindowTop] > 0)
oldFrame.origin.y = [userPrefs MainWindowTop];
if( [userPrefs MainWindowLeft] > 0)
oldFrame.origin.x = [userPrefs MainWindowLeft];
// set windows properties
[window setFrame:oldFrame display:YES animate:NO];
}
It works but the screen first shows default size and then changes to the stored size so visually a hiccup. This tells me that its too late in the event chain to set these parameters.
I also tried awakefromnib but that seems too early in the chain since setting width and height is simply ignored.
Which event would be the right one to plug this code in to reset the window right before it is show on screen?
Any advise would be appreciated. Every beginning is hard.
thank you.
This is because window's frame is first loaded from nib, and then window is shown (once finished loading from nib).
You can disable 'show window on start' checkbox in interface builder, and show it manually in applicationDidFinishLaunching.
The applicationDidFinishLaunching function is a place to do things, well... as soon as the app has finished launching. But what you really want is to catch the window at the time when it has just been loaded from the nib, but before it has shown. IOW, you're trying to do this in the wrong place.
You need more control over your window, so... create your own window controller! Create your own class which inherits from NSWindowController, say MyWindTrol. In the implementation file, add the awakeFromNib function, and put your efforts to control your window's size and location in there.
In your nib file, drag an NSObject from the library, declare it to be of class MyWindTrol, and control-drag the connections so that your MyWindTrol object's window property points to the window object.

UITextView setText should not jump to top in ios8

Following iOS 8 code is called every second:
- (void)appendString(NSString *)newString toTextView:(UITextView *)textView {
textView.scrollEnabled = NO;
textView.text = [NSString stringWithFormat:#"%#%#%#", textView.text, newString, #"\n"];
textView.scrollEnabled = YES;
[textView scrollRangeToVisible:NSMakeRange(textView.text.length, 0)];
}
The goal is to have the same scrolling down behaviour as the XCode console when the text starts running off the bottom. Unfortunately, setText causes the view to reset to the top before I can scroll down again with scrollRangeToVisible.
This was solved in iOS7 with the above code and it worked, but after upgrading last week to iOS8, that solution no longer seems to work anymore.
I can't figure out how to get this going fluently without the jumping behaviour?
I meet this problem too. You can try this.
textView.layoutManager.allowsNonContiguousLayout = NO;
refrence:http://hayatomo.com/2014/09/26/1307
The following two solutions don't work for me on iOS 8.0.
textView.scrollEnabled = NO;
[textView.setText: text];
textView.scrollEnabled = YES;
and
CGPoint offset = textView.contentOffset;
[textView.setText: text];
[textView setContentOffset:offset];
I setup a delegate to the textview to monitor the scroll event, and noticed that after my operation to restore the offset, the offset is reset to 0 again. So I instead use the main operation queue to make sure my restore operation happens after the "reset to 0" option.
Here's my solution that works for iOS 8.0.
CGPoint offset = self.textView.contentOffset;
self.textView.attributedText = replace;
[[NSOperationQueue mainQueue] addOperationWithBlock: ^{
[self.textView setContentOffset: offset];
}];
Try just to add text to UITextView (without scrollRangeToVisible/scrollEnabled). It seams that hack with scroll enabled/disabled is no more needed in iOS8 SDK. UITextView scrolls automatically.

Cocoa: User Notifications never being delivered

I'm trying to deliver a local notification, it looks something like this:
NSUserNotification *notification = [[NSUserNotification alloc] init];
//set title, subtitle, and sound
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
But the notification doesn't appear. I know sometimes notifications are not presented if the app is frontmost but at the time of delivery it's not. In system preferences I made sure that notifications from my app are allowed, and I even overrode the userNotificationCenter:shouldPresentNotification: method to always return YES but it still doesn't present the notification.
What is most confusing is that everything was working fine until I updated to Mavericks. I suppose something has changed in the update but I can't figure out what.
Thanks for the help.
my guess is that something is nil. make sure you are either assigning a (valid and non-nil) title, or informativeText.
I imagine that having invalid values for other properties such as otherButtonTitle might prevent the notification from being displayed as well.
Are there any error messages in your console?
Use the debugger or NSLog() statements to assess the values assigned to the notification. You could also see this problem if the NSUserNotification pointer is nil (not the case from the code you posted, but worth mentioning).
Here is a minimal test for an app delegate that works on Mac OS X 10.9 (Mavericks):
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSUserNotificationCenter* unc = [NSUserNotificationCenter defaultUserNotificationCenter];
unc.delegate = self;
NSUserNotification* notice = [[NSUserNotification alloc] init];
notice.title = #"title"; // notifications need a title, or informativeText at minimum to appear on screen
//notice.informativeText = #"informativeText";
NSLog(#"notification: %#, notification center:%#", notice, unc);
[unc deliverNotification:notice];
}
// The notifications will always dispaly even if we are in the foreground
- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification
{
return YES;
}

UITextField - message sent to deallocated instance "UIKBStringWideAttributeValueForKey:"

After enabling Zombie Objects I am able to see the following error when I try to edit a UITextField (textLvl):
2013-01-13 13:27:10.509 testob[18418:907] *** -[NSConcreteMutableAttributedString
_UIKBStringWideAttributeValueForKey:]: message sent to deallocated instance 0x2066a1f0
I have posted the portion of code that is causing the issue below, it seems to specifically be the "textField.text = self.storeText;" part - as when I comment this out the problem goes away.
You may be able to tell I am not the most experienced iOS dev, why would my UITextView deallocate after I've set the text? Help please!
Also, I've never heard of "_UIKBStringWideAttributeValueForKey" before - any ideas?
Thanks all!
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
NSLog(#"Text began editing");
self.storeText = textField.text;
textField.text = #"";
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
if (textField == textLvl){
if ([textField.text isEqualToString:#""]){
textField.text = self.storeText;
NSLog(#"No Text");
}
self.conv = [textField.text intValue];
if (self.conv >= 101){
textField.text = #"100";
UIAlertView *successAlert = [[UIAlertView alloc] initWithTitle:#"Oh no!" message:#"Can't be higher than 100." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[successAlert show]; }
}}
This might be a bug internal to the framework. I suggest you add - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField and set the textfield text to nil and then reset the textfield text.
I think the real answer here is that you're dealing with a UITextField that has been set to handle NSAttributedString rather than NSString. You'll notice if you're dealing with UITextField defined in a .xib, it's top property option is now "Text" with options Plain or Attributed.
If your text field was switched to attributed, you'll find this error happening if you continue to deal with the text field as if it were Plain.
My textfield was in a xib file and it's delegate was hooked up to the files owner. This was causing the crash for me, because the file's owner was NSObject.
I actually wanted to hook up the delegate to the cell, and not files owner.
Use instruments so see the retains/releases:
If you need to see where retains, releases and autoreleases occur for an object use instruments:
Run in instruments, in Allocations set "Record reference counts" on on (you have to stop recording to set the option). Cause the picker to run, stop recording, search for there ivar (datePickerView), drill down and you will be able to see where all retains, releases and autoreleases occurred.

How to get the frame (origin, Size) of every visible windows on the active space?

I'm trying to figure out how to get the frame of all visible windows.
I tried the following code, but it only works for the app itself other windows report {0,0,0,0}
NSArray *windowArray = [NSWindow windowNumbersWithOptions:NSWindowNumberListAllApplications | NSWindowNumberListAllSpaces];
for(NSNumber *number in windowArray){
NSLog(#"Window number: %#", number);
NSWindow *window = [[NSApplication sharedApplication] windowWithWindowNumber:[number intValue]];
NSLog(#"Window: %#", NSStringFromRect( [[window contentView] frame]));
}
Sample code is appreciated.
I figured it out:
NSMutableArray *windows = (__bridge NSMutableArray *)CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID);
for (NSDictionary *window in windows) {
NSString *name = [window objectForKey:#"kCGWindowName" ];
CGRect bounds;
CGRectMakeWithDictionaryRepresentation((CFDictionaryRef)[window objectForKey:#"kCGWindowBounds"], &bounds);
NSLog(#"%#: %#",name,NSStringFromRect(bounds));
}
You can't create an NSWindow for a window of another application. In general, you can't access the objects of other applications except through an interface that they cooperate with, like scripting.
You can get what you're looking for using the Quartz Window Services (a.k.a. CGWindowList) API.
I'm not at all sure that the window numbers returned by Cocoa are the same as the window numbers used by that API. In fact, the docs for -[NSWindow windowNumber] specifically say "note that this isn’t the same as the global window number assigned by the window server". I'm note sure to what use you can put the window numbers returned by +[NSWindow windowNumbersWithOptions:] which are not for your application's windows.

Resources