blob: 9990aab79ee64f6956834a552b8a01f187459dac [file] [log] [blame]
[email protected]a87ecb3c2009-08-24 15:46:451// Copyright (c) 2009 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
6#include "views/controls/menu/menu_host_gtk.h"
7
8#include <gdk/gdk.h>
9
10#include "views/controls/menu/menu_controller.h"
11#include "views/controls/menu/menu_host_root_view.h"
12#include "views/controls/menu/menu_item_view.h"
13#include "views/controls/menu/submenu_view.h"
14
15namespace views {
16
17MenuHost::MenuHost(SubmenuView* submenu)
18 : WidgetGtk(WidgetGtk::TYPE_POPUP),
19 closed_(false),
[email protected]40e59f92009-08-26 20:51:0220 submenu_(submenu),
21 did_pointer_grab_(false) {
[email protected]a87ecb3c2009-08-24 15:46:4522 // TODO(sky): make sure this is needed.
23 GdkModifierType current_event_mod;
24 if (gtk_get_current_event_state(&current_event_mod)) {
25 set_mouse_down(
26 (current_event_mod & GDK_BUTTON1_MASK) ||
27 (current_event_mod & GDK_BUTTON2_MASK) ||
28 (current_event_mod & GDK_BUTTON3_MASK) ||
29 (current_event_mod & GDK_BUTTON4_MASK) ||
30 (current_event_mod & GDK_BUTTON5_MASK));
31 }
32}
33
34void MenuHost::Init(gfx::NativeView parent,
35 const gfx::Rect& bounds,
36 View* contents_view,
37 bool do_capture) {
38 WidgetGtk::Init(parent, bounds);
39 SetContentsView(contents_view);
40 // TODO(sky): see if there is some way to show without changing focus.
41 Show();
42 if (do_capture) {
[email protected]40e59f92009-08-26 20:51:0243 // Release the current grab.
44 GtkWidget* current_grab_window = gtk_grab_get_current();
45 if (current_grab_window)
46 gtk_grab_remove(current_grab_window);
47
48 // Make sure all app mouse events are targetted at us only.
[email protected]a87ecb3c2009-08-24 15:46:4549 DoGrab();
[email protected]40e59f92009-08-26 20:51:0250
51 // And do a grab.
52 // NOTE: we do this to ensure we get mouse events from other apps, a grab
53 // done with gtk_grab_add doesn't get events from other apps.
54 GdkGrabStatus grab_status =
55 gdk_pointer_grab(window_contents()->window, FALSE,
56 static_cast<GdkEventMask>(
57 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
58 GDK_POINTER_MOTION_MASK),
59 NULL, NULL, GDK_CURRENT_TIME);
60 did_pointer_grab_ = (grab_status == GDK_GRAB_SUCCESS);
61 DCHECK(did_pointer_grab_);
62 // need keyboard grab.
[email protected]a87ecb3c2009-08-24 15:46:4563#ifdef DEBUG_MENU
64 DLOG(INFO) << "Doing capture";
65#endif
66 }
67}
68
69void MenuHost::Show() {
70 WidgetGtk::Show();
71}
72
73void MenuHost::Hide() {
74 if (closed_) {
75 // We're already closed, nothing to do.
76 // This is invoked twice if the first time just hid us, and the second
77 // time deleted Closed (deleted) us.
78 return;
79 }
80 // The menus are freed separately, and possibly before the window is closed,
81 // remove them so that View doesn't try to access deleted objects.
82 static_cast<MenuHostRootView*>(GetRootView())->suspend_events();
83 GetRootView()->RemoveAllChildViews(false);
[email protected]345dd302009-08-26 20:12:5984 ReleaseGrab();
[email protected]40e59f92009-08-26 20:51:0285 closed_ = true;
[email protected]a87ecb3c2009-08-24 15:46:4586 WidgetGtk::Hide();
87}
88
89void MenuHost::HideWindow() {
90 // Make sure we release capture before hiding.
91 ReleaseGrab();
92 WidgetGtk::Hide();
93}
94
95void MenuHost::ReleaseCapture() {
96 ReleaseGrab();
97}
98
99RootView* MenuHost::CreateRootView() {
100 return new MenuHostRootView(this, submenu_);
101}
102
[email protected]40e59f92009-08-26 20:51:02103gboolean MenuHost::OnGrabBrokeEvent(GtkWidget* widget, GdkEvent* event) {
104 if (!closed_)
[email protected]a87ecb3c2009-08-24 15:46:45105 submenu_->GetMenuItem()->GetMenuController()->Cancel(true);
[email protected]40e59f92009-08-26 20:51:02106 return WidgetGtk::OnGrabBrokeEvent(widget, event);
107}
108
109void MenuHost::OnGrabNotify(GtkWidget* widget, gboolean was_grabbed) {
110 if (!closed_ && (widget != window_contents() || !was_grabbed))
111 submenu_->GetMenuItem()->GetMenuController()->Cancel(true);
112 WidgetGtk::OnGrabNotify(widget, was_grabbed);
[email protected]a87ecb3c2009-08-24 15:46:45113}
114
115// Overriden to return false, we do NOT want to release capture on mouse
116// release.
117bool MenuHost::ReleaseCaptureOnMouseReleased() {
118 return false;
119}
120
[email protected]40e59f92009-08-26 20:51:02121void MenuHost::ReleaseGrab() {
122 WidgetGtk::ReleaseGrab();
123 if (did_pointer_grab_) {
124 did_pointer_grab_ = false;
125 gdk_pointer_ungrab(GDK_CURRENT_TIME);
126 }
127}
128
[email protected]a87ecb3c2009-08-24 15:46:45129} // namespace views