diff options
Diffstat (limited to 'views')
-rw-r--r-- | views/controls/button/native_button_gtk.cc | 13 | ||||
-rw-r--r-- | views/controls/button/native_button_gtk.h | 6 | ||||
-rw-r--r-- | views/controls/native/native_view_host.cc | 18 | ||||
-rw-r--r-- | views/controls/native/native_view_host_gtk.cc | 152 | ||||
-rw-r--r-- | views/controls/native/native_view_host_gtk.h | 24 | ||||
-rw-r--r-- | views/controls/native_control_gtk.cc | 2 | ||||
-rw-r--r-- | views/widget/widget_gtk.cc | 14 | ||||
-rw-r--r-- | views/widget/widget_gtk.h | 2 |
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. |