1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "views/controls/menu/menu_host_gtk.h"
#include <gdk/gdk.h>
#include "views/controls/menu/menu_controller.h"
#include "views/controls/menu/menu_host_root_view.h"
#include "views/controls/menu/menu_item_view.h"
#include "views/controls/menu/submenu_view.h"
namespace views {
MenuHost::MenuHost(SubmenuView* submenu)
: WidgetGtk(WidgetGtk::TYPE_POPUP),
closed_(false),
submenu_(submenu),
did_pointer_grab_(false) {
GdkModifierType current_event_mod;
if (gtk_get_current_event_state(¤t_event_mod)) {
set_mouse_down(
(current_event_mod & GDK_BUTTON1_MASK) ||
(current_event_mod & GDK_BUTTON2_MASK) ||
(current_event_mod & GDK_BUTTON3_MASK) ||
(current_event_mod & GDK_BUTTON4_MASK) ||
(current_event_mod & GDK_BUTTON5_MASK));
}
}
void MenuHost::Init(gfx::NativeWindow parent,
const gfx::Rect& bounds,
View* contents_view,
bool do_capture) {
WidgetGtk::Init(GTK_WIDGET(parent), bounds);
SetContentsView(contents_view);
// TODO(sky): see if there is some way to show without changing focus.
Show();
if (do_capture) {
// Release the current grab.
GtkWidget* current_grab_window = gtk_grab_get_current();
if (current_grab_window)
gtk_grab_remove(current_grab_window);
// Make sure all app mouse events are targetted at us only.
DoGrab();
// And do a grab.
// NOTE: we do this to ensure we get mouse events from other apps, a grab
// done with gtk_grab_add doesn't get events from other apps.
GdkGrabStatus grab_status =
gdk_pointer_grab(window_contents()->window, FALSE,
static_cast<GdkEventMask>(
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
GDK_POINTER_MOTION_MASK),
NULL, NULL, GDK_CURRENT_TIME);
did_pointer_grab_ = (grab_status == GDK_GRAB_SUCCESS);
DCHECK(did_pointer_grab_);
// need keyboard grab.
#ifdef DEBUG_MENU
DLOG(INFO) << "Doing capture";
#endif
}
}
gfx::NativeWindow MenuHost::GetNativeWindow() {
return GTK_WINDOW(GetNativeView());
}
void MenuHost::Show() {
WidgetGtk::Show();
}
void MenuHost::Hide() {
if (closed_) {
// We're already closed, nothing to do.
// This is invoked twice if the first time just hid us, and the second
// time deleted Closed (deleted) us.
return;
}
// The menus are freed separately, and possibly before the window is closed,
// remove them so that View doesn't try to access deleted objects.
static_cast<MenuHostRootView*>(GetRootView())->suspend_events();
GetRootView()->RemoveAllChildViews(false);
ReleaseGrab();
closed_ = true;
WidgetGtk::Hide();
}
void MenuHost::HideWindow() {
// Make sure we release capture before hiding.
ReleaseGrab();
WidgetGtk::Hide();
}
void MenuHost::ReleaseCapture() {
ReleaseGrab();
}
RootView* MenuHost::CreateRootView() {
return new MenuHostRootView(this, submenu_);
}
gboolean MenuHost::OnGrabBrokeEvent(GtkWidget* widget, GdkEvent* event) {
// Grab breaking only happens when drag and drop starts. So, we don't try
// and ungrab or cancel the menu.
did_pointer_grab_ = false;
return WidgetGtk::OnGrabBrokeEvent(widget, event);
}
// Overriden to return false, we do NOT want to release capture on mouse
// release.
bool MenuHost::ReleaseCaptureOnMouseReleased() {
return false;
}
void MenuHost::ReleaseGrab() {
WidgetGtk::ReleaseGrab();
if (did_pointer_grab_) {
did_pointer_grab_ = false;
gdk_pointer_ungrab(GDK_CURRENT_TIME);
}
}
} // namespace views
|