summaryrefslogtreecommitdiffstats
path: root/views/focus
diff options
context:
space:
mode:
authorjcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-31 22:53:37 +0000
committerjcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-31 22:53:37 +0000
commit148d105e27c7c8c2cda0c81292690b9edafcae1f (patch)
treee278052fc84a6e5399aec5bd0d423162aecb6d16 /views/focus
parentdc75d4823b598a9b9b313728a06f6b47d6a73929 (diff)
downloadchromium_src-148d105e27c7c8c2cda0c81292690b9edafcae1f.zip
chromium_src-148d105e27c7c8c2cda0c81292690b9edafcae1f.tar.gz
chromium_src-148d105e27c7c8c2cda0c81292690b9edafcae1f.tar.bz2
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
Diffstat (limited to 'views/focus')
-rw-r--r--views/focus/accelerator_handler.h40
-rw-r--r--views/focus/accelerator_handler_gtk.cc61
-rw-r--r--views/focus/accelerator_handler_win.cc44
-rw-r--r--views/focus/focus_manager.cc74
-rw-r--r--views/focus/focus_manager.h14
-rw-r--r--views/focus/focus_manager_unittest.cc185
6 files changed, 278 insertions, 140 deletions
diff --git a/views/focus/accelerator_handler.h b/views/focus/accelerator_handler.h
new file mode 100644
index 0000000..618f541
--- /dev/null
+++ b/views/focus/accelerator_handler.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2006-2008 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.
+
+#ifndef VIEWS_FOCUS_ACCELERATOR_HANDLER_H_
+#define VIEWS_FOCUS_ACCELERATOR_HANDLER_H_
+
+#if defined(OS_LINUX)
+#include <gdk/gdk.h>
+#endif
+
+#include "base/message_loop.h"
+
+namespace views {
+
+// This class delegates the key messages to the associated FocusManager class
+// for the window that is receiving these messages for accelerator processing.
+class AcceleratorHandler : public MessageLoopForUI::Dispatcher {
+ public:
+ AcceleratorHandler();
+ // Dispatcher method. This returns true if an accelerator was processed by the
+ // focus manager
+#if defined(OS_WIN)
+ virtual bool Dispatch(const MSG& msg);
+#else
+ virtual bool Dispatch(GdkEvent* event);
+#endif
+
+ private:
+#if defined(OS_LINUX)
+ // Last key pressed and consumed as an accelerator.
+ guint last_key_pressed_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(AcceleratorHandler);
+};
+
+} // namespace views
+
+#endif // VIEWS_FOCUS_ACCELERATOR_HANDLER_H_
diff --git a/views/focus/accelerator_handler_gtk.cc b/views/focus/accelerator_handler_gtk.cc
new file mode 100644
index 0000000..938dfcc
--- /dev/null
+++ b/views/focus/accelerator_handler_gtk.cc
@@ -0,0 +1,61 @@
+// 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 <gtk/gtk.h>
+
+#include "views/focus/accelerator_handler.h"
+
+#include "views/focus/focus_manager.h"
+#include "views/widget/widget_gtk.h"
+#include "views/window/window_gtk.h"
+
+namespace views {
+
+AcceleratorHandler::AcceleratorHandler() : last_key_pressed_(0) {
+}
+
+bool AcceleratorHandler::Dispatch(GdkEvent* event) {
+ if (event->type != GDK_KEY_PRESS && event->type != GDK_KEY_RELEASE) {
+ gtk_main_do_event(event);
+ return true;
+ }
+
+ GdkEventKey* key_event = reinterpret_cast<GdkEventKey*>(event);
+ // Let's retrieve the focus manager for the GdkWindow.
+ GdkWindow* window = gdk_window_get_toplevel(key_event->window);
+ gpointer ptr;
+ gdk_window_get_user_data(window, &ptr);
+ DCHECK(ptr); // The top-level window is expected to always be associated
+ // with the top-level gtk widget.
+ WindowGtk* widget =
+ WidgetGtk::GetWindowForNative(reinterpret_cast<GtkWidget*>(ptr));
+ FocusManager* focus_manager = widget->GetFocusManager();
+ if (!focus_manager) {
+ NOTREACHED();
+ return true;
+ }
+
+ if (event->type == GDK_KEY_PRESS) {
+ KeyEvent view_key_event(key_event, true);
+ // FocusManager::OnKeyPressed and OnKeyReleased return false if this
+ // message has been consumed and should not be propagated further.
+ if (!focus_manager->OnKeyEvent(view_key_event)) {
+ last_key_pressed_ = key_event->keyval;
+ return true;
+ }
+ }
+
+ // Key release, make sure to filter-out the key release for key press consumed
+ // as accelerators to avoid unpaired key release.
+ if (event->type == GDK_KEY_RELEASE &&
+ key_event->keyval == last_key_pressed_) {
+ last_key_pressed_ = 0;
+ return true;
+ }
+
+ gtk_main_do_event(event);
+ return true;
+}
+
+} // namespace views
diff --git a/views/focus/accelerator_handler_win.cc b/views/focus/accelerator_handler_win.cc
new file mode 100644
index 0000000..eb8bfb9
--- /dev/null
+++ b/views/focus/accelerator_handler_win.cc
@@ -0,0 +1,44 @@
+// 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/focus/accelerator_handler.h"
+
+#include "views/event.h"
+#include "views/focus/focus_manager.h"
+
+namespace views {
+
+AcceleratorHandler::AcceleratorHandler() {
+}
+
+bool AcceleratorHandler::Dispatch(const MSG& msg) {
+ bool process_message = true;
+
+ if (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST) {
+ FocusManager* focus_manager =
+ FocusManager::GetFocusManagerForNativeView(msg.hwnd);
+ if (focus_manager) {
+ switch (msg.message) {
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN: {
+ KeyEvent event(Event::ET_KEY_PRESSED,
+ msg.wParam,
+ msg.lParam & 0xFFFF,
+ (msg.lParam & 0xFFFF0000) >> 16);
+ process_message = focus_manager->OnKeyEvent(event);
+ break;
+ }
+ }
+ }
+ }
+
+ if (process_message) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ return true;
+}
+
+} // namespace views
diff --git a/views/focus/focus_manager.cc b/views/focus/focus_manager.cc
index 04f1f9b..1a0f7ae 100644
--- a/views/focus/focus_manager.cc
+++ b/views/focus/focus_manager.cc
@@ -12,6 +12,7 @@
#include <gtk/gtk.h>
#endif
+#include "base/keyboard_codes.h"
#include "base/logging.h"
#include "views/accelerator.h"
#include "views/focus/view_storage.h"
@@ -19,10 +20,6 @@
#include "views/widget/root_view.h"
#include "views/widget/widget.h"
-#if defined(OS_WIN)
-#include "base/win_util.h"
-#endif
-
namespace views {
// FocusManager -----------------------------------------------------
@@ -41,49 +38,36 @@ FocusManager::~FocusManager() {
DCHECK(focus_change_listeners_.empty());
}
-#if defined(OS_WIN)
-// Message handlers.
-bool FocusManager::OnKeyDown(HWND window, UINT message, WPARAM wparam,
- LPARAM lparam) {
- DCHECK((message == WM_KEYDOWN) || (message == WM_SYSKEYDOWN));
- HWND hwnd = widget_->GetNativeView();
-
- if (!IsWindowVisible(hwnd)) {
- // We got a message for a hidden window. Because WidgetWin::Close hides the
- // window, then destroys it, it it possible to get a message after we've
- // hidden the window. If we allow the message to be dispatched chances are
- // we'll crash in some weird place. By returning false we make sure the
- // message isn't dispatched.
- return false;
- }
-
- int virtual_key_code = static_cast<int>(wparam);
- int repeat_count = LOWORD(lparam);
- int flags = HIWORD(lparam);
- KeyEvent key_event(Event::ET_KEY_PRESSED,
- virtual_key_code, repeat_count, flags);
-
+bool FocusManager::OnKeyEvent(const KeyEvent& event) {
// If the focused view wants to process the key event as is, let it be.
- if (focused_view_ && focused_view_->SkipDefaultKeyEventProcessing(key_event))
+ if (focused_view_ && focused_view_->SkipDefaultKeyEventProcessing(event))
return true;
// Intercept Tab related messages for focus traversal.
// Note that we don't do focus traversal if the root window is not part of the
// active window hierarchy as this would mean we have no focused view and
// would focus the first focusable view.
+#if defined(OS_WIN)
HWND top_window = widget_->GetNativeView();
HWND active_window = ::GetActiveWindow();
if ((active_window == top_window || ::IsChild(active_window, top_window)) &&
- IsTabTraversalKeyEvent(key_event)) {
- AdvanceFocus(win_util::IsShiftPressed());
+ IsTabTraversalKeyEvent(event)) {
+ AdvanceFocus(event.IsShiftDown());
return false;
}
+#else
+ if (IsTabTraversalKeyEvent(event)) {
+ AdvanceFocus(event.IsShiftDown());
+ return false;
+ }
+#endif
// Intercept arrow key messages to switch between grouped views.
+ int key_code = event.GetCharacter();
if (focused_view_ && focused_view_->GetGroup() != -1 &&
- (virtual_key_code == VK_UP || virtual_key_code == VK_DOWN ||
- virtual_key_code == VK_LEFT || virtual_key_code == VK_RIGHT)) {
- bool next = (virtual_key_code == VK_RIGHT || virtual_key_code == VK_DOWN);
+ (key_code == base::VKEY_UP || key_code == base::VKEY_DOWN ||
+ key_code == base::VKEY_LEFT || key_code == base::VKEY_RIGHT)) {
+ bool next = (key_code == base::VKEY_RIGHT || key_code == base::VKEY_DOWN);
std::vector<View*> views;
focused_view_->GetParent()->GetViewsWithGroup(focused_view_->GetGroup(),
&views);
@@ -103,22 +87,19 @@ bool FocusManager::OnKeyDown(HWND window, UINT message, WPARAM wparam,
}
// Process keyboard accelerators.
- // We process accelerators here as we have no way of knowing if a HWND has
- // really processed a key event. If the key combination matches an
- // accelerator, the accelerator is triggered, otherwise we forward the
- // event to the HWND.
- Accelerator accelerator(Accelerator(static_cast<int>(virtual_key_code),
- win_util::IsShiftPressed(),
- win_util::IsCtrlPressed(),
- win_util::IsAltPressed()));
+ // If the key combination matches an accelerator, the accelerator is
+ // triggered, otherwise the key event is proceed as usual.
+ Accelerator accelerator(event.GetCharacter(),
+ event.IsShiftDown(),
+ event.IsControlDown(),
+ event.IsAltDown());
if (ProcessAccelerator(accelerator)) {
// If a shortcut was activated for this keydown message, do not propagate
- // the message further.
+ // the event further.
return false;
}
return true;
}
-#endif
void FocusManager::ValidateFocusedView() {
if (focused_view_) {
@@ -410,7 +391,6 @@ bool FocusManager::ProcessAccelerator(const Accelerator& accelerator) {
return true;
}
}
-
return false;
}
@@ -424,12 +404,8 @@ AcceleratorTarget* FocusManager::GetCurrentTargetForAccelerator(
// static
bool FocusManager::IsTabTraversalKeyEvent(const KeyEvent& key_event) {
-#if defined(OS_WIN)
- return key_event.GetCharacter() == VK_TAB && !win_util::IsCtrlPressed();
-#else
- NOTIMPLEMENTED();
- return false;
-#endif
+ return key_event.GetCharacter() == base::VKEY_TAB &&
+ !key_event.IsControlDown();
}
void FocusManager::ViewRemoved(View* parent, View* removed) {
diff --git a/views/focus/focus_manager.h b/views/focus/focus_manager.h
index b1c87b6..3106f72 100644
--- a/views/focus/focus_manager.h
+++ b/views/focus/focus_manager.h
@@ -5,9 +5,6 @@
#ifndef VIEWS_FOCUS_FOCUS_MANAGER_H_
#define VIEWS_FOCUS_FOCUS_MANAGER_H_
-#if defined(OS_WIN)
-#include <windows.h>
-#endif
#include <vector>
#include <map>
#include <list>
@@ -140,13 +137,10 @@ class FocusManager {
explicit FocusManager(Widget* widget);
~FocusManager();
-#if defined(OS_WIN)
- // OnKeyDown covers WM_KEYDOWN and WM_SYSKEYDOWN.
- bool OnKeyDown(HWND window,
- UINT message,
- WPARAM wparam,
- LPARAM lparam);
-#endif
+ // Processes the passed key event for accelerators and tab traversal.
+ // Returns false if the event has been consumed and should not be processed
+ // further.
+ bool OnKeyEvent(const KeyEvent& event);
// Returns true is the specified is part of the hierarchy of the window
// associated with this FocusManager.
diff --git a/views/focus/focus_manager_unittest.cc b/views/focus/focus_manager_unittest.cc
index 2ae52e1..fe5b8d0 100644
--- a/views/focus/focus_manager_unittest.cc
+++ b/views/focus/focus_manager_unittest.cc
@@ -10,6 +10,7 @@
#include "app/resource_bundle.h"
#include "base/gfx/rect.h"
+#include "base/keyboard_codes.h"
#include "base/string_util.h"
#include "third_party/skia/include/core/SkColor.h"
#include "views/background.h"
@@ -21,19 +22,28 @@
#include "views/controls/combobox/native_combobox_wrapper.h"
#include "views/controls/label.h"
#include "views/controls/link.h"
+#if defined(OS_WIN)
#include "views/controls/native_control.h"
#include "views/controls/scroll_view.h"
#include "views/controls/tabbed_pane/native_tabbed_pane_wrapper.h"
#include "views/controls/tabbed_pane/tabbed_pane.h"
#include "views/controls/textfield/textfield.h"
-#include "views/widget/accelerator_handler.h"
+#endif
+#include "views/focus/accelerator_handler.h"
#include "views/widget/root_view.h"
-#include "views/widget/widget_win.h"
+#include "views/window/window.h"
#include "views/window/window_delegate.h"
+
+#if defined(OS_WIN)
+#include "views/widget/widget_win.h"
#include "views/window/window_win.h"
+#else
+#include "views/window/window_gtk.h"
+#endif
namespace views {
+#if defined(OS_WIN)
static const int kWindowWidth = 600;
static const int kWindowHeight = 500;
@@ -93,9 +103,95 @@ static const int kHelpLinkID = count++; // 45
static const int kThumbnailContainerID = count++;
static const int kThumbnailStarID = count++;
static const int kThumbnailSuperStarID = count++;
+#endif
+
+class FocusManagerTest : public testing::Test, public WindowDelegate {
+ public:
+ FocusManagerTest()
+ : window_(NULL),
+ content_view_(NULL),
+ focus_change_listener_(NULL) {
+#if defined(OS_WIN)
+ OleInitialize(NULL);
+#endif
+ }
+
+ ~FocusManagerTest() {
+#if defined(OS_WIN)
+ OleUninitialize();
+#endif
+ }
-class FocusManagerTest;
+ virtual void SetUp() {
+ window_ = Window::CreateChromeWindow(NULL, bounds(), this);
+ InitContentView();
+ window_->Show();
+ }
+
+ virtual void TearDown() {
+ if (focus_change_listener_)
+ GetFocusManager()->RemoveFocusChangeListener(focus_change_listener_);
+ // window_->CloseNow();
+ window_->Close();
+
+ // Flush the message loop to make Purify happy.
+ message_loop()->RunAllPending();
+ }
+
+ FocusManager* GetFocusManager() {
+#if defined(OS_WIN)
+ return static_cast<WindowWin*>(window_)->GetFocusManager();
+#elif defined(OS_LINUX)
+ return static_cast<WindowGtk*>(window_)->GetFocusManager();
+#elif
+ NOTIMPLEMENTED();
+#endif
+ }
+
+ // WindowDelegate Implementation.
+ virtual View* GetContentsView() {
+ if (!content_view_)
+ content_view_ = new View();
+ return content_view_;
+ }
+
+ virtual void InitContentView() {
+ }
+
+ protected:
+ virtual gfx::Rect bounds() {
+ return gfx::Rect(0, 0, 500, 500);
+ }
+
+#if defined(OS_WIN)
+ // Mocks activating/deactivating the window.
+ void SimulateActivateWindow() {
+ ::SendMessage(window_->GetNativeWindow(), WM_ACTIVATE, WA_ACTIVE, NULL);
+ }
+ void SimulateDeactivateWindow() {
+ ::SendMessage(window_->GetNativeWindow(), WM_ACTIVATE, WA_INACTIVE, NULL);
+ }
+#endif
+
+ MessageLoopForUI* message_loop() { return &message_loop_; }
+
+ Window* window_;
+ View* content_view_;
+
+ void AddFocusChangeListener(FocusChangeListener* listener) {
+ ASSERT_FALSE(focus_change_listener_);
+ focus_change_listener_ = listener;
+ GetFocusManager()->AddFocusChangeListener(listener);
+ }
+
+ private:
+ FocusChangeListener* focus_change_listener_;
+ MessageLoopForUI message_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(FocusManagerTest);
+};
+#if defined(OS_WIN)
// BorderView is a NativeControl that creates a tab control as its child and
// takes a View to add as the child of the tab control. The tab control is used
// to give a nice background for the view. At some point we'll have a real
@@ -183,81 +279,6 @@ class DummyComboboxModel : public Combobox::Model {
}
};
-class FocusManagerTest : public testing::Test, public WindowDelegate {
- public:
- FocusManagerTest()
- : window_(NULL),
- focus_change_listener_(NULL),
- content_view_(NULL) {
- OleInitialize(NULL);
- }
-
- ~FocusManagerTest() {
- OleUninitialize();
- }
-
- virtual void SetUp() {
- window_ = static_cast<WindowWin*>(
- Window::CreateChromeWindow(NULL, bounds(), this));
- InitContentView();
- window_->Show();
- }
-
- virtual void TearDown() {
- if (focus_change_listener_)
- GetFocusManager()->RemoveFocusChangeListener(focus_change_listener_);
- window_->CloseNow();
-
- // Flush the message loop to make Purify happy.
- message_loop()->RunAllPending();
- }
-
- FocusManager* GetFocusManager() {
- return FocusManager::GetFocusManagerForNativeView(
- window_->GetNativeWindow());
- }
-
- // WindowDelegate Implementation.
- virtual View* GetContentsView() {
- if (!content_view_)
- content_view_ = new View();
- return content_view_;
- }
-
- virtual void InitContentView() {
- }
-
- protected:
- virtual gfx::Rect bounds() {
- return gfx::Rect(0, 0, 500, 500);
- }
-
- // Mocks activating/deactivating the window.
- void SimulateActivateWindow() {
- ::SendMessage(window_->GetNativeWindow(), WM_ACTIVATE, WA_ACTIVE, NULL);
- }
- void SimulateDeactivateWindow() {
- ::SendMessage(window_->GetNativeWindow(), WM_ACTIVATE, WA_INACTIVE, NULL);
- }
-
- MessageLoopForUI* message_loop() { return &message_loop_; }
-
- WindowWin* window_;
- View* content_view_;
-
- void AddFocusChangeListener(FocusChangeListener* listener) {
- ASSERT_FALSE(focus_change_listener_);
- focus_change_listener_ = listener;
- GetFocusManager()->AddFocusChangeListener(listener);
- }
-
- private:
- FocusChangeListener* focus_change_listener_;
- MessageLoopForUI message_loop_;
-
- DISALLOW_COPY_AND_ASSIGN(FocusManagerTest);
-};
-
class FocusTraversalTest : public FocusManagerTest {
public:
~FocusTraversalTest();
@@ -975,6 +996,8 @@ TEST_F(FocusTraversalTest, TraversalWithNonEnabledViews) {
}
}
+#endif // WIN_OS
+
// Counts accelerator calls.
class TestAcceleratorTarget : public AcceleratorTarget {
public:
@@ -997,8 +1020,8 @@ class TestAcceleratorTarget : public AcceleratorTarget {
TEST_F(FocusManagerTest, CallsNormalAcceleratorTarget) {
FocusManager* focus_manager = GetFocusManager();
- Accelerator return_accelerator(VK_RETURN, false, false, false);
- Accelerator escape_accelerator(VK_ESCAPE, false, false, false);
+ Accelerator return_accelerator(base::VKEY_RETURN, false, false, false);
+ Accelerator escape_accelerator(base::VKEY_ESCAPE, false, false, false);
TestAcceleratorTarget return_target(true);
TestAcceleratorTarget escape_target(true);
@@ -1115,7 +1138,7 @@ class SelfUnregisteringAcceleratorTarget : public AcceleratorTarget {
TEST_F(FocusManagerTest, CallsSelfDeletingAcceleratorTarget) {
FocusManager* focus_manager = GetFocusManager();
- Accelerator return_accelerator(VK_RETURN, false, false, false);
+ Accelerator return_accelerator(base::VKEY_RETURN, false, false, false);
SelfUnregisteringAcceleratorTarget target(return_accelerator, focus_manager);
EXPECT_EQ(target.accelerator_count(), 0);
EXPECT_EQ(NULL,