atom_api_menu_views.cc 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. // Copyright (c) 2014 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "shell/browser/api/atom_api_menu_views.h"
  5. #include <memory>
  6. #include <utility>
  7. #include "shell/browser/native_window_views.h"
  8. #include "shell/browser/unresponsive_suppressor.h"
  9. #include "ui/display/screen.h"
  10. using views::MenuRunner;
  11. namespace electron {
  12. namespace api {
  13. MenuViews::MenuViews(v8::Isolate* isolate, v8::Local<v8::Object> wrapper)
  14. : Menu(isolate, wrapper), weak_factory_(this) {}
  15. MenuViews::~MenuViews() = default;
  16. void MenuViews::PopupAt(TopLevelWindow* window,
  17. int x,
  18. int y,
  19. int positioning_item,
  20. base::OnceClosure callback) {
  21. auto* native_window = static_cast<NativeWindowViews*>(window->window());
  22. if (!native_window)
  23. return;
  24. // (-1, -1) means showing on mouse location.
  25. gfx::Point location;
  26. if (x == -1 || y == -1) {
  27. location = display::Screen::GetScreen()->GetCursorScreenPoint();
  28. } else {
  29. gfx::Point origin = native_window->GetContentBounds().origin();
  30. location = gfx::Point(origin.x() + x, origin.y() + y);
  31. }
  32. int flags = MenuRunner::CONTEXT_MENU | MenuRunner::HAS_MNEMONICS;
  33. // Don't emit unresponsive event when showing menu.
  34. electron::UnresponsiveSuppressor suppressor;
  35. // Make sure the Menu object would not be garbage-collected until the callback
  36. // has run.
  37. base::OnceClosure callback_with_ref = BindSelfToClosure(std::move(callback));
  38. // Show the menu.
  39. //
  40. // Note that while views::MenuRunner accepts RepeatingCallback as close
  41. // callback, it is fine passing OnceCallback to it because we reset the
  42. // menu runner immediately when the menu is closed.
  43. int32_t window_id = window->weak_map_id();
  44. auto close_callback = base::AdaptCallbackForRepeating(
  45. base::BindOnce(&MenuViews::OnClosed, weak_factory_.GetWeakPtr(),
  46. window_id, std::move(callback_with_ref)));
  47. menu_runners_[window_id] =
  48. std::make_unique<MenuRunner>(model(), flags, std::move(close_callback));
  49. menu_runners_[window_id]->RunMenuAt(
  50. native_window->widget(), NULL, gfx::Rect(location, gfx::Size()),
  51. views::MenuAnchorPosition::kTopLeft, ui::MENU_SOURCE_MOUSE);
  52. }
  53. void MenuViews::ClosePopupAt(int32_t window_id) {
  54. auto runner = menu_runners_.find(window_id);
  55. if (runner != menu_runners_.end()) {
  56. // Close the runner for the window.
  57. runner->second->Cancel();
  58. } else if (window_id == -1) {
  59. // Or just close all opened runners.
  60. for (auto it = menu_runners_.begin(); it != menu_runners_.end();) {
  61. // The iterator is invalidated after the call.
  62. (it++)->second->Cancel();
  63. }
  64. }
  65. }
  66. void MenuViews::OnClosed(int32_t window_id, base::OnceClosure callback) {
  67. menu_runners_.erase(window_id);
  68. std::move(callback).Run();
  69. }
  70. // static
  71. mate::WrappableBase* Menu::New(mate::Arguments* args) {
  72. return new MenuViews(args->isolate(), args->GetThis());
  73. }
  74. } // namespace api
  75. } // namespace electron