 |
 |
NSWindow resizing problem
|
 |
|
 |
|
Mac Enthusiast
Join Date: Feb 2000
Location: Storrs,Connecticut, USA
Status:
Offline
|
|
I have a strange problem with Window resizing in Cocoa. I wanted to give the user the ability to resize the window. Since I need to move around and resize a bunch of NSViews I posted an observer for NSWindowDidResizeNotification. Now, in my program, the NSView objects that I have would look pretty funky if they were able to be resized freely. So, in part of the method that is called from the notification I programmatically keep the proportions correct. Basically, the length of one side is dependent upon the length that the user dragged for the other. It appears that the resized NSWindow isn't redrawn until after the notification has executed, which is good because it prevents flicker. As a result of this special resizing, however the window no longer respect the user limitation of resizing the window only to a few pixels above the bottom of the screen. I don't really care about that. What I do care about is the fact that when I resize the window so that the bottom is below the bottom of the screen my program crashes, immediately, with signal 11. I thought that windows could be placed on the screen with coordinates ranging from +16000 to -16000 with (0,0) being the lower left hand corner of the screen. resizing the window like that does NOT violate those limits. Actually I can drag the window such that it's bottom is below the bottom of the screen and nothing bad happens. It will crash when the bottom of the window is resized beyond the bottom of the screen, regardless of the resolution. So... can anyone tell me why this is doing this and what I can do to keep it from crashing?
|
|
|
| |
|
|
|
 |
|
 |
|
Fresh-Faced Recruit
Join Date: Jan 2001
Location: San Jose, CA USA
Status:
Offline
|
|
This could be an AppKit bug. But no one's going to be able to tell unless you post a backtrace of the exception. Run your app in PB's debugger and the debugger should stop at the point of the crash. To get a backtrace for us, type "bt" into the gdb console at the top of the window and paste the resulting output into a message. Preferably you should also submit this in feedback to Apple as a bug report, if the crash does look like it's occurring in AppKit and not your code.
BTW, are you really sure that you have to implement custom resize behavior for your views rather than using the usual "springs and struts"? That's unusual; I've never had to do it.
|
|
|
| |
|
|
|
 |
|
 |
