diff options
author | xiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-14 16:47:30 +0000 |
---|---|---|
committer | xiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-14 16:47:30 +0000 |
commit | 483eb5b9225f4d57bb693de0c42679d00552c7da (patch) | |
tree | 07421c43ca730be83307bb7bdee90ce3cc41eef6 /views | |
parent | c06504a1ff40d8569a93b9898d9503f5f116ab0b (diff) | |
download | chromium_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.cc | 67 |
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) { |