mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-09 00:11:44 +00:00
Bug 420491 - Implement HideWindowChrome on Mac OS X by creating a new borderless native window and reparenting the content view. r=smichaud, r=josh
This commit is contained in:
parent
ce92341f20
commit
742bcfcba2
@ -413,6 +413,7 @@ public:
|
||||
NS_IMETHOD EndSecureKeyboardInput();
|
||||
|
||||
void HidePlugin();
|
||||
void UpdatePluginPort();
|
||||
|
||||
void ResetParent();
|
||||
|
||||
|
@ -776,61 +776,18 @@ void* nsChildView::GetNativeData(PRUint32 aDataType)
|
||||
break;
|
||||
|
||||
case NS_NATIVE_PLUGIN_PORT:
|
||||
#ifndef NP_NO_QUICKDRAW
|
||||
case NS_NATIVE_PLUGIN_PORT_QD:
|
||||
{
|
||||
mPluginIsCG = PR_FALSE;
|
||||
mIsPluginView = PR_TRUE;
|
||||
if ([mView isKindOfClass:[ChildView class]])
|
||||
[(ChildView*)mView setIsPluginView:YES];
|
||||
|
||||
NSWindow* window = [mView nativeWindow];
|
||||
if (window) {
|
||||
WindowRef topLevelWindow = (WindowRef)[window windowRef];
|
||||
if (topLevelWindow) {
|
||||
mPluginPort.qdPort.port = ::GetWindowPort(topLevelWindow);
|
||||
|
||||
NSPoint viewOrigin = [mView convertPoint:NSZeroPoint toView:nil];
|
||||
NSRect frame = [[window contentView] frame];
|
||||
viewOrigin.y = frame.size.height - viewOrigin.y;
|
||||
|
||||
// need to convert view's origin to window coordinates.
|
||||
// then, encode as "SetOrigin" ready values.
|
||||
mPluginPort.qdPort.portx = (PRInt32)-viewOrigin.x;
|
||||
mPluginPort.qdPort.porty = (PRInt32)-viewOrigin.y;
|
||||
}
|
||||
}
|
||||
|
||||
retVal = (void*)&mPluginPort;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case NS_NATIVE_PLUGIN_PORT_CG:
|
||||
{
|
||||
mPluginIsCG = PR_TRUE;
|
||||
#ifdef NP_NO_QUICKDRAW
|
||||
aDataType = NS_NATIVE_PLUGIN_PORT_CG;
|
||||
#endif
|
||||
mPluginIsCG = (aDataType == NS_NATIVE_PLUGIN_PORT_CG);
|
||||
mIsPluginView = PR_TRUE;
|
||||
if ([mView isKindOfClass:[ChildView class]])
|
||||
[(ChildView*)mView setIsPluginView:YES];
|
||||
|
||||
NSWindow* window = [mView nativeWindow];
|
||||
if (window) {
|
||||
// [NSGraphicsContext currentContext] is supposed to "return the
|
||||
// current graphics context of the current thread." But sometimes
|
||||
// (when called while mView isn't focused for drawing) it returns a
|
||||
// graphics context for the wrong window. [window graphicsContext]
|
||||
// (which "provides the graphics context associated with the window
|
||||
// for the current thread") seems always to return the "right"
|
||||
// graphics context. See bug 500130.
|
||||
mPluginPort.cgPort.context = (CGContextRef)
|
||||
[[window graphicsContext] graphicsPort];
|
||||
WindowRef topLevelWindow = (WindowRef)[window windowRef];
|
||||
mPluginPort.cgPort.window = topLevelWindow;
|
||||
} else {
|
||||
mPluginPort.cgPort.context = nil;
|
||||
mPluginPort.cgPort.window = nil;
|
||||
}
|
||||
|
||||
UpdatePluginPort();
|
||||
retVal = (void*)&mPluginPort;
|
||||
break;
|
||||
}
|
||||
@ -939,6 +896,46 @@ void nsChildView::HidePlugin()
|
||||
}
|
||||
}
|
||||
|
||||
void nsChildView::UpdatePluginPort()
|
||||
{
|
||||
NS_ASSERTION(mIsPluginView, "UpdatePluginPort called on non-plugin view");
|
||||
|
||||
NSWindow* window = [mView nativeWindow];
|
||||
WindowRef topLevelWindow = window ? (WindowRef)[window windowRef] : nil;
|
||||
if (mPluginIsCG) {
|
||||
if (topLevelWindow) {
|
||||
// [NSGraphicsContext currentContext] is supposed to "return the
|
||||
// current graphics context of the current thread." But sometimes
|
||||
// (when called while mView isn't focused for drawing) it returns a
|
||||
// graphics context for the wrong window. [window graphicsContext]
|
||||
// (which "provides the graphics context associated with the window
|
||||
// for the current thread") seems always to return the "right"
|
||||
// graphics context. See bug 500130.
|
||||
mPluginPort.cgPort.context = (CGContextRef)
|
||||
[[window graphicsContext] graphicsPort];
|
||||
mPluginPort.cgPort.window = topLevelWindow;
|
||||
} else {
|
||||
mPluginPort.cgPort.context = nil;
|
||||
mPluginPort.cgPort.window = nil;
|
||||
}
|
||||
} else {
|
||||
if (topLevelWindow) {
|
||||
mPluginPort.qdPort.port = ::GetWindowPort(topLevelWindow);
|
||||
|
||||
NSPoint viewOrigin = [mView convertPoint:NSZeroPoint toView:nil];
|
||||
NSRect frame = [[window contentView] frame];
|
||||
viewOrigin.y = frame.size.height - viewOrigin.y;
|
||||
|
||||
// need to convert view's origin to window coordinates.
|
||||
// then, encode as "SetOrigin" ready values.
|
||||
mPluginPort.qdPort.portx = (PRInt32)-viewOrigin.x;
|
||||
mPluginPort.qdPort.porty = (PRInt32)-viewOrigin.y;
|
||||
} else {
|
||||
mPluginPort.qdPort.port = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void HideChildPluginViews(NSView* aView)
|
||||
{
|
||||
NSArray* subviews = [aView subviews];
|
||||
@ -2277,6 +2274,9 @@ NSEvent* gLastDragEvent = nil;
|
||||
- (void)setNativeWindow:(NSWindow*)aWindow
|
||||
{
|
||||
mWindow = aWindow;
|
||||
if (aWindow && [self isPluginView] && mGeckoChild) {
|
||||
mGeckoChild->UpdatePluginPort();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)systemMetricsChanged
|
||||
|
@ -214,7 +214,7 @@ public:
|
||||
NS_IMETHOD PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
|
||||
nsIWidget *aWidget, PRBool aActivate);
|
||||
NS_IMETHOD SetSizeMode(PRInt32 aMode);
|
||||
|
||||
NS_IMETHOD HideWindowChrome(PRBool aShouldHide);
|
||||
NS_IMETHOD Resize(PRInt32 aWidth,PRInt32 aHeight, PRBool aRepaint);
|
||||
NS_IMETHOD Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint);
|
||||
NS_IMETHOD GetScreenBounds(nsIntRect &aRect);
|
||||
@ -281,8 +281,9 @@ protected:
|
||||
nsIToolkit *aToolkit,
|
||||
nsWidgetInitData *aInitData,
|
||||
nsNativeWidget aNativeWindow = nsnull);
|
||||
nsresult CreateNativeWindow(const nsIntRect &aRect,
|
||||
nsBorderStyle aBorderStyle);
|
||||
nsresult CreateNativeWindow(const NSRect &aRect,
|
||||
nsBorderStyle aBorderStyle,
|
||||
PRBool aRectIsFrameRect);
|
||||
nsresult CreatePopupContentView(const nsIntRect &aRect,
|
||||
EVENT_CALLBACK aHandleEventFunction,
|
||||
nsIDeviceContext *aContext,
|
||||
|
@ -124,6 +124,22 @@ nsCocoaWindow::nsCocoaWindow()
|
||||
|
||||
}
|
||||
|
||||
// Sometimes NSViews are removed from a window or moved to a new window.
|
||||
// Since our ChildViews have their own mWindow field instead of always using
|
||||
// [view window], we need to notify them when this happens.
|
||||
static void SetNativeWindowOnSubviews(NSView *aNativeView, NSWindow *aWin)
|
||||
{
|
||||
if (!aNativeView)
|
||||
return;
|
||||
if ([aNativeView respondsToSelector:@selector(setNativeWindow:)])
|
||||
[(NSView<mozView>*)aNativeView setNativeWindow:aWin];
|
||||
NSArray *immediateSubviews = [aNativeView subviews];
|
||||
int count = [immediateSubviews count];
|
||||
for (int i = 0; i < count; ++i)
|
||||
SetNativeWindowOnSubviews((NSView *)[immediateSubviews objectAtIndex:i], aWin);
|
||||
}
|
||||
|
||||
|
||||
// Under unusual circumstances, an nsCocoaWindow object can be destroyed
|
||||
// before the nsChildView objects it contains are destroyed. But this will
|
||||
// invalidate the (weak) mWindow variable in these nsChildView objects
|
||||
@ -132,14 +148,7 @@ nsCocoaWindow::nsCocoaWindow()
|
||||
// resolve bmo bug 479749.
|
||||
static void TellNativeViewsGoodbye(NSView *aNativeView)
|
||||
{
|
||||
if (!aNativeView)
|
||||
return;
|
||||
if ([aNativeView respondsToSelector:@selector(setNativeWindow:)])
|
||||
[(NSView<mozView>*)aNativeView setNativeWindow:nil];
|
||||
NSArray *immediateSubviews = [aNativeView subviews];
|
||||
int count = [immediateSubviews count];
|
||||
for (int i = 0; i < count; ++i)
|
||||
TellNativeViewsGoodbye((NSView *)[immediateSubviews objectAtIndex:i]);
|
||||
SetNativeWindowOnSubviews(aNativeView, nil);
|
||||
}
|
||||
|
||||
void nsCocoaWindow::DestroyNativeWindow()
|
||||
@ -256,7 +265,8 @@ nsresult nsCocoaWindow::StandardCreate(nsIWidget *aParent,
|
||||
|
||||
// Create a window if we aren't given one, or if this should be a non-native popup.
|
||||
if ((mWindowType == eWindowType_popup) ? !UseNativePopupWindows() : !aNativeWindow) {
|
||||
nsresult rv = CreateNativeWindow(aRect, mBorderStyle);
|
||||
nsresult rv = CreateNativeWindow(nsCocoaUtils::GeckoRectToCocoaRect(aRect),
|
||||
mBorderStyle, PR_FALSE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mWindowType == eWindowType_popup) {
|
||||
@ -265,10 +275,9 @@ nsresult nsCocoaWindow::StandardCreate(nsIWidget *aParent,
|
||||
}
|
||||
} else {
|
||||
mWindow = (NSWindow*)aNativeWindow;
|
||||
[[WindowDataMap sharedWindowDataMap] ensureDataForWindow:mWindow];
|
||||
}
|
||||
|
||||
[[WindowDataMap sharedWindowDataMap] ensureDataForWindow:mWindow];
|
||||
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
@ -296,8 +305,13 @@ static unsigned int WindowMaskForBorderStyle(nsBorderStyle aBorderStyle)
|
||||
return mask;
|
||||
}
|
||||
|
||||
nsresult nsCocoaWindow::CreateNativeWindow(const nsIntRect &aRect,
|
||||
nsBorderStyle aBorderStyle)
|
||||
// If aRectIsFrameRect, aRect specifies the frame rect of the new window.
|
||||
// Otherwise, aRect.x/y specify the position of the window's frame relative to
|
||||
// the bottom of the menubar and aRect.width/height specify the size of the
|
||||
// content rect.
|
||||
nsresult nsCocoaWindow::CreateNativeWindow(const NSRect &aRect,
|
||||
nsBorderStyle aBorderStyle,
|
||||
PRBool aRectIsFrameRect)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
@ -332,34 +346,39 @@ nsresult nsCocoaWindow::CreateNativeWindow(const nsIntRect &aRect,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* We pass a content area rect to initialize the native Cocoa window. The
|
||||
* content rect we give is the same size as the size we're given by gecko.
|
||||
* The origin we're given for non-popup windows is moved down by the height
|
||||
* of the menu bar so that an origin of (0,100) from gecko puts the window
|
||||
* 100 pixels below the top of the available desktop area. We also move the
|
||||
* origin down by the height of a title bar if it exists. This is so the
|
||||
* origin that gecko gives us for the top-left of the window turns out to
|
||||
* be the top-left of the window we create. This is how it was done in
|
||||
* Carbon. If it ought to be different we'll probably need to look at all
|
||||
* the callers.
|
||||
*
|
||||
* Note: This means that if you put a secondary screen on top of your main
|
||||
* screen and open a window in the top screen, it'll be incorrectly shifted
|
||||
* down by the height of the menu bar. Same thing would happen in Carbon.
|
||||
*
|
||||
* Note: If you pass a rect with 0,0 for an origin, the window ends up in a
|
||||
* weird place for some reason. This stops that without breaking popups.
|
||||
*/
|
||||
NSRect rect = nsCocoaUtils::GeckoRectToCocoaRect(aRect);
|
||||
NSRect contentRect;
|
||||
|
||||
// compensate for difference between frame and content area height (e.g. title bar)
|
||||
NSRect newWindowFrame = [NSWindow frameRectForContentRect:rect styleMask:features];
|
||||
if (aRectIsFrameRect) {
|
||||
contentRect = [NSWindow contentRectForFrameRect:aRect styleMask:features];
|
||||
} else {
|
||||
/*
|
||||
* We pass a content area rect to initialize the native Cocoa window. The
|
||||
* content rect we give is the same size as the size we're given by gecko.
|
||||
* The origin we're given for non-popup windows is moved down by the height
|
||||
* of the menu bar so that an origin of (0,100) from gecko puts the window
|
||||
* 100 pixels below the top of the available desktop area. We also move the
|
||||
* origin down by the height of a title bar if it exists. This is so the
|
||||
* origin that gecko gives us for the top-left of the window turns out to
|
||||
* be the top-left of the window we create. This is how it was done in
|
||||
* Carbon. If it ought to be different we'll probably need to look at all
|
||||
* the callers.
|
||||
*
|
||||
* Note: This means that if you put a secondary screen on top of your main
|
||||
* screen and open a window in the top screen, it'll be incorrectly shifted
|
||||
* down by the height of the menu bar. Same thing would happen in Carbon.
|
||||
*
|
||||
* Note: If you pass a rect with 0,0 for an origin, the window ends up in a
|
||||
* weird place for some reason. This stops that without breaking popups.
|
||||
*/
|
||||
// Compensate for difference between frame and content area height (e.g. title bar).
|
||||
NSRect newWindowFrame = [NSWindow frameRectForContentRect:aRect styleMask:features];
|
||||
|
||||
rect.origin.y -= (newWindowFrame.size.height - rect.size.height);
|
||||
contentRect = aRect;
|
||||
contentRect.origin.y -= (newWindowFrame.size.height - aRect.size.height);
|
||||
|
||||
if (mWindowType != eWindowType_popup)
|
||||
rect.origin.y -= ::GetMBarHeight();
|
||||
if (mWindowType != eWindowType_popup)
|
||||
contentRect.origin.y -= ::GetMBarHeight();
|
||||
}
|
||||
|
||||
// NSLog(@"Top-level window being created at Cocoa rect: %f, %f, %f, %f\n",
|
||||
// rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
|
||||
@ -381,9 +400,16 @@ nsresult nsCocoaWindow::CreateNativeWindow(const nsIntRect &aRect,
|
||||
windowClass = [BorderlessWindow class];
|
||||
|
||||
// Create the window
|
||||
mWindow = [[windowClass alloc] initWithContentRect:rect styleMask:features
|
||||
mWindow = [[windowClass alloc] initWithContentRect:contentRect styleMask:features
|
||||
backing:NSBackingStoreBuffered defer:YES];
|
||||
|
||||
// Make sure that the content rect we gave has been honored.
|
||||
NSRect wantedFrame = [mWindow frameRectForContentRect:contentRect];
|
||||
if (!NSEqualRects([mWindow frame], wantedFrame)) {
|
||||
// This can happen when the window is not on the primary screen.
|
||||
[mWindow setFrame:wantedFrame display:NO];
|
||||
}
|
||||
|
||||
if (mWindowType == eWindowType_invisible) {
|
||||
[mWindow setLevel:kCGDesktopWindowLevelKey];
|
||||
} else if (mWindowType == eWindowType_popup) {
|
||||
@ -399,6 +425,7 @@ nsresult nsCocoaWindow::CreateNativeWindow(const nsIntRect &aRect,
|
||||
mDelegate = [[WindowDelegate alloc] initWithGeckoWindow:this];
|
||||
[mWindow setDelegate:mDelegate];
|
||||
|
||||
[[WindowDataMap sharedWindowDataMap] ensureDataForWindow:mWindow];
|
||||
mWindowMadeHere = PR_TRUE;
|
||||
|
||||
return NS_OK;
|
||||
@ -956,6 +983,61 @@ NS_METHOD nsCocoaWindow::SetSizeMode(PRInt32 aMode)
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
// This has to preserve the window's frame bounds.
|
||||
// This method requires (as does the Windows impl.) that you call Resize shortly
|
||||
// after calling HideWindowChrome. See bug 498835 for fixing this.
|
||||
NS_IMETHODIMP nsCocoaWindow::HideWindowChrome(PRBool aShouldHide)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
if (!mWindowMadeHere ||
|
||||
(mWindowType != eWindowType_toplevel && mWindowType != eWindowType_dialog))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
BOOL isVisible = [mWindow isVisible];
|
||||
|
||||
// Remove child windows.
|
||||
NSArray* childWindows = [mWindow childWindows];
|
||||
NSEnumerator* enumerator = [childWindows objectEnumerator];
|
||||
NSWindow* child = nil;
|
||||
while ((child = [enumerator nextObject])) {
|
||||
[mWindow removeChildWindow:child];
|
||||
}
|
||||
|
||||
// Remove the content view.
|
||||
NSView* contentView = [mWindow contentView];
|
||||
[contentView retain];
|
||||
[contentView removeFromSuperviewWithoutNeedingDisplay];
|
||||
|
||||
// Recreate the window with the right border style.
|
||||
NSRect frameRect = [mWindow frame];
|
||||
DestroyNativeWindow();
|
||||
nsresult rv = CreateNativeWindow(frameRect, aShouldHide ? eBorderStyle_none : mBorderStyle, PR_TRUE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Reparent the content view.
|
||||
[mWindow setContentView:contentView];
|
||||
[contentView release];
|
||||
SetNativeWindowOnSubviews(contentView, mWindow);
|
||||
|
||||
// Reparent child windows.
|
||||
enumerator = [childWindows objectEnumerator];
|
||||
while ((child = [enumerator nextObject])) {
|
||||
[mWindow addChildWindow:child ordered:NSWindowAbove];
|
||||
}
|
||||
|
||||
// Show the new window.
|
||||
if (isVisible) {
|
||||
rv = Show(PR_TRUE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsCocoaWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, PRBool aRepaint)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
Loading…
x
Reference in New Issue
Block a user