|
Mac Enthusiast
Join Date: Feb 2000
Location: Storrs,Connecticut, USA
Status:
Offline
|
|
Code:
Okay, here's the backtrace. All of those calls to [gameController resizeGameWindow] and all of those notifications are probably because gameController was set as an observer for the NSWindowDidResizeNotification. The backtrace was so long I left out everything after line 100. (It were 1600 lines) I figured that the problem probably occurred in the last call to resizeGameWindow but I thought that I should leave in some extra just in case. I did figure out a workaround for this, so it isn't a problem for me anymore. I'm still wondering if this is a bug with AppKit. If you think that it looks like a bug in AppKit then I'll send the complete backtrace to Apple.
GNU gdb 4.18.1-20000320 (Apple version gdb-172) (UI_OUT)
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "powerpc-apple-macos10".
(gdb) (gdb) (gdb) (gdb) (gdb) Reading symbols for shared libraries ... done
run
[Switching to thread 1 (process 321 thread 0x6003)]
unable to read unknown load command 0x12
unable to read unknown load command 0x12
unable to read unknown load command 0x12
unable to read unknown load command 0x12
unable to read unknown load command 0x12
Reading symbols for shared libraries ....................................... done
Reading symbols for shared libraries .... done
Reading symbols for shared libraries .. done
Program received signal EXC_BAD_ACCESS, Could not access memory.
0x4b84349c in __CFRecordAllocationEvent ()
(gdb) bt
#0 0x4b84349c in __CFRecordAllocationEvent ()
#1 0x9aab984c in NSIncrementExtraRefCount ()
#2 0x9aab984c in NSIncrementExtraRefCount ()
#3 0x9aab975c in -[NSObject retain] ()
#4 0x45b92074 in -[NSViewHierarchyLock lockForWriting] ()
#5 0x45b92024 in -[NSWindow _lockViewHierarchyForModification] ()
#6 0x45b96328 in -[NSWindow _setFrameCommon:display:stashSize:] ()
#7 0x45b961e8 in -[NSWindow setFrame:display:] ()
#8 0x00004f2c in -[GameController resizeGameWindow] (self=0x91f760, _cmd=0x6578) at GameController.m:297
#9 0x9aac9328 in _nsNotificationCenterCallBack ()
#10 0x4b873784 in _postNotification ()
#11 0x4b871b1c in _CFNotificationCenterPostLocalNotification ()
#12 0x4b867288 in _CFNotificationCenterPostNotification ()
#13 0x9aac0a64 in -[NSNotificationCenter postNotificationName:object:userInfo:flags:] ()
#14 0x9aac80a4 in -[NSNotificationCenter postNotificationName:object:] ()
#15 0x45b963b8 in -[NSWindow _setFrameCommon:display:stashSize:] ()
#16 0x45b961e8 in -[NSWindow setFrame:display:] ()
#17 0x00004f2c in -[GameController resizeGameWindow] (self=0x91f760, _cmd=0x6578) at GameController.m:297
#18 0x9aac9328 in _nsNotificationCenterCallBack ()
#19 0x4b873784 in _postNotification ()
#20 0x4b871b1c in _CFNotificationCenterPostLocalNotification ()
#21 0x4b867288 in _CFNotificationCenterPostNotification ()
#22 0x9aac0a64 in -[NSNotificationCenter postNotificationName:object:userInfo:flags:] ()
#23 0x9aac80a4 in -[NSNotificationCenter postNotificationName:object:] ()
#24 0x45b963b8 in -[NSWindow _setFrameCommon:display:stashSize:] ()
#25 0x45b961e8 in -[NSWindow setFrame:display:] ()
#26 0x00004f2c in -[GameController resizeGameWindow] (self=0x91f760, _cmd=0x6578) at GameController.m:297
#27 0x9aac9328 in _nsNotificationCenterCallBack ()
#28 0x4b873784 in _postNotification ()
#29 0x4b871b1c in _CFNotificationCenterPostLocalNotification ()
#30 0x4b867288 in _CFNotificationCenterPostNotification ()
#31 0x9aac0a64 in -[NSNotificationCenter postNotificationName:object:userInfo:flags:] ()
#32 0x9aac80a4 in -[NSNotificationCenter postNotificationName:object:] ()
#33 0x45b963b8 in -[NSWindow _setFrameCommon:display:stashSize:] ()
#34 0x45b961e8 in -[NSWindow setFrame:display:] ()
#35 0x00004f2c in -[GameController resizeGameWindow] (self=0x91f760, _cmd=0x6578) at GameController.m:297
#36 0x9aac9328 in _nsNotificationCenterCallBack ()
#37 0x4b873784 in _postNotification ()
#38 0x4b871b1c in _CFNotificationCenterPostLocalNotification ()
#39 0x4b867288 in _CFNotificationCenterPostNotification ()
#40 0x9aac0a64 in -[NSNotificationCenter postNotificationName:object:userInfo:flags:] ()
#41 0x9aac80a4 in -[NSNotificationCenter postNotificationName:object:] ()
#42 0x45b963b8 in -[NSWindow _setFrameCommon:display:stashSize:] ()
#43 0x45b961e8 in -[NSWindow setFrame:display:] ()
#44 0x00004f2c in -[GameController resizeGameWindow] (self=0x91f760, _cmd=0x6578) at GameController.m:297
#45 0x9aac9328 in _nsNotificationCenterCallBack ()
#46 0x4b873784 in _postNotification ()
#47 0x4b871b1c in _CFNotificationCenterPostLocalNotification ()
#48 0x4b867288 in _CFNotificationCenterPostNotification ()
#49 0x9aac0a64 in -[NSNotificationCenter postNotificationName:object:userInfo:flags:] ()
#50 0x9aac80a4 in -[NSNotificationCenter postNotificationName:object:] ()
#51 0x45b963b8 in -[NSWindow _setFrameCommon:display:stashSize:] ()
#52 0x45b961e8 in -[NSWindow setFrame:display:] ()
#53 0x00004f2c in -[GameController resizeGameWindow] (self=0x91f760, _cmd=0x6578) at GameController.m:297
#54 0x9aac9328 in _nsNotificationCenterCallBack ()
#55 0x4b873784 in _postNotification ()
#56 0x4b871b1c in _CFNotificationCenterPostLocalNotification ()
#57 0x4b867288 in _CFNotificationCenterPostNotification ()
#58 0x9aac0a64 in -[NSNotificationCenter postNotificationName:object:userInfo:flags:] ()
#59 0x9aac80a4 in -[NSNotificationCenter postNotificationName:object:] ()
#60 0x45b963b8 in -[NSWindow _setFrameCommon:display:stashSize:] ()
#61 0x45b961e8 in -[NSWindow setFrame:display:] ()
#62 0x00004f2c in -[GameController resizeGameWindow] (self=0x91f760, _cmd=0x6578) at GameController.m:297
#63 0x9aac9328 in _nsNotificationCenterCallBack ()
#64 0x4b873784 in _postNotification ()
#65 0x4b871b1c in _CFNotificationCenterPostLocalNotification ()
#66 0x4b867288 in _CFNotificationCenterPostNotification ()
#67 0x9aac0a64 in -[NSNotificationCenter postNotificationName:object:userInfo:flags:] ()
#68 0x9aac80a4 in -[NSNotificationCenter postNotificationName:object:] ()
#69 0x45b963b8 in -[NSWindow _setFrameCommon:display:stashSize:] ()
#70 0x45b961e8 in -[NSWindow setFrame:display:] ()
#71 0x00004f2c in -[GameController resizeGameWindow] (self=0x91f760, _cmd=0x6578) at GameController.m:297
#72 0x9aac9328 in _nsNotificationCenterCallBack ()
#73 0x4b873784 in _postNotification ()
#74 0x4b871b1c in _CFNotificationCenterPostLocalNotification ()
#75 0x4b867288 in _CFNotificationCenterPostNotification ()
#76 0x9aac0a64 in -[NSNotificationCenter postNotificationName:object:userInfo:flags:] ()
#77 0x9aac80a4 in -[NSNotificationCenter postNotificationName:object:] ()
#78 0x45b963b8 in -[NSWindow _setFrameCommon:display:stashSize:] ()
#79 0x45b961e8 in -[NSWindow setFrame:display:] ()
#80 0x00004f2c in -[GameController resizeGameWindow] (self=0x91f760, _cmd=0x6578) at GameController.m:297
#81 0x9aac9328 in _nsNotificationCenterCallBack ()
#82 0x4b873784 in _postNotification ()
#83 0x4b871b1c in _CFNotificationCenterPostLocalNotification ()
#84 0x4b867288 in _CFNotificationCenterPostNotification ()
#85 0x9aac0a64 in -[NSNotificationCenter postNotificationName:object:userInfo:flags:] ()
#86 0x9aac80a4 in -[NSNotificationCenter postNotificationName:object:] ()
#87 0x45b963b8 in -[NSWindow _setFrameCommon:display:stashSize:] ()
#88 0x45b961e8 in -[NSWindow setFrame:display:] ()
#89 0x00004f2c in -[GameController resizeGameWindow] (self=0x91f760, _cmd=0x6578) at GameController.m:297
#90 0x9aac9328 in _nsNotificationCenterCallBack ()
#91 0x4b873784 in _postNotification ()
#92 0x4b871b1c in _CFNotificationCenterPostLocalNotification ()
#93 0x4b867288 in _CFNotificationCenterPostNotification ()
#94 0x9aac0a64 in -[NSNotificationCenter postNotificationName:object:userInfo:flags:] ()
#95 0x9aac80a4 in -[NSNotificationCenter postNotificationName:object:] ()
#96 0x45b963b8 in -[NSWindow _setFrameCommon:display:stashSize:] ()
#97 0x45b961e8 in -[NSWindow setFrame:display:] ()
#98 0x00004f2c in -[GameController resizeGameWindow] (self=0x91f760, _cmd=0x6578) at GameController.m:297
#99 0x9aac9328 in _nsNotificationCenterCallBack ()
#100 0x4b873784 in _postNotification ()
|
|
|
| |
|
|
|
 |
