full screen window problem

I don’t know the objective c language so I’m hoping somebody can help me with this. In my application I’m using a full screen mode using the code from this MacOSX Hints comment… here

My problem is that when I enter the full screen mode it’s not actually my application’s window that’s going full screen. It looks to me that the code is creating a new window instead of using my window, and therefore none of the interface elements I created for my application show up in the full screen window.

So my question is this, how can I make that code from MacOSX Hints use my window for the full screen window?

Hi regulus,

the problem is - you can’t. When creating an NSWindow a stylemask is used which can’t be altered afterwards - so a window either has a title bar (your 'normal window from Interface Builder) - or it hasn’t (the fullscreen window). What you could do, is to swap the content from your window to the fullscreen window when starting the mode - and swap it back when ending. this could look like so:

[code]// file: FullScreenWindow.m (no ‘.h’ needed)

#import <Cocoa/Cocoa.h>

@interface FullScreenWindow: NSWindow {}
@end

@implementation FullScreenWindow

  • (BOOL) canBecomeKeyWindow {
    return YES;
    }
    @end

@interface NSWindow (ASKAFullScreen)

  • (NSWindow *)beginFullScreen;
  • (void)endFullScreen;
    @end

FullScreenWindow *fsWindow;

@implementation NSWindow (ASKAFullScreen)

  • (NSWindow *)beginFullScreen
    { fsWindow = [
    [FullScreenWindow alloc]
    initWithContentRect:[[NSScreen mainScreen] frame]
    styleMask:NSBorderlessWindowMask
    backing:NSBackingStoreBuffered
    defer:NO];
    [NSMenu setMenuBarVisible:NO];
    [fsWindow setHasShadow:NO];
    [fsWindow setContentView:[self contentView]];

    [fsWindow makeKeyAndOrderFront];
    [self orderOut:nil];
    return fsWindow;
    }

  • (void)endFullScreen
    { [NSMenu setMenuBarVisible:YES];
    [self setContentView:[fsWindow contentView]];
    [self orderFront:nil];
    [fsWindow orderOut:nil];
    [fsWindow release];
    }
    @end[/code]
    and the calls from AppleScript:

set theWindow to (call method "beginFullScreen" of (window "main"))

call method "endFullScreen" of (window "main")

regards,

Dominik

Thanks again Dominik! I appreciate your taking the time to help me. That works except I’m having one small problem with it. The problem is because of the way my window is set up. Maybe you have an idea how I can fix it because I can’t figure it out.

In my window, I have an image view and a custom view. It’s the custom view I’m having trouble with. I have buttons in the custom view and it’s connected to “mouse entered” and “mouse exited” calls. When my mouse enters the area of the custom view I make the buttons visible so I can click them. When my mouse exits the custom view I make the buttons invisible so I don’t have to look at them because I want to see the image in the image view without distraction.

So here’s what’s happening. I mouse over the custom view in my normal window, the buttons become visible, I press the button to go full screen using your code, and the window goes full screen… as it should. But here’s the problem, the buttons are visible in the full screen window. Moving my mouse over the custom view area doesn’t make the buttons visible/invisible any more. They’re stuck being visible. I can still click the buttons but the mouse entered/exited handlers aren’t being recognized. The same thing happens when I exit full screen mode.

One of my buttons displays an alert message attached to the main window. I found if I click that button to display the alert message, then after I dismiss the alert message I can then use the mouse handlers as normal. Here’s how I have my handlers set up…

on mouse entered theObject event theEvent
tell window of theObject
set visible of button “buttonFullScreen” of theObject to true
end tell
end mouse entered

on mouse exited theObject event theEvent
tell window of theObject
set visible of button “buttonFullScreen” of theObject to false
end tell
end mouse exited

Any ideas?

regulus,

do you have your buttons ‘in’ the custom view (= subviews) or are they just placed over it?
Guessing from your script they are subviews. Then this should work:

on mouse entered theObject event theEvent
	set visible of button "buttonFullScreen" of theObject to true
end mouse entered

on mouse exited theObject event theEvent
	set visible of button "buttonFullScreen" of theObject to false
end mouse exited

The window should not be referenced explicitely since it’s already contained in ‘theObject’.

I am not really sure what this alert window effect means … please tell me if this did not solve your problem …

D.

You’re right about not needing the tell window part… although it’s funny that I wasn’t getting any errors with that code. But I removed it and still I have the same problem. My buttons are “in” the custom view.

As a check to see if the button calls impacted the mouse handlers, I made a menu item to make the window go full screen. So now I run my app, the buttons are not showing, I go to the menu item and select the full screen mode. The app goes full screen but again when I mouse over the custom view area the buttons don’t appear. I made a shorcut in the menu to call the alert dialog, so when I’m in full screen I can call the alert from the keyboard… and when I call the alert (and dismiss it) the custom view works normally.

One thing to note is that when I try to quit the application after going through this routine something strange happens. Another instance of my application launches (I can see it in the dock). For a few seconds my mouse cursor is the spinning wheel. Then that instance closes by itself, and my app is still running (it didn’t quit) but the normal window of my app is now empty of anything that was in it. I can then quit that instance with no troubles. This had ahppened before but I thought the problem was related to the custom view and the buttons…

Note that if I run my app in its normal window without going full screen this quitting problem doesn’t happen. Also I can run my app, enter full screen, and quit the app using cmd-q and this problem doesn’t happen. But if I run my app, enter full screen mode, exit full screen mode, then quit… then I have the quit problem.

this is the error message from the run log when the quit problem happens…
ImageViewer has exited due to signal 11 (SIGSEGV)

Hi regulus,

your strange effect/second instance of the app effect is easy to explain - there is a mistake (my mistake) in the memory management of FullScreen.m. The second app ist automatically started by Xcode in debugging mode in such a case …
I really can’t see currently where the problem exactly is - but I think there is a better solution for you anyway: instead of creating the fullscreen window on the fly everytime - like suggested in the macosxhints code - you create it once in Interface Builder. A further advantage is, that you now can give it an AppleScript name and address it directly.

Just add a second window to your nib and create/use a subclass for it:

[code] // FSWindow.m
#import <Cocoa/Cocoa.h>

@interface FSWindow : NSWindow {}
@end

@implementation FSWindow

  • (id)initWithContentRect:(NSRect)contentRect styleMask:(unsigned int)styleMask backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation{
    self = [super initWithContentRect:[[NSScreen mainScreen] frame]
    styleMask:NSBorderlessWindowMask
    backing:bufferingType
    defer:deferCreation];
    if (self != nil) {
    [self setHasShadow:NO];
    }
    return self;
    }

  • (BOOL) canBecomeKeyWindow {
    return YES;
    }

@end[/code]
now you can do all the swapping and hiding in the script:

on clicked theObject
    if (name of theObject is "fs_start") then
        call method "setMenuBarVisible:" of class "NSMenu" with parameter no
        my swapWindows(window "main", window "fs_main")
    else if (name of theObject is "fs_end") then
        call method "setMenuBarVisible:" of class "NSMenu" with parameter yes
        my swapWindows(window "fs_main", window "main")
    end if
end clicked

on swapWindows(fromWindow, toWindow)
    call method "setContentView:" of toWindow with parameter (call method "contentView" of fromWindow)
    set visible of fromWindow to false
    set visible of toWindow to true
end swapWindows

Unfortunately I haven’t found a satisfying AppleScript solution for your mouseover problem - do you want to show and hide all subviews/buttons of the view on mouseover at once? then you might use a little custom view class doing this job:

[code]#import <Cocoa/Cocoa.h>

@interface MouseOverFieldView : NSView
{
NSTrackingRectTag tag;
}
@end

@implementation MouseOverFieldView

  • (id)initWithFrame:(NSRect)frameRect
    {
    if ((self = [super initWithFrame:frameRect]) != nil) {
    tag = -1;
    }
    return self;
    }

  • (void)drawRect:(NSRect)Rect {}

  • (void)viewDidMoveToWindow
    {
    if (tag != -1 ) [self removeTrackingRect:tag];
    tag = [self addTrackingRect:[self bounds] owner:self userData:nil assumeInside:NO];
    [super viewDidMoveToWindow];
    }

  • (void)mouseEntered:(NSEvent *)theEvent
    {
    NSArray *btns = [self subviews];
    NSEnumerator *enumerator = [btns objectEnumerator];
    id btn;
    while (btn = [enumerator nextObject]) {
    [(NSView *)btn setHidden:NO];
    }
    }

  • (void)mouseExited:(NSEvent *)theEvent
    {
    NSArray *btns = [self subviews];
    NSEnumerator *enumerator = [btns objectEnumerator];
    id btn;
    while (btn = [enumerator nextObject]) {
    [(NSView *)btn setHidden:YES];
    }
    }[/code]

That works really well Dominik! I appreciate all the time you put into this. The full screen window was simple to implement and the swapping of the windows works well. There’s no more memory error problem.

I still had the mouse-over menu problem though. I tried toggling the buttons on/off to see if that would fix the problem but it wouldn’t. The only thing that fixes it is to display an alert message as I mentioned. I’m wondering what it is about the alert message. It’s almost as if when the windows are switched the custom view (with the buttons) isn’t a front view (this view is on top of the image view but not “in” the image view) and somehow the alert message makes it the front view so it can recognize the mouse-over events.

Anyway, I tried implementing your code for the custom mouse-over code but couldn’t get it to work. Here’s what I tried… I created a subclass of the NSView class with your code, and attached that custom class to my custom view. Then I unchecked the mouse-over commands for the custom view in interface builder. On running the application nothing happened in either the regular window or the full screen window. I then went back to interface builder and checked the mouseover commands, but again nothing happened. I feel I need to call this custom class somehow when I mouseover the area, but I don’t know how.

Any advice??? :smiley:

Wait! I got it working. I renamed my custom class to “MouseOverFieldView” which I saw you called it in your code and now it works. Great! Now the buttons show/hide properly. Thank you, thank you Dominik!

Maybe you have a simple solution for this. I wanted a background color for my custom view so that the buttons look as if they’re on a palette of some kind rather than floating in mid air. So after some research I found I could modify the drawRect portion of the mouseover code like so…

  • (void)drawRect:(NSRect)Rect {
    NSRect myRect = NSMakeRect (0,0,79,215);
    [[NSColor darkGrayColor] set];
    NSRectFill ( myRect );
    }

This does indeed draw the dark grey background for me, but obviously the background is drawn all the time even when the buttons aren’t showing. My question is how can I do this but only have the background drawn when the buttons are visble. I tried adding the NSRectFill part to the mouseEntered handler but that gave me an error because myRect isn’t defined in that handler.

I really don’t want to take up any more of your time. You’ve done more than enough! But if you can quickly see the solution then that would be great. If it’s more involved then please don’t waste your time because it’s not a big deal.

My thinking is that I could draw the darkGrayColor when the butons are visible and draw a clearColor when the buttons are not visible. My other attempt at this was to add a text field to the custom view, and give the text field a background color. This worked except the text field showed on top of the buttons… even when I used “send to back” for its layout.

Never mind! I found a solution. I created a second custom view, added a gray picture to it, gave it the custom mouseover class, and placed it underneath my buttons custom view. It works!

I found a problem with the mouseover class. If I launch the application with the same window size as I have built in interface builder then I have no problems. But if my application launches with the main window being a different size from the window I built in iterface builder then the mouseover area is not matched to the actual location of my cutom view on the screen. The mouseover area is always defined by its position away from the lower left corner of the window I built in interface builder. But my custom view moves depending on the window size. If I launch my application’s window at the size from interface builder, I can change the size of the window after my application launches with no problems. The problem only happens when the initially launched window is a different size from the interface builder built window.

That’s the way it happens when I have my custom view pinned to stay in the upper left corner of the window. Everything gets messed up if I have the custom view pinned to another corner of the window or have it stay in the middle of one of the edges of the window. In these cases I can’t even change the window size without the mouseover and actual locations of my custom view becoming unmatched.

Any ideas how to solve this?

Hi regulus,

that’s true - you need to update the tracking rect when the window is resized. I’ve added a method you can call from outside (using your window’s ‘resized’-Handler) and I have added the drawing of a grey background (only when the mouse is inside):

[code]#import <Cocoa/Cocoa.h>

@interface MouseOverFieldView : NSView
{
NSTrackingRectTag tag;
BOOL mouseinside;
}
- (void)updateTrackingRect;
@end

@implementation MouseOverFieldView

  • (id)initWithFrame:(NSRect)frameRect
    {
    if ((self = [super initWithFrame:frameRect]) != nil) {
    tag = -1;
    mouseinside = NO;
    }
    return self;
    }

  • (void)drawRect:(NSRect)rect {
    if (mouseinside) {
    [[NSColor darkGrayColor] set];
    NSRectFill (rect);
    }
    }

  • (void)viewDidMoveToWindow
    {
    [self updateTrackingRect];
    [super viewDidMoveToWindow];
    }

  • (void)updateTrackingRect{
    if (tag != -1 ) [self removeTrackingRect:tag];
    tag = [self addTrackingRect:[self bounds] owner:self userData:nil assumeInside:NO];
    }

  • (void)mouseEntered:(NSEvent *)theEvent
    {
    mouseinside = YES;
    NSArray *btns = [self subviews];
    NSEnumerator *enumerator = [btns objectEnumerator];
    id btn;
    while (btn = [enumerator nextObject]) {
    [(NSView *)btn setHidden:NO];
    }
    [self setNeedsDisplay:YES];
    }

  • (void)mouseExited:(NSEvent *)theEvent
    {
    mouseinside = NO;
    NSArray *btns = [self subviews];
    NSEnumerator *enumerator = [btns objectEnumerator];
    id btn;
    while (btn = [enumerator nextObject]) {
    [(NSView *)btn setHidden:YES];
    }
    [self setNeedsDisplay:YES];
    }
    @end[/code]

on resized theObject
    call method "updateTrackingRect" of (view "view" of window "main")
end resized

Thanks again Dominik! The gray background works great.

I’m troubleshooting the “resize” code now. I’m having a couple problems. At application launch time I get an error. It seems the “on resized” handler gets called first, before any objects on the window exist, so it errors because it can’t find the custom view. Once I get around the first error, the new code works really well in my main window. I can move/resize the window and everything stays in sync. I’m having a problem after I enter and exit full screen mode too though. After exiting I have no problems. But after I then resize the main window the mouseover area gets unsynced again.

I’m working on solving these errors. I think I can do it by calling the “updateTrackingRect” in other handlers too. I’ll let you know how I make out.

OK, the problem at launch was easily fixed. I just put a try block around the code in the “on resized” handler to ignore the error. Then I put the code in the “on idle” handler which updates the location properly at launch. This allows me to be able to save the window size/position from the last time I quit the application and have the window reopen where it was the next time I launch the application without any problems.

I’ll work on the enter/leave full screen mode problem now.

No! :frowning:
I can’t solve it. No matter what I try it’s always the same problem. It happens after I resize the main window after I’ve exited full screen mode. The rest of the time it’s fine. I’m wondering if it’s a bug in applescript studio. It might be a mouse tracking bug.

Dominik has graciously been helping solve the mouseover problem off-line, and now after 2 days he has it working perfect. Thank you Dominik! So to finish this topic here’s the final results. This will yield a mouseover area where you can have buttons show/hide when mousing over the area.

[code]property isAwake : false

on awake from nib theObject
set isAwake to true
call method “addTrackingRect” of (view “buttonView” of window “main”)
set visible of buttons of view “buttonView” of window “main” to false
end awake from nib

on resized theObject
if (isAwake) then
call method “updateTrackingRect” of (view “buttonView” of window “main”)
end if
end resized[/code]
In interface builder add a custom view to your main window. Connect the “awake from nib” and “resized” applescript handlers to the custom view. Inside the custom view place the buttons that you want to show/hide on mouseover. Add a custom class in interface builder under the NSView class and call it MouseOverFieldView. Connect this custom class to your custom view. Then back in Xcode code add the following to your MouseOverFieldView.m file. You don’t need a MouseOverFieldView.h file. Look here if you don’t know how to add a custom class in interface builder.

[code]#import <Cocoa/Cocoa.h>

@interface MouseOverFieldView : NSView
{
NSTrackingRectTag tag;
BOOL mouseinside;
}

  • (void)updateTrackingRect;
  • (void)addTrackingRect;
  • (void)removeTrackingRect;
    @end

@implementation MouseOverFieldView

  • (id)initWithFrame:(NSRect)frameRect
    {
    if ((self = [super initWithFrame:frameRect]) != nil) {
    tag = -1;
    mouseinside = NO;
    }
    return self;
    }

  • (void)drawRect:(NSRect)rect {
    if (mouseinside) {
    [[NSColor darkGrayColor] set];
    NSRectFill (rect);
    }
    }

  • (void)removeTrackingRect{
    if (tag != -1 ) {
    [self removeTrackingRect:tag];
    }
    }

  • (void)addTrackingRect{
    tag = [self addTrackingRect:[self bounds] owner:self userData:nil assumeInside:NO];
    }

  • (void)updateTrackingRect{
    [self removeTrackingRect];
    [self addTrackingRect];
    }

  • (void)mouseEntered:(NSEvent *)theEvent
    {
    mouseinside = YES;
    NSArray *btns = [self subviews];
    NSEnumerator *enumerator = [btns objectEnumerator];
    id btn;
    while (btn = [enumerator nextObject]) {
    [(NSView *)btn setHidden:NO];
    }
    [self setNeedsDisplay:YES];
    }

  • (void)mouseExited:(NSEvent *)theEvent
    {
    mouseinside = NO;
    NSArray *btns = [self subviews];
    NSEnumerator *enumerator = [btns objectEnumerator];
    id btn;
    while (btn = [enumerator nextObject]) {
    [(NSView *)btn setHidden:YES];
    }
    [self setNeedsDisplay:YES];
    }

@end[/code]
Good luck!

I may sound noobish (which I really am :P), but how is am I supposed to “attach” this Obj-C into my App? Obviously I have to create an Objective-C Class into my project, but what’s next? I already have the second window added to the .nib, and also all the AppleScript needed is in place.

I’m using Xcode 3.

I’d be very happy to get some help with this, seems I can’t figure it out myself :slight_smile: