Commit b5a1864e authored by oshima@google.com's avatar oshima@google.com

Send fake event when event_type is set to exit menu so that

nested loop can exit.

BUG=104684
TEST=BrowserTest.CloseWithAppMenuOpen passes on aura build

Review URL: http://codereview.chromium.org/8597010

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@110774 0039d316-1c4b-4281-b951-d872f2087c98
parent 3b73f527
......@@ -413,6 +413,10 @@ bool Desktop::IsMouseButtonDown() const {
return mouse_button_flags_ != 0;
}
void Desktop::PostNativeEvent(const base::NativeEvent& native_event) {
host_->PostNativeEvent(native_event);
}
void Desktop::SetCapture(Window* window) {
if (capture_window_ == window)
return;
......
......@@ -125,6 +125,9 @@ class AURA_EXPORT Desktop : public ui::CompositorDelegate,
// Are any mouse buttons currently down?
bool IsMouseButtonDown() const;
// Posts |native_event| to the platform's event queue.
void PostNativeEvent(const base::NativeEvent& native_event);
// Capture -------------------------------------------------------------------
// Sets capture to the specified window.
......
......@@ -58,6 +58,9 @@ class DesktopHost : public MessageLoop::Dispatcher {
// You should probably call Desktop::last_mouse_location() instead; this
// method can be expensive.
virtual gfx::Point QueryMouseLocation() = 0;
// Posts |native_event| to the platform's event queue.
virtual void PostNativeEvent(const base::NativeEvent& native_event) = 0;
};
} // namespace aura
......
......@@ -240,6 +240,7 @@ class DesktopHostLinux : public DesktopHost {
virtual void SetSize(const gfx::Size& size) OVERRIDE;
virtual void SetCursor(gfx::NativeCursor cursor_type) OVERRIDE;
virtual gfx::Point QueryMouseLocation() OVERRIDE;
virtual void PostNativeEvent(const base::NativeEvent& event) OVERRIDE;
// Returns true if there's an X window manager present... in most cases. Some
// window managers (notably, ion3) don't implement enough of ICCCM for us to
......@@ -481,6 +482,15 @@ gfx::Point DesktopHostLinux::QueryMouseLocation() {
max(0, min(size_.height(), win_y_return)));
}
void DesktopHostLinux::PostNativeEvent(const base::NativeEvent& native_event) {
DCHECK(xwindow_);
DCHECK(xdisplay_);
XEvent xevent = *native_event;
xevent.xany.display = xdisplay_;
xevent.xany.window = xwindow_;
::XPutBackEvent(xdisplay_, &xevent);
}
bool DesktopHostLinux::IsWindowManagerPresent() {
// Per ICCCM 2.8, "Manager Selections", window managers should take ownership
// of WM_Sn selections (where n is a screen number).
......
......@@ -225,6 +225,11 @@ gfx::Point DesktopHostWin::QueryMouseLocation() {
max(0, min(size.height(), static_cast<int>(pt.y))));
}
void DesktopHostWin::PostNativeEvent(const base::NativeEvent& native_event) {
::PostMessage(
hwnd(), native_event.message, native_event.wParam, native_event.lParam);
}
void DesktopHostWin::OnClose() {
// TODO: this obviously shouldn't be here.
MessageLoopForUI::current()->Quit();
......
......@@ -29,6 +29,7 @@ class DesktopHostWin : public DesktopHost, public ui::WindowImpl {
virtual void SetSize(const gfx::Size& size) OVERRIDE;
virtual void SetCursor(gfx::NativeCursor cursor) OVERRIDE;
virtual gfx::Point QueryMouseLocation() OVERRIDE;
virtual void PostNativeEvent(const base::NativeEvent& native_event) OVERRIDE;
private:
BEGIN_MSG_MAP_EX(DesktopHostWin)
......
......@@ -103,6 +103,9 @@ UI_EXPORT float GetTouchAngle(const base::NativeEvent& native_event);
// Gets the force from a native_event. Normalized to be [0, 1]. Default is 0.0.
UI_EXPORT float GetTouchForce(const base::NativeEvent& native_event);
// Creates and returns no-op event.
UI_EXPORT base::NativeEvent CreateNoopEvent();
} // namespace ui
#endif // UI_BASE_EVENTS_H_
......@@ -253,4 +253,12 @@ float GetTouchForce(const base::NativeEvent& native_event) {
return 0.0;
}
base::NativeEvent CreateNoopEvent() {
MSG event;
event.message = WM_USER;
event.wParam = 0;
event.lParam = 0;
return event;
}
} // namespace ui
......@@ -4,6 +4,7 @@
#include "ui/base/events.h"
#include <X11/Xlib.h>
#include <X11/extensions/XInput2.h>
#include "base/logging.h"
......@@ -354,4 +355,14 @@ float GetTouchForce(const base::NativeEvent& native_event) {
return force;
}
base::NativeEvent CreateNoopEvent() {
static XEvent* noop = new XEvent();
noop->xclient.type = ClientMessage;
noop->xclient.display = NULL;
noop->xclient.window = None;
noop->xclient.message_type = 0;
noop->xclient.format = 0;
return noop;
}
} // namespace ui
......@@ -24,11 +24,11 @@
#include "views/widget/root_view.h"
#include "views/widget/widget.h"
#if defined(USE_AURA) && !defined(OS_WIN)
#if defined(USE_AURA)
#include "ui/aura/desktop.h"
#endif
#if defined(OS_LINUX)
#if defined(TOOLKIT_USES_GTK)
#include "ui/base/keycodes/keyboard_code_conversion_gtk.h"
#endif
......@@ -348,7 +348,7 @@ MenuItemView* MenuController::Run(Widget* parent,
*result_mouse_event_flags = result_mouse_event_flags_;
if (exit_type_ == EXIT_OUTERMOST) {
exit_type_ = EXIT_NONE;
SetExitType(EXIT_NONE);
} else {
if (nested_menu && result) {
// We're nested and about to return a value. The caller might enter
......@@ -359,7 +359,7 @@ MenuItemView* MenuController::Run(Widget* parent,
// Set exit_all_, which makes sure all nested loops exit immediately.
if (exit_type_ != EXIT_DESTROYED)
exit_type_ = EXIT_ALL;
SetExitType(EXIT_ALL);
}
}
......@@ -387,7 +387,7 @@ void MenuController::Cancel(ExitType type) {
}
MenuItemView* selected = state_.item;
exit_type_ = type;
SetExitType(type);
SendMouseCaptureLostToActiveView();
......@@ -426,7 +426,7 @@ void MenuController::OnMousePressed(SubmenuView* source,
// We're going to close and we own the mouse capture. We need to repost the
// mouse down, otherwise the window the user clicked on won't get the
// event.
#if defined(OS_WIN)
#if defined(OS_WIN) && !defined(USE_AURA)
RepostEvent(source, event);
// NOTE: not reposting on linux seems fine.
#endif
......@@ -720,7 +720,7 @@ int MenuController::OnPerformDrop(SubmenuView* source,
// Set state such that we exit.
showing_ = false;
exit_type_ = EXIT_ALL;
SetExitType(EXIT_ALL);
// If over an empty menu item, drop occurs on the parent.
if (drop_target->id() == MenuItemView::kEmptyMenuItemViewID)
......@@ -1101,9 +1101,9 @@ void MenuController::Accept(MenuItemView* item, int mouse_event_flags) {
result_ = item;
if (item && !menu_stack_.empty() &&
!item->GetDelegate()->ShouldCloseAllMenusOnExecute(item->GetCommand())) {
exit_type_ = EXIT_OUTERMOST;
SetExitType(EXIT_OUTERMOST);
} else {
exit_type_ = EXIT_ALL;
SetExitType(EXIT_ALL);
}
result_mouse_event_flags_ = mouse_event_flags;
}
......@@ -1782,12 +1782,7 @@ bool MenuController::SelectByChar(char16 character) {
return false;
}
#if defined(OS_WIN)
#if defined(USE_AURA)
void MenuController::RepostEvent(SubmenuView* source,
const MouseEvent& event) {
}
#else
#if defined(OS_WIN) && !defined(USE_AURA)
void MenuController::RepostEvent(SubmenuView* source,
const MouseEvent& event) {
if (!state_.item) {
......@@ -1854,7 +1849,6 @@ void MenuController::RepostEvent(SubmenuView* source,
}
}
}
#endif // !defined(USE_AURA)
#endif // defined(OS_WIN)
void MenuController::SetDropMenuItem(
......@@ -1961,4 +1955,17 @@ void MenuController::SendMouseCaptureLostToActiveView() {
active_view->OnMouseCaptureLost();
}
void MenuController::SetExitType(ExitType type) {
exit_type_ = type;
#if defined(USE_AURA)
// On aura, closing menu may not trigger next native event, which
// is necessary to exit from nested loop (See Dispatch methods).
// Send non-op event so that Dispatch method will always be called.
// crbug.com/104684.
if (exit_type_ == EXIT_ALL || exit_type_ == EXIT_DESTROYED)
aura::Desktop::GetInstance()->PostNativeEvent(ui::CreateNoopEvent());
#endif
}
} // namespace views
......@@ -413,6 +413,9 @@ class VIEWS_EXPORT MenuController : public MessageLoop::Dispatcher {
// sets it to null.
void SendMouseCaptureLostToActiveView();
// Set exit type.
void SetExitType(ExitType type);
// The active instance.
static MenuController* active_instance_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment