| OLD | NEW | 
|---|
|  | (Empty) | 
| 1 // Copyright (c) 2010 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/gtk/download_item_gtk.h" |  | 
| 6 |  | 
| 7 #include "app/l10n_util.h" |  | 
| 8 #include "app/resource_bundle.h" |  | 
| 9 #include "app/text_elider.h" |  | 
| 10 #include "base/basictypes.h" |  | 
| 11 #include "base/callback.h" |  | 
| 12 #include "base/metrics/histogram.h" |  | 
| 13 #include "base/string_util.h" |  | 
| 14 #include "base/time.h" |  | 
| 15 #include "base/utf_string_conversions.h" |  | 
| 16 #include "chrome/browser/browser_process.h" |  | 
| 17 #include "chrome/browser/download/download_item.h" |  | 
| 18 #include "chrome/browser/download/download_item_model.h" |  | 
| 19 #include "chrome/browser/download/download_manager.h" |  | 
| 20 #include "chrome/browser/download/download_shelf.h" |  | 
| 21 #include "chrome/browser/download/download_util.h" |  | 
| 22 #include "chrome/browser/gtk/custom_drag.h" |  | 
| 23 #include "chrome/browser/gtk/download_shelf_gtk.h" |  | 
| 24 #include "chrome/browser/gtk/gtk_theme_provider.h" |  | 
| 25 #include "chrome/browser/gtk/gtk_util.h" |  | 
| 26 #include "chrome/browser/gtk/menu_gtk.h" |  | 
| 27 #include "chrome/browser/gtk/nine_box.h" |  | 
| 28 #include "chrome/browser/ui/browser.h" |  | 
| 29 #include "chrome/common/notification_service.h" |  | 
| 30 #include "gfx/canvas_skia_paint.h" |  | 
| 31 #include "gfx/color_utils.h" |  | 
| 32 #include "gfx/font.h" |  | 
| 33 #include "gfx/skia_utils_gtk.h" |  | 
| 34 #include "grit/generated_resources.h" |  | 
| 35 #include "grit/theme_resources.h" |  | 
| 36 #include "third_party/skia/include/core/SkBitmap.h" |  | 
| 37 #include "ui/base/animation/slide_animation.h" |  | 
| 38 |  | 
| 39 namespace { |  | 
| 40 |  | 
| 41 // The width of the |menu_button_| widget. It has to be at least as wide as the |  | 
| 42 // bitmap that we use to draw it, i.e. 16, but can be more. |  | 
| 43 const int kMenuButtonWidth = 16; |  | 
| 44 |  | 
| 45 // Padding on left and right of items in dangerous download prompt. |  | 
| 46 const int kDangerousElementPadding = 3; |  | 
| 47 |  | 
| 48 // Amount of space we allot to showing the filename. If the filename is too wide |  | 
| 49 // it will be elided. |  | 
| 50 const int kTextWidth = 140; |  | 
| 51 |  | 
| 52 // We only cap the size of the tooltip so we don't crash. |  | 
| 53 const int kTooltipMaxWidth = 1000; |  | 
| 54 |  | 
| 55 // The minimum width we will ever draw the download item. Used as a lower bound |  | 
| 56 // during animation. This number comes from the width of the images used to |  | 
| 57 // make the download item. |  | 
| 58 const int kMinDownloadItemWidth = download_util::kSmallProgressIconSize; |  | 
| 59 |  | 
| 60 // New download item animation speed in milliseconds. |  | 
| 61 const int kNewItemAnimationDurationMs = 800; |  | 
| 62 |  | 
| 63 // How long the 'download complete' animation should last for. |  | 
| 64 const int kCompleteAnimationDurationMs = 2500; |  | 
| 65 |  | 
| 66 // Width of the body area of the download item. |  | 
| 67 // TODO(estade): get rid of the fudge factor. http://crbug.com/18692 |  | 
| 68 const int kBodyWidth = kTextWidth + 50 + download_util::kSmallProgressIconSize; |  | 
| 69 |  | 
| 70 // The font size of the text, and that size rounded down to the nearest integer |  | 
| 71 // for the size of the arrow in GTK theme mode. |  | 
| 72 const double kTextSize = 13.4;  // 13.4px == 10pt @ 96dpi |  | 
| 73 |  | 
| 74 // Darken light-on-dark download status text by 20% before drawing, thus |  | 
| 75 // creating a "muted" version of title text for both dark-on-light and |  | 
| 76 // light-on-dark themes. |  | 
| 77 static const double kDownloadItemLuminanceMod = 0.8; |  | 
| 78 |  | 
| 79 }  // namespace |  | 
| 80 |  | 
| 81 // DownloadShelfContextMenuGtk ------------------------------------------------- |  | 
| 82 |  | 
| 83 class DownloadShelfContextMenuGtk : public DownloadShelfContextMenu, |  | 
| 84                                     public MenuGtk::Delegate { |  | 
| 85  public: |  | 
| 86   // The constructor creates the menu and immediately pops it up. |  | 
| 87   // |model| is the download item model associated with this context menu, |  | 
| 88   // |widget| is the button that popped up this context menu, and |e| is |  | 
| 89   // the button press event that caused this menu to be created. |  | 
| 90   DownloadShelfContextMenuGtk(BaseDownloadItemModel* model, |  | 
| 91                               DownloadItemGtk* download_item) |  | 
| 92       : DownloadShelfContextMenu(model), |  | 
| 93         download_item_(download_item) { |  | 
| 94   } |  | 
| 95 |  | 
| 96   ~DownloadShelfContextMenuGtk() { |  | 
| 97   } |  | 
| 98 |  | 
| 99   void Popup(GtkWidget* widget, GdkEvent* event) { |  | 
| 100     // Create the menu if we have not created it yet or we created it for |  | 
| 101     // an in-progress download that has since completed. |  | 
| 102     if (download_->state() == DownloadItem::COMPLETE) |  | 
| 103       menu_.reset(new MenuGtk(this, GetFinishedMenuModel())); |  | 
| 104     else |  | 
| 105       menu_.reset(new MenuGtk(this, GetInProgressMenuModel())); |  | 
| 106     menu_->Popup(widget, event); |  | 
| 107   } |  | 
| 108 |  | 
| 109   // MenuGtk::Delegate implementation: |  | 
| 110   virtual void StoppedShowing() { |  | 
| 111     download_item_->menu_showing_ = false; |  | 
| 112     gtk_widget_queue_draw(download_item_->menu_button_); |  | 
| 113   } |  | 
| 114 |  | 
| 115   virtual GtkWidget* GetImageForCommandId(int command_id) const { |  | 
| 116     const char* stock = NULL; |  | 
| 117     switch (command_id) { |  | 
| 118       case SHOW_IN_FOLDER: |  | 
| 119       case OPEN_WHEN_COMPLETE: |  | 
| 120         stock = GTK_STOCK_OPEN; |  | 
| 121         break; |  | 
| 122 |  | 
| 123       case CANCEL: |  | 
| 124         stock = GTK_STOCK_CANCEL; |  | 
| 125         break; |  | 
| 126 |  | 
| 127       case ALWAYS_OPEN_TYPE: |  | 
| 128       case TOGGLE_PAUSE: |  | 
| 129         stock = NULL; |  | 
| 130     } |  | 
| 131 |  | 
| 132     return stock ? gtk_image_new_from_stock(stock, GTK_ICON_SIZE_MENU) : NULL; |  | 
| 133   } |  | 
| 134 |  | 
| 135  private: |  | 
| 136   // The menu we show on Popup(). We keep a pointer to it for a couple reasons: |  | 
| 137   //  * we don't want to have to recreate the menu every time it's popped up. |  | 
| 138   //  * we have to keep it in scope for longer than the duration of Popup(), or |  | 
| 139   //    completing the user-selected action races against the menu's |  | 
| 140   //    destruction. |  | 
| 141   scoped_ptr<MenuGtk> menu_; |  | 
| 142 |  | 
| 143   // The download item that created us. |  | 
| 144   DownloadItemGtk* download_item_; |  | 
| 145 }; |  | 
| 146 |  | 
| 147 // DownloadItemGtk ------------------------------------------------------------- |  | 
| 148 |  | 
| 149 NineBox* DownloadItemGtk::body_nine_box_normal_ = NULL; |  | 
| 150 NineBox* DownloadItemGtk::body_nine_box_prelight_ = NULL; |  | 
| 151 NineBox* DownloadItemGtk::body_nine_box_active_ = NULL; |  | 
| 152 |  | 
| 153 NineBox* DownloadItemGtk::menu_nine_box_normal_ = NULL; |  | 
| 154 NineBox* DownloadItemGtk::menu_nine_box_prelight_ = NULL; |  | 
| 155 NineBox* DownloadItemGtk::menu_nine_box_active_ = NULL; |  | 
| 156 |  | 
| 157 NineBox* DownloadItemGtk::dangerous_nine_box_ = NULL; |  | 
| 158 |  | 
| 159 DownloadItemGtk::DownloadItemGtk(DownloadShelfGtk* parent_shelf, |  | 
| 160                                  BaseDownloadItemModel* download_model) |  | 
| 161     : parent_shelf_(parent_shelf), |  | 
| 162       arrow_(NULL), |  | 
| 163       menu_showing_(false), |  | 
| 164       theme_provider_(GtkThemeProvider::GetFrom( |  | 
| 165                           parent_shelf->browser()->profile())), |  | 
| 166       progress_angle_(download_util::kStartAngleDegrees), |  | 
| 167       download_model_(download_model), |  | 
| 168       dangerous_prompt_(NULL), |  | 
| 169       dangerous_label_(NULL), |  | 
| 170       icon_small_(NULL), |  | 
| 171       icon_large_(NULL), |  | 
| 172       creation_time_(base::Time::Now()) { |  | 
| 173   LoadIcon(); |  | 
| 174 |  | 
| 175   body_.Own(gtk_button_new()); |  | 
| 176   gtk_widget_set_app_paintable(body_.get(), TRUE); |  | 
| 177   UpdateTooltip(); |  | 
| 178 |  | 
| 179   g_signal_connect(body_.get(), "expose-event", |  | 
| 180                    G_CALLBACK(OnExposeThunk), this); |  | 
| 181   g_signal_connect(body_.get(), "clicked", |  | 
| 182                    G_CALLBACK(OnClickThunk), this); |  | 
| 183   GTK_WIDGET_UNSET_FLAGS(body_.get(), GTK_CAN_FOCUS); |  | 
| 184   // Remove internal padding on the button. |  | 
| 185   GtkRcStyle* no_padding_style = gtk_rc_style_new(); |  | 
| 186   no_padding_style->xthickness = 0; |  | 
| 187   no_padding_style->ythickness = 0; |  | 
| 188   gtk_widget_modify_style(body_.get(), no_padding_style); |  | 
| 189   g_object_unref(no_padding_style); |  | 
| 190 |  | 
| 191   name_label_ = gtk_label_new(NULL); |  | 
| 192 |  | 
| 193   UpdateNameLabel(); |  | 
| 194 |  | 
| 195   status_label_ = gtk_label_new(NULL); |  | 
| 196   g_signal_connect(status_label_, "destroy", |  | 
| 197                    G_CALLBACK(gtk_widget_destroyed), &status_label_); |  | 
| 198   // Left align and vertically center the labels. |  | 
| 199   gtk_misc_set_alignment(GTK_MISC(name_label_), 0, 0.5); |  | 
| 200   gtk_misc_set_alignment(GTK_MISC(status_label_), 0, 0.5); |  | 
| 201   // Until we switch to vector graphics, force the font size. |  | 
| 202   gtk_util::ForceFontSizePixels(name_label_, kTextSize); |  | 
| 203   gtk_util::ForceFontSizePixels(status_label_, kTextSize); |  | 
| 204 |  | 
| 205   // Stack the labels on top of one another. |  | 
| 206   GtkWidget* text_stack = gtk_vbox_new(FALSE, 0); |  | 
| 207   gtk_box_pack_start(GTK_BOX(text_stack), name_label_, TRUE, TRUE, 0); |  | 
| 208   gtk_box_pack_start(GTK_BOX(text_stack), status_label_, FALSE, FALSE, 0); |  | 
| 209 |  | 
| 210   // We use a GtkFixed because we don't want it to have its own window. |  | 
| 211   // This choice of widget is not critically important though. |  | 
| 212   progress_area_.Own(gtk_fixed_new()); |  | 
| 213   gtk_widget_set_size_request(progress_area_.get(), |  | 
| 214       download_util::kSmallProgressIconSize, |  | 
| 215       download_util::kSmallProgressIconSize); |  | 
| 216   gtk_widget_set_app_paintable(progress_area_.get(), TRUE); |  | 
| 217   g_signal_connect(progress_area_.get(), "expose-event", |  | 
| 218                    G_CALLBACK(OnProgressAreaExposeThunk), this); |  | 
| 219 |  | 
| 220   // Put the download progress icon on the left of the labels. |  | 
| 221   GtkWidget* body_hbox = gtk_hbox_new(FALSE, 0); |  | 
| 222   gtk_container_add(GTK_CONTAINER(body_.get()), body_hbox); |  | 
| 223   gtk_box_pack_start(GTK_BOX(body_hbox), progress_area_.get(), FALSE, FALSE, 0); |  | 
| 224   gtk_box_pack_start(GTK_BOX(body_hbox), text_stack, TRUE, TRUE, 0); |  | 
| 225 |  | 
| 226   menu_button_ = gtk_button_new(); |  | 
| 227   gtk_widget_set_app_paintable(menu_button_, TRUE); |  | 
| 228   GTK_WIDGET_UNSET_FLAGS(menu_button_, GTK_CAN_FOCUS); |  | 
| 229   g_signal_connect(menu_button_, "expose-event", |  | 
| 230                    G_CALLBACK(OnExposeThunk), this); |  | 
| 231   g_signal_connect(menu_button_, "button-press-event", |  | 
| 232                    G_CALLBACK(OnMenuButtonPressEventThunk), this); |  | 
| 233   g_object_set_data(G_OBJECT(menu_button_), "left-align-popup", |  | 
| 234                     reinterpret_cast<void*>(true)); |  | 
| 235 |  | 
| 236   GtkWidget* shelf_hbox = parent_shelf->GetHBox(); |  | 
| 237   hbox_.Own(gtk_hbox_new(FALSE, 0)); |  | 
| 238   g_signal_connect(hbox_.get(), "expose-event", |  | 
| 239                    G_CALLBACK(OnHboxExposeThunk), this); |  | 
| 240   gtk_box_pack_start(GTK_BOX(hbox_.get()), body_.get(), FALSE, FALSE, 0); |  | 
| 241   gtk_box_pack_start(GTK_BOX(hbox_.get()), menu_button_, FALSE, FALSE, 0); |  | 
| 242   gtk_box_pack_start(GTK_BOX(shelf_hbox), hbox_.get(), FALSE, FALSE, 0); |  | 
| 243   // Insert as the leftmost item. |  | 
| 244   gtk_box_reorder_child(GTK_BOX(shelf_hbox), hbox_.get(), 0); |  | 
| 245 |  | 
| 246   get_download()->AddObserver(this); |  | 
| 247 |  | 
| 248   new_item_animation_.reset(new ui::SlideAnimation(this)); |  | 
| 249   new_item_animation_->SetSlideDuration(kNewItemAnimationDurationMs); |  | 
| 250   gtk_widget_show_all(hbox_.get()); |  | 
| 251 |  | 
| 252   if (IsDangerous()) { |  | 
| 253     // Hide the download item components for now. |  | 
| 254     gtk_widget_hide(body_.get()); |  | 
| 255     gtk_widget_hide(menu_button_); |  | 
| 256 |  | 
| 257     // Create an hbox to hold it all. |  | 
| 258     dangerous_hbox_ = gtk_hbox_new(FALSE, kDangerousElementPadding); |  | 
| 259 |  | 
| 260     // Add padding at the beginning and end. The hbox will add padding between |  | 
| 261     // the empty labels and the other elements. |  | 
| 262     GtkWidget* empty_label_a = gtk_label_new(NULL); |  | 
| 263     GtkWidget* empty_label_b = gtk_label_new(NULL); |  | 
| 264     gtk_box_pack_start(GTK_BOX(dangerous_hbox_), empty_label_a, |  | 
| 265                        FALSE, FALSE, 0); |  | 
| 266     gtk_box_pack_end(GTK_BOX(dangerous_hbox_), empty_label_b, |  | 
| 267                      FALSE, FALSE, 0); |  | 
| 268 |  | 
| 269     // Create the warning icon. |  | 
| 270     dangerous_image_ = gtk_image_new(); |  | 
| 271     gtk_box_pack_start(GTK_BOX(dangerous_hbox_), dangerous_image_, |  | 
| 272                        FALSE, FALSE, 0); |  | 
| 273 |  | 
| 274     dangerous_label_ = gtk_label_new(NULL); |  | 
| 275     // We pass TRUE, TRUE so that the label will condense to less than its |  | 
| 276     // request when the animation is going on. |  | 
| 277     gtk_box_pack_start(GTK_BOX(dangerous_hbox_), dangerous_label_, |  | 
| 278                        TRUE, TRUE, 0); |  | 
| 279 |  | 
| 280     // Create the nevermind button. |  | 
| 281     GtkWidget* dangerous_decline = gtk_button_new_with_label( |  | 
| 282         l10n_util::GetStringUTF8(IDS_DISCARD_DOWNLOAD).c_str()); |  | 
| 283     g_signal_connect(dangerous_decline, "clicked", |  | 
| 284                      G_CALLBACK(OnDangerousDeclineThunk), this); |  | 
| 285     gtk_util::CenterWidgetInHBox(dangerous_hbox_, dangerous_decline, false, 0); |  | 
| 286 |  | 
| 287     // Create the ok button. |  | 
| 288     GtkWidget* dangerous_accept = gtk_button_new_with_label( |  | 
| 289         l10n_util::GetStringUTF8( |  | 
| 290             download_model->download()->is_extension_install() ? |  | 
| 291                 IDS_CONTINUE_EXTENSION_DOWNLOAD : IDS_SAVE_DOWNLOAD).c_str()); |  | 
| 292     g_signal_connect(dangerous_accept, "clicked", |  | 
| 293                      G_CALLBACK(OnDangerousAcceptThunk), this); |  | 
| 294     gtk_util::CenterWidgetInHBox(dangerous_hbox_, dangerous_accept, false, 0); |  | 
| 295 |  | 
| 296     // Put it in an alignment so that padding will be added on the left and |  | 
| 297     // right. |  | 
| 298     dangerous_prompt_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); |  | 
| 299     gtk_alignment_set_padding(GTK_ALIGNMENT(dangerous_prompt_), |  | 
| 300         0, 0, kDangerousElementPadding, kDangerousElementPadding); |  | 
| 301     gtk_container_add(GTK_CONTAINER(dangerous_prompt_), dangerous_hbox_); |  | 
| 302     gtk_box_pack_start(GTK_BOX(hbox_.get()), dangerous_prompt_, FALSE, FALSE, |  | 
| 303                        0); |  | 
| 304     gtk_widget_set_app_paintable(dangerous_prompt_, TRUE); |  | 
| 305     gtk_widget_set_redraw_on_allocate(dangerous_prompt_, TRUE); |  | 
| 306     g_signal_connect(dangerous_prompt_, "expose-event", |  | 
| 307                      G_CALLBACK(OnDangerousPromptExposeThunk), this); |  | 
| 308     gtk_widget_show_all(dangerous_prompt_); |  | 
| 309   } |  | 
| 310 |  | 
| 311   registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, |  | 
| 312                  NotificationService::AllSources()); |  | 
| 313   theme_provider_->InitThemesFor(this); |  | 
| 314 |  | 
| 315   // Set the initial width of the widget to be animated. |  | 
| 316   if (IsDangerous()) { |  | 
| 317     gtk_widget_set_size_request(dangerous_hbox_, |  | 
| 318                                 dangerous_hbox_start_width_, -1); |  | 
| 319   } else { |  | 
| 320     gtk_widget_set_size_request(body_.get(), kMinDownloadItemWidth, -1); |  | 
| 321   } |  | 
| 322 |  | 
| 323   new_item_animation_->Show(); |  | 
| 324 } |  | 
| 325 |  | 
| 326 DownloadItemGtk::~DownloadItemGtk() { |  | 
| 327   icon_consumer_.CancelAllRequests(); |  | 
| 328   StopDownloadProgress(); |  | 
| 329   get_download()->RemoveObserver(this); |  | 
| 330 |  | 
| 331   // We may free some shelf space for showing more download items. |  | 
| 332   parent_shelf_->MaybeShowMoreDownloadItems(); |  | 
| 333 |  | 
| 334   hbox_.Destroy(); |  | 
| 335   progress_area_.Destroy(); |  | 
| 336   body_.Destroy(); |  | 
| 337 |  | 
| 338   // Make sure this widget has been destroyed and the pointer we hold to it |  | 
| 339   // NULLed. |  | 
| 340   DCHECK(!status_label_); |  | 
| 341 } |  | 
| 342 |  | 
| 343 void DownloadItemGtk::OnDownloadUpdated(DownloadItem* download) { |  | 
| 344   DCHECK_EQ(download, get_download()); |  | 
| 345 |  | 
| 346   if (dangerous_prompt_ != NULL && |  | 
| 347       download->safety_state() == DownloadItem::DANGEROUS_BUT_VALIDATED) { |  | 
| 348     // We have been approved. |  | 
| 349     gtk_widget_show_all(hbox_.get()); |  | 
| 350     gtk_widget_destroy(dangerous_prompt_); |  | 
| 351     gtk_widget_set_size_request(body_.get(), kBodyWidth, -1); |  | 
| 352     dangerous_prompt_ = NULL; |  | 
| 353 |  | 
| 354     // We may free some shelf space for showing more download items. |  | 
| 355     parent_shelf_->MaybeShowMoreDownloadItems(); |  | 
| 356   } |  | 
| 357 |  | 
| 358   if (download->GetUserVerifiedFilePath() != icon_filepath_) { |  | 
| 359     // Turns out the file path is "unconfirmed %d.crdownload" for dangerous |  | 
| 360     // downloads. When the download is confirmed, the file is renamed on |  | 
| 361     // another thread, so reload the icon if the download filename changes. |  | 
| 362     LoadIcon(); |  | 
| 363 |  | 
| 364     UpdateTooltip(); |  | 
| 365   } |  | 
| 366 |  | 
| 367   switch (download->state()) { |  | 
| 368     case DownloadItem::REMOVING: |  | 
| 369       parent_shelf_->RemoveDownloadItem(this);  // This will delete us! |  | 
| 370       return; |  | 
| 371     case DownloadItem::CANCELLED: |  | 
| 372       StopDownloadProgress(); |  | 
| 373       gtk_widget_queue_draw(progress_area_.get()); |  | 
| 374       break; |  | 
| 375     case DownloadItem::COMPLETE: |  | 
| 376       if (download->auto_opened()) { |  | 
| 377         parent_shelf_->RemoveDownloadItem(this);  // This will delete us! |  | 
| 378         return; |  | 
| 379       } |  | 
| 380       StopDownloadProgress(); |  | 
| 381 |  | 
| 382       // Set up the widget as a drag source. |  | 
| 383       DownloadItemDrag::SetSource(body_.get(), get_download(), icon_large_); |  | 
| 384 |  | 
| 385       complete_animation_.reset(new ui::SlideAnimation(this)); |  | 
| 386       complete_animation_->SetSlideDuration(kCompleteAnimationDurationMs); |  | 
| 387       complete_animation_->SetTweenType(ui::Tween::LINEAR); |  | 
| 388       complete_animation_->Show(); |  | 
| 389       break; |  | 
| 390     case DownloadItem::IN_PROGRESS: |  | 
| 391       get_download()->is_paused() ? |  | 
| 392           StopDownloadProgress() : StartDownloadProgress(); |  | 
| 393       break; |  | 
| 394     default: |  | 
| 395       NOTREACHED(); |  | 
| 396   } |  | 
| 397 |  | 
| 398   // Now update the status label. We may have already removed it; if so, we |  | 
| 399   // do nothing. |  | 
| 400   if (!status_label_) { |  | 
| 401     return; |  | 
| 402   } |  | 
| 403 |  | 
| 404   status_text_ = UTF16ToUTF8(download_model_->GetStatusText()); |  | 
| 405   // Remove the status text label. |  | 
| 406   if (status_text_.empty()) { |  | 
| 407     gtk_widget_destroy(status_label_); |  | 
| 408     return; |  | 
| 409   } |  | 
| 410 |  | 
| 411   UpdateStatusLabel(status_text_); |  | 
| 412 } |  | 
| 413 |  | 
| 414 void DownloadItemGtk::AnimationProgressed(const ui::Animation* animation) { |  | 
| 415   if (animation == complete_animation_.get()) { |  | 
| 416     gtk_widget_queue_draw(progress_area_.get()); |  | 
| 417   } else { |  | 
| 418     if (IsDangerous()) { |  | 
| 419       int progress = static_cast<int>((dangerous_hbox_full_width_ - |  | 
| 420                                        dangerous_hbox_start_width_) * |  | 
| 421                                       new_item_animation_->GetCurrentValue()); |  | 
| 422       int showing_width = dangerous_hbox_start_width_ + progress; |  | 
| 423       gtk_widget_set_size_request(dangerous_hbox_, showing_width, -1); |  | 
| 424     } else { |  | 
| 425       DCHECK(animation == new_item_animation_.get()); |  | 
| 426       int showing_width = std::max(kMinDownloadItemWidth, |  | 
| 427           static_cast<int>(kBodyWidth * |  | 
| 428                            new_item_animation_->GetCurrentValue())); |  | 
| 429       gtk_widget_set_size_request(body_.get(), showing_width, -1); |  | 
| 430     } |  | 
| 431   } |  | 
| 432 } |  | 
| 433 |  | 
| 434 void DownloadItemGtk::Observe(NotificationType type, |  | 
| 435                               const NotificationSource& source, |  | 
| 436                               const NotificationDetails& details) { |  | 
| 437   if (type == NotificationType::BROWSER_THEME_CHANGED) { |  | 
| 438     // Our GtkArrow is only visible in gtk mode. Otherwise, we let the custom |  | 
| 439     // rendering code do whatever it wants. |  | 
| 440     if (theme_provider_->UseGtkTheme()) { |  | 
| 441       if (!arrow_) { |  | 
| 442         arrow_ = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE); |  | 
| 443         gtk_widget_set_size_request(arrow_, |  | 
| 444                                     static_cast<int>(kTextSize), |  | 
| 445                                     static_cast<int>(kTextSize)); |  | 
| 446         gtk_container_add(GTK_CONTAINER(menu_button_), arrow_); |  | 
| 447       } |  | 
| 448 |  | 
| 449       gtk_widget_set_size_request(menu_button_, -1, -1); |  | 
| 450       gtk_widget_show(arrow_); |  | 
| 451     } else { |  | 
| 452       InitNineBoxes(); |  | 
| 453 |  | 
| 454       gtk_widget_set_size_request(menu_button_, kMenuButtonWidth, 0); |  | 
| 455 |  | 
| 456       if (arrow_) |  | 
| 457         gtk_widget_hide(arrow_); |  | 
| 458     } |  | 
| 459 |  | 
| 460     UpdateNameLabel(); |  | 
| 461     UpdateStatusLabel(status_text_); |  | 
| 462     UpdateDangerWarning(); |  | 
| 463   } |  | 
| 464 } |  | 
| 465 |  | 
| 466 DownloadItem* DownloadItemGtk::get_download() { |  | 
| 467   return download_model_->download(); |  | 
| 468 } |  | 
| 469 |  | 
| 470 bool DownloadItemGtk::IsDangerous() { |  | 
| 471   return get_download()->safety_state() == DownloadItem::DANGEROUS; |  | 
| 472 } |  | 
| 473 |  | 
| 474 // Download progress animation functions. |  | 
| 475 |  | 
| 476 void DownloadItemGtk::UpdateDownloadProgress() { |  | 
| 477   progress_angle_ = (progress_angle_ + |  | 
| 478                      download_util::kUnknownIncrementDegrees) % |  | 
| 479                     download_util::kMaxDegrees; |  | 
| 480   gtk_widget_queue_draw(progress_area_.get()); |  | 
| 481 } |  | 
| 482 |  | 
| 483 void DownloadItemGtk::StartDownloadProgress() { |  | 
| 484   if (progress_timer_.IsRunning()) |  | 
| 485     return; |  | 
| 486   progress_timer_.Start( |  | 
| 487       base::TimeDelta::FromMilliseconds(download_util::kProgressRateMs), this, |  | 
| 488       &DownloadItemGtk::UpdateDownloadProgress); |  | 
| 489 } |  | 
| 490 |  | 
| 491 void DownloadItemGtk::StopDownloadProgress() { |  | 
| 492   progress_timer_.Stop(); |  | 
| 493 } |  | 
| 494 |  | 
| 495 // Icon loading functions. |  | 
| 496 |  | 
| 497 void DownloadItemGtk::OnLoadSmallIconComplete(IconManager::Handle handle, |  | 
| 498                                               SkBitmap* icon_bitmap) { |  | 
| 499   icon_small_ = icon_bitmap; |  | 
| 500   gtk_widget_queue_draw(progress_area_.get()); |  | 
| 501 } |  | 
| 502 |  | 
| 503 void DownloadItemGtk::OnLoadLargeIconComplete(IconManager::Handle handle, |  | 
| 504                                               SkBitmap* icon_bitmap) { |  | 
| 505   icon_large_ = icon_bitmap; |  | 
| 506   DownloadItemDrag::SetSource(body_.get(), get_download(), icon_large_); |  | 
| 507 } |  | 
| 508 |  | 
| 509 void DownloadItemGtk::LoadIcon() { |  | 
| 510   icon_consumer_.CancelAllRequests(); |  | 
| 511   IconManager* im = g_browser_process->icon_manager(); |  | 
| 512   icon_filepath_ = get_download()->GetUserVerifiedFilePath(); |  | 
| 513   im->LoadIcon(icon_filepath_, |  | 
| 514                IconLoader::SMALL, &icon_consumer_, |  | 
| 515                NewCallback(this, &DownloadItemGtk::OnLoadSmallIconComplete)); |  | 
| 516   im->LoadIcon(icon_filepath_, |  | 
| 517                IconLoader::LARGE, &icon_consumer_, |  | 
| 518                NewCallback(this, &DownloadItemGtk::OnLoadLargeIconComplete)); |  | 
| 519 } |  | 
| 520 |  | 
| 521 void DownloadItemGtk::UpdateTooltip() { |  | 
| 522   string16 elided_filename = gfx::ElideFilename( |  | 
| 523       get_download()->GetFileNameToReportUser(), |  | 
| 524       gfx::Font(), kTooltipMaxWidth); |  | 
| 525   gtk_widget_set_tooltip_text(body_.get(), |  | 
| 526                               UTF16ToUTF8(elided_filename).c_str()); |  | 
| 527 } |  | 
| 528 |  | 
| 529 void DownloadItemGtk::UpdateNameLabel() { |  | 
| 530   // TODO(estade): This is at best an educated guess, since we don't actually |  | 
| 531   // use gfx::Font() to draw the text. This is why we need to add so |  | 
| 532   // much padding when we set the size request. We need to either use gfx::Font |  | 
| 533   // or somehow extend TextElider. |  | 
| 534   string16 elided_filename = gfx::ElideFilename( |  | 
| 535       get_download()->GetFileNameToReportUser(), |  | 
| 536       gfx::Font(), kTextWidth); |  | 
| 537 |  | 
| 538   GdkColor color = theme_provider_->GetGdkColor( |  | 
| 539       BrowserThemeProvider::COLOR_BOOKMARK_TEXT); |  | 
| 540   gtk_util::SetLabelColor(name_label_, theme_provider_->UseGtkTheme() ? |  | 
| 541                                        NULL : &color); |  | 
| 542   gtk_label_set_text(GTK_LABEL(name_label_), |  | 
| 543                      UTF16ToUTF8(elided_filename).c_str()); |  | 
| 544 } |  | 
| 545 |  | 
| 546 void DownloadItemGtk::UpdateStatusLabel(const std::string& status_text) { |  | 
| 547   if (!status_label_) |  | 
| 548     return; |  | 
| 549 |  | 
| 550   GdkColor text_color; |  | 
| 551   if (!theme_provider_->UseGtkTheme()) { |  | 
| 552     SkColor color = theme_provider_->GetColor( |  | 
| 553         BrowserThemeProvider::COLOR_BOOKMARK_TEXT); |  | 
| 554     if (color_utils::RelativeLuminance(color) > 0.5) { |  | 
| 555       color = SkColorSetRGB( |  | 
| 556           static_cast<int>(kDownloadItemLuminanceMod * |  | 
| 557                            SkColorGetR(color)), |  | 
| 558           static_cast<int>(kDownloadItemLuminanceMod * |  | 
| 559                            SkColorGetG(color)), |  | 
| 560           static_cast<int>(kDownloadItemLuminanceMod * |  | 
| 561                            SkColorGetB(color))); |  | 
| 562     } |  | 
| 563 |  | 
| 564     // Lighten the color by blending it with the download item body color. These |  | 
| 565     // values are taken from IDR_DOWNLOAD_BUTTON. |  | 
| 566     SkColor blend_color = SkColorSetRGB(241, 245, 250); |  | 
| 567     text_color = gfx::SkColorToGdkColor( |  | 
| 568         color_utils::AlphaBlend(blend_color, color, 77)); |  | 
| 569   } |  | 
| 570 |  | 
| 571   gtk_util::SetLabelColor(status_label_, theme_provider_->UseGtkTheme() ? |  | 
| 572                                         NULL : &text_color); |  | 
| 573   gtk_label_set_text(GTK_LABEL(status_label_), status_text.c_str()); |  | 
| 574 } |  | 
| 575 |  | 
| 576 void DownloadItemGtk::UpdateDangerWarning() { |  | 
| 577   if (dangerous_prompt_) { |  | 
| 578     // We create |dangerous_warning| as a wide string so we can more easily |  | 
| 579     // calculate its length in characters. |  | 
| 580     string16 dangerous_warning; |  | 
| 581     if (get_download()->is_extension_install()) { |  | 
| 582       dangerous_warning = |  | 
| 583           l10n_util::GetStringUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD_EXTENSION); |  | 
| 584     } else { |  | 
| 585       string16 elided_filename = gfx::ElideFilename( |  | 
| 586           get_download()->target_name(), gfx::Font(), kTextWidth); |  | 
| 587 |  | 
| 588       dangerous_warning = |  | 
| 589           l10n_util::GetStringFUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD, |  | 
| 590                                      elided_filename); |  | 
| 591     } |  | 
| 592 |  | 
| 593     if (theme_provider_->UseGtkTheme()) { |  | 
| 594       gtk_image_set_from_stock(GTK_IMAGE(dangerous_image_), |  | 
| 595           GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR); |  | 
| 596 |  | 
| 597       gtk_util::SetLabelColor(dangerous_label_, NULL); |  | 
| 598     } else { |  | 
| 599       // Set the warning icon. |  | 
| 600       ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |  | 
| 601       GdkPixbuf* download_pixbuf = rb.GetPixbufNamed(IDR_WARNING); |  | 
| 602       gtk_image_set_from_pixbuf(GTK_IMAGE(dangerous_image_), download_pixbuf); |  | 
| 603 |  | 
| 604       GdkColor color = theme_provider_->GetGdkColor( |  | 
| 605           BrowserThemeProvider::COLOR_BOOKMARK_TEXT); |  | 
| 606       gtk_util::SetLabelColor(dangerous_label_, &color); |  | 
| 607     } |  | 
| 608 |  | 
| 609     gtk_label_set_text(GTK_LABEL(dangerous_label_), |  | 
| 610                        UTF16ToUTF8(dangerous_warning).c_str()); |  | 
| 611 |  | 
| 612     // Until we switch to vector graphics, force the font size. |  | 
| 613     gtk_util::ForceFontSizePixels(dangerous_label_, kTextSize); |  | 
| 614 |  | 
| 615     // Get the label width when displaying in one line, and reduce it to 60% to |  | 
| 616     // wrap the label into two lines. |  | 
| 617     gtk_widget_set_size_request(dangerous_label_, -1, -1); |  | 
| 618     gtk_label_set_line_wrap(GTK_LABEL(dangerous_label_), FALSE); |  | 
| 619 |  | 
| 620     GtkRequisition req; |  | 
| 621     gtk_widget_size_request(dangerous_label_, &req); |  | 
| 622 |  | 
| 623     gint label_width = req.width * 6 / 10; |  | 
| 624     gtk_label_set_line_wrap(GTK_LABEL(dangerous_label_), TRUE); |  | 
| 625     gtk_widget_set_size_request(dangerous_label_, label_width, -1); |  | 
| 626 |  | 
| 627     // The width will depend on the text. We must do this each time we possibly |  | 
| 628     // change the label above. |  | 
| 629     gtk_widget_size_request(dangerous_hbox_, &req); |  | 
| 630     dangerous_hbox_full_width_ = req.width; |  | 
| 631     dangerous_hbox_start_width_ = dangerous_hbox_full_width_ - label_width; |  | 
| 632   } |  | 
| 633 } |  | 
| 634 |  | 
| 635 // static |  | 
| 636 void DownloadItemGtk::InitNineBoxes() { |  | 
| 637   if (body_nine_box_normal_) |  | 
| 638     return; |  | 
| 639 |  | 
| 640   body_nine_box_normal_ = new NineBox( |  | 
| 641       IDR_DOWNLOAD_BUTTON_LEFT_TOP, |  | 
| 642       IDR_DOWNLOAD_BUTTON_CENTER_TOP, |  | 
| 643       IDR_DOWNLOAD_BUTTON_RIGHT_TOP, |  | 
| 644       IDR_DOWNLOAD_BUTTON_LEFT_MIDDLE, |  | 
| 645       IDR_DOWNLOAD_BUTTON_CENTER_MIDDLE, |  | 
| 646       IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE, |  | 
| 647       IDR_DOWNLOAD_BUTTON_LEFT_BOTTOM, |  | 
| 648       IDR_DOWNLOAD_BUTTON_CENTER_BOTTOM, |  | 
| 649       IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM); |  | 
| 650 |  | 
| 651   body_nine_box_prelight_ = new NineBox( |  | 
| 652       IDR_DOWNLOAD_BUTTON_LEFT_TOP_H, |  | 
| 653       IDR_DOWNLOAD_BUTTON_CENTER_TOP_H, |  | 
| 654       IDR_DOWNLOAD_BUTTON_RIGHT_TOP_H, |  | 
| 655       IDR_DOWNLOAD_BUTTON_LEFT_MIDDLE_H, |  | 
| 656       IDR_DOWNLOAD_BUTTON_CENTER_MIDDLE_H, |  | 
| 657       IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE_H, |  | 
| 658       IDR_DOWNLOAD_BUTTON_LEFT_BOTTOM_H, |  | 
| 659       IDR_DOWNLOAD_BUTTON_CENTER_BOTTOM_H, |  | 
| 660       IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM_H); |  | 
| 661 |  | 
| 662   body_nine_box_active_ = new NineBox( |  | 
| 663       IDR_DOWNLOAD_BUTTON_LEFT_TOP_P, |  | 
| 664       IDR_DOWNLOAD_BUTTON_CENTER_TOP_P, |  | 
| 665       IDR_DOWNLOAD_BUTTON_RIGHT_TOP_P, |  | 
| 666       IDR_DOWNLOAD_BUTTON_LEFT_MIDDLE_P, |  | 
| 667       IDR_DOWNLOAD_BUTTON_CENTER_MIDDLE_P, |  | 
| 668       IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE_P, |  | 
| 669       IDR_DOWNLOAD_BUTTON_LEFT_BOTTOM_P, |  | 
| 670       IDR_DOWNLOAD_BUTTON_CENTER_BOTTOM_P, |  | 
| 671       IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM_P); |  | 
| 672 |  | 
| 673   menu_nine_box_normal_ = new NineBox( |  | 
| 674       IDR_DOWNLOAD_BUTTON_MENU_TOP, 0, 0, |  | 
| 675       IDR_DOWNLOAD_BUTTON_MENU_MIDDLE, 0, 0, |  | 
| 676       IDR_DOWNLOAD_BUTTON_MENU_BOTTOM, 0, 0); |  | 
| 677 |  | 
| 678   menu_nine_box_prelight_ = new NineBox( |  | 
| 679       IDR_DOWNLOAD_BUTTON_MENU_TOP_H, 0, 0, |  | 
| 680       IDR_DOWNLOAD_BUTTON_MENU_MIDDLE_H, 0, 0, |  | 
| 681       IDR_DOWNLOAD_BUTTON_MENU_BOTTOM_H, 0, 0); |  | 
| 682 |  | 
| 683   menu_nine_box_active_ = new NineBox( |  | 
| 684       IDR_DOWNLOAD_BUTTON_MENU_TOP_P, 0, 0, |  | 
| 685       IDR_DOWNLOAD_BUTTON_MENU_MIDDLE_P, 0, 0, |  | 
| 686       IDR_DOWNLOAD_BUTTON_MENU_BOTTOM_P, 0, 0); |  | 
| 687 |  | 
| 688   dangerous_nine_box_ = new NineBox( |  | 
| 689       IDR_DOWNLOAD_BUTTON_LEFT_TOP, |  | 
| 690       IDR_DOWNLOAD_BUTTON_CENTER_TOP, |  | 
| 691       IDR_DOWNLOAD_BUTTON_RIGHT_TOP_NO_DD, |  | 
| 692       IDR_DOWNLOAD_BUTTON_LEFT_MIDDLE, |  | 
| 693       IDR_DOWNLOAD_BUTTON_CENTER_MIDDLE, |  | 
| 694       IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE_NO_DD, |  | 
| 695       IDR_DOWNLOAD_BUTTON_LEFT_BOTTOM, |  | 
| 696       IDR_DOWNLOAD_BUTTON_CENTER_BOTTOM, |  | 
| 697       IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM_NO_DD); |  | 
| 698 } |  | 
| 699 |  | 
| 700 gboolean DownloadItemGtk::OnHboxExpose(GtkWidget* widget, GdkEventExpose* e) { |  | 
| 701   if (theme_provider_->UseGtkTheme()) { |  | 
| 702     int border_width = GTK_CONTAINER(widget)->border_width; |  | 
| 703     int x = widget->allocation.x + border_width; |  | 
| 704     int y = widget->allocation.y + border_width; |  | 
| 705     int width = widget->allocation.width - border_width * 2; |  | 
| 706     int height = widget->allocation.height - border_width * 2; |  | 
| 707 |  | 
| 708     if (IsDangerous()) { |  | 
| 709       // Draw a simple frame around the area when we're displaying the warning. |  | 
| 710       gtk_paint_shadow(widget->style, widget->window, |  | 
| 711                        static_cast<GtkStateType>(widget->state), |  | 
| 712                        static_cast<GtkShadowType>(GTK_SHADOW_OUT), |  | 
| 713                        &e->area, widget, "frame", |  | 
| 714                        x, y, width, height); |  | 
| 715     } else { |  | 
| 716       // Manually draw the GTK button border around the download item. We draw |  | 
| 717       // the left part of the button (the file), a divider, and then the right |  | 
| 718       // part of the button (the menu). We can't draw a button on top of each |  | 
| 719       // other (*cough*Clearlooks*cough*) so instead, to draw the left part of |  | 
| 720       // the button, we instruct GTK to draw the entire button...with a |  | 
| 721       // doctored clip rectangle to the left part of the button sans |  | 
| 722       // separator. We then repeat this for the right button. |  | 
| 723       GtkStyle* style = body_.get()->style; |  | 
| 724 |  | 
| 725       GtkAllocation left_allocation = body_.get()->allocation; |  | 
| 726       GdkRectangle left_clip = { |  | 
| 727         left_allocation.x, left_allocation.y, |  | 
| 728         left_allocation.width, left_allocation.height |  | 
| 729       }; |  | 
| 730 |  | 
| 731       GtkAllocation right_allocation = menu_button_->allocation; |  | 
| 732       GdkRectangle right_clip = { |  | 
| 733         right_allocation.x, right_allocation.y, |  | 
| 734         right_allocation.width, right_allocation.height |  | 
| 735       }; |  | 
| 736 |  | 
| 737       GtkShadowType body_shadow = |  | 
| 738           GTK_BUTTON(body_.get())->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT; |  | 
| 739       gtk_paint_box(style, widget->window, |  | 
| 740                     static_cast<GtkStateType>(GTK_WIDGET_STATE(body_.get())), |  | 
| 741                     body_shadow, |  | 
| 742                     &left_clip, widget, "button", |  | 
| 743                     x, y, width, height); |  | 
| 744 |  | 
| 745       GtkShadowType menu_shadow = |  | 
| 746           GTK_BUTTON(menu_button_)->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT; |  | 
| 747       gtk_paint_box(style, widget->window, |  | 
| 748                     static_cast<GtkStateType>(GTK_WIDGET_STATE(menu_button_)), |  | 
| 749                     menu_shadow, |  | 
| 750                     &right_clip, widget, "button", |  | 
| 751                     x, y, width, height); |  | 
| 752 |  | 
| 753       // Doing the math to reverse engineer where we should be drawing our line |  | 
| 754       // is hard and relies on copying GTK internals, so instead steal the |  | 
| 755       // allocation of the gtk arrow which is close enough (and will error on |  | 
| 756       // the conservative side). |  | 
| 757       GtkAllocation arrow_allocation = arrow_->allocation; |  | 
| 758       gtk_paint_vline(style, widget->window, |  | 
| 759                       static_cast<GtkStateType>(GTK_WIDGET_STATE(widget)), |  | 
| 760                       &e->area, widget, "button", |  | 
| 761                       arrow_allocation.y, |  | 
| 762                       arrow_allocation.y + arrow_allocation.height, |  | 
| 763                       left_allocation.x + left_allocation.width); |  | 
| 764     } |  | 
| 765   } |  | 
| 766   return FALSE; |  | 
| 767 } |  | 
| 768 |  | 
| 769 gboolean DownloadItemGtk::OnExpose(GtkWidget* widget, GdkEventExpose* e) { |  | 
| 770   if (!theme_provider_->UseGtkTheme()) { |  | 
| 771     bool is_body = widget == body_.get(); |  | 
| 772 |  | 
| 773     NineBox* nine_box = NULL; |  | 
| 774     // If true, this widget is |body_|, otherwise it is |menu_button_|. |  | 
| 775     if (GTK_WIDGET_STATE(widget) == GTK_STATE_PRELIGHT) |  | 
| 776       nine_box = is_body ? body_nine_box_prelight_ : menu_nine_box_prelight_; |  | 
| 777     else if (GTK_WIDGET_STATE(widget) == GTK_STATE_ACTIVE) |  | 
| 778       nine_box = is_body ? body_nine_box_active_ : menu_nine_box_active_; |  | 
| 779     else |  | 
| 780       nine_box = is_body ? body_nine_box_normal_ : menu_nine_box_normal_; |  | 
| 781 |  | 
| 782     // When the button is showing, we want to draw it as active. We have to do |  | 
| 783     // this explicitly because the button's state will be NORMAL while the menu |  | 
| 784     // has focus. |  | 
| 785     if (!is_body && menu_showing_) |  | 
| 786       nine_box = menu_nine_box_active_; |  | 
| 787 |  | 
| 788     nine_box->RenderToWidget(widget); |  | 
| 789   } |  | 
| 790 |  | 
| 791   GtkWidget* child = gtk_bin_get_child(GTK_BIN(widget)); |  | 
| 792   if (child) |  | 
| 793     gtk_container_propagate_expose(GTK_CONTAINER(widget), child, e); |  | 
| 794 |  | 
| 795   return TRUE; |  | 
| 796 } |  | 
| 797 |  | 
| 798 void DownloadItemGtk::OnClick(GtkWidget* widget) { |  | 
| 799   UMA_HISTOGRAM_LONG_TIMES("clickjacking.open_download", |  | 
| 800                            base::Time::Now() - creation_time_); |  | 
| 801   get_download()->OpenDownload(); |  | 
| 802 } |  | 
| 803 |  | 
| 804 gboolean DownloadItemGtk::OnProgressAreaExpose(GtkWidget* widget, |  | 
| 805                                                GdkEventExpose* event) { |  | 
| 806   // Create a transparent canvas. |  | 
| 807   gfx::CanvasSkiaPaint canvas(event, false); |  | 
| 808   if (complete_animation_.get()) { |  | 
| 809     if (complete_animation_->is_animating()) { |  | 
| 810       download_util::PaintDownloadComplete(&canvas, |  | 
| 811           widget->allocation.x, widget->allocation.y, |  | 
| 812           complete_animation_->GetCurrentValue(), |  | 
| 813           download_util::SMALL); |  | 
| 814     } |  | 
| 815   } else if (get_download()->state() != |  | 
| 816              DownloadItem::CANCELLED) { |  | 
| 817     download_util::PaintDownloadProgress(&canvas, |  | 
| 818         widget->allocation.x, widget->allocation.y, |  | 
| 819         progress_angle_, |  | 
| 820         get_download()->PercentComplete(), |  | 
| 821         download_util::SMALL); |  | 
| 822   } |  | 
| 823 |  | 
| 824   // |icon_small_| may be NULL if it is still loading. If the file is an |  | 
| 825   // unrecognized type then we will get back a generic system icon. Hence |  | 
| 826   // there is no need to use the chromium-specific default download item icon. |  | 
| 827   if (icon_small_) { |  | 
| 828     const int offset = download_util::kSmallProgressIconOffset; |  | 
| 829     canvas.DrawBitmapInt(*icon_small_, |  | 
| 830         widget->allocation.x + offset, widget->allocation.y + offset); |  | 
| 831   } |  | 
| 832 |  | 
| 833   return TRUE; |  | 
| 834 } |  | 
| 835 |  | 
| 836 gboolean DownloadItemGtk::OnMenuButtonPressEvent(GtkWidget* button, |  | 
| 837                                                  GdkEvent* event) { |  | 
| 838   // Stop any completion animation. |  | 
| 839   if (complete_animation_.get() && complete_animation_->is_animating()) |  | 
| 840     complete_animation_->End(); |  | 
| 841 |  | 
| 842   if (event->type == GDK_BUTTON_PRESS) { |  | 
| 843     GdkEventButton* event_button = reinterpret_cast<GdkEventButton*>(event); |  | 
| 844     if (event_button->button == 1) { |  | 
| 845       if (menu_.get() == NULL) { |  | 
| 846         menu_.reset(new DownloadShelfContextMenuGtk( |  | 
| 847             download_model_.get(), this)); |  | 
| 848       } |  | 
| 849       menu_->Popup(button, event); |  | 
| 850       menu_showing_ = true; |  | 
| 851       gtk_widget_queue_draw(button); |  | 
| 852     } |  | 
| 853   } |  | 
| 854 |  | 
| 855   return FALSE; |  | 
| 856 } |  | 
| 857 |  | 
| 858 gboolean DownloadItemGtk::OnDangerousPromptExpose(GtkWidget* widget, |  | 
| 859                                                   GdkEventExpose* event) { |  | 
| 860   if (!theme_provider_->UseGtkTheme()) { |  | 
| 861     // The hbox renderer will take care of the border when in GTK mode. |  | 
| 862     dangerous_nine_box_->RenderToWidget(widget); |  | 
| 863   } |  | 
| 864   return FALSE;  // Continue propagation. |  | 
| 865 } |  | 
| 866 |  | 
| 867 void DownloadItemGtk::OnDangerousAccept(GtkWidget* button) { |  | 
| 868   UMA_HISTOGRAM_LONG_TIMES("clickjacking.save_download", |  | 
| 869                            base::Time::Now() - creation_time_); |  | 
| 870   get_download()->DangerousDownloadValidated(); |  | 
| 871 } |  | 
| 872 |  | 
| 873 void DownloadItemGtk::OnDangerousDecline(GtkWidget* button) { |  | 
| 874   UMA_HISTOGRAM_LONG_TIMES("clickjacking.discard_download", |  | 
| 875                            base::Time::Now() - creation_time_); |  | 
| 876   if (get_download()->state() == DownloadItem::IN_PROGRESS) |  | 
| 877     get_download()->Cancel(true); |  | 
| 878   get_download()->Remove(true); |  | 
| 879 } |  | 
| OLD | NEW | 
|---|