summaryrefslogtreecommitdiffstats
path: root/views
diff options
context:
space:
mode:
authorxiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-14 16:47:30 +0000
committerxiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-14 16:47:30 +0000
commit483eb5b9225f4d57bb693de0c42679d00552c7da (patch)
tree07421c43ca730be83307bb7bdee90ce3cc41eef6 /views
parentc06504a1ff40d8569a93b9898d9503f5f116ab0b (diff)
downloadchromium_src-483eb5b9225f4d57bb693de0c42679d00552c7da.zip
chromium_src-483eb5b9225f4d57bb693de0c42679d00552c7da.tar.gz
chromium_src-483eb5b9225f4d57bb693de0c42679d00552c7da.tar.bz2
Use a widget as drag icon for proper transparency handling.
gtk_drag_set_icon_pixbuf converts pixbuf with alpha into a pixmap and mask. It uses the pixmap as window back pixmap and shape the window with the mask. This should work theoretically. However, the underlying window's content get mixed into the drag icon and make it un-usable. So changing to use a drag icon widget of our own which would render everything correctly. BUG=none. TEST=Verify the drag-n-drop works correct without a messed up drag icon on bookmark bar and omnibox. Review URL: http://codereview.chromium.org/1630017 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@44483 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views')
-rw-r--r--views/widget/widget_gtk.cc67
1 files changed, 62 insertions, 5 deletions
diff --git a/views/widget/widget_gtk.cc b/views/widget/widget_gtk.cc
index 329ceb3..d850b90 100644
--- a/views/widget/widget_gtk.cc
+++ b/views/widget/widget_gtk.cc
@@ -88,6 +88,43 @@ static void GetWidgetPositionOnScreen(GtkWidget* widget, int* x, int *y) {
*y += window_y;
}
+// "expose-event" handler of drag icon widget that renders drag image pixbuf.
+static gboolean DragIconWidgetPaint(GtkWidget* widget,
+ GdkEventExpose* event,
+ gpointer data) {
+ GdkPixbuf* pixbuf = reinterpret_cast<GdkPixbuf*>(data);
+
+ cairo_t* cr = gdk_cairo_create(widget->window);
+
+ gdk_cairo_region(cr, event->region);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ gdk_cairo_set_source_pixbuf(cr, pixbuf, 0.0, 0.0);
+ cairo_paint(cr);
+
+ cairo_destroy(cr);
+ return true;
+}
+
+// Creates a drag icon widget that draws drag_image.
+static GtkWidget* CreateDragIconWidget(GdkPixbuf* drag_image) {
+ GdkColormap* rgba_colormap =
+ gdk_screen_get_rgba_colormap(gdk_screen_get_default());
+ if (!rgba_colormap)
+ return NULL;
+
+ GtkWidget* drag_widget = gtk_window_new(GTK_WINDOW_POPUP);
+
+ gtk_widget_set_colormap(drag_widget, rgba_colormap);
+ gtk_widget_set_app_paintable(drag_widget, true);
+ gtk_widget_set_size_request(drag_widget,
+ gdk_pixbuf_get_width(drag_image),
+ gdk_pixbuf_get_height(drag_image));
+
+ g_signal_connect(G_OBJECT(drag_widget), "expose-event",
+ G_CALLBACK(&DragIconWidgetPaint), drag_image);
+ return drag_widget;
+}
+
// static
GtkWidget* WidgetGtk::null_parent_ = NULL;
@@ -212,12 +249,27 @@ void WidgetGtk::DoDrag(const OSExchangeData& data, int operation) {
1,
current_event);
+ GtkWidget* drag_icon_widget = NULL;
+
// Set the drag image if one was supplied.
- if (provider.drag_image())
- gtk_drag_set_icon_pixbuf(context,
- provider.drag_image(),
- provider.cursor_offset().x(),
- provider.cursor_offset().y());
+ if (provider.drag_image()) {
+ drag_icon_widget = CreateDragIconWidget(provider.drag_image());
+ if (drag_icon_widget) {
+ // Use a widget as the drag icon when compositing is enabled for proper
+ // transparency handling.
+ g_object_ref(provider.drag_image());
+ gtk_drag_set_icon_widget(context,
+ drag_icon_widget,
+ provider.cursor_offset().x(),
+ provider.cursor_offset().y());
+ } else {
+ gtk_drag_set_icon_pixbuf(context,
+ provider.drag_image(),
+ provider.cursor_offset().x(),
+ provider.cursor_offset().y());
+ }
+ }
+
if (current_event)
gdk_event_free(current_event);
gtk_target_list_unref(targets);
@@ -228,6 +280,11 @@ void WidgetGtk::DoDrag(const OSExchangeData& data, int operation) {
MessageLoopForUI::current()->Run(NULL);
drag_data_ = NULL;
+
+ if (drag_icon_widget) {
+ gtk_widget_destroy(drag_icon_widget);
+ g_object_unref(provider.drag_image());
+ }
}
void WidgetGtk::SetFocusTraversableParent(FocusTraversable* parent) {