summaryrefslogtreecommitdiffstats
path: root/views
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-26 15:35:13 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-26 15:35:13 +0000
commite959f0b97dba7228c76b7722cf4227fdf6416524 (patch)
tree7af84f30c8a3560c19e17f7cb1dc220e1e4fa0be /views
parentbf6a46bed6770a7041c222e4505135bd30701576 (diff)
downloadchromium_src-e959f0b97dba7228c76b7722cf4227fdf6416524.zip
chromium_src-e959f0b97dba7228c76b7722cf4227fdf6416524.tar.gz
chromium_src-e959f0b97dba7228c76b7722cf4227fdf6416524.tar.bz2
Makes it so that when a folder is open on the bookmark bar and the
mouse moves over another folder, the menu for that folder is shown. BUG=355 TEST=thorougly test all possible permutations of bookmark menus you can think of, including drag and drop to the menus. Review URL: http://codereview.chromium.org/328012 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@30049 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views')
-rw-r--r--views/controls/button/menu_button.cc1
-rw-r--r--views/controls/menu/menu_controller.cc117
-rw-r--r--views/controls/menu/menu_controller.h11
-rw-r--r--views/controls/menu/menu_delegate.h16
-rw-r--r--views/controls/menu/menu_host_gtk.cc69
-rw-r--r--views/controls/menu/menu_host_gtk.h1
-rw-r--r--views/controls/menu/menu_host_win.cc19
-rw-r--r--views/controls/menu/menu_host_win.h1
-rw-r--r--views/controls/menu/menu_item_view.cc25
-rw-r--r--views/controls/menu/menu_item_view.h2
-rw-r--r--views/controls/menu/submenu_view.cc2
-rw-r--r--views/screen.h3
-rw-r--r--views/screen_gtk.cc14
-rw-r--r--views/screen_win.cc5
14 files changed, 202 insertions, 84 deletions
diff --git a/views/controls/button/menu_button.cc b/views/controls/button/menu_button.cc
index 5dc59cb..e457304 100644
--- a/views/controls/button/menu_button.cc
+++ b/views/controls/button/menu_button.cc
@@ -47,7 +47,6 @@ MenuButton::MenuButton(ButtonListener* listener,
bool show_menu_marker)
: TextButton(listener, text),
menu_visible_(false),
- menu_closed_time_(),
menu_delegate_(menu_delegate),
show_menu_marker_(show_menu_marker) {
if (kMenuMarker == NULL) {
diff --git a/views/controls/menu/menu_controller.cc b/views/controls/menu/menu_controller.cc
index 6175e62..4388d91 100644
--- a/views/controls/menu/menu_controller.cc
+++ b/views/controls/menu/menu_controller.cc
@@ -9,6 +9,7 @@
#include "app/os_exchange_data.h"
#include "base/keyboard_codes.h"
#include "base/time.h"
+#include "views/controls/button/menu_button.h"
#include "views/controls/menu/menu_scroll_view_container.h"
#include "views/controls/menu/submenu_view.h"
#include "views/drag_utils.h"
@@ -143,6 +144,7 @@ static int nested_depth = 0;
#endif
MenuItemView* MenuController::Run(gfx::NativeWindow parent,
+ MenuButton* button,
MenuItemView* root,
const gfx::Rect& bounds,
MenuItemView::AnchorPosition position,
@@ -168,19 +170,9 @@ MenuItemView* MenuController::Run(gfx::NativeWindow parent,
// Reset current state.
pending_state_ = State();
state_ = State();
- pending_state_.initial_bounds = bounds;
- if (bounds.height() > 1) {
- // Inset the bounds slightly, otherwise drag coordinates don't line up
- // nicely and menus close prematurely.
- pending_state_.initial_bounds.Inset(0, 1);
- }
- pending_state_.anchor = position;
- owner_ = parent;
+ UpdateInitialLocation(bounds, position);
- // Calculate the bounds of the monitor we'll show menus on. Do this once to
- // avoid repeated system queries for the info.
- pending_state_.monitor_bounds = Screen::GetMonitorAreaNearestPoint(
- bounds.origin());
+ owner_ = parent;
// Set the selection, which opens the initial menu.
SetSelection(root, true, true);
@@ -190,6 +182,8 @@ MenuItemView* MenuController::Run(gfx::NativeWindow parent,
// notification when the drag has finished.
StartCancelAllTimer();
return NULL;
+ } else if (button) {
+ menu_button_ = button;
}
#ifdef DEBUG_MENU
@@ -245,6 +239,11 @@ MenuItemView* MenuController::Run(gfx::NativeWindow parent,
exit_all_ = true;
}
+ if (menu_button_) {
+ menu_button_->SetState(CustomButton::BS_NORMAL);
+ menu_button_->SchedulePaint();
+ }
+
return result;
}
@@ -316,8 +315,7 @@ void MenuController::OnMousePressed(SubmenuView* source,
if (!blocking_run_)
return;
- MenuPart part =
- GetMenuPartByScreenCoordinate(source, event.x(), event.y());
+ MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y());
if (part.is_scroll())
return; // Ignore presses on scroll buttons.
@@ -362,8 +360,7 @@ void MenuController::OnMouseDragged(SubmenuView* source,
#ifdef DEBUG_MENU
DLOG(INFO) << "OnMouseDragged source=" << source;
#endif
- MenuPart part =
- GetMenuPartByScreenCoordinate(source, event.x(), event.y());
+ MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y());
UpdateScrolling(part);
if (!blocking_run_)
@@ -409,6 +406,8 @@ void MenuController::OnMouseDragged(SubmenuView* source,
if (!part.menu)
part.menu = source->GetMenuItem();
SetSelection(part.menu ? part.menu : state_.item, true, false);
+ } else if (part.type == MenuPart::NONE) {
+ ShowSiblingMenu(source, event);
}
}
@@ -423,8 +422,7 @@ void MenuController::OnMouseReleased(SubmenuView* source,
DCHECK(state_.item);
possible_drag_ = false;
DCHECK(blocking_run_);
- MenuPart part =
- GetMenuPartByScreenCoordinate(source, event.x(), event.y());
+ MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y());
if (event.IsRightMouseButton() && (part.type == MenuPart::MENU_ITEM &&
part.menu)) {
// Set the selection immediately, making sure the submenu is only open
@@ -460,14 +458,16 @@ void MenuController::OnMouseMoved(SubmenuView* source,
if (showing_submenu_)
return;
- MenuPart part =
- GetMenuPartByScreenCoordinate(source, event.x(), event.y());
+ MenuPart part = GetMenuPartByScreenCoordinate(source, event.x(), event.y());
UpdateScrolling(part);
if (!blocking_run_)
return;
+ if (part.type == MenuPart::NONE && ShowSiblingMenu(source, event))
+ return;
+
if (part.type == MenuPart::MENU_ITEM && part.menu) {
SetSelection(part.menu, true, false);
} else if (!part.is_scroll() && pending_state_.item &&
@@ -803,7 +803,8 @@ MenuController::MenuController(bool blocking)
owner_(NULL),
possible_drag_(false),
valid_drop_coordinates_(false),
- showing_submenu_(false) {
+ showing_submenu_(false),
+ menu_button_(NULL) {
#ifdef DEBUG_MENU
instance_count++;
DLOG(INFO) << "created MC, count=" << instance_count;
@@ -820,6 +821,23 @@ MenuController::~MenuController() {
#endif
}
+void MenuController::UpdateInitialLocation(
+ const gfx::Rect& bounds,
+ MenuItemView::AnchorPosition position) {
+ pending_state_.initial_bounds = bounds;
+ if (bounds.height() > 1) {
+ // Inset the bounds slightly, otherwise drag coordinates don't line up
+ // nicely and menus close prematurely.
+ pending_state_.initial_bounds.Inset(0, 1);
+ }
+ pending_state_.anchor = position;
+
+ // Calculate the bounds of the monitor we'll show menus on. Do this once to
+ // avoid repeated system queries for the info.
+ pending_state_.monitor_bounds = Screen::GetMonitorAreaNearestPoint(
+ bounds.origin());
+}
+
void MenuController::Accept(MenuItemView* item, int mouse_event_flags) {
DCHECK(IsBlockingRun());
result_ = item;
@@ -827,6 +845,63 @@ void MenuController::Accept(MenuItemView* item, int mouse_event_flags) {
result_mouse_event_flags_ = mouse_event_flags;
}
+bool MenuController::ShowSiblingMenu(SubmenuView* source, const MouseEvent& e) {
+ if (!menu_stack_.empty() || !menu_button_)
+ return false;
+
+ View* source_view = source->GetScrollViewContainer();
+ if (e.x() >= 0 && e.x() < source_view->width() && e.y() >= 0 &&
+ e.y() < source_view->height()) {
+ // The mouse is over the menu, no need to continue.
+ return false;
+ }
+
+ gfx::NativeWindow window_under_mouse = Screen::GetWindowAtCursorScreenPoint();
+ if (window_under_mouse != owner_)
+ return false;
+
+ // The user moved the mouse outside the menu and over the owning window. See
+ // if there is a sibling menu we should show.
+ gfx::Point screen_point(e.location());
+ View::ConvertPointToScreen(source_view, &screen_point);
+ MenuItemView::AnchorPosition anchor;
+ bool has_mnemonics;
+ MenuButton* button = NULL;
+ MenuItemView* alt_menu = source->GetMenuItem()->GetDelegate()->
+ GetSiblingMenu(source->GetMenuItem()->GetRootMenuItem(),
+ screen_point, &anchor, &has_mnemonics, &button);
+ if (!alt_menu || alt_menu == state_.item)
+ return false;
+
+ if (!button) {
+ // If the delegate returns a menu, they must also return a button.
+ NOTREACHED();
+ return false;
+ }
+
+ // There is a sibling menu, update the button state, hide the current menu
+ // and show the new one.
+ menu_button_->SetState(CustomButton::BS_NORMAL);
+ menu_button_->SchedulePaint();
+ menu_button_ = button;
+ menu_button_->SetState(CustomButton::BS_PUSHED);
+ menu_button_->SchedulePaint();
+
+ // Need to reset capture when we show the menu again, otherwise we aren't
+ // going to get any events.
+ did_capture_ = false;
+ gfx::Point screen_menu_loc;
+ View::ConvertPointToScreen(button, &screen_menu_loc);
+ // Subtract 1 from the height to make the popup flush with the button border.
+ UpdateInitialLocation(gfx::Rect(screen_menu_loc.x(), screen_menu_loc.y(),
+ button->width(), button->height() - 1),
+ anchor);
+ alt_menu->PrepareForRun(has_mnemonics);
+ alt_menu->controller_ = this;
+ SetSelection(alt_menu, true, true);
+ return true;
+}
+
void MenuController::CloseAllNestedMenus() {
for (std::list<State>::iterator i = menu_stack_.begin();
i != menu_stack_.end(); ++i) {
diff --git a/views/controls/menu/menu_controller.h b/views/controls/menu/menu_controller.h
index bc57036..2ef1bb7 100644
--- a/views/controls/menu/menu_controller.h
+++ b/views/controls/menu/menu_controller.h
@@ -22,6 +22,7 @@ class OSExchangeData;
namespace views {
class DropTargetEvent;
+class MenuButton;
class MenuHostRootView;
class MouseEvent;
class SubmenuView;
@@ -44,6 +45,7 @@ class MenuController : public MessageLoopForUI::Dispatcher {
// block, the selected item is returned. If the menu does not block this
// returns NULL immediately.
MenuItemView* Run(gfx::NativeWindow parent,
+ MenuButton* button,
MenuItemView* root,
const gfx::Rect& bounds,
MenuItemView::AnchorPosition position,
@@ -182,10 +184,15 @@ class MenuController : public MessageLoopForUI::Dispatcher {
~MenuController();
+ void UpdateInitialLocation(const gfx::Rect& bounds,
+ MenuItemView::AnchorPosition position);
+
// Invoked when the user accepts the selected item. This is only used
// when blocking. This schedules the loop to quit.
void Accept(MenuItemView* item, int mouse_event_flags);
+ bool ShowSiblingMenu(SubmenuView* source, const MouseEvent& e);
+
// Closes all menus, including any menus of nested invocations of Run.
void CloseAllNestedMenus();
@@ -330,7 +337,7 @@ class MenuController : public MessageLoopForUI::Dispatcher {
MenuItemView* result_;
// The mouse event flags when the user clicked on a menu. Is 0 if the
- // user did not use the mousee to select the menu.
+ // user did not use the mouse to select the menu.
int result_mouse_event_flags_;
// If not empty, it means we're nested. When Run is invoked from within
@@ -376,6 +383,8 @@ class MenuController : public MessageLoopForUI::Dispatcher {
// underway.
scoped_ptr<MenuScrollTask> scroll_task_;
+ MenuButton* menu_button_;
+
DISALLOW_COPY_AND_ASSIGN(MenuController);
};
diff --git a/views/controls/menu/menu_delegate.h b/views/controls/menu/menu_delegate.h
index ec66a4f..2f7cd66 100644
--- a/views/controls/menu/menu_delegate.h
+++ b/views/controls/menu/menu_delegate.h
@@ -12,12 +12,13 @@
#include "app/os_exchange_data.h"
#include "base/logging.h"
#include "views/controls/menu/controller.h"
+#include "views/controls/menu/menu_item_view.h"
#include "views/event.h"
namespace views {
class DropTargetEvent;
-class MenuItemView;
+class MenuButton;
// MenuDelegate --------------------------------------------------------------
@@ -180,6 +181,19 @@ class MenuDelegate : Controller {
// Notification that the user has highlighted the specified item.
virtual void SelectionChanged(MenuItemView* menu) {
}
+
+ // If the user drags the mouse outside the bounds of the menu the delegate
+ // is queried for a sibling menu to show. If this returns non-null the
+ // current menu is hidden, and the menu returned from this method is shown.
+ //
+ // The delegate owns the returned menu, not the controller.
+ virtual MenuItemView* GetSiblingMenu(MenuItemView* menu,
+ const gfx::Point& screen_point,
+ MenuItemView::AnchorPosition* anchor,
+ bool* has_mnemonics,
+ MenuButton** button) {
+ return NULL;
+ }
};
} // namespace views
diff --git a/views/controls/menu/menu_host_gtk.cc b/views/controls/menu/menu_host_gtk.cc
index 11033c4..38945e5 100644
--- a/views/controls/menu/menu_host_gtk.cc
+++ b/views/controls/menu/menu_host_gtk.cc
@@ -19,14 +19,13 @@ MenuHost::MenuHost(SubmenuView* submenu)
closed_(false),
submenu_(submenu),
did_pointer_grab_(false) {
- GdkModifierType current_event_mod;
- if (gtk_get_current_event_state(&current_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));
+ GdkEvent* event = gtk_get_current_event();
+ if (event) {
+ if (event->type == GDK_BUTTON_PRESS || event->type == GDK_2BUTTON_PRESS ||
+ event->type == GDK_3BUTTON_PRESS) {
+ set_mouse_down(true);
+ }
+ gdk_event_free(event);
}
}
@@ -36,33 +35,9 @@ void MenuHost::Init(gfx::NativeWindow parent,
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
- }
+ if (do_capture)
+ DoCapture();
}
gfx::NativeWindow MenuHost::GetNativeWindow() {
@@ -95,6 +70,32 @@ void MenuHost::HideWindow() {
WidgetGtk::Hide();
}
+void MenuHost::DoCapture() {
+ // 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
+}
+
void MenuHost::ReleaseCapture() {
ReleaseGrab();
}
diff --git a/views/controls/menu/menu_host_gtk.h b/views/controls/menu/menu_host_gtk.h
index 8e69ce8..4ae1b77 100644
--- a/views/controls/menu/menu_host_gtk.h
+++ b/views/controls/menu/menu_host_gtk.h
@@ -27,6 +27,7 @@ class MenuHost : public WidgetGtk {
void Show();
virtual void Hide();
virtual void HideWindow();
+ void DoCapture();
void ReleaseCapture();
protected:
diff --git a/views/controls/menu/menu_host_win.cc b/views/controls/menu/menu_host_win.cc
index d6fd655..f2c2c2c 100644
--- a/views/controls/menu/menu_host_win.cc
+++ b/views/controls/menu/menu_host_win.cc
@@ -37,14 +37,8 @@ void MenuHost::Init(HWND parent,
WidgetWin::Init(parent, bounds);
SetContentsView(contents_view);
Show();
- owns_capture_ = do_capture;
- if (do_capture) {
- SetCapture();
- has_capture_ = true;
-#ifdef DEBUG_MENU
- DLOG(INFO) << "Doing capture";
-#endif
- }
+ if (do_capture)
+ DoCapture();
}
void MenuHost::Show() {
@@ -82,6 +76,15 @@ void MenuHost::OnCaptureChanged(HWND hwnd) {
#endif
}
+void MenuHost::DoCapture() {
+ owns_capture_ = true;
+ SetCapture();
+ has_capture_ = true;
+#ifdef DEBUG_MENU
+ DLOG(INFO) << "Doing capture";
+#endif
+}
+
void MenuHost::ReleaseCapture() {
if (owns_capture_) {
#ifdef DEBUG_MENU
diff --git a/views/controls/menu/menu_host_win.h b/views/controls/menu/menu_host_win.h
index 6e645d2..ec5d060 100644
--- a/views/controls/menu/menu_host_win.h
+++ b/views/controls/menu/menu_host_win.h
@@ -28,6 +28,7 @@ class MenuHost : public WidgetWin {
virtual void Hide();
virtual void HideWindow();
virtual void OnCaptureChanged(HWND hwnd);
+ void DoCapture();
void ReleaseCapture();
protected:
diff --git a/views/controls/menu/menu_item_view.cc b/views/controls/menu/menu_item_view.cc
index 4d5b3ae..2734788 100644
--- a/views/controls/menu/menu_item_view.cc
+++ b/views/controls/menu/menu_item_view.cc
@@ -66,23 +66,15 @@ MenuItemView::MenuItemView(MenuDelegate* delegate) {
}
MenuItemView::~MenuItemView() {
- if (controller_) {
- // We're currently showing.
-
- // We can't delete ourselves while we're blocking.
- DCHECK(!controller_->IsBlockingRun());
-
- // Invoking Cancel is going to call us back and notify the delegate.
- // Notifying the delegate from the destructor can be problematic. To avoid
- // this the delegate is set to NULL.
- delegate_ = NULL;
-
- controller_->Cancel(true);
- }
+ // TODO(sky): ownership is bit wrong now. In particular if a nested message
+ // loop is running deletion can't be done, otherwise the stack gets
+ // thoroughly screwed. The destructor should be made private, and
+ // MenuController should be the only place handling deletion of the menu.
delete submenu_;
}
void MenuItemView::RunMenuAt(gfx::NativeWindow parent,
+ MenuButton* button,
const gfx::Rect& bounds,
AnchorPosition anchor,
bool has_mnemonics) {
@@ -115,7 +107,7 @@ void MenuItemView::RunMenuAt(gfx::NativeWindow parent,
// Run the loop.
MenuItemView* result =
- controller->Run(parent, this, bounds, anchor, &mouse_event_flags);
+ controller->Run(parent, button, this, bounds, anchor, &mouse_event_flags);
RemoveEmptyMenus();
@@ -151,7 +143,7 @@ void MenuItemView::RunMenuForDropAt(gfx::NativeWindow parent,
// Set the instance, that way it can be canceled by another menu.
MenuController::SetActiveInstance(controller_);
- controller_->Run(parent, this, bounds, anchor, NULL);
+ controller_->Run(parent, NULL, this, bounds, anchor, NULL);
}
void MenuItemView::Cancel() {
@@ -337,9 +329,6 @@ void MenuItemView::PrepareForRun(bool has_mnemonics) {
// Currently we only support showing the root.
DCHECK(!parent_menu_item_);
- // Don't invoke run from within run on the same menu.
- DCHECK(!controller_);
-
// Force us to have a submenu.
CreateSubmenu();
diff --git a/views/controls/menu/menu_item_view.h b/views/controls/menu/menu_item_view.h
index ecb3b78..a85e265 100644
--- a/views/controls/menu/menu_item_view.h
+++ b/views/controls/menu/menu_item_view.h
@@ -10,6 +10,7 @@
namespace views {
+class MenuButton;
class MenuController;
class MenuDelegate;
class SubmenuView;
@@ -82,6 +83,7 @@ class MenuItemView : public View {
// whether the items have mnemonics. Mnemonics are identified by way of the
// character following the '&'.
void RunMenuAt(gfx::NativeWindow parent,
+ MenuButton* button,
const gfx::Rect& bounds,
AnchorPosition anchor,
bool has_mnemonics);
diff --git a/views/controls/menu/submenu_view.cc b/views/controls/menu/submenu_view.cc
index d08de6f..3b315ef 100644
--- a/views/controls/menu/submenu_view.cc
+++ b/views/controls/menu/submenu_view.cc
@@ -221,6 +221,8 @@ void SubmenuView::ShowAt(gfx::NativeWindow parent,
bool do_capture) {
if (host_) {
host_->Show();
+ if (do_capture)
+ host_->DoCapture();
return;
}
diff --git a/views/screen.h b/views/screen.h
index f7c023c..f95b368 100644
--- a/views/screen.h
+++ b/views/screen.h
@@ -27,6 +27,9 @@ class Screen {
// Returns the monitor area (not the work area, but the complete bounds) of
// the monitor nearest the specified point.
static gfx::Rect GetMonitorAreaNearestPoint(const gfx::Point& point);
+
+ // Returns the window under the cursor.
+ static gfx::NativeWindow GetWindowAtCursorScreenPoint();
};
} // namespace views
diff --git a/views/screen_gtk.cc b/views/screen_gtk.cc
index 9302853..a0daa19 100644
--- a/views/screen_gtk.cc
+++ b/views/screen_gtk.cc
@@ -58,5 +58,19 @@ gfx::Rect Screen::GetMonitorAreaNearestPoint(const gfx::Point& point) {
return gfx::Rect(bounds);
}
+gfx::NativeWindow Screen::GetWindowAtCursorScreenPoint() {
+ GdkWindow* window = gdk_window_at_pointer(NULL, NULL);
+ if (!window)
+ return NULL;
+
+ gpointer data = NULL;
+ gdk_window_get_user_data(window, &data);
+ GtkWidget* widget = reinterpret_cast<GtkWidget*>(data);
+ if (!widget)
+ return NULL;
+ widget = gtk_widget_get_toplevel(widget);
+ return GTK_IS_WINDOW(widget) ? GTK_WINDOW(widget) : NULL;
+}
+
} // namespace
diff --git a/views/screen_win.cc b/views/screen_win.cc
index 82e95e6..4ddb7c1 100644
--- a/views/screen_win.cc
+++ b/views/screen_win.cc
@@ -46,5 +46,10 @@ gfx::Rect Screen::GetMonitorAreaNearestPoint(const gfx::Point& point) {
return gfx::Rect(mi.rcMonitor);
}
+gfx::NativeWindow Screen::GetWindowAtCursorScreenPoint() {
+ POINT location;
+ return GetCursorPos(&location) ? WindowFromPoint(location) : NULL;
+}
+
} // namespace