diff options
18 files changed, 138 insertions, 79 deletions
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view.h b/chrome/browser/autocomplete/autocomplete_edit_view.h index 928d7e4..cba7342 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view.h +++ b/chrome/browser/autocomplete/autocomplete_edit_view.h @@ -97,6 +97,9 @@ class AutocompleteEditView { // Closes the autocomplete popup, if it's open. virtual void ClosePopup() = 0; + // Sets the focus to the autocomplete view. + virtual void SetFocus() = 0; + // Called when the temporary text in the model may have changed. // |display_text| is the new text to show; |save_original_selection| is true // when there wasn't previously a temporary text and thus we need to save off diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h index 2f51e88..64fd6a2 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h +++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h @@ -60,9 +60,6 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, GtkWidget* widget() { return alignment_.get(); } - // Grab keyboard input focus, putting focus on the location widget. - void SetFocus(); - // Returns the width, in pixels, needed to display the current text. The // returned value includes margins and borders. int TextWidth(); @@ -103,6 +100,8 @@ class AutocompleteEditViewGtk : public AutocompleteEditView, virtual void UpdatePopup(); virtual void ClosePopup(); + virtual void SetFocus(); + virtual void OnTemporaryTextMaybeChanged(const std::wstring& display_text, bool save_original_selection); virtual bool OnInlineAutocompleteTextMaybeChanged( diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_mac.h b/chrome/browser/autocomplete/autocomplete_edit_view_mac.h index f6179fb..45ce48b 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_mac.h +++ b/chrome/browser/autocomplete/autocomplete_edit_view_mac.h @@ -78,6 +78,7 @@ class AutocompleteEditViewMac : public AutocompleteEditView { virtual void RevertAll(); virtual void UpdatePopup(); virtual void ClosePopup(); + virtual void SetFocus(); virtual void OnTemporaryTextMaybeChanged(const std::wstring& display_text, bool save_original_selection); virtual bool OnInlineAutocompleteTextMaybeChanged( diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm b/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm index dc70cc1..00485f5 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm +++ b/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm @@ -362,6 +362,9 @@ void AutocompleteEditViewMac::ClosePopup() { popup_view_->GetModel()->StopAutocomplete(); } +void AutocompleteEditViewMac::SetFocus() { +} + void AutocompleteEditViewMac::SetText(const std::wstring& display_text) { NSString* ss = base::SysWideToNSString(display_text); NSMutableAttributedString* as = diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_win.cc b/chrome/browser/autocomplete/autocomplete_edit_view_win.cc index 7a09dac..eb7ae14 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_win.cc +++ b/chrome/browser/autocomplete/autocomplete_edit_view_win.cc @@ -706,6 +706,10 @@ void AutocompleteEditViewWin::ClosePopup() { popup_view_->GetModel()->StopAutocomplete(); } +void AutocompleteEditViewWin::SetFocus() { + ::SetFocus(m_hWnd); +} + IAccessible* AutocompleteEditViewWin::GetIAccessible() { if (!autocomplete_accessibility_) { CComObject<AutocompleteAccessibility>* accessibility = NULL; diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_win.h b/chrome/browser/autocomplete/autocomplete_edit_view_win.h index 2f64f84..a66583f 100644 --- a/chrome/browser/autocomplete/autocomplete_edit_view_win.h +++ b/chrome/browser/autocomplete/autocomplete_edit_view_win.h @@ -110,6 +110,8 @@ class AutocompleteEditViewWin virtual void UpdatePopup(); virtual void ClosePopup(); + virtual void SetFocus(); + virtual void OnTemporaryTextMaybeChanged(const std::wstring& display_text, bool save_original_selection); virtual bool OnInlineAutocompleteTextMaybeChanged( diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc index adc109f..83c28b7 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc +++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc @@ -148,7 +148,7 @@ class RenderWidgetHostViewGtkWidget { } host_view->ShowCurrentCursor(); - host_view->GetRenderWidgetHost()->Focus(); + host_view->GetRenderWidgetHost()->GotFocus(); // The only way to enable a GtkIMContext object is to call its focus in // handler. diff --git a/chrome/browser/views/frame/browser_frame_gtk.cc b/chrome/browser/views/frame/browser_frame_gtk.cc index a2ce1db..7ca24f9 100644 --- a/chrome/browser/views/frame/browser_frame_gtk.cc +++ b/chrome/browser/views/frame/browser_frame_gtk.cc @@ -81,3 +81,17 @@ views::RootView* BrowserFrameGtk::CreateRootView() { root_view_ = new BrowserRootView(browser_view_, this); return root_view_; } + +gboolean BrowserFrameGtk::OnFocusIn(GtkWidget* widget, + GdkEventFocus* event) { + browser_view_->ActivationChanged(true); + return views::WindowGtk::OnFocusIn(widget, event); +} + +gboolean BrowserFrameGtk::OnFocusOut(GtkWidget* widget, + GdkEventFocus* event) { + browser_view_->ActivationChanged(false); + return views::WindowGtk::OnFocusOut(widget, event); +} + + diff --git a/chrome/browser/views/frame/browser_frame_gtk.h b/chrome/browser/views/frame/browser_frame_gtk.h index 78e9d53..1e1f308 100644 --- a/chrome/browser/views/frame/browser_frame_gtk.h +++ b/chrome/browser/views/frame/browser_frame_gtk.h @@ -36,6 +36,8 @@ class BrowserFrameGtk : public BrowserFrame, // Overridden from views::Widget. virtual ThemeProvider* GetThemeProvider() const; virtual ThemeProvider* GetDefaultThemeProvider() const; + virtual gboolean OnFocusIn(GtkWidget* widget, GdkEventFocus* event); + virtual gboolean OnFocusOut(GtkWidget* widget, GdkEventFocus* event); protected: // WidgetGtk overrides. diff --git a/chrome/browser/views/location_bar_view.cc b/chrome/browser/views/location_bar_view.cc index 0723d16..fb5ca9f 100644 --- a/chrome/browser/views/location_bar_view.cc +++ b/chrome/browser/views/location_bar_view.cc @@ -289,11 +289,8 @@ void LocationBarView::InvalidatePageActions() { } void LocationBarView::Focus() { -#if defined(OS_WIN) - ::SetFocus(location_entry_->m_hWnd); -#else - gtk_widget_grab_focus(location_entry_->widget()); -#endif + // Focus the location entry native view. + location_entry_->SetFocus(); } void LocationBarView::SetProfile(Profile* profile) { diff --git a/chrome/browser/views/tab_contents/native_tab_contents_container_gtk.cc b/chrome/browser/views/tab_contents/native_tab_contents_container_gtk.cc index 29a6ef2..6eb37c3 100644 --- a/chrome/browser/views/tab_contents/native_tab_contents_container_gtk.cc +++ b/chrome/browser/views/tab_contents/native_tab_contents_container_gtk.cc @@ -17,7 +17,8 @@ NativeTabContentsContainerGtk::NativeTabContentsContainerGtk( TabContentsContainer* container) - : container_(container) { + : container_(container), + focus_callback_id_(0) { } NativeTabContentsContainerGtk::~NativeTabContentsContainerGtk() { @@ -27,48 +28,11 @@ NativeTabContentsContainerGtk::~NativeTabContentsContainerGtk() { // NativeTabContentsContainerGtk, NativeTabContentsContainer overrides: void NativeTabContentsContainerGtk::AttachContents(TabContents* contents) { - // We need to register the tab contents window with the BrowserContainer so - // that the BrowserContainer is the focused view when the focus is on the - // TabContents window (for the TabContents case). - set_focus_view(this); - Attach(contents->GetNativeView()); - - // TODO(port): figure out focus interception -#if defined(OS_WIN) - HWND contents_hwnd = contents->GetContentNativeView(); - if (contents_hwnd) - views::FocusManager::InstallFocusSubclass(contents_hwnd, this); -#else - NOTIMPLEMENTED(); -#endif } void NativeTabContentsContainerGtk::DetachContents(TabContents* contents) { - // TODO(port): figure out focus interception -#if defined(OS_WIN) - // TODO(brettw) should this move to NativeViewHost::Detach which is called - // below? It needs cleanup regardless. - HWND container_hwnd = contents->GetNativeView(); - - // Hide the contents before adjusting its parent to avoid a full desktop - // flicker. - ShowWindow(container_hwnd, SW_HIDE); - - // Reset the parent to NULL to ensure hidden tabs don't receive messages. - ::SetParent(container_hwnd, NULL); - - // Unregister the tab contents window from the FocusManager. - views::FocusManager::UninstallFocusSubclass(container_hwnd); - HWND hwnd = contents->GetContentNativeView(); - if (hwnd) { - // We may not have an HWND anymore, if the renderer crashed and we are - // displaying the sad tab for example. - views::FocusManager::UninstallFocusSubclass(hwnd); - } -#else gtk_widget_hide(contents->GetNativeView()); -#endif // Now detach the TabContents. Detach(); @@ -81,31 +45,10 @@ void NativeTabContentsContainerGtk::SetFastResize(bool fast_resize) { void NativeTabContentsContainerGtk::RenderViewHostChanged( RenderViewHost* old_host, RenderViewHost* new_host) { - // TODO(port): figure out focus interception -#if defined(OS_WIN) - if (old_host && old_host->view()) { - views::FocusManager::UninstallFocusSubclass( - old_host->view()->GetNativeView()); - } - - if (new_host && new_host->view()) { - views::FocusManager::InstallFocusSubclass( - new_host->view()->GetNativeView(), this); - } - // If we are focused, we need to pass the focus to the new RenderViewHost. - views::FocusManager* focus_manager = views::FocusManager::GetFocusManager( - GetRootView()->GetWidget()->GetNativeView()); + views::FocusManager* focus_manager = GetFocusManager(); if (focus_manager->GetFocusedView() == this) Focus(); -#else - // If we are focused, we need to pass the focus to the new RenderViewHost. - // TODO: uncomment this once FocusManager has been ported. - // views::FocusManager* focus_manager = views::FocusManager::GetFocusManager( - // GetRootView()->GetWidget()->GetNativeView()); - // if (focus_manager->GetFocusedView() == this) - // Focus(); -#endif } views::View* NativeTabContentsContainerGtk::GetView() { @@ -114,14 +57,15 @@ views::View* NativeTabContentsContainerGtk::GetView() { void NativeTabContentsContainerGtk::TabContentsFocused( TabContents* tab_contents) { -#if defined(OS_WIN) + // Called when the tab contents native view gets focused (typically through a + // user click). We make ourself the focused view, so the focus is restored + // properly when the browser window is deactivated/reactivated. views::FocusManager* focus_manager = GetFocusManager(); if (!focus_manager) { NOTREACHED(); return; } focus_manager->SetFocusedView(this); -#endif } //////////////////////////////////////////////////////////////////////////////// diff --git a/chrome/browser/views/tab_contents/native_tab_contents_container_gtk.h b/chrome/browser/views/tab_contents/native_tab_contents_container_gtk.h index 0d4ed05..e30c11f 100644 --- a/chrome/browser/views/tab_contents/native_tab_contents_container_gtk.h +++ b/chrome/browser/views/tab_contents/native_tab_contents_container_gtk.h @@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_VIEWS_TAB_CONTENTS_NATIVE_TAB_CONTENTS_CONTAINER_GTK_H_ #define CHROME_BROWSER_VIEWS_TAB_CONTENTS_NATIVE_TAB_CONTENTS_CONTAINER_GTK_H_ +#include <gtk/gtk.h> + #include "chrome/browser/views/tab_contents/native_tab_contents_container.h" #include "views/controls/native/native_view_host.h" @@ -35,6 +37,8 @@ class NativeTabContentsContainerGtk : public NativeTabContentsContainer, private: TabContentsContainer* container_; + gulong focus_callback_id_; + DISALLOW_COPY_AND_ASSIGN(NativeTabContentsContainerGtk); }; diff --git a/chrome/browser/views/tab_contents/tab_contents_view_gtk.cc b/chrome/browser/views/tab_contents/tab_contents_view_gtk.cc index 8ca4d16..e39bfde 100644 --- a/chrome/browser/views/tab_contents/tab_contents_view_gtk.cc +++ b/chrome/browser/views/tab_contents/tab_contents_view_gtk.cc @@ -23,6 +23,7 @@ #include "chrome/browser/tab_contents/tab_contents_delegate.h" #include "chrome/browser/views/sad_tab_view.h" #include "chrome/browser/views/tab_contents/render_view_context_menu_win.h" +#include "views/focus/view_storage.h" #include "views/controls/native/native_view_host.h" #include "views/widget/root_view.h" @@ -97,9 +98,19 @@ TabContentsViewGtk::TabContentsViewGtk(TabContents* tab_contents) views::WidgetGtk(TYPE_CHILD), ignore_next_char_event_(false) { drag_source_.reset(new TabContentsDragSource(this)); + last_focused_view_storage_id_ = + views::ViewStorage::GetSharedInstance()->CreateStorageID(); } TabContentsViewGtk::~TabContentsViewGtk() { + // Make sure to remove any stored view we may still have in the ViewStorage. + // + // It is possible the view went away before us, so we only do this if the + // view is registered. + views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance(); + if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL) + view_storage->RemoveView(last_focused_view_storage_id_); + // Just deleting the object doesn't destroy the GtkWidget. We need to do that // manually, and synchronously, since subsequent signal handlers may expect // to locate this object. @@ -218,12 +229,48 @@ void TabContentsViewGtk::SetInitialFocus() { } void TabContentsViewGtk::StoreFocus() { - NOTIMPLEMENTED(); + views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance(); + + if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL) + view_storage->RemoveView(last_focused_view_storage_id_); + + views::FocusManager* focus_manager = + views::FocusManager::GetFocusManagerForNativeView(GetNativeView()); + if (focus_manager) { + // |focus_manager| can be NULL if the tab has been detached but still + // exists. + views::View* focused_view = focus_manager->GetFocusedView(); + if (focused_view) + view_storage->StoreView(last_focused_view_storage_id_, focused_view); + } } void TabContentsViewGtk::RestoreFocus() { - NOTIMPLEMENTED(); - SetInitialFocus(); + views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance(); + views::View* last_focused_view = + view_storage->RetrieveView(last_focused_view_storage_id_); + if (!last_focused_view) { + SetInitialFocus(); + } else { + views::FocusManager* focus_manager = + views::FocusManager::GetFocusManagerForNativeView(GetNativeView()); + + // If you hit this DCHECK, please report it to Jay (jcampan). + DCHECK(focus_manager != NULL) << "No focus manager when restoring focus."; + + if (last_focused_view->IsFocusable() && focus_manager && + focus_manager->ContainsView(last_focused_view)) { + last_focused_view->RequestFocus(); + } else { + // The focused view may not belong to the same window hierarchy (e.g. + // if the location bar was focused and the tab is dragged out), or it may + // no longer be focusable (e.g. if the location bar was focused and then + // we switched to fullscreen mode). In that case we default to the + // default focus. + SetInitialFocus(); + } + view_storage->RemoveView(last_focused_view_storage_id_); + } } void TabContentsViewGtk::UpdateDragCursor(WebDragOperation operation) { diff --git a/chrome/browser/views/tab_contents/tab_contents_view_gtk.h b/chrome/browser/views/tab_contents/tab_contents_view_gtk.h index 71fbdf6..8788468 100644 --- a/chrome/browser/views/tab_contents/tab_contents_view_gtk.h +++ b/chrome/browser/views/tab_contents/tab_contents_view_gtk.h @@ -81,6 +81,9 @@ class TabContentsViewGtk : public TabContentsView, // Whether to ignore the next CHAR keyboard event. bool ignore_next_char_event_; + // The id used in the ViewStorage to store the last focused view. + int last_focused_view_storage_id_; + // The context menu. Callbacks are asynchronous so we need to keep it around. scoped_ptr<RenderViewContextMenuWin> context_menu_; diff --git a/views/controls/native/native_view_host.cc b/views/controls/native/native_view_host.cc index e6637a9..9cbeaf7 100644 --- a/views/controls/native/native_view_host.cc +++ b/views/controls/native/native_view_host.cc @@ -33,6 +33,10 @@ NativeViewHost::~NativeViewHost() { void NativeViewHost::Attach(gfx::NativeView native_view) { DCHECK(!native_view_); native_view_ = native_view; + // If set_focus_view() has not been invoked, this view is the one that should + // be seen as focused when the native view receives focus. + if (!focus_view_) + focus_view_ = this; native_wrapper_->NativeViewAttached(); } diff --git a/views/controls/native/native_view_host.h b/views/controls/native/native_view_host.h index d34ccf9..679e176 100644 --- a/views/controls/native/native_view_host.h +++ b/views/controls/native/native_view_host.h @@ -71,12 +71,12 @@ class NativeViewHost : public View { virtual void Layout(); virtual void Paint(gfx::Canvas* canvas); virtual void VisibilityChanged(View* starting_from, bool is_visible); + virtual void Focus(); protected: virtual void VisibleBoundsInRootChanged(); virtual void ViewHierarchyChanged(bool is_add, View* parent, View* child); virtual std::string GetClassName() const; - virtual void Focus(); private: // The attached native view. diff --git a/views/controls/native/native_view_host_gtk.cc b/views/controls/native/native_view_host_gtk.cc index 5e91d18..306aa94 100644 --- a/views/controls/native/native_view_host_gtk.cc +++ b/views/controls/native/native_view_host_gtk.cc @@ -8,6 +8,7 @@ #include "base/logging.h" #include "views/controls/native/native_view_host.h" +#include "views/focus/focus_manager.h" #include "views/widget/widget_gtk.h" namespace views { @@ -19,6 +20,7 @@ NativeViewHostGtk::NativeViewHostGtk(NativeViewHost* host) : host_(host), installed_clip_(false), destroy_signal_id_(0), + focus_signal_id_(0), fixed_(NULL) { CreateFixed(false); } @@ -44,6 +46,12 @@ void NativeViewHostGtk::NativeViewAttached() { this); } + if (!focus_signal_id_) { + focus_signal_id_ = g_signal_connect(G_OBJECT(host_->native_view()), + "focus-in-event", + G_CALLBACK(CallFocusIn), this); + } + // Always layout though. host_->Layout(); @@ -61,8 +69,10 @@ void NativeViewHostGtk::NativeViewDetaching() { destroy_signal_id_); destroy_signal_id_ = 0; - // TODO(port): focus. - // FocusManager::UninstallFocusSubclass(native_view()); + g_signal_handler_disconnect(G_OBJECT(host_->native_view()), + focus_signal_id_); + focus_signal_id_ = 0; + installed_clip_ = false; // Release ownership back to the caller. @@ -154,7 +164,8 @@ void NativeViewHostGtk::HideWidget() { } void NativeViewHostGtk::SetFocus() { - NOTIMPLEMENTED(); + DCHECK(host_->native_view()); + gtk_widget_grab_focus(host_->native_view()); } //////////////////////////////////////////////////////////////////////////////// @@ -199,7 +210,20 @@ WidgetGtk* NativeViewHostGtk::GetHostWidget() const { // static void NativeViewHostGtk::CallDestroy(GtkObject* object, NativeViewHostGtk* host) { - return host->host_->NativeViewDestroyed(); + host->host_->NativeViewDestroyed(); +} + +// static +void NativeViewHostGtk::CallFocusIn(GtkWidget* widget, + GdkEventFocus* event, + NativeViewHostGtk* host) { + FocusManager* focus_manager = + FocusManager::GetFocusManagerForNativeView(widget); + if (!focus_manager) { + NOTREACHED(); + return; + } + focus_manager->SetFocusedView(host->host_->focus_view()); } //////////////////////////////////////////////////////////////////////////////// diff --git a/views/controls/native/native_view_host_gtk.h b/views/controls/native/native_view_host_gtk.h index 70cf438..81a2a7a1 100644 --- a/views/controls/native/native_view_host_gtk.h +++ b/views/controls/native/native_view_host_gtk.h @@ -54,6 +54,11 @@ class NativeViewHostGtk : public NativeViewHostWrapper { // Invoked from the 'destroy' signal. static void CallDestroy(GtkObject* object, NativeViewHostGtk* host); + // Invoked from the 'focus-in-event' signal. + static void CallFocusIn(GtkWidget* widget, + GdkEventFocus* event, + NativeViewHostGtk* button); + // Our associated NativeViewHost. NativeViewHost* host_; @@ -68,6 +73,9 @@ class NativeViewHostGtk : public NativeViewHostWrapper { // Signal handle id for 'destroy' signal. gulong destroy_signal_id_; + // Signal handle id for 'focus-in-event' signal. + gulong focus_signal_id_; + // The GtkFixed that contains the attached gfx::NativeView (used for // clipping). GtkWidget* fixed_; |