зеркало из https://github.com/mozilla/gecko-dev.git
Fix bug 179307: when a sheet is displayed in Camino, push a native code security context onto the stack so that the context is correct for native code that can run via PLEvents while the sheet is being displayed. This fixes backwards typing in other windows. r=mento
Also fix warnings.
This commit is contained in:
Родитель
1c26e358f9
Коммит
23c7a2ca2e
|
@ -3938,7 +3938,7 @@
|
|||
GCC_OPTIMIZATION_LEVEL = 2;
|
||||
GCC_PREFIX_HEADER = src/includes/ChimeraPrefix.h;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "OSTYPE=Darwin1.4 OSARCH=Darwin MOZILLA_INTERNAL_API=1";
|
||||
HEADER_SEARCH_PATHS = "../dist/include/exthandler ../dist/include/helperAppDlg ../dist/include/intl ../dist/include/pipboot ../dist/include/pipnss ../dist/include/webbrwsr ../dist/include/dom ../dist/include/nspr ../dist/include/string ../dist/include/uconv ../dist/include/necko ../dist/include/find ../dist/include/embed_base ../dist/include/commandhandler ../dist/include/windowwatcher ../dist/include/webshell ../dist/include/widget ../dist/include/uriloader ../dist/include/nkcache ../dist/include/docshell ../dist/include/profdirserviceprovider ../dist/include/layout ../dist/include/content ../dist/include/webbrowserpersist ../dist/include/pref ../dist/include/mimetype ../dist/include/shistory ../dist/include/history ../dist/include/view ../dist/include/gfx ../dist/include/xultmpl ../dist/include/xmlextras ../dist/include/htmlparser ../dist/include/locale ../dist/include/chardet ../dist/include/unicharutil ../dist/include/appcomps ../dist/include/chrome ../dist/include/xpcom ../dist/include/xpcom_obsolete ../dist/include/cookie ../dist/include/mork ../dist/include/ ../dist/public/nss ../ $(SYSTEM_DEVELOPER_DIR)/Headers/FlatCarbon $(LOCAL_LIBRARY_DIR)/Frameworks/SharedMenusCocoa.framework/Headers";
|
||||
HEADER_SEARCH_PATHS = "../dist/include/exthandler ../dist/include/helperAppDlg ../dist/include/intl ../dist/include/pipboot ../dist/include/pipnss ../dist/include/webbrwsr ../dist/include/dom ../dist/include/nspr ../dist/include/string ../dist/include/uconv ../dist/include/necko ../dist/include/find ../dist/include/embed_base ../dist/include/commandhandler ../dist/include/windowwatcher ../dist/include/webshell ../dist/include/widget ../dist/include/uriloader ../dist/include/nkcache ../dist/include/docshell ../dist/include/profdirserviceprovider ../dist/include/layout ../dist/include/content ../dist/include/webbrowserpersist ../dist/include/pref ../dist/include/mimetype ../dist/include/shistory ../dist/include/history ../dist/include/view ../dist/include/gfx ../dist/include/xultmpl ../dist/include/xmlextras ../dist/include/htmlparser ../dist/include/locale ../dist/include/chardet ../dist/include/unicharutil ../dist/include/appcomps ../dist/include/chrome ../dist/include/xpcom ../dist/include/xpcom_obsolete ../dist/include/cookie ../dist/include/mork ../dist/include/xpconnect ../dist/include/ ../dist/public/nss ../ $(SYSTEM_DEVELOPER_DIR)/Headers/FlatCarbon $(LOCAL_LIBRARY_DIR)/Frameworks/SharedMenusCocoa.framework/Headers";
|
||||
INFOPLIST_FILE = "Info-Camino.plist";
|
||||
INSTALL_PATH = "$(HOME)/Applications";
|
||||
LIBRARY_SEARCH_PATHS = "../dist/bin ../dist/lib ../dist/Embed/components ../intl/unicharutil/util";
|
||||
|
@ -7864,7 +7864,7 @@
|
|||
GCC_OPTIMIZATION_LEVEL = 2;
|
||||
GCC_PREFIX_HEADER = src/includes/ChimeraPrefix.h;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "OSTYPE=Darwin1.4 OSARCH=Darwin _BUILD_STATIC_BIN MOZILLA_INTERNAL_API=1";
|
||||
HEADER_SEARCH_PATHS = "../dist/include/helperAppDlg ../dist/include/exthandler ../dist/include/intl ../dist/include/pipboot ../dist/include/pipnss ../dist/include/webbrwsr ../dist/include/dom ../dist/include/nspr ../dist/include/string ../dist/include/uconv ../dist/include/necko ../dist/include/find ../dist/include/embed_base ../dist/include/commandhandler ../dist/include/windowwatcher ../dist/include/webshell ../dist/include/widget ../dist/include/uriloader ../dist/include/nkcache ../dist/include/docshell ../dist/include/profdirserviceprovider ../dist/include/layout ../dist/include/content ../dist/include/webbrowserpersist ../dist/include/pref ../dist/include/mimetype ../dist/include/shistory ../dist/include/history ../dist/include/view ../dist/include/gfx ../dist/include/xultmpl ../dist/include/xmlextras ../dist/include/htmlparser ../dist/include/locale ../dist/include/chardet ../dist/include/unicharutil ../dist/include/appcomps ../dist/include/chrome ../dist/include/xpcom ../dist/include/xpcom_obsolete ../dist/include/cookie ../dist/include/mork ../dist/include/ ../dist/public/nss $(SYSTEM_DEVELOPER_DIR)/Headers/FlatCarbon $(LOCAL_LIBRARY_DIR)/Frameworks/SharedMenusCocoa.framework/Headers";
|
||||
HEADER_SEARCH_PATHS = "../dist/include/helperAppDlg ../dist/include/exthandler ../dist/include/intl ../dist/include/pipboot ../dist/include/pipnss ../dist/include/webbrwsr ../dist/include/dom ../dist/include/nspr ../dist/include/string ../dist/include/uconv ../dist/include/necko ../dist/include/find ../dist/include/embed_base ../dist/include/commandhandler ../dist/include/windowwatcher ../dist/include/webshell ../dist/include/widget ../dist/include/uriloader ../dist/include/nkcache ../dist/include/docshell ../dist/include/profdirserviceprovider ../dist/include/layout ../dist/include/content ../dist/include/webbrowserpersist ../dist/include/pref ../dist/include/mimetype ../dist/include/shistory ../dist/include/history ../dist/include/view ../dist/include/gfx ../dist/include/xultmpl ../dist/include/xmlextras ../dist/include/htmlparser ../dist/include/locale ../dist/include/chardet ../dist/include/unicharutil ../dist/include/appcomps ../dist/include/chrome ../dist/include/xpcom ../dist/include/xpcom_obsolete ../dist/include/cookie ../dist/include/mork ../dist/include/xpconnect ../dist/include/ ../dist/public/nss $(SYSTEM_DEVELOPER_DIR)/Headers/FlatCarbon $(LOCAL_LIBRARY_DIR)/Frameworks/SharedMenusCocoa.framework/Headers";
|
||||
INFOPLIST_FILE = "Info-CaminoStatic.plist";
|
||||
INSTALL_PATH = "$(HOME)/Applications";
|
||||
LIBRARY_SEARCH_PATHS = "../dist/bin ../dist/lib ../dist/lib/components ../js/src/liveconnect ../js/src/xpconnect/loader";
|
||||
|
|
|
@ -133,12 +133,7 @@ NS_IMETHODIMP SecurityDialogs::ConfirmDownloadCACert(nsIInterfaceRequestor *ctx,
|
|||
|
||||
// XXX fix window parenting
|
||||
NSWindow* parentWindow = [(MainController*)[NSApp delegate] getFrontmostBrowserWindow];
|
||||
int result;
|
||||
if (parentWindow)
|
||||
result = [NSApp runModalForWindow:[downloadCertDialogController window] relativeToWindow:parentWindow];
|
||||
else
|
||||
result = [NSApp runModalForWindow:[downloadCertDialogController window]];
|
||||
|
||||
int result = [nsAlertController safeRunModalForWindow:[downloadCertDialogController window] relativeToWindow:parentWindow];
|
||||
if (result == NSAlertDefaultReturn)
|
||||
{
|
||||
*trust = [downloadCertDialogController trustMaskSetting];
|
||||
|
@ -148,7 +143,7 @@ NS_IMETHODIMP SecurityDialogs::ConfirmDownloadCACert(nsIInterfaceRequestor *ctx,
|
|||
*_retval = PR_FALSE;
|
||||
|
||||
[downloadCertDialogController release];
|
||||
return NS_OK;
|
||||
return (result == NSAlertErrorReturn) ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -202,16 +197,13 @@ NS_IMETHODIMP SecurityDialogs::SetPKCS12FilePassword(nsIInterfaceRequestor *ctx,
|
|||
[pwDialogController setTitle:titleString message:messageString];
|
||||
[pwDialogController hideChangePasswordField];
|
||||
|
||||
NSWindow* parentWindow = nil;
|
||||
// XXX fix window parenting
|
||||
#if 0
|
||||
NSWindow* parentWindow = [(MainController*)[NSApp delegate] getFrontmostBrowserWindow];
|
||||
int result;
|
||||
if (parentWindow)
|
||||
result = [NSApp runModalForWindow:[pwDialogController window] relativeToWindow:parentWindow];
|
||||
else
|
||||
parentWindow = [(MainController*)[NSApp delegate] getFrontmostBrowserWindow];
|
||||
#endif
|
||||
|
||||
int result = [NSApp runModalForWindow:[pwDialogController window]];
|
||||
int result = [nsAlertController safeRunModalForWindow:[pwDialogController window] relativeToWindow:parentWindow];
|
||||
BOOL confirmed = (result == NSAlertDefaultReturn);
|
||||
|
||||
NSString* thePassword = [pwDialogController newPassword];
|
||||
|
@ -220,7 +212,7 @@ NS_IMETHODIMP SecurityDialogs::SetPKCS12FilePassword(nsIInterfaceRequestor *ctx,
|
|||
[thePassword assignTo_nsAString:password];
|
||||
|
||||
[pwDialogController release];
|
||||
return NS_OK;
|
||||
return (result == NSAlertErrorReturn) ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -375,13 +367,8 @@ SecurityDialogs::ConfirmUnknownIssuer(nsIInterfaceRequestor *socketInfo,
|
|||
// HACK: there is no way to get which window this is for from the API. The
|
||||
// security team in mozilla just cheats and assumes the frontmost window so
|
||||
// that's what we'll do. Yes, it's wrong. Yes, it's skanky. Oh well.
|
||||
|
||||
NSWindow* parentWindow = [(MainController*)[NSApp delegate] getFrontmostBrowserWindow];
|
||||
int result;
|
||||
if (parentWindow)
|
||||
result = [NSApp runModalForWindow:[dialogController window] relativeToWindow:parentWindow];
|
||||
else
|
||||
result = [NSApp runModalForWindow:[dialogController window]];
|
||||
int result = [nsAlertController safeRunModalForWindow:[dialogController window] relativeToWindow:parentWindow];
|
||||
|
||||
switch (result)
|
||||
{
|
||||
|
@ -403,7 +390,7 @@ SecurityDialogs::ConfirmUnknownIssuer(nsIInterfaceRequestor *socketInfo,
|
|||
}
|
||||
|
||||
[dialogController release];
|
||||
return NS_OK;
|
||||
return (result == NSAlertErrorReturn) ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -436,16 +423,12 @@ SecurityDialogs::ConfirmMismatchDomain(nsIInterfaceRequestor *socketInfo,
|
|||
|
||||
// XXX fix window parenting
|
||||
NSWindow* parentWindow = [(MainController*)[NSApp delegate] getFrontmostBrowserWindow];
|
||||
int result;
|
||||
if (parentWindow)
|
||||
result = [NSApp runModalForWindow:[certDialogController window] relativeToWindow:parentWindow];
|
||||
else
|
||||
result = [NSApp runModalForWindow:[certDialogController window]];
|
||||
int result = [nsAlertController safeRunModalForWindow:[certDialogController window] relativeToWindow:parentWindow];
|
||||
|
||||
*_retval = (result == NSAlertDefaultReturn);
|
||||
|
||||
[certDialogController release];
|
||||
return NS_OK;
|
||||
return (result == NSAlertErrorReturn) ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -474,15 +457,12 @@ SecurityDialogs::ConfirmCertExpired(nsIInterfaceRequestor *socketInfo,
|
|||
[expiredCertController setCertificateItem:[CertificateItem certificateItemWithCert:cert]];
|
||||
// XXX fix window parenting
|
||||
NSWindow* parentWindow = [(MainController*)[NSApp delegate] getFrontmostBrowserWindow];
|
||||
int result;
|
||||
if (parentWindow)
|
||||
result = [NSApp runModalForWindow:[expiredCertController window] relativeToWindow:parentWindow];
|
||||
else
|
||||
result = [NSApp runModalForWindow:[expiredCertController window]];
|
||||
int result = [nsAlertController safeRunModalForWindow:[expiredCertController window] relativeToWindow:parentWindow];
|
||||
|
||||
*_retval = (result == NSAlertDefaultReturn);
|
||||
[expiredCertController release];
|
||||
return NS_OK;
|
||||
|
||||
return (result == NSAlertErrorReturn) ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -651,37 +631,35 @@ SecurityDialogs::SetPassword(nsIInterfaceRequestor *ctx, const PRUnichar *tokenN
|
|||
if (!showOldPasswordField)
|
||||
[pwDialogController hideChangePasswordField];
|
||||
|
||||
NSWindow* parentWindow = nil;
|
||||
// XXX fix window parenting
|
||||
#if 0
|
||||
NSWindow* parentWindow = [(MainController*)[NSApp delegate] getFrontmostBrowserWindow];
|
||||
int result;
|
||||
if (parentWindow)
|
||||
result = [NSApp runModalForWindow:[pwDialogController window] relativeToWindow:parentWindow];
|
||||
else
|
||||
parentWindow = [(MainController*)[NSApp delegate] getFrontmostBrowserWindow];
|
||||
#endif
|
||||
|
||||
int result = [NSApp runModalForWindow:[pwDialogController window]];
|
||||
int result = [nsAlertController safeRunModalForWindow:[pwDialogController window] relativeToWindow:parentWindow];
|
||||
|
||||
[pwDialogController setDelegate:nil];
|
||||
|
||||
if (result != NSAlertDefaultReturn)
|
||||
nsresult rv;
|
||||
if (result == NSAlertDefaultReturn)
|
||||
{
|
||||
*canceled = PR_FALSE;
|
||||
|
||||
nsAutoString oldPassword, newPassword;
|
||||
[[pwDialogController currentPassword] assignTo_nsAString:oldPassword];
|
||||
[[pwDialogController newPassword] assignTo_nsAString:newPassword];
|
||||
|
||||
if (slotStatus == nsIPKCS11Slot::SLOT_UNINITIALIZED)
|
||||
rv = theToken->InitPassword(newPassword.get());
|
||||
else
|
||||
rv = theToken->ChangePassword(oldPassword.get(), newPassword.get());
|
||||
}
|
||||
else
|
||||
{
|
||||
*canceled = PR_TRUE;
|
||||
return NS_OK;
|
||||
rv = (result == NSAlertErrorReturn) ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
|
||||
*canceled = PR_FALSE;
|
||||
|
||||
nsAutoString oldPassword, newPassword;
|
||||
[[pwDialogController currentPassword] assignTo_nsAString:oldPassword];
|
||||
[[pwDialogController newPassword] assignTo_nsAString:newPassword];
|
||||
|
||||
nsresult rv;
|
||||
if (slotStatus == nsIPKCS11Slot::SLOT_UNINITIALIZED)
|
||||
rv = theToken->InitPassword(newPassword.get());
|
||||
else
|
||||
rv = theToken->ChangePassword(oldPassword.get(), newPassword.get());
|
||||
|
||||
|
||||
[pwDialogController release];
|
||||
return rv;
|
||||
}
|
||||
|
@ -791,11 +769,7 @@ SecurityDialogs::ChooseCertificate(nsIInterfaceRequestor *ctx, const PRUnichar *
|
|||
|
||||
// XXX fix window parenting
|
||||
NSWindow* parentWindow = [(MainController*)[NSApp delegate] getFrontmostBrowserWindow];
|
||||
int result;
|
||||
if (parentWindow)
|
||||
result = [NSApp runModalForWindow:[dialogController window] relativeToWindow:parentWindow];
|
||||
else
|
||||
result = [NSApp runModalForWindow:[dialogController window]];
|
||||
int result = [nsAlertController safeRunModalForWindow:[dialogController window] relativeToWindow:parentWindow];
|
||||
|
||||
if (result == NSAlertDefaultReturn)
|
||||
{
|
||||
|
@ -809,7 +783,7 @@ SecurityDialogs::ChooseCertificate(nsIInterfaceRequestor *ctx, const PRUnichar *
|
|||
|
||||
[dialogController release];
|
||||
|
||||
return NS_OK;
|
||||
return (result == NSAlertErrorReturn) ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
|
||||
// nsITokenDialogs
|
||||
|
@ -902,7 +876,7 @@ SecurityDialogs::DisplayGeneratingKeypairInfo(nsIInterfaceRequestor *ctx, nsIKey
|
|||
nsCOMPtr<nsIObserver> completionObserver = new GenKeyPairCompletionObserver(dialogController);
|
||||
runnable->StartKeyGeneration(completionObserver);
|
||||
|
||||
int result = [NSApp runModalForWindow:[dialogController window]];
|
||||
int result = [nsAlertController safeRunModalForWindow:[dialogController window] relativeToWindow:nil];
|
||||
|
||||
eventQueueService->PopThreadEventQueue(newQueue);
|
||||
|
||||
|
@ -916,7 +890,7 @@ SecurityDialogs::DisplayGeneratingKeypairInfo(nsIInterfaceRequestor *ctx, nsIKey
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return (result == NSAlertErrorReturn) ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -46,6 +46,24 @@
|
|||
- (IBAction)hitButton2:(id)sender;
|
||||
- (IBAction)hitButton3:(id)sender;
|
||||
|
||||
//
|
||||
// This is a version of [NSApp runModalForWindow:(relativeToWindow:)] that does three
|
||||
// things:
|
||||
//
|
||||
// 1. It verifies that inParentWindow is a valid window to show a sheet on
|
||||
// (i.e. that it's not nil, is visible, and doesn't already have a sheet).
|
||||
//
|
||||
// 2. It doesn't show inWindow as a sheet if there is already a modal (non-sheet)
|
||||
// dialog on the screen, because that fubars AppKit.
|
||||
//
|
||||
// 3. It does some JS context stack magic that pushes a "native code" security principle
|
||||
// ("trust label") so that Gecko knows we're running native code, and not calling
|
||||
// from JS. This is important, because we can remain on the stack while PLEvents
|
||||
// are being handled in the sheet's event loop, and those PLEvents can cause
|
||||
// code to run that is sensitive to the security context. See bug 179307 for details.
|
||||
//
|
||||
+ (int)safeRunModalForWindow:(NSWindow*)inWindow relativeToWindow:(NSWindow*)inParentWindow;
|
||||
|
||||
//
|
||||
// Nota Bene: all of these methods can throw Objective-C exceptions
|
||||
// if there was an error displaying the dialog.
|
||||
|
|
|
@ -34,7 +34,11 @@
|
|||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
struct JSContext; // allow nsIJSContextStack to be included without sucking in JS headers
|
||||
#include "nsIJSContextStack.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
#import "nsAlertController.h"
|
||||
#import "CHBrowserService.h"
|
||||
|
||||
|
@ -115,6 +119,42 @@ const int kLabelCheckboxAdjustment = 2; // # pixels the label must be pushed dow
|
|||
|
||||
@implementation nsAlertController
|
||||
|
||||
+ (int)safeRunModalForWindow:(NSWindow*)inWindow relativeToWindow:(NSWindow*)inParentWindow
|
||||
{
|
||||
if (inParentWindow)
|
||||
{
|
||||
// If there is already a modal window up, convert a sheet into a modal window,
|
||||
// because AppKit will hang if you try to do this (possibly because we're using
|
||||
// the deprecated and sucky runModalForWindow:relativeToWindow:).
|
||||
// Also, if the parent window already has an attached sheet, or is not visible,
|
||||
// also null out the parent and show this as a modal dialog.
|
||||
if ([NSApp modalWindow] || [inParentWindow attachedSheet] || ![inParentWindow isVisible])
|
||||
inParentWindow = nil;
|
||||
}
|
||||
|
||||
int result = NSAlertErrorReturn;
|
||||
|
||||
nsCOMPtr<nsIJSContextStack> stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
|
||||
if (stack && NS_SUCCEEDED(stack->Push(nsnull)))
|
||||
{
|
||||
// be paranoid; we don't want to throw Obj-C exceptions over C++ code
|
||||
NS_DURING
|
||||
if (inParentWindow)
|
||||
result = [NSApp runModalForWindow:inWindow relativeToWindow:inParentWindow];
|
||||
else
|
||||
result = [NSApp runModalForWindow:inWindow];
|
||||
NS_HANDLER
|
||||
NSLog(@"Exception caught in safeRunModalForWindow:relativeToWindow: %@", localException);
|
||||
NS_ENDHANDLER
|
||||
|
||||
JSContext* cx;
|
||||
stack->Pop(&cx);
|
||||
NS_ASSERTION(cx == nsnull, "JSContextStack mismatch");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (IBAction)hitButton1:(id)sender
|
||||
{
|
||||
[NSApp stopModalWithCode:NSAlertDefaultReturn];
|
||||
|
@ -398,23 +438,8 @@ const int kLabelCheckboxAdjustment = 2; // # pixels the label must be pushed dow
|
|||
|
||||
- (int)runModalWindow:(NSWindow*)inDialog relativeToWindow:(NSWindow*)inParentWindow
|
||||
{
|
||||
if (inParentWindow)
|
||||
{
|
||||
// If there is already a modal window up, convert a sheet into a modal window,
|
||||
// because AppKit will hang if you try to do this (possibly because we're using
|
||||
// the deprecated and sucky runModalForWindow:relativeToWindow:).
|
||||
// Also, if the parent window already has an attached sheet, or is not visible,
|
||||
// also null out the parent and show this as a modal dialog.
|
||||
if ([NSApp modalWindow] || [inParentWindow attachedSheet] || ![inParentWindow isVisible])
|
||||
inParentWindow = nil;
|
||||
}
|
||||
int result = [nsAlertController safeRunModalForWindow:inDialog relativeToWindow:inParentWindow];
|
||||
|
||||
int result;
|
||||
if (inParentWindow)
|
||||
result = [NSApp runModalForWindow:inDialog relativeToWindow:inParentWindow];
|
||||
else
|
||||
result = [NSApp runModalForWindow:inDialog];
|
||||
|
||||
// Convert any error into an exception
|
||||
if (result == NSAlertErrorReturn)
|
||||
[NSException raise:NSInternalInconsistencyException format:@"-runModalForWindow returned error"];
|
||||
|
|
|
@ -37,9 +37,10 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#import "ImageAdditions.h"
|
||||
#import "NSBezierPath+Utils.h"
|
||||
|
||||
#import "TabButtonCell.h"
|
||||
#import "TruncatingTextAndImageCell.h"
|
||||
#import "BrowserTabBarView.h"
|
||||
|
||||
static const int kTabLeftMargin = 4; //distance between left edge and close button
|
||||
static const int kTabCloseButtonPad = 2; //distance between close button and label
|
||||
|
|
Загрузка…
Ссылка в новой задаче