mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-09-29 18:47:38 +00:00
quartz dnd: add hidpi support for gtk_drag_set_icon_surface()
Instead of storing the dnd icon as a pixbuf store it as a cairo surface and transfer the device scale when converting it to a NSImage. In the pixbuf/stock/named setters convert to a surface instead (no hidpi support yet)
This commit is contained in:
parent
5003b5873a
commit
4b23ba53c5
@ -96,7 +96,7 @@ struct _GtkDragSourceInfo
|
||||
GdkDragContext *context; /* drag context */
|
||||
NSEvent *nsevent; /* what started it */
|
||||
gint hot_x, hot_y; /* Hot spot for drag */
|
||||
GdkPixbuf *icon_pixbuf;
|
||||
cairo_surface_t *icon_surface;
|
||||
gboolean success;
|
||||
gboolean delete;
|
||||
};
|
||||
@ -1162,7 +1162,8 @@ gtk_drag_begin_idle (gpointer arg)
|
||||
/* FIXME: If the event isn't a mouse event, use the global cursor position instead */
|
||||
point = [info->nsevent locationInWindow];
|
||||
|
||||
drag_image = _gtk_quartz_create_image_from_pixbuf (info->icon_pixbuf);
|
||||
drag_image = _gtk_quartz_create_image_from_surface (info->icon_surface);
|
||||
|
||||
if (drag_image == NULL)
|
||||
{
|
||||
g_object_unref (info->context);
|
||||
@ -1290,7 +1291,7 @@ gtk_drag_begin_internal (GtkWidget *widget,
|
||||
* application may have set one in ::drag_begin, or it may
|
||||
* not have set one.
|
||||
*/
|
||||
if (!info->icon_pixbuf)
|
||||
if (!info->icon_surface)
|
||||
{
|
||||
if (!site || site->icon_type == GTK_IMAGE_EMPTY)
|
||||
gtk_drag_set_icon_default (context);
|
||||
@ -1804,6 +1805,8 @@ set_icon_stock_pixbuf (GdkDragContext *context,
|
||||
gint hot_y)
|
||||
{
|
||||
GtkDragSourceInfo *info;
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr;
|
||||
|
||||
info = gtk_drag_get_source_info (context, FALSE);
|
||||
|
||||
@ -1821,11 +1824,19 @@ set_icon_stock_pixbuf (GdkDragContext *context,
|
||||
else
|
||||
g_object_ref (pixbuf);
|
||||
|
||||
if (info->icon_pixbuf)
|
||||
g_object_unref (info->icon_pixbuf);
|
||||
info->icon_pixbuf = pixbuf;
|
||||
info->hot_x = hot_x;
|
||||
info->hot_y = hot_y;
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
||||
gdk_pixbuf_get_width (pixbuf),
|
||||
gdk_pixbuf_get_height (pixbuf));
|
||||
|
||||
cr = cairo_create (surface);
|
||||
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
|
||||
cairo_paint (cr);
|
||||
cairo_destroy (cr);
|
||||
g_object_unref (pixbuf);
|
||||
|
||||
cairo_surface_set_device_offset (surface, -hot_x, -hot_y);
|
||||
gtk_drag_set_icon_surface (context, surface);
|
||||
cairo_surface_destroy (surface);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1873,44 +1884,6 @@ gtk_drag_set_icon_stock (GdkDragContext *context,
|
||||
set_icon_stock_pixbuf (context, stock_id, NULL, hot_x, hot_y);
|
||||
}
|
||||
|
||||
|
||||
/* XXX: This function is in gdk, too. Should it be in Cairo? */
|
||||
static gboolean
|
||||
_gtk_cairo_surface_extents (cairo_surface_t *surface,
|
||||
GdkRectangle *extents)
|
||||
{
|
||||
double x1, x2, y1, y2;
|
||||
cairo_t *cr;
|
||||
|
||||
g_return_val_if_fail (surface != NULL, FALSE);
|
||||
g_return_val_if_fail (extents != NULL, FALSE);
|
||||
|
||||
cr = cairo_create (surface);
|
||||
cairo_clip_extents (cr, &x1, &y1, &x2, &y2);
|
||||
|
||||
x1 = floor (x1);
|
||||
y1 = floor (y1);
|
||||
x2 = ceil (x2);
|
||||
y2 = ceil (y2);
|
||||
x2 -= x1;
|
||||
y2 -= y1;
|
||||
|
||||
if (x1 < G_MININT || x1 > G_MAXINT ||
|
||||
y1 < G_MININT || y1 > G_MAXINT ||
|
||||
x2 > G_MAXINT || y2 > G_MAXINT)
|
||||
{
|
||||
extents->x = extents->y = extents->width = extents->height = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
extents->x = x1;
|
||||
extents->y = y1;
|
||||
extents->width = x2;
|
||||
extents->height = y2;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_drag_set_icon_surface:
|
||||
* @context: the context for a drag. (This must be called
|
||||
@ -1930,21 +1903,22 @@ void
|
||||
gtk_drag_set_icon_surface (GdkDragContext *context,
|
||||
cairo_surface_t *surface)
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
GdkRectangle extents;
|
||||
double x_offset, y_offset;
|
||||
GtkDragSourceInfo *info;
|
||||
|
||||
g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
|
||||
g_return_if_fail (surface != NULL);
|
||||
|
||||
_gtk_cairo_surface_extents (surface, &extents);
|
||||
cairo_surface_get_device_offset (surface, &x_offset, &y_offset);
|
||||
info = gtk_drag_get_source_info (context, FALSE);
|
||||
cairo_surface_reference (surface);
|
||||
|
||||
pixbuf = gdk_pixbuf_get_from_surface (surface,
|
||||
extents.x, extents.y,
|
||||
extents.width, extents.height);
|
||||
gtk_drag_set_icon_pixbuf (context, pixbuf, -x_offset, -y_offset);
|
||||
g_object_unref (pixbuf);
|
||||
if (info->icon_surface)
|
||||
cairo_surface_destroy (info->icon_surface);
|
||||
|
||||
info->icon_surface = surface;
|
||||
info->hot_x = -x_offset;
|
||||
info->hot_y = -y_offset;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2021,8 +1995,8 @@ gtk_drag_source_info_destroy (GtkDragSourceInfo *info)
|
||||
NSPasteboard *pasteboard;
|
||||
NSAutoreleasePool *pool;
|
||||
|
||||
if (info->icon_pixbuf)
|
||||
g_object_unref (info->icon_pixbuf);
|
||||
if (info->icon_surface)
|
||||
cairo_surface_destroy (info->icon_surface);
|
||||
|
||||
g_signal_emit_by_name (info->widget, "drag-end",
|
||||
info->context);
|
||||
|
100
gtk/gtkquartz.c
100
gtk/gtkquartz.c
@ -22,6 +22,106 @@
|
||||
#include "gtkselectionprivate.h"
|
||||
#include <gdk/quartz/gdkquartz.h>
|
||||
|
||||
|
||||
static gboolean
|
||||
_cairo_surface_extents (cairo_surface_t *surface,
|
||||
GdkRectangle *extents)
|
||||
{
|
||||
double x1, x2, y1, y2;
|
||||
cairo_t *cr;
|
||||
|
||||
g_return_val_if_fail (surface != NULL, FALSE);
|
||||
g_return_val_if_fail (extents != NULL, FALSE);
|
||||
|
||||
cr = cairo_create (surface);
|
||||
cairo_clip_extents (cr, &x1, &y1, &x2, &y2);
|
||||
|
||||
x1 = floor (x1);
|
||||
y1 = floor (y1);
|
||||
x2 = ceil (x2);
|
||||
y2 = ceil (y2);
|
||||
x2 -= x1;
|
||||
y2 -= y1;
|
||||
|
||||
if (x1 < G_MININT || x1 > G_MAXINT ||
|
||||
y1 < G_MININT || y1 > G_MAXINT ||
|
||||
x2 > G_MAXINT || y2 > G_MAXINT)
|
||||
{
|
||||
extents->x = extents->y = extents->width = extents->height = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
extents->x = x1;
|
||||
extents->y = y1;
|
||||
extents->width = x2;
|
||||
extents->height = y2;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_data_provider_release_cairo_surface (void* info, const void* data, size_t size)
|
||||
{
|
||||
cairo_surface_destroy ((cairo_surface_t *)info);
|
||||
}
|
||||
|
||||
/* Returns a new NSImage or %NULL in case of an error.
|
||||
* The device scale factor will be transfered to the NSImage (hidpi)
|
||||
*/
|
||||
NSImage *
|
||||
_gtk_quartz_create_image_from_surface (cairo_surface_t *surface)
|
||||
{
|
||||
CGColorSpaceRef colorspace;
|
||||
CGDataProviderRef data_provider;
|
||||
CGImageRef image;
|
||||
void *data;
|
||||
NSImage *nsimage;
|
||||
double sx, sy;
|
||||
cairo_t *cr;
|
||||
cairo_surface_t *img_surface;
|
||||
cairo_rectangle_int_t extents;
|
||||
int width, height, rowstride;
|
||||
|
||||
if (!_cairo_surface_extents (surface, &extents))
|
||||
return NULL;
|
||||
|
||||
cairo_surface_get_device_scale (surface, &sx, &sy);
|
||||
width = extents.width * sx;
|
||||
height = extents.height * sy;
|
||||
|
||||
img_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
cr = cairo_create (img_surface);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_scale (cr, sx, sy);
|
||||
cairo_set_source_surface (cr, surface, -extents.x, -extents.y);
|
||||
cairo_paint (cr);
|
||||
cairo_destroy (cr);
|
||||
|
||||
cairo_surface_flush (img_surface);
|
||||
rowstride = cairo_image_surface_get_stride (img_surface);
|
||||
data = cairo_image_surface_get_data (img_surface);
|
||||
|
||||
colorspace = CGColorSpaceCreateDeviceRGB ();
|
||||
/* Note: the release callback will only be called after NSImage below dies */
|
||||
data_provider = CGDataProviderCreateWithData (surface, data, height * rowstride,
|
||||
_data_provider_release_cairo_surface);
|
||||
|
||||
image = CGImageCreate (width, height, 8,
|
||||
32, rowstride,
|
||||
colorspace,
|
||||
/* XXX: kCGBitmapByteOrderDefault gives wrong colors..?? */
|
||||
kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst,
|
||||
data_provider, NULL, FALSE,
|
||||
kCGRenderingIntentDefault);
|
||||
CGDataProviderRelease (data_provider);
|
||||
CGColorSpaceRelease (colorspace);
|
||||
|
||||
nsimage = [[NSImage alloc] initWithCGImage:image size:NSMakeSize (extents.width, extents.height)];
|
||||
CGImageRelease (image);
|
||||
|
||||
return nsimage;
|
||||
}
|
||||
|
||||
NSImage *
|
||||
_gtk_quartz_create_image_from_pixbuf (GdkPixbuf *pixbuf)
|
||||
{
|
||||
|
@ -39,6 +39,8 @@ void _gtk_quartz_set_selection_data_for_pasteboard (NSPasteboard *pasteboard,
|
||||
|
||||
NSImage *_gtk_quartz_create_image_from_pixbuf (GdkPixbuf *pixbuf);
|
||||
|
||||
NSImage *_gtk_quartz_create_image_from_surface (cairo_surface_t *surface);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_QUARTZ_H__ */
|
||||
|
Loading…
Reference in New Issue
Block a user