Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / gtk / download / download_started_animation_gtk.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/download/download_started_animation.h"
6
7 #include <math.h>
8
9 #include <gtk/gtk.h>
10
11 #include "base/message_loop/message_loop.h"
12 #include "content/public/browser/web_contents.h"
13 #include "content/public/browser/web_contents_view.h"
14 #include "grit/theme_resources.h"
15 #include "ui/base/resource/resource_bundle.h"
16 #include "ui/gfx/animation/linear_animation.h"
17 #include "ui/gfx/image/image.h"
18 #include "ui/gfx/rect.h"
19
20 namespace {
21
22 // How long to spend moving downwards and fading out after waiting.
23 const int kMoveTimeMs = 600;
24
25 // The animation framerate.
26 const int kFrameRateHz = 60;
27
28 class DownloadStartedAnimationGtk : public gfx::LinearAnimation {
29  public:
30   explicit DownloadStartedAnimationGtk(content::WebContents* web_contents);
31
32   // DownloadStartedAnimation will delete itself, but this is public so
33   // that we can use DeleteSoon().
34   virtual ~DownloadStartedAnimationGtk();
35
36  private:
37   // Move the arrow to wherever it should currently be.
38   void Reposition();
39
40   // Shut down cleanly.
41   void Close();
42
43   // Animation implementation.
44   virtual void AnimateToState(double state) OVERRIDE;
45
46   // The top level window that floats over the browser and displays the
47   // image.
48   GtkWidget* popup_;
49
50   // Dimensions of the image.
51   int width_;
52   int height_;
53
54   // The content area at the start of the animation. We store this so that the
55   // download shelf's resizing of the content area doesn't cause the animation
56   // to move around. This means that once started, the animation won't move
57   // with the parent window, but it's so fast that this shouldn't cause too
58   // much heartbreak.
59   gfx::Rect web_contents_bounds_;
60
61   DISALLOW_COPY_AND_ASSIGN(DownloadStartedAnimationGtk);
62 };
63
64 DownloadStartedAnimationGtk::DownloadStartedAnimationGtk(
65     content::WebContents* web_contents)
66     : gfx::LinearAnimation(kMoveTimeMs, kFrameRateHz, NULL),
67       popup_(NULL) {
68   static GdkPixbuf* kDownloadImage = NULL;
69   if (!kDownloadImage) {
70     ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
71     kDownloadImage = rb.GetNativeImageNamed(
72         IDR_DOWNLOAD_ANIMATION_BEGIN).ToGdkPixbuf();
73   }
74
75   width_ = gdk_pixbuf_get_width(kDownloadImage);
76   height_ = gdk_pixbuf_get_height(kDownloadImage);
77
78   // If we're too small to show the download image, then don't bother -
79   // the shelf will be enough.
80   web_contents->GetView()->GetContainerBounds(&web_contents_bounds_);
81   if (web_contents_bounds_.height() < height_)
82     return;
83
84   // TODO(estade): don't show up on the wrong virtual desktop.
85
86   popup_ = gtk_window_new(GTK_WINDOW_POPUP);
87   GtkWidget* image = gtk_image_new_from_pixbuf(kDownloadImage);
88   gtk_container_add(GTK_CONTAINER(popup_), image);
89
90   // Set the shape of the window to that of the arrow. Areas with
91   // opacity less than 0xff (i.e. <100% opacity) will be transparent.
92   GdkBitmap* mask = gdk_pixmap_new(NULL, width_, height_, 1);
93   gdk_pixbuf_render_threshold_alpha(kDownloadImage, mask,
94                                     0, 0,
95                                     0, 0, -1, -1,
96                                     0xff);
97   gtk_widget_shape_combine_mask(popup_, mask, 0, 0);
98   g_object_unref(mask);
99
100   Reposition();
101   gtk_widget_show_all(popup_);
102   // Make sure our window has focus, is brought to the top, etc.
103   gtk_window_present(GTK_WINDOW(popup_));
104
105   Start();
106 }
107
108 DownloadStartedAnimationGtk::~DownloadStartedAnimationGtk() {
109 }
110
111 void DownloadStartedAnimationGtk::Reposition() {
112   DCHECK(popup_);
113
114   // Align the image with the bottom left of the web contents (so that it
115   // points to the newly created download).
116   gtk_window_move(GTK_WINDOW(popup_),
117       web_contents_bounds_.x(),
118       static_cast<int>(web_contents_bounds_.bottom() -
119           height_ - height_ * (1 - GetCurrentValue())));
120 }
121
122 void DownloadStartedAnimationGtk::Close() {
123   DCHECK(popup_);
124
125   gtk_widget_destroy(popup_);
126   base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
127 }
128
129 void DownloadStartedAnimationGtk::AnimateToState(double state) {
130   if (state >= 1.0) {
131     Close();
132   } else {
133     Reposition();
134
135     // Start at zero, peak halfway and end at zero.
136     double opacity = std::min(1.0 - pow(GetCurrentValue() - 0.5, 2) * 4.0,
137                               static_cast<double>(1.0));
138
139     // This only works when there's a compositing manager running. Oh well.
140     gtk_window_set_opacity(GTK_WINDOW(popup_), opacity);
141   }
142 }
143
144 }  // namespace
145
146 // static
147 void DownloadStartedAnimation::Show(content::WebContents* web_contents) {
148   // The animation will delete itself.
149   new DownloadStartedAnimationGtk(web_contents);
150 }