| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this |
| 2 // source code is governed by a BSD-style license that can be found in the | 2 // source code is governed by a BSD-style license that can be found in the |
| 3 // LICENSE file. | 3 // LICENSE file. |
| 4 | 4 |
| 5 #include "views/controls/menu/native_menu_gtk.h" | 5 #include "views/controls/menu/native_menu_gtk.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "app/gfx/gtk_util.h" | 9 #include "app/gfx/gtk_util.h" |
| 10 #include "base/keyboard_codes.h" | 10 #include "base/keyboard_codes.h" |
| 11 #include "base/message_loop.h" | 11 #include "base/message_loop.h" |
| 12 #include "base/string_util.h" | 12 #include "base/string_util.h" |
| 13 #include "base/time.h" | 13 #include "base/time.h" |
| 14 #include "third_party/skia/include/core/SkBitmap.h" | 14 #include "third_party/skia/include/core/SkBitmap.h" |
| 15 #include "views/accelerator.h" | 15 #include "views/accelerator.h" |
| 16 #include "views/controls/menu/menu_2.h" | 16 #include "views/controls/menu/menu_2.h" |
| 17 | 17 |
| 18 namespace { | 18 namespace { |
| 19 // Data passed to the UpdateStateCallback from gtk_container_foreach. | 19 |
| 20 struct UpdateStateData { | 20 const char kPositionString[] = "position"; |
| 21 // The model to retrieve state from. | |
| 22 views::Menu2Model* model; | |
| 23 // The index within said model. | |
| 24 int index; | |
| 25 }; | |
| 26 | 21 |
| 27 // Data passed to the MenuPositionFunc from gtk_menu_popup | 22 // Data passed to the MenuPositionFunc from gtk_menu_popup |
| 28 struct Position { | 23 struct Position { |
| 29 // The point to run the menu at. | 24 // The point to run the menu at. |
| 30 gfx::Point point; | 25 gfx::Point point; |
| 31 // The alignment of the menu at that point. | 26 // The alignment of the menu at that point. |
| 32 views::Menu2::Alignment alignment; | 27 views::Menu2::Alignment alignment; |
| 33 }; | 28 }; |
| 34 | 29 |
| 35 std::string ConvertAcceleratorsFromWindowsStyle(const std::string& label) { | 30 std::string ConvertAcceleratorsFromWindowsStyle(const std::string& label) { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 61 } // namespace | 56 } // namespace |
| 62 | 57 |
| 63 namespace views { | 58 namespace views { |
| 64 | 59 |
| 65 //////////////////////////////////////////////////////////////////////////////// | 60 //////////////////////////////////////////////////////////////////////////////// |
| 66 // NativeMenuGtk, public: | 61 // NativeMenuGtk, public: |
| 67 | 62 |
| 68 NativeMenuGtk::NativeMenuGtk(Menu2Model* model) | 63 NativeMenuGtk::NativeMenuGtk(Menu2Model* model) |
| 69 : model_(model), | 64 : model_(model), |
| 70 menu_(NULL), | 65 menu_(NULL), |
| 71 menu_shown_(false) { | 66 menu_shown_(false), |
| 67 suppress_activate_signal_(false) { |
| 72 } | 68 } |
| 73 | 69 |
| 74 NativeMenuGtk::~NativeMenuGtk() { | 70 NativeMenuGtk::~NativeMenuGtk() { |
| 75 gtk_widget_destroy(menu_); | 71 gtk_widget_destroy(menu_); |
| 76 } | 72 } |
| 77 | 73 |
| 78 //////////////////////////////////////////////////////////////////////////////// | 74 //////////////////////////////////////////////////////////////////////////////// |
| 79 // NativeMenuGtk, MenuWrapper implementation: | 75 // NativeMenuGtk, MenuWrapper implementation: |
| 80 | 76 |
| 81 void NativeMenuGtk::RunMenuAt(const gfx::Point& point, int alignment) { | 77 void NativeMenuGtk::RunMenuAt(const gfx::Point& point, int alignment) { |
| 78 UpdateStates(); |
| 82 Position position = { point, static_cast<Menu2::Alignment>(alignment) }; | 79 Position position = { point, static_cast<Menu2::Alignment>(alignment) }; |
| 83 // TODO(beng): value of '1' will not work for context menus! | 80 // TODO(beng): value of '1' will not work for context menus! |
| 84 gtk_menu_popup(GTK_MENU(menu_), NULL, NULL, MenuPositionFunc, &position, 1, | 81 gtk_menu_popup(GTK_MENU(menu_), NULL, NULL, MenuPositionFunc, &position, 1, |
| 85 gtk_get_current_event_time()); | 82 gtk_get_current_event_time()); |
| 86 | 83 |
| 87 DCHECK(!menu_shown_); | 84 DCHECK(!menu_shown_); |
| 88 menu_shown_ = true; | 85 menu_shown_ = true; |
| 89 // Listen for "hide" signal so that we know when to return from the blocking | 86 // Listen for "hide" signal so that we know when to return from the blocking |
| 90 // RunMenuAt call. | 87 // RunMenuAt call. |
| 91 gint handle_id = | 88 gint handle_id = |
| (...skipping 17 matching lines...) Expand all Loading... |
| 109 for (int i = 0; i < model_->GetItemCount(); ++i) { | 106 for (int i = 0; i < model_->GetItemCount(); ++i) { |
| 110 Menu2Model::ItemType type = model_->GetTypeAt(i); | 107 Menu2Model::ItemType type = model_->GetTypeAt(i); |
| 111 if (type == Menu2Model::TYPE_SEPARATOR) | 108 if (type == Menu2Model::TYPE_SEPARATOR) |
| 112 AddSeparatorAt(i); | 109 AddSeparatorAt(i); |
| 113 else | 110 else |
| 114 AddMenuItemAt(i, &last_radio_item); | 111 AddMenuItemAt(i, &last_radio_item); |
| 115 } | 112 } |
| 116 } | 113 } |
| 117 | 114 |
| 118 void NativeMenuGtk::UpdateStates() { | 115 void NativeMenuGtk::UpdateStates() { |
| 119 UpdateStateData data = { model_, 0 }; | 116 gtk_container_foreach(GTK_CONTAINER(menu_), &UpdateStateCallback, this); |
| 120 gtk_container_foreach(GTK_CONTAINER(menu_), &UpdateStateCallback, &data); | |
| 121 } | 117 } |
| 122 | 118 |
| 123 gfx::NativeMenu NativeMenuGtk::GetNativeMenu() const { | 119 gfx::NativeMenu NativeMenuGtk::GetNativeMenu() const { |
| 124 return menu_; | 120 return menu_; |
| 125 } | 121 } |
| 126 | 122 |
| 127 //////////////////////////////////////////////////////////////////////////////// | 123 //////////////////////////////////////////////////////////////////////////////// |
| 128 // NativeMenuGtk, private: | 124 // NativeMenuGtk, private: |
| 129 | 125 |
| 130 // static | 126 // static |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 188 Menu2* submenu = new Menu2(model_->GetSubmenuModelAt(index)); | 184 Menu2* submenu = new Menu2(model_->GetSubmenuModelAt(index)); |
| 189 g_object_set_data(G_OBJECT(menu_item), "submenu", submenu); | 185 g_object_set_data(G_OBJECT(menu_item), "submenu", submenu); |
| 190 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), | 186 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), |
| 191 submenu->GetNativeMenu()); | 187 submenu->GetNativeMenu()); |
| 192 } | 188 } |
| 193 | 189 |
| 194 views::Accelerator accelerator(base::VKEY_UNKNOWN, false, false, false); | 190 views::Accelerator accelerator(base::VKEY_UNKNOWN, false, false, false); |
| 195 if (model_->GetAcceleratorAt(index, &accelerator)) { | 191 if (model_->GetAcceleratorAt(index, &accelerator)) { |
| 196 // TODO(beng): accelerators w/gtk_widget_add_accelerator. | 192 // TODO(beng): accelerators w/gtk_widget_add_accelerator. |
| 197 } | 193 } |
| 198 g_object_set_data(G_OBJECT(menu_item), "position", | 194 g_object_set_data(G_OBJECT(menu_item), kPositionString, |
| 199 reinterpret_cast<void*>(index)); | 195 reinterpret_cast<void*>(index)); |
| 200 g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(CallActivate), | 196 g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(CallActivate), |
| 201 this); | 197 this); |
| 202 gtk_widget_show(menu_item); | 198 gtk_widget_show(menu_item); |
| 203 gtk_menu_append(menu_, menu_item); | 199 gtk_menu_append(menu_, menu_item); |
| 204 } | 200 } |
| 205 | 201 |
| 206 // static | 202 void NativeMenuGtk::ResetMenu() { |
| 207 void NativeMenuGtk::UpdateStateCallback(GtkWidget* menu_item, gpointer data) { | 203 if (menu_) |
| 208 UpdateStateData* usd = reinterpret_cast<UpdateStateData*>(data); | 204 gtk_widget_destroy(menu_); |
| 209 gtk_widget_set_sensitive(menu_item, usd->model->IsEnabledAt(usd->index)); | 205 menu_ = gtk_menu_new(); |
| 206 } |
| 207 |
| 208 void NativeMenuGtk::UpdateMenuItemState(GtkWidget* menu_item) { |
| 209 int index = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu_item), |
| 210 kPositionString)); |
| 211 |
| 212 gtk_widget_set_sensitive(menu_item, model_->IsEnabledAt(index)); |
| 210 if (GTK_IS_CHECK_MENU_ITEM(menu_item)) { | 213 if (GTK_IS_CHECK_MENU_ITEM(menu_item)) { |
| 214 suppress_activate_signal_ = true; |
| 211 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), | 215 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), |
| 212 usd->model->IsItemCheckedAt(usd->index)); | 216 model_->IsItemCheckedAt(index)); |
| 217 suppress_activate_signal_ = false; |
| 213 } | 218 } |
| 214 // Recurse into submenus, too. | 219 // Recurse into submenus, too. |
| 215 if (GTK_IS_MENU_ITEM(menu_item)) { | 220 if (GTK_IS_MENU_ITEM(menu_item)) { |
| 216 if (gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_item))) { | 221 if (gtk_menu_item_get_submenu(GTK_MENU_ITEM(menu_item))) { |
| 217 Menu2* submenu = | 222 Menu2* submenu = |
| 218 reinterpret_cast<Menu2*>(g_object_get_data(G_OBJECT(menu_item), | 223 reinterpret_cast<Menu2*>(g_object_get_data(G_OBJECT(menu_item), |
| 219 "submenu")); | 224 "submenu")); |
| 220 if (submenu) | 225 if (submenu) |
| 221 submenu->UpdateStates(); | 226 submenu->UpdateStates(); |
| 222 } | 227 } |
| 223 } | 228 } |
| 224 ++usd->index; | |
| 225 } | |
| 226 | |
| 227 void NativeMenuGtk::ResetMenu() { | |
| 228 if (menu_) | |
| 229 gtk_widget_destroy(menu_); | |
| 230 menu_ = gtk_menu_new(); | |
| 231 } | 229 } |
| 232 | 230 |
| 233 // static | 231 // static |
| 232 void NativeMenuGtk::UpdateStateCallback(GtkWidget* menu_item, gpointer data) { |
| 233 NativeMenuGtk* menu = reinterpret_cast<NativeMenuGtk*>(data); |
| 234 menu->UpdateMenuItemState(menu_item); |
| 235 } |
| 236 |
| 237 // static |
| 234 void NativeMenuGtk::MenuPositionFunc(GtkMenu* menu, | 238 void NativeMenuGtk::MenuPositionFunc(GtkMenu* menu, |
| 235 int* x, | 239 int* x, |
| 236 int* y, | 240 int* y, |
| 237 gboolean* push_in, | 241 gboolean* push_in, |
| 238 void* data) { | 242 void* data) { |
| 239 Position* position = reinterpret_cast<Position*>(data); | 243 Position* position = reinterpret_cast<Position*>(data); |
| 240 // TODO(beng): RTL | 244 // TODO(beng): RTL |
| 241 *x = position->point.x(); | 245 *x = position->point.x(); |
| 242 *y = position->point.y(); | 246 *y = position->point.y(); |
| 243 if (position->alignment == Menu2::ALIGN_TOPRIGHT) { | 247 if (position->alignment == Menu2::ALIGN_TOPRIGHT) { |
| 244 GtkRequisition menu_req; | 248 GtkRequisition menu_req; |
| 245 gtk_widget_size_request(GTK_WIDGET(menu), &menu_req); | 249 gtk_widget_size_request(GTK_WIDGET(menu), &menu_req); |
| 246 *x -= menu_req.width; | 250 *x -= menu_req.width; |
| 247 } | 251 } |
| 248 *push_in = FALSE; | 252 *push_in = FALSE; |
| 249 } | 253 } |
| 250 | 254 |
| 251 void NativeMenuGtk::OnActivate(GtkMenuItem* menu_item) { | 255 void NativeMenuGtk::OnActivate(GtkMenuItem* menu_item) { |
| 256 if (suppress_activate_signal_) |
| 257 return; |
| 252 int position = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu_item), | 258 int position = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menu_item), |
| 253 "position")); | 259 kPositionString)); |
| 254 if (model_->IsEnabledAt(position) && | 260 if (model_->IsEnabledAt(position) && |
| 255 MenuTypeCanExecute(model_->GetTypeAt(position))) { | 261 MenuTypeCanExecute(model_->GetTypeAt(position))) { |
| 256 model_->ActivatedAt(position); | 262 model_->ActivatedAt(position); |
| 257 } | 263 } |
| 258 } | 264 } |
| 259 | 265 |
| 260 // static | 266 // static |
| 261 void NativeMenuGtk::CallActivate(GtkMenuItem* menu_item, | 267 void NativeMenuGtk::CallActivate(GtkMenuItem* menu_item, |
| 262 NativeMenuGtk* native_menu) { | 268 NativeMenuGtk* native_menu) { |
| 263 native_menu->OnActivate(menu_item); | 269 native_menu->OnActivate(menu_item); |
| 264 } | 270 } |
| 265 | 271 |
| 266 //////////////////////////////////////////////////////////////////////////////// | 272 //////////////////////////////////////////////////////////////////////////////// |
| 267 // MenuWrapper, public: | 273 // MenuWrapper, public: |
| 268 | 274 |
| 269 // static | 275 // static |
| 270 MenuWrapper* MenuWrapper::CreateWrapper(Menu2* menu) { | 276 MenuWrapper* MenuWrapper::CreateWrapper(Menu2* menu) { |
| 271 return new NativeMenuGtk(menu->model()); | 277 return new NativeMenuGtk(menu->model()); |
| 272 } | 278 } |
| 273 | 279 |
| 274 } // namespace views | 280 } // namespace views |
| OLD | NEW |