How can we draw a NSWindow in a custom NSView?

  • I'm investigating possible solutions to draw a window frame (title bar,
    buttons, title, resize box, background) in a NSView that's inside a
    real window.

    Something like this:

    +---------------------------------------------+
    | O O O          A real window                |
    +---------------------------------------------+
    |                                            |
    |  +------------------------------------+    |
    |  | O O O    A fake window            |    |
    |  +------------------------------------+    |
    |  |                                    |    |
    |  |                                    |    |
    .  .                                    .    .

    And in my dream, I would like to have shadow too (but with NSShadow
    this might be easy)).

    I had a look at the AppKit headers to see if I could find some
    functions that would draw a window frame but I was not able to find
    one. IIRC, there used to be such functions in Carbon.

    One solution could be to use an Overlay window but I would rather not
    have to go this way to avoid sharing outlet connections between 2
    windows and having to handle resizing in an awkward way.

    Another solution could be to render the window frame using multiple
    pictures but that would not be a good solution from a resolution
    independence point of view. Not to mention that depending on the OS
    version, I would have to use different sets of pictures.

    Any better idea or suggestion?
  • Hate to ask, but why? MDI on Mac OS is not a good idea ;)
    Anyway, the HITheme APIs are probably your best bet. (Carbon)

    On Sep 30, 2007, at 4:32 PM, Stéphane Sudre wrote:

    > I'm investigating possible solutions to draw a window frame (title
    > bar, buttons, title, resize box, background) in a NSView that's
    > inside a real window.
    >
    > Something like this:
    >
    > +---------------------------------------------+
    > | O O O          A real window                |
    > +---------------------------------------------+
    > |                                            |
    > |  +------------------------------------+    |
    > |  | O O O    A fake window            |    |
    > |  +------------------------------------+    |
    > |  |                                    |    |
    > |  |                                    |    |
    > .  .                                    .    .
    >
    > And in my dream, I would like to have shadow too (but with NSShadow
    > this might be easy)).
    >
    > I had a look at the AppKit headers to see if I could find some
    > functions that would draw a window frame but I was not able to find
    > one. IIRC, there used to be such functions in Carbon.
    >
    > One solution could be to use an Overlay window but I would rather
    > not have to go this way to avoid sharing outlet connections between
    > 2 windows and having to handle resizing in an awkward way.
    >
    > Another solution could be to render the window frame using multiple
    > pictures but that would not be a good solution from a resolution
    > independence point of view. Not to mention that depending on the OS
    > version, I would have to use different sets of pictures.
    >
    > Any better idea or suggestion?
  • I need to render one fake window inside a real window. Think of it as a
    UI simulator. It's definitely not a MDI thing.

    My issue with HIThemes APIs is that they are probably not resolution
    independent compatible. I think I will have to classdump NSWindow.

    On lundi, octobre 1, 2007, at 02:17  AM, John Stiles wrote:

    > Hate to ask, but why? MDI on Mac OS is not a good idea ;)
    > Anyway, the HITheme APIs are probably your best bet. (Carbon)
    >
    > On Sep 30, 2007, at 4:32 PM, Stéphane Sudre wrote:
    >
    >> I'm investigating possible solutions to draw a window frame (title
    >> bar, buttons, title, resize box, background) in a NSView that's
    >> inside a real window.
    >>
    >> Something like this:
    >>
    >> +---------------------------------------------+
    >> | O O O          A real window                |
    >> +---------------------------------------------+
    >> |                                            |
    >> |  +------------------------------------+    |
    >> |  | O O O    A fake window            |    |
    >> |  +------------------------------------+    |
    >> |  |                                    |    |
    >> |  |                                    |    |
    >> .  .                                    .    .
    >>
    >> And in my dream, I would like to have shadow too (but with NSShadow
    >> this might be easy)).
    >>
    >> I had a look at the AppKit headers to see if I could find some
    >> functions that would draw a window frame but I was not able to find
    >> one. IIRC, there used to be such functions in Carbon.
    >>
    >> One solution could be to use an Overlay window but I would rather not
    >> have to go this way to avoid sharing outlet connections between 2
    >> windows and having to handle resizing in an awkward way.
    >>
    >> Another solution could be to render the window frame using multiple
    >> pictures but that would not be a good solution from a resolution
    >> independence point of view. Not to mention that depending on the OS
    >> version, I would have to use different sets of pictures.
    >>
    >> Any better idea or suggestion?
  • On Oct 1, 2007, at 12:58 PM, Stéphane Sudre wrote:

    > My issue with HIThemes APIs is that they are probably not resolution
    > independent compatible.

    Actually, they are.

    -eric
  • On lundi, octobre 1, 2007, at 10:02  PM, Eric Schlegel wrote:

    >
    > On Oct 1, 2007, at 12:58 PM, Stéphane Sudre wrote:
    >
    >> My issue with HIThemes APIs is that they are probably not resolution
    >> independent compatible.
    >
    > Actually, they are.

    I'm not sure I can say they are. My point being that if the drawing is
    already incorrect at resolution = 1.0f, I don't think it can be said
    that they correctly deal with higher resolution.

    I've just spent some times testing the HITheme API to draw a window
    frame and while I'm getting close to a not too bad result, I've found
    the method to draw Window frame to be buggy:

    (1) it doesn't draw the window frame, it draws the inner part of a
    window frame.

    (2) it doesn't draw the window growbox the Cocoa way

    (3) it doesn't draw the Window buttons correctly (they are vertically
    offseted by at least 2 pixels).

    While it's possible to work around (2) pretty easily, (1) and (3) are
    more problematic.

    (1) could be solved by computing the frame line but there are no
    guarantees the frame would be the same on different OS versions.

    (3) might be solved by using the NSWindow API to get access to real
    NSWindow buttons. But again, it's not a nice move toward compatibility.
  • On Oct 1, 2007, at 6:27 PM, Stéphane Sudre wrote:

    >
    > On lundi, octobre 1, 2007, at 10:02  PM, Eric Schlegel wrote:
    >
    >>
    >> On Oct 1, 2007, at 12:58 PM, Stéphane Sudre wrote:
    >>
    >>> My issue with HIThemes APIs is that they are probably not
    >>> resolution independent compatible.
    >>
    >> Actually, they are.
    >
    > I'm not sure I can say they are. My point being that if the drawing
    > is already incorrect at resolution = 1.0f, I don't think it can be
    > said that they correctly deal with higher resolution.
    >
    > I've just spent some times testing the HITheme API to draw a window
    > frame and while I'm getting close to a not too bad result, I've
    > found the method to draw Window frame to be buggy:
    >
    > (1) it doesn't draw the window frame, it draws the inner part of a
    > window frame.
    >
    > (2) it doesn't draw the window growbox the Cocoa way
    >
    > (3) it doesn't draw the Window buttons correctly (they are
    > vertically offseted by at least 2 pixels).
    >
    > While it's possible to work around (2) pretty easily, (1) and (3)
    > are more problematic.
    >
    > (1) could be solved by computing the frame line but there are no
    > guarantees the frame would be the same on different OS versions.
    >
    > (3) might be solved by using the NSWindow API to get access to real
    > NSWindow buttons. But again, it's not a nice move toward
    > compatibility.

    One thing you could try (I just tried an experiment and it mostly
    works) is to do this:

    Create a subclass of NSWindow (your fake window):

    - (id)initWithParentWindow:(NSWindow*)aWindow;
    {
    NSRect theParentWindowRect = [aWindow frame];
    NSRect theFakeWindowRect = NSInsetRect (theParentWindowRect, 50.0f,
    50.0f);

    if ((self = [super initWithContentRect:theFakeWindowRect
      styleMask:(NSTitledWindowMask | NSClosableWindowMask |
    NSMiniaturizableWindowMask | NSResizableWindowMask)
      backing:NSBackingStoreBuffered
      defer:NO]) != nil)
      {
      [self setHidesOnDeactivate:NO];
      [self setReleasedWhenClosed:NO];
      [self setMovableByWindowBackground:NO];
      [self setHasShadow:YES];
      [self useOptimizedDrawing:YES];
      [self setOpaque:YES];

      [aWindow addChildWindow:self ordered:NSWindowAbove];
      }

    return self;
    }

    In my test nib, I created an outlet to the default window supplied by
    a Cocoa nib.  Created a controller subclass and in
    applicationDidFinishLaunching, I create an instance of the fakeWindow
    with a parent of the default window.

    Then at least override the following as well in your NSWindow subclass:

    - (BOOL)canBecomeKeyWindow (return NO)
    - (BOOL)canBecomeMainWindow (return NO)
    - (BOOL)accessibilityIsIgnored (return YES)

    This will at least draw a window with frame, title bar and shadow.

    However, my limited test app will not do the following:

    - resizing main window will not dynamically resize the fake window
    - you're able to resize the fake window.  Not sure how to do it, but
    you may be able to disable that control.
    - The three title button widgets always appear disabled (unless you
    mouse-over).  They are also clickable and will take the appropriate
    action.  You'd have to figure out how to trap for those as well.
    - while dragging the window by its background isn't allowed, you can
    drag it from its title bar.

    One cool thing about this approach is that it appears to be Expose-
    savvy (at least in 10.4.x).  The fake window's position will always
    be in sync with its parent window.  And, since the fake window can
    never become key/main, expose keeps it out of its list of windows you
    can directly select.  When you mouseover the fake window, expose
    gives you the name of its parent window instead.

    ___________________________________________________________
    Ricky A. Sharp        mailto:<rsharp...>
    Instant Interactive(tm)  http://www.instantinteractive.com
  • On mardi, octobre 2, 2007, at 02:42  AM, Ricky Sharp wrote:

    > ...
    >
    > One cool thing about this approach is that it appears to be
    > Expose-savvy (at least in 10.4.x).  The fake window's position will
    > always be in sync with its parent window.  And, since the fake window
    > can never become key/main, expose keeps it out of its list of windows
    > you can directly select.  When you mouseover the fake window, expose
    > gives you the name of its parent window instead.

    That's the overlay window solution I talked about in the original post.
    The main issue with this solution is that the depth is not the same for
    the items inside the overlay window and the parent window. That could
    be a problem for all the drawing process I have in mind.

    But this might be the solution I will end up using.
  • On mardi, octobre 2, 2007, at 08:57  AM, Stéphane Sudre wrote:

    >
    > On mardi, octobre 2, 2007, at 02:42  AM, Ricky Sharp wrote:
    >
    >> ...
    >>
    >> One cool thing about this approach is that it appears to be
    >> Expose-savvy (at least in 10.4.x).  The fake window's position will
    >> always be in sync with its parent window.  And, since the fake window
    >> can never become key/main, expose keeps it out of its list of windows
    >> you can directly select.  When you mouseover the fake window, expose
    >> gives you the name of its parent window instead.
    >
    > That's the overlay window solution I talked about in the original
    > post. The main issue with this solution is that the depth is not the
    > same for the items inside the overlay window and the parent window.
    > That could be a problem for all the drawing process I have in mind.
    >
    > But this might be the solution I will end up using.

    The other issue with an overlay window is when you minimize the parent
    window. If I am to believe what I see with Drawers, the child window
    would be hidden before the window is minimized. Leaving a large blank
    space in the parent window. I don't like this a lot.
  • On Sep 30, 2007, at 4:32 PM, Stéphane Sudre wrote:

    > I'm investigating possible solutions to draw a window frame (title
    > bar, buttons, title, resize box, background) in a NSView that's
    > inside a real window.
    >
    > Something like this:
    >
    > +---------------------------------------------+
    > | O O O          A real window                |
    > +---------------------------------------------+
    > |                                            |
    > |  +------------------------------------+    |
    > |  | O O O    A fake window            |    |
    > |  +------------------------------------+    |
    > |  |                                    |    |
    > |  |                                    |    |
    > .  .                                    .    .
    >
    > And in my dream, I would like to have shadow too (but with NSShadow
    > this might be easy)).
    >
    > I had a look at the AppKit headers to see if I could find some
    > functions that would draw a window frame but I was not able to find
    > one. IIRC, there used to be such functions in Carbon.
    >
    > One solution could be to use an Overlay window but I would rather
    > not have to go this way to avoid sharing outlet connections between
    > 2 windows and having to handle resizing in an awkward way.
    >
    > Another solution could be to render the window frame using multiple
    > pictures but that would not be a good solution from a resolution
    > independence point of view. Not to mention that depending on the OS
    > version, I would have to use different sets of pictures.
    >
    > Any better idea or suggestion?

    I would say that the child window is probably the easiest and most
    robust approach.  If you *really* need to make the window draw in a
    view somewhere, you can always ask the window for its PDF data, and
    draw that with an NSImage.

    -jcr
previous month october 2007 next month
MTWTFSS
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        
Go to today