|
 |
|
Mac Enthusiast
Join Date: Feb 2000
Location: Storrs,Connecticut, USA
Status:
Offline
|
|
BTW, what are spring and struts that you described? Are they those springy things that you can turn into straight lines by clicking in the inspector in Interface Builder? They never seem to do anything for me. I really have no idea what they are supposed to do because they don't work.
Anyway I have multiple NSView objects in my window, only one of which is supposed to change size as the window is resized, but all of which move around as the window is resized. The one that changes size is supposed to keep the same proportions all of the time. The ratio of the lengths of adjacent sides of the window isn't constant. That's why I could see no way to allow the user to resize the window properly without implementing custom resize behavior. I've seen other programs do this, but very few. I don't think that this is an issue that comes up much.
|
|
|
| |
|
|
|
 |
|
 |
|
Dedicated MacNNer
Join Date: Jan 2001
Location: Virginia, US
Status:
Offline
|
|
Your code has infinite recursion. It's crashing when it's run out of stack space. :-) Since you're calling setFrame:display: on the window, it's posting the size changed notification again, your method gets called, you call setFrame:display: again, etc.
First off, if you're just trying to keep the same aspect ratio on the window, then you might be best off just by calling the -setAspectRatio: method on NSWindow. That should keep the same shape automatically.
If that's not exactly what you want, then I'd recommend using the -windowWillResize:toSize: delegate method, which gives you a chance to alter the proposed size before the window actually changes. It's a much much cleaner way to do it.
If you want to stick with what you have, then you'll have to remove yourself as an observer while calling setFrame:display: or keep an instance variable that's set to YES while calling setFrame:display: and make sure to abort out at the top if the variable is YES when you're called.
NSViews have methods to turn off resizing notifications when you resize them to avoid situations like this, but NSWindow doesn't (mainly because there are better alternatives, listed above).
Originally posted by Dalgo:
BTW, what are spring and struts that you described? Are they those springy things that you can turn into straight lines by clicking in the inspector in Interface Builder? They never seem to do anything for me. I really have no idea what they are supposed to do because they don't work.
Yes, those are the springs and struts. They work just fine. See the NSView class documentation.
Anyway I have multiple NSView objects in my window, only one of which is supposed to change size as the window is resized, but all of which move around as the window is resized. The one that changes size is supposed to keep the same proportions all of the time. The ratio of the lengths of adjacent sides of the window isn't constant. That's why I could see no way to allow the user to resize the window properly without implementing custom resize behavior. I've seen other programs do this, but very few. I don't think that this is an issue that comes up much.
Ah, OK. In that case, the view that is supposed to resize should have its interior sprintg set, but no springs on the outside edges (allowing the view to resize in either dimension but keeping its edges fixed relative to the edges of the window). All of the other views should have the interior springs off (meaning they never resize when the window resizes), and also springs off for the edges that you want the view to "stick" to when the window resizes. For example, if you want a button to stick in the bottom left corner of the window, the bottom and left should be set as struts, and the top and right set as springs.
It does sound as though you'll need to implement the window delegate method, as the resizing behavior is a bit custom.
|
|
|
| |
|
|
|
 |
