172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/notifications/balloon_view_gtk.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <gtk/gtk.h> 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <string> 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <vector> 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/message_loop.h" 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_host.h" 15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_process_manager.h" 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/notifications/balloon.h" 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/notifications/desktop_notification_service.h" 18201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include "chrome/browser/notifications/notification.h" 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/notifications/notification_options_menu_model.h" 2021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h" 21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/themes/theme_service.h" 22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/browser_list.h" 23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/browser_window.h" 2472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/custom_button.h" 25ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/gtk/gtk_theme_service.h" 2672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/gtk_util.h" 2772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/info_bubble_gtk.h" 2872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/menu_gtk.h" 2972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/notifications/balloon_view_host_gtk.h" 3072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/rounded_window.h" 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension.h" 32dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_view_host.h" 33dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_widget_host_view.h" 34dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/common/notification_details.h" 35dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/common/notification_service.h" 36dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/common/notification_source.h" 37dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/common/notification_type.h" 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h" 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/theme_resources.h" 403f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "ui/base/animation/slide_animation.h" 4172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h" 4272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/resource/resource_bundle.h" 4372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/canvas.h" 4472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/insets.h" 4572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/native_widget_types.h" 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Margin, in pixels, between the notification frame and the contents 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// of the notification. 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kTopMargin = 0; 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kBottomMargin = 1; 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kLeftMargin = 1; 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kRightMargin = 1; 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// How many pixels of overlap there is between the shelf top and the 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// balloon bottom. 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kShelfBorderTopOverlap = 0; 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Properties of the origin label. 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kLeftLabelMargin = 8; 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TODO(johnnyg): Add a shadow for the frame. 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kLeftShadowWidth = 0; 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kRightShadowWidth = 0; 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kTopShadowWidth = 0; 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kBottomShadowWidth = 0; 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Space in pixels between text and icon on the buttons. 703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst int kButtonSpacing = 4; 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Number of characters to show in the origin label before ellipsis. 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kOriginLabelCharacters = 18; 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The shelf height for the system default font size. It is scaled 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// with changes in the default font size. 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kDefaultShelfHeight = 21; 783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst int kShelfVerticalMargin = 4; 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The amount that the bubble collections class offsets from the side of the 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// screen. 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kScreenBorder = 5; 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Colors specified in various ways for different parts of the UI. 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// These match the windows colors in balloon_view.cc 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char* kLabelColor = "#7D7D7D"; 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst double kShelfBackgroundColorR = 245.0 / 255.0; 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst double kShelfBackgroundColorG = 245.0 / 255.0; 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst double kShelfBackgroundColorB = 245.0 / 255.0; 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst double kDividerLineColorR = 180.0 / 255.0; 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst double kDividerLineColorG = 180.0 / 255.0; 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst double kDividerLineColorB = 180.0 / 255.0; 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Makes the website label relatively smaller to the base text size. 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char* kLabelMarkup = "<span size=\"small\" color=\"%s\">%s</span>"; 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBalloonViewImpl::BalloonViewImpl(BalloonCollection* collection) 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : balloon_(NULL), 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch frame_container_(NULL), 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch html_container_(NULL), 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch method_factory_(this), 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch close_button_(NULL), 10572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen animation_(NULL), 10672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen menu_showing_(false), 10772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen pending_close_(false) { 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBalloonViewImpl::~BalloonViewImpl() { 111ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (frame_container_) { 112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen GtkWidget* widget = frame_container_; 113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen frame_container_ = NULL; 114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen gtk_widget_hide(widget); 115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BalloonViewImpl::Close(bool by_user) { 11972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Delay a system-initiated close if the menu is showing. 12072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!by_user && menu_showing_) { 12172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen pending_close_ = true; 12272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } else { 12372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen MessageLoop::current()->PostTask( 12472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen FROM_HERE, 12572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen method_factory_.NewRunnableMethod( 12672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen &BalloonViewImpl::DelayedClose, by_user)); 12772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Size BalloonViewImpl::GetSize() const { 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // BalloonView has no size if it hasn't been shown yet (which is when 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // balloon_ is set). 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!balloon_) 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return gfx::Size(); 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Although this may not be the instantaneous size of the balloon if 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // called in the middle of an animation, it is the effective size that 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // will result from the animation. 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return gfx::Size(GetDesiredTotalWidth(), GetDesiredTotalHeight()); 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 14221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenBalloonHost* BalloonViewImpl::GetHost() const { 14321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen return html_contents_.get(); 14421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen} 14521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BalloonViewImpl::DelayedClose(bool by_user) { 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch html_contents_->Shutdown(); 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (frame_container_) { 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // It's possible that |frame_container_| was destroyed before the 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // BalloonViewImpl if our related browser window was closed first. 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_hide(frame_container_); 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch balloon_->OnClose(by_user); 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BalloonViewImpl::RepositionToBalloon() { 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!frame_container_) { 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // No need to create a slide animation when this balloon is fading out. 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(balloon_); 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create an amination from the current position to the desired one. 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int start_x; 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int start_y; 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int start_w; 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int start_h; 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_window_get_position(GTK_WINDOW(frame_container_), &start_x, &start_y); 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_window_get_size(GTK_WINDOW(frame_container_), &start_w, &start_h); 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int end_x = balloon_->GetPosition().x(); 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int end_y = balloon_->GetPosition().y(); 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int end_w = GetDesiredTotalWidth(); 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int end_h = GetDesiredTotalHeight(); 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch anim_frame_start_ = gfx::Rect(start_x, start_y, start_w, start_h); 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch anim_frame_end_ = gfx::Rect(end_x, end_y, end_w, end_h); 1793f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen animation_.reset(new ui::SlideAnimation(this)); 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch animation_->Show(); 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1833f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid BalloonViewImpl::AnimationProgressed(const ui::Animation* animation) { 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK_EQ(animation, animation_.get()); 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Linear interpolation from start to end position. 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double end = animation->GetCurrentValue(); 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch double start = 1.0 - end; 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect frame_position( 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<int>(start * anim_frame_start_.x() + 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch end * anim_frame_end_.x()), 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<int>(start * anim_frame_start_.y() + 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch end * anim_frame_end_.y()), 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<int>(start * anim_frame_start_.width() + 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch end * anim_frame_end_.width()), 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<int>(start * anim_frame_start_.height() + 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch end * anim_frame_end_.height())); 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_window_resize(GTK_WINDOW(frame_container_), 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch frame_position.width(), frame_position.height()); 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_window_move(GTK_WINDOW(frame_container_), 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch frame_position.x(), frame_position.y()); 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Rect contents_rect = GetContentsRectangle(); 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch html_contents_->UpdateActualSize(contents_rect.size()); 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BalloonViewImpl::Show(Balloon* balloon) { 209ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen theme_service_ = GtkThemeService::GetFrom(balloon->profile()); 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string source_label_text = l10n_util::GetStringFUTF8( 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch IDS_NOTIFICATION_BALLOON_SOURCE_LABEL, 2133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick balloon->notification().display_source()); 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string options_text = 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch l10n_util::GetStringUTF8(IDS_NOTIFICATION_OPTIONS_MENU_LABEL); 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string dismiss_text = 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch l10n_util::GetStringUTF8(IDS_NOTIFICATION_BALLOON_DISMISS_LABEL); 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch balloon_ = balloon; 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch frame_container_ = gtk_window_new(GTK_WINDOW_POPUP); 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Construct the options menu. 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch options_menu_model_.reset(new NotificationOptionsMenuModel(balloon_)); 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch options_menu_.reset(new MenuGtk(this, options_menu_model_.get())); 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create a BalloonViewHost to host the HTML contents of this balloon. 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch html_contents_.reset(new BalloonViewHost(balloon)); 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch html_contents_->Init(); 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::NativeView contents = html_contents_->native_view(); 23072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen g_signal_connect_after(contents, "expose-event", 23172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen G_CALLBACK(OnContentsExposeThunk), this); 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Divide the frame vertically into the shelf and the content area. 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GtkWidget* vbox = gtk_vbox_new(0, 0); 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_container_add(GTK_CONTAINER(frame_container_), vbox); 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch shelf_ = gtk_hbox_new(0, 0); 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_container_add(GTK_CONTAINER(vbox), shelf_); 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GtkWidget* alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_alignment_set_padding( 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GTK_ALIGNMENT(alignment), 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kTopMargin, kBottomMargin, kLeftMargin, kRightMargin); 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_show_all(alignment); 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_container_add(GTK_CONTAINER(alignment), contents); 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_container_add(GTK_CONTAINER(vbox), alignment); 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create a toolbar and add it to the shelf. 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch hbox_ = gtk_hbox_new(FALSE, 0); 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_set_size_request(GTK_WIDGET(hbox_), -1, GetShelfHeight()); 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_container_add(GTK_CONTAINER(shelf_), hbox_); 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_show_all(vbox); 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_signal_connect(frame_container_, "expose-event", 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch G_CALLBACK(OnExposeThunk), this); 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_signal_connect(frame_container_, "destroy", 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch G_CALLBACK(OnDestroyThunk), this); 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create a label for the source of the notification and add it to the 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // toolbar. 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GtkWidget* source_label_ = gtk_label_new(NULL); 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch char* markup = g_markup_printf_escaped(kLabelMarkup, 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kLabelColor, 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch source_label_text.c_str()); 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_label_set_markup(GTK_LABEL(source_label_), markup); 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_free(markup); 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_label_set_max_width_chars(GTK_LABEL(source_label_), 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kOriginLabelCharacters); 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_label_set_ellipsize(GTK_LABEL(source_label_), PANGO_ELLIPSIZE_END); 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GtkWidget* label_alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_alignment_set_padding(GTK_ALIGNMENT(label_alignment), 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kShelfVerticalMargin, kShelfVerticalMargin, 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kLeftLabelMargin, 0); 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_container_add(GTK_CONTAINER(label_alignment), source_label_); 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_box_pack_start(GTK_BOX(hbox_), label_alignment, FALSE, FALSE, 0); 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 2773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 2783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create a button to dismiss the balloon and add it to the toolbar. 2803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick close_button_.reset(new CustomDrawButton(IDR_TAB_CLOSE, 2813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick IDR_TAB_CLOSE_P, 2823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick IDR_TAB_CLOSE_H, 2833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick IDR_TAB_CLOSE)); 2843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick close_button_->SetBackground(SK_ColorBLACK, 2853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick rb.GetBitmapNamed(IDR_TAB_CLOSE), 2863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick rb.GetBitmapNamed(IDR_TAB_CLOSE_MASK)); 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_set_tooltip_text(close_button_->widget(), dismiss_text.c_str()); 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch g_signal_connect(close_button_->widget(), "clicked", 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch G_CALLBACK(OnCloseButtonThunk), this); 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GTK_WIDGET_UNSET_FLAGS(close_button_->widget(), GTK_CAN_FOCUS); 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GtkWidget* close_alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_alignment_set_padding(GTK_ALIGNMENT(close_alignment), 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kShelfVerticalMargin, kShelfVerticalMargin, 2943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 0, kButtonSpacing); 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_container_add(GTK_CONTAINER(close_alignment), close_button_->widget()); 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_box_pack_end(GTK_BOX(hbox_), close_alignment, FALSE, FALSE, 0); 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create a button for showing the options menu, and add it to the toolbar. 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch options_menu_button_.reset(new CustomDrawButton(IDR_BALLOON_WRENCH, 3003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick IDR_BALLOON_WRENCH_P, 3013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick IDR_BALLOON_WRENCH_H, 3023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 0)); 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_set_tooltip_text(options_menu_button_->widget(), 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch options_text.c_str()); 30572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen g_signal_connect(options_menu_button_->widget(), "button-press-event", 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch G_CALLBACK(OnOptionsMenuButtonThunk), this); 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GTK_WIDGET_UNSET_FLAGS(options_menu_button_->widget(), GTK_CAN_FOCUS); 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GtkWidget* options_alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_alignment_set_padding(GTK_ALIGNMENT(options_alignment), 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kShelfVerticalMargin, kShelfVerticalMargin, 3113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 0, kButtonSpacing); 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_container_add(GTK_CONTAINER(options_alignment), 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch options_menu_button_->widget()); 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_box_pack_end(GTK_BOX(hbox_), options_alignment, FALSE, FALSE, 0); 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch notification_registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationService::AllSources()); 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We don't do InitThemesFor() because it just forces a redraw. 320513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch gtk_util::ActAsRoundedWindow(frame_container_, gtk_util::kGdkBlack, 3, 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_util::ROUNDED_ALL, 322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_util::BORDER_ALL); 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Realize the frame container so we can do size calculations. 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_realize(frame_container_); 326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Update to make sure we have everything sized properly and then move our 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // window offscreen for its initial animation. 329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch html_contents_->UpdateActualSize(balloon_->content_size()); 330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int window_width; 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_window_get_size(GTK_WINDOW(frame_container_), &window_width, NULL); 332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int pos_x = gdk_screen_width() - window_width - kScreenBorder; 334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int pos_y = gdk_screen_height(); 335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_window_move(GTK_WINDOW(frame_container_), pos_x, pos_y); 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch balloon_->SetPosition(gfx::Point(pos_x, pos_y), false); 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_show_all(frame_container_); 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch notification_registrar_.Add(this, 340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationType::NOTIFY_BALLOON_DISCONNECTED, Source<Balloon>(balloon)); 341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BalloonViewImpl::Update() { 344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(html_contents_.get()) << "BalloonView::Update called before Show"; 345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (html_contents_->render_view_host()) 346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch html_contents_->render_view_host()->NavigateToURL( 347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch balloon_->notification().content_url()); 348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Point BalloonViewImpl::GetContentsOffset() const { 351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return gfx::Point(kLeftShadowWidth + kLeftMargin, 352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetShelfHeight() + kTopShadowWidth + kTopMargin); 353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BalloonViewImpl::GetShelfHeight() const { 356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(johnnyg): add scaling here. 357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return kDefaultShelfHeight; 358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BalloonViewImpl::GetDesiredTotalWidth() const { 361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return balloon_->content_size().width() + 362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kLeftMargin + kRightMargin + kLeftShadowWidth + kRightShadowWidth; 363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint BalloonViewImpl::GetDesiredTotalHeight() const { 366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return balloon_->content_size().height() + 367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kTopMargin + kBottomMargin + kTopShadowWidth + kBottomShadowWidth + 368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetShelfHeight(); 369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Rect BalloonViewImpl::GetContentsRectangle() const { 372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!frame_container_) 373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return gfx::Rect(); 374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Size content_size = balloon_->content_size(); 376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Point offset = GetContentsOffset(); 377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int x = 0, y = 0; 378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_window_get_position(GTK_WINDOW(frame_container_), &x, &y); 379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return gfx::Rect(x + offset.x(), y + offset.y(), 380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch content_size.width(), content_size.height()); 381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BalloonViewImpl::Observe(NotificationType type, 384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationSource& source, 385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationDetails& details) { 386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (type == NotificationType::NOTIFY_BALLOON_DISCONNECTED) { 387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the renderer process attached to this balloon is disconnected 388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // (e.g., because of a crash), we want to close the balloon. 389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch notification_registrar_.Remove(this, 390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationType::NOTIFY_BALLOON_DISCONNECTED, 391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Source<Balloon>(balloon_)); 392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Close(false); 393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else if (type == NotificationType::BROWSER_THEME_CHANGED) { 394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Since all the buttons change their own properties, and our expose does 395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // all the real differences, we'll need a redraw. 396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gtk_widget_queue_draw(frame_container_); 397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 4023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid BalloonViewImpl::OnCloseButton(GtkWidget* widget) { 4033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick Close(true); 4043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 4053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 40672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// We draw black dots on the bottom left and right corners to fill in the 40772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// border. Otherwise, the border has a gap because the sharp corners of the 40872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// HTML view cut off the roundedness of the notification window. 40972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsengboolean BalloonViewImpl::OnContentsExpose(GtkWidget* sender, 41072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen GdkEventExpose* event) { 41172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(sender->window)); 41272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen gdk_cairo_rectangle(cr, &event->area); 41372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen cairo_clip(cr); 41472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 41572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // According to a discussion on a mailing list I found, these degenerate 41672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // paths are the officially supported way to draw points in Cairo. 41772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen cairo_set_source_rgb(cr, 0, 0, 0); 41872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); 41972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen cairo_set_line_width(cr, 1.0); 42072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen cairo_move_to(cr, 0.5, sender->allocation.height - 0.5); 42172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen cairo_close_path(cr); 42272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen cairo_move_to(cr, sender->allocation.width - 0.5, 42372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen sender->allocation.height - 0.5); 42472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen cairo_close_path(cr); 42572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen cairo_stroke(cr); 42672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen cairo_destroy(cr); 42772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 42872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return FALSE; 42972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 43072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean BalloonViewImpl::OnExpose(GtkWidget* sender, GdkEventExpose* event) { 432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(sender->window)); 433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gdk_cairo_rectangle(cr, &event->area); 434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_clip(cr); 435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Size content_size = balloon_->content_size(); 437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Point offset = GetContentsOffset(); 438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Draw a background color behind the shelf. 440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_set_source_rgb(cr, kShelfBackgroundColorR, 441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kShelfBackgroundColorG, kShelfBackgroundColorB); 442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_rectangle(cr, kLeftMargin, kTopMargin + 0.5, 443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch content_size.width() - 0.5, GetShelfHeight()); 444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_fill(cr); 445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Now draw a one pixel line between content and shelf. 447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_move_to(cr, offset.x(), offset.y() - 1); 448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_line_to(cr, offset.x() + content_size.width(), offset.y() - 1); 449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_set_line_width(cr, 0.5); 450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_set_source_rgb(cr, kDividerLineColorR, 451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kDividerLineColorG, kDividerLineColorB); 452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_stroke(cr); 453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cairo_destroy(cr); 455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return FALSE; 457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 45972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid BalloonViewImpl::OnOptionsMenuButton(GtkWidget* widget, 46072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen GdkEventButton* event) { 46172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen menu_showing_ = true; 46272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen options_menu_->PopupForWidget(widget, event->button, event->time); 46372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 46472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 46572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Called when the menu stops showing. 46672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid BalloonViewImpl::StoppedShowing() { 46772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen menu_showing_ = false; 468dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (pending_close_) { 469dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen MessageLoop::current()->PostTask( 470dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen FROM_HERE, 471dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen method_factory_.NewRunnableMethod( 472dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen &BalloonViewImpl::DelayedClose, false)); 473dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean BalloonViewImpl::OnDestroy(GtkWidget* widget) { 477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch frame_container_ = NULL; 478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Close(false); 479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return FALSE; // Propagate. 480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 481