| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2009 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/extension_popup_gtk.h" | |
| 6 | |
| 7 #include <gtk/gtk.h> | |
| 8 | |
| 9 #include <algorithm> | |
| 10 | |
| 11 #include "base/i18n/rtl.h" | |
| 12 #include "base/message_loop.h" | |
| 13 #include "chrome/browser/browser_window.h" | |
| 14 #include "chrome/browser/debugger/devtools_manager.h" | |
| 15 #include "chrome/browser/profiles/profile.h" | |
| 16 #include "chrome/browser/extensions/extension_host.h" | |
| 17 #include "chrome/browser/extensions/extension_process_manager.h" | |
| 18 #include "chrome/browser/gtk/gtk_theme_provider.h" | |
| 19 #include "chrome/browser/renderer_host/render_view_host.h" | |
| 20 #include "chrome/browser/renderer_host/render_widget_host_view_gtk.h" | |
| 21 #include "chrome/browser/ui/browser.h" | |
| 22 #include "chrome/common/notification_details.h" | |
| 23 #include "chrome/common/notification_source.h" | |
| 24 #include "googleurl/src/gurl.h" | |
| 25 | |
| 26 ExtensionPopupGtk* ExtensionPopupGtk::current_extension_popup_ = NULL; | |
| 27 | |
| 28 // The minimum/maximum dimensions of the extension popup. | |
| 29 // The minimum is just a little larger than the size of a browser action button. | |
| 30 // The maximum is an arbitrary number that should be smaller than most screens. | |
| 31 const int ExtensionPopupGtk::kMinWidth = 25; | |
| 32 const int ExtensionPopupGtk::kMinHeight = 25; | |
| 33 const int ExtensionPopupGtk::kMaxWidth = 800; | |
| 34 const int ExtensionPopupGtk::kMaxHeight = 600; | |
| 35 | |
| 36 ExtensionPopupGtk::ExtensionPopupGtk(Browser* browser, | |
| 37 ExtensionHost* host, | |
| 38 GtkWidget* anchor, | |
| 39 bool inspect) | |
| 40 : browser_(browser), | |
| 41 bubble_(NULL), | |
| 42 host_(host), | |
| 43 anchor_(anchor), | |
| 44 being_inspected_(inspect), | |
| 45 method_factory_(this) { | |
| 46 host_->view()->SetContainer(this); | |
| 47 | |
| 48 // If the host had somehow finished loading, then we'd miss the notification | |
| 49 // and not show. This seems to happen in single-process mode. | |
| 50 if (host->did_stop_loading()) { | |
| 51 ShowPopup(); | |
| 52 } else { | |
| 53 registrar_.Add(this, NotificationType::EXTENSION_HOST_DID_STOP_LOADING, | |
| 54 Source<Profile>(host->profile())); | |
| 55 } | |
| 56 | |
| 57 registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE, | |
| 58 Source<Profile>(host->profile())); | |
| 59 } | |
| 60 | |
| 61 ExtensionPopupGtk::~ExtensionPopupGtk() { | |
| 62 } | |
| 63 | |
| 64 void ExtensionPopupGtk::Observe(NotificationType type, | |
| 65 const NotificationSource& source, | |
| 66 const NotificationDetails& details) { | |
| 67 switch (type.value) { | |
| 68 case NotificationType::EXTENSION_HOST_DID_STOP_LOADING: | |
| 69 if (Details<ExtensionHost>(host_.get()) == details) | |
| 70 ShowPopup(); | |
| 71 break; | |
| 72 case NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE: | |
| 73 if (Details<ExtensionHost>(host_.get()) == details) | |
| 74 DestroyPopup(); | |
| 75 break; | |
| 76 case NotificationType::DEVTOOLS_WINDOW_CLOSING: | |
| 77 // Make sure its the devtools window that inspecting our popup. | |
| 78 if (Details<RenderViewHost>(host_->render_view_host()) != details) | |
| 79 break; | |
| 80 | |
| 81 // If the devtools window is closing, we post a task to ourselves to | |
| 82 // close the popup. This gives the devtools window a chance to finish | |
| 83 // detaching from the inspected RenderViewHost. | |
| 84 MessageLoop::current()->PostTask(FROM_HERE, | |
| 85 method_factory_.NewRunnableMethod(&ExtensionPopupGtk::DestroyPopup)); | |
| 86 break; | |
| 87 default: | |
| 88 NOTREACHED() << "Received unexpected notification"; | |
| 89 } | |
| 90 } | |
| 91 | |
| 92 void ExtensionPopupGtk::ShowPopup() { | |
| 93 if (bubble_) { | |
| 94 NOTREACHED(); | |
| 95 return; | |
| 96 } | |
| 97 | |
| 98 if (being_inspected_) { | |
| 99 DevToolsManager::GetInstance()->OpenDevToolsWindow( | |
| 100 host_->render_view_host()); | |
| 101 // Listen for the the devtools window closing. | |
| 102 registrar_.Add(this, NotificationType::DEVTOOLS_WINDOW_CLOSING, | |
| 103 Source<Profile>(host_->profile())); | |
| 104 } | |
| 105 | |
| 106 // Only one instance should be showing at a time. Get rid of the old one, if | |
| 107 // any. Typically, |current_extension_popup_| will be NULL, but it can be | |
| 108 // non-NULL if a browser action button is clicked while another extension | |
| 109 // popup's extension host is still loading. | |
| 110 if (current_extension_popup_) | |
| 111 current_extension_popup_->DestroyPopup(); | |
| 112 current_extension_popup_ = this; | |
| 113 | |
| 114 // We'll be in the upper-right corner of the window for LTR languages, so we | |
| 115 // want to put the arrow at the upper-right corner of the bubble to match the | |
| 116 // page and app menus. | |
| 117 InfoBubbleGtk::ArrowLocationGtk arrow_location = | |
| 118 !base::i18n::IsRTL() ? | |
| 119 InfoBubbleGtk::ARROW_LOCATION_TOP_RIGHT : | |
| 120 InfoBubbleGtk::ARROW_LOCATION_TOP_LEFT; | |
| 121 bubble_ = InfoBubbleGtk::Show(anchor_, | |
| 122 NULL, | |
| 123 host_->view()->native_view(), | |
| 124 arrow_location, | |
| 125 false, // match_system_theme | |
| 126 !being_inspected_, // grab_input | |
| 127 GtkThemeProvider::GetFrom(browser_->profile()), | |
| 128 this); | |
| 129 } | |
| 130 | |
| 131 bool ExtensionPopupGtk::DestroyPopup() { | |
| 132 if (!bubble_) { | |
| 133 NOTREACHED(); | |
| 134 return false; | |
| 135 } | |
| 136 | |
| 137 bubble_->Close(); | |
| 138 return true; | |
| 139 } | |
| 140 | |
| 141 void ExtensionPopupGtk::InfoBubbleClosing(InfoBubbleGtk* bubble, | |
| 142 bool closed_by_escape) { | |
| 143 current_extension_popup_ = NULL; | |
| 144 delete this; | |
| 145 } | |
| 146 | |
| 147 void ExtensionPopupGtk::OnExtensionPreferredSizeChanged( | |
| 148 ExtensionViewGtk* view, | |
| 149 const gfx::Size& new_size) { | |
| 150 int width = std::max(kMinWidth, std::min(kMaxWidth, new_size.width())); | |
| 151 int height = std::max(kMinHeight, std::min(kMaxHeight, new_size.height())); | |
| 152 | |
| 153 view->render_view_host()->view()->SetSize(gfx::Size(width, height)); | |
| 154 gtk_widget_set_size_request(view->native_view(), width, height); | |
| 155 } | |
| 156 | |
| 157 // static | |
| 158 void ExtensionPopupGtk::Show(const GURL& url, Browser* browser, | |
| 159 GtkWidget* anchor, bool inspect) { | |
| 160 ExtensionProcessManager* manager = | |
| 161 browser->profile()->GetExtensionProcessManager(); | |
| 162 DCHECK(manager); | |
| 163 if (!manager) | |
| 164 return; | |
| 165 | |
| 166 ExtensionHost* host = manager->CreatePopup(url, browser); | |
| 167 // This object will delete itself when the info bubble is closed. | |
| 168 new ExtensionPopupGtk(browser, host, anchor, inspect); | |
| 169 } | |
| 170 | |
| 171 gfx::Rect ExtensionPopupGtk::GetViewBounds() { | |
| 172 return gfx::Rect(host_->view()->native_view()->allocation); | |
| 173 } | |
| OLD | NEW |