From 23ebfa29559c943bfc8b5e544a4e8568c8ec8f0c Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Fri, 14 Mar 2014 21:44:09 +0800 Subject: [PATCH] gtk: Enabling setting menubar for window. --- browser/api/atom_api_menu_gtk.cc | 14 +++++++++++++- browser/native_window_gtk.cc | 10 +++++++++- browser/native_window_gtk.h | 11 ++++++++++- browser/ui/gtk/menu_gtk.cc | 7 ++++++- browser/ui/gtk/menu_gtk.h | 3 +++ 5 files changed, 41 insertions(+), 4 deletions(-) diff --git a/browser/api/atom_api_menu_gtk.cc b/browser/api/atom_api_menu_gtk.cc index cc8de662d5..a28e9217b7 100644 --- a/browser/api/atom_api_menu_gtk.cc +++ b/browser/api/atom_api_menu_gtk.cc @@ -4,11 +4,14 @@ #include "browser/api/atom_api_menu_gtk.h" -#include "browser/native_window.h" +#include "browser/native_window_gtk.h" +#include "common/v8/native_type_conversions.h" #include "content/public/browser/render_widget_host_view.h" #include "ui/gfx/point.h" #include "ui/gfx/screen.h" +#include "common/v8/node_common.h" + namespace atom { namespace api { @@ -40,6 +43,15 @@ void MenuGtk::Popup(NativeWindow* native_window) { // static void Menu::AttachToWindow(const v8::FunctionCallbackInfo& args) { + Menu* self = ObjectWrap::Unwrap(args.This()); + if (self == NULL) + return node::ThrowError("Menu is already destroyed"); + + NativeWindow* native_window; + if (!FromV8Arguments(args, &native_window)) + return node::ThrowTypeError("Bad argument"); + + static_cast(native_window)->SetMenu(self->model_.get()); } // static diff --git a/browser/native_window_gtk.cc b/browser/native_window_gtk.cc index 8b9ecc217c..b686ceb317 100644 --- a/browser/native_window_gtk.cc +++ b/browser/native_window_gtk.cc @@ -31,9 +31,11 @@ NativeWindowGtk::NativeWindowGtk(content::WebContents* web_contents, base::DictionaryValue* options) : NativeWindow(web_contents, options), window_(GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL))), + vbox_(gtk_vbox_new(FALSE, 0)), state_(GDK_WINDOW_STATE_WITHDRAWN), is_always_on_top_(false) { - gtk_container_add(GTK_CONTAINER(window_), + gtk_container_add(GTK_CONTAINER(window_), vbox_); + gtk_container_add(GTK_CONTAINER(vbox_), GetWebContents()->GetView()->GetNativeView()); int width = 800, height = 600; @@ -254,6 +256,12 @@ gfx::NativeWindow NativeWindowGtk::GetNativeWindow() { return window_; } +void NativeWindowGtk::SetMenu(ui::MenuModel* menu_model) { + menu_.reset(new ::MenuGtk(this, menu_model, true)); + gtk_box_pack_start(GTK_BOX(vbox_), menu_->widget(), FALSE, FALSE, 0); + gtk_box_reorder_child(GTK_BOX(vbox_), menu_->widget(), 0); +} + void NativeWindowGtk::UpdateDraggableRegions( const std::vector& regions) { // Draggable region is not supported for non-frameless window. diff --git a/browser/native_window_gtk.h b/browser/native_window_gtk.h index 6fee4fc661..209cba9695 100644 --- a/browser/native_window_gtk.h +++ b/browser/native_window_gtk.h @@ -8,13 +8,15 @@ #include #include "browser/native_window.h" +#include "browser/ui/gtk/menu_gtk.h" #include "third_party/skia/include/core/SkRegion.h" #include "ui/base/gtk/gtk_signal.h" #include "ui/gfx/size.h" namespace atom { -class NativeWindowGtk : public NativeWindow { +class NativeWindowGtk : public NativeWindow, + public MenuGtk::Delegate { public: explicit NativeWindowGtk(content::WebContents* web_contents, base::DictionaryValue* options); @@ -56,6 +58,9 @@ class NativeWindowGtk : public NativeWindow { virtual bool HasModalDialog() OVERRIDE; virtual gfx::NativeWindow GetNativeWindow() OVERRIDE; + // Set the native window menu. + void SetMenu(ui::MenuModel* menu_model); + protected: virtual void UpdateDraggableRegions( const std::vector& regions) OVERRIDE; @@ -83,6 +88,7 @@ class NativeWindowGtk : public NativeWindow { GdkEventButton*); GtkWindow* window_; + GtkWidget* vbox_; GdkWindowState state_; bool is_always_on_top_; @@ -101,6 +107,9 @@ class NativeWindowGtk : public NativeWindow { // custom frame border. We set it to NULL if we want the default cursor. GdkCursor* frame_cursor_; + // The window menu. + scoped_ptr menu_; + DISALLOW_COPY_AND_ASSIGN(NativeWindowGtk); }; diff --git a/browser/ui/gtk/menu_gtk.cc b/browser/ui/gtk/menu_gtk.cc index ebcde0d1fa..50f19fb964 100644 --- a/browser/ui/gtk/menu_gtk.cc +++ b/browser/ui/gtk/menu_gtk.cc @@ -182,6 +182,7 @@ MenuGtk::MenuGtk(MenuGtk::Delegate* delegate, bool is_menubar) : delegate_(delegate), model_(model), + is_menubar_(is_menubar), dummy_accel_group_(gtk_accel_group_new()), menu_(is_menubar ? gtk_menu_bar_new() : gtk_custom_menu_new()), weak_factory_(this) { @@ -331,7 +332,8 @@ void MenuGtk::PopupAsFromKeyEvent(GtkWidget* widget) { } void MenuGtk::Cancel() { - gtk_menu_popdown(GTK_MENU(menu_)); + if (!is_menubar_) + gtk_menu_popdown(GTK_MENU(menu_)); } void MenuGtk::UpdateMenu() { @@ -710,6 +712,9 @@ void MenuGtk::OnSubMenuShow(GtkWidget* submenu) { } void MenuGtk::OnSubMenuHidden(GtkWidget* submenu) { + if (is_menubar_) + return; + // Increase the reference count of the old submenu, and schedule it to be // deleted later. We get this hide notification before we've processed menu // activations, so if we were to delete the submenu now, we might lose the diff --git a/browser/ui/gtk/menu_gtk.h b/browser/ui/gtk/menu_gtk.h index 74bc923adc..70ea2bd33c 100644 --- a/browser/ui/gtk/menu_gtk.h +++ b/browser/ui/gtk/menu_gtk.h @@ -198,6 +198,9 @@ class MenuGtk { // menu (overriding the delegate as a controller). ui::MenuModel* model_; + // Whether this is a menu bar. + bool is_menubar_; + // For some menu items, we want to show the accelerator, but not actually // explicitly handle it. To this end we connect those menu items' accelerators // to this group, but don't attach this group to any top level window.