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

Side by Side Diff: chrome/browser/chromeos/views/native_menu_webui.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/native_menu_webui.h"
6
7 #include <string>
8
9 #include "base/message_loop.h"
10 #include "base/string_util.h"
11 #include "chrome/browser/chromeos/views/menu_locator.h"
12 #include "chrome/browser/chromeos/views/webui_menu_widget.h"
13 #include "chrome/browser/chromeos/webui/menu_ui.h"
14 #include "chrome/browser/profiles/profile_manager.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/browser_list.h"
17 #include "chrome/browser/ui/browser_window.h"
18 #include "chrome/common/url_constants.h"
19 #include "ui/base/models/menu_model.h"
20 #include "ui/gfx/rect.h"
21 #include "views/controls/menu/menu_2.h"
22 #include "views/controls/menu/nested_dispatcher_gtk.h"
23
24 #if defined(TOUCH_UI)
25 #include "views/focus/accelerator_handler.h"
26 #include "views/controls/menu/native_menu_x.h"
27 #else
28 #include "views/controls/menu/native_menu_gtk.h"
29 #endif
30
31 namespace {
32
33 using chromeos::NativeMenuWebUI;
34 using chromeos::WebUIMenuWidget;
35
36 // Returns true if the menu item type specified can be executed as a command.
37 bool MenuTypeCanExecute(ui::MenuModel::ItemType type) {
38 return type == ui::MenuModel::TYPE_COMMAND ||
39 type == ui::MenuModel::TYPE_CHECK ||
40 type == ui::MenuModel::TYPE_RADIO;
41 }
42
43 gboolean Destroy(GtkWidget* widget, gpointer data) {
44 WebUIMenuWidget* menu_widget = static_cast<WebUIMenuWidget*>(data);
45 NativeMenuWebUI* webui_menu = menu_widget->webui_menu();
46 // webui_menu can be NULL if widget is destroyed by signal.
47 if (webui_menu)
48 webui_menu->Hide();
49 return true;
50 }
51
52 // Returns the active toplevel window.
53 gfx::NativeWindow FindActiveToplevelWindow() {
54 GList* toplevels = gtk_window_list_toplevels();
55 while (toplevels) {
56 gfx::NativeWindow window = static_cast<gfx::NativeWindow>(toplevels->data);
57 if (gtk_window_is_active(window)) {
58 return window;
59 }
60 toplevels = g_list_next(toplevels);
61 }
62 return NULL;
63 }
64
65 // Currently opened menu. See RunMenuAt for reason why we need this.
66 NativeMenuWebUI* current_ = NULL;
67
68 } // namespace
69
70 namespace chromeos {
71
72 // static
73 void NativeMenuWebUI::SetMenuURL(views::Menu2* menu2, const GURL& url) {
74 // No-op if WebUI menu is disabled.
75 if (!MenuUI::IsEnabled())
76 return;
77
78 gfx::NativeView native = menu2->GetNativeMenu();
79 DCHECK(native);
80 WebUIMenuWidget* widget = WebUIMenuWidget::FindWebUIMenuWidget(native);
81 DCHECK(widget);
82 widget->webui_menu()->set_menu_url(url);
83 }
84
85 ////////////////////////////////////////////////////////////////////////////////
86 // NativeMenuWebUI, public:
87
88 NativeMenuWebUI::NativeMenuWebUI(ui::MenuModel* menu_model, bool root)
89 : parent_(NULL),
90 submenu_(NULL),
91 model_(menu_model),
92 menu_widget_(NULL),
93 menu_shown_(false),
94 activated_menu_(NULL),
95 activated_index_(-1),
96 menu_action_(MENU_ACTION_NONE),
97 menu_url_(StringPrintf("chrome://%s", chrome::kChromeUIMenu)),
98 on_menu_opened_called_(false),
99 nested_dispatcher_(NULL) {
100 menu_widget_ = new WebUIMenuWidget(this, root);
101 // Set the initial location off the screen not to show small
102 // window with dropshadow.
103 menu_widget_->Init(NULL, gfx::Rect(-10000, -10000, 1, 1));
104 }
105
106 NativeMenuWebUI::~NativeMenuWebUI() {
107 if (nested_dispatcher_) {
108 // Menu is destroyed while its in message loop.
109 // Let nested dispatcher know the creator is deleted.
110 nested_dispatcher_->CreatorDestroyed();
111 Hide();
112 }
113 if (menu_widget_) {
114 menu_widget_->Close();
115 menu_widget_ = NULL;
116 }
117 parent_ = NULL;
118 }
119
120 ////////////////////////////////////////////////////////////////////////////////
121 // NativeMenuWebUI, MenuWrapper implementation:
122
123 void NativeMenuWebUI::RunMenuAt(const gfx::Point& point, int alignment) {
124 if (current_ != NULL) {
125 // This happens when there is a nested task to show menu, which is
126 // executed after menu is open. Since we need to enable nested task,
127 // this condition has to be handled here.
128 return;
129 }
130 current_ = this;
131 bool context = false;
132
133 // TODO(oshima): This is quick hack to check if it's context menu. (in rtl)
134 // Fix this once we migrated.
135 if (alignment == views::Menu2::ALIGN_TOPLEFT) {
136 context = true;
137 }
138
139 activated_menu_ = NULL;
140 activated_index_ = -1;
141 menu_action_ = MENU_ACTION_NONE;
142
143 MenuLocator* locator = context ?
144 MenuLocator::CreateContextMenuLocator(point) :
145 MenuLocator::CreateDropDownMenuLocator(point);
146 ShowAt(locator);
147 DCHECK(!menu_shown_);
148 menu_shown_ = true;
149 on_menu_opened_called_ = false;
150
151 // TODO(oshima): A menu must be deleted when parent window is
152 // closed. Menu2 doesn't know about the parent window, however, so
153 // we're using toplevel gtkwindow. This is probably sufficient, but
154 // I will update Menu2 to pass host view (which is necessary anyway
155 // to get the right position) and get a parent widnow through
156 // it. http://crosbug/7642
157 gfx::NativeWindow parent = FindActiveToplevelWindow();
158 gulong handle = 0;
159 if (parent) {
160 handle = g_signal_connect(G_OBJECT(parent), "destroy",
161 G_CALLBACK(&Destroy),
162 menu_widget_);
163 }
164 // We need to turn on nestable tasks as a renderer uses tasks internally.
165 // Without this, renderer cannnot finish loading page.
166 nested_dispatcher_ =
167 new views::NestedDispatcherGtk(this, true /* allow nested */);
168 bool deleted = nested_dispatcher_->RunAndSelfDestruct();
169 current_ = NULL; // this is static and safe to access.
170 if (deleted) {
171 // The menu was destryed while menu is shown, so return immediately.
172 // Don't touch the instance which is already deleted.
173 return;
174 }
175 nested_dispatcher_ = NULL;
176 if (menu_shown_) {
177 // If this happens it means we haven't yet gotten the hide signal and
178 // someone else quit the message loop on us.
179 NOTREACHED();
180 menu_shown_ = false;
181 }
182 if (handle)
183 g_signal_handler_disconnect(G_OBJECT(parent), handle);
184
185 menu_widget_->Hide();
186 // Close All submenus.
187 submenu_.reset();
188 ProcessActivate();
189 }
190
191 void NativeMenuWebUI::CancelMenu() {
192 Hide();
193 }
194
195 void NativeMenuWebUI::Rebuild() {
196 activated_menu_ = NULL;
197 menu_widget_->ExecuteJavascript(L"modelUpdated()");
198 }
199
200 void NativeMenuWebUI::UpdateStates() {
201 // Update menu contnets and submenus.
202 Rebuild();
203 }
204
205 gfx::NativeMenu NativeMenuWebUI::GetNativeMenu() const {
206 return menu_widget_->GetNativeView();
207 }
208
209 NativeMenuWebUI::MenuAction NativeMenuWebUI::GetMenuAction() const {
210 return menu_action_;
211 }
212
213 void NativeMenuWebUI::AddMenuListener(views::MenuListener* listener) {
214 listeners_.AddObserver(listener);
215 }
216
217 void NativeMenuWebUI::RemoveMenuListener(views::MenuListener* listener) {
218 listeners_.RemoveObserver(listener);
219 }
220
221 void NativeMenuWebUI::SetMinimumWidth(int width) {
222 gtk_widget_set_size_request(menu_widget_->GetNativeView(), width, 1);
223 }
224
225 ////////////////////////////////////////////////////////////////////////////////
226 // NativeMenuWebUI, MessageLoopForUI::Dispatcher implementation:
227
228 bool NativeMenuWebUI::Dispatch(GdkEvent* event) {
229 switch (event->type) {
230 case GDK_MOTION_NOTIFY: {
231 NativeMenuWebUI* target = FindMenuAt(
232 gfx::Point(event->motion.x_root, event->motion.y_root));
233 if (target)
234 target->menu_widget_->EnableInput(false);
235 break;
236 }
237 case GDK_BUTTON_PRESS: {
238 NativeMenuWebUI* target = FindMenuAt(
239 gfx::Point(event->motion.x_root, event->motion.y_root));
240 if (!target) {
241 Hide();
242 return true;
243 }
244 break;
245 }
246 default:
247 break;
248 }
249 gtk_main_do_event(event);
250 return true;
251 }
252
253 #if defined(TOUCH_UI)
254 base::MessagePumpGlibXDispatcher::DispatchStatus
255 NativeMenuWebUI::DispatchX(XEvent* xevent) {
256 return views::DispatchXEvent(xevent) ?
257 base::MessagePumpGlibXDispatcher::EVENT_PROCESSED :
258 base::MessagePumpGlibXDispatcher::EVENT_IGNORED;
259
260 }
261 #endif
262
263 ////////////////////////////////////////////////////////////////////////////////
264 // NativeMenuWebUI, MenuControl implementation:
265
266 void NativeMenuWebUI::Activate(ui::MenuModel* model,
267 int index,
268 ActivationMode activation) {
269 NativeMenuWebUI* root = GetRoot();
270 if (root) {
271 if (activation == CLOSE_AND_ACTIVATE) {
272 root->activated_menu_ = model;
273 root->activated_index_ = index;
274 root->menu_action_ = MENU_ACTION_SELECTED;
275 root->Hide();
276 } else {
277 if (model->IsEnabledAt(index) &&
278 MenuTypeCanExecute(model->GetTypeAt(index))) {
279 model->ActivatedAt(index);
280 }
281 }
282 }
283 }
284
285 void NativeMenuWebUI::OpenSubmenu(int index, int y) {
286 submenu_.reset();
287 // Returns the model for the submenu at the specified index.
288 ui::MenuModel* submenu = model_->GetSubmenuModelAt(index);
289 submenu_.reset(new chromeos::NativeMenuWebUI(submenu, false));
290 submenu_->set_menu_url(menu_url_);
291 // y in menu_widget_ coordinate.
292 submenu_->set_parent(this);
293 submenu_->ShowAt(
294 MenuLocator::CreateSubMenuLocator(
295 menu_widget_,
296 menu_widget_->menu_locator()->GetSubmenuDirection(),
297 y));
298 }
299
300 void NativeMenuWebUI::CloseAll() {
301 NativeMenuWebUI* root = GetRoot();
302 // root can be null if the submenu is detached from parent.
303 if (root)
304 root->Hide();
305 }
306
307 void NativeMenuWebUI::CloseSubmenu() {
308 submenu_.reset(); // This closes subsequent children.
309 }
310
311 void NativeMenuWebUI::MoveInputToSubmenu() {
312 if (submenu_.get()) {
313 submenu_->menu_widget_->EnableInput(true);
314 }
315 }
316
317 void NativeMenuWebUI::MoveInputToParent() {
318 if (parent_) {
319 parent_->menu_widget_->EnableInput(true);
320 }
321 }
322
323 void NativeMenuWebUI::OnLoad() {
324 // TODO(oshima): OnLoad is no longer used, but kept in case
325 // we may need it. Delete this if this is not necessary to
326 // implement wrench/network/bookmark menus.
327 }
328
329 void NativeMenuWebUI::SetSize(const gfx::Size& size) {
330 menu_widget_->SetSize(size);
331 }
332
333 ////////////////////////////////////////////////////////////////////////////////
334 // NativeMenuWebUI, public:
335
336 void NativeMenuWebUI::Hide() {
337 // Only root can hide and exit the message loop.
338 DCHECK(menu_widget_->is_root());
339 DCHECK(!parent_);
340 if (!menu_shown_) {
341 // The menu has been already hidden by us and we're in the process of
342 // quiting the message loop..
343 return;
344 }
345 CloseSubmenu();
346 menu_shown_ = false;
347 MessageLoop::current()->Quit();
348 }
349
350 NativeMenuWebUI* NativeMenuWebUI::GetRoot() {
351 NativeMenuWebUI* ancestor = this;
352 while (ancestor->parent_)
353 ancestor = ancestor->parent_;
354 if (ancestor->menu_widget_->is_root())
355 return ancestor;
356 else
357 return NULL;
358 }
359
360 Profile* NativeMenuWebUI::GetProfile() {
361 Browser* browser = BrowserList::GetLastActive();
362 // browser can be null in login screen.
363 if (!browser)
364 return ProfileManager::GetDefaultProfile();
365 return browser->GetProfile();
366 }
367
368 void NativeMenuWebUI::InputIsReady() {
369 if (!on_menu_opened_called_) {
370 on_menu_opened_called_ = true;
371 FOR_EACH_OBSERVER(views::MenuListener, listeners_, OnMenuOpened());
372 }
373 }
374
375 ////////////////////////////////////////////////////////////////////////////////
376 // NativeMenuWebUI, private:
377
378 void NativeMenuWebUI::ProcessActivate() {
379 if (activated_menu_ &&
380 activated_menu_->IsEnabledAt(activated_index_) &&
381 MenuTypeCanExecute(activated_menu_->GetTypeAt(activated_index_))) {
382 activated_menu_->ActivatedAt(activated_index_);
383 }
384 }
385
386 void NativeMenuWebUI::ShowAt(MenuLocator* locator) {
387 model_->MenuWillShow();
388 menu_widget_->ShowAt(locator);
389 }
390
391 NativeMenuWebUI* NativeMenuWebUI::FindMenuAt(const gfx::Point& point) {
392 if (submenu_.get()) {
393 NativeMenuWebUI* found = submenu_->FindMenuAt(point);
394 if (found)
395 return found;
396 }
397 gfx::Rect bounds = menu_widget_->GetClientAreaScreenBounds();
398 return bounds.Contains(point) ? this : NULL;
399 }
400
401 } // namespace chromeos
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/views/native_menu_webui.h ('k') | chrome/browser/chromeos/views/webui_menu_widget.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698