diff options
author | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-18 18:32:07 +0000 |
---|---|---|
committer | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-18 18:32:07 +0000 |
commit | 1d1b0bcc55dba17158b241934ddbe16c22122e2e (patch) | |
tree | 29fb23fb26b6217cce189ed953e954b2484f5fc1 | |
parent | 2e64450c701bed1243703071245a48e0233cbf33 (diff) | |
download | chromium_src-1d1b0bcc55dba17158b241934ddbe16c22122e2e.zip chromium_src-1d1b0bcc55dba17158b241934ddbe16c22122e2e.tar.gz chromium_src-1d1b0bcc55dba17158b241934ddbe16c22122e2e.tar.bz2 |
Implement GTK dropdown menus.
These are used for <select> html items, for example.
Review URL: http://codereview.chromium.org/48054
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@11991 0039d316-1c4b-4281-b951-d872f2087c98
4 files changed, 108 insertions, 23 deletions
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 166db75..bb238f7 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc +++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc @@ -79,7 +79,7 @@ class RenderWidgetHostViewGtkWidget { NativeWebKeyboardEvent wke(event); host_view->GetRenderWidgetHost()->ForwardKeyboardEvent(wke); // We return TRUE because we did handle the event. If it turns out webkit - // can't handle the event, we'll deal with in + // can't handle the event, we'll deal with it in // RenderView::UnhandledKeyboardEvent(). return TRUE; } @@ -92,6 +92,9 @@ class RenderWidgetHostViewGtkWidget { static gboolean FocusOut(GtkWidget* widget, GdkEventFocus* focus, RenderWidgetHostViewGtk* host_view) { + // Whenever we lose focus, set the cursor back to that of our parent window, + // which should be the default arrow. + gdk_window_set_cursor(widget->window, NULL); host_view->GetRenderWidgetHost()->Blur(); return FALSE; } @@ -127,6 +130,12 @@ class RenderWidgetHostViewGtkWidget { DISALLOW_IMPLICIT_CONSTRUCTORS(RenderWidgetHostViewGtkWidget); }; +gboolean OnPopupParentFocusOut(GtkWidget* parent, GdkEventFocus* focus, + RenderWidgetHost* host) { + host->Shutdown(); + return FALSE; +} + } // namespace // static @@ -136,18 +145,50 @@ RenderWidgetHostView* RenderWidgetHostView::CreateViewForWidget( } RenderWidgetHostViewGtk::RenderWidgetHostViewGtk(RenderWidgetHost* widget_host) - : host_(widget_host) { + : host_(widget_host), + parent_host_view_(NULL), + parent_(NULL), + popup_signal_id_(0), + activatable_(true) { host_->set_view(this); - // BUG 8707: We will live in some container (in this case in WebContents). - // We want to destroy during Destroy(), independent of how we are managed in - // any containers. We need to sink the reference here to "own" the widget so - // it can be added and removed from containers without being destroyed. - view_.Own(RenderWidgetHostViewGtkWidget::CreateNewWidget(this)); } RenderWidgetHostViewGtk::~RenderWidgetHostViewGtk() { } +void RenderWidgetHostViewGtk::InitAsChild() { + view_.Own(RenderWidgetHostViewGtkWidget::CreateNewWidget(this)); + gtk_widget_show(view_.get()); +} + +void RenderWidgetHostViewGtk::InitAsPopup( + RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) { + parent_host_view_ = parent_host_view; + parent_ = parent_host_view->GetPluginNativeView(); + GtkWidget* popup = gtk_window_new(GTK_WINDOW_POPUP); + view_.Own(RenderWidgetHostViewGtkWidget::CreateNewWidget(this)); + gtk_container_add(GTK_CONTAINER(popup), view_.get()); + + // If we are not activatable, we don't want to grab keyboard input, + // and webkit will manage our destruction. + if (activatable_) { + // Grab all input for the app. If a click lands outside the bounds of the + // popup, WebKit will notice and destroy us. + gtk_grab_add(view_.get()); + // We also destroy ourselves if our parent loses focus. + popup_signal_id_ = g_signal_connect(parent_, "focus-out-event", + G_CALLBACK(OnPopupParentFocusOut), host_); + // Our parent widget actually keeps GTK focus within its window, but we have + // to make the webkit selection box disappear to maintain appearances. + parent_host_view->Blur(); + } + + gtk_window_set_default_size(GTK_WINDOW(popup), + pos.width(), pos.height()); + gtk_widget_show_all(popup); + gtk_window_move(GTK_WINDOW(popup), pos.x(), pos.y()); +} + void RenderWidgetHostViewGtk::DidBecomeSelected() { NOTIMPLEMENTED(); } @@ -176,11 +217,11 @@ void RenderWidgetHostViewGtk::MovePluginWindows( } void RenderWidgetHostViewGtk::Focus() { - NOTIMPLEMENTED(); + host_->Focus(); } void RenderWidgetHostViewGtk::Blur() { - NOTIMPLEMENTED(); + host_->Blur(); } bool RenderWidgetHostViewGtk::HasFocus() { @@ -257,6 +298,16 @@ void RenderWidgetHostViewGtk::RenderViewGone() { } void RenderWidgetHostViewGtk::Destroy() { + // If |parent_| is non-null, we are a popup and we must disconnect from our + // parent and destroy the popup window. + if (parent_) { + if (activatable_) { + g_signal_handler_disconnect(parent_, popup_signal_id_); + parent_host_view_->Focus(); + } + gtk_widget_destroy(gtk_widget_get_parent(view_.get())); + } + // We need to disconnect ourselves from our parent widget at this time; this // does the right thing, automatically removing ourselves from our parent // container. diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.h b/chrome/browser/renderer_host/render_widget_host_view_gtk.h index 3cf06b1..e045213 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_gtk.h +++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.h @@ -22,6 +22,17 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView { RenderWidgetHostViewGtk(RenderWidgetHost* widget); ~RenderWidgetHostViewGtk(); + // Initialize this object for use as a drawing area. + void InitAsChild(); + + // Initialize this object for use as a popup (e.g. HTML dropdown menu). + void InitAsPopup(RenderWidgetHostView* parent_host_view, + const gfx::Rect& pos); + + // TODO(estade): unfork this with RenderWidgetHostViewWin function of same + // name. + void set_activatable(bool activatable) { activatable_ = activatable; } + // --------------------------------------------------------------------------- // Implementation of RenderWidgetHostView... @@ -60,6 +71,21 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView { RenderWidgetHost *const host_; // The native UI widget. OwnedWidgetGtk view_; + // Variables used only for popups -------------------------------------------- + // Our parent widget. + RenderWidgetHostView* parent_host_view_; + // The native view of our parent, equivalent to + // parent_host_view_->GetPluginNativeView(). + GtkWidget* parent_; + // We connect to the parent's focus out event. When we are destroyed, we need + // to remove this handler, so we must keep track of its id. + gulong popup_signal_id_; + // This variable determines our degree of control over user input. If we are + // activatable, we must grab and handle all user input. If we are not + // activatable, then our parent render view retains more control. Example of + // activatable popup: <select> dropdown. Example of non-activatable popup: + // form autocomplete. + bool activatable_; // The cursor for the page. This is passed up from the renderer. WebCursor current_cursor_; diff --git a/chrome/browser/tab_contents/web_contents_view_gtk.cc b/chrome/browser/tab_contents/web_contents_view_gtk.cc index 8bfde32..dbb8bc9 100644 --- a/chrome/browser/tab_contents/web_contents_view_gtk.cc +++ b/chrome/browser/tab_contents/web_contents_view_gtk.cc @@ -36,13 +36,6 @@ gboolean OnFocus(GtkWidget* widget, GtkDirectionType focus, return TRUE; } -// Whenever we lose focus, set the cursor back to that of our parent window, -// which should be the default arrow. -gboolean OnFocusOut(GtkWidget* widget, GdkEventFocus* event, void*) { - gdk_window_set_cursor(widget->window, NULL); - return FALSE; -} - // Callback used in WebContentsViewGtk::CreateViewForWidget(). void RemoveWidget(GtkWidget* widget, gpointer container) { gtk_container_remove(GTK_CONTAINER(container), widget); @@ -77,11 +70,9 @@ RenderWidgetHostView* WebContentsViewGtk::CreateViewForWidget( DCHECK(!render_widget_host->view()); RenderWidgetHostViewGtk* view = new RenderWidgetHostViewGtk(render_widget_host); - gtk_widget_show(view->native_view()); + view->InitAsChild(); g_signal_connect(view->native_view(), "focus", G_CALLBACK(OnFocus), web_contents_); - g_signal_connect(view->native_view(), "focus-out-event", - G_CALLBACK(OnFocusOut), NULL); gtk_container_foreach(GTK_CONTAINER(vbox_.get()), RemoveWidget, vbox_.get()); gtk_box_pack_start(GTK_BOX(vbox_.get()), view->native_view(), TRUE, TRUE, 0); return view; @@ -193,11 +184,17 @@ WebContents* WebContentsViewGtk::CreateNewWindowInternal( return NULL; } +// TODO(estade): unfork this from the version in web_contents_view_win. RenderWidgetHostView* WebContentsViewGtk::CreateNewWidgetInternal( int route_id, bool activatable) { - NOTIMPLEMENTED(); - return NULL; + RenderWidgetHost* widget_host = + new RenderWidgetHost(web_contents_->process(), route_id); + RenderWidgetHostViewGtk* widget_view = + new RenderWidgetHostViewGtk(widget_host); + widget_view->set_activatable(activatable); + + return widget_view; } void WebContentsViewGtk::ShowCreatedWindowInternal( @@ -208,8 +205,19 @@ void WebContentsViewGtk::ShowCreatedWindowInternal( NOTIMPLEMENTED(); } +// TODO(estade): unfork this from the version in web_contents_view_win. void WebContentsViewGtk::ShowCreatedWidgetInternal( RenderWidgetHostView* widget_host_view, const gfx::Rect& initial_pos) { - NOTIMPLEMENTED(); + RenderWidgetHostViewGtk* widget_host_view_gtk = + static_cast<RenderWidgetHostViewGtk*>(widget_host_view); + + RenderWidgetHost* widget_host = widget_host_view->GetRenderWidgetHost(); + if (!widget_host->process()->channel()) { + // The view has gone away or the renderer crashed. Nothing to do. + return; + } + + widget_host_view_gtk->InitAsPopup( + web_contents_->render_widget_host_view(), initial_pos); } diff --git a/chrome/browser/tab_contents/web_contents_view_win.cc b/chrome/browser/tab_contents/web_contents_view_win.cc index 6ce86db..0446368 100644 --- a/chrome/browser/tab_contents/web_contents_view_win.cc +++ b/chrome/browser/tab_contents/web_contents_view_win.cc @@ -402,7 +402,7 @@ RenderWidgetHostView* WebContentsViewWin::CreateNewWidgetInternal( RenderWidgetHostViewWin* widget_view = new RenderWidgetHostViewWin(widget_host); - // We set the parent HWDN explicitly as pop-up HWNDs are parented and owned by + // We set the parent HWND explicitly as pop-up HWNDs are parented and owned by // the first non-child HWND of the HWND that was specified to the CreateWindow // call. // TODO(brettw) this should not need to get the current RVHView from the |