diff options
author | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-08 18:13:50 +0000 |
---|---|---|
committer | sky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-08 18:13:50 +0000 |
commit | cb1e496b84e8f9d702a4f78da65f7a3a5ec18594 (patch) | |
tree | b974c4bb3673c1a3c587544f19a4caa7af8d2394 /views | |
parent | a1c3c861aea9a429785f40324c93a0d27f12b8a6 (diff) | |
download | chromium_src-cb1e496b84e8f9d702a4f78da65f7a3a5ec18594.zip chromium_src-cb1e496b84e8f9d702a4f78da65f7a3a5ec18594.tar.gz chromium_src-cb1e496b84e8f9d702a4f78da65f7a3a5ec18594.tar.bz2 |
Makes it possible for Widget's on GTK to have a transparent
background. Additionally implements always on top and makes ImageView
support borders.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/119269
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@17878 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views')
-rw-r--r-- | views/controls/image_view.cc | 16 | ||||
-rw-r--r-- | views/widget/root_view_gtk.cc | 4 | ||||
-rw-r--r-- | views/widget/widget_gtk.cc | 89 | ||||
-rw-r--r-- | views/widget/widget_gtk.h | 20 | ||||
-rw-r--r-- | views/window/window_gtk.cc | 2 |
5 files changed, 122 insertions, 9 deletions
diff --git a/views/controls/image_view.cc b/views/controls/image_view.cc index 10d87b1..d8108b04 100644 --- a/views/controls/image_view.cc +++ b/views/controls/image_view.cc @@ -5,6 +5,7 @@ #include "views/controls/image_view.h" #include "app/gfx/canvas.h" +#include "app/gfx/insets.h" #include "base/logging.h" namespace views { @@ -53,12 +54,15 @@ void ImageView::ResetImageSize() { } gfx::Size ImageView::GetPreferredSize() { + gfx::Insets insets = GetInsets(); if (image_size_set_) { gfx::Size image_size; GetImageSize(&image_size); + image_size.Enlarge(insets.width(), insets.height()); return image_size; } - return gfx::Size(image_.width(), image_.height()); + return gfx::Size(image_.width() + insets.width(), + image_.height() + insets.height()); } void ImageView::ComputeImageOrigin(int image_width, int image_height, @@ -75,12 +79,14 @@ void ImageView::ComputeImageOrigin(int image_width, int image_height, actual_horiz_alignment = TRAILING; } + gfx::Insets insets = GetInsets(); + switch(actual_horiz_alignment) { case LEADING: - *x = 0; + *x = insets.left(); break; case TRAILING: - *x = width() - image_width; + *x = width() - insets.right() - image_width; break; case CENTER: *x = (width() - image_width) / 2; @@ -91,10 +97,10 @@ void ImageView::ComputeImageOrigin(int image_width, int image_height, switch (vert_alignment_) { case LEADING: - *y = 0; + *y = insets.top(); break; case TRAILING: - *y = height() - image_height; + *y = height() - insets.bottom() - image_height; break; case CENTER: *y = (height() - image_height) / 2; diff --git a/views/widget/root_view_gtk.cc b/views/widget/root_view_gtk.cc index 5c02a71..8f0c495 100644 --- a/views/widget/root_view_gtk.cc +++ b/views/widget/root_view_gtk.cc @@ -8,7 +8,7 @@ #include "app/gfx/canvas.h" #include "base/logging.h" -#include "third_party/skia/include/core/SkColor.h" +#include "views/widget/widget_gtk.h" namespace views { @@ -16,6 +16,8 @@ void RootView::OnPaint(GdkEventExpose* event) { gfx::CanvasPaint canvas(event); if (!canvas.isEmpty()) { + canvas.set_composite_alpha( + static_cast<WidgetGtk*>(GetWidget())->is_transparent()); SchedulePaint(gfx::Rect(canvas.rectangle()), false); if (NeedsPainting(false)) { ProcessPaint(&canvas); diff --git a/views/widget/widget_gtk.cc b/views/widget/widget_gtk.cc index b105af8..4928d27 100644 --- a/views/widget/widget_gtk.cc +++ b/views/widget/widget_gtk.cc @@ -64,7 +64,8 @@ WidgetGtk::WidgetGtk(Type type) has_capture_(false), last_mouse_event_was_move_(false), ALLOW_THIS_IN_INITIALIZER_LIST(close_widget_factory_(this)), - delete_on_destroy_(true) { + delete_on_destroy_(true), + transparent_(false) { } WidgetGtk::~WidgetGtk() { @@ -146,6 +147,10 @@ void WidgetGtk::Init(GtkWidget* parent, g_signal_connect(G_OBJECT(widget_), "destroy", G_CALLBACK(CallDestroy), NULL); + if (transparent_) { + g_signal_connect(G_OBJECT(widget_), "expose_event", + G_CALLBACK(CallWindowPaint), this); + } // TODO(erg): Ignore these signals for now because they're such a drag. // @@ -172,6 +177,26 @@ void WidgetGtk::Init(GtkWidget* parent, } } +bool WidgetGtk::MakeTransparent() { + // Transparency can only be enabled for windows/popups and only if we haven't + // realized the widget. + DCHECK(!widget_ && type_ != TYPE_CHILD); + + if (!gdk_screen_is_composited(gdk_screen_get_default())) { + // Transparency is only supported for compositing window managers. + DLOG(WARNING) << "compsiting not supported"; + return false; + } + + if (!gdk_screen_get_rgba_colormap(gdk_screen_get_default())) { + // We need rgba to make the window transparent. + return false; + } + + transparent_ = true; + return true; +} + void WidgetGtk::AddChild(GtkWidget* child) { gtk_container_add(GTK_CONTAINER(child_widget_parent_), child); } @@ -366,8 +391,10 @@ void WidgetGtk::CreateGtkWidget() { 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); + + if (transparent_) + ConfigureWidgetForTransparentBackground(); } // The widget needs to be realized before handlers like size-allocate can @@ -483,6 +510,24 @@ RootView* WidgetGtk::CreateRootView() { return new RootView(this); } +void WidgetGtk::OnWindowPaint(GtkWidget* widget, GdkEventExpose* event) { + // NOTE: for reasons I don't understand this code is never hit. It should + // be hit when transparent_, but we never get the expose-event for the + // window in this case, even though a stand alone test case triggers it. I'm + // leaving it in just in case. + + // Fill the background totally transparent. We don't need to paint the root + // view here as that is done by OnPaint. + DCHECK(transparent_); + int width, height; + gtk_window_get_size (GTK_WINDOW (widget), &width, &height); + cairo_t* cr = gdk_cairo_create(widget->window); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba(cr, 0, 0, 0, 0); + cairo_rectangle(cr, 0, 0, width, height); + cairo_fill(cr); +} + bool WidgetGtk::ProcessMousePressed(GdkEventButton* event) { if (event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS) { // The sequence for double clicks is press, release, press, 2press, release. @@ -557,6 +602,7 @@ void WidgetGtk::CallSizeAllocate(GtkWidget* widget, GtkAllocation* allocation) { widget_gtk->OnSizeAllocate(widget, allocation); } +// static gboolean WidgetGtk::CallPaint(GtkWidget* widget, GdkEventExpose* event) { WidgetGtk* widget_gtk = GetViewForNative(widget); if (widget_gtk) @@ -564,6 +610,14 @@ gboolean WidgetGtk::CallPaint(GtkWidget* widget, GdkEventExpose* event) { return false; // False indicates other widgets should get the event as well. } +// static +gboolean WidgetGtk::CallWindowPaint(GtkWidget* widget, + GdkEventExpose* event, + WidgetGtk* widget_gtk) { + widget_gtk->OnWindowPaint(widget, event); + return false; // False indicates other widgets should get the event as well. +} + gboolean WidgetGtk::CallEnterNotify(GtkWidget* widget, GdkEventCrossing* event) { WidgetGtk* widget_gtk = GetViewForNative(widget); if (!widget_gtk) @@ -692,6 +746,37 @@ Window* WidgetGtk::GetWindowImpl(GtkWidget* widget) { return NULL; } +void WidgetGtk::ConfigureWidgetForTransparentBackground() { + DCHECK(widget_ && child_widget_parent_ && + widget_ != child_widget_parent_); + + GdkColormap* rgba_colormap = + gdk_screen_get_rgba_colormap(gdk_screen_get_default()); + if (!rgba_colormap) { + transparent_ = false; + return; + } + // To make the background transparent we need to install the RGBA colormap + // on both the window and fixed. In addition we need to turn off double + // buffering and make sure no decorations are drawn. The last bit is to make + // sure the widget doesn't attempt to draw a pixmap in it's background. + gtk_widget_set_colormap(widget_, rgba_colormap); + gtk_widget_set_app_paintable(widget_, true); + GTK_WIDGET_UNSET_FLAGS(widget_, GTK_DOUBLE_BUFFERED); + gtk_widget_realize(widget_); + gdk_window_set_decorations(widget_->window, + static_cast<GdkWMDecoration>(0)); + // 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_); + // Widget must be realized before setting pixmap. + gdk_window_set_back_pixmap(child_widget_parent_->window, NULL, FALSE); +} + void WidgetGtk::HandleGrabBroke() { if (has_capture_) { if (is_mouse_down_) diff --git a/views/widget/widget_gtk.h b/views/widget/widget_gtk.h index 6bd501e..8ac47fc 100644 --- a/views/widget/widget_gtk.h +++ b/views/widget/widget_gtk.h @@ -43,6 +43,13 @@ class WidgetGtk : public Widget, public MessageLoopForUI::Observer { const gfx::Rect& bounds, bool has_own_focus_manager); + // Makes the background of the window totally transparent. This must be + // invoked before Init. This does a couple of checks and returns true if + // the window can be made transparent. The actual work of making the window + // transparent is done by ConfigureWidgetForTransparentBackground. + bool MakeTransparent(); + bool is_transparent() const { return transparent_; } + // Sets whether or not we are deleted when the widget is destroyed. The // default is true. void set_delete_on_destroy(bool delete_on_destroy) { @@ -126,6 +133,8 @@ class WidgetGtk : public Widget, public MessageLoopForUI::Observer { private: virtual RootView* CreateRootView(); + void OnWindowPaint(GtkWidget* widget, GdkEventExpose* event); + // Process a mouse click bool ProcessMousePressed(GdkEventButton* event); void ProcessMouseReleased(GdkEventButton* event); @@ -141,6 +150,9 @@ class WidgetGtk : public Widget, public MessageLoopForUI::Observer { // TODO(beng): alphabetize! static void CallSizeAllocate(GtkWidget* widget, GtkAllocation* allocation); static gboolean CallPaint(GtkWidget* widget, GdkEventExpose* event); + static gboolean CallWindowPaint(GtkWidget* widget, + GdkEventExpose* event, + WidgetGtk* widget_gtk); static gboolean CallEnterNotify(GtkWidget* widget, GdkEventCrossing* event); static gboolean CallLeaveNotify(GtkWidget* widget, GdkEventCrossing* event); static gboolean CallMotionNotify(GtkWidget* widget, GdkEventMotion* event); @@ -163,6 +175,11 @@ class WidgetGtk : public Widget, public MessageLoopForUI::Observer { // Creates the GtkWidget. void CreateGtkWidget(); + // Invoked from create widget to enable the various bits needed for a + // transparent background. This is only invoked if MakeTransparent has been + // invoked. + void ConfigureWidgetForTransparentBackground(); + void HandleGrabBroke(); const Type type_; @@ -201,6 +218,9 @@ class WidgetGtk : public Widget, public MessageLoopForUI::Observer { // See description above setter. bool delete_on_destroy_; + // See description above make_transparent for details. + bool transparent_; + scoped_ptr<DefaultThemeProvider> default_theme_provider_; DISALLOW_COPY_AND_ASSIGN(WidgetGtk); diff --git a/views/window/window_gtk.cc b/views/window/window_gtk.cc index e62fd73..b90aa6f 100644 --- a/views/window/window_gtk.cc +++ b/views/window/window_gtk.cc @@ -208,7 +208,7 @@ void WindowGtk::UpdateWindowIcon() { } void WindowGtk::SetIsAlwaysOnTop(bool always_on_top) { - NOTIMPLEMENTED(); + gtk_window_set_keep_above(GetNativeWindow(), always_on_top); } NonClientFrameView* WindowGtk::CreateFrameViewForWindow() { |