summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorestade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-18 18:32:07 +0000
committerestade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-18 18:32:07 +0000
commit1d1b0bcc55dba17158b241934ddbe16c22122e2e (patch)
tree29fb23fb26b6217cce189ed953e954b2484f5fc1 /chrome/browser
parent2e64450c701bed1243703071245a48e0233cbf33 (diff)
downloadchromium_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
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_gtk.cc69
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_gtk.h26
-rw-r--r--chrome/browser/tab_contents/web_contents_view_gtk.cc34
-rw-r--r--chrome/browser/tab_contents/web_contents_view_win.cc2
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