forked from AuroraMiddleware/gtk
eabac453e6
The history before this was kind of twisted as several different approaches were tested, so that was all squashed into this initial commit to hide the uninteresting changes and files that were later removed.
1528 lines
40 KiB
C
1528 lines
40 KiB
C
/* GIMP Drawing Kit
|
|
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
/*
|
|
* Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
|
|
* file for a list of people on the GTK+ Team. See the ChangeLog
|
|
* files for a list of changes. These files are distributed with
|
|
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "gdkx.h"
|
|
#include "gdkregion-generic.h"
|
|
|
|
#include <cairo-xlib.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h> /* for memcpy() */
|
|
|
|
#if defined (HAVE_IPC_H) && defined (HAVE_SHM_H) && defined (HAVE_XSHM_H)
|
|
#define USE_SHM
|
|
#endif
|
|
|
|
#ifdef USE_SHM
|
|
#include <X11/extensions/XShm.h>
|
|
#endif /* USE_SHM */
|
|
|
|
#include "gdkprivate-x11.h"
|
|
#include "gdkdrawable-x11.h"
|
|
#include "gdkpixmap-x11.h"
|
|
#include "gdkscreen-x11.h"
|
|
#include "gdkdisplay-x11.h"
|
|
|
|
#include "gdkalias.h"
|
|
|
|
static void gdk_x11_draw_rectangle (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
gboolean filled,
|
|
gint x,
|
|
gint y,
|
|
gint width,
|
|
gint height);
|
|
static void gdk_x11_draw_arc (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
gboolean filled,
|
|
gint x,
|
|
gint y,
|
|
gint width,
|
|
gint height,
|
|
gint angle1,
|
|
gint angle2);
|
|
static void gdk_x11_draw_polygon (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
gboolean filled,
|
|
GdkPoint *points,
|
|
gint npoints);
|
|
static void gdk_x11_draw_text (GdkDrawable *drawable,
|
|
GdkFont *font,
|
|
GdkGC *gc,
|
|
gint x,
|
|
gint y,
|
|
const gchar *text,
|
|
gint text_length);
|
|
static void gdk_x11_draw_text_wc (GdkDrawable *drawable,
|
|
GdkFont *font,
|
|
GdkGC *gc,
|
|
gint x,
|
|
gint y,
|
|
const GdkWChar *text,
|
|
gint text_length);
|
|
static void gdk_x11_draw_drawable (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
GdkPixmap *src,
|
|
gint xsrc,
|
|
gint ysrc,
|
|
gint xdest,
|
|
gint ydest,
|
|
gint width,
|
|
gint height);
|
|
static void gdk_x11_draw_points (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
GdkPoint *points,
|
|
gint npoints);
|
|
static void gdk_x11_draw_segments (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
GdkSegment *segs,
|
|
gint nsegs);
|
|
static void gdk_x11_draw_lines (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
GdkPoint *points,
|
|
gint npoints);
|
|
|
|
static void gdk_x11_draw_image (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
GdkImage *image,
|
|
gint xsrc,
|
|
gint ysrc,
|
|
gint xdest,
|
|
gint ydest,
|
|
gint width,
|
|
gint height);
|
|
static void gdk_x11_draw_pixbuf (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
GdkPixbuf *pixbuf,
|
|
gint src_x,
|
|
gint src_y,
|
|
gint dest_x,
|
|
gint dest_y,
|
|
gint width,
|
|
gint height,
|
|
GdkRgbDither dither,
|
|
gint x_dither,
|
|
gint y_dither);
|
|
|
|
static cairo_surface_t *gdk_x11_ref_cairo_surface (GdkDrawable *drawable);
|
|
|
|
static void gdk_x11_set_colormap (GdkDrawable *drawable,
|
|
GdkColormap *colormap);
|
|
|
|
static GdkColormap* gdk_x11_get_colormap (GdkDrawable *drawable);
|
|
static gint gdk_x11_get_depth (GdkDrawable *drawable);
|
|
static GdkScreen * gdk_x11_get_screen (GdkDrawable *drawable);
|
|
static GdkVisual* gdk_x11_get_visual (GdkDrawable *drawable);
|
|
|
|
static void gdk_drawable_impl_x11_finalize (GObject *object);
|
|
|
|
static const cairo_user_data_key_t gdk_x11_cairo_key;
|
|
|
|
G_DEFINE_TYPE (GdkDrawableImplX11, _gdk_drawable_impl_x11, GDK_TYPE_DRAWABLE)
|
|
|
|
static void
|
|
_gdk_drawable_impl_x11_class_init (GdkDrawableImplX11Class *klass)
|
|
{
|
|
GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
object_class->finalize = gdk_drawable_impl_x11_finalize;
|
|
|
|
drawable_class->create_gc = _gdk_x11_gc_new;
|
|
drawable_class->draw_rectangle = gdk_x11_draw_rectangle;
|
|
drawable_class->draw_arc = gdk_x11_draw_arc;
|
|
drawable_class->draw_polygon = gdk_x11_draw_polygon;
|
|
drawable_class->draw_text = gdk_x11_draw_text;
|
|
drawable_class->draw_text_wc = gdk_x11_draw_text_wc;
|
|
drawable_class->draw_drawable = gdk_x11_draw_drawable;
|
|
drawable_class->draw_points = gdk_x11_draw_points;
|
|
drawable_class->draw_segments = gdk_x11_draw_segments;
|
|
drawable_class->draw_lines = gdk_x11_draw_lines;
|
|
drawable_class->draw_image = gdk_x11_draw_image;
|
|
drawable_class->draw_pixbuf = gdk_x11_draw_pixbuf;
|
|
|
|
drawable_class->ref_cairo_surface = gdk_x11_ref_cairo_surface;
|
|
|
|
drawable_class->set_colormap = gdk_x11_set_colormap;
|
|
drawable_class->get_colormap = gdk_x11_get_colormap;
|
|
|
|
drawable_class->get_depth = gdk_x11_get_depth;
|
|
drawable_class->get_screen = gdk_x11_get_screen;
|
|
drawable_class->get_visual = gdk_x11_get_visual;
|
|
|
|
drawable_class->_copy_to_image = _gdk_x11_copy_to_image;
|
|
}
|
|
|
|
static void
|
|
_gdk_drawable_impl_x11_init (GdkDrawableImplX11 *impl)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gdk_drawable_impl_x11_finalize (GObject *object)
|
|
{
|
|
gdk_drawable_set_colormap (GDK_DRAWABLE (object), NULL);
|
|
|
|
G_OBJECT_CLASS (_gdk_drawable_impl_x11_parent_class)->finalize (object);
|
|
}
|
|
|
|
/**
|
|
* _gdk_x11_drawable_finish:
|
|
* @drawable: a #GdkDrawableImplX11.
|
|
*
|
|
* Performs necessary cleanup prior to freeing a pixmap or
|
|
* destroying a window.
|
|
**/
|
|
void
|
|
_gdk_x11_drawable_finish (GdkDrawable *drawable)
|
|
{
|
|
GdkDrawableImplX11 *impl = GDK_DRAWABLE_IMPL_X11 (drawable);
|
|
|
|
if (impl->picture)
|
|
{
|
|
XRenderFreePicture (GDK_SCREEN_XDISPLAY (impl->screen),
|
|
impl->picture);
|
|
impl->picture = None;
|
|
}
|
|
|
|
if (impl->cairo_surface)
|
|
{
|
|
cairo_surface_finish (impl->cairo_surface);
|
|
cairo_surface_set_user_data (impl->cairo_surface, &gdk_x11_cairo_key,
|
|
NULL, NULL);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* _gdk_x11_drawable_update_size:
|
|
* @drawable: a #GdkDrawableImplX11.
|
|
*
|
|
* Updates the state of the drawable (in particular the drawable's
|
|
* cairo surface) when its size has changed.
|
|
**/
|
|
void
|
|
_gdk_x11_drawable_update_size (GdkDrawable *drawable)
|
|
{
|
|
GdkDrawableImplX11 *impl = GDK_DRAWABLE_IMPL_X11 (drawable);
|
|
|
|
if (impl->cairo_surface)
|
|
{
|
|
int width, height;
|
|
|
|
gdk_drawable_get_size (drawable, &width, &height);
|
|
cairo_xlib_surface_set_size (impl->cairo_surface, width, height);
|
|
}
|
|
}
|
|
|
|
static void
|
|
try_pixmap (Display *xdisplay,
|
|
int screen,
|
|
int depth)
|
|
{
|
|
Pixmap pixmap = XCreatePixmap (xdisplay,
|
|
RootWindow (xdisplay, screen),
|
|
1, 1, depth);
|
|
XFreePixmap (xdisplay, pixmap);
|
|
}
|
|
|
|
gboolean
|
|
_gdk_x11_have_render (GdkDisplay *display)
|
|
{
|
|
Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
|
|
GdkDisplayX11 *x11display = GDK_DISPLAY_X11 (display);
|
|
|
|
if (x11display->have_render == GDK_UNKNOWN)
|
|
{
|
|
int event_base, error_base;
|
|
x11display->have_render =
|
|
XRenderQueryExtension (xdisplay, &event_base, &error_base)
|
|
? GDK_YES : GDK_NO;
|
|
|
|
if (x11display->have_render == GDK_YES)
|
|
{
|
|
/*
|
|
* Sun advertises RENDER, but fails to support 32-bit pixmaps.
|
|
* That is just no good. Therefore, we check all screens
|
|
* for proper support.
|
|
*/
|
|
|
|
int screen;
|
|
for (screen = 0; screen < ScreenCount (xdisplay); screen++)
|
|
{
|
|
int count;
|
|
int *depths = XListDepths (xdisplay, screen, &count);
|
|
gboolean has_8 = FALSE, has_32 = FALSE;
|
|
|
|
if (depths)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
if (depths[i] == 8)
|
|
has_8 = TRUE;
|
|
else if (depths[i] == 32)
|
|
has_32 = TRUE;
|
|
}
|
|
XFree (depths);
|
|
}
|
|
|
|
/* At this point, we might have a false positive;
|
|
* buggy versions of Xinerama only report depths for
|
|
* which there is an associated visual; so we actually
|
|
* go ahead and try create pixmaps.
|
|
*/
|
|
if (!(has_8 && has_32))
|
|
{
|
|
gdk_error_trap_push ();
|
|
if (!has_8)
|
|
try_pixmap (xdisplay, screen, 8);
|
|
if (!has_32)
|
|
try_pixmap (xdisplay, screen, 32);
|
|
XSync (xdisplay, False);
|
|
if (gdk_error_trap_pop () == 0)
|
|
{
|
|
has_8 = TRUE;
|
|
has_32 = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!(has_8 && has_32))
|
|
{
|
|
g_warning ("The X server advertises that RENDER support is present,\n"
|
|
"but fails to supply the necessary pixmap support. In\n"
|
|
"other words, it is buggy.");
|
|
x11display->have_render = GDK_NO;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return x11display->have_render == GDK_YES;
|
|
}
|
|
|
|
static Picture
|
|
gdk_x11_drawable_get_picture (GdkDrawable *drawable)
|
|
{
|
|
GdkDrawableImplX11 *impl = GDK_DRAWABLE_IMPL_X11 (drawable);
|
|
|
|
if (!impl->picture)
|
|
{
|
|
Display *xdisplay = GDK_SCREEN_XDISPLAY (impl->screen);
|
|
XRenderPictFormat *format;
|
|
|
|
GdkVisual *visual = gdk_drawable_get_visual (GDK_DRAWABLE_IMPL_X11 (drawable)->wrapper);
|
|
if (!visual)
|
|
return None;
|
|
|
|
format = XRenderFindVisualFormat (xdisplay, GDK_VISUAL_XVISUAL (visual));
|
|
if (format)
|
|
{
|
|
XRenderPictureAttributes attributes;
|
|
attributes.graphics_exposures = False;
|
|
|
|
impl->picture = XRenderCreatePicture (xdisplay, impl->xid, format,
|
|
CPGraphicsExposure, &attributes);
|
|
}
|
|
}
|
|
|
|
return impl->picture;
|
|
}
|
|
|
|
static void
|
|
gdk_x11_drawable_update_picture_clip (GdkDrawable *drawable,
|
|
GdkGC *gc)
|
|
{
|
|
GdkDrawableImplX11 *impl = GDK_DRAWABLE_IMPL_X11 (drawable);
|
|
Display *xdisplay = GDK_SCREEN_XDISPLAY (impl->screen);
|
|
Picture picture = gdk_x11_drawable_get_picture (drawable);
|
|
GdkRegion *clip_region = gc ? _gdk_gc_get_clip_region (gc) : NULL;
|
|
|
|
if (clip_region)
|
|
{
|
|
GdkRegionBox *boxes = clip_region->rects;
|
|
gint n_boxes = clip_region->numRects;
|
|
XRectangle *rects = g_new (XRectangle, n_boxes);
|
|
int i;
|
|
|
|
for (i=0; i < n_boxes; i++)
|
|
{
|
|
rects[i].x = CLAMP (boxes[i].x1 + gc->clip_x_origin, G_MINSHORT, G_MAXSHORT);
|
|
rects[i].y = CLAMP (boxes[i].y1 + gc->clip_y_origin, G_MINSHORT, G_MAXSHORT);
|
|
rects[i].width = CLAMP (boxes[i].x2 + gc->clip_x_origin, G_MINSHORT, G_MAXSHORT) - rects[i].x;
|
|
rects[i].height = CLAMP (boxes[i].y2 + gc->clip_y_origin, G_MINSHORT, G_MAXSHORT) - rects[i].y;
|
|
}
|
|
|
|
XRenderSetPictureClipRectangles (xdisplay, picture,
|
|
0, 0, rects, n_boxes);
|
|
|
|
g_free (rects);
|
|
}
|
|
else
|
|
{
|
|
XRenderPictureAttributes pa;
|
|
pa.clip_mask = None;
|
|
XRenderChangePicture (xdisplay, picture,
|
|
CPClipMask, &pa);
|
|
}
|
|
}
|
|
|
|
/*****************************************************
|
|
* X11 specific implementations of generic functions *
|
|
*****************************************************/
|
|
|
|
static GdkColormap*
|
|
gdk_x11_get_colormap (GdkDrawable *drawable)
|
|
{
|
|
GdkDrawableImplX11 *impl;
|
|
|
|
impl = GDK_DRAWABLE_IMPL_X11 (drawable);
|
|
|
|
return impl->colormap;
|
|
}
|
|
|
|
static void
|
|
gdk_x11_set_colormap (GdkDrawable *drawable,
|
|
GdkColormap *colormap)
|
|
{
|
|
GdkDrawableImplX11 *impl;
|
|
|
|
impl = GDK_DRAWABLE_IMPL_X11 (drawable);
|
|
|
|
if (impl->colormap == colormap)
|
|
return;
|
|
|
|
if (impl->colormap)
|
|
g_object_unref (impl->colormap);
|
|
impl->colormap = colormap;
|
|
if (impl->colormap)
|
|
g_object_ref (impl->colormap);
|
|
}
|
|
|
|
/* Drawing
|
|
*/
|
|
|
|
static void
|
|
gdk_x11_draw_rectangle (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
gboolean filled,
|
|
gint x,
|
|
gint y,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
GdkDrawableImplX11 *impl;
|
|
|
|
impl = GDK_DRAWABLE_IMPL_X11 (drawable);
|
|
|
|
if (filled)
|
|
XFillRectangle (GDK_SCREEN_XDISPLAY (impl->screen), impl->xid,
|
|
GDK_GC_GET_XGC (gc), x, y, width, height);
|
|
else
|
|
XDrawRectangle (GDK_SCREEN_XDISPLAY (impl->screen), impl->xid,
|
|
GDK_GC_GET_XGC (gc), x, y, width, height);
|
|
}
|
|
|
|
static void
|
|
gdk_x11_draw_arc (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
gboolean filled,
|
|
gint x,
|
|
gint y,
|
|
gint width,
|
|
gint height,
|
|
gint angle1,
|
|
gint angle2)
|
|
{
|
|
GdkDrawableImplX11 *impl;
|
|
|
|
impl = GDK_DRAWABLE_IMPL_X11 (drawable);
|
|
|
|
|
|
if (filled)
|
|
XFillArc (GDK_SCREEN_XDISPLAY (impl->screen), impl->xid,
|
|
GDK_GC_GET_XGC (gc), x, y, width, height, angle1, angle2);
|
|
else
|
|
XDrawArc (GDK_SCREEN_XDISPLAY (impl->screen), impl->xid,
|
|
GDK_GC_GET_XGC (gc), x, y, width, height, angle1, angle2);
|
|
}
|
|
|
|
static void
|
|
gdk_x11_draw_polygon (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
gboolean filled,
|
|
GdkPoint *points,
|
|
gint npoints)
|
|
{
|
|
XPoint *tmp_points;
|
|
gint tmp_npoints, i;
|
|
GdkDrawableImplX11 *impl;
|
|
|
|
impl = GDK_DRAWABLE_IMPL_X11 (drawable);
|
|
|
|
|
|
if (!filled &&
|
|
(points[0].x != points[npoints-1].x || points[0].y != points[npoints-1].y))
|
|
{
|
|
tmp_npoints = npoints + 1;
|
|
tmp_points = g_new (XPoint, tmp_npoints);
|
|
tmp_points[npoints].x = points[0].x;
|
|
tmp_points[npoints].y = points[0].y;
|
|
}
|
|
else
|
|
{
|
|
tmp_npoints = npoints;
|
|
tmp_points = g_new (XPoint, tmp_npoints);
|
|
}
|
|
|
|
for (i=0; i<npoints; i++)
|
|
{
|
|
tmp_points[i].x = points[i].x;
|
|
tmp_points[i].y = points[i].y;
|
|
}
|
|
|
|
if (filled)
|
|
XFillPolygon (GDK_SCREEN_XDISPLAY (impl->screen), impl->xid,
|
|
GDK_GC_GET_XGC (gc), tmp_points, tmp_npoints, Complex, CoordModeOrigin);
|
|
else
|
|
XDrawLines (GDK_SCREEN_XDISPLAY (impl->screen), impl->xid,
|
|
GDK_GC_GET_XGC (gc), tmp_points, tmp_npoints, CoordModeOrigin);
|
|
|
|
g_free (tmp_points);
|
|
}
|
|
|
|
/* gdk_x11_draw_text
|
|
*
|
|
* Modified by Li-Da Lho to draw 16 bits and Multibyte strings
|
|
*
|
|
* Interface changed: add "GdkFont *font" to specify font or fontset explicitely
|
|
*/
|
|
static void
|
|
gdk_x11_draw_text (GdkDrawable *drawable,
|
|
GdkFont *font,
|
|
GdkGC *gc,
|
|
gint x,
|
|
gint y,
|
|
const gchar *text,
|
|
gint text_length)
|
|
{
|
|
GdkDrawableImplX11 *impl;
|
|
Display *xdisplay;
|
|
|
|
impl = GDK_DRAWABLE_IMPL_X11 (drawable);
|
|
xdisplay = GDK_SCREEN_XDISPLAY (impl->screen);
|
|
|
|
if (font->type == GDK_FONT_FONT)
|
|
{
|
|
XFontStruct *xfont = (XFontStruct *) GDK_FONT_XFONT (font);
|
|
XSetFont(xdisplay, GDK_GC_GET_XGC (gc), xfont->fid);
|
|
if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
|
|
{
|
|
XDrawString (xdisplay, impl->xid,
|
|
GDK_GC_GET_XGC (gc), x, y, text, text_length);
|
|
}
|
|
else
|
|
{
|
|
XDrawString16 (xdisplay, impl->xid,
|
|
GDK_GC_GET_XGC (gc), x, y, (XChar2b *) text, text_length / 2);
|
|
}
|
|
}
|
|
else if (font->type == GDK_FONT_FONTSET)
|
|
{
|
|
XFontSet fontset = (XFontSet) GDK_FONT_XFONT (font);
|
|
XmbDrawString (xdisplay, impl->xid,
|
|
fontset, GDK_GC_GET_XGC (gc), x, y, text, text_length);
|
|
}
|
|
else
|
|
g_error("undefined font type\n");
|
|
}
|
|
|
|
static void
|
|
gdk_x11_draw_text_wc (GdkDrawable *drawable,
|
|
GdkFont *font,
|
|
GdkGC *gc,
|
|
gint x,
|
|
gint y,
|
|
const GdkWChar *text,
|
|
gint text_length)
|
|
{
|
|
GdkDrawableImplX11 *impl;
|
|
Display *xdisplay;
|
|
|
|
impl = GDK_DRAWABLE_IMPL_X11 (drawable);
|
|
xdisplay = GDK_SCREEN_XDISPLAY (impl->screen);
|
|
|
|
if (font->type == GDK_FONT_FONT)
|
|
{
|
|
XFontStruct *xfont = (XFontStruct *) GDK_FONT_XFONT (font);
|
|
gchar *text_8bit;
|
|
gint i;
|
|
XSetFont(xdisplay, GDK_GC_GET_XGC (gc), xfont->fid);
|
|
text_8bit = g_new (gchar, text_length);
|
|
for (i=0; i<text_length; i++) text_8bit[i] = text[i];
|
|
XDrawString (xdisplay, impl->xid,
|
|
GDK_GC_GET_XGC (gc), x, y, text_8bit, text_length);
|
|
g_free (text_8bit);
|
|
}
|
|
else if (font->type == GDK_FONT_FONTSET)
|
|
{
|
|
if (sizeof(GdkWChar) == sizeof(wchar_t))
|
|
{
|
|
XwcDrawString (xdisplay, impl->xid,
|
|
(XFontSet) GDK_FONT_XFONT (font),
|
|
GDK_GC_GET_XGC (gc), x, y, (wchar_t *)text, text_length);
|
|
}
|
|
else
|
|
{
|
|
wchar_t *text_wchar;
|
|
gint i;
|
|
text_wchar = g_new (wchar_t, text_length);
|
|
for (i=0; i<text_length; i++) text_wchar[i] = text[i];
|
|
XwcDrawString (xdisplay, impl->xid,
|
|
(XFontSet) GDK_FONT_XFONT (font),
|
|
GDK_GC_GET_XGC (gc), x, y, text_wchar, text_length);
|
|
g_free (text_wchar);
|
|
}
|
|
}
|
|
else
|
|
g_error("undefined font type\n");
|
|
}
|
|
|
|
static void
|
|
gdk_x11_draw_drawable (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
GdkPixmap *src,
|
|
gint xsrc,
|
|
gint ysrc,
|
|
gint xdest,
|
|
gint ydest,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
int src_depth = gdk_drawable_get_depth (src);
|
|
int dest_depth = gdk_drawable_get_depth (drawable);
|
|
GdkDrawableImplX11 *impl;
|
|
GdkDrawableImplX11 *src_impl;
|
|
|
|
impl = GDK_DRAWABLE_IMPL_X11 (drawable);
|
|
|
|
if (GDK_IS_DRAWABLE_IMPL_X11 (src))
|
|
src_impl = GDK_DRAWABLE_IMPL_X11 (src);
|
|
else
|
|
src_impl = NULL;
|
|
|
|
if (src_depth == 1)
|
|
{
|
|
XCopyArea (GDK_SCREEN_XDISPLAY (impl->screen),
|
|
src_impl ? src_impl->xid : GDK_DRAWABLE_XID (src),
|
|
impl->xid,
|
|
GDK_GC_GET_XGC (gc),
|
|
xsrc, ysrc,
|
|
width, height,
|
|
xdest, ydest);
|
|
}
|
|
else if (dest_depth != 0 && src_depth == dest_depth)
|
|
{
|
|
XCopyArea (GDK_SCREEN_XDISPLAY (impl->screen),
|
|
src_impl ? src_impl->xid : GDK_DRAWABLE_XID (src),
|
|
impl->xid,
|
|
GDK_GC_GET_XGC (gc),
|
|
xsrc, ysrc,
|
|
width, height,
|
|
xdest, ydest);
|
|
}
|
|
else
|
|
g_warning ("Attempt to draw a drawable with depth %d to a drawable with depth %d",
|
|
src_depth, dest_depth);
|
|
}
|
|
|
|
static void
|
|
gdk_x11_draw_points (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
GdkPoint *points,
|
|
gint npoints)
|
|
{
|
|
GdkDrawableImplX11 *impl;
|
|
|
|
impl = GDK_DRAWABLE_IMPL_X11 (drawable);
|
|
|
|
|
|
/* We special-case npoints == 1, because X will merge multiple
|
|
* consecutive XDrawPoint requests into a PolyPoint request
|
|
*/
|
|
if (npoints == 1)
|
|
{
|
|
XDrawPoint (GDK_SCREEN_XDISPLAY (impl->screen),
|
|
impl->xid,
|
|
GDK_GC_GET_XGC (gc),
|
|
points[0].x, points[0].y);
|
|
}
|
|
else
|
|
{
|
|
gint i;
|
|
XPoint *tmp_points = g_new (XPoint, npoints);
|
|
|
|
for (i=0; i<npoints; i++)
|
|
{
|
|
tmp_points[i].x = points[i].x;
|
|
tmp_points[i].y = points[i].y;
|
|
}
|
|
|
|
XDrawPoints (GDK_SCREEN_XDISPLAY (impl->screen),
|
|
impl->xid,
|
|
GDK_GC_GET_XGC (gc),
|
|
tmp_points,
|
|
npoints,
|
|
CoordModeOrigin);
|
|
|
|
g_free (tmp_points);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gdk_x11_draw_segments (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
GdkSegment *segs,
|
|
gint nsegs)
|
|
{
|
|
GdkDrawableImplX11 *impl;
|
|
|
|
impl = GDK_DRAWABLE_IMPL_X11 (drawable);
|
|
|
|
|
|
/* We special-case nsegs == 1, because X will merge multiple
|
|
* consecutive XDrawLine requests into a PolySegment request
|
|
*/
|
|
if (nsegs == 1)
|
|
{
|
|
XDrawLine (GDK_SCREEN_XDISPLAY (impl->screen), impl->xid,
|
|
GDK_GC_GET_XGC (gc), segs[0].x1, segs[0].y1,
|
|
segs[0].x2, segs[0].y2);
|
|
}
|
|
else
|
|
{
|
|
gint i;
|
|
XSegment *tmp_segs = g_new (XSegment, nsegs);
|
|
|
|
for (i=0; i<nsegs; i++)
|
|
{
|
|
tmp_segs[i].x1 = segs[i].x1;
|
|
tmp_segs[i].x2 = segs[i].x2;
|
|
tmp_segs[i].y1 = segs[i].y1;
|
|
tmp_segs[i].y2 = segs[i].y2;
|
|
}
|
|
|
|
XDrawSegments (GDK_SCREEN_XDISPLAY (impl->screen),
|
|
impl->xid,
|
|
GDK_GC_GET_XGC (gc),
|
|
tmp_segs, nsegs);
|
|
|
|
g_free (tmp_segs);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gdk_x11_draw_lines (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
GdkPoint *points,
|
|
gint npoints)
|
|
{
|
|
gint i;
|
|
XPoint *tmp_points = g_new (XPoint, npoints);
|
|
GdkDrawableImplX11 *impl;
|
|
|
|
impl = GDK_DRAWABLE_IMPL_X11 (drawable);
|
|
|
|
|
|
for (i=0; i<npoints; i++)
|
|
{
|
|
tmp_points[i].x = points[i].x;
|
|
tmp_points[i].y = points[i].y;
|
|
}
|
|
|
|
XDrawLines (GDK_SCREEN_XDISPLAY (impl->screen),
|
|
impl->xid,
|
|
GDK_GC_GET_XGC (gc),
|
|
tmp_points, npoints,
|
|
CoordModeOrigin);
|
|
|
|
g_free (tmp_points);
|
|
}
|
|
|
|
static void
|
|
gdk_x11_draw_image (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
GdkImage *image,
|
|
gint xsrc,
|
|
gint ysrc,
|
|
gint xdest,
|
|
gint ydest,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
GdkDrawableImplX11 *impl;
|
|
|
|
impl = GDK_DRAWABLE_IMPL_X11 (drawable);
|
|
|
|
#ifdef USE_SHM
|
|
if (image->type == GDK_IMAGE_SHARED)
|
|
XShmPutImage (GDK_SCREEN_XDISPLAY (impl->screen), impl->xid,
|
|
GDK_GC_GET_XGC (gc), GDK_IMAGE_XIMAGE (image),
|
|
xsrc, ysrc, xdest, ydest, width, height, False);
|
|
else
|
|
#endif
|
|
XPutImage (GDK_SCREEN_XDISPLAY (impl->screen), impl->xid,
|
|
GDK_GC_GET_XGC (gc), GDK_IMAGE_XIMAGE (image),
|
|
xsrc, ysrc, xdest, ydest, width, height);
|
|
}
|
|
|
|
static gint
|
|
gdk_x11_get_depth (GdkDrawable *drawable)
|
|
{
|
|
/* This is a bit bogus but I'm not sure the other way is better */
|
|
|
|
return gdk_drawable_get_depth (GDK_DRAWABLE_IMPL_X11 (drawable)->wrapper);
|
|
}
|
|
|
|
static GdkDrawable *
|
|
get_impl_drawable (GdkDrawable *drawable)
|
|
{
|
|
if (GDK_IS_WINDOW (drawable))
|
|
return ((GdkWindowObject *)drawable)->impl;
|
|
else if (GDK_IS_PIXMAP (drawable))
|
|
return ((GdkPixmapObject *)drawable)->impl;
|
|
else
|
|
{
|
|
g_warning (G_STRLOC " drawable is not a pixmap or window");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
static GdkScreen*
|
|
gdk_x11_get_screen (GdkDrawable *drawable)
|
|
{
|
|
if (GDK_IS_DRAWABLE_IMPL_X11 (drawable))
|
|
return GDK_DRAWABLE_IMPL_X11 (drawable)->screen;
|
|
else
|
|
return GDK_DRAWABLE_IMPL_X11 (get_impl_drawable (drawable))->screen;
|
|
}
|
|
|
|
static GdkVisual*
|
|
gdk_x11_get_visual (GdkDrawable *drawable)
|
|
{
|
|
return gdk_drawable_get_visual (GDK_DRAWABLE_IMPL_X11 (drawable)->wrapper);
|
|
}
|
|
|
|
/**
|
|
* gdk_x11_drawable_get_xdisplay:
|
|
* @drawable: a #GdkDrawable.
|
|
*
|
|
* Returns the display of a #GdkDrawable.
|
|
*
|
|
* Return value: an Xlib <type>Display*</type>.
|
|
**/
|
|
Display *
|
|
gdk_x11_drawable_get_xdisplay (GdkDrawable *drawable)
|
|
{
|
|
if (GDK_IS_DRAWABLE_IMPL_X11 (drawable))
|
|
return GDK_SCREEN_XDISPLAY (GDK_DRAWABLE_IMPL_X11 (drawable)->screen);
|
|
else
|
|
return GDK_SCREEN_XDISPLAY (GDK_DRAWABLE_IMPL_X11 (get_impl_drawable (drawable))->screen);
|
|
}
|
|
|
|
/**
|
|
* gdk_x11_drawable_get_xid:
|
|
* @drawable: a #GdkDrawable.
|
|
*
|
|
* Returns the X resource (window or pixmap) belonging to a #GdkDrawable.
|
|
*
|
|
* Return value: the ID of @drawable's X resource.
|
|
**/
|
|
XID
|
|
gdk_x11_drawable_get_xid (GdkDrawable *drawable)
|
|
{
|
|
GdkDrawable *impl;
|
|
|
|
if (GDK_IS_WINDOW (drawable))
|
|
{
|
|
if (!GDK_WINDOW_IS_X11 (drawable))
|
|
{
|
|
/* TODO: At this point we could convert a virtual window
|
|
to a native one (unless its in an offscreen window) */
|
|
g_warning (G_STRLOC " drawable is not a native X11 window");
|
|
return None;
|
|
}
|
|
|
|
impl = ((GdkPixmapObject *)drawable)->impl;
|
|
}
|
|
else if (GDK_IS_PIXMAP (drawable))
|
|
impl = ((GdkPixmapObject *)drawable)->impl;
|
|
else
|
|
{
|
|
g_warning (G_STRLOC " drawable is not a pixmap or window");
|
|
return None;
|
|
}
|
|
|
|
return ((GdkDrawableImplX11 *)impl)->xid;
|
|
}
|
|
|
|
/* Code for accelerated alpha compositing using the RENDER extension.
|
|
* It's a bit long because there are lots of possibilities for
|
|
* what's the fastest depending on the available picture formats,
|
|
* whether we can used shared pixmaps, etc.
|
|
*/
|
|
|
|
static GdkX11FormatType
|
|
select_format (GdkDisplay *display,
|
|
XRenderPictFormat **format,
|
|
XRenderPictFormat **mask)
|
|
{
|
|
Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
|
|
XRenderPictFormat pf;
|
|
|
|
if (!_gdk_x11_have_render (display))
|
|
return GDK_X11_FORMAT_NONE;
|
|
|
|
/* Look for a 32-bit xRGB and Axxx formats that exactly match the
|
|
* in memory data format. We can use them as pixmap and mask
|
|
* to deal with non-premultiplied data.
|
|
*/
|
|
|
|
pf.type = PictTypeDirect;
|
|
pf.depth = 32;
|
|
pf.direct.redMask = 0xff;
|
|
pf.direct.greenMask = 0xff;
|
|
pf.direct.blueMask = 0xff;
|
|
|
|
pf.direct.alphaMask = 0;
|
|
if (ImageByteOrder (xdisplay) == LSBFirst)
|
|
{
|
|
/* ABGR */
|
|
pf.direct.red = 0;
|
|
pf.direct.green = 8;
|
|
pf.direct.blue = 16;
|
|
}
|
|
else
|
|
{
|
|
/* RGBA */
|
|
pf.direct.red = 24;
|
|
pf.direct.green = 16;
|
|
pf.direct.blue = 8;
|
|
}
|
|
|
|
*format = XRenderFindFormat (xdisplay,
|
|
(PictFormatType | PictFormatDepth |
|
|
PictFormatRedMask | PictFormatRed |
|
|
PictFormatGreenMask | PictFormatGreen |
|
|
PictFormatBlueMask | PictFormatBlue |
|
|
PictFormatAlphaMask),
|
|
&pf,
|
|
0);
|
|
|
|
pf.direct.alphaMask = 0xff;
|
|
if (ImageByteOrder (xdisplay) == LSBFirst)
|
|
{
|
|
/* ABGR */
|
|
pf.direct.alpha = 24;
|
|
}
|
|
else
|
|
{
|
|
pf.direct.alpha = 0;
|
|
}
|
|
|
|
*mask = XRenderFindFormat (xdisplay,
|
|
(PictFormatType | PictFormatDepth |
|
|
PictFormatAlphaMask | PictFormatAlpha),
|
|
&pf,
|
|
0);
|
|
|
|
if (*format && *mask)
|
|
return GDK_X11_FORMAT_EXACT_MASK;
|
|
|
|
/* OK, that failed, now look for xRGB and Axxx formats in
|
|
* RENDER's preferred order
|
|
*/
|
|
pf.direct.alphaMask = 0;
|
|
/* ARGB */
|
|
pf.direct.red = 16;
|
|
pf.direct.green = 8;
|
|
pf.direct.blue = 0;
|
|
|
|
*format = XRenderFindFormat (xdisplay,
|
|
(PictFormatType | PictFormatDepth |
|
|
PictFormatRedMask | PictFormatRed |
|
|
PictFormatGreenMask | PictFormatGreen |
|
|
PictFormatBlueMask | PictFormatBlue |
|
|
PictFormatAlphaMask),
|
|
&pf,
|
|
0);
|
|
|
|
pf.direct.alphaMask = 0xff;
|
|
pf.direct.alpha = 24;
|
|
|
|
*mask = XRenderFindFormat (xdisplay,
|
|
(PictFormatType | PictFormatDepth |
|
|
PictFormatAlphaMask | PictFormatAlpha),
|
|
&pf,
|
|
0);
|
|
|
|
if (*format && *mask)
|
|
return GDK_X11_FORMAT_ARGB_MASK;
|
|
|
|
/* Finally, if neither of the above worked, fall back to
|
|
* looking for combined ARGB -- we'll premultiply ourselves.
|
|
*/
|
|
|
|
pf.type = PictTypeDirect;
|
|
pf.depth = 32;
|
|
pf.direct.red = 16;
|
|
pf.direct.green = 8;
|
|
pf.direct.blue = 0;
|
|
pf.direct.alphaMask = 0xff;
|
|
pf.direct.alpha = 24;
|
|
|
|
*format = XRenderFindFormat (xdisplay,
|
|
(PictFormatType | PictFormatDepth |
|
|
PictFormatRedMask | PictFormatRed |
|
|
PictFormatGreenMask | PictFormatGreen |
|
|
PictFormatBlueMask | PictFormatBlue |
|
|
PictFormatAlphaMask | PictFormatAlpha),
|
|
&pf,
|
|
0);
|
|
*mask = NULL;
|
|
|
|
if (*format)
|
|
return GDK_X11_FORMAT_ARGB;
|
|
|
|
return GDK_X11_FORMAT_NONE;
|
|
}
|
|
|
|
#if 0
|
|
static void
|
|
list_formats (XRenderPictFormat *pf)
|
|
{
|
|
gint i;
|
|
|
|
for (i=0 ;; i++)
|
|
{
|
|
XRenderPictFormat *pf = XRenderFindFormat (impl->xdisplay, 0, NULL, i);
|
|
if (pf)
|
|
{
|
|
g_print ("%2d R-%#06x/%#06x G-%#06x/%#06x B-%#06x/%#06x A-%#06x/%#06x\n",
|
|
pf->depth,
|
|
pf->direct.red,
|
|
pf->direct.redMask,
|
|
pf->direct.green,
|
|
pf->direct.greenMask,
|
|
pf->direct.blue,
|
|
pf->direct.blueMask,
|
|
pf->direct.alpha,
|
|
pf->direct.alphaMask);
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void
|
|
_gdk_x11_convert_to_format (guchar *src_buf,
|
|
gint src_rowstride,
|
|
guchar *dest_buf,
|
|
gint dest_rowstride,
|
|
GdkX11FormatType dest_format,
|
|
GdkByteOrder dest_byteorder,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
gint i;
|
|
|
|
for (i=0; i < height; i++)
|
|
{
|
|
switch (dest_format)
|
|
{
|
|
case GDK_X11_FORMAT_EXACT_MASK:
|
|
{
|
|
memcpy (dest_buf + i * dest_rowstride,
|
|
src_buf + i * src_rowstride,
|
|
width * 4);
|
|
break;
|
|
}
|
|
case GDK_X11_FORMAT_ARGB_MASK:
|
|
{
|
|
guchar *row = src_buf + i * src_rowstride;
|
|
if (((gsize)row & 3) != 0)
|
|
{
|
|
guchar *p = row;
|
|
guint32 *q = (guint32 *)(dest_buf + i * dest_rowstride);
|
|
guchar *end = p + 4 * width;
|
|
|
|
while (p < end)
|
|
{
|
|
*q = (p[3] << 24) | (p[0] << 16) | (p[1] << 8) | p[2];
|
|
p += 4;
|
|
q++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
guint32 *p = (guint32 *)row;
|
|
guint32 *q = (guint32 *)(dest_buf + i * dest_rowstride);
|
|
guint32 *end = p + width;
|
|
|
|
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
|
if (dest_byteorder == GDK_LSB_FIRST)
|
|
{
|
|
/* ABGR => ARGB */
|
|
|
|
while (p < end)
|
|
{
|
|
*q = ( (*p & 0xff00ff00) |
|
|
((*p & 0x000000ff) << 16) |
|
|
((*p & 0x00ff0000) >> 16));
|
|
q++;
|
|
p++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* ABGR => BGRA */
|
|
|
|
while (p < end)
|
|
{
|
|
*q = (((*p & 0xff000000) >> 24) |
|
|
((*p & 0x00ffffff) << 8));
|
|
q++;
|
|
p++;
|
|
}
|
|
}
|
|
#else /* G_BYTE_ORDER == G_BIG_ENDIAN */
|
|
if (dest_byteorder == GDK_LSB_FIRST)
|
|
{
|
|
/* RGBA => BGRA */
|
|
|
|
while (p < end)
|
|
{
|
|
*q = ( (*p & 0x00ff00ff) |
|
|
((*p & 0x0000ff00) << 16) |
|
|
((*p & 0xff000000) >> 16));
|
|
q++;
|
|
p++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* RGBA => ARGB */
|
|
|
|
while (p < end)
|
|
{
|
|
*q = (((*p & 0xffffff00) >> 8) |
|
|
((*p & 0x000000ff) << 24));
|
|
q++;
|
|
p++;
|
|
}
|
|
}
|
|
#endif /* G_BYTE_ORDER*/
|
|
}
|
|
break;
|
|
}
|
|
case GDK_X11_FORMAT_ARGB:
|
|
{
|
|
guchar *p = (src_buf + i * src_rowstride);
|
|
guchar *q = (dest_buf + i * dest_rowstride);
|
|
guchar *end = p + 4 * width;
|
|
guint t1,t2,t3;
|
|
|
|
#define MULT(d,c,a,t) G_STMT_START { t = c * a; d = ((t >> 8) + t) >> 8; } G_STMT_END
|
|
|
|
if (dest_byteorder == GDK_LSB_FIRST)
|
|
{
|
|
while (p < end)
|
|
{
|
|
MULT(q[0], p[2], p[3], t1);
|
|
MULT(q[1], p[1], p[3], t2);
|
|
MULT(q[2], p[0], p[3], t3);
|
|
q[3] = p[3];
|
|
p += 4;
|
|
q += 4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (p < end)
|
|
{
|
|
q[0] = p[3];
|
|
MULT(q[1], p[0], p[3], t1);
|
|
MULT(q[2], p[1], p[3], t2);
|
|
MULT(q[3], p[2], p[3], t3);
|
|
p += 4;
|
|
q += 4;
|
|
}
|
|
}
|
|
#undef MULT
|
|
break;
|
|
}
|
|
case GDK_X11_FORMAT_NONE:
|
|
g_assert_not_reached ();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
draw_with_images (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
GdkX11FormatType format_type,
|
|
XRenderPictFormat *format,
|
|
XRenderPictFormat *mask_format,
|
|
guchar *src_rgb,
|
|
gint src_rowstride,
|
|
gint dest_x,
|
|
gint dest_y,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
GdkScreen *screen = GDK_DRAWABLE_IMPL_X11 (drawable)->screen;
|
|
Display *xdisplay = GDK_SCREEN_XDISPLAY (screen);
|
|
GdkImage *image;
|
|
GdkPixmap *pix;
|
|
GdkGC *pix_gc;
|
|
Picture pict;
|
|
Picture dest_pict;
|
|
Picture mask = None;
|
|
gint x0, y0;
|
|
|
|
pix = gdk_pixmap_new (gdk_screen_get_root_window (screen), width, height, 32);
|
|
|
|
pict = XRenderCreatePicture (xdisplay,
|
|
GDK_PIXMAP_XID (pix),
|
|
format, 0, NULL);
|
|
if (mask_format)
|
|
mask = XRenderCreatePicture (xdisplay,
|
|
GDK_PIXMAP_XID (pix),
|
|
mask_format, 0, NULL);
|
|
|
|
dest_pict = gdk_x11_drawable_get_picture (drawable);
|
|
|
|
pix_gc = _gdk_drawable_get_scratch_gc (pix, FALSE);
|
|
|
|
for (y0 = 0; y0 < height; y0 += GDK_SCRATCH_IMAGE_HEIGHT)
|
|
{
|
|
gint height1 = MIN (height - y0, GDK_SCRATCH_IMAGE_HEIGHT);
|
|
for (x0 = 0; x0 < width; x0 += GDK_SCRATCH_IMAGE_WIDTH)
|
|
{
|
|
gint xs0, ys0;
|
|
|
|
gint width1 = MIN (width - x0, GDK_SCRATCH_IMAGE_WIDTH);
|
|
|
|
image = _gdk_image_get_scratch (screen, width1, height1, 32, &xs0, &ys0);
|
|
|
|
_gdk_x11_convert_to_format (src_rgb + y0 * src_rowstride + 4 * x0, src_rowstride,
|
|
(guchar *)image->mem + ys0 * image->bpl + xs0 * image->bpp, image->bpl,
|
|
format_type, image->byte_order,
|
|
width1, height1);
|
|
|
|
gdk_draw_image (pix, pix_gc,
|
|
image, xs0, ys0, x0, y0, width1, height1);
|
|
}
|
|
}
|
|
|
|
XRenderComposite (xdisplay, PictOpOver, pict, mask, dest_pict,
|
|
0, 0, 0, 0, dest_x, dest_y, width, height);
|
|
|
|
XRenderFreePicture (xdisplay, pict);
|
|
if (mask)
|
|
XRenderFreePicture (xdisplay, mask);
|
|
|
|
g_object_unref (pix);
|
|
}
|
|
|
|
typedef struct _ShmPixmapInfo ShmPixmapInfo;
|
|
|
|
struct _ShmPixmapInfo
|
|
{
|
|
Display *display;
|
|
Pixmap pix;
|
|
Picture pict;
|
|
Picture mask;
|
|
};
|
|
|
|
static void
|
|
shm_pixmap_info_destroy (gpointer data)
|
|
{
|
|
ShmPixmapInfo *info = data;
|
|
|
|
if (info->pict != None)
|
|
XRenderFreePicture (info->display, info->pict);
|
|
if (info->mask != None)
|
|
XRenderFreePicture (info->display, info->mask);
|
|
|
|
g_free (data);
|
|
}
|
|
|
|
|
|
/* Returns FALSE if we can't get a shm pixmap */
|
|
static gboolean
|
|
get_shm_pixmap_for_image (Display *xdisplay,
|
|
GdkImage *image,
|
|
XRenderPictFormat *format,
|
|
XRenderPictFormat *mask_format,
|
|
Pixmap *pix,
|
|
Picture *pict,
|
|
Picture *mask)
|
|
{
|
|
ShmPixmapInfo *info;
|
|
|
|
if (image->type != GDK_IMAGE_SHARED)
|
|
return FALSE;
|
|
|
|
info = g_object_get_data (G_OBJECT (image), "gdk-x11-shm-pixmap");
|
|
if (!info)
|
|
{
|
|
*pix = _gdk_x11_image_get_shm_pixmap (image);
|
|
|
|
if (!*pix)
|
|
return FALSE;
|
|
|
|
info = g_new (ShmPixmapInfo, 1);
|
|
info->display = xdisplay;
|
|
info->pix = *pix;
|
|
|
|
info->pict = XRenderCreatePicture (xdisplay, info->pix,
|
|
format, 0, NULL);
|
|
if (mask_format)
|
|
info->mask = XRenderCreatePicture (xdisplay, info->pix,
|
|
mask_format, 0, NULL);
|
|
else
|
|
info->mask = None;
|
|
|
|
g_object_set_data_full (G_OBJECT (image), "gdk-x11-shm-pixmap", info,
|
|
shm_pixmap_info_destroy);
|
|
}
|
|
|
|
*pix = info->pix;
|
|
*pict = info->pict;
|
|
*mask = info->mask;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#ifdef USE_SHM
|
|
/* Returns FALSE if drawing with ShmPixmaps is not possible */
|
|
static gboolean
|
|
draw_with_pixmaps (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
GdkX11FormatType format_type,
|
|
XRenderPictFormat *format,
|
|
XRenderPictFormat *mask_format,
|
|
guchar *src_rgb,
|
|
gint src_rowstride,
|
|
gint dest_x,
|
|
gint dest_y,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
Display *xdisplay = GDK_SCREEN_XDISPLAY (GDK_DRAWABLE_IMPL_X11 (drawable)->screen);
|
|
GdkImage *image;
|
|
Pixmap pix;
|
|
Picture pict;
|
|
Picture dest_pict;
|
|
Picture mask = None;
|
|
gint x0, y0;
|
|
|
|
dest_pict = gdk_x11_drawable_get_picture (drawable);
|
|
|
|
for (y0 = 0; y0 < height; y0 += GDK_SCRATCH_IMAGE_HEIGHT)
|
|
{
|
|
gint height1 = MIN (height - y0, GDK_SCRATCH_IMAGE_HEIGHT);
|
|
for (x0 = 0; x0 < width; x0 += GDK_SCRATCH_IMAGE_WIDTH)
|
|
{
|
|
gint xs0, ys0;
|
|
|
|
gint width1 = MIN (width - x0, GDK_SCRATCH_IMAGE_WIDTH);
|
|
|
|
image = _gdk_image_get_scratch (GDK_DRAWABLE_IMPL_X11 (drawable)->screen,
|
|
width1, height1, 32, &xs0, &ys0);
|
|
if (!get_shm_pixmap_for_image (xdisplay, image, format, mask_format, &pix, &pict, &mask))
|
|
return FALSE;
|
|
|
|
_gdk_x11_convert_to_format (src_rgb + y0 * src_rowstride + 4 * x0, src_rowstride,
|
|
(guchar *)image->mem + ys0 * image->bpl + xs0 * image->bpp, image->bpl,
|
|
format_type, image->byte_order,
|
|
width1, height1);
|
|
|
|
XRenderComposite (xdisplay, PictOpOver, pict, mask, dest_pict,
|
|
xs0, ys0, xs0, ys0, x0 + dest_x, y0 + dest_y,
|
|
width1, height1);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
gdk_x11_draw_pixbuf (GdkDrawable *drawable,
|
|
GdkGC *gc,
|
|
GdkPixbuf *pixbuf,
|
|
gint src_x,
|
|
gint src_y,
|
|
gint dest_x,
|
|
gint dest_y,
|
|
gint width,
|
|
gint height,
|
|
GdkRgbDither dither,
|
|
gint x_dither,
|
|
gint y_dither)
|
|
{
|
|
GdkX11FormatType format_type;
|
|
XRenderPictFormat *format, *mask_format;
|
|
gint rowstride;
|
|
#ifdef USE_SHM
|
|
gboolean use_pixmaps = TRUE;
|
|
#endif /* USE_SHM */
|
|
|
|
format_type = select_format (gdk_drawable_get_display (drawable),
|
|
&format, &mask_format);
|
|
|
|
if (format_type == GDK_X11_FORMAT_NONE ||
|
|
!gdk_pixbuf_get_has_alpha (pixbuf) ||
|
|
gdk_drawable_get_depth (drawable) == 1 ||
|
|
(dither == GDK_RGB_DITHER_MAX && gdk_drawable_get_depth (drawable) != 24) ||
|
|
gdk_x11_drawable_get_picture (drawable) == None)
|
|
{
|
|
GdkDrawable *wrapper = GDK_DRAWABLE_IMPL_X11 (drawable)->wrapper;
|
|
GDK_DRAWABLE_CLASS (_gdk_drawable_impl_x11_parent_class)->draw_pixbuf (wrapper, gc, pixbuf,
|
|
src_x, src_y, dest_x, dest_y,
|
|
width, height,
|
|
dither, x_dither, y_dither);
|
|
return;
|
|
}
|
|
|
|
gdk_x11_drawable_update_picture_clip (drawable, gc);
|
|
|
|
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
|
|
|
|
#ifdef USE_SHM
|
|
if (use_pixmaps)
|
|
{
|
|
if (!draw_with_pixmaps (drawable, gc,
|
|
format_type, format, mask_format,
|
|
gdk_pixbuf_get_pixels (pixbuf) + src_y * rowstride + src_x * 4,
|
|
rowstride,
|
|
dest_x, dest_y, width, height))
|
|
use_pixmaps = FALSE;
|
|
}
|
|
|
|
if (!use_pixmaps)
|
|
#endif /* USE_SHM */
|
|
draw_with_images (drawable, gc,
|
|
format_type, format, mask_format,
|
|
gdk_pixbuf_get_pixels (pixbuf) + src_y * rowstride + src_x * 4,
|
|
rowstride,
|
|
dest_x, dest_y, width, height);
|
|
}
|
|
|
|
static void
|
|
gdk_x11_cairo_surface_destroy (void *data)
|
|
{
|
|
GdkDrawableImplX11 *impl = data;
|
|
|
|
impl->cairo_surface = NULL;
|
|
}
|
|
|
|
void
|
|
_gdk_windowing_set_cairo_surface_size (cairo_surface_t *surface,
|
|
int width,
|
|
int height)
|
|
{
|
|
cairo_xlib_surface_set_size (surface, width, height);
|
|
}
|
|
|
|
cairo_surface_t *
|
|
_gdk_windowing_create_cairo_surface (GdkDrawable *drawable,
|
|
int width,
|
|
int height)
|
|
{
|
|
GdkDrawableImplX11 *impl = GDK_DRAWABLE_IMPL_X11 (drawable);
|
|
GdkVisual *visual;
|
|
|
|
visual = gdk_drawable_get_visual (drawable);
|
|
if (visual)
|
|
return cairo_xlib_surface_create (GDK_SCREEN_XDISPLAY (impl->screen),
|
|
impl->xid,
|
|
GDK_VISUAL_XVISUAL (visual),
|
|
width, height);
|
|
else if (gdk_drawable_get_depth (drawable) == 1)
|
|
return cairo_xlib_surface_create_for_bitmap (GDK_SCREEN_XDISPLAY (impl->screen),
|
|
impl->xid,
|
|
GDK_SCREEN_XSCREEN (impl->screen),
|
|
width, height);
|
|
else
|
|
{
|
|
g_warning ("Using Cairo rendering requires the drawable argument to\n"
|
|
"have a specified colormap. All windows have a colormap,\n"
|
|
"however, pixmaps only have colormap by default if they\n"
|
|
"were created with a non-NULL window argument. Otherwise\n"
|
|
"a colormap must be set on them with gdk_drawable_set_colormap");
|
|
return NULL;
|
|
}
|
|
|
|
}
|
|
|
|
static cairo_surface_t *
|
|
gdk_x11_ref_cairo_surface (GdkDrawable *drawable)
|
|
{
|
|
GdkDrawableImplX11 *impl = GDK_DRAWABLE_IMPL_X11 (drawable);
|
|
|
|
if (GDK_IS_WINDOW_IMPL_X11 (drawable) &&
|
|
GDK_WINDOW_DESTROYED (impl->wrapper))
|
|
return NULL;
|
|
|
|
if (!impl->cairo_surface)
|
|
{
|
|
int width, height;
|
|
|
|
gdk_drawable_get_size (drawable, &width, &height);
|
|
|
|
impl->cairo_surface = _gdk_windowing_create_cairo_surface (drawable, width, height);
|
|
|
|
if (impl->cairo_surface)
|
|
cairo_surface_set_user_data (impl->cairo_surface, &gdk_x11_cairo_key,
|
|
drawable, gdk_x11_cairo_surface_destroy);
|
|
}
|
|
else
|
|
cairo_surface_reference (impl->cairo_surface);
|
|
|
|
return impl->cairo_surface;
|
|
}
|
|
|
|
#define __GDK_DRAWABLE_X11_C__
|
|
#include "gdkaliasdef.c"
|