summaryrefslogtreecommitdiffstats
path: root/views
diff options
context:
space:
mode:
Diffstat (limited to 'views')
-rw-r--r--views/controls/button/native_button_gtk.cc13
-rw-r--r--views/controls/button/native_button_gtk.h6
-rw-r--r--views/controls/native/native_view_host.cc18
-rw-r--r--views/controls/native/native_view_host_gtk.cc152
-rw-r--r--views/controls/native/native_view_host_gtk.h24
-rw-r--r--views/controls/native_control_gtk.cc2
-rw-r--r--views/widget/widget_gtk.cc14
-rw-r--r--views/widget/widget_gtk.h2
8 files changed, 156 insertions, 75 deletions
diff --git a/views/controls/button/native_button_gtk.cc b/views/controls/button/native_button_gtk.cc
index 1680019..7bd4da6 100644
--- a/views/controls/button/native_button_gtk.cc
+++ b/views/controls/button/native_button_gtk.cc
@@ -34,6 +34,7 @@ void NativeButtonGtk::UpdateLabel() {
gtk_button_set_label(GTK_BUTTON(native_view()),
WideToUTF8(native_button_->label()).c_str());
+ preferred_size_ = gfx::Size();
}
void NativeButtonGtk::UpdateFont() {
@@ -41,6 +42,7 @@ void NativeButtonGtk::UpdateFont() {
return;
NOTIMPLEMENTED();
+ preferred_size_ = gfx::Size();
// SendMessage(GetHWND(), WM_SETFONT,
// reinterpret_cast<WPARAM>(native_button_->font().hfont()),
// FALSE);
@@ -75,9 +77,14 @@ gfx::NativeView NativeButtonGtk::GetTestingHandle() const {
gfx::Size NativeButtonGtk::GetPreferredSize() {
if (!native_view())
return gfx::Size();
- GtkRequisition size_request = { 0, 0 };
- gtk_widget_size_request(native_view(), &size_request);
- return gfx::Size(size_request.width, size_request.height);
+
+ if (preferred_size_.IsEmpty()) {
+ GtkRequisition size_request = { 0, 0 };
+ gtk_widget_size_request(native_view(), &size_request);
+ preferred_size_.SetSize(size_request.width,
+ std::max(size_request.height, 29));
+ }
+ return preferred_size_;
}
void NativeButtonGtk::CreateNativeControl() {
diff --git a/views/controls/button/native_button_gtk.h b/views/controls/button/native_button_gtk.h
index 6c3f600..1d0dfc1 100644
--- a/views/controls/button/native_button_gtk.h
+++ b/views/controls/button/native_button_gtk.h
@@ -44,6 +44,12 @@ class NativeButtonGtk : public NativeControlGtk, public NativeButtonWrapper {
// The NativeButton we are bound to.
NativeButton* native_button_;
+ // The preferred size from the last size_request. We save this until we are
+ // notified that data may have caused the preferred size to change because
+ // otherwise it seems every time we call gtk_widget_size_request the size
+ // returned is a little larger (?!).
+ gfx::Size preferred_size_;
+
DISALLOW_COPY_AND_ASSIGN(NativeButtonGtk);
};
diff --git a/views/controls/native/native_view_host.cc b/views/controls/native/native_view_host.cc
index ad1ed75..e6637a9 100644
--- a/views/controls/native/native_view_host.cc
+++ b/views/controls/native/native_view_host.cc
@@ -64,13 +64,6 @@ void NativeViewHost::Layout() {
if (!native_view_ || !native_wrapper_.get())
return;
- // Since widgets know nothing about the View hierarchy (they are direct
- // children of the Widget that hosts our View hierarchy) they need to be
- // positioned in the coordinate system of the Widget, not the current
- // view.
- gfx::Point top_left;
- ConvertPointToWidget(this, &top_left);
-
gfx::Rect vis_bounds = GetVisibleBounds();
bool visible = !vis_bounds.IsEmpty();
@@ -88,10 +81,17 @@ void NativeViewHost::Layout() {
}
}
- if (visible)
+ if (visible) {
+ // Since widgets know nothing about the View hierarchy (they are direct
+ // children of the Widget that hosts our View hierarchy) they need to be
+ // positioned in the coordinate system of the Widget, not the current
+ // view.
+ gfx::Point top_left;
+ ConvertPointToWidget(this, &top_left);
native_wrapper_->ShowWidget(top_left.x(), top_left.y(), width(), height());
- else
+ } else {
native_wrapper_->HideWidget();
+ }
}
void NativeViewHost::Paint(gfx::Canvas* canvas) {
diff --git a/views/controls/native/native_view_host_gtk.cc b/views/controls/native/native_view_host_gtk.cc
index 2130a634..8e566c6 100644
--- a/views/controls/native/native_view_host_gtk.cc
+++ b/views/controls/native/native_view_host_gtk.cc
@@ -18,10 +18,14 @@ namespace views {
NativeViewHostGtk::NativeViewHostGtk(NativeViewHost* host)
: host_(host),
installed_clip_(false),
- destroy_signal_id_(0) {
+ destroy_signal_id_(0),
+ fixed_(NULL) {
+ CreateFixed(false);
}
NativeViewHostGtk::~NativeViewHostGtk() {
+ if (fixed_)
+ gtk_widget_destroy(fixed_);
}
////////////////////////////////////////////////////////////////////////////////
@@ -29,11 +33,10 @@ NativeViewHostGtk::~NativeViewHostGtk() {
void NativeViewHostGtk::NativeViewAttached() {
DCHECK(host_->native_view());
-
if (gtk_widget_get_parent(host_->native_view()))
- GetHostWidget()->ReparentChild(host_->native_view());
+ gtk_widget_reparent(host_->native_view(), fixed_);
else
- GetHostWidget()->AddChild(host_->native_view());
+ gtk_container_add(GTK_CONTAINER(fixed_), host_->native_view());
if (!destroy_signal_id_) {
destroy_signal_id_ = g_signal_connect(G_OBJECT(host_->native_view()),
@@ -60,23 +63,23 @@ void NativeViewHostGtk::NativeViewDetaching() {
}
void NativeViewHostGtk::AddedToWidget() {
+ if (gtk_widget_get_parent(fixed_))
+ GetHostWidget()->ReparentChild(fixed_);
+ else
+ GetHostWidget()->AddChild(fixed_);
+
if (!host_->native_view())
return;
- WidgetGtk* parent_widget = GetHostWidget();
- GtkWidget* widget_parent = gtk_widget_get_parent(host_->native_view());
- GtkWidget* parent_widget_widget = parent_widget->window_contents();
- if (widget_parent != parent_widget_widget) {
- g_object_ref(host_->native_view());
- if (widget_parent)
- gtk_container_remove(GTK_CONTAINER(widget_parent), host_->native_view());
- gtk_container_add(GTK_CONTAINER(parent_widget_widget),
- host_->native_view());
- g_object_unref(host_->native_view());
- }
+
+ if (gtk_widget_get_parent(host_->native_view()))
+ gtk_widget_reparent(host_->native_view(), fixed_);
+ else
+ gtk_container_add(GTK_CONTAINER(fixed_), host_->native_view());
+
if (host_->IsVisibleInRootView())
- gtk_widget_show(host_->native_view());
+ gtk_widget_show(fixed_);
else
- gtk_widget_hide(host_->native_view());
+ gtk_widget_hide(fixed_);
host_->Layout();
}
@@ -84,46 +87,21 @@ void NativeViewHostGtk::RemovedFromWidget() {
if (!host_->native_view())
return;
- WidgetGtk* parent_widget = GetHostWidget();
- gtk_widget_hide(host_->native_view());
- if (parent_widget) {
- // We can be called after the contents widget has been destroyed, e.g. any
- // NativeViewHost not removed from the view hierarchy before the window is
- // closed.
- if (GTK_IS_CONTAINER(parent_widget->window_contents())) {
- gtk_container_remove(GTK_CONTAINER(parent_widget->window_contents()),
- host_->native_view());
- }
- }
+ // TODO(beng): We leak host_->native_view() here. Fix: make all widgets not be
+ // refcounted.
+ DestroyFixed();
}
void NativeViewHostGtk::InstallClip(int x, int y, int w, int h) {
DCHECK(w > 0 && h > 0);
-
- bool has_window =
- (GTK_WIDGET_FLAGS(host_->native_view()) & GTK_NO_WINDOW) == 0;
- if (!has_window) {
- // Clip is only supported on GtkWidgets that have windows. If this becomes
- // an issue (as it may be in the options dialog) we'll need to wrap the
- // widget in a GtkFixed with a window. We have to do this as not all widgets
- // support turning on GTK_NO_WINDOW (for example, buttons don't appear to
- // draw anything when they have a window).
- // NOTREACHED();
- return;
- }
- DCHECK(has_window);
- // Unset the current region.
- gdk_window_shape_combine_region(host_->native_view()->window, NULL, 0, 0);
-
- // Set a new region.
- // TODO: using shapes is a bit expensive. Should investigated if there is
- // another more efficient way to accomplish this.
- GdkRectangle clip_rect = { x, y, w, h };
- GdkRegion* clip_region = gdk_region_rectangle(&clip_rect);
- gdk_window_shape_combine_region(host_->native_view()->window, clip_region, x,
- y);
- gdk_region_destroy(clip_region);
+ installed_clip_bounds_.SetRect(x, y, w, h);
installed_clip_ = true;
+
+ // We only re-create the fixed with a window when a cliprect is installed.
+ // Because the presence of a X Window will prevent transparency from working
+ // properly, we only want it to be active for the duration of a clip
+ // (typically during animations and scrolling.)
+ CreateFixed(true);
}
bool NativeViewHostGtk::HasInstalledClip() {
@@ -131,17 +109,42 @@ bool NativeViewHostGtk::HasInstalledClip() {
}
void NativeViewHostGtk::UninstallClip() {
- gtk_widget_shape_combine_mask(host_->native_view(), NULL, 0, 0);
installed_clip_ = false;
+ // We now re-create the fixed without a X Window so transparency works again.
+ CreateFixed(false);
}
void NativeViewHostGtk::ShowWidget(int x, int y, int w, int h) {
- GetHostWidget()->PositionChild(host_->native_view(), x, y, w, h);
- gtk_widget_show(host_->native_view());
+ // x and y are the desired position of host_ in WidgetGtk coordiantes.
+ int fixed_x = x;
+ int fixed_y = y;
+ int fixed_w = w;
+ int fixed_h = h;
+ int child_x = 0;
+ int child_y = 0;
+ int child_w = w;
+ int child_h = h;
+ if (installed_clip_) {
+ child_x = -installed_clip_bounds_.x();
+ child_y = -installed_clip_bounds_.y();
+ fixed_x += -child_x;
+ fixed_y += -child_y;
+ fixed_w = std::min(installed_clip_bounds_.width(), w);
+ fixed_h = std::min(installed_clip_bounds_.height(), h);
+ }
+
+ // Size and place the fixed_.
+ GetHostWidget()->PositionChild(fixed_, fixed_x, fixed_y, fixed_w, fixed_h);
+
+ // Size and place the hosted NativeView.
+ gtk_widget_set_size_request(host_->native_view(), child_w, child_h);
+ gtk_fixed_move(GTK_FIXED(fixed_), host_->native_view(), child_x, child_y);
+
+ gtk_widget_show(fixed_);
}
void NativeViewHostGtk::HideWidget() {
- gtk_widget_hide(host_->native_view());
+ gtk_widget_hide(fixed_);
}
void NativeViewHostGtk::SetFocus() {
@@ -151,6 +154,43 @@ void NativeViewHostGtk::SetFocus() {
////////////////////////////////////////////////////////////////////////////////
// NativeViewHostGtk, private:
+void NativeViewHostGtk::CreateFixed(bool needs_window) {
+ bool native_view_addrefed = DestroyFixed();
+
+ fixed_ = gtk_fixed_new();
+ gtk_fixed_set_has_window(GTK_FIXED(fixed_), needs_window);
+ // Defeat refcounting. We need to own the fixed.
+ gtk_widget_ref(fixed_);
+
+ WidgetGtk* widget_gtk = GetHostWidget();
+ if (widget_gtk)
+ widget_gtk->AddChild(fixed_);
+ if (host_->native_view())
+ gtk_container_add(GTK_CONTAINER(fixed_), host_->native_view());
+ if (native_view_addrefed)
+ gtk_widget_unref(host_->native_view());
+}
+
+bool NativeViewHostGtk::DestroyFixed() {
+ bool native_view_addrefed = false;
+ if (!fixed_)
+ return native_view_addrefed;
+
+ gtk_widget_hide(fixed_);
+ GetHostWidget()->RemoveChild(fixed_);
+
+ if (host_->native_view()) {
+ // We can't allow the hosted NativeView's refcount to drop to zero.
+ gtk_widget_ref(host_->native_view());
+ native_view_addrefed = true;
+ gtk_container_remove(GTK_CONTAINER(fixed_), host_->native_view());
+ }
+
+ gtk_widget_destroy(fixed_);
+ fixed_ = NULL;
+ return native_view_addrefed;
+}
+
WidgetGtk* NativeViewHostGtk::GetHostWidget() const {
return static_cast<WidgetGtk*>(host_->GetWidget());
}
diff --git a/views/controls/native/native_view_host_gtk.h b/views/controls/native/native_view_host_gtk.h
index 154da70..8292d52 100644
--- a/views/controls/native/native_view_host_gtk.h
+++ b/views/controls/native/native_view_host_gtk.h
@@ -8,6 +8,7 @@
#include <gtk/gtk.h>
#include <string>
+#include "base/gfx/rect.h"
#include "base/logging.h"
#include "views/controls/native/native_view_host_wrapper.h"
@@ -34,6 +35,21 @@ class NativeViewHostGtk : public NativeViewHostWrapper {
virtual void SetFocus();
private:
+ // Create and Destroy the GtkFixed that performs clipping on our hosted
+ // GtkWidget. |needs_window| is true when a clip is installed and implies the
+ // fixed is backed by a X Window which actually performs the clipping.
+ // It's kind of retarded that Gtk/Cairo doesn't clip painting of child windows
+ // regardless of whether or not there's an X Window. It's not that hard.
+ void CreateFixed(bool needs_window);
+
+ // DestroyFixed returns true if an associated GtkWidget was addref'ed.
+ // It does this because when the fixed is destroyed the refcount for the
+ // contained GtkWidget is decremented, which may cause it to be destroyed
+ // which we do not want. If this function returns true, the caller is
+ // responsible for unrefing the GtkWidget after it has been added to the new
+ // container.
+ bool DestroyFixed();
+
WidgetGtk* GetHostWidget() const;
// Invoked from the 'destroy' signal.
@@ -46,9 +62,17 @@ class NativeViewHostGtk : public NativeViewHostWrapper {
// visible portion of the gfx::NativeView ?
bool installed_clip_;
+ // The installed clip rect. InstallClip doesn't actually perform the clipping,
+ // a call to ShowWidget will.
+ gfx::Rect installed_clip_bounds_;
+
// Signal handle id for 'destroy' signal.
gulong destroy_signal_id_;
+ // The GtkFixed that contains the attached gfx::NativeView (used for
+ // clipping).
+ GtkWidget* fixed_;
+
DISALLOW_COPY_AND_ASSIGN(NativeViewHostGtk);
};
diff --git a/views/controls/native_control_gtk.cc b/views/controls/native_control_gtk.cc
index b1ec8b7..5576f29 100644
--- a/views/controls/native_control_gtk.cc
+++ b/views/controls/native_control_gtk.cc
@@ -45,7 +45,9 @@ void NativeControlGtk::VisibilityChanged(View* starting_from, bool is_visible) {
if (!is_visible) {
// We destroy the child widget when we become invisible because of the
// performance cost of maintaining widgets that aren't currently needed.
+ GtkWidget* widget = native_view();
Detach();
+ gtk_widget_destroy(widget);
} else if (!native_view()) {
CreateNativeControl();
}
diff --git a/views/widget/widget_gtk.cc b/views/widget/widget_gtk.cc
index e2d0c81..a77bd14 100644
--- a/views/widget/widget_gtk.cc
+++ b/views/widget/widget_gtk.cc
@@ -206,7 +206,11 @@ void WidgetGtk::AddChild(GtkWidget* child) {
}
void WidgetGtk::RemoveChild(GtkWidget* child) {
- gtk_container_remove(GTK_CONTAINER(window_contents_), child);
+ // We can be called after the contents widget has been destroyed, e.g. any
+ // NativeViewHost not removed from the view hierarchy before the window is
+ // closed.
+ if (GTK_IS_CONTAINER(window_contents_))
+ gtk_container_remove(GTK_CONTAINER(window_contents_), child);
}
void WidgetGtk::ReparentChild(GtkWidget* child) {
@@ -533,7 +537,7 @@ void WidgetGtk::OnGrabNotify(GtkWidget* widget, gboolean was_grabbed) {
HandleGrabBroke();
}
-void WidgetGtk::OnDestroy(GtkWidget* widget) {
+void WidgetGtk::OnDestroy() {
widget_ = window_contents_ = NULL;
root_view_->OnWidgetDestroyed();
if (delete_on_destroy_)
@@ -773,10 +777,8 @@ void WidgetGtk::CallGrabNotify(GtkWidget* widget, gboolean was_grabbed) {
// static
void WidgetGtk::CallDestroy(GtkObject* object) {
WidgetGtk* widget_gtk = GetViewForNative(GTK_WIDGET(object));
- if (!widget_gtk)
- return;
-
- return widget_gtk->OnDestroy(GTK_WIDGET(object));
+ if (widget_gtk)
+ widget_gtk->OnDestroy();
}
// static
diff --git a/views/widget/widget_gtk.h b/views/widget/widget_gtk.h
index 28cf8be..61a85d9 100644
--- a/views/widget/widget_gtk.h
+++ b/views/widget/widget_gtk.h
@@ -129,7 +129,7 @@ class WidgetGtk : public Widget, public MessageLoopForUI::Observer {
}
virtual gboolean OnGrabBrokeEvent(GtkWidget* widget, GdkEvent* event);
virtual void OnGrabNotify(GtkWidget* widget, gboolean was_grabbed);
- virtual void OnDestroy(GtkWidget* widget);
+ virtual void OnDestroy();
// Returns whether capture should be released on mouse release. The default
// is true.