2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
30 #include "gdkregion-generic.h"
32 #include <pango/pangoxft.h>
34 #include <cairo-xlib.h>
37 #include <string.h> /* for memcpy() */
39 #if defined (HAVE_IPC_H) && defined (HAVE_SHM_H) && defined (HAVE_XSHM_H)
44 #include <X11/extensions/XShm.h>
47 #include "gdkprivate-x11.h"
48 #include "gdkdrawable-x11.h"
49 #include "gdkpixmap-x11.h"
50 #include "gdkscreen-x11.h"
51 #include "gdkdisplay-x11.h"
55 static void gdk_x11_draw_rectangle (GdkDrawable *drawable,
62 static void gdk_x11_draw_arc (GdkDrawable *drawable,
71 static void gdk_x11_draw_polygon (GdkDrawable *drawable,
76 static void gdk_x11_draw_text (GdkDrawable *drawable,
83 static void gdk_x11_draw_text_wc (GdkDrawable *drawable,
90 static void gdk_x11_draw_drawable (GdkDrawable *drawable,
99 static void gdk_x11_draw_points (GdkDrawable *drawable,
103 static void gdk_x11_draw_segments (GdkDrawable *drawable,
107 static void gdk_x11_draw_lines (GdkDrawable *drawable,
112 static void gdk_x11_draw_glyphs (GdkDrawable *drawable,
117 PangoGlyphString *glyphs);
118 static void gdk_x11_draw_glyphs_transformed (GdkDrawable *drawable,
124 PangoGlyphString *glyphs);
126 static void gdk_x11_draw_image (GdkDrawable *drawable,
135 static void gdk_x11_draw_pixbuf (GdkDrawable *drawable,
148 static void gdk_x11_draw_trapezoids (GdkDrawable *drawable,
150 GdkTrapezoid *trapezoids,
153 static void gdk_x11_set_cairo_target (GdkDrawable *drawable,
156 static void gdk_x11_set_colormap (GdkDrawable *drawable,
157 GdkColormap *colormap);
159 static GdkColormap* gdk_x11_get_colormap (GdkDrawable *drawable);
160 static gint gdk_x11_get_depth (GdkDrawable *drawable);
161 static GdkScreen * gdk_x11_get_screen (GdkDrawable *drawable);
162 static GdkVisual* gdk_x11_get_visual (GdkDrawable *drawable);
164 static void gdk_drawable_impl_x11_class_init (GdkDrawableImplX11Class *klass);
166 static void gdk_drawable_impl_x11_finalize (GObject *object);
168 static gpointer parent_class = NULL;
171 _gdk_drawable_impl_x11_get_type (void)
173 static GType object_type = 0;
177 static const GTypeInfo object_info =
179 sizeof (GdkDrawableImplX11Class),
180 (GBaseInitFunc) NULL,
181 (GBaseFinalizeFunc) NULL,
182 (GClassInitFunc) gdk_drawable_impl_x11_class_init,
183 NULL, /* class_finalize */
184 NULL, /* class_data */
185 sizeof (GdkDrawableImplX11),
187 (GInstanceInitFunc) NULL,
190 object_type = g_type_register_static (GDK_TYPE_DRAWABLE,
191 "GdkDrawableImplX11",
199 gdk_drawable_impl_x11_class_init (GdkDrawableImplX11Class *klass)
201 GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
202 GObjectClass *object_class = G_OBJECT_CLASS (klass);
204 parent_class = g_type_class_peek_parent (klass);
206 object_class->finalize = gdk_drawable_impl_x11_finalize;
208 drawable_class->create_gc = _gdk_x11_gc_new;
209 drawable_class->draw_rectangle = gdk_x11_draw_rectangle;
210 drawable_class->draw_arc = gdk_x11_draw_arc;
211 drawable_class->draw_polygon = gdk_x11_draw_polygon;
212 drawable_class->draw_text = gdk_x11_draw_text;
213 drawable_class->draw_text_wc = gdk_x11_draw_text_wc;
214 drawable_class->draw_drawable = gdk_x11_draw_drawable;
215 drawable_class->draw_points = gdk_x11_draw_points;
216 drawable_class->draw_segments = gdk_x11_draw_segments;
217 drawable_class->draw_lines = gdk_x11_draw_lines;
218 drawable_class->draw_glyphs = gdk_x11_draw_glyphs;
219 drawable_class->draw_glyphs_transformed = gdk_x11_draw_glyphs_transformed;
220 drawable_class->draw_image = gdk_x11_draw_image;
221 drawable_class->draw_pixbuf = gdk_x11_draw_pixbuf;
222 drawable_class->draw_trapezoids = gdk_x11_draw_trapezoids;
224 drawable_class->set_cairo_target = gdk_x11_set_cairo_target;
226 drawable_class->set_colormap = gdk_x11_set_colormap;
227 drawable_class->get_colormap = gdk_x11_get_colormap;
229 drawable_class->get_depth = gdk_x11_get_depth;
230 drawable_class->get_screen = gdk_x11_get_screen;
231 drawable_class->get_visual = gdk_x11_get_visual;
233 drawable_class->_copy_to_image = _gdk_x11_copy_to_image;
237 gdk_drawable_impl_x11_finalize (GObject *object)
239 gdk_drawable_set_colormap (GDK_DRAWABLE (object), NULL);
241 G_OBJECT_CLASS (parent_class)->finalize (object);
245 try_pixmap (Display *xdisplay,
249 Pixmap pixmap = XCreatePixmap (xdisplay,
250 RootWindow (xdisplay, screen),
252 XFreePixmap (xdisplay, pixmap);
256 _gdk_x11_have_render (GdkDisplay *display)
258 Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
259 GdkDisplayX11 *x11display = GDK_DISPLAY_X11 (display);
261 if (x11display->have_render == GDK_UNKNOWN)
263 int event_base, error_base;
264 x11display->have_render =
265 XRenderQueryExtension (xdisplay, &event_base, &error_base)
268 if (x11display->have_render == GDK_YES)
271 * Sun advertises RENDER, but fails to support 32-bit pixmaps.
272 * That is just no good. Therefore, we check all screens
273 * for proper support.
277 for (screen = 0; screen < ScreenCount (xdisplay); screen++)
280 int *depths = XListDepths (xdisplay, screen, &count);
281 gboolean has_8 = FALSE, has_32 = FALSE;
287 for (i = 0; i < count; i++)
291 else if (depths[i] == 32)
297 /* At this point, we might have a false positive;
298 * buggy versions of Xinerama only report depths for
299 * which there is an associated visual; so we actually
300 * go ahead and try create pixmaps.
302 if (!(has_8 && has_32))
304 gdk_error_trap_push ();
306 try_pixmap (xdisplay, screen, 8);
308 try_pixmap (xdisplay, screen, 32);
309 XSync (xdisplay, False);
310 if (gdk_error_trap_pop () == 0)
317 if (!(has_8 && has_32))
319 g_warning ("The X server advertises that RENDER support is present,\n"
320 "but fails to supply the necessary pixmap support. In\n"
321 "other words, it is buggy.");
322 x11display->have_render = GDK_NO;
329 return x11display->have_render == GDK_YES;
333 _gdk_x11_have_render_with_trapezoids (GdkDisplay *display)
335 Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
336 GdkDisplayX11 *x11display = GDK_DISPLAY_X11 (display);
338 if (x11display->have_render_with_trapezoids == GDK_UNKNOWN)
340 x11display->have_render_with_trapezoids = GDK_NO;
341 if (_gdk_x11_have_render (display))
344 * Require protocol >= 0.4 for CompositeTrapezoids support.
346 int major_version, minor_version;
348 #define XRENDER_TETRAPEZOIDS_MAJOR 0
349 #define XRENDER_TETRAPEZOIDS_MINOR 4
351 if (XRenderQueryVersion (xdisplay, &major_version,
354 if ((major_version == XRENDER_TETRAPEZOIDS_MAJOR) &&
355 (minor_version >= XRENDER_TETRAPEZOIDS_MINOR))
356 x11display->have_render_with_trapezoids = GDK_YES;
361 return x11display->have_render_with_trapezoids == GDK_YES;
365 gdk_x11_drawable_get_xft_draw (GdkDrawable *drawable)
367 GdkDrawableImplX11 *impl = GDK_DRAWABLE_IMPL_X11 (drawable);
369 if (impl->xft_draw == NULL)
371 GdkColormap *colormap = gdk_drawable_get_colormap (drawable);
377 visual = gdk_colormap_get_visual (colormap);
379 impl->xft_draw = XftDrawCreate (GDK_SCREEN_XDISPLAY (impl->screen), impl->xid,
380 GDK_VISUAL_XVISUAL (visual), GDK_COLORMAP_XCOLORMAP (colormap));
382 else if (gdk_drawable_get_depth (drawable) == 1)
384 impl->xft_draw = XftDrawCreateBitmap (GDK_SCREEN_XDISPLAY (impl->screen), impl->xid);
388 g_warning ("Using Xft rendering requires the drawable argument to\n"
389 "have a specified colormap. All windows have a colormap,\n"
390 "however, pixmaps only have colormap by default if they\n"
391 "were created with a non-NULL window argument. Otherwise\n"
392 "a colormap must be set on them with gdk_drawable_set_colormap");
397 return impl->xft_draw;
401 gdk_x11_drawable_get_picture (GdkDrawable *drawable)
403 XftDraw *draw = gdk_x11_drawable_get_xft_draw (drawable);
405 return draw ? XftDrawPicture (draw) : None;
409 gdk_x11_drawable_update_xft_clip (GdkDrawable *drawable,
412 GdkGCX11 *gc_private = gc ? GDK_GC_X11 (gc) : NULL;
413 XftDraw *xft_draw = gdk_x11_drawable_get_xft_draw (drawable);
415 if (gc && gc_private->clip_region)
417 GdkRegionBox *boxes = gc_private->clip_region->rects;
418 gint n_boxes = gc_private->clip_region->numRects;
419 #if 0 /* Until XftDrawSetClipRectangles is there */
420 XRectangle *rects = g_new (XRectangle, n_boxes);
423 for (i=0; i < n_boxes; i++)
425 rects[i].x = CLAMP (boxes[i].x1 + gc->clip_x_origin, G_MINSHORT, G_MAXSHORT);
426 rects[i].y = CLAMP (boxes[i].y1 + gc->clip_y_origin, G_MINSHORT, G_MAXSHORT);
427 rects[i].width = CLAMP (boxes[i].x2 + gc->clip_x_origin, G_MINSHORT, G_MAXSHORT) - rects[i].x;
428 rects[i].height = CLAMP (boxes[i].y2 + gc->clip_y_origin, G_MINSHORT, G_MAXSHORT) - rects[i].y;
430 XftDrawSetClipRectangles (xft_draw, 0, 0, rects, n_boxes);
434 Region xregion = XCreateRegion ();
437 for (i=0; i < n_boxes; i++)
441 rect.x = CLAMP (boxes[i].x1 + gc->clip_x_origin, G_MINSHORT, G_MAXSHORT);
442 rect.y = CLAMP (boxes[i].y1 + gc->clip_y_origin, G_MINSHORT, G_MAXSHORT);
443 rect.width = CLAMP (boxes[i].x2 + gc->clip_x_origin, G_MINSHORT, G_MAXSHORT) - rect.x;
444 rect.height = CLAMP (boxes[i].y2 + gc->clip_y_origin, G_MINSHORT, G_MAXSHORT) - rect.y;
446 XUnionRectWithRegion (&rect, xregion, xregion);
449 XftDrawSetClip (xft_draw, xregion);
450 XDestroyRegion (xregion);
455 XftDrawSetClip (xft_draw, NULL);
459 /*****************************************************
460 * X11 specific implementations of generic functions *
461 *****************************************************/
464 gdk_x11_get_colormap (GdkDrawable *drawable)
466 GdkDrawableImplX11 *impl;
468 impl = GDK_DRAWABLE_IMPL_X11 (drawable);
470 return impl->colormap;
474 gdk_x11_set_colormap (GdkDrawable *drawable,
475 GdkColormap *colormap)
477 GdkDrawableImplX11 *impl;
479 impl = GDK_DRAWABLE_IMPL_X11 (drawable);
481 if (impl->colormap == colormap)
485 g_object_unref (impl->colormap);
486 impl->colormap = colormap;
488 g_object_ref (impl->colormap);
495 gdk_x11_draw_rectangle (GdkDrawable *drawable,
503 GdkDrawableImplX11 *impl;
505 impl = GDK_DRAWABLE_IMPL_X11 (drawable);
508 XFillRectangle (GDK_SCREEN_XDISPLAY (impl->screen), impl->xid,
509 GDK_GC_GET_XGC (gc), x, y, width, height);
511 XDrawRectangle (GDK_SCREEN_XDISPLAY (impl->screen), impl->xid,
512 GDK_GC_GET_XGC (gc), x, y, width, height);
516 gdk_x11_draw_arc (GdkDrawable *drawable,
526 GdkDrawableImplX11 *impl;
528 impl = GDK_DRAWABLE_IMPL_X11 (drawable);
532 XFillArc (GDK_SCREEN_XDISPLAY (impl->screen), impl->xid,
533 GDK_GC_GET_XGC (gc), x, y, width, height, angle1, angle2);
535 XDrawArc (GDK_SCREEN_XDISPLAY (impl->screen), impl->xid,
536 GDK_GC_GET_XGC (gc), x, y, width, height, angle1, angle2);
540 gdk_x11_draw_polygon (GdkDrawable *drawable,
548 GdkDrawableImplX11 *impl;
550 impl = GDK_DRAWABLE_IMPL_X11 (drawable);
554 (points[0].x != points[npoints-1].x || points[0].y != points[npoints-1].y))
556 tmp_npoints = npoints + 1;
557 tmp_points = g_new (XPoint, tmp_npoints);
558 tmp_points[npoints].x = points[0].x;
559 tmp_points[npoints].y = points[0].y;
563 tmp_npoints = npoints;
564 tmp_points = g_new (XPoint, tmp_npoints);
567 for (i=0; i<npoints; i++)
569 tmp_points[i].x = points[i].x;
570 tmp_points[i].y = points[i].y;
574 XFillPolygon (GDK_SCREEN_XDISPLAY (impl->screen), impl->xid,
575 GDK_GC_GET_XGC (gc), tmp_points, tmp_npoints, Complex, CoordModeOrigin);
577 XDrawLines (GDK_SCREEN_XDISPLAY (impl->screen), impl->xid,
578 GDK_GC_GET_XGC (gc), tmp_points, tmp_npoints, CoordModeOrigin);
585 * Modified by Li-Da Lho to draw 16 bits and Multibyte strings
587 * Interface changed: add "GdkFont *font" to specify font or fontset explicitely
590 gdk_x11_draw_text (GdkDrawable *drawable,
598 GdkDrawableImplX11 *impl;
601 impl = GDK_DRAWABLE_IMPL_X11 (drawable);
602 xdisplay = GDK_SCREEN_XDISPLAY (impl->screen);
604 if (font->type == GDK_FONT_FONT)
606 XFontStruct *xfont = (XFontStruct *) GDK_FONT_XFONT (font);
607 XSetFont(xdisplay, GDK_GC_GET_XGC (gc), xfont->fid);
608 if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
610 XDrawString (xdisplay, impl->xid,
611 GDK_GC_GET_XGC (gc), x, y, text, text_length);
615 XDrawString16 (xdisplay, impl->xid,
616 GDK_GC_GET_XGC (gc), x, y, (XChar2b *) text, text_length / 2);
619 else if (font->type == GDK_FONT_FONTSET)
621 XFontSet fontset = (XFontSet) GDK_FONT_XFONT (font);
622 XmbDrawString (xdisplay, impl->xid,
623 fontset, GDK_GC_GET_XGC (gc), x, y, text, text_length);
626 g_error("undefined font type\n");
630 gdk_x11_draw_text_wc (GdkDrawable *drawable,
635 const GdkWChar *text,
638 GdkDrawableImplX11 *impl;
641 impl = GDK_DRAWABLE_IMPL_X11 (drawable);
642 xdisplay = GDK_SCREEN_XDISPLAY (impl->screen);
644 if (font->type == GDK_FONT_FONT)
646 XFontStruct *xfont = (XFontStruct *) GDK_FONT_XFONT (font);
649 XSetFont(xdisplay, GDK_GC_GET_XGC (gc), xfont->fid);
650 text_8bit = g_new (gchar, text_length);
651 for (i=0; i<text_length; i++) text_8bit[i] = text[i];
652 XDrawString (xdisplay, impl->xid,
653 GDK_GC_GET_XGC (gc), x, y, text_8bit, text_length);
656 else if (font->type == GDK_FONT_FONTSET)
658 if (sizeof(GdkWChar) == sizeof(wchar_t))
660 XwcDrawString (xdisplay, impl->xid,
661 (XFontSet) GDK_FONT_XFONT (font),
662 GDK_GC_GET_XGC (gc), x, y, (wchar_t *)text, text_length);
668 text_wchar = g_new (wchar_t, text_length);
669 for (i=0; i<text_length; i++) text_wchar[i] = text[i];
670 XwcDrawString (xdisplay, impl->xid,
671 (XFontSet) GDK_FONT_XFONT (font),
672 GDK_GC_GET_XGC (gc), x, y, text_wchar, text_length);
677 g_error("undefined font type\n");
681 gdk_x11_draw_drawable (GdkDrawable *drawable,
691 int src_depth = gdk_drawable_get_depth (src);
692 int dest_depth = gdk_drawable_get_depth (drawable);
693 GdkDrawableImplX11 *impl;
694 GdkDrawableImplX11 *src_impl;
696 impl = GDK_DRAWABLE_IMPL_X11 (drawable);
698 if (GDK_IS_DRAWABLE_IMPL_X11 (src))
699 src_impl = GDK_DRAWABLE_IMPL_X11 (src);
705 XCopyArea (GDK_SCREEN_XDISPLAY (impl->screen),
706 src_impl ? src_impl->xid : GDK_DRAWABLE_XID (src),
713 else if (dest_depth != 0 && src_depth == dest_depth)
715 XCopyArea (GDK_SCREEN_XDISPLAY (impl->screen),
716 src_impl ? src_impl->xid : GDK_DRAWABLE_XID (src),
724 g_warning ("Attempt to draw a drawable with depth %d to a drawable with depth %d",
725 src_depth, dest_depth);
729 gdk_x11_draw_points (GdkDrawable *drawable,
734 GdkDrawableImplX11 *impl;
736 impl = GDK_DRAWABLE_IMPL_X11 (drawable);
739 /* We special-case npoints == 1, because X will merge multiple
740 * consecutive XDrawPoint requests into a PolyPoint request
744 XDrawPoint (GDK_SCREEN_XDISPLAY (impl->screen),
747 points[0].x, points[0].y);
752 XPoint *tmp_points = g_new (XPoint, npoints);
754 for (i=0; i<npoints; i++)
756 tmp_points[i].x = points[i].x;
757 tmp_points[i].y = points[i].y;
760 XDrawPoints (GDK_SCREEN_XDISPLAY (impl->screen),
772 gdk_x11_draw_segments (GdkDrawable *drawable,
777 GdkDrawableImplX11 *impl;
779 impl = GDK_DRAWABLE_IMPL_X11 (drawable);
782 /* We special-case nsegs == 1, because X will merge multiple
783 * consecutive XDrawLine requests into a PolySegment request
787 XDrawLine (GDK_SCREEN_XDISPLAY (impl->screen), impl->xid,
788 GDK_GC_GET_XGC (gc), segs[0].x1, segs[0].y1,
789 segs[0].x2, segs[0].y2);
794 XSegment *tmp_segs = g_new (XSegment, nsegs);
796 for (i=0; i<nsegs; i++)
798 tmp_segs[i].x1 = segs[i].x1;
799 tmp_segs[i].x2 = segs[i].x2;
800 tmp_segs[i].y1 = segs[i].y1;
801 tmp_segs[i].y2 = segs[i].y2;
804 XDrawSegments (GDK_SCREEN_XDISPLAY (impl->screen),
814 gdk_x11_draw_lines (GdkDrawable *drawable,
820 XPoint *tmp_points = g_new (XPoint, npoints);
821 GdkDrawableImplX11 *impl;
823 impl = GDK_DRAWABLE_IMPL_X11 (drawable);
826 for (i=0; i<npoints; i++)
828 tmp_points[i].x = points[i].x;
829 tmp_points[i].y = points[i].y;
832 XDrawLines (GDK_SCREEN_XDISPLAY (impl->screen),
842 gdk_x11_draw_glyphs (GdkDrawable *drawable,
847 PangoGlyphString *glyphs)
849 gdk_x11_draw_glyphs_transformed (drawable, gc, NULL,
857 gdk_x11_draw_glyphs_transformed (GdkDrawable *drawable,
863 PangoGlyphString *glyphs)
865 GdkDrawableImplX11 *impl;
866 PangoRenderer *renderer;
868 impl = GDK_DRAWABLE_IMPL_X11 (drawable);
870 g_return_if_fail (PANGO_XFT_IS_FONT (font));
872 renderer = _gdk_x11_renderer_get (drawable, gc);
874 pango_renderer_set_matrix (renderer, matrix);
875 pango_renderer_draw_glyphs (renderer, font, glyphs, x, y);
877 pango_renderer_set_matrix (renderer, NULL);
881 gdk_x11_draw_image (GdkDrawable *drawable,
891 GdkDrawableImplX11 *impl;
893 impl = GDK_DRAWABLE_IMPL_X11 (drawable);
896 if (image->type == GDK_IMAGE_SHARED)
897 XShmPutImage (GDK_SCREEN_XDISPLAY (impl->screen), impl->xid,
898 GDK_GC_GET_XGC (gc), GDK_IMAGE_XIMAGE (image),
899 xsrc, ysrc, xdest, ydest, width, height, False);
902 XPutImage (GDK_SCREEN_XDISPLAY (impl->screen), impl->xid,
903 GDK_GC_GET_XGC (gc), GDK_IMAGE_XIMAGE (image),
904 xsrc, ysrc, xdest, ydest, width, height);
908 gdk_x11_get_depth (GdkDrawable *drawable)
910 /* This is a bit bogus but I'm not sure the other way is better */
912 return gdk_drawable_get_depth (GDK_DRAWABLE_IMPL_X11 (drawable)->wrapper);
916 get_impl_drawable (GdkDrawable *drawable)
918 if (GDK_IS_WINDOW (drawable))
919 return ((GdkWindowObject *)drawable)->impl;
920 else if (GDK_IS_PIXMAP (drawable))
921 return ((GdkPixmapObject *)drawable)->impl;
924 g_warning (G_STRLOC " drawable is not a pixmap or window");
930 gdk_x11_get_screen (GdkDrawable *drawable)
932 if (GDK_IS_DRAWABLE_IMPL_X11 (drawable))
933 return GDK_DRAWABLE_IMPL_X11 (drawable)->screen;
935 return GDK_DRAWABLE_IMPL_X11 (get_impl_drawable (drawable))->screen;
939 gdk_x11_get_visual (GdkDrawable *drawable)
941 return gdk_drawable_get_visual (GDK_DRAWABLE_IMPL_X11 (drawable)->wrapper);
945 * gdk_x11_drawable_get_xdisplay:
946 * @drawable: a #GdkDrawable.
948 * Returns the display of a #GdkDrawable.
950 * Return value: an Xlib <type>Display*</type>.
953 gdk_x11_drawable_get_xdisplay (GdkDrawable *drawable)
955 if (GDK_IS_DRAWABLE_IMPL_X11 (drawable))
956 return GDK_SCREEN_XDISPLAY (GDK_DRAWABLE_IMPL_X11 (drawable)->screen);
958 return GDK_SCREEN_XDISPLAY (GDK_DRAWABLE_IMPL_X11 (get_impl_drawable (drawable))->screen);
962 * gdk_x11_drawable_get_xid:
963 * @drawable: a #GdkDrawable.
965 * Returns the X resource (window or pixmap) belonging to a #GdkDrawable.
967 * Return value: the ID of @drawable's X resource.
970 gdk_x11_drawable_get_xid (GdkDrawable *drawable)
974 if (GDK_IS_WINDOW (drawable))
975 impl = ((GdkPixmapObject *)drawable)->impl;
976 else if (GDK_IS_PIXMAP (drawable))
977 impl = ((GdkPixmapObject *)drawable)->impl;
980 g_warning (G_STRLOC " drawable is not a pixmap or window");
984 return ((GdkDrawableImplX11 *)impl)->xid;
987 /* Code for accelerated alpha compositing using the RENDER extension.
988 * It's a bit long because there are lots of possibilities for
989 * what's the fastest depending on the available picture formats,
990 * whether we can used shared pixmaps, etc.
993 static GdkX11FormatType
994 select_format (GdkDisplay *display,
995 XRenderPictFormat **format,
996 XRenderPictFormat **mask)
998 Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
999 XRenderPictFormat pf;
1001 if (!_gdk_x11_have_render (display))
1002 return GDK_X11_FORMAT_NONE;
1004 /* Look for a 32-bit xRGB and Axxx formats that exactly match the
1005 * in memory data format. We can use them as pixmap and mask
1006 * to deal with non-premultiplied data.
1009 pf.type = PictTypeDirect;
1011 pf.direct.redMask = 0xff;
1012 pf.direct.greenMask = 0xff;
1013 pf.direct.blueMask = 0xff;
1015 pf.direct.alphaMask = 0;
1016 if (ImageByteOrder (xdisplay) == LSBFirst)
1020 pf.direct.green = 8;
1021 pf.direct.blue = 16;
1027 pf.direct.green = 16;
1031 *format = XRenderFindFormat (xdisplay,
1032 (PictFormatType | PictFormatDepth |
1033 PictFormatRedMask | PictFormatRed |
1034 PictFormatGreenMask | PictFormatGreen |
1035 PictFormatBlueMask | PictFormatBlue |
1036 PictFormatAlphaMask),
1040 pf.direct.alphaMask = 0xff;
1041 if (ImageByteOrder (xdisplay) == LSBFirst)
1044 pf.direct.alpha = 24;
1048 pf.direct.alpha = 0;
1051 *mask = XRenderFindFormat (xdisplay,
1052 (PictFormatType | PictFormatDepth |
1053 PictFormatAlphaMask | PictFormatAlpha),
1057 if (*format && *mask)
1058 return GDK_X11_FORMAT_EXACT_MASK;
1060 /* OK, that failed, now look for xRGB and Axxx formats in
1061 * RENDER's preferred order
1063 pf.direct.alphaMask = 0;
1066 pf.direct.green = 8;
1069 *format = XRenderFindFormat (xdisplay,
1070 (PictFormatType | PictFormatDepth |
1071 PictFormatRedMask | PictFormatRed |
1072 PictFormatGreenMask | PictFormatGreen |
1073 PictFormatBlueMask | PictFormatBlue |
1074 PictFormatAlphaMask),
1078 pf.direct.alphaMask = 0xff;
1079 pf.direct.alpha = 24;
1081 *mask = XRenderFindFormat (xdisplay,
1082 (PictFormatType | PictFormatDepth |
1083 PictFormatAlphaMask | PictFormatAlpha),
1087 if (*format && *mask)
1088 return GDK_X11_FORMAT_ARGB_MASK;
1090 /* Finally, if neither of the above worked, fall back to
1091 * looking for combined ARGB -- we'll premultiply ourselves.
1094 pf.type = PictTypeDirect;
1097 pf.direct.green = 8;
1099 pf.direct.alphaMask = 0xff;
1100 pf.direct.alpha = 24;
1102 *format = XRenderFindFormat (xdisplay,
1103 (PictFormatType | PictFormatDepth |
1104 PictFormatRedMask | PictFormatRed |
1105 PictFormatGreenMask | PictFormatGreen |
1106 PictFormatBlueMask | PictFormatBlue |
1107 PictFormatAlphaMask | PictFormatAlpha),
1113 return GDK_X11_FORMAT_ARGB;
1115 return GDK_X11_FORMAT_NONE;
1120 list_formats (XRenderPictFormat *pf)
1126 XRenderPictFormat *pf = XRenderFindFormat (impl->xdisplay, 0, NULL, i);
1129 g_print ("%2d R-%#06x/%#06x G-%#06x/%#06x B-%#06x/%#06x A-%#06x/%#06x\n",
1134 pf->direct.greenMask,
1136 pf->direct.blueMask,
1138 pf->direct.alphaMask);
1147 _gdk_x11_convert_to_format (guchar *src_buf,
1150 gint dest_rowstride,
1151 GdkX11FormatType dest_format,
1152 GdkByteOrder dest_byteorder,
1158 for (i=0; i < height; i++)
1160 switch (dest_format)
1162 case GDK_X11_FORMAT_EXACT_MASK:
1164 memcpy (dest_buf + i * dest_rowstride,
1165 src_buf + i * src_rowstride,
1169 case GDK_X11_FORMAT_ARGB_MASK:
1171 guchar *row = src_buf + i * src_rowstride;
1172 if (((gsize)row & 3) != 0)
1175 guint32 *q = (guint32 *)(dest_buf + i * dest_rowstride);
1176 guchar *end = p + 4 * width;
1180 *q = (p[3] << 24) | (p[0] << 16) | (p[1] << 8) | p[2];
1187 guint32 *p = (guint32 *)row;
1188 guint32 *q = (guint32 *)(dest_buf + i * dest_rowstride);
1189 guint32 *end = p + width;
1191 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1192 if (dest_byteorder == GDK_LSB_FIRST)
1198 *q = ( (*p & 0xff00ff00) |
1199 ((*p & 0x000000ff) << 16) |
1200 ((*p & 0x00ff0000) >> 16));
1211 *q = (((*p & 0xff000000) >> 24) |
1212 ((*p & 0x00ffffff) << 8));
1217 #else /* G_BYTE_ORDER == G_BIG_ENDIAN */
1218 if (dest_byteorder == GDK_LSB_FIRST)
1224 *q = ( (*p & 0x00ff00ff) |
1225 ((*p & 0x0000ff00) << 16) |
1226 ((*p & 0xff000000) >> 16));
1237 *q = (((*p & 0xffffff00) >> 8) |
1238 ((*p & 0x000000ff) << 24));
1243 #endif /* G_BYTE_ORDER*/
1247 case GDK_X11_FORMAT_ARGB:
1249 guchar *p = (src_buf + i * src_rowstride);
1250 guchar *q = (dest_buf + i * dest_rowstride);
1251 guchar *end = p + 4 * width;
1254 #define MULT(d,c,a,t) G_STMT_START { t = c * a; d = ((t >> 8) + t) >> 8; } G_STMT_END
1256 if (dest_byteorder == GDK_LSB_FIRST)
1260 MULT(q[0], p[2], p[3], t1);
1261 MULT(q[1], p[1], p[3], t2);
1262 MULT(q[2], p[0], p[3], t3);
1273 MULT(q[1], p[0], p[3], t1);
1274 MULT(q[2], p[1], p[3], t2);
1275 MULT(q[3], p[2], p[3], t3);
1283 case GDK_X11_FORMAT_NONE:
1284 g_assert_not_reached ();
1291 draw_with_images (GdkDrawable *drawable,
1293 GdkX11FormatType format_type,
1294 XRenderPictFormat *format,
1295 XRenderPictFormat *mask_format,
1303 GdkScreen *screen = GDK_DRAWABLE_IMPL_X11 (drawable)->screen;
1304 Display *xdisplay = GDK_SCREEN_XDISPLAY (screen);
1310 Picture mask = None;
1313 pix = gdk_pixmap_new (gdk_screen_get_root_window (screen), width, height, 32);
1315 pict = XRenderCreatePicture (xdisplay,
1316 GDK_PIXMAP_XID (pix),
1319 mask = XRenderCreatePicture (xdisplay,
1320 GDK_PIXMAP_XID (pix),
1321 mask_format, 0, NULL);
1323 dest_pict = gdk_x11_drawable_get_picture (drawable);
1325 pix_gc = _gdk_drawable_get_scratch_gc (pix, FALSE);
1327 for (y0 = 0; y0 < height; y0 += GDK_SCRATCH_IMAGE_HEIGHT)
1329 gint height1 = MIN (height - y0, GDK_SCRATCH_IMAGE_HEIGHT);
1330 for (x0 = 0; x0 < width; x0 += GDK_SCRATCH_IMAGE_WIDTH)
1334 gint width1 = MIN (width - x0, GDK_SCRATCH_IMAGE_WIDTH);
1336 image = _gdk_image_get_scratch (screen, width1, height1, 32, &xs0, &ys0);
1338 _gdk_x11_convert_to_format (src_rgb + y0 * src_rowstride + 4 * x0, src_rowstride,
1339 (guchar *)image->mem + ys0 * image->bpl + xs0 * image->bpp, image->bpl,
1340 format_type, image->byte_order,
1343 gdk_draw_image (pix, pix_gc,
1344 image, xs0, ys0, x0, y0, width1, height1);
1348 XRenderComposite (xdisplay, PictOpOver, pict, mask, dest_pict,
1349 0, 0, 0, 0, dest_x, dest_y, width, height);
1351 XRenderFreePicture (xdisplay, pict);
1353 XRenderFreePicture (xdisplay, mask);
1355 g_object_unref (pix);
1358 typedef struct _ShmPixmapInfo ShmPixmapInfo;
1360 struct _ShmPixmapInfo
1368 /* Returns FALSE if we can't get a shm pixmap */
1370 get_shm_pixmap_for_image (Display *xdisplay,
1372 XRenderPictFormat *format,
1373 XRenderPictFormat *mask_format,
1378 ShmPixmapInfo *info;
1380 if (image->type != GDK_IMAGE_SHARED)
1383 info = g_object_get_data (G_OBJECT (image), "gdk-x11-shm-pixmap");
1386 *pix = _gdk_x11_image_get_shm_pixmap (image);
1391 info = g_new (ShmPixmapInfo, 1);
1394 info->pict = XRenderCreatePicture (xdisplay, info->pix,
1397 info->mask = XRenderCreatePicture (xdisplay, info->pix,
1398 mask_format, 0, NULL);
1402 g_object_set_data (G_OBJECT (image), "gdk-x11-shm-pixmap", info);
1413 /* Returns FALSE if drawing with ShmPixmaps is not possible */
1415 draw_with_pixmaps (GdkDrawable *drawable,
1417 GdkX11FormatType format_type,
1418 XRenderPictFormat *format,
1419 XRenderPictFormat *mask_format,
1427 Display *xdisplay = GDK_SCREEN_XDISPLAY (GDK_DRAWABLE_IMPL_X11 (drawable)->screen);
1432 Picture mask = None;
1435 dest_pict = gdk_x11_drawable_get_picture (drawable);
1437 for (y0 = 0; y0 < height; y0 += GDK_SCRATCH_IMAGE_HEIGHT)
1439 gint height1 = MIN (height - y0, GDK_SCRATCH_IMAGE_HEIGHT);
1440 for (x0 = 0; x0 < width; x0 += GDK_SCRATCH_IMAGE_WIDTH)
1444 gint width1 = MIN (width - x0, GDK_SCRATCH_IMAGE_WIDTH);
1446 image = _gdk_image_get_scratch (GDK_DRAWABLE_IMPL_X11 (drawable)->screen,
1447 width1, height1, 32, &xs0, &ys0);
1448 if (!get_shm_pixmap_for_image (xdisplay, image, format, mask_format, &pix, &pict, &mask))
1451 _gdk_x11_convert_to_format (src_rgb + y0 * src_rowstride + 4 * x0, src_rowstride,
1452 (guchar *)image->mem + ys0 * image->bpl + xs0 * image->bpp, image->bpl,
1453 format_type, image->byte_order,
1456 XRenderComposite (xdisplay, PictOpOver, pict, mask, dest_pict,
1457 xs0, ys0, xs0, ys0, x0 + dest_x, y0 + dest_y,
1467 gdk_x11_draw_pixbuf (GdkDrawable *drawable,
1476 GdkRgbDither dither,
1480 GdkX11FormatType format_type;
1481 XRenderPictFormat *format, *mask_format;
1484 gboolean use_pixmaps = TRUE;
1485 #endif /* USE_SHM */
1487 format_type = select_format (gdk_drawable_get_display (drawable),
1488 &format, &mask_format);
1490 if (format_type == GDK_X11_FORMAT_NONE ||
1491 !gdk_pixbuf_get_has_alpha (pixbuf) ||
1492 gdk_drawable_get_depth (drawable) == 1 ||
1493 (dither == GDK_RGB_DITHER_MAX && gdk_drawable_get_depth (drawable) != 24) ||
1494 gdk_x11_drawable_get_picture (drawable) == None)
1496 GdkDrawable *wrapper = GDK_DRAWABLE_IMPL_X11 (drawable)->wrapper;
1497 GDK_DRAWABLE_CLASS (parent_class)->draw_pixbuf (wrapper, gc, pixbuf,
1498 src_x, src_y, dest_x, dest_y,
1500 dither, x_dither, y_dither);
1504 gdk_x11_drawable_update_xft_clip (drawable, gc);
1506 rowstride = gdk_pixbuf_get_rowstride (pixbuf);
1511 if (!draw_with_pixmaps (drawable, gc,
1512 format_type, format, mask_format,
1513 gdk_pixbuf_get_pixels (pixbuf) + src_y * rowstride + src_x * 4,
1515 dest_x, dest_y, width, height))
1516 use_pixmaps = FALSE;
1520 #endif /* USE_SHM */
1521 draw_with_images (drawable, gc,
1522 format_type, format, mask_format,
1523 gdk_pixbuf_get_pixels (pixbuf) + src_y * rowstride + src_x * 4,
1525 dest_x, dest_y, width, height);
1529 gdk_x11_draw_trapezoids (GdkDrawable *drawable,
1531 GdkTrapezoid *trapezoids,
1534 GdkScreen *screen = GDK_DRAWABLE_IMPL_X11 (drawable)->screen;
1535 GdkDisplay *display = gdk_screen_get_display (screen);
1536 XTrapezoid *xtrapezoids;
1539 if (!_gdk_x11_have_render_with_trapezoids (display))
1541 GdkDrawable *wrapper = GDK_DRAWABLE_IMPL_X11 (drawable)->wrapper;
1542 GDK_DRAWABLE_CLASS (parent_class)->draw_trapezoids (wrapper, gc,
1543 trapezoids, n_trapezoids);
1547 xtrapezoids = g_new (XTrapezoid, n_trapezoids);
1549 for (i = 0; i < n_trapezoids; i++)
1551 xtrapezoids[i].top = XDoubleToFixed (trapezoids[i].y1);
1552 xtrapezoids[i].bottom = XDoubleToFixed (trapezoids[i].y2);
1553 xtrapezoids[i].left.p1.x = XDoubleToFixed (trapezoids[i].x11);
1554 xtrapezoids[i].left.p1.y = XDoubleToFixed (trapezoids[i].y1);
1555 xtrapezoids[i].left.p2.x = XDoubleToFixed (trapezoids[i].x12);
1556 xtrapezoids[i].left.p2.y = XDoubleToFixed (trapezoids[i].y2);
1557 xtrapezoids[i].right.p1.x = XDoubleToFixed (trapezoids[i].x21);
1558 xtrapezoids[i].right.p1.y = XDoubleToFixed (trapezoids[i].y1);
1559 xtrapezoids[i].right.p2.x = XDoubleToFixed (trapezoids[i].x22);
1560 xtrapezoids[i].right.p2.y = XDoubleToFixed (trapezoids[i].y2);
1563 _gdk_x11_drawable_draw_xtrapezoids (drawable, gc,
1564 xtrapezoids, n_trapezoids);
1566 g_free (xtrapezoids);
1569 static cairo_surface_t *
1570 gdk_x11_drawable_get_cairo_surface (GdkDrawable *drawable)
1572 GdkDrawableImplX11 *impl = GDK_DRAWABLE_IMPL_X11 (drawable);
1573 GdkColormap *colormap;
1576 if (GDK_IS_WINDOW_IMPL_X11 (drawable) &&
1577 GDK_WINDOW_DESTROYED (impl->wrapper))
1580 colormap = gdk_drawable_get_colormap (drawable);
1583 g_warning ("Using Cairo rendering requires the drawable argument to\n"
1584 "have a specified colormap. All windows have a colormap,\n"
1585 "however, pixmaps only have colormap by default if they\n"
1586 "were created with a non-NULL window argument. Otherwise\n"
1587 "a colormap must be set on them with gdk_drawable_set_colormap");
1591 visual = gdk_colormap_get_visual (colormap);
1593 if (!impl->cairo_surface)
1595 impl->cairo_surface = cairo_xlib_surface_create (GDK_SCREEN_XDISPLAY (impl->screen),
1597 GDK_VISUAL_XVISUAL (visual),
1599 GDK_COLORMAP_XCOLORMAP (colormap));
1602 return impl->cairo_surface;
1606 gdk_x11_set_cairo_target (GdkDrawable *drawable,
1609 cairo_surface_t *surface = gdk_x11_drawable_get_cairo_surface (drawable);
1611 cairo_set_target_surface (cr, surface);
1615 * gdk_draw_rectangle_alpha_libgtk_only:
1616 * @drawable: The #GdkDrawable to draw on
1617 * @x: the x coordinate of the left edge of the rectangle.
1618 * @y: the y coordinate of the top edge of the rectangle.
1619 * @width: the width of the rectangle.
1620 * @height: the height of the rectangle.
1622 * @alpha: The alpha value.
1624 * Tries to draw a filled alpha blended rectangle using the window
1625 * system's native routines. This is not public API and must not be
1626 * used by applications.
1628 * Return value: TRUE if the rectangle could be drawn, FALSE
1632 gdk_draw_rectangle_alpha_libgtk_only (GdkDrawable *drawable,
1641 XRenderColor render_color;
1643 int x_offset, y_offset;
1644 GdkDrawable *real_drawable, *impl;
1646 g_return_val_if_fail (color != NULL, FALSE);
1648 if (!GDK_IS_WINDOW (drawable))
1651 if (!_gdk_x11_have_render (gdk_drawable_get_display (drawable)))
1654 gdk_window_get_internal_paint_info (GDK_WINDOW (drawable),
1656 &x_offset, &y_offset);
1658 impl = ((GdkWindowObject *)real_drawable)->impl;
1660 pict = gdk_x11_drawable_get_picture (impl);
1665 xdisplay = GDK_DISPLAY_XDISPLAY (gdk_drawable_get_display (drawable));
1667 render_color.alpha = alpha;
1668 render_color.red = (guint32)color->red * render_color.alpha / 0xffff;
1669 render_color.green = (guint32)color->green * render_color.alpha / 0xffff;
1670 render_color.blue = (guint32)color->blue * render_color.alpha / 0xffff;
1672 XRenderFillRectangle (xdisplay,
1673 PictOpOver, pict, &render_color,
1674 x - x_offset, y - y_offset,
1680 _gdk_x11_drawable_draw_xtrapezoids (GdkDrawable *drawable,
1682 XTrapezoid *xtrapezoids,
1685 GdkScreen *screen = GDK_DRAWABLE_IMPL_X11 (drawable)->screen;
1686 GdkDisplay *display = gdk_screen_get_display (screen);
1687 GdkDisplayX11 *x11display = GDK_DISPLAY_X11 (display);
1691 if (!_gdk_x11_have_render_with_trapezoids (display))
1693 /* This is the case of drawing the borders of the unknown glyph box
1694 * without render on the display, we need to feed it back to
1695 * fallback code. Not efficient, but doesn't matter.
1697 GdkTrapezoid *trapezoids = g_new (GdkTrapezoid, n_trapezoids);
1700 for (i = 0; i < n_trapezoids; i++)
1702 trapezoids[i].y1 = XFixedToDouble (xtrapezoids[i].top);
1703 trapezoids[i].y2 = XFixedToDouble (xtrapezoids[i].bottom);
1704 trapezoids[i].x11 = XFixedToDouble (xtrapezoids[i].left.p1.x);
1705 trapezoids[i].x12 = XFixedToDouble (xtrapezoids[i].left.p2.x);
1706 trapezoids[i].x21 = XFixedToDouble (xtrapezoids[i].right.p1.x);
1707 trapezoids[i].x22 = XFixedToDouble (xtrapezoids[i].right.p2.x);
1710 gdk_x11_draw_trapezoids (drawable, gc, trapezoids, n_trapezoids);
1711 g_free (trapezoids);
1716 gdk_x11_drawable_update_xft_clip (drawable, gc);
1717 draw = gdk_x11_drawable_get_xft_draw (drawable);
1719 if (!x11display->mask_format)
1720 x11display->mask_format = XRenderFindStandardFormat (x11display->xdisplay,
1723 XRenderCompositeTrapezoids (x11display->xdisplay, PictOpOver,
1724 _gdk_x11_gc_get_fg_picture (gc),
1725 XftDrawPicture (draw),
1726 x11display->mask_format,
1727 - gc->ts_x_origin, - gc->ts_y_origin,
1728 xtrapezoids, n_trapezoids);
1732 _gdk_x11_drawable_draw_xft_glyphs (GdkDrawable *drawable,
1735 XftGlyphSpec *glyphs,
1738 GdkScreen *screen = GDK_DRAWABLE_IMPL_X11 (drawable)->screen;
1739 GdkDisplay *display = gdk_screen_get_display (screen);
1740 GdkDisplayX11 *x11display = GDK_DISPLAY_X11 (display);
1743 gdk_x11_drawable_update_xft_clip (drawable, gc);
1744 draw = gdk_x11_drawable_get_xft_draw (drawable);
1746 if (_gdk_x11_have_render (display))
1748 XftGlyphSpecRender (x11display->xdisplay, PictOpOver,
1749 _gdk_x11_gc_get_fg_picture (gc),
1751 XftDrawPicture (draw),
1752 - gc->ts_x_origin, - gc->ts_y_origin,
1759 _gdk_gc_x11_get_fg_xft_color (gc, &color);
1760 XftDrawGlyphSpec (draw, &color, xft_font, glyphs, n_glyphs);
1764 #define __GDK_DRAWABLE_X11_C__
1765 #include "gdkaliasdef.c"