Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(31)

Side by Side Diff: chrome/browser/chromeos/views/webui_menu_widget.cc

Issue 6693032: Remove WebUI menu (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: " Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 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/chromeos/views/webui_menu_widget.h"
6
7 #include <algorithm>
8
9 #include "base/stringprintf.h"
10 #include "base/singleton.h"
11 #include "base/task.h"
12 #include "base/utf_string_conversions.h"
13 #include "chrome/browser/chromeos/views/menu_locator.h"
14 #include "chrome/browser/chromeos/views/native_menu_webui.h"
15 #include "chrome/browser/chromeos/wm_ipc.h"
16 #include "chrome/browser/ui/views/dom_view.h"
17 #include "chrome/common/url_constants.h"
18 #include "content/browser/renderer_host/render_view_host.h"
19 #include "content/browser/renderer_host/render_widget_host_view.h"
20 #include "content/browser/tab_contents/tab_contents.h"
21 #include "googleurl/src/gurl.h"
22 #include "third_party/cros/chromeos_wm_ipc_enums.h"
23 #include "third_party/skia/include/effects/SkGradientShader.h"
24 #include "ui/gfx/canvas_skia.h"
25 #include "views/border.h"
26 #include "views/layout/layout_manager.h"
27 #include "views/widget/root_view.h"
28
29 namespace {
30
31 // Colors for the menu's gradient background.
32 const SkColor kMenuStartColor = SK_ColorWHITE;
33 const SkColor kMenuEndColor = 0xFFEEEEEE;
34
35 // Rounded border for menu. This draws three types of rounded border,
36 // for context menu, dropdown menu and submenu. Please see
37 // menu_locator.cc for details.
38 class RoundedBorder : public views::Border {
39 public:
40 explicit RoundedBorder(chromeos::MenuLocator* locator)
41 : menu_locator_(locator) {
42 }
43
44 private:
45 // views::Border implementations.
46 virtual void Paint(const views::View& view, gfx::Canvas* canvas) const {
47 const SkScalar* corners = menu_locator_->GetCorners();
48 // The menu is in off screen so no need to draw corners.
49 if (!corners)
50 return;
51 int w = view.width();
52 int h = view.height();
53 SkRect rect = {0, 0, w, h};
54 SkPath path;
55 path.addRoundRect(rect, corners);
56 SkPaint paint;
57 paint.setStyle(SkPaint::kFill_Style);
58 paint.setFlags(SkPaint::kAntiAlias_Flag);
59 SkPoint p[2] = { {0, 0}, {0, h} };
60 SkColor colors[2] = {kMenuStartColor, kMenuEndColor};
61 SkShader* s = SkGradientShader::CreateLinear(
62 p, colors, NULL, 2, SkShader::kClamp_TileMode, NULL);
63 paint.setShader(s);
64 // Need to unref shader, otherwise never deleted.
65 s->unref();
66 canvas->AsCanvasSkia()->drawPath(path, paint);
67 }
68
69 virtual void GetInsets(gfx::Insets* insets) const {
70 DCHECK(insets);
71 menu_locator_->GetInsets(insets);
72 }
73
74 chromeos::MenuLocator* menu_locator_; // not owned
75
76 DISALLOW_COPY_AND_ASSIGN(RoundedBorder);
77 };
78
79 class InsetsLayout : public views::LayoutManager {
80 public:
81 InsetsLayout() : views::LayoutManager() {}
82
83 private:
84 // views::LayoutManager implementations.
85 virtual void Layout(views::View* host) {
86 if (!host->has_children())
87 return;
88 gfx::Insets insets = host->GetInsets();
89 views::View* view = host->GetChildViewAt(0);
90
91 view->SetBounds(insets.left(), insets.top(),
92 host->width() - insets.width(),
93 host->height() - insets.height());
94 }
95
96 virtual gfx::Size GetPreferredSize(views::View* host) {
97 DCHECK(host->child_count() == 1);
98 gfx::Insets insets = host->GetInsets();
99 gfx::Size size = host->GetChildViewAt(0)->GetPreferredSize();
100 return gfx::Size(size.width() + insets.width(),
101 size.height() + insets.height());
102 }
103
104 DISALLOW_COPY_AND_ASSIGN(InsetsLayout);
105 };
106
107 // A gtk widget key used to test if a given WidgetGtk instance is
108 // a WebUIMenuWidgetKey.
109 const char* kWebUIMenuWidgetKey = "__WEBUI_MENU_WIDGET__";
110
111 } // namespace
112
113 namespace chromeos {
114
115 // static
116 WebUIMenuWidget* WebUIMenuWidget::FindWebUIMenuWidget(gfx::NativeView native) {
117 DCHECK(native);
118 native = gtk_widget_get_toplevel(native);
119 if (!native)
120 return NULL;
121 return static_cast<chromeos::WebUIMenuWidget*>(
122 g_object_get_data(G_OBJECT(native), kWebUIMenuWidgetKey));
123 }
124
125 ///////////////////////////////////////////////////////////////////////////////
126 // WebUIMenuWidget public:
127
128 WebUIMenuWidget::WebUIMenuWidget(chromeos::NativeMenuWebUI* webui_menu,
129 bool root)
130 : views::WidgetGtk(views::WidgetGtk::TYPE_POPUP),
131 webui_menu_(webui_menu),
132 dom_view_(NULL),
133 did_input_grab_(false),
134 is_root_(root) {
135 DCHECK(webui_menu_);
136 // TODO(oshima): Disabling transparent until we migrate bookmark
137 // menus to WebUI. See crosbug.com/7718.
138 // MakeTransparent();
139 }
140
141 WebUIMenuWidget::~WebUIMenuWidget() {
142 }
143
144 void WebUIMenuWidget::Init(gfx::NativeView parent, const gfx::Rect& bounds) {
145 WidgetGtk::Init(parent, bounds);
146 gtk_window_set_destroy_with_parent(GTK_WINDOW(GetNativeView()), TRUE);
147 gtk_window_set_type_hint(GTK_WINDOW(GetNativeView()),
148 GDK_WINDOW_TYPE_HINT_MENU);
149 g_object_set_data(G_OBJECT(GetNativeView()), kWebUIMenuWidgetKey, this);
150 }
151
152 void WebUIMenuWidget::Hide() {
153 ReleaseNativeCapture();
154 WidgetGtk::Hide();
155 // Clears the content.
156 ExecuteJavascript(L"updateModel({'items':[]})");
157 }
158
159 void WebUIMenuWidget::Close() {
160 if (dom_view_ != NULL) {
161 dom_view_->parent()->RemoveChildView(dom_view_);
162 delete dom_view_;
163 dom_view_ = NULL;
164 }
165
166 // Detach the webui_menu_ which is being deleted.
167 webui_menu_ = NULL;
168 views::WidgetGtk::Close();
169 }
170
171 void WebUIMenuWidget::ReleaseNativeCapture() {
172 WidgetGtk::ReleaseNativeCapture();
173 if (did_input_grab_) {
174 did_input_grab_ = false;
175 gdk_pointer_ungrab(GDK_CURRENT_TIME);
176 gdk_keyboard_ungrab(GDK_CURRENT_TIME);
177
178 ClearGrabWidget();
179 }
180 }
181
182 gboolean WebUIMenuWidget::OnGrabBrokeEvent(GtkWidget* widget,
183 GdkEvent* event) {
184 did_input_grab_ = false;
185 Hide();
186 return WidgetGtk::OnGrabBrokeEvent(widget, event);
187 }
188
189 void WebUIMenuWidget::OnSizeAllocate(GtkWidget* widget,
190 GtkAllocation* allocation) {
191 views::WidgetGtk::OnSizeAllocate(widget, allocation);
192 // Adjust location when menu gets resized.
193 gfx::Rect bounds = GetClientAreaScreenBounds();
194 // Don't move until the menu gets contents.
195 if (bounds.height() > 1) {
196 menu_locator_->Move(this);
197 webui_menu_->InputIsReady();
198 }
199 }
200
201 gboolean MapToFocus(GtkWidget* widget, GdkEvent* event, gpointer data) {
202 WebUIMenuWidget* menu_widget = WebUIMenuWidget::FindWebUIMenuWidget(widget);
203 if (menu_widget) {
204 // See EnableInput for the meaning of data.
205 bool select_item = data != NULL;
206 menu_widget->EnableInput(select_item);
207 }
208 return true;
209 }
210
211 void WebUIMenuWidget::EnableScroll(bool enable) {
212 ExecuteJavascript(StringPrintf(
213 L"enableScroll(%ls)", enable ? L"true" : L"false"));
214 }
215
216 void WebUIMenuWidget::EnableInput(bool select_item) {
217 if (!dom_view_)
218 return;
219 DCHECK(dom_view_->tab_contents()->render_view_host());
220 DCHECK(dom_view_->tab_contents()->render_view_host()->view());
221 GtkWidget* target =
222 dom_view_->tab_contents()->render_view_host()->view()->GetNativeView();
223 DCHECK(target);
224 // Skip if the widget already own the input.
225 if (gtk_grab_get_current() == target)
226 return;
227
228 ClearGrabWidget();
229
230 if (!GTK_WIDGET_REALIZED(target)) {
231 // Wait grabbing widget if the widget is not yet realized.
232 // Using data as a flag. |select_item| is false if data is NULL,
233 // or true otherwise.
234 g_signal_connect(G_OBJECT(target), "map-event",
235 G_CALLBACK(&MapToFocus),
236 select_item ? this : NULL);
237 return;
238 }
239
240 gtk_grab_add(target);
241 dom_view_->tab_contents()->Focus();
242 if (select_item) {
243 ExecuteJavascript(L"selectItem()");
244 }
245 }
246
247 void WebUIMenuWidget::ExecuteJavascript(const std::wstring& script) {
248 // Don't execute if there is no DOMView associated. This is fine because
249 // 1) selectItem make sense only when DOMView is associated.
250 // 2) updateModel will be called again when a DOMView is created/assigned.
251 if (!dom_view_)
252 return;
253
254 DCHECK(dom_view_->tab_contents()->render_view_host());
255 dom_view_->tab_contents()->render_view_host()->
256 ExecuteJavascriptInWebFrame(string16(), WideToUTF16Hack(script));
257 }
258
259 void WebUIMenuWidget::ShowAt(chromeos::MenuLocator* locator) {
260 DCHECK(webui_menu_);
261 menu_locator_.reset(locator);
262 if (!dom_view_) {
263 // TODO(oshima): Replace DOMView with direct use of RVH for beta.
264 // DOMView should be refactored to use RVH directly, but
265 // it'll require a lot of change and will take time.
266 dom_view_ = new DOMView();
267 dom_view_->Init(webui_menu_->GetProfile(), NULL);
268 // TODO(oshima): remove extra view to draw rounded corner.
269 views::View* container = new views::View();
270 container->AddChildView(dom_view_);
271 container->set_border(new RoundedBorder(locator));
272 container->SetLayoutManager(new InsetsLayout());
273 SetContentsView(container);
274 dom_view_->LoadURL(webui_menu_->menu_url());
275 } else {
276 webui_menu_->UpdateStates();
277 dom_view_->parent()->set_border(new RoundedBorder(locator));
278 menu_locator_->Move(this);
279 }
280 Show();
281
282 // The pointer grab is captured only on the top level menu,
283 // all mouse event events are delivered to submenu using gtk_add_grab.
284 if (is_root_) {
285 CaptureGrab();
286 }
287 }
288
289 void WebUIMenuWidget::SetSize(const gfx::Size& new_size) {
290 DCHECK(webui_menu_);
291 // Ignore the empty new_size request which is called when
292 // menu.html is loaded.
293 if (new_size.IsEmpty())
294 return;
295 int width, height;
296 gtk_widget_get_size_request(GetNativeView(), &width, &height);
297 gfx::Size real_size(std::max(new_size.width(), width),
298 new_size.height());
299 // Ignore the size request with the same size.
300 gfx::Rect bounds = GetClientAreaScreenBounds();
301 if (bounds.size() == real_size)
302 return;
303 menu_locator_->SetBounds(this, real_size);
304 }
305
306 ///////////////////////////////////////////////////////////////////////////////
307 // WebUIMenuWidget private:
308
309 void WebUIMenuWidget::CaptureGrab() {
310 // Release the current grab.
311 ClearGrabWidget();
312
313 // NOTE: we do this to ensure we get mouse/keyboard events from
314 // other apps, a grab done with gtk_grab_add doesn't get events from
315 // other apps.
316 GdkGrabStatus pointer_grab_status =
317 gdk_pointer_grab(window_contents()->window, FALSE,
318 static_cast<GdkEventMask>(
319 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
320 GDK_POINTER_MOTION_MASK),
321 NULL, NULL, GDK_CURRENT_TIME);
322 GdkGrabStatus keyboard_grab_status =
323 gdk_keyboard_grab(window_contents()->window, FALSE,
324 GDK_CURRENT_TIME);
325
326 did_input_grab_ = pointer_grab_status == GDK_GRAB_SUCCESS &&
327 keyboard_grab_status == GDK_GRAB_SUCCESS;
328 DCHECK(did_input_grab_);
329
330 EnableInput(false /* no selection */);
331 }
332
333 void WebUIMenuWidget::ClearGrabWidget() {
334 GtkWidget* grab_widget;
335 while ((grab_widget = gtk_grab_get_current()))
336 gtk_grab_remove(grab_widget);
337 }
338
339 } // namespace chromeos
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/views/webui_menu_widget.h ('k') | chrome/browser/chromeos/webui/menu_ui.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698