Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5475)

Unified Diff: chrome/browser/chromeos/login/screen_locker.cc

Issue 5043002: A workaround to close currently opened menu. Send escape key if screen locker fails to grab input. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: use grab_server Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/chromeos/login/screen_locker.cc
diff --git a/chrome/browser/chromeos/login/screen_locker.cc b/chrome/browser/chromeos/login/screen_locker.cc
index 2d8ccd08ea5d0ed9f4e6899a2e923814298f6266..f0e4005bf7334e5ae2ea6c96335877195021be71 100644
--- a/chrome/browser/chromeos/login/screen_locker.cc
+++ b/chrome/browser/chromeos/login/screen_locker.cc
@@ -4,11 +4,15 @@
#include "chrome/browser/chromeos/login/screen_locker.h"
+#include <gdk/gdkx.h>
#include <string>
#include <vector>
+#include <X11/extensions/XTest.h>
+#include <X11/keysym.h>
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
+#include "app/x11_util.h"
#include "base/command_line.h"
#include "base/metrics/histogram.h"
#include "base/message_loop.h"
@@ -274,12 +278,13 @@ class GrabWidget : public views::WidgetGtk {
views::WidgetGtk::Show();
}
- void ClearGrab() {
+ void ClearGtkGrab() {
GtkWidget* current_grab_window;
- // Grab gtk input first so that the menu holding grab will close itself.
+ // Grab gtk input first so that the menu holding gtk grab will
+ // close itself.
gtk_grab_add(window_contents());
- // Make sure there is no grab widget so that gtk simply propagates
+ // Make sure there is no gtk grab widget so that gtk simply propagates
// an event. This is necessary to allow message bubble and password
// field, button to process events simultaneously. GTK
// maintains grab widgets in a linked-list, so we need to remove
@@ -298,6 +303,11 @@ class GrabWidget : public views::WidgetGtk {
// grab and the retry count is within a limit, or fails with CHECK.
void TryGrabAllInputs();
+ // This method tries to steal pointer/keyboard grab from other
+ // client by sending events that will hopefullly close menu or window
Daniel Erat 2010/11/17 01:24:23 nit: s/menu or window/menus or windows/
oshima 2010/11/17 18:15:38 Done.
+ // that have the grab.
+ void TryUngrabOtherClients();
+
private:
virtual void HandleGrabBroke() {
// Input should never be stolen from ScreenLocker once it's
@@ -322,12 +332,13 @@ class GrabWidget : public views::WidgetGtk {
};
void GrabWidget::TryGrabAllInputs() {
- ClearGrab();
-
if (kbd_grab_status_ != GDK_GRAB_SUCCESS) {
kbd_grab_status_ = gdk_keyboard_grab(window_contents()->window, FALSE,
GDK_CURRENT_TIME);
}
+ // Grab x server so that we can atomically grab and take
+ // action when grab fails.
+ gdk_x11_grab_server();
Daniel Erat 2010/11/17 01:24:23 Do you mean for this to appear before the call to
oshima 2010/11/17 18:15:38 Doh, yes, that's what I meant.
if (mouse_grab_status_ != GDK_GRAB_SUCCESS) {
mouse_grab_status_ =
gdk_pointer_grab(window_contents()->window,
@@ -345,6 +356,7 @@ void GrabWidget::TryGrabAllInputs() {
LOG(WARNING) << "Failed to grab inputs. Trying again in "
<< kRetryGrabIntervalMs << " ms: kbd="
<< kbd_grab_status_ << ", mouse=" << mouse_grab_status_;
+ TryUngrabOtherClients();
MessageLoop::current()->PostDelayedTask(
FROM_HERE,
task_factory_.NewRunnableMethod(&GrabWidget::TryGrabAllInputs),
@@ -357,6 +369,55 @@ void GrabWidget::TryGrabAllInputs() {
DVLOG(1) << "Grab Success";
screen_locker_->OnGrabInputs();
}
+ gdk_x11_ungrab_server();
Daniel Erat 2010/11/17 01:24:23 Server grabs block all other clients from doing an
oshima 2010/11/17 18:15:38 Done.
+}
+
+void GrabWidget::TryUngrabOtherClients() {
+#if !defined(NDEBUG)
+ {
+ int event_base, error_base;
+ int major, minor;
+ // Make sure we have XTest extension.
+ DCHECK(XTestQueryExtension(x11_util::GetXDisplay(),
+ &event_base, &error_base,
+ &major, &minor));
+ }
+#endif
+
+ // The following code is an attempt to grab inputs by closing
+ // supposedly opened menu. This happens when a plugin has a menu
+ // opened.
+ if (mouse_grab_status_ == GDK_GRAB_ALREADY_GRABBED ||
+ mouse_grab_status_ == GDK_GRAB_FROZEN) {
+ // Successfully grabbed the keyboard, but pointer is still
+ // grabbed by other client. Another attempt to close supposedly
+ // opened menu by emulating keypress at the left top corner.
+ Display* display = x11_util::GetXDisplay();
+ Window root, child;
+ int root_x, root_y, win_x, winy;
+ unsigned int mask;
+ XQueryPointer(display,
+ x11_util::GetX11WindowFromGtkWidget(window_contents()),
+ &root, &child, &root_x, &root_y,
+ &win_x, &winy, &mask);
+ XTestFakeMotionEvent(display, -1, -10000, -10000, CurrentTime);
+ XTestFakeButtonEvent(display, 1, True, CurrentTime);
+ XTestFakeButtonEvent(display, 1, False, CurrentTime);
+ // Move the pointer back.
+ XTestFakeMotionEvent(display, -1, root_x, root_y, CurrentTime);
+ XFlush(display);
+ } else if (kbd_grab_status_ == GDK_GRAB_ALREADY_GRABBED ||
+ kbd_grab_status_ == GDK_GRAB_FROZEN) {
+ // Successfully grabbed the pointer, but keyboard is still grabbed
+ // by other client. Another attempt to close supposedly opened
+ // menu by emulating escape key. Such situation must be very
+ // rare, but handling this just in case
+ Display* display = x11_util::GetXDisplay();
+ KeyCode escape = XKeysymToKeycode(display, XK_Escape);
+ XTestFakeKeyEvent(display, escape, True, CurrentTime);
+ XTestFakeKeyEvent(display, escape, False, CurrentTime);
+ XFlush(display);
+ }
}
// BackgroundView for ScreenLocker, which layouts a lock widget in
@@ -612,12 +673,16 @@ void ScreenLocker::Init() {
lock_window_->SetContentsView(background_view_);
lock_window_->Show();
+ cast_lock_widget->ClearGtkGrab();
+
+ // Call this after lock_window_->Show() otherwise the 1st invocation
+ // of gdk_xxx_grab() will always fail.
cast_lock_widget->TryGrabAllInputs();
// Add the window to its own group so that its grab won't be stolen if
// gtk_grab_add() gets called on behalf on a non-screen-locker widget (e.g.
// a modal dialog) -- see http://crosbug.com/8999. We intentionally do this
- // after calling TryGrabAllInputs(), as want to be in the default window group
+ // after calling ClearGtkGrab(), as want to be in the default window group
// then so we can break any existing GTK grabs.
GtkWindowGroup* window_group = gtk_window_group_new();
gtk_window_group_add_window(window_group,
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698