add support for sheets to Cocoa widgets. b=330587 r=mento sr=pinkerton

This commit is contained in:
joshmoz%gmail.com 2006-06-08 17:29:18 +00:00
Родитель 9508adeaf8
Коммит 2e57557bb0
3 изменённых файлов: 182 добавлений и 21 удалений

Просмотреть файл

@ -163,11 +163,12 @@ protected:
NSWindow* mWindow; // our cocoa window [STRONG]
WindowDelegate* mDelegate; // our delegate for processing window msgs [STRONG]
nsCOMPtr<nsIMenuBar> mMenuBar;
NSWindow* mSheetWindowParent; // if this is a sheet, this is the NSWindow it's attached to
PRPackedBool mIsSheet; // true if the window is a dialog
PRPackedBool mIsResizing; // we originated the resize, prevent infinite recursion
PRPackedBool mWindowMadeHere; // true if we created the window, false for embedding
PRPackedBool mVisible; // Whether or not we're visible.
PRPackedBool mSheetNeedsShow; // if this is a sheet, are we waiting to be shown?
};

Просмотреть файл

@ -127,10 +127,12 @@ static nsRect cocoaRectToGeckoRect(const NSRect &cocoaRect)
nsCocoaWindow::nsCocoaWindow()
: mParent(nsnull)
, mWindow(nil)
, mIsSheet(PR_FALSE)
, mDelegate(nil)
, mSheetWindowParent(nil)
, mIsResizing(PR_FALSE)
, mWindowMadeHere(PR_FALSE)
, mVisible(PR_FALSE)
, mSheetNeedsShow(PR_FALSE)
{
}
@ -278,13 +280,10 @@ nsresult nsCocoaWindow::StandardCreate(nsIWidget *aParent,
if (aInitData) {
nsWindowType parentType;
aParent->GetWindowType(parentType);
if (parentType != eWindowType_invisible) {
// at this point we make the window a sheet
mIsSheet = PR_TRUE;
if (aInitData->mBorderStyle & eBorderStyle_resizeh) {
if (parentType != eWindowType_invisible &&
aInitData->mBorderStyle & eBorderStyle_resizeh) {
features = NSResizableWindowMask;
}
}
else {
features = NSMiniaturizableWindowMask;
}
@ -447,19 +446,126 @@ NS_IMETHODIMP nsCocoaWindow::IsVisible(PRBool & aState)
//
NS_IMETHODIMP nsCocoaWindow::Show(PRBool bState)
{
if (bState) {
if (mWindowType == eWindowType_popup) {
nsIWidget* parentWidget = mParent;
nsCOMPtr<nsPIWidgetCocoa> piParentWidget(do_QueryInterface(parentWidget));
NSWindow* nativeParentWindow = (parentWidget) ?
(NSWindow*)parentWidget->GetNativeData(NS_NATIVE_WINDOW) : nil;
if (bState && !mBounds.IsEmpty()) {
if (mWindowType == eWindowType_sheet) {
// bail if no parent window (its basically what we do in Carbon)
if (!nativeParentWindow || !piParentWidget)
return NS_ERROR_FAILURE;
NSWindow* topNonSheetWindow = nativeParentWindow;
// If this sheet is the child of another sheet, hide the parent so that
// this sheet can be displayed. Leave the parent mSheetNeedsShow alone,
// that is only used to handle sibling sheet contention. The parent will
// return once there are no more child sheets.
PRBool parentIsSheet = PR_FALSE;
if (NS_SUCCEEDED(piParentWidget->GetIsSheet(&parentIsSheet)) &&
parentIsSheet) {
piParentWidget->GetSheetWindowParent(&topNonSheetWindow);
[NSApp endSheet:nativeParentWindow];
}
nsCocoaWindow* sheetShown = nsnull;
if (NS_SUCCEEDED(piParentWidget->GetChildSheet(PR_TRUE, &sheetShown)) &&
(!sheetShown || sheetShown == this)) {
// If this sheet is already the sheet actually being shown, don't
// tell it to show again. Otherwise the number of calls to
// [NSApp beginSheet...] won't match up with [NSApp endSheet...].
if (![mWindow isSheet]) {
mVisible = PR_TRUE;
mSheetNeedsShow = PR_FALSE;
mSheetWindowParent = topNonSheetWindow;
[[mSheetWindowParent delegate] sendLostFocusAndDeactivate];
[NSApp beginSheet:mWindow
modalForWindow:mSheetWindowParent
modalDelegate:mDelegate
didEndSelector:@selector(didEndSheet:returnCode:contextInfo:)
contextInfo:mSheetWindowParent];
[[mWindow delegate] sendGotFocusAndActivate];
}
}
else {
// A sibling of this sheet is active, don't show this sheet yet.
// When the active sheet hides, its brothers and sisters that have
// mSheetNeedsShow set will have their opportunities to display.
mSheetNeedsShow = PR_TRUE;
}
}
else if (mWindowType == eWindowType_popup) {
mVisible = PR_TRUE;
[mWindow orderFront:nil];
}
else {
mVisible = PR_TRUE;
[mWindow makeKeyAndOrderFront:nil];
}
}
else {
[mWindow orderOut:nil];
// roll up any popups if a top-level window is going away
if (mWindowType == eWindowType_toplevel) {
if (gRollupListener != nsnull && gRollupWidget != nsnull)
gRollupListener->Rollup();
NS_IF_RELEASE(gRollupListener);
NS_IF_RELEASE(gRollupWidget);
}
mVisible = bState;
// now get rid of the window/sheet
if (mWindowType == eWindowType_sheet) {
if (mVisible) {
mVisible = PR_FALSE;
// get sheet's parent *before* hiding the sheet (which breaks the linkage)
NSWindow* sheetParent = mSheetWindowParent;
// hide the sheet
[NSApp endSheet:mWindow];
[[mWindow delegate] sendLostFocusAndDeactivate];
nsCocoaWindow* siblingSheetToShow = nsnull;
PRBool parentIsSheet = PR_FALSE;
if (nativeParentWindow && piParentWidget &&
NS_SUCCEEDED(piParentWidget->GetChildSheet(PR_FALSE, &siblingSheetToShow)) &&
siblingSheetToShow) {
// First, give sibling sheets an opportunity to show.
siblingSheetToShow->Show(PR_TRUE);
}
else if (nativeParentWindow && piParentWidget &&
NS_SUCCEEDED(piParentWidget->GetIsSheet(&parentIsSheet)) &&
parentIsSheet) {
// If there are no sibling sheets, but the parent is a sheet, restore
// it. It wasn't sent any deactivate events when it was hidden, so
// don't call through Show, just let the OS put it back up.
[NSApp beginSheet:nativeParentWindow
modalForWindow:sheetParent
modalDelegate:[nativeParentWindow delegate]
didEndSelector:@selector(didEndSheet:returnCode:contextInfo:)
contextInfo:sheetParent];
}
else {
// Sheet, that was hard. No more siblings or parents, going back
// to a real window.
[sheetParent makeKeyAndOrderFront:nil];
}
}
else if (mSheetNeedsShow) {
// This is an attempt to hide a sheet that never had a chance to
// be shown. There's nothing to do other than make sure that it
// won't show.
mSheetNeedsShow = PR_FALSE;
}
}
else {
[mWindow orderOut:nil];
mVisible = PR_FALSE;
}
}
return NS_OK;
}
@ -555,7 +661,14 @@ NS_IMETHODIMP nsCocoaWindow::Resize(PRInt32 aWidth, PRInt32 aHeight, PRBool aRep
if (mWindow) {
NSRect newBounds = [mWindow frame];
newBounds.size.width = aWidth;
if (mWindowType == eWindowType_popup)
// Note that [mWindow isSheet] is not the same as checking for
// |mWindowType == eWindowType_sheet|. If this is a sheet object, the latter
// will always be true. The former is true only when the sheet is being shown.
// Here we need to know if the sheet is actually being shown because if it is,
// the content view and the window's frame are equal, despite the fact that
// the native window object has the title bar flag set. If the window is not
// being shown as a sheet the content area and window frame differ.
if (mWindowType == eWindowType_popup || [mWindow isSheet])
newBounds.size.height = aHeight;
else
newBounds.size.height = aHeight + kTitleBarHeight; // add height of title bar
@ -646,7 +759,31 @@ NS_IMETHODIMP nsCocoaWindow::ComeToFront()
NS_IMETHODIMP nsCocoaWindow::GetChildSheet(PRBool aShown, nsCocoaWindow** _retval)
{
nsIWidget* child = GetFirstChild();
while (child) {
// find out if this is a top-level window
nsCOMPtr<nsPIWidgetCocoa> piChildWidget(do_QueryInterface(child));
if (piChildWidget) {
// if it implements nsPIWidgetCocoa, it must be an nsCocoaWindow
nsCocoaWindow* window = NS_STATIC_CAST(nsCocoaWindow*, child);
nsWindowType type;
if (NS_SUCCEEDED(window->GetWindowType(type)) &&
type == eWindowType_sheet) {
// if it's a sheet, it must be an nsCocoaWindow
nsCocoaWindow* cocoaWindow = NS_STATIC_CAST(nsCocoaWindow*, window);
if ((aShown && cocoaWindow->mVisible) ||
(!aShown && cocoaWindow->mSheetNeedsShow)) {
*_retval = cocoaWindow;
return NS_OK;
}
}
}
child = child->GetNextSibling();
}
*_retval = nsnull;
return NS_OK;
}
@ -660,7 +797,14 @@ NS_IMETHODIMP nsCocoaWindow::GetMenuBar(nsIMenuBar** menuBar)
NS_IMETHODIMP nsCocoaWindow::GetIsSheet(PRBool* isSheet)
{
*isSheet = mIsSheet;
mWindowType == eWindowType_sheet ? *isSheet = PR_TRUE : *isSheet = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP nsCocoaWindow::GetSheetWindowParent(NSWindow** sheetWindowParent)
{
*sheetWindowParent = mSheetWindowParent;
return NS_OK;
}
@ -791,9 +935,9 @@ NS_IMETHODIMP nsCocoaWindow::CaptureRollupEvents(nsIRollupListener * aListener,
return;
// Gecko already compensates for the title bar, so we have to strip it out here.
NSRect frameRect = [[aNotification object] frame];
NSRect frameRect = [[[aNotification object] contentView] frame];
mGeckoWindow->Resize(NS_STATIC_CAST(PRInt32,frameRect.size.width),
NS_STATIC_CAST(PRInt32,frameRect.size.height - nsCocoaWindow::kTitleBarHeight), PR_TRUE);
NS_STATIC_CAST(PRInt32,frameRect.size.height), PR_TRUE);
}
@ -893,4 +1037,15 @@ NS_IMETHODIMP nsCocoaWindow::CaptureRollupEvents(nsIRollupListener * aListener,
}
- (void)didEndSheet:(NSWindow*)sheet returnCode:(int)returnCode contextInfo:(void*)contextInfo
{
// Note: 'contextInfo' is the window that is the parent of the sheet,
// we set that in nsCocoaWindow::Show. 'contextInfo' is always the top-level
// window, not another sheet itself.
[[sheet delegate] sendLostFocusAndDeactivate];
[sheet orderOut:self];
[[(NSWindow*)contextInfo delegate] sendGotFocusAndActivate];
}
@end

Просмотреть файл

@ -1,6 +1,5 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* ***** BEGIN LICENSE BLOCK *****
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
@ -43,13 +42,15 @@
interface nsIMenuBar;
interface nsCocoaWindow;
[ptr] native NSWindowPtr(NSWindow);
//
// nsPIWidgetCocoa
//
// A private interface (unfrozen, private to the widget implementation) that
// gives us access to some extra features on a widget/window.
//
[scriptable, uuid(97e466b1-967f-40fd-81d1-577eaa2ac4d3)]
[uuid(ce1a5550-f680-11da-974d-0800200c9a66)]
interface nsPIWidgetCocoa : nsISupports
{
// Like OS ::BringToFront, but constrains the window to its z-level
@ -62,6 +63,10 @@ interface nsPIWidgetCocoa : nsISupports
// wants to be displayed (if !aShown)
nsCocoaWindow GetChildSheet(in boolean aShown);
// If the object implementing this interface is a sheet, this will return the
// native NSWindow it is attached to
readonly attribute NSWindowPtr sheetWindowParent;
// True if window is a sheet
readonly attribute boolean isSheet;