mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 10:00:54 +00:00
3e9dcd40e5
Site icons that are loaded to into the necko cache. We also cache data for missing site icons, to avoid continual refetches. Site icons are on by default, but can be turned off via the "browser.chrome.site_icons" pref.
670 lines
19 KiB
Plaintext
670 lines
19 KiB
Plaintext
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.1 (the "License"); you may not use this file except in
|
|
* compliance with the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 2002
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the NPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the NPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#import "NSString+Utils.h"
|
|
|
|
#import "CHPreferenceManager.h"
|
|
#import "CHBrowserWrapper.h"
|
|
#import "BrowserWindowController.h"
|
|
#import "BookmarksService.h"
|
|
#import "SiteIconProvider.h"
|
|
#import "CHIconTabViewItem.h"
|
|
#import "ToolTip.h"
|
|
|
|
#include "nsCOMPtr.h"
|
|
#include "nsIServiceManager.h"
|
|
#include "nsIIOService.h"
|
|
#include "ContentClickListener.h"
|
|
#include "nsIDOMWindow.h"
|
|
#include "nsIWebBrowser.h"
|
|
#include "nsIDOMDocument.h"
|
|
#include "nsIDOMHTMLDocument.h"
|
|
#include "nsIChromeEventHandler.h"
|
|
#include "nsPIDOMWindow.h"
|
|
#include "nsIDOMEventReceiver.h"
|
|
#include "nsIPrefBranch.h"
|
|
#include "nsIPrefService.h"
|
|
#include "nsCocoaBrowserService.h"
|
|
#include "nsIWebProgressListener.h"
|
|
|
|
#include <QuickDraw.h>
|
|
|
|
#define DOCUMENT_DONE_STRING @"Document: Done"
|
|
|
|
static const char* ioServiceContractID = "@mozilla.org/network/io-service;1";
|
|
|
|
const NSString* kOfflineNotificationName = @"offlineModeChanged";
|
|
|
|
@interface CHBrowserWrapper(Private)
|
|
|
|
- (void)setPendingActive:(BOOL)active;
|
|
- (void)registerNotificationListener;
|
|
|
|
- (void)setSiteIconImage:(NSImage*)inSiteIcon;
|
|
- (void)setSiteIconURI:(NSString*)inSiteIconURI;
|
|
|
|
- (void)updateSiteIconImage:(NSImage*)inSiteIcon withURI:(NSString *)inSiteIconURI;
|
|
|
|
@end
|
|
|
|
@implementation CHBrowserWrapper
|
|
|
|
-(void)windowClosed
|
|
{
|
|
// Break the cycle.
|
|
[mBrowserView destroyWebBrowser];
|
|
[mBrowserView setContainer: nil];
|
|
[mBrowserView removeListener: self];
|
|
}
|
|
|
|
-(void)dealloc
|
|
{
|
|
#if DEBUG
|
|
NSLog(@"The browser wrapper died.");
|
|
#endif
|
|
|
|
[[NSNotificationCenter defaultCenter] removeObserver: self];
|
|
|
|
[mSiteIconImage release];
|
|
[mSiteIconURI release];
|
|
[mDefaultStatusString release];
|
|
[mLoadingStatusString release];
|
|
[mToolTip release];
|
|
|
|
[super dealloc];
|
|
}
|
|
|
|
- (IBAction)load:(id)sender
|
|
{
|
|
[mBrowserView loadURI:[urlbar stringValue] referrer:nil flags:NSLoadFlagsNone];
|
|
}
|
|
|
|
-(void)disconnectView
|
|
{
|
|
urlbar = nil;
|
|
status = nil;
|
|
progress = nil;
|
|
progressSuper = nil;
|
|
mIsPrimary = NO;
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self name:kOfflineNotificationName object:nil];
|
|
|
|
[mBrowserView setActive: NO];
|
|
}
|
|
|
|
-(id)initWithTab:(id)aTab andWindow: (NSWindow*)aWindow
|
|
{
|
|
mTab = aTab;
|
|
mWindow = aWindow;
|
|
mIsBookmarksImport = NO;
|
|
return [self initWithFrame: NSZeroRect];
|
|
}
|
|
|
|
//
|
|
// initWithFrame: (designated initializer)
|
|
//
|
|
// Create a Gecko browser view and hook everything up to the UI
|
|
//
|
|
- (id)initWithFrame:(NSRect)frameRect
|
|
{
|
|
if ( (self = [super initWithFrame: frameRect]) ) {
|
|
mBrowserView = [[[CHBrowserView alloc] initWithFrame:[self bounds] andWindow: [self getNativeWindow]] autorelease];
|
|
[self addSubview: mBrowserView];
|
|
[mBrowserView setContainer:self];
|
|
[mBrowserView addListener:self];
|
|
mIsBusy = NO;
|
|
mListenersAttached = NO;
|
|
mSecureState = nsIWebProgressListener::STATE_IS_INSECURE;
|
|
|
|
mToolTip = [[ToolTip alloc] init];
|
|
|
|
//[self setSiteIconImage:[NSImage imageNamed:@"globe_ico"]];
|
|
//[self setSiteIconURI: [NSString string]];
|
|
|
|
[self registerNotificationListener];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
-(void)setTab: (NSTabViewItem*)tab
|
|
{
|
|
mTab = tab;
|
|
}
|
|
|
|
-(void)makePrimaryBrowserView: (id)aUrlbar status: (id)aStatus
|
|
progress: (id)aProgress windowController: (BrowserWindowController*)aWindowController
|
|
{
|
|
urlbar = aUrlbar;
|
|
status = aStatus;
|
|
progress = aProgress;
|
|
progressSuper = [aProgress superview];
|
|
mWindowController = aWindowController;
|
|
|
|
if (!mIsBusy)
|
|
[progress removeFromSuperview];
|
|
|
|
mDefaultStatusString = NULL;
|
|
mLoadingStatusString = DOCUMENT_DONE_STRING;
|
|
[status setStringValue:mLoadingStatusString];
|
|
|
|
mIsPrimary = YES;
|
|
|
|
// update the global lock icon to the current state of this browser. We need
|
|
// to do this after we set |mIsPrimary|.
|
|
[self onSecurityStateChange:mSecureState];
|
|
|
|
// update the window's title.
|
|
[self setTitle:mTitle];
|
|
|
|
if ([[self window] isKeyWindow])
|
|
[mBrowserView setActive: YES];
|
|
|
|
nsCOMPtr<nsIIOService> ioService(do_GetService(ioServiceContractID));
|
|
if (!ioService)
|
|
return;
|
|
PRBool offline = PR_FALSE;
|
|
ioService->GetOffline(&offline);
|
|
mOffline = offline;
|
|
|
|
if (mWindowController) // Only register if we're the content area.
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(offlineModeChanged:)
|
|
name:kOfflineNotificationName
|
|
object:nil];
|
|
|
|
// Update the URL bar.
|
|
[mWindowController updateLocationFields:[self getCurrentURLSpec]];
|
|
[mWindowController updateSiteIcons:mSiteIconImage];
|
|
|
|
if (mWindowController && !mListenersAttached) {
|
|
mListenersAttached = YES;
|
|
|
|
// We need to hook up our click and context menu listeners.
|
|
ContentClickListener* clickListener = new ContentClickListener(mWindowController);
|
|
if (!clickListener)
|
|
return;
|
|
|
|
nsCOMPtr<nsIDOMWindow> contentWindow = getter_AddRefs([[self getBrowserView] getContentWindow]);
|
|
nsCOMPtr<nsPIDOMWindow> piWindow(do_QueryInterface(contentWindow));
|
|
nsCOMPtr<nsIChromeEventHandler> chromeHandler;
|
|
piWindow->GetChromeEventHandler(getter_AddRefs(chromeHandler));
|
|
nsCOMPtr<nsIDOMEventReceiver> rec(do_QueryInterface(chromeHandler));
|
|
rec->AddEventListenerByIID(clickListener, NS_GET_IID(nsIDOMMouseListener));
|
|
}
|
|
}
|
|
|
|
-(NSString*)getCurrentURLSpec
|
|
{
|
|
return [mBrowserView getCurrentURLSpec];
|
|
}
|
|
|
|
- (void)awakeFromNib
|
|
{
|
|
}
|
|
|
|
- (void)setFrame:(NSRect)frameRect
|
|
{
|
|
[super setFrame:frameRect];
|
|
|
|
// Only resize our browser view if we are visible. If we're hidden, the frame
|
|
// will get reset when we get placed back into the view hierarchy anyway. This
|
|
// enhancement keeps resizing in a window with many tabs from being slow.
|
|
if ([self window]) {
|
|
NSRect bounds = [self bounds];
|
|
[mBrowserView setFrame:bounds];
|
|
}
|
|
}
|
|
|
|
-(BOOL)isBusy
|
|
{
|
|
return mIsBusy;
|
|
}
|
|
|
|
- (void)loadURI:(NSString *)urlSpec referrer:(NSString*)referrer flags:(unsigned int)flags activate:(BOOL)activate
|
|
{
|
|
mActivateOnLoad = activate;
|
|
[mBrowserView loadURI:urlSpec referrer:referrer flags:flags];
|
|
}
|
|
|
|
- (void)onLoadingStarted
|
|
{
|
|
if (mDefaultStatusString) {
|
|
[mDefaultStatusString release];
|
|
mDefaultStatusString = NULL;
|
|
}
|
|
|
|
[progressSuper addSubview:progress];
|
|
[progress setIndeterminate:YES];
|
|
[progress startAnimation:self];
|
|
|
|
mLoadingStatusString = NSLocalizedString(@"TabLoading", @"");
|
|
[status setStringValue:mLoadingStatusString];
|
|
|
|
mIsBusy = YES;
|
|
[mTab setLabel: NSLocalizedString(@"TabLoading", @"")];
|
|
|
|
if (mWindowController) {
|
|
[mWindowController updateToolbarItems];
|
|
[mWindowController startThrobber];
|
|
}
|
|
}
|
|
|
|
- (void)onLoadingCompleted:(BOOL)succeeded
|
|
{
|
|
if (mActivateOnLoad) {
|
|
[mBrowserView setActive:YES];
|
|
mActivateOnLoad = NO;
|
|
}
|
|
|
|
[progress setIndeterminate:YES];
|
|
[progress stopAnimation:self];
|
|
[progress removeFromSuperview];
|
|
|
|
mLoadingStatusString = DOCUMENT_DONE_STRING;
|
|
if (mDefaultStatusString) {
|
|
[status setStringValue:mDefaultStatusString];
|
|
}
|
|
else {
|
|
[status setStringValue:mLoadingStatusString];
|
|
}
|
|
|
|
mIsBusy = NO;
|
|
|
|
if (mIsBookmarksImport) {
|
|
nsCOMPtr<nsIDOMWindow> domWindow;
|
|
nsCOMPtr<nsIWebBrowser> webBrowser = getter_AddRefs([mBrowserView getWebBrowser]);
|
|
webBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
|
|
if (domWindow) {
|
|
nsCOMPtr<nsIDOMDocument> domDocument;
|
|
domWindow->GetDocument(getter_AddRefs(domDocument));
|
|
nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(domDocument));
|
|
if (htmlDoc)
|
|
BookmarksService::ImportBookmarks(htmlDoc);
|
|
}
|
|
[self windowClosed];
|
|
[self removeFromSuperview];
|
|
}
|
|
|
|
if (mWindowController) {
|
|
[mWindowController updateToolbarItems];
|
|
[mWindowController stopThrobber];
|
|
}
|
|
}
|
|
|
|
- (void)onProgressChange:(int)currentBytes outOf:(int)maxBytes
|
|
{
|
|
if (maxBytes > 0) {
|
|
BOOL isIndeterminate = [progress isIndeterminate];
|
|
if (isIndeterminate) {
|
|
[progress setIndeterminate:NO];
|
|
}
|
|
double val = ((double)currentBytes / (double)maxBytes) * 100.0;
|
|
[progress setDoubleValue:val];
|
|
}
|
|
}
|
|
|
|
- (void)onLocationChange:(NSString*)urlSpec
|
|
{
|
|
BOOL useSiteIcons = [[CHPreferenceManager sharedInstance] getBooleanPref:"browser.chrome.site_icons" withSuccess:NULL];
|
|
BOOL siteIconLoadInitiated = NO;
|
|
|
|
SiteIconProvider* faviconProvider = [SiteIconProvider sharedFavoriteIconProvider];
|
|
NSString* faviconURI = [SiteIconProvider faviconLocationStringFromURI:urlSpec];
|
|
|
|
if (useSiteIcons && [faviconURI length] > 0)
|
|
{
|
|
// if the favicon uri has changed, fire off favicon load. When it completes, our
|
|
// imageLoadedNotification selector gets called.
|
|
if (![faviconURI isEqualToString:mSiteIconURI])
|
|
siteIconLoadInitiated = [faviconProvider loadFavoriteIcon:self forURI:urlSpec withUserData:nil allowNetwork:YES];
|
|
}
|
|
else
|
|
{
|
|
if ([urlSpec isEqualToString:@"about:blank"])
|
|
faviconURI = urlSpec;
|
|
else
|
|
faviconURI = @"";
|
|
}
|
|
|
|
if (!siteIconLoadInitiated)
|
|
[self updateSiteIconImage:nil withURI:faviconURI];
|
|
|
|
if (mIsPrimary)
|
|
[mWindowController updateLocationFields:urlSpec];
|
|
}
|
|
|
|
- (void)onStatusChange:(NSString*)aStatusString
|
|
{
|
|
[status setStringValue: aStatusString];
|
|
}
|
|
|
|
//
|
|
// onSecurityStateChange:
|
|
//
|
|
// Update the lock to the appropriate icon to match what necko is telling us, but
|
|
// only if we own the UI. If we're not the primary browser, we have no business
|
|
// mucking with the lock icon.
|
|
//
|
|
- (void)onSecurityStateChange:(unsigned long)newState
|
|
{
|
|
mSecureState = newState;
|
|
if ( mIsPrimary )
|
|
[mWindowController updateLock:newState];
|
|
}
|
|
|
|
- (void)setStatus:(NSString *)statusString ofType:(NSStatusType)type
|
|
{
|
|
if (type == NSStatusTypeScriptDefault) {
|
|
if (mDefaultStatusString) {
|
|
[mDefaultStatusString release];
|
|
}
|
|
mDefaultStatusString = statusString;
|
|
if (mDefaultStatusString) {
|
|
[mDefaultStatusString retain];
|
|
}
|
|
}
|
|
else if (!statusString) {
|
|
if (mDefaultStatusString) {
|
|
[status setStringValue:mDefaultStatusString];
|
|
}
|
|
else {
|
|
[status setStringValue:mLoadingStatusString];
|
|
}
|
|
}
|
|
else {
|
|
[status setStringValue:statusString];
|
|
}
|
|
}
|
|
|
|
- (NSString *)title
|
|
{
|
|
return mTitle;
|
|
}
|
|
|
|
- (void)setTitle:(NSString *)title
|
|
{
|
|
[mTitle autorelease];
|
|
|
|
// We must be the primary content area to actually set the title, but we
|
|
// still want to hold onto the title in case we become the primary later.
|
|
NSString* newTitle = nil;
|
|
if (mOffline) {
|
|
if (title && ![title isEqualToString:@""])
|
|
newTitle = [title stringByAppendingString: @" [Working Offline]"]; // XXX localize me
|
|
else
|
|
newTitle = [NSString stringWithString:@"Untitled [Working Offline]"];
|
|
mTitle = [newTitle retain];
|
|
}
|
|
else {
|
|
if (!title || [title isEqualToString:@""])
|
|
title = [NSString stringWithString:NSLocalizedString(@"UntitledPageTitle", @"")];
|
|
mTitle = [title retain];
|
|
}
|
|
|
|
if ( mIsPrimary && mWindowController )
|
|
[[mWindowController window] setTitle:[mTitle stringByTruncatingTo:80 at:kTruncateAtEnd]];
|
|
|
|
// Always set the tab.
|
|
if (title && ![title isEqualToString:@""])
|
|
[mTab setLabel:title]; // tab titles get truncated when setting them to tabs
|
|
else
|
|
[mTab setLabel:NSLocalizedString(@"UntitledPageTitle", @"")];
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isFlipped
|
|
{
|
|
return YES;
|
|
}
|
|
|
|
//
|
|
// onShowTooltip:where:withText
|
|
//
|
|
// Unfortunately, we can't use cocoa's apis here because they rely on setting a region
|
|
// and waiting. We already have waited and we just want to display the tooltip, so we
|
|
// drop down to the Carbon help manager routines.
|
|
//
|
|
// |where| is relative to the browser view in QD coordinates (top left is (0,0))
|
|
// and must be converted to global QD coordinates for the carbon help manager.
|
|
//
|
|
- (void)onShowTooltip:(NSPoint)where withText:(NSString*)text
|
|
{
|
|
NSPoint point = [[self window] convertBaseToScreen:[self convertPoint: where toView:nil]];
|
|
[mToolTip showToolTipAtPoint: point withString: text];
|
|
}
|
|
|
|
- (void)onHideTooltip
|
|
{
|
|
[mToolTip closeToolTip];
|
|
}
|
|
|
|
// Called when a context menu should be shown.
|
|
- (void)onShowContextMenu:(int)flags domEvent:(nsIDOMEvent*)aEvent domNode:(nsIDOMNode*)aNode
|
|
{
|
|
[mWindowController onShowContextMenu: flags domEvent: aEvent domNode: aNode];
|
|
}
|
|
|
|
-(NSMenu*)getContextMenu
|
|
{
|
|
return [mWindowController getContextMenu];
|
|
}
|
|
|
|
-(NSWindow*)getNativeWindow
|
|
{
|
|
NSWindow* window = [self window];
|
|
if (window)
|
|
return window;
|
|
|
|
if (mWindow)
|
|
return mWindow;
|
|
|
|
return nil;
|
|
}
|
|
|
|
-(void)setIsBookmarksImport:(BOOL)aIsImport
|
|
{
|
|
mIsBookmarksImport = aIsImport;
|
|
}
|
|
|
|
- (void)offlineModeChanged: (NSNotification*)aNotification
|
|
{
|
|
nsCOMPtr<nsIIOService> ioService(do_GetService(ioServiceContractID));
|
|
if (!ioService)
|
|
return;
|
|
PRBool offline = PR_FALSE;
|
|
ioService->GetOffline(&offline);
|
|
mOffline = offline;
|
|
|
|
if (mOffline) {
|
|
NSString* newTitle = [[[mWindowController window] title] stringByAppendingString: @" [Working Offline]"];
|
|
[[mWindowController window] setTitle: newTitle];
|
|
}
|
|
else {
|
|
NSArray* titleItems = [[[mWindowController window] title] componentsSeparatedByString:@" [Working Offline]"];
|
|
[[mWindowController window] setTitle: [titleItems objectAtIndex: 0]];
|
|
}
|
|
}
|
|
|
|
//
|
|
// sizeBrowserTo
|
|
//
|
|
// Sizes window so that browser has dimensions given by |dimensions|
|
|
//
|
|
- (void)sizeBrowserTo:(NSSize)dimensions
|
|
{
|
|
NSRect bounds = [self bounds];
|
|
float dx = dimensions.width - bounds.size.width;
|
|
float dy = dimensions.height - bounds.size.height;
|
|
|
|
NSRect frame = [[self window] frame];
|
|
frame.size.width += dx;
|
|
frame.size.height += dy;
|
|
|
|
[[self window] setFrame:frame display:YES];
|
|
}
|
|
|
|
- (CHBrowserView*)createBrowserWindow:(unsigned int)aMask
|
|
{
|
|
nsCOMPtr<nsIPrefBranch> pref(do_GetService("@mozilla.org/preferences-service;1"));
|
|
if (!pref)
|
|
return NS_OK; // Something bad happened if we can't get prefs.
|
|
|
|
PRBool showBlocker;
|
|
pref->GetBoolPref("browser.popups.showPopupBlocker", &showBlocker);
|
|
|
|
if (showBlocker) {
|
|
nsCOMPtr<nsIDOMWindow> domWindow = getter_AddRefs([mBrowserView getContentWindow]);
|
|
nsCOMPtr<nsPIDOMWindow> piWindow(do_QueryInterface(domWindow));
|
|
PRBool isUnrequested;
|
|
piWindow->IsLoadingOrRunningTimeout(&isUnrequested);
|
|
if (isUnrequested) {
|
|
// A popup is being opened while the page is currently loading. Offer to block the
|
|
// popup.
|
|
nsAlertController* controller = nsCocoaBrowserService::GetAlertController();
|
|
BOOL confirm = [controller confirm: [self window] title: @"Unrequested Popup Detected"
|
|
text: [NSString stringWithFormat: NSLocalizedString(@"PopupBlockMsg", @""), NSLocalizedStringFromTable(@"CFBundleName", @"InfoPlist", nil)]];
|
|
|
|
// This is a one-time dialog.
|
|
pref->SetBoolPref("browser.popups.showPopupBlocker", PR_FALSE);
|
|
|
|
if (confirm) {
|
|
pref->SetBoolPref("dom.disable_open_during_load", PR_TRUE);
|
|
pref->SetIntPref("dom.disable_open_click_delay", 1000);
|
|
}
|
|
|
|
nsCOMPtr<nsIPrefService> prefService(do_QueryInterface(pref));
|
|
prefService->SavePrefFile(nsnull);
|
|
|
|
if (confirm)
|
|
return nil;
|
|
}
|
|
}
|
|
|
|
BrowserWindowController* controller = [[BrowserWindowController alloc] initWithWindowNibName: @"BrowserWindow"];
|
|
[controller setChromeMask: aMask];
|
|
[controller disableAutosave]; // The Web page opened this window, so we don't ever use its settings.
|
|
[controller disableLoadPage]; // don't load about:blank initially since this is a script-opened window
|
|
[controller enterModalSession];
|
|
[[controller getBrowserWrapper] setPendingActive: YES];
|
|
return [[controller getBrowserWrapper] getBrowserView];
|
|
}
|
|
|
|
- (CHBrowserView*)getBrowserView
|
|
{
|
|
return mBrowserView;
|
|
}
|
|
|
|
- (void)setPendingActive:(BOOL)active
|
|
{
|
|
mActivateOnLoad = active;
|
|
}
|
|
|
|
- (void)setSiteIconImage:(NSImage*)inSiteIcon
|
|
{
|
|
[mSiteIconImage autorelease];
|
|
mSiteIconImage = [inSiteIcon retain];
|
|
}
|
|
|
|
- (void)setSiteIconURI:(NSString*)inSiteIconURI
|
|
{
|
|
[mSiteIconURI autorelease];
|
|
mSiteIconURI = [inSiteIconURI retain];
|
|
}
|
|
|
|
// A nil inSiteIcon image indicates that we should use the default icon
|
|
// If inSiteIconURI is "about:blank", we don't show any icon
|
|
- (void)updateSiteIconImage:(NSImage*)inSiteIcon withURI:(NSString *)inSiteIconURI
|
|
{
|
|
BOOL resetTabIcon = NO;
|
|
|
|
if (![mSiteIconURI isEqualToString:inSiteIconURI])
|
|
{
|
|
if (!inSiteIcon)
|
|
{
|
|
if (![inSiteIconURI isEqualToString:@"about:blank"])
|
|
inSiteIcon = [NSImage imageNamed:@"globe_ico"];
|
|
}
|
|
|
|
[self setSiteIconImage: inSiteIcon];
|
|
[self setSiteIconURI: inSiteIconURI];
|
|
|
|
// update the proxy icon
|
|
if (mIsPrimary)
|
|
[mWindowController updateSiteIcons:mSiteIconImage];
|
|
|
|
resetTabIcon = YES;
|
|
}
|
|
|
|
// update the tab icon
|
|
if ([mTab isMemberOfClass:[CHIconTabViewItem class]])
|
|
{
|
|
CHIconTabViewItem* tabItem = (CHIconTabViewItem*)mTab;
|
|
if (resetTabIcon || ![tabItem tabIcon])
|
|
[tabItem setTabIcon:mSiteIconImage];
|
|
}
|
|
|
|
}
|
|
|
|
- (void)registerNotificationListener
|
|
{
|
|
[[NSNotificationCenter defaultCenter] addObserver: self
|
|
selector: @selector(imageLoadedNotification:)
|
|
name: SiteIconLoadNotificationName
|
|
object: self];
|
|
|
|
}
|
|
|
|
// called when [[SiteIconProvider sharedFavoriteIconProvider] loadFavoriteIcon] completes
|
|
- (void)imageLoadedNotification:(NSNotification*)notification
|
|
{
|
|
NSDictionary* userInfo = [notification userInfo];
|
|
if (userInfo)
|
|
{
|
|
NSImage* iconImage = [userInfo objectForKey:SiteIconLoadImageKey];
|
|
NSString* siteIconURI = [userInfo objectForKey:SiteIconLoadURIKey];
|
|
|
|
// NSLog(@"CHBrowserWrapper imageLoadedNotification got image %@ and uri %@", iconImage, proxyImageURI);
|
|
if (iconImage == nil)
|
|
siteIconURI = @""; // go back to default image
|
|
|
|
[self updateSiteIconImage:iconImage withURI:siteIconURI];
|
|
}
|
|
}
|
|
|
|
|
|
@end
|