summaryrefslogtreecommitdiffstats
path: root/views
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-08 18:13:50 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-08 18:13:50 +0000
commitcb1e496b84e8f9d702a4f78da65f7a3a5ec18594 (patch)
treeb974c4bb3673c1a3c587544f19a4caa7af8d2394 /views
parenta1c3c861aea9a429785f40324c93a0d27f12b8a6 (diff)
downloadchromium_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.cc16
-rw-r--r--views/widget/root_view_gtk.cc4
-rw-r--r--views/widget/widget_gtk.cc89
-rw-r--r--views/widget/widget_gtk.h20
-rw-r--r--views/window/window_gtk.cc2
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() {