This CL adds accelerators to the Linux toolkit views.
The MessageLoop had to be modified to support Dispatchers on Linux.

BUG=None
TEST=On Windows and Linux, make sure the accelerators still work as expected. On Linux toolkit views, build and run the unit-tests.

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@22210 0039d316-1c4b-4281-b951-d872f2087c98


CrOS-Libchrome-Original-Commit: 148d105e27c7c8c2cda0c81292690b9edafcae1f
diff --git a/base/keyboard_codes.h b/base/keyboard_codes.h
index 2f66ac1..3d8700f 100644
--- a/base/keyboard_codes.h
+++ b/base/keyboard_codes.h
@@ -9,8 +9,10 @@
 
 #if defined(OS_WIN)
 #include "base/keyboard_codes_win.h"
-#elif defined(OS_POSIX)
-#include "base/keyboard_codes_posix.h"
+#elif defined(OS_LINUX)
+#include "base/keyboard_codes_linux.h"
+#elif defined(OS_MACOSX)
+#include "base/keyboard_codes_mac.h"
 #endif
 
 #endif  // BASE_KEYBOARD_CODES_H_
diff --git a/base/keyboard_codes_linux.h b/base/keyboard_codes_linux.h
new file mode 100644
index 0000000..50b30b1
--- /dev/null
+++ b/base/keyboard_codes_linux.h
@@ -0,0 +1,214 @@
+// 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.
+
+/*
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com. All rights reserved.
+ * Copyright (C) 2008, 2009 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF USE, DATA, OR
+ * PROFITS, OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BASE_KEYBOARD_CODES_LINUX_H_
+#define BASE_KEYBOARD_CODES_LINUX_H_
+
+#include <gdk/gdkkeysyms.h>
+#include <X11/XF86keysym.h>
+
+namespace base {
+
+enum {
+  VKEY_BACK = GDK_BackSpace,
+  VKEY_TAB = GDK_Tab,
+  VKEY_CLEAR = GDK_Clear,
+  VKEY_RETURN = GDK_Return,
+  VKEY_SHIFT = GDK_Shift_L,  // TODO(jcampan): what about GDK_Shift_R?
+  VKEY_CONTROL = GDK_Control_L,  // TODO(jcampan): what about GDK_Control_R?
+  VKEY_MENU = GDK_Menu,
+  VKEY_PAUSE = GDK_Pause,
+  VKEY_CAPITAL = GDK_Shift_Lock,
+  VKEY_KANA = GDK_Kana_Shift,
+  VKEY_HANGUL = GDK_Hangul,
+  // TODO(jcampan): not sure what the next 2 are.
+  VKEY_JUNJA = GDK_Hangul,
+  VKEY_FINAL = GDK_Hangul,
+  VKEY_HANJA = GDK_Hangul_Hanja,
+  VKEY_KANJI = GDK_Kanji,
+  VKEY_ESCAPE = GDK_Escape,
+  // TODO(jcampan): not sure what the next 4 are.
+  VKEY_CONVERT = 0x1C,
+  VKEY_NONCONVERT = 0x1D,
+  VKEY_ACCEPT = 0x1E,
+  VKEY_MODECHANGE = 0x1F,
+  VKEY_SPACE = GDK_space,
+  VKEY_PRIOR = GDK_Prior,
+  VKEY_NEXT = GDK_Next,
+  VKEY_END = GDK_End,
+  VKEY_HOME = GDK_Home,
+  VKEY_LEFT = GDK_Left,
+  VKEY_UP = GDK_Up,
+  VKEY_RIGHT = GDK_Right,
+  VKEY_DOWN = GDK_Down,
+  VKEY_SELECT = GDK_Select,
+  VKEY_PRINT = GDK_Print,
+  VKEY_EXECUTE = GDK_Execute,
+  VKEY_SNAPSHOT = 0x2C,    // TODO(jcampan): not sure what this one is.
+  VKEY_INSERT = GDK_Insert,
+  VKEY_DELETE = GDK_Delete,
+  VKEY_HELP = GDK_Help,
+  VKEY_0 = GDK_0,
+  VKEY_1 = GDK_1,
+  VKEY_2 = GDK_2,
+  VKEY_3 = GDK_3,
+  VKEY_4 = GDK_4,
+  VKEY_5 = GDK_5,
+  VKEY_6 = GDK_6,
+  VKEY_7 = GDK_7,
+  VKEY_8 = GDK_8,
+  VKEY_9 = GDK_9,
+  VKEY_A = GDK_A,
+  VKEY_B = GDK_B,
+  VKEY_C = GDK_C,
+  VKEY_D = GDK_D,
+  VKEY_E = GDK_E,
+  VKEY_F = GDK_F,
+  VKEY_G = GDK_G,
+  VKEY_H = GDK_H,
+  VKEY_I = GDK_I,
+  VKEY_J = GDK_J,
+  VKEY_K = GDK_K,
+  VKEY_L = GDK_L,
+  VKEY_M = GDK_M,
+  VKEY_N = GDK_N,
+  VKEY_O = GDK_O,
+  VKEY_P = GDK_P,
+  VKEY_Q = GDK_Q,
+  VKEY_R = GDK_R,
+  VKEY_S = GDK_S,
+  VKEY_T = GDK_T,
+  VKEY_U = GDK_U,
+  VKEY_V = GDK_V,
+  VKEY_W = GDK_W,
+  VKEY_X = GDK_X,
+  VKEY_Y = GDK_Y,
+  VKEY_Z = GDK_Z,
+  VKEY_LWIN = GDK_Meta_L,
+  VKEY_RWIN = GDK_Meta_R,
+  VKEY_APPS = 0x5D,  // TODO(jcampan): not sure what this one is.
+  VKEY_SLEEP = XF86XK_Sleep,
+  VKEY_NUMPAD0 = GDK_KP_0,
+  VKEY_NUMPAD1 = GDK_KP_1,
+  VKEY_NUMPAD2 = GDK_KP_2,
+  VKEY_NUMPAD3 = GDK_KP_3,
+  VKEY_NUMPAD4 = GDK_KP_4,
+  VKEY_NUMPAD5 = GDK_KP_5,
+  VKEY_NUMPAD6 = GDK_KP_6,
+  VKEY_NUMPAD7 = GDK_KP_7,
+  VKEY_NUMPAD8 = GDK_KP_8,
+  VKEY_NUMPAD9 = GDK_KP_9,
+  VKEY_MULTIPLY = GDK_KP_Multiply,
+  VKEY_ADD = GDK_KP_Add,
+  VKEY_SEPARATOR = GDK_KP_Separator,
+  VKEY_SUBTRACT = GDK_KP_Subtract,
+  VKEY_DECIMAL = GDK_KP_Decimal,
+  VKEY_DIVIDE = GDK_KP_Divide,
+  VKEY_F1 = GDK_F1,
+  VKEY_F2 = GDK_F2,
+  VKEY_F3 = GDK_F3,
+  VKEY_F4 = GDK_F4,
+  VKEY_F5 = GDK_F5,
+  VKEY_F6 = GDK_F6,
+  VKEY_F7 = GDK_F7,
+  VKEY_F8 = GDK_F8,
+  VKEY_F9 = GDK_F9,
+  VKEY_F10 = GDK_F10,
+  VKEY_F11 = GDK_F11,
+  VKEY_F12 = GDK_F12,
+  VKEY_F13 = GDK_F13,
+  VKEY_F14 = GDK_F14,
+  VKEY_F15 = GDK_F15,
+  VKEY_F16 = GDK_F16,
+  VKEY_F17 = GDK_F17,
+  VKEY_F18 = GDK_F18,
+  VKEY_F19 = GDK_F19,
+  VKEY_F20 = GDK_F20,
+  VKEY_F21 = GDK_F21,
+  VKEY_F22 = GDK_F22,
+  VKEY_F23 = GDK_F23,
+  VKEY_F24 = GDK_F24,
+  VKEY_NUMLOCK = GDK_Num_Lock,
+  VKEY_SCROLL = GDK_Scroll_Lock,
+  VKEY_LSHIFT = GDK_Shift_L,
+  VKEY_RSHIFT = GDK_Shift_R,
+  VKEY_LCONTROL = GDK_Control_L,
+  VKEY_RCONTROL = GDK_Control_R,
+  VKEY_LMENU = GDK_Alt_L,
+  VKEY_RMENU = GDK_Alt_R,
+  VKEY_BROWSER_BACK = XF86XK_Back,
+  VKEY_BROWSER_FORWARD = XF86XK_Forward,
+  VKEY_BROWSER_REFRESH = XF86XK_Refresh,
+  VKEY_BROWSER_STOP = XF86XK_Stop,
+  VKEY_BROWSER_SEARCH = XF86XK_Search,
+  VKEY_BROWSER_FAVORITES = XF86XK_Favorites,
+  VKEY_BROWSER_HOME = XF86XK_HomePage,
+  VKEY_VOLUME_MUTE = XF86XK_AudioMute,
+  VKEY_VOLUME_DOWN = XF86XK_AudioLowerVolume,
+  VKEY_VOLUME_UP = XF86XK_AudioRaiseVolume,
+  VKEY_MEDIA_NEXT_TRACK = XF86XK_AudioNext,
+  VKEY_MEDIA_PREV_TRACK = XF86XK_AudioPrev,
+  VKEY_MEDIA_STOP = XF86XK_AudioStop,
+  VKEY_MEDIA_PLAY_PAUSE = XF86XK_AudioPause,
+  VKEY_MEDIA_LAUNCH_MAIL = XF86XK_Mail,
+  VKEY_MEDIA_LAUNCH_MEDIA_SELECT = XF86XK_AudioMedia,
+  VKEY_MEDIA_LAUNCH_APP1 = XF86XK_Launch1,
+  VKEY_MEDIA_LAUNCH_APP2 = XF86XK_Launch2,
+  // TODO(jcampan): Figure-out values below.
+  VKEY_OEM_1 = 0xBA,
+  VKEY_OEM_PLUS = 0xBB,
+  VKEY_OEM_COMMA = 0xBC,
+  VKEY_OEM_MINUS = 0xBD,
+  VKEY_OEM_PERIOD = 0xBE,
+  VKEY_OEM_2 = 0xBF,
+  VKEY_OEM_3 = 0xC0,
+  VKEY_OEM_4 = 0xDB,
+  VKEY_OEM_5 = 0xDC,
+  VKEY_OEM_6 = 0xDD,
+  VKEY_OEM_7 = 0xDE,
+  VKEY_OEM_8 = 0xDF,
+  VKEY_OEM_102 = 0xE2,
+  VKEY_PROCESSKEY = 0xE5,
+  VKEY_PACKET = 0xE7,
+  VKEY_ATTN = 0xF6,
+  VKEY_CRSEL = 0xF7,
+  VKEY_EXSEL = 0xF8,
+  VKEY_EREOF = 0xF9,
+  VKEY_PLAY = 0xFA,
+  VKEY_ZOOM = XF86XK_ZoomIn,
+  VKEY_NONAME = 0xFC,
+  VKEY_PA1 = 0xFD,
+  VKEY_OEM_CLEAR = 0xFE,
+  VKEY_UNKNOWN = 0
+};
+
+}  // namespace views
+
+#endif  // BASE_KEYBOARD_CODES_LINUX_H_
diff --git a/base/keyboard_codes_posix.h b/base/keyboard_codes_posix.h
deleted file mode 100644
index 5100d96..0000000
--- a/base/keyboard_codes_posix.h
+++ /dev/null
@@ -1,208 +0,0 @@
-// 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.
-
-/*
- * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com. All rights reserved.
- * Copyright (C) 2008, 2009 Google Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF USE, DATA, OR
- * PROFITS, OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef BASE_KEYBOARD_CODES_POSIX_H_
-#define BASE_KEYBOARD_CODES_POSIX_H_
-
-namespace base {
-
-enum {
-  VKEY_BACK = 0x08,
-  VKEY_TAB = 0x09,
-  VKEY_CLEAR = 0x0C,
-  VKEY_RETURN = 0x0D,
-  VKEY_SHIFT = 0x10,
-  VKEY_CONTROL = 0x11,
-  VKEY_MENU = 0x12,
-  VKEY_PAUSE = 0x13,
-  VKEY_CAPITAL = 0x14,
-  VKEY_KANA = 0x15,
-  VKEY_HANGUL = 0x15,
-  VKEY_JUNJA = 0x17,
-  VKEY_FINAL = 0x18,
-  VKEY_HANJA = 0x19,
-  VKEY_KANJI = 0x19,
-  VKEY_ESCAPE = 0x1B,
-  VKEY_CONVERT = 0x1C,
-  VKEY_NONCONVERT = 0x1D,
-  VKEY_ACCEPT = 0x1E,
-  VKEY_MODECHANGE = 0x1F,
-  VKEY_SPACE = 0x20,
-  VKEY_PRIOR = 0x21,
-  VKEY_NEXT = 0x22,
-  VKEY_END = 0x23,
-  VKEY_HOME = 0x24,
-  VKEY_LEFT = 0x25,
-  VKEY_UP = 0x26,
-  VKEY_RIGHT = 0x27,
-  VKEY_DOWN = 0x28,
-  VKEY_SELECT = 0x29,
-  VKEY_PRINT = 0x2A,
-  VKEY_EXECUTE = 0x2B,
-  VKEY_SNAPSHOT = 0x2C,
-  VKEY_INSERT = 0x2D,
-  VKEY_DELETE = 0x2E,
-  VKEY_HELP = 0x2F,
-  VKEY_0 = 0x30,
-  VKEY_1 = 0x31,
-  VKEY_2 = 0x32,
-  VKEY_3 = 0x33,
-  VKEY_4 = 0x34,
-  VKEY_5 = 0x35,
-  VKEY_6 = 0x36,
-  VKEY_7 = 0x37,
-  VKEY_8 = 0x38,
-  VKEY_9 = 0x39,
-  VKEY_A = 0x41,
-  VKEY_B = 0x42,
-  VKEY_C = 0x43,
-  VKEY_D = 0x44,
-  VKEY_E = 0x45,
-  VKEY_F = 0x46,
-  VKEY_G = 0x47,
-  VKEY_H = 0x48,
-  VKEY_I = 0x49,
-  VKEY_J = 0x4A,
-  VKEY_K = 0x4B,
-  VKEY_L = 0x4C,
-  VKEY_M = 0x4D,
-  VKEY_N = 0x4E,
-  VKEY_O = 0x4F,
-  VKEY_P = 0x50,
-  VKEY_Q = 0x51,
-  VKEY_R = 0x52,
-  VKEY_S = 0x53,
-  VKEY_T = 0x54,
-  VKEY_U = 0x55,
-  VKEY_V = 0x56,
-  VKEY_W = 0x57,
-  VKEY_X = 0x58,
-  VKEY_Y = 0x59,
-  VKEY_Z = 0x5A,
-  VKEY_LWIN = 0x5B,
-  VKEY_RWIN = 0x5C,
-  VKEY_APPS = 0x5D,
-  VKEY_SLEEP = 0x5F,
-  VKEY_NUMPAD0 = 0x60,
-  VKEY_NUMPAD1 = 0x61,
-  VKEY_NUMPAD2 = 0x62,
-  VKEY_NUMPAD3 = 0x63,
-  VKEY_NUMPAD4 = 0x64,
-  VKEY_NUMPAD5 = 0x65,
-  VKEY_NUMPAD6 = 0x66,
-  VKEY_NUMPAD7 = 0x67,
-  VKEY_NUMPAD8 = 0x68,
-  VKEY_NUMPAD9 = 0x69,
-  VKEY_MULTIPLY = 0x6A,
-  VKEY_ADD = 0x6B,
-  VKEY_SEPARATOR = 0x6C,
-  VKEY_SUBTRACT = 0x6D,
-  VKEY_DECIMAL = 0x6E,
-  VKEY_DIVIDE = 0x6F,
-  VKEY_F1 = 0x70,
-  VKEY_F2 = 0x71,
-  VKEY_F3 = 0x72,
-  VKEY_F4 = 0x73,
-  VKEY_F5 = 0x74,
-  VKEY_F6 = 0x75,
-  VKEY_F7 = 0x76,
-  VKEY_F8 = 0x77,
-  VKEY_F9 = 0x78,
-  VKEY_F10 = 0x79,
-  VKEY_F11 = 0x7A,
-  VKEY_F12 = 0x7B,
-  VKEY_F13 = 0x7C,
-  VKEY_F14 = 0x7D,
-  VKEY_F15 = 0x7E,
-  VKEY_F16 = 0x7F,
-  VKEY_F17 = 0x80,
-  VKEY_F18 = 0x81,
-  VKEY_F19 = 0x82,
-  VKEY_F20 = 0x83,
-  VKEY_F21 = 0x84,
-  VKEY_F22 = 0x85,
-  VKEY_F23 = 0x86,
-  VKEY_F24 = 0x87,
-  VKEY_NUMLOCK = 0x90,
-  VKEY_SCROLL = 0x91,
-  VKEY_LSHIFT = 0xA0,
-  VKEY_RSHIFT = 0xA1,
-  VKEY_LCONTROL = 0xA2,
-  VKEY_RCONTROL = 0xA3,
-  VKEY_LMENU = 0xA4,
-  VKEY_RMENU = 0xA5,
-  VKEY_BROWSER_BACK = 0xA6,
-  VKEY_BROWSER_FORWARD = 0xA7,
-  VKEY_BROWSER_REFRESH = 0xA8,
-  VKEY_BROWSER_STOP = 0xA9,
-  VKEY_BROWSER_SEARCH = 0xAA,
-  VKEY_BROWSER_FAVORITES = 0xAB,
-  VKEY_BROWSER_HOME = 0xAC,
-  VKEY_VOLUME_MUTE = 0xAD,
-  VKEY_VOLUME_DOWN = 0xAE,
-  VKEY_VOLUME_UP = 0xAF,
-  VKEY_MEDIA_NEXT_TRACK = 0xB0,
-  VKEY_MEDIA_PREV_TRACK = 0xB1,
-  VKEY_MEDIA_STOP = 0xB2,
-  VKEY_MEDIA_PLAY_PAUSE = 0xB3,
-  VKEY_MEDIA_LAUNCH_MAIL = 0xB4,
-  VKEY_MEDIA_LAUNCH_MEDIA_SELECT = 0xB5,
-  VKEY_MEDIA_LAUNCH_APP1 = 0xB6,
-  VKEY_MEDIA_LAUNCH_APP2 = 0xB7,
-  VKEY_OEM_1 = 0xBA,
-  VKEY_OEM_PLUS = 0xBB,
-  VKEY_OEM_COMMA = 0xBC,
-  VKEY_OEM_MINUS = 0xBD,
-  VKEY_OEM_PERIOD = 0xBE,
-  VKEY_OEM_2 = 0xBF,
-  VKEY_OEM_3 = 0xC0,
-  VKEY_OEM_4 = 0xDB,
-  VKEY_OEM_5 = 0xDC,
-  VKEY_OEM_6 = 0xDD,
-  VKEY_OEM_7 = 0xDE,
-  VKEY_OEM_8 = 0xDF,
-  VKEY_OEM_102 = 0xE2,
-  VKEY_PROCESSKEY = 0xE5,
-  VKEY_PACKET = 0xE7,
-  VKEY_ATTN = 0xF6,
-  VKEY_CRSEL = 0xF7,
-  VKEY_EXSEL = 0xF8,
-  VKEY_EREOF = 0xF9,
-  VKEY_PLAY = 0xFA,
-  VKEY_ZOOM = 0xFB,
-  VKEY_NONAME = 0xFC,
-  VKEY_PA1 = 0xFD,
-  VKEY_OEM_CLEAR = 0xFE,
-  VKEY_UNKNOWN = 0
-};
-
-}  // namespace views
-
-#endif  // BASE_KEYBOARD_CODES_POSIX_H_
diff --git a/base/message_loop.cc b/base/message_loop.cc
index 4c91b1f..5464670 100644
--- a/base/message_loop.cc
+++ b/base/message_loop.cc
@@ -188,9 +188,10 @@
 
   StartHistogrammer();
 
-#if defined(OS_WIN)
-  if (state_->dispatcher) {
-    pump_win()->RunWithDispatcher(this, state_->dispatcher);
+#if defined(OS_WIN) || defined(OS_LINUX)
+  if (state_->dispatcher && type() == TYPE_UI) {
+    static_cast<base::MessagePumpForUI*>(pump_.get())->
+        RunWithDispatcher(this, state_->dispatcher);
     return;
   }
 #endif
@@ -480,7 +481,7 @@
 
   // Initialize the other fields:
   quit_received = false;
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(OS_LINUX)
   dispatcher = NULL;
 #endif
 }
@@ -570,26 +571,7 @@
 //------------------------------------------------------------------------------
 // MessageLoopForUI
 
-#if defined(OS_LINUX) || defined(OS_WIN)
-
-void MessageLoopForUI::AddObserver(Observer* observer) {
-  pump_ui()->AddObserver(observer);
-}
-
-void MessageLoopForUI::RemoveObserver(Observer* observer) {
-  pump_ui()->RemoveObserver(observer);
-}
-
-#endif
-
 #if defined(OS_WIN)
-
-void MessageLoopForUI::Run(Dispatcher* dispatcher) {
-  AutoRunState save_state(this);
-  state_->dispatcher = dispatcher;
-  RunHandler();
-}
-
 void MessageLoopForUI::WillProcessMessage(const MSG& message) {
   pump_win()->WillProcessMessage(message);
 }
@@ -602,6 +584,22 @@
 
 #endif  // defined(OS_WIN)
 
+#if defined(OS_LINUX) || defined(OS_WIN)
+void MessageLoopForUI::AddObserver(Observer* observer) {
+  pump_ui()->AddObserver(observer);
+}
+
+void MessageLoopForUI::RemoveObserver(Observer* observer) {
+  pump_ui()->RemoveObserver(observer);
+}
+
+void MessageLoopForUI::Run(Dispatcher* dispatcher) {
+  AutoRunState save_state(this);
+  state_->dispatcher = dispatcher;
+  RunHandler();
+}
+#endif  // defined(OS_LINUX) || defined(OS_WIN)
+
 //------------------------------------------------------------------------------
 // MessageLoopForIO
 
diff --git a/base/message_loop.h b/base/message_loop.h
index debbade..395ce6e 100644
--- a/base/message_loop.h
+++ b/base/message_loop.h
@@ -234,6 +234,14 @@
   // Returns true if we are currently running a nested message loop.
   bool IsNested();
 
+#if defined(OS_WIN)
+  typedef base::MessagePumpWin::Dispatcher Dispatcher;
+  typedef base::MessagePumpWin::Observer Observer;
+#elif defined(OS_LINUX)
+  typedef base::MessagePumpForUI::Dispatcher Dispatcher;
+  typedef base::MessagePumpForUI::Observer Observer;
+#endif
+
   //----------------------------------------------------------------------------
  protected:
   struct RunState {
@@ -244,8 +252,8 @@
     // once it becomes idle.
     bool quit_received;
 
-#if defined(OS_WIN)
-    base::MessagePumpWin::Dispatcher* dispatcher;
+#if defined(OS_WIN) || defined(OS_LINUX)
+    Dispatcher* dispatcher;
 #endif
   };
 
@@ -416,34 +424,25 @@
     return static_cast<MessageLoopForUI*>(loop);
   }
 
-#if defined(OS_LINUX)
-  typedef base::MessagePumpForUI::Observer Observer;
-
-  // See message_pump_glib for definitions of these methods.
-  void AddObserver(Observer* observer);
-  void RemoveObserver(Observer* observer);
-#endif
-
 #if defined(OS_WIN)
-  typedef base::MessagePumpWin::Dispatcher Dispatcher;
-  typedef base::MessagePumpWin::Observer Observer;
-
-  // Please see MessagePumpWin for definitions of these methods.
-  void AddObserver(Observer* observer);
-  void RemoveObserver(Observer* observer);
-  void Run(Dispatcher* dispatcher);
   void WillProcessMessage(const MSG& message);
   void DidProcessMessage(const MSG& message);
   void PumpOutPendingPaintMessages();
 #endif
 
 #if defined(OS_WIN) || defined(OS_LINUX)
+  // Please see message_pump_win/message_pump_glib for definitions of these
+  // methods.
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+  void Run(Dispatcher* dispatcher);
+
  protected:
   // TODO(rvargas): Make this platform independent.
   base::MessagePumpForUI* pump_ui() {
     return static_cast<base::MessagePumpForUI*>(pump_.get());
   }
-#endif  // defined(OS_WIN)
+#endif  // defined(OS_WIN) || defined(OS_LINUX)
 };
 
 // Do not add any member variables to MessageLoopForUI!  This is important b/c
diff --git a/base/message_pump_glib.cc b/base/message_pump_glib.cc
index ac0a080..6f050ba 100644
--- a/base/message_pump_glib.cc
+++ b/base/message_pump_glib.cc
@@ -153,7 +153,8 @@
   close(wakeup_pipe_write_);
 }
 
-void MessagePumpForUI::Run(Delegate* delegate) {
+void MessagePumpForUI::RunWithDispatcher(Delegate* delegate,
+                                         Dispatcher* dispatcher) {
 #ifndef NDEBUG
   // Make sure we only run this on one thread.  GTK only has one message pump
   // so we can only have one UI loop per process.
@@ -165,6 +166,7 @@
 
   RunState state;
   state.delegate = delegate;
+  state.dispatcher = dispatcher;
   state.should_quit = false;
   state.run_depth = state_ ? state_->run_depth + 1 : 1;
   state.has_work = false;
@@ -309,9 +311,16 @@
 
 // static
 void MessagePumpForUI::EventDispatcher(GdkEvent* event, gpointer data) {
-  reinterpret_cast<MessagePumpForUI*>(data)->WillProcessEvent(event);
-  gtk_main_do_event(event);
-  reinterpret_cast<MessagePumpForUI*>(data)->DidProcessEvent(event);
+  MessagePumpForUI* message_pump = reinterpret_cast<MessagePumpForUI*>(data);
+
+  message_pump->WillProcessEvent(event);
+  if (message_pump->state_->dispatcher) {
+    if (!message_pump->state_->dispatcher->Dispatch(event))
+      message_pump->state_->should_quit = true;
+  } else {
+    gtk_main_do_event(event);
+  }
+  message_pump->DidProcessEvent(event);
 }
 
 }  // namespace base
diff --git a/base/message_pump_glib.h b/base/message_pump_glib.h
index e8288a8..08e1964 100644
--- a/base/message_pump_glib.h
+++ b/base/message_pump_glib.h
@@ -31,10 +31,29 @@
     virtual void DidProcessEvent(GdkEvent* event) = 0;
   };
 
-  MessagePumpForUI();
-  ~MessagePumpForUI();
+  // Dispatcher is used during a nested invocation of Run to dispatch events.
+  // If Run is invoked with a non-NULL Dispatcher, MessageLoop does not
+  // dispatch events (or invoke gtk_main_do_event), rather every event is
+  // passed to Dispatcher's Dispatch method for dispatch. It is up to the
+  // Dispatcher to dispatch, or not, the event.
+  //
+  // The nested loop is exited by either posting a quit, or returning false
+  // from Dispatch.
+  class Dispatcher {
+   public:
+    virtual ~Dispatcher() {}
+    // Dispatches the event. If true is returned processing continues as
+    // normal. If false is returned, the nested loop exits immediately.
+    virtual bool Dispatch(GdkEvent* event) = 0;
+  };
 
-  virtual void Run(Delegate* delegate);
+  MessagePumpForUI();
+  virtual ~MessagePumpForUI();
+
+  // Like MessagePump::Run, but GdkEvent objects are routed through dispatcher.
+  virtual void RunWithDispatcher(Delegate* delegate, Dispatcher* dispatcher);
+
+  virtual void Run(Delegate* delegate) { RunWithDispatcher(delegate, NULL); }
   virtual void Quit();
   virtual void ScheduleWork();
   virtual void ScheduleDelayedWork(const Time& delayed_work_time);
@@ -49,10 +68,10 @@
   bool HandleCheck();
   void HandleDispatch();
 
-  // Add an Observer, which will start receiving notifications immediately.
+  // Adds an Observer, which will start receiving notifications immediately.
   void AddObserver(Observer* observer);
 
-  // Remove an Observer.  It is safe to call this method while an Observer is
+  // Removes an Observer.  It is safe to call this method while an Observer is
   // receiving a notification callback.
   void RemoveObserver(Observer* observer);
 
@@ -61,6 +80,7 @@
   // separate between them in this structure type.
   struct RunState {
     Delegate* delegate;
+    Dispatcher* dispatcher;
 
     // Used to flag that the current Run() invocation should return ASAP.
     bool should_quit;