Native titlebar -> window position

Hey guys,

When I set a (standalone) program to use a native titlebar (Win7) the window is sometimes positioned so that the upper left position of the window content is exactly in the upper-left-most position on the screen, thus hiding the titlebar outside of the screen/reach with no way of getting it back.

With a resizable window I can then resize the windows and Windows7 would magically move the window the tinyest amount for me to be able to drag the titlebar. Non-resizable windows: no such luck!

  • Bram

Have you tried using a ComponentBoundsConstrainer to keep it on-screen?

The thing is: this is an app straight from the Jucer/Introdjucer, the only change being:

MainAppWindow::MainAppWindow()
    : DocumentWindow (JUCEApplication::getInstance()->getApplicationName(),
                      Colours::lightgrey,
                      DocumentWindow::allButtons)
{
    setUsingNativeTitleBar(true);
    m_Component = new MyComponent();
    setContentOwned(m_Component, true);
    setVisible (true);
}

I checked the bounds:

	DBG(getConstrainer()->getMinimumWhenOffTheTop()); -> 65536
	DBG(getConstrainer()->getMinimumWhenOffTheLeft()); -> 16
	DBG(getConstrainer()->getMinimumWhenOffTheBottom()); -> 24
	DBG(getConstrainer()->getMinimumWhenOffTheRight()); -> 16

Calling getConstrainer()->checkComponentBounds(this); at the end of the constructor fixes it… Perhaps setUsingNativeTitleBar should call getConstrainer()->checkComponentBounds(this) too?

  • bram

Well, it’s only a template for you to start from! It never claimed to deal with every possible situation!

Of course, I’m just saying it’s a minimal example.
What I’m also saying is that perhaps setUsingNativeTitleBar( … ) should call getConstrainer()->checkComponentBounds(this), which solves the problem (consistently / for me).

  • bram

In general, though, why does switching to a native title bar (for example, in the Juce Demo app) change the window position/size? It seems to me that these should be preserved exactly, even if the content component size has to be changed a little bit to accommodate a different window frame size. Or, it could work the other way – the content component size is preserved exactly, and the overall window size/position are changed a little bit. But either of those seem to better than making the native window’s client area be the same size as the entire Juce window.

I’m not sure if this is directly relevant but I wrote a simple wrapper that makes the JUCE ComponentBoundsConstrainer behave better when trying to specify sizes that are independent of the window frame thickness:

https://github.com/vinniefalco/VFLib/blob/master/modules/vf_gui/layout/vf_ContentComponentConstrainer.h

Is it a problem that ever arises in the real world? What kind of application would ever need its windows to repeatedly flip between native title bars and juce ones…?

It’s not flipping back and forth that’s an issue for me. It’s that, when I do something like setTopLeftPosition(0,0) on a native window, the window frame goes off the screen. This seems strange to me. I would expect that saying setTopLeftPosition(0,0) on a native window would do the same thing as on a Juce window, which is that the top left corner of the window frame gets put at (0,0) – not the top left corner of the content component.

A non-native titlebar window has a 0 pixel thick window border, while a native titlebar window has a non-zero sized window border. You can observe this yourself by stepping through HWNDComponentPeer::updateBorderSize() (juce_win32_Windowing.cpp).

If you want to specify coordinates independent of the native or non-native condition of the titlebar then you need to add to your coordinates the thickness of the left and top sides of the border from the ComponentPeer, by calling:

contentComponent->getPeer()->getFrameSize()

Note that this is exactly what the code in my ComponentBoundsConstrainer class does.

Here’s an example function:

void setAbsoluteTopLeft (Component* component, Point <int> topLeft)
{
  component->setTopLeftPosition (
    topLeft.x + component->getPeer()->getFrameSize().getX(),
    topLeft.y + component->getPeer()->getFrameSize().getY());
}

I understand. It just seems to me that the frame size should automatically be taken into account. Or, another way to say it is that your code should be part of the standard Juce code :).

There are a lot of things that “should”… native menu bars come to mind :slight_smile:

Yeah, agreed. But didn’t I read somewhere that you can’t programatically create native OS X menus?

Wow…seriously??!

Nah that’s not right, according to the people in #macdev. “NSMenu” provides an interface for adding items:

https://developer.apple.com/library/mac/#documentation/cocoa/reference/applicationkit/classes/nsmenu_class/Reference/Reference.html#//apple_ref/doc/uid/20000267-DontLinkElementID_3

Ok. Fair enough.