|
 |
|
Mac Enthusiast
Join Date: Feb 2000
Location: Storrs,Connecticut, USA
Status:
Offline
|
|
Thanks. At least now I know what those springs and struts do. I doubt that the reason that it was crashing was a result of too many notifications because it only crashed when I resized the bottom of the window below the bottom of the screen. I could resize the window all over the place and it wouldn't crash until I moved it below the bottom of the screen. I have a feeling that the setFrame: display: only sends the notification if the size of the window actually changes. This would mean that when the user begins moving the mouse a notification is sent. and my method then calls setFrame: display: on it's own, and another notification is sent, but when my method responds to that notification and calls setFrame: display: again no notification is sent. Out. If a constant stream of notification was always going out it would never pay attention to the user resizing the window after the first move and the spinning beachball should come up and then it should crash. I will change my method, however, in order to prevent multiple notifications from doing anything.
One problem, though. The setAspectRatio method doesn't work! I called it in my awakeFromNid method, before the window appears, (It's not set to display automatically on program launch) and once the window appears it seems to be behaving appropriately, but the second I click on the resize widget or the zoom box the window vanishes and no amount of makeKeyAndOrderFront can bring it back. There are no errors in the console on compilation or when I run the program. The window is not set to release on close, and I had disabled my observer for NSWindowDidResizeNotification. However, I tried subclassing NSWindow and putting a call to setAspectRatio in the init method. The window didn't suddenly disappear when I clicked the zoom button or the resize widget; it just didn't obey the aspect ratio at all. I could resize it to any proportions. So them I tried using the (void)setResizeIncrements  NSSize)increments method. That didn't so anything whether I put it in awakeFromNib or in init.
So... What is my problem? Do these windows just hate me resizing them or what?
[This message has been edited by Dalgo (edited 01-28-2001).]
|
|
|
| |
|
|
|
 |
