summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ui/cocoa/notifications/balloon_controller.mm
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/ui/cocoa/notifications/balloon_controller.mm')
-rw-r--r--chrome/browser/ui/cocoa/notifications/balloon_controller.mm241
1 files changed, 241 insertions, 0 deletions
diff --git a/chrome/browser/ui/cocoa/notifications/balloon_controller.mm b/chrome/browser/ui/cocoa/notifications/balloon_controller.mm
new file mode 100644
index 0000000..f0d914e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/notifications/balloon_controller.mm
@@ -0,0 +1,241 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/cocoa/notifications/balloon_controller.h"
+
+#include "app/l10n_util.h"
+#include "app/mac/nsimage_cache.h"
+#include "app/resource_bundle.h"
+#import "base/mac/cocoa_protocols.h"
+#include "base/mac_util.h"
+#import "base/scoped_nsobject.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/notifications/balloon.h"
+#include "chrome/browser/notifications/desktop_notification_service.h"
+#include "chrome/browser/notifications/notification.h"
+#include "chrome/browser/notifications/notification_options_menu_model.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#import "chrome/browser/ui/cocoa/hover_image_button.h"
+#import "chrome/browser/ui/cocoa/menu_controller.h"
+#import "chrome/browser/ui/cocoa/notifications/balloon_view.h"
+#include "chrome/browser/ui/cocoa/notifications/balloon_view_host_mac.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+
+namespace {
+
+// Margin, in pixels, between the notification frame and the contents
+// of the notification.
+const int kTopMargin = 1;
+const int kBottomMargin = 2;
+const int kLeftMargin = 2;
+const int kRightMargin = 2;
+
+} // namespace
+
+@interface BalloonController (Private)
+- (void)updateTrackingRect;
+@end
+
+@implementation BalloonController
+
+- (id)initWithBalloon:(Balloon*)balloon {
+ NSString* nibpath =
+ [mac_util::MainAppBundle() pathForResource:@"Notification"
+ ofType:@"nib"];
+ if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
+ balloon_ = balloon;
+ [self initializeHost];
+ menuModel_.reset(new NotificationOptionsMenuModel(balloon));
+ menuController_.reset([[MenuController alloc] initWithModel:menuModel_.get()
+ useWithPopUpButtonCell:NO]);
+ }
+ return self;
+}
+
+- (void)awakeFromNib {
+ DCHECK([self window]);
+ DCHECK_EQ(self, [[self window] delegate]);
+
+ NSImage* image = app::mac::GetCachedImageWithName(@"balloon_wrench.pdf");
+ [optionsButton_ setDefaultImage:image];
+ [optionsButton_ setDefaultOpacity:0.6];
+ [optionsButton_ setHoverImage:image];
+ [optionsButton_ setHoverOpacity:0.9];
+ [optionsButton_ setPressedImage:image];
+ [optionsButton_ setPressedOpacity:1.0];
+ [[optionsButton_ cell] setHighlightsBy:NSNoCellMask];
+
+ NSString* sourceLabelText = l10n_util::GetNSStringF(
+ IDS_NOTIFICATION_BALLOON_SOURCE_LABEL,
+ balloon_->notification().display_source());
+ [originLabel_ setStringValue:sourceLabelText];
+
+ // This condition is false in unit tests which have no RVH.
+ if (htmlContents_.get()) {
+ gfx::NativeView contents = htmlContents_->native_view();
+ [contents setFrame:NSMakeRect(kLeftMargin, kTopMargin, 0, 0)];
+ [[htmlContainer_ superview] addSubview:contents
+ positioned:NSWindowBelow
+ relativeTo:nil];
+ }
+
+ // Use the standard close button for a utility window.
+ closeButton_ = [NSWindow standardWindowButton:NSWindowCloseButton
+ forStyleMask:NSUtilityWindowMask];
+ NSRect frame = [closeButton_ frame];
+ [closeButton_ setFrame:NSMakeRect(6, 1, frame.size.width, frame.size.height)];
+ [closeButton_ setTarget:self];
+ [closeButton_ setAction:@selector(closeButtonPressed:)];
+ [shelf_ addSubview:closeButton_];
+ [self updateTrackingRect];
+
+ // Set the initial position without animating (the balloon should not
+ // yet be visible).
+ DCHECK(![[self window] isVisible]);
+ NSRect balloon_frame = NSMakeRect(balloon_->GetPosition().x(),
+ balloon_->GetPosition().y(),
+ [self desiredTotalWidth],
+ [self desiredTotalHeight]);
+ [[self window] setFrame:balloon_frame
+ display:NO];
+}
+
+- (void)updateTrackingRect {
+ if (closeButtonTrackingTag_)
+ [shelf_ removeTrackingRect:closeButtonTrackingTag_];
+
+ closeButtonTrackingTag_ = [shelf_ addTrackingRect:[closeButton_ frame]
+ owner:self
+ userData:nil
+ assumeInside:NO];
+}
+
+- (BOOL)handleEvent:(NSEvent*)event {
+ BOOL eventHandled = NO;
+ if ([event type] == NSLeftMouseDown) {
+ NSPoint mouse = [shelf_ convertPoint:[event locationInWindow]
+ fromView:nil];
+ if (NSPointInRect(mouse, [closeButton_ frame])) {
+ [closeButton_ mouseDown:event];
+
+ // Bring back the front process that is deactivated when we click the
+ // close button.
+ if (frontProcessNum_.highLongOfPSN || frontProcessNum_.lowLongOfPSN) {
+ SetFrontProcessWithOptions(&frontProcessNum_,
+ kSetFrontProcessFrontWindowOnly);
+ frontProcessNum_.highLongOfPSN = 0;
+ frontProcessNum_.lowLongOfPSN = 0;
+ }
+
+ eventHandled = YES;
+ } else if (NSPointInRect(mouse, [optionsButton_ frame])) {
+ [optionsButton_ mouseDown:event];
+ eventHandled = YES;
+ }
+ }
+ return eventHandled;
+}
+
+- (void) mouseEntered:(NSEvent*)event {
+ [[closeButton_ cell] setHighlighted:YES];
+
+ // Remember the current front process so that we can bring it back later.
+ if (!frontProcessNum_.highLongOfPSN && !frontProcessNum_.lowLongOfPSN)
+ GetFrontProcess(&frontProcessNum_);
+}
+
+- (void) mouseExited:(NSEvent*)event {
+ [[closeButton_ cell] setHighlighted:NO];
+
+ frontProcessNum_.highLongOfPSN = 0;
+ frontProcessNum_.lowLongOfPSN = 0;
+}
+
+- (IBAction)optionsButtonPressed:(id)sender {
+ [NSMenu popUpContextMenu:[menuController_ menu]
+ withEvent:[NSApp currentEvent]
+ forView:optionsButton_];
+}
+
+- (IBAction)permissionRevoked:(id)sender {
+ DesktopNotificationService* service =
+ balloon_->profile()->GetDesktopNotificationService();
+ service->DenyPermission(balloon_->notification().origin_url());
+}
+
+- (IBAction)closeButtonPressed:(id)sender {
+ [self closeBalloon:YES];
+ [self close];
+}
+
+- (void)close {
+ if (closeButtonTrackingTag_)
+ [shelf_ removeTrackingRect:closeButtonTrackingTag_];
+
+ [super close];
+}
+
+- (void)closeBalloon:(bool)byUser {
+ if (!balloon_)
+ return;
+ [self close];
+ if (htmlContents_.get())
+ htmlContents_->Shutdown();
+ if (balloon_)
+ balloon_->OnClose(byUser);
+ balloon_ = NULL;
+}
+
+- (void)updateContents {
+ DCHECK(htmlContents_.get()) << "BalloonView::Update called before Show";
+ if (htmlContents_->render_view_host())
+ htmlContents_->render_view_host()->NavigateToURL(
+ balloon_->notification().content_url());
+}
+
+- (void)repositionToBalloon {
+ DCHECK(balloon_);
+ int x = balloon_->GetPosition().x();
+ int y = balloon_->GetPosition().y();
+ int w = [self desiredTotalWidth];
+ int h = [self desiredTotalHeight];
+
+ if (htmlContents_.get())
+ htmlContents_->UpdateActualSize(balloon_->content_size());
+
+ [[[self window] animator] setFrame:NSMakeRect(x, y, w, h)
+ display:YES];
+}
+
+// Returns the total width the view should be to accommodate the balloon.
+- (int)desiredTotalWidth {
+ return (balloon_ ? balloon_->content_size().width() : 0) +
+ kLeftMargin + kRightMargin;
+}
+
+// Returns the total height the view should be to accommodate the balloon.
+- (int)desiredTotalHeight {
+ return (balloon_ ? balloon_->content_size().height() : 0) +
+ kTopMargin + kBottomMargin + [shelf_ frame].size.height;
+}
+
+// Returns the BalloonHost {
+- (BalloonViewHost*) getHost {
+ return htmlContents_.get();
+}
+
+// Initializes the renderer host showing the HTML contents.
+- (void)initializeHost {
+ htmlContents_.reset(new BalloonViewHost(balloon_));
+ htmlContents_->Init();
+}
+
+// NSWindowDelegate notification.
+- (void)windowWillClose:(NSNotification*)notif {
+ [self autorelease];
+}
+
+@end