summaryrefslogtreecommitdiffstats
path: root/views
diff options
context:
space:
mode:
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) {