summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-17 04:23:00 +0000
committerben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-17 04:23:00 +0000
commit4c9471c16ba43fb40017e9f5fae8231799e86ccb (patch)
tree86d1f5ec140af9841b92108299208ca3e7fdfed7
parent061efec5fa1af222d72b887feb5788260cb5248f (diff)
downloadchromium_src-4c9471c16ba43fb40017e9f5fae8231799e86ccb.zip
chromium_src-4c9471c16ba43fb40017e9f5fae8231799e86ccb.tar.gz
chromium_src-4c9471c16ba43fb40017e9f5fae8231799e86ccb.tar.bz2
Fix build bustage by removing another dependency on browser/gtk by creating a new TabContentsViewGtk specifically for views. This subclasses WidgetGtk similar to how TabContentsViewWin subclasses WidgetWin.
There was a bug in NativeViewHostGtk - reparenting needs to be done atomically using gtk_widget_reparent since GtkWidgets are refcounted and when removed from a container are released, causing a crash when a TabContents is reparented. The code now compiles thanks to a stubbed BlockedPopupContainer, however there is one remaining issue - the browser window no longer paints and the app instantly hangs. However this is better than the current state so I figured I'd send the code review. Review URL: http://codereview.chromium.org/126107 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18588 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/views/tab_contents/render_view_context_menu_win.h2
-rw-r--r--chrome/browser/views/tab_contents/tab_contents_view_gtk.cc325
-rw-r--r--chrome/browser/views/tab_contents/tab_contents_view_gtk.h87
-rw-r--r--chrome/chrome.gyp13
-rw-r--r--views/controls/button/native_button_gtk.cc8
-rw-r--r--views/controls/button/native_button_gtk.h2
-rw-r--r--views/controls/native/native_view_host_gtk.cc66
-rw-r--r--views/controls/native/native_view_host_gtk.h14
-rw-r--r--views/widget/widget_gtk.cc103
-rw-r--r--views/widget/widget_gtk.h32
10 files changed, 540 insertions, 112 deletions
diff --git a/chrome/browser/views/tab_contents/render_view_context_menu_win.h b/chrome/browser/views/tab_contents/render_view_context_menu_win.h
index 1d4be70..e897e7e 100644
--- a/chrome/browser/views/tab_contents/render_view_context_menu_win.h
+++ b/chrome/browser/views/tab_contents/render_view_context_menu_win.h
@@ -28,7 +28,7 @@ class RenderViewContextMenuWin : public RenderViewContextMenu,
views::Accelerator* accelerator);
virtual void ExecuteCommand(int command_id);
- HMENU GetMenuHandle() const {
+ gfx::NativeMenu GetMenuHandle() const {
return (menu_.get() ? menu_->GetNativeMenu() : NULL);
}
diff --git a/chrome/browser/views/tab_contents/tab_contents_view_gtk.cc b/chrome/browser/views/tab_contents/tab_contents_view_gtk.cc
new file mode 100644
index 0000000..a4d8ad6
--- /dev/null
+++ b/chrome/browser/views/tab_contents/tab_contents_view_gtk.cc
@@ -0,0 +1,325 @@
+// 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 "chrome/browser/views/tab_contents/tab_contents_view_gtk.h"
+
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+#include "base/string_util.h"
+#include "base/gfx/point.h"
+#include "base/gfx/rect.h"
+#include "base/gfx/size.h"
+#include "build/build_config.h"
+#include "chrome/browser/blocked_popup_container.h"
+#include "chrome/browser/download/download_shelf.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/renderer_host/render_view_host_factory.h"
+#include "chrome/browser/renderer_host/render_widget_host_view_gtk.h"
+#include "chrome/browser/tab_contents/interstitial_page.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#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/controls/native/native_view_host.h"
+#include "views/widget/root_view.h"
+
+using WebKit::WebInputEvent;
+
+
+namespace {
+
+// Called when the content view gtk widget is tabbed to, or after the call to
+// gtk_widget_child_focus() in TakeFocus(). We return true
+// and grab focus if we don't have it. The call to
+// FocusThroughTabTraversal(bool) forwards the "move focus forward" effect to
+// webkit.
+gboolean OnFocus(GtkWidget* widget, GtkDirectionType focus,
+ TabContents* tab_contents) {
+ // If we already have focus, let the next widget have a shot at it. We will
+ // reach this situation after the call to gtk_widget_child_focus() in
+ // TakeFocus().
+ if (gtk_widget_is_focus(widget))
+ return FALSE;
+
+ gtk_widget_grab_focus(widget);
+ bool reverse = focus == GTK_DIR_TAB_BACKWARD;
+ tab_contents->FocusThroughTabTraversal(reverse);
+ return TRUE;
+}
+
+// Called when the mouse leaves the widget. We notify our delegate.
+gboolean OnLeaveNotify(GtkWidget* widget, GdkEventCrossing* event,
+ TabContents* tab_contents) {
+ if (tab_contents->delegate())
+ tab_contents->delegate()->ContentsMouseEvent(tab_contents, false);
+ return FALSE;
+}
+
+// Called when the mouse moves within the widget. We notify our delegate.
+gboolean OnMouseMove(GtkWidget* widget, GdkEventMotion* event,
+ TabContents* tab_contents) {
+ if (tab_contents->delegate())
+ tab_contents->delegate()->ContentsMouseEvent(tab_contents, true);
+ return FALSE;
+}
+
+// See tab_contents_view_win.cc for discussion of mouse scroll zooming.
+gboolean OnMouseScroll(GtkWidget* widget, GdkEventScroll* event,
+ TabContents* tab_contents) {
+ if ((event->state & gtk_accelerator_get_default_mod_mask()) ==
+ GDK_CONTROL_MASK) {
+ if (event->direction == GDK_SCROLL_DOWN) {
+ tab_contents->delegate()->ContentsZoomChange(false);
+ return TRUE;
+ } else if (event->direction == GDK_SCROLL_UP) {
+ tab_contents->delegate()->ContentsZoomChange(true);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+} // namespace
+
+// static
+TabContentsView* TabContentsView::Create(TabContents* tab_contents) {
+ return new TabContentsViewGtk(tab_contents);
+}
+
+TabContentsViewGtk::TabContentsViewGtk(TabContents* tab_contents)
+ : TabContentsView(tab_contents),
+ views::WidgetGtk(TYPE_CHILD),
+ ignore_next_char_event_(false) {
+}
+
+TabContentsViewGtk::~TabContentsViewGtk() {
+}
+
+void TabContentsViewGtk::CreateView() {
+ set_delete_on_destroy(false);
+ WidgetGtk::Init(NULL, gfx::Rect(), false);
+}
+
+RenderWidgetHostView* TabContentsViewGtk::CreateViewForWidget(
+ RenderWidgetHost* render_widget_host) {
+ if (render_widget_host->view()) {
+ // During testing, the view will already be set up in most cases to the
+ // test view, so we don't want to clobber it with a real one. To verify that
+ // this actually is happening (and somebody isn't accidentally creating the
+ // view twice), we check for the RVH Factory, which will be set when we're
+ // making special ones (which go along with the special views).
+ DCHECK(RenderViewHostFactory::has_factory());
+ return render_widget_host->view();
+ }
+
+ RenderWidgetHostViewGtk* view =
+ new RenderWidgetHostViewGtk(render_widget_host);
+ view->InitAsChild();
+ g_signal_connect(view->native_view(), "focus",
+ G_CALLBACK(OnFocus), tab_contents());
+/*
+ g_signal_connect(view->native_view(), "leave-notify-event",
+ G_CALLBACK(OnLeaveNotify), tab_contents());
+*/
+ g_signal_connect(view->native_view(), "motion-notify-event",
+ G_CALLBACK(OnMouseMove), tab_contents());
+ g_signal_connect(view->native_view(), "scroll-event",
+ G_CALLBACK(OnMouseScroll), tab_contents());
+ gtk_widget_add_events(view->native_view(), GDK_LEAVE_NOTIFY_MASK |
+ GDK_POINTER_MOTION_MASK);
+
+ gtk_fixed_put(GTK_FIXED(GetNativeView()), view->native_view(), 0, 0);
+ return view;
+}
+
+gfx::NativeView TabContentsViewGtk::GetNativeView() const {
+ return WidgetGtk::GetNativeView();
+}
+
+gfx::NativeView TabContentsViewGtk::GetContentNativeView() const {
+ if (!tab_contents()->render_widget_host_view())
+ return NULL;
+ return tab_contents()->render_widget_host_view()->GetNativeView();
+}
+
+gfx::NativeWindow TabContentsViewGtk::GetTopLevelNativeWindow() const {
+ GtkWidget* window = gtk_widget_get_ancestor(GetNativeView(), GTK_TYPE_WINDOW);
+ return window ? GTK_WINDOW(window) : NULL;
+}
+
+void TabContentsViewGtk::GetContainerBounds(gfx::Rect* out) const {
+ GetBounds(out, false);
+}
+
+void TabContentsViewGtk::StartDragging(const WebDropData& drop_data) {
+ NOTIMPLEMENTED();
+
+ // Until we have d'n'd implemented, just immediately pretend we're
+ // already done with the drag and drop so we don't get stuck
+ // thinking we're in mid-drag.
+ // TODO(port): remove me when the above NOTIMPLEMENTED is fixed.
+ if (tab_contents()->render_view_host())
+ tab_contents()->render_view_host()->DragSourceSystemDragEnded();
+}
+
+void TabContentsViewGtk::OnContentsDestroy() {
+ // TODO(brettw) this seems like maybe it can be moved into OnDestroy and this
+ // function can be deleted? If you're adding more here, consider whether it
+ // can be moved into OnDestroy which is a Windows message handler as the
+ // window is being torn down.
+
+ // When a tab is closed all its child plugin windows are destroyed
+ // automatically. This happens before plugins get any notification that its
+ // instances are tearing down.
+ //
+ // Plugins like Quicktime assume that their windows will remain valid as long
+ // as they have plugin instances active. Quicktime crashes in this case
+ // because its windowing code cleans up an internal data structure that the
+ // handler for NPP_DestroyStream relies on.
+ //
+ // The fix is to detach plugin windows from web contents when it is going
+ // away. This will prevent the plugin windows from getting destroyed
+ // automatically. The detached plugin windows will get cleaned up in proper
+ // sequence as part of the usual cleanup when the plugin instance goes away.
+ NOTIMPLEMENTED();
+}
+
+void TabContentsViewGtk::SetPageTitle(const std::wstring& title) {
+ // Set the window name to include the page title so it's easier to spot
+ // when debugging (e.g. via xwininfo -tree).
+ gfx::NativeView content_view = GetContentNativeView();
+ if (content_view && content_view->window)
+ gdk_window_set_title(content_view->window, WideToUTF8(title).c_str());
+}
+
+void TabContentsViewGtk::OnTabCrashed() {
+ NOTIMPLEMENTED();
+}
+
+void TabContentsViewGtk::SizeContents(const gfx::Size& size) {
+ // TODO(brettw) this is a hack and should be removed. See tab_contents_view.h.
+ WasSized(size);
+}
+
+void TabContentsViewGtk::Focus() {
+ if (tab_contents()->interstitial_page()) {
+ tab_contents()->interstitial_page()->Focus();
+ return;
+ }
+
+ if (sad_tab_.get()) {
+ sad_tab_->RequestFocus();
+ return;
+ }
+
+ RenderWidgetHostView* rwhv = tab_contents()->render_widget_host_view();
+ gtk_widget_grab_focus(rwhv ? rwhv->GetNativeView() : GetNativeView());
+}
+
+void TabContentsViewGtk::SetInitialFocus() {
+ if (tab_contents()->FocusLocationBarByDefault())
+ tab_contents()->delegate()->SetFocusToLocationBar();
+ else
+ Focus();
+}
+
+void TabContentsViewGtk::StoreFocus() {
+ NOTIMPLEMENTED();
+}
+
+void TabContentsViewGtk::RestoreFocus() {
+ NOTIMPLEMENTED();
+ SetInitialFocus();
+}
+
+void TabContentsViewGtk::UpdateDragCursor(bool is_drop_target) {
+ NOTIMPLEMENTED();
+}
+
+void TabContentsViewGtk::GotFocus() {
+ tab_contents()->delegate()->TabContentsFocused(tab_contents());
+}
+
+void TabContentsViewGtk::TakeFocus(bool reverse) {
+ // This is called when we the renderer asks us to take focus back (i.e., it
+ // has iterated past the last focusable element on the page).
+ gtk_widget_child_focus(GTK_WIDGET(GetTopLevelNativeWindow()),
+ reverse ? GTK_DIR_TAB_BACKWARD : GTK_DIR_TAB_FORWARD);
+}
+
+void TabContentsViewGtk::HandleKeyboardEvent(
+ const NativeWebKeyboardEvent& event) {
+ NOTIMPLEMENTED();
+ // TODO(port): could be an accelerator, pass to parent.
+}
+
+void TabContentsViewGtk::ShowContextMenu(const ContextMenuParams& params) {
+ // Allow delegates to handle the context menu operation first.
+ if (tab_contents()->delegate()->HandleContextMenu(params))
+ return;
+
+ context_menu_.reset(new RenderViewContextMenuWin(tab_contents(), params));
+ context_menu_->Init();
+
+ gfx::Point screen_point(params.x, params.y);
+ views::View::ConvertPointToScreen(GetRootView(), &screen_point);
+
+ // Enable recursive tasks on the message loop so we can get updates while
+ // the context menu is being displayed.
+ bool old_state = MessageLoop::current()->NestableTasksAllowed();
+ MessageLoop::current()->SetNestableTasksAllowed(true);
+ context_menu_->RunMenuAt(screen_point.x(), screen_point.y());
+ MessageLoop::current()->SetNestableTasksAllowed(old_state);
+}
+
+void TabContentsViewGtk::OnSizeAllocate(GtkWidget* widget,
+ GtkAllocation* allocation) {
+ WasSized(gfx::Size(allocation->width, allocation->height));
+}
+
+void TabContentsViewGtk::WasHidden() {
+ tab_contents()->HideContents();
+}
+
+void TabContentsViewGtk::WasShown() {
+ tab_contents()->ShowContents();
+}
+
+void TabContentsViewGtk::WasSized(const gfx::Size& size) {
+ if (tab_contents()->interstitial_page())
+ tab_contents()->interstitial_page()->SetSize(size);
+ if (tab_contents()->render_widget_host_view())
+ tab_contents()->render_widget_host_view()->SetSize(size);
+
+ // TODO(brettw) this function can probably be moved to this class.
+ tab_contents()->RepositionSupressedPopupsToFit();
+}
+
+// TODO(port): port BlockedPopupContainerViewWin...
+
+class BlockedPopupContainerViewGtk : public BlockedPopupContainerView {
+ public:
+ BlockedPopupContainerViewGtk() {}
+ virtual ~BlockedPopupContainerViewGtk() {}
+
+ // Overridden from BlockedPopupContainerView:
+ virtual void SetPosition() {}
+ virtual void ShowView() {}
+ virtual void UpdateLabel() {}
+ virtual void HideView() {}
+ virtual void Destroy() {
+ delete this;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BlockedPopupContainerViewGtk);
+};
+
+// static
+BlockedPopupContainerView* BlockedPopupContainerView::Create(
+ BlockedPopupContainer* container) {
+ return new BlockedPopupContainerViewGtk;
+}
diff --git a/chrome/browser/views/tab_contents/tab_contents_view_gtk.h b/chrome/browser/views/tab_contents/tab_contents_view_gtk.h
new file mode 100644
index 0000000..900fecc
--- /dev/null
+++ b/chrome/browser/views/tab_contents/tab_contents_view_gtk.h
@@ -0,0 +1,87 @@
+// 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.
+
+#ifndef CHROME_BROWSER_VIEWS_TAB_CONTENTS_TAB_CONTENTS_VIEW_GTK_H_
+#define CHROME_BROWSER_VIEWS_TAB_CONTENTS_TAB_CONTENTS_VIEW_GTK_H_
+
+#include "base/gfx/size.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/tab_contents/tab_contents_view.h"
+#include "views/widget/widget_gtk.h"
+
+class RenderViewContextMenuWin;
+class SadTabView;
+namespace views {
+class NativeViewHost;
+}
+
+// Gtk-specific implementation of the TabContentsView for the views-based front
+// end. It is a WidgetGtk that contains all of the contents of the tab and
+// associated child views.
+class TabContentsViewGtk : public TabContentsView,
+ public views::WidgetGtk {
+ public:
+ // The corresponding TabContents is passed in the constructor, and manages our
+ // lifetime. This doesn't need to be the case, but is this way currently
+ // because that's what was easiest when they were split.
+ explicit TabContentsViewGtk(TabContents* tab_contents);
+ virtual ~TabContentsViewGtk();
+
+ // TabContentsView implementation --------------------------------------------
+
+ virtual void CreateView();
+ virtual RenderWidgetHostView* CreateViewForWidget(
+ RenderWidgetHost* render_widget_host);
+ virtual gfx::NativeView GetNativeView() const;
+ virtual gfx::NativeView GetContentNativeView() const;
+ virtual gfx::NativeWindow GetTopLevelNativeWindow() const;
+ virtual void GetContainerBounds(gfx::Rect* out) const;
+ virtual void OnContentsDestroy();
+ virtual void SetPageTitle(const std::wstring& title);
+ virtual void OnTabCrashed();
+ virtual void SizeContents(const gfx::Size& size);
+ virtual void Focus();
+ virtual void SetInitialFocus();
+ virtual void StoreFocus();
+ virtual void RestoreFocus();
+
+ // Backend implementation of RenderViewHostDelegate::View.
+ virtual void ShowContextMenu(const ContextMenuParams& params);
+ virtual void StartDragging(const WebDropData& drop_data);
+ virtual void UpdateDragCursor(bool is_drop_target);
+ virtual void GotFocus();
+ virtual void TakeFocus(bool reverse);
+ virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event);
+
+ private:
+ // Signal handlers -----------------------------------------------------------
+
+ // Overridden from views::WidgetGtk:
+ virtual void OnSizeAllocate(GtkWidget* widget, GtkAllocation* allocation);
+
+ // Handles notifying the TabContents and other operations when the window was
+ // shown or hidden.
+ void WasHidden();
+ void WasShown();
+
+ // Handles resizing of the contents. This will notify the RenderWidgetHostView
+ // of the change, reposition popups, and the find in page bar.
+ void WasSized(const gfx::Size& size);
+
+ // ---------------------------------------------------------------------------
+
+ // Used to render the sad tab. This will be non-NULL only when the sad tab is
+ // visible.
+ scoped_ptr<SadTabView> sad_tab_;
+
+ // Whether to ignore the next CHAR keyboard event.
+ bool ignore_next_char_event_;
+
+ // The context menu. Callbacks are asynchronous so we need to keep it around.
+ scoped_ptr<RenderViewContextMenuWin> context_menu_;
+
+ DISALLOW_COPY_AND_ASSIGN(TabContentsViewGtk);
+};
+
+#endif // CHROME_BROWSER_VIEWS_TAB_CONTENTS_TAB_CONTENTS_VIEW_GTK_H_
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index a407299..18cef6d 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -1597,6 +1597,8 @@
'browser/views/tab_contents/render_view_context_menu_win.h',
'browser/views/tab_contents/render_view_context_menu_external_win.cc',
'browser/views/tab_contents/render_view_context_menu_external_win.h',
+ 'browser/views/tab_contents/tab_contents_view_gtk.cc',
+ 'browser/views/tab_contents/tab_contents_view_gtk.h',
'browser/views/tab_contents/tab_contents_view_win.cc',
'browser/views/tab_contents/tab_contents_view_win.h',
'browser/views/tabs/dragged_tab_controller.cc',
@@ -1890,8 +1892,12 @@
['include', '^browser/views/status_bubble_views.h'],
['include', '^browser/views/tab_contents/native_tab_contents_container_gtk.cc'],
['include', '^browser/views/tab_contents/native_tab_contents_container_gtk.h'],
+ ['include', '^browser/views/tab_contents/render_view_context_menu_win.cc'],
+ ['include', '^browser/views/tab_contents/render_view_context_menu_win.h'],
['include', '^browser/views/tab_contents/tab_contents_container.cc'],
['include', '^browser/views/tab_contents/tab_contents_container.h'],
+ ['include', '^browser/views/tab_contents/tab_contents_view_gtk.cc'],
+ ['include', '^browser/views/tab_contents/tab_contents_view_gtk.h'],
['include', '^browser/views/tab_icon_view.cc'],
['include', '^browser/views/tab_icon_view.h'],
['include', '^browser/views/tabs/dragged_tab_controller.cc'],
@@ -1932,6 +1938,13 @@
# More GTK stuff to exclude outside of the browser/gtk directory
['exclude', '^browser/bookmarks/bookmark_context_menu_gtk.cc'],
+
+ # Other excluded stuff.
+ ['exclude', '^browser/extensions/external_registry_extension_provider_win.cc'],
+ ['exclude', '^browser/tab_contents/tab_contents_view_gtk.cc'],
+ ['exclude', '^browser/tab_contents/tab_contents_view_gtk.h'],
+ ['exclude', '^browser/tab_contents/render_view_context_menu_gtk.cc'],
+ ['exclude', '^browser/tab_contents/render_view_context_menu_gtk.h'],
],
}],
['linux2==1',{
diff --git a/views/controls/button/native_button_gtk.cc b/views/controls/button/native_button_gtk.cc
index c97d1e0..1680019 100644
--- a/views/controls/button/native_button_gtk.cc
+++ b/views/controls/button/native_button_gtk.cc
@@ -83,7 +83,7 @@ gfx::Size NativeButtonGtk::GetPreferredSize() {
void NativeButtonGtk::CreateNativeControl() {
GtkWidget* widget = gtk_button_new();
g_signal_connect(G_OBJECT(widget), "clicked",
- G_CALLBACK(CallClicked), NULL);
+ G_CALLBACK(CallClicked), this);
NativeControlCreated(widget);
}
@@ -96,10 +96,8 @@ void NativeButtonGtk::NativeControlCreated(GtkWidget* widget) {
}
// static
-void NativeButtonGtk::CallClicked(GtkButton* widget) {
- View* view = NativeViewHostGtk::GetViewForNative(GTK_WIDGET(widget));
- if (view)
- static_cast<NativeButtonGtk*>(view)->OnClicked();
+void NativeButtonGtk::CallClicked(GtkButton* widget, NativeButtonGtk* button) {
+ button->OnClicked();
}
void NativeButtonGtk::OnClicked() {
diff --git a/views/controls/button/native_button_gtk.h b/views/controls/button/native_button_gtk.h
index e719202..6c3f600 100644
--- a/views/controls/button/native_button_gtk.h
+++ b/views/controls/button/native_button_gtk.h
@@ -36,7 +36,7 @@ class NativeButtonGtk : public NativeControlGtk, public NativeButtonWrapper {
virtual bool IsCheckbox() const { return false; }
private:
- static void CallClicked(GtkButton* widget);
+ static void CallClicked(GtkButton* widget, NativeButtonGtk* button);
// Invoked when the user clicks on the button.
void OnClicked();
diff --git a/views/controls/native/native_view_host_gtk.cc b/views/controls/native/native_view_host_gtk.cc
index 7f59144..6fa7325 100644
--- a/views/controls/native/native_view_host_gtk.cc
+++ b/views/controls/native/native_view_host_gtk.cc
@@ -24,47 +24,21 @@ NativeViewHostGtk::NativeViewHostGtk(NativeViewHost* host)
NativeViewHostGtk::~NativeViewHostGtk() {
}
-// static
-View* NativeViewHostGtk::GetViewForNative(GtkWidget* widget) {
- gpointer user_data = g_object_get_data(G_OBJECT(widget), "chrome-view");
- return static_cast<View*>(user_data);
-}
-
-// static
-void NativeViewHostGtk::SetViewForNative(GtkWidget* widget, View* view) {
- g_object_set_data(G_OBJECT(widget), "chrome-view", view);
-}
-
////////////////////////////////////////////////////////////////////////////////
// NativeViewHostGtk, NativeViewHostWrapper implementation:
void NativeViewHostGtk::NativeViewAttached() {
DCHECK(host_->native_view());
- GtkWidget* current_parent = gtk_widget_get_parent(host_->native_view());
- GtkWidget* new_parent = host_->GetWidget()->GetNativeView();
- // Only adjust the parent if the parent actually changed.
- if (current_parent != new_parent) {
- // First hide the new window. We don't want anything to draw (like sub-hwnd
- // borders), when we change the parent below.
- gtk_widget_hide(host_->native_view());
-
- if (current_parent) {
- gtk_container_remove(GTK_CONTAINER(current_parent),
- host_->native_view());
- }
-
- // Adds a mapping between the GtkWidget and us.
- SetViewForNative(host_->native_view(), host_);
-
- if (!destroy_signal_id_) {
- destroy_signal_id_ = g_signal_connect(G_OBJECT(host_->native_view()),
- "destroy", G_CALLBACK(CallDestroy),
- NULL);
- }
+ if (gtk_widget_get_parent(host_->native_view()))
+ GetHostWidget()->ReparentChild(host_->native_view());
+ else
+ GetHostWidget()->AddChild(host_->native_view());
- // Set the parent.
- static_cast<WidgetGtk*>(host_->GetWidget())->AddChild(host_->native_view());
+ if (!destroy_signal_id_) {
+ destroy_signal_id_ = g_signal_connect(G_OBJECT(host_->native_view()),
+ "destroy", G_CALLBACK(CallDestroy),
+ this);
}
// Always layout though.
@@ -88,9 +62,9 @@ void NativeViewHostGtk::NativeViewDetaching() {
void NativeViewHostGtk::AddedToWidget() {
if (!host_->native_view())
return;
- WidgetGtk* parent_widget = static_cast<WidgetGtk*>(host_->GetWidget());
+ WidgetGtk* parent_widget = GetHostWidget();
GtkWidget* widget_parent = gtk_widget_get_parent(host_->native_view());
- GtkWidget* parent_widget_widget = parent_widget->child_widget_parent();
+ GtkWidget* parent_widget_widget = parent_widget->window_contents();
if (widget_parent != parent_widget_widget) {
g_object_ref(host_->native_view());
if (widget_parent)
@@ -110,10 +84,10 @@ void NativeViewHostGtk::RemovedFromWidget() {
if (!host_->native_view())
return;
- WidgetGtk* parent_widget = static_cast<WidgetGtk*>(host_->GetWidget());
+ WidgetGtk* parent_widget = GetHostWidget();
gtk_widget_hide(host_->native_view());
if (parent_widget) {
- gtk_container_remove(GTK_CONTAINER(parent_widget->child_widget_parent()),
+ gtk_container_remove(GTK_CONTAINER(parent_widget->window_contents()),
host_->native_view());
}
}
@@ -157,8 +131,7 @@ void NativeViewHostGtk::UninstallClip() {
}
void NativeViewHostGtk::ShowWidget(int x, int y, int w, int h) {
- WidgetGtk* parent = static_cast<WidgetGtk*>(host_->GetWidget());
- parent->PositionChild(host_->native_view(), x, y, w, h);
+ GetHostWidget()->PositionChild(host_->native_view(), x, y, w, h);
gtk_widget_show(host_->native_view());
}
@@ -173,13 +146,14 @@ void NativeViewHostGtk::SetFocus() {
////////////////////////////////////////////////////////////////////////////////
// NativeViewHostGtk, private:
-// static
-void NativeViewHostGtk::CallDestroy(GtkObject* object) {
- View* view = GetViewForNative(GTK_WIDGET(object));
- if (!view)
- return;
+WidgetGtk* NativeViewHostGtk::GetHostWidget() const {
+ return static_cast<WidgetGtk*>(host_->GetWidget());
+}
- return static_cast<NativeViewHost*>(view)->NativeViewDestroyed();
+// static
+void NativeViewHostGtk::CallDestroy(GtkObject* object,
+ NativeViewHostGtk* host) {
+ return host->host_->NativeViewDestroyed();
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/views/controls/native/native_view_host_gtk.h b/views/controls/native/native_view_host_gtk.h
index 40a6a65..154da70 100644
--- a/views/controls/native/native_view_host_gtk.h
+++ b/views/controls/native/native_view_host_gtk.h
@@ -14,17 +14,13 @@
namespace views {
class View;
+class WidgetGtk;
class NativeViewHostGtk : public NativeViewHostWrapper {
public:
explicit NativeViewHostGtk(NativeViewHost* host);
virtual ~NativeViewHostGtk();
- // Sets and retrieves the View associated with a particular widget.
- // TODO(beng): move to NativeViewHost, and have take gfx::NativeViews.
- static View* GetViewForNative(GtkWidget* widget);
- static void SetViewForNative(GtkWidget* widget, View* view);
-
// Overridden from NativeViewHostWrapper:
virtual void NativeViewAttached();
virtual void NativeViewDetaching();
@@ -38,6 +34,11 @@ class NativeViewHostGtk : public NativeViewHostWrapper {
virtual void SetFocus();
private:
+ WidgetGtk* GetHostWidget() const;
+
+ // Invoked from the 'destroy' signal.
+ static void CallDestroy(GtkObject* object, NativeViewHostGtk* host);
+
// Our associated NativeViewHost.
NativeViewHost* host_;
@@ -48,9 +49,6 @@ class NativeViewHostGtk : public NativeViewHostWrapper {
// Signal handle id for 'destroy' signal.
gulong destroy_signal_id_;
- // Invoked from the 'destroy' signal.
- static void CallDestroy(GtkObject* object);
-
DISALLOW_COPY_AND_ASSIGN(NativeViewHostGtk);
};
diff --git a/views/widget/widget_gtk.cc b/views/widget/widget_gtk.cc
index 7d7e74b..1aec6a4 100644
--- a/views/widget/widget_gtk.cc
+++ b/views/widget/widget_gtk.cc
@@ -53,6 +53,9 @@ static int GetFlagsForEventButton(const GdkEventButton& event) {
return flags;
}
+// static
+GtkWidget* WidgetGtk::null_parent_ = NULL;
+
////////////////////////////////////////////////////////////////////////////////
// WidgetGtk, public:
@@ -60,7 +63,7 @@ WidgetGtk::WidgetGtk(Type type)
: is_window_(false),
type_(type),
widget_(NULL),
- child_widget_parent_(NULL),
+ window_contents_(NULL),
is_mouse_down_(false),
has_capture_(false),
last_mouse_event_was_move_(false),
@@ -84,7 +87,7 @@ void WidgetGtk::Init(GtkWidget* parent,
#endif
// Make container here.
- CreateGtkWidget();
+ CreateGtkWidget(parent);
// Make sure we receive our motion events.
@@ -92,7 +95,7 @@ void WidgetGtk::Init(GtkWidget* parent,
// minimum we need painting to happen on the parent (otherwise painting
// doesn't work at all), and similarly we need mouse release events on the
// parent as windows don't get mouse releases.
- gtk_widget_add_events(child_widget_parent_,
+ gtk_widget_add_events(window_contents_,
GDK_ENTER_NOTIFY_MASK |
GDK_LEAVE_NOTIFY_MASK |
GDK_BUTTON_PRESS_MASK |
@@ -109,33 +112,34 @@ void WidgetGtk::Init(GtkWidget* parent,
MessageLoopForUI::current()->AddObserver(this);
- g_signal_connect_after(G_OBJECT(child_widget_parent_), "size_allocate",
+ // TODO(beng): make these take this rather than NULL.
+ g_signal_connect_after(G_OBJECT(window_contents_), "size_allocate",
G_CALLBACK(CallSizeAllocate), NULL);
- g_signal_connect(G_OBJECT(child_widget_parent_), "expose_event",
+ g_signal_connect(G_OBJECT(window_contents_), "expose_event",
G_CALLBACK(CallPaint), NULL);
- g_signal_connect(G_OBJECT(child_widget_parent_), "enter_notify_event",
+ g_signal_connect(G_OBJECT(window_contents_), "enter_notify_event",
G_CALLBACK(CallEnterNotify), NULL);
- g_signal_connect(G_OBJECT(child_widget_parent_), "leave_notify_event",
+ g_signal_connect(G_OBJECT(window_contents_), "leave_notify_event",
G_CALLBACK(CallLeaveNotify), NULL);
- g_signal_connect(G_OBJECT(child_widget_parent_), "motion_notify_event",
+ g_signal_connect(G_OBJECT(window_contents_), "motion_notify_event",
G_CALLBACK(CallMotionNotify), NULL);
- g_signal_connect(G_OBJECT(child_widget_parent_), "button_press_event",
+ g_signal_connect(G_OBJECT(window_contents_), "button_press_event",
G_CALLBACK(CallButtonPress), NULL);
- g_signal_connect(G_OBJECT(child_widget_parent_), "button_release_event",
+ g_signal_connect(G_OBJECT(window_contents_), "button_release_event",
G_CALLBACK(CallButtonRelease), NULL);
- g_signal_connect(G_OBJECT(child_widget_parent_), "grab_broken_event",
+ g_signal_connect(G_OBJECT(window_contents_), "focus_out_event",
+ G_CALLBACK(CallFocusOut), NULL);
+ g_signal_connect(G_OBJECT(window_contents_), "grab_broken_event",
G_CALLBACK(CallGrabBrokeEvent), NULL);
- g_signal_connect(G_OBJECT(child_widget_parent_), "grab_notify",
+ g_signal_connect(G_OBJECT(window_contents_), "grab_notify",
G_CALLBACK(CallGrabNotify), NULL);
- g_signal_connect(G_OBJECT(child_widget_parent_), "focus_out_event",
- G_CALLBACK(CallFocusOut), NULL);
- g_signal_connect(G_OBJECT(child_widget_parent_), "key_press_event",
+ g_signal_connect(G_OBJECT(window_contents_), "key_press_event",
G_CALLBACK(CallKeyPress), NULL);
- g_signal_connect(G_OBJECT(child_widget_parent_), "key_release_event",
+ g_signal_connect(G_OBJECT(window_contents_), "key_release_event",
G_CALLBACK(CallKeyRelease), NULL);
- g_signal_connect(G_OBJECT(child_widget_parent_), "scroll_event",
+ g_signal_connect(G_OBJECT(window_contents_), "scroll_event",
G_CALLBACK(CallScroll), NULL);
- g_signal_connect(G_OBJECT(child_widget_parent_), "visibility_notify_event",
+ g_signal_connect(G_OBJECT(window_contents_), "visibility_notify_event",
G_CALLBACK(CallVisibilityNotify), NULL);
// In order to receive notification when the window is no longer the front
@@ -167,10 +171,12 @@ void WidgetGtk::Init(GtkWidget* parent,
tooltip_manager_.reset(new TooltipManagerGtk(this));
if (type_ == TYPE_CHILD) {
- WidgetGtk* parent_widget = GetViewForNative(parent);
- parent_widget->AddChild(widget_);
- parent_widget->PositionChild(widget_, bounds.x(), bounds.y(),
- bounds.width(), bounds.height());
+ if (parent) {
+ WidgetGtk* parent_widget = GetViewForNative(parent);
+ parent_widget->AddChild(widget_);
+ parent_widget->PositionChild(widget_, bounds.x(), bounds.y(),
+ bounds.width(), bounds.height());
+ }
} else {
if (bounds.width() > 0 && bounds.height() > 0)
gtk_window_resize(GTK_WINDOW(widget_), bounds.width(), bounds.height());
@@ -199,11 +205,15 @@ bool WidgetGtk::MakeTransparent() {
}
void WidgetGtk::AddChild(GtkWidget* child) {
- gtk_container_add(GTK_CONTAINER(child_widget_parent_), child);
+ gtk_container_add(GTK_CONTAINER(window_contents_), child);
}
void WidgetGtk::RemoveChild(GtkWidget* child) {
- gtk_container_remove(GTK_CONTAINER(child_widget_parent_), child);
+ gtk_container_remove(GTK_CONTAINER(window_contents_), child);
+}
+
+void WidgetGtk::ReparentChild(GtkWidget* child) {
+ gtk_widget_reparent(child, window_contents_);
}
void WidgetGtk::PositionChild(GtkWidget* child, int x, int y, int w, int h) {
@@ -211,7 +221,7 @@ void WidgetGtk::PositionChild(GtkWidget* child, int x, int y, int w, int h) {
// For some reason we need to do both of these to size a widget.
gtk_widget_size_allocate(child, &alloc);
gtk_widget_set_size_request(child, w, h);
- gtk_fixed_move(GTK_FIXED(child_widget_parent_), child, x, y);
+ gtk_fixed_move(GTK_FIXED(window_contents_), child, x, y);
}
void WidgetGtk::SetContentsView(View* view) {
@@ -389,10 +399,17 @@ void WidgetGtk::DidProcessEvent(GdkEvent* event) {
////////////////////////////////////////////////////////////////////////////////
// TODO(beng): organize into sections:
-void WidgetGtk::CreateGtkWidget() {
+void WidgetGtk::CreateGtkWidget(GtkWidget* parent) {
if (type_ == TYPE_CHILD) {
- child_widget_parent_ = widget_ = gtk_fixed_new();
+ window_contents_ = widget_ = gtk_fixed_new();
gtk_fixed_set_has_window(GTK_FIXED(widget_), true);
+ if (!parent && !null_parent_) {
+ GtkWidget* popup = gtk_window_new(GTK_WINDOW_POPUP);
+ null_parent_ = gtk_fixed_new();
+ gtk_container_add(GTK_CONTAINER(popup), null_parent_);
+ gtk_widget_realize(null_parent_);
+ }
+ gtk_container_add(GTK_CONTAINER(parent ? parent : null_parent_), widget_);
SetViewForNative(widget_, this);
} else {
widget_ = gtk_window_new(
@@ -403,16 +420,15 @@ void WidgetGtk::CreateGtkWidget() {
SetWindowForNative(widget_, static_cast<WindowGtk*>(this));
SetViewForNative(widget_, this);
- child_widget_parent_ = gtk_fixed_new();
- gtk_fixed_set_has_window(GTK_FIXED(child_widget_parent_), true);
- gtk_container_add(GTK_CONTAINER(widget_), child_widget_parent_);
- gtk_widget_show(child_widget_parent_);
- SetViewForNative(child_widget_parent_, this);
+ window_contents_ = gtk_fixed_new();
+ gtk_fixed_set_has_window(GTK_FIXED(window_contents_), true);
+ gtk_container_add(GTK_CONTAINER(widget_), window_contents_);
+ gtk_widget_show(window_contents_);
+ SetViewForNative(window_contents_, this);
if (transparent_)
ConfigureWidgetForTransparentBackground();
}
-
// The widget needs to be realized before handlers like size-allocate can
// function properly.
gtk_widget_realize(widget_);
@@ -500,12 +516,12 @@ gboolean WidgetGtk::OnGrabBrokeEvent(GtkWidget* widget, GdkEvent* event) {
}
void WidgetGtk::OnGrabNotify(GtkWidget* widget, gboolean was_grabbed) {
- gtk_grab_remove(child_widget_parent_);
+ gtk_grab_remove(window_contents_);
HandleGrabBroke();
}
void WidgetGtk::OnDestroy(GtkWidget* widget) {
- widget_ = child_widget_parent_ = NULL;
+ widget_ = window_contents_ = NULL;
root_view_->OnWidgetDestroyed();
if (delete_on_destroy_)
delete this;
@@ -564,7 +580,7 @@ bool WidgetGtk::ProcessMousePressed(GdkEventButton* event) {
is_mouse_down_ = true;
if (!has_capture_) {
has_capture_ = true;
- gtk_grab_add(child_widget_parent_);
+ gtk_grab_add(window_contents_);
}
return true;
}
@@ -581,7 +597,7 @@ void WidgetGtk::ProcessMouseReleased(GdkEventButton* event) {
if (has_capture_ && ReleaseCaptureOnMouseReleased()) {
has_capture_ = false;
- gtk_grab_remove(child_widget_parent_);
+ gtk_grab_remove(window_contents_);
}
is_mouse_down_ = false;
root_view_->OnMouseReleased(mouse_up, false);
@@ -763,8 +779,7 @@ Window* WidgetGtk::GetWindowImpl(GtkWidget* widget) {
}
void WidgetGtk::ConfigureWidgetForTransparentBackground() {
- DCHECK(widget_ && child_widget_parent_ &&
- widget_ != child_widget_parent_);
+ DCHECK(widget_ && window_contents_ && widget_ != window_contents_);
GdkColormap* rgba_colormap =
gdk_screen_get_rgba_colormap(gdk_screen_get_default());
@@ -785,12 +800,12 @@ void WidgetGtk::ConfigureWidgetForTransparentBackground() {
// Widget must be realized before setting pixmap.
gdk_window_set_back_pixmap(widget_->window, NULL, FALSE);
- gtk_widget_set_colormap(child_widget_parent_, rgba_colormap);
- gtk_widget_set_app_paintable(child_widget_parent_, true);
- GTK_WIDGET_UNSET_FLAGS(child_widget_parent_, GTK_DOUBLE_BUFFERED);
- gtk_widget_realize(child_widget_parent_);
+ gtk_widget_set_colormap(window_contents_, rgba_colormap);
+ gtk_widget_set_app_paintable(window_contents_, true);
+ GTK_WIDGET_UNSET_FLAGS(window_contents_, GTK_DOUBLE_BUFFERED);
+ gtk_widget_realize(window_contents_);
// Widget must be realized before setting pixmap.
- gdk_window_set_back_pixmap(child_widget_parent_->window, NULL, FALSE);
+ gdk_window_set_back_pixmap(window_contents_->window, NULL, FALSE);
}
void WidgetGtk::HandleGrabBroke() {
diff --git a/views/widget/widget_gtk.h b/views/widget/widget_gtk.h
index 2442f74..b5dd6a0 100644
--- a/views/widget/widget_gtk.h
+++ b/views/widget/widget_gtk.h
@@ -56,15 +56,25 @@ class WidgetGtk : public Widget, public MessageLoopForUI::Observer {
delete_on_destroy_ = delete_on_destroy;
}
+ // Adds and removes the specified widget as a child of this widget's contents.
+ // These methods make sure to add the widget to the window's contents
+ // container if this widget is a window.
void AddChild(GtkWidget* child);
void RemoveChild(GtkWidget* child);
+ // A safe way to reparent a child widget to this widget. Calls
+ // gtk_widget_reparent which handles refcounting to avoid destroying the
+ // widget when removing it from its old parent.
+ void ReparentChild(GtkWidget* child);
+
// Positions a child GtkWidget at the specified location and bounds.
void PositionChild(GtkWidget* child, int x, int y, int w, int h);
- // Parent GtkWidget all children are added to. This is not necessarily
- // the same as returned by GetNativeView.
- GtkWidget* child_widget_parent() const { return child_widget_parent_; }
+ // Parent GtkWidget all children are added to. When this WidgetGtk corresponds
+ // to a top level window, this is the GtkFixed within the GtkWindow, not the
+ // GtkWindow itself. For child widgets, this is the same GtkFixed as
+ // |widget_|.
+ GtkWidget* window_contents() const { return window_contents_; }
virtual void SetContentsView(View* view);
@@ -174,7 +184,10 @@ class WidgetGtk : public Widget, public MessageLoopForUI::Observer {
static Window* GetWindowImpl(GtkWidget* widget);
// Creates the GtkWidget.
- void CreateGtkWidget();
+ void CreateGtkWidget(GtkWidget* parent);
+
+ // Attaches the widget contents to the window's widget.
+ void AttachGtkWidgetToWindow();
// Invoked from create widget to enable the various bits needed for a
// transparent background. This is only invoked if MakeTransparent has been
@@ -186,10 +199,15 @@ class WidgetGtk : public Widget, public MessageLoopForUI::Observer {
const Type type_;
// Our native views. If we're a window/popup, then widget_ is the window and
- // child_widget_parent_ is a GtkFixed. If we're not a window/popup, then
- // widget_ and child_widget_parent_ are a GtkFixed.
+ // window_contents_ is a GtkFixed. If we're not a window/popup, then widget_
+ // and window_contents_ point to the same GtkFixed.
GtkWidget* widget_;
- GtkWidget* child_widget_parent_;
+ GtkWidget* window_contents_;
+
+ // Child GtkWidgets created with no parent need to be parented to a valid top
+ // level window otherwise Gtk throws a fit. |null_parent_| is an invisible
+ // popup that such GtkWidgets are parented to.
+ static GtkWidget* null_parent_;
// The root of the View hierarchy attached to this window.
scoped_ptr<RootView> root_view_;