|
 |
|
Dedicated MacNNer
Join Date: Jan 2001
Location: Virginia, US
Status:
Offline
|
|
Originally posted by Dalgo:
I doubt that the reason that it was crashing was a result of too many notifications because it only crashed when I resized the bottom of the window below the bottom of the screen. I could resize the window all over the place and it wouldn't crash until I moved it below the bottom of the screen.
OK, then NSWindow will not post another size changed notification for any changes made to the size while posting a size change notification. This protects against most problems of the sort you're facing, so that makes sense. However, there must be some other code called later that ensures the window doesn't overlap the Dock. It appears that if *this* code changes the window frame, the size changed notification will be called again. This would cause the behavior you're seeing. The backtrace you posted is definitely an infinite-recursion problem.
One problem, though. The setAspectRatio method doesn't work! I called it in my awakeFromNid method, before the window appears, (It's not set to display automatically on program launch) and once the window appears it seems to be behaving appropriately, but the second I click on the resize widget or the zoom box the window vanishes and no amount of makeKeyAndOrderFront can bring it back. There are no errors in the console on compilation or when I run the program. The window is not set to release on close, and I had disabled my observer for NSWindowDidResizeNotification.
Very, very strange. I don't understand this one at all -- never seen it. I can only guess that the window is being moved very far off-screen -- some mathematical error when calculating a new frame.
However, I tried subclassing NSWindow and putting a call to setAspectRatio in the init method. The window didn't suddenly disappear when I clicked the zoom button or the resize widget; it just didn't obey the aspect ratio at all.
NSWindow's designated initializer is -initWithContentRect:styleMask:backing:defer:. The -init method will generally not get called on NSWindow, particularly when coming out of a .nib.
I could resize it to any proportions. So them I tried using the (void)setResizeIncrements NSSize)increments method. That didn't so anything whether I put it in awakeFromNib or in init.
Dunno about this either. A call to -setAspectRatio: will cancel the resizeIncrements setting, if that helps. These settings are usually best done by a controller after the nib has been loaded but before you call -makeKeyAndOrderFront:. If you're using an NSWindowController, you can do it in -windowDidLoad; if you're using NSDocument, you can do it in -windowControllerDidLoadNib:. -awakeFromNib should work though. Sometimes it helps to put in logging statements (or break in the debugger) on the method to make sure it's being called, or to make sure the variable pointing to the NSWindow is actually set (isn't nil), etc.
For your original problem, I still think you should set the window's delegate to be your controller object, and implement the -windowWillResize:toSize: delegate method.
|
|
|
| |
|
|
|
 |
 |
|
 |
|
|
|
|
|

|
|
 |
Forum Rules
|
 |
 |
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
|
HTML code is Off
|
|
|
|
|
|
 |
 |
 |
 |
|
 |
|