/* GDK - The 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 "gdkx.h" #include "gdkregion-generic.h" #include #include #if HAVE_XFT #include #endif #include #if defined (HAVE_IPC_H) && defined (HAVE_SHM_H) && defined (HAVE_XSHM_H) #define USE_SHM #endif #ifdef USE_SHM #include #endif /* USE_SHM */ #include "gdkprivate-x11.h" #include "gdkdrawable-x11.h" #include "gdkpixmap-x11.h" static void gdk_x11_draw_rectangle (GdkDrawable *drawable, GdkGC *gc, gint filled, gint x, gint y, gint width, gint height); static void gdk_x11_draw_arc (GdkDrawable *drawable, GdkGC *gc, gint filled, gint x, gint y, gint width, gint height, gint angle1, gint angle2); static void gdk_x11_draw_polygon (GdkDrawable *drawable, GdkGC *gc, gint 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_glyphs (GdkDrawable *drawable, GdkGC *gc, PangoFont *font, gint x, gint y, PangoGlyphString *glyphs); 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_set_colormap (GdkDrawable *drawable, GdkColormap *colormap); static GdkColormap* gdk_x11_get_colormap (GdkDrawable *drawable); static gint gdk_x11_get_depth (GdkDrawable *drawable); static GdkVisual* gdk_x11_get_visual (GdkDrawable *drawable); static void gdk_drawable_impl_x11_class_init (GdkDrawableImplX11Class *klass); static void gdk_drawable_impl_x11_finalize (GObject *object); static gpointer parent_class = NULL; GType _gdk_drawable_impl_x11_get_type (void) { static GType object_type = 0; if (!object_type) { static const GTypeInfo object_info = { sizeof (GdkDrawableImplX11Class), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) gdk_drawable_impl_x11_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (GdkDrawableImplX11), 0, /* n_preallocs */ (GInstanceInitFunc) NULL, }; object_type = g_type_register_static (GDK_TYPE_DRAWABLE, "GdkDrawableImplX11", &object_info, 0); } return object_type; } static void gdk_drawable_impl_x11_class_init (GdkDrawableImplX11Class *klass) { GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); parent_class = g_type_class_peek_parent (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_glyphs = gdk_x11_draw_glyphs; drawable_class->draw_image = gdk_x11_draw_image; 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_visual = gdk_x11_get_visual; drawable_class->get_image = _gdk_x11_get_image; } static void gdk_drawable_impl_x11_finalize (GObject *object) { gdk_drawable_set_colormap (GDK_DRAWABLE (object), NULL); G_OBJECT_CLASS (parent_class)->finalize (object); } #ifdef HAVE_XFT static Picture gdk_x11_drawable_get_picture (GdkDrawable *drawable) { GdkDrawableImplX11 *impl = GDK_DRAWABLE_IMPL_X11 (drawable); if (impl->picture == None) { GdkVisual *visual = gdk_drawable_get_visual (drawable); XRenderPictFormat *format; if (!visual) { g_warning ("Using Xft 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 None; } format = XRenderFindVisualFormat (impl->xdisplay, GDK_VISUAL_XVISUAL (visual)); impl->picture = XRenderCreatePicture (impl->xdisplay, impl->xid, format, 0, NULL); } return impl->picture; } static void gdk_x11_drawable_update_picture_clip (GdkDrawable *drawable, GdkGC *gc) { GdkGCX11 *gc_private = GDK_GC_X11 (gc); GdkDrawableImplX11 *impl = GDK_DRAWABLE_IMPL_X11 (drawable); Picture picture = gdk_x11_drawable_get_picture (drawable); if (gc_private->clip_region) { GdkRegionBox *boxes = gc_private->clip_region->rects; gint n_boxes = gc_private->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 (impl->xdisplay, picture, 0, 0, rects, n_boxes); g_free (rects); } else { XRenderPictureAttributes pa; pa.clip_mask = None; XRenderChangePicture (impl->xdisplay, picture, CPClipMask, &pa); } } #endif /***************************************************** * 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) gdk_colormap_unref (impl->colormap); impl->colormap = colormap; if (impl->colormap) gdk_colormap_ref (impl->colormap); } /* Drawing */ static void gdk_x11_draw_rectangle (GdkDrawable *drawable, GdkGC *gc, gint filled, gint x, gint y, gint width, gint height) { GdkDrawableImplX11 *impl; impl = GDK_DRAWABLE_IMPL_X11 (drawable); if (filled) XFillRectangle (impl->xdisplay, impl->xid, GDK_GC_GET_XGC (gc), x, y, width, height); else XDrawRectangle (impl->xdisplay, impl->xid, GDK_GC_GET_XGC (gc), x, y, width, height); } static void gdk_x11_draw_arc (GdkDrawable *drawable, GdkGC *gc, gint filled, gint x, gint y, gint width, gint height, gint angle1, gint angle2) { GdkDrawableImplX11 *impl; impl = GDK_DRAWABLE_IMPL_X11 (drawable); if (filled) XFillArc (impl->xdisplay, impl->xid, GDK_GC_GET_XGC (gc), x, y, width, height, angle1, angle2); else XDrawArc (impl->xdisplay, impl->xid, GDK_GC_GET_XGC (gc), x, y, width, height, angle1, angle2); } static void gdk_x11_draw_polygon (GdkDrawable *drawable, GdkGC *gc, gint 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; ixdisplay, impl->xid, GDK_GC_GET_XGC (gc), tmp_points, tmp_npoints, Complex, CoordModeOrigin); else XDrawLines (impl->xdisplay, 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; impl = GDK_DRAWABLE_IMPL_X11 (drawable); if (font->type == GDK_FONT_FONT) { XFontStruct *xfont = (XFontStruct *) GDK_FONT_XFONT (font); XSetFont(impl->xdisplay, GDK_GC_GET_XGC (gc), xfont->fid); if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) { XDrawString (impl->xdisplay, impl->xid, GDK_GC_GET_XGC (gc), x, y, text, text_length); } else { XDrawString16 (impl->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 (impl->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; impl = GDK_DRAWABLE_IMPL_X11 (drawable); if (font->type == GDK_FONT_FONT) { XFontStruct *xfont = (XFontStruct *) GDK_FONT_XFONT (font); gchar *text_8bit; gint i; XSetFont(impl->xdisplay, GDK_GC_GET_XGC (gc), xfont->fid); text_8bit = g_new (gchar, text_length); for (i=0; ixdisplay, 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 (impl->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; ixdisplay, 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 (impl->xdisplay, 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 (impl->xdisplay, 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 (impl->xdisplay, 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; ixdisplay, 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 (impl->xdisplay, 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; ixdisplay, 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; ixdisplay, impl->xid, GDK_GC_GET_XGC (gc), tmp_points, npoints, CoordModeOrigin); g_free (tmp_points); } static void gdk_x11_draw_glyphs (GdkDrawable *drawable, GdkGC *gc, PangoFont *font, gint x, gint y, PangoGlyphString *glyphs) { GdkDrawableImplX11 *impl; impl = GDK_DRAWABLE_IMPL_X11 (drawable); #if HAVE_XFT if (PANGO_XFT_IS_FONT (font)) { Picture src_picture; Picture dest_picture; src_picture = _gdk_x11_gc_get_fg_picture (gc); gdk_x11_drawable_update_picture_clip (drawable, gc); dest_picture = gdk_x11_drawable_get_picture (drawable); pango_xft_picture_render (impl->xdisplay, src_picture, dest_picture, font, glyphs, x, y); } else #endif /* !HAVE_XFT */ pango_x_render (impl->xdisplay, impl->xid, GDK_GC_GET_XGC (gc), font, glyphs, x, y); } 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); if (image->type == GDK_IMAGE_SHARED) XShmPutImage (impl->xdisplay, impl->xid, GDK_GC_GET_XGC (gc), GDK_IMAGE_XIMAGE (image), xsrc, ysrc, xdest, ydest, width, height, False); else XPutImage (impl->xdisplay, 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 GdkVisual* gdk_x11_get_visual (GdkDrawable *drawable) { return gdk_drawable_get_visual (GDK_DRAWABLE_IMPL_X11 (drawable)->wrapper); } Display * gdk_x11_drawable_get_xdisplay (GdkDrawable *drawable) { GdkDrawable *impl; if (GDK_IS_WINDOW (drawable)) 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 NULL; } return ((GdkDrawableImplX11 *)impl)->xdisplay; } XID gdk_x11_drawable_get_xid (GdkDrawable *drawable) { GdkDrawable *impl; if (GDK_IS_WINDOW (drawable)) 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; }