summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan D <jan.h.d@swipnet.se>2015-02-11 16:14:35 +0100
committerJan D <jan.h.d@swipnet.se>2015-02-11 16:14:35 +0100
commitdddcc0e78452f2186c132823a33a174d2596ba33 (patch)
tree8369d54925d9ea4b60ecf6a53c6a321dffd194f9
parent061c7e2b5a5a5854b2b85f2ace5b1d9222dd7f11 (diff)
Add cairo drawing.
* configure.ac (with-cairo): New option. (USE_CAIRO): Default to yes for Gtk+ 3. Add code to test for cairo, set CAIRO_CFLAGS, CAIRO_LIBS. Add ftcrfonto to FONT_OBJ if cairo. Output "Does Emacs use cairo?". * lisp/version.el (emacs-version): Add cairo version. * src/Makefile.in (CAIRO_CFLAGS, CAIRO_LIBS): New variables. (FONT_OBJ): Add comment about ftcrfont. (ALL_CFLAGS): Add CAIRO_CFLAGS. (LIBES): Add CAIRO_LIBS. * src/dispextern.h (struct image): Add cr_data for cairo. (x_cr_init_fringe): Declare. * src/font.c (syms_of_font): Call syms_of_ftcrfont for cairo. * src/font.h (ftcrfont_driver, syms_of_ftcrfont): Declare * src/fringe.c (x_cr_init_fringe): New function name that shares code with w32_init_fringe. * src/ftcrfont.c: New font driver for cairo, based on the ftfont driver. * src/ftfont.c (ftfont_info_size); New global variable. (ftfont_open2): New extern function almost the same as old ftfont_open, but takes the font_object as argument. (ftfont_open): Build font object and call ftfont_open2. * src/ftfont.h (ftfont_open2, ftfont_info_size): Declare. * src/gtkutil.c (xg_clear_under_internal_border) (xg_update_scrollbar_pos, xg_update_horizontal_scrollbar_pos): Only queue_draw if not cairo. Change args to x_clear_area. (xg_get_font): Use Qftcr when using cairo, Qxft otherwise. (xg_page_setup_dialog, xg_get_page_setup, draw_page) (xg_print_frames_dialog): New functions for printing. * src/gtkutil.h (xg_page_setup_dialog, xg_get_page_setup) (xg_print_frames_dialog): Declare. * src/image.c: Add defined (USE_CAIRO) for PNG. Add !defined USE_CAIRO for W32 PNG code. (x_clear_image): If cairo, destroy the surface in cr_data. (png_load): Add new cairo compatible implementation. (lookup_image_type): Add defined (USE_CAIRO) for define png_type. * src/xfns.c: New section Printing. (x-export-frames, x-page-setup-dialog, x-get-page-setup) (x-print-frames-dialog): New printing functions. (Fx_create_frame, x_create_tip_frame): Register ftcrfont if cairo. (syms_of_xfns): Defsym Qorientation, Qtop_margin, Qbottom_margin, Qportrait, Qlandscape, Qreverse_portrait, Qreverse_landscape). (syms_of_xfns): Provide cairo and defvar cairo-version-string. defsubr Sx_page_setup_dialog, Sx_get_page_setup, Sx_print_frames_dialog. * src/xterm.c (x_clear_area1, x_prepare_for_xlibdraw) (x_set_clip_rectangles, x_reset_clip_rectangles, x_fill_rectangle) (x_draw_rectangle, x_fill_trapezoid_for_relief, x_clear_window) (x_gc_get_ext_data, x_extension_initialize, x_cr_accumulate_data): Declare. (FRAME_CR_CONTEXT, FRAME_CR_SURFACE): New macros. (max_fringe_bmp, fringe_bmp): New variables. (x_gc_get_ext_data, x_extension_initialize) (x_cr_destroy_surface, x_begin_cr_clip, x_end_cr_clip) (x_set_cr_source_with_gc_foreground) (x_set_cr_source_with_gc_background, x_cr_define_fringe_bitmap) (x_cr_destroy_fringe_bitmap, x_cr_draw_image, x_cr_draw_frame) (x_cr_accumulate_data, x_cr_destroy, x_cr_export_frames) (x_prepare_for_xlibdraw, x_set_clip_rectangles) (x_reset_clip_rectangles, x_fill_rectangle, x_draw_rectangle) (x_clear_window, x_fill_trapezoid_for_relief): New functions. (x_update_begin): Create cairo surface if needed. (x_draw_vertical_window_border): Call x_fill_rectangle for cairo. (x_update_end): Paint cairo drawing surface to xlib surface. (x_clear_under_internal_border, x_after_update_window_line): Adjust arguments to x_clear_area. (x_draw_fringe_bitmap): Call x_fill_rectangle. Get GC values and call x_cr_draw_image for cairo. Call x_reset_clip_rectangles instead of XSetClipMask. (x_set_glyph_string_clipping) (x_set_glyph_string_clipping_exactly): Use x_set_clip_rectangles instead of XSetClipRectangles. (x_clear_glyph_string_rect, x_draw_glyph_string_background): Use x_fill_rectangle instead of XFillRectangle. (x_draw_glyph_string_foreground) (x_draw_composite_glyph_string_foreground) (x_draw_glyphless_glyph_string_foreground): Use x_draw_rectangle instead of XDrawRectangle. (x_draw_relief_rect): Add code for USE_CAIRO. Call x_reset_clip_rectangles instead of XSetClipMask. (x_draw_box_rect): x_set_clip_rectangles instead of XSetClipRectangles, x_fill_rectangle instead of XFillRectangle, x_reset_clip_rectangles instead of XSetClipMask. (x_draw_image_foreground, x_draw_image_foreground_1): x_draw_rectangle instead of XDrawRectangle. (x_draw_glyph_string_bg_rect): x_fill_rectangle instead of XFillRectangle. (x_draw_image_glyph_string): If img has cr_data, use it as a cairo surface. (x_draw_stretch_glyph_string): x_set_clip_rectangles instead of XSetClipRectangles, x_fill_rectangle instead of XFillRectangle. (x_draw_glyph_string): x_fill_rectangle instead of XFillRectangle., x_reset_clip_rectangles instead of XSetClipMask. (x_shift_glyphs_for_insert): Call x_prepare_for_xlibdraw. (x_clear_area1): New function that calls XClearArea. (x_clear_area): Takes frame as parameter, calls x_clear_area1 for non-cairo. (x_clear_frame): x_clear_window instead of XClearWindow. (x_scroll_run): Set frame garbaged if cairo. (XTmouse_position): Initialize *part to 0. (x_scroll_bar_create): Adjust arguments to x_clear_area. (x_scroll_bar_set_handle): x_clear_area1 instead of x_clear_area, x_fill_rectangle instead of XFillRectangle. (XTset_vertical_scroll_bar, XTset_horizontal_scroll_bar): Adjust arguments to x_clear_area. (x_scroll_bar_expose): x_draw_rectangle instead of XDrawRectangle. (handle_one_xevent): Adjust arguments to x_clear_area. Destroy cairo surface for frame if ConfigureNotify. (x_clip_to_row): x_set_clip_rectangles instead of XSetClipRectangles. (x_draw_hollow_cursor): x_draw_rectangle instead of XDrawRectangle, x_reset_clip_rectangles instead of XSetClipMask. (x_draw_bar_cursor): x_fill_rectangle instead of XFillRectangle, x_reset_clip_rectangles instead of XSetClipMask. (x_clear_frame_area): Adjust arguments to x_clear_area. (x_free_frame_resources): Call x_prepare_for_xlibdraw. (x_term_init): Call x_extension_initialize if cairo. (x_redisplay_interface): Add x_cr_define_fringe_bitmap, x_cr_destroy_fringe_bitmap for cairo. (x_initialize): Call x_cr_init_fringe for cairo. * src/xterm.h: Add include of cairo header files. (x_bitmap_record): Add img if cairo. (x_gc_ext_data): New struct for cairo. (x_display_info): Add ext_codes for cairo. (x_output): Add cr_context and cr_surface for cairo. (x_clear_area): Change arguments from Display*/Window to frame pointer. (x_query_color, x_begin_cr_clip, x_end_cr_clip) (x_set_cr_source_with_gc_foreground, x_set_cr_source_with_gc_background) (x_cr_draw_frame, x_cr_export_frames): Declare.
-rw-r--r--ChangeLog7
-rw-r--r--configure.ac35
-rw-r--r--lisp/ChangeLog4
-rw-r--r--lisp/version.el7
-rw-r--r--src/ChangeLog138
-rw-r--r--src/Makefile.in8
-rw-r--r--src/dispextern.h6
-rw-r--r--src/font.c4
-rw-r--r--src/font.h4
-rw-r--r--src/fringe.c8
-rw-r--r--src/ftcrfont.c314
-rw-r--r--src/ftfont.c26
-rw-r--r--src/ftfont.h5
-rw-r--r--src/gtkutil.c131
-rw-r--r--src/gtkutil.h6
-rw-r--r--src/image.c55
-rw-r--r--src/xfns.c195
-rw-r--r--src/xterm.c895
-rw-r--r--src/xterm.h53
19 files changed, 1794 insertions, 107 deletions
diff --git a/ChangeLog b/ChangeLog
index a574ac86e2..a48b3055f9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2015-02-11 Jan Djärv <jan.h.d@swipnet.se>
+
+ * configure.ac (with-cairo): New option.
+ (USE_CAIRO): Default to yes for Gtk+ 3. Add code to test for cairo,
+ set CAIRO_CFLAGS, CAIRO_LIBS. Add ftcrfonto to FONT_OBJ if cairo.
+ Output "Does Emacs use cairo?".
+
2015-02-09 Paul Eggert <eggert@cs.ucla.edu>
* configure.ac (HAVE_LIBXML2): Add missing comma.
diff --git a/configure.ac b/configure.ac
index 68291b8950..261944f9aa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -335,6 +335,7 @@ OPTION_DEFAULT_ON([tiff],[don't compile with TIFF image support])
OPTION_DEFAULT_ON([gif],[don't compile with GIF image support])
OPTION_DEFAULT_ON([png],[don't compile with PNG image support])
OPTION_DEFAULT_ON([rsvg],[don't compile with SVG image support])
+OPTION_DEFAULT_OFF([cairo],[compile with Cairo drawing])
OPTION_DEFAULT_ON([xml2],[don't compile with XML parsing support])
OPTION_DEFAULT_ON([imagemagick],[don't compile with ImageMagick image support])
@@ -2386,6 +2387,7 @@ if test "${opsys}" != "mingw32"; then
AC_DEFINE(HAVE_GTK3, 1, [Define to 1 if using GTK 3 or later.])
GTK_OBJ=emacsgtkfixed.o
gtk_term_header=gtkutil.h
+ USE_CAIRO=yes
USE_GTK_TOOLKIT="GTK3"
if test "x$ac_enable_gtk_deprecation_warnings" = x; then
AC_DEFINE([GDK_DISABLE_DEPRECATION_WARNINGS], [1],
@@ -3052,6 +3054,30 @@ AC_SUBST(LIBOTF_LIBS)
AC_SUBST(M17N_FLT_CFLAGS)
AC_SUBST(M17N_FLT_LIBS)
+USE_CAIRO=no
+if test "${HAVE_X11}" = "yes"; then
+ if test "${with_cairo}" != "no"; then
+ CAIRO_REQUIRED=1.12.0
+ CAIRO_MODULE="cairo >= $CAIRO_REQUIRED"
+ PKG_CHECK_MODULES(CAIRO, $CAIRO_MODULE, USE_CAIRO=yes, :)
+ if test $USE_CAIRO = yes; then
+ AC_DEFINE(USE_CAIRO, 1, [Define to 1 if using cairo.])
+ else
+ AC_MSG_ERROR([cairo requested but not found.])
+ fi
+ with_xpm=no
+ with_jpeg=no
+ with_gif=no
+ with_tiff=no
+
+ CFLAGS="$CFLAGS $CAIRO_CFLAGS"
+ LIBS="$LIBS $CAIRO_LIBS"
+ AC_SUBST(CAIRO_CFLAGS)
+ AC_SUBST(CAIRO_LIBS)
+ fi
+fi
+
+
### Use -lXpm if available, unless `--with-xpm=no'.
### mingw32 doesn't use -lXpm, since it loads the library dynamically.
### In the Cygwin-w32 build, we need to use /usr/include/noX/X11/xpm.h
@@ -3987,8 +4013,8 @@ OLDCFLAGS="$CFLAGS"
OLDLIBS="$LIBS"
CFLAGS="$CFLAGS $GTK_CFLAGS $RSVG_CFLAGS $DBUS_CFLAGS $SETTINGS_CFLAGS"
LIBS="$LIBS $GTK_LIBS $RSVG_LIBS $DBUS_LIBS $SETTINGS_LIBS"
-CFLAGS="$CFLAGS $GFILENOTIFY_CFLAGS"
-LIBS="$LIBS $GFILENOTIFY_LIBS"
+CFLAGS="$CFLAGS $GFILENOTIFY_CFLAGS $CAIRO_CFLAGS"
+LIBS="$LIBS $GFILENOTIFY_LIBS $CAIRO_LIBS"
AC_MSG_CHECKING([whether GLib is linked in])
AC_LINK_IFELSE([AC_LANG_PROGRAM(
[[#include <glib.h>
@@ -4754,7 +4780,9 @@ if test "${HAVE_X_WINDOWS}" = "yes" ; then
XMENU_OBJ=xmenu.o
XOBJ="xterm.o xfns.o xselect.o xrdb.o xsmfns.o xsettings.o"
FONT_OBJ=xfont.o
- if test "$HAVE_XFT" = "yes"; then
+ if test "$USE_CAIRO" = "yes"; then
+ FONT_OBJ="ftfont.o ftcrfont.o"
+ elif test "$HAVE_XFT" = "yes"; then
FONT_OBJ="$FONT_OBJ ftfont.o xftfont.o ftxfont.o"
elif test "$HAVE_FREETYPE" = "yes"; then
FONT_OBJ="$FONT_OBJ ftfont.o ftxfont.o"
@@ -5101,6 +5129,7 @@ echo " Does Emacs use -ltiff? ${HAVE_TIFF}"
echo " Does Emacs use a gif library? ${HAVE_GIF} $LIBGIF"
echo " Does Emacs use a png library? ${HAVE_PNG} $LIBPNG"
echo " Does Emacs use -lrsvg-2? ${HAVE_RSVG}"
+echo " Does Emacs use cairo? ${USE_CAIRO}"
echo " Does Emacs use imagemagick? ${HAVE_IMAGEMAGICK}"
echo " Does Emacs support sound? ${HAVE_SOUND}"
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index a6e5f59503..de2eb71696 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,7 @@
+2015-02-11 Jan Djärv <jan.h.d@swipnet.se>
+
+ * version.el (emacs-version): Add cairo version.
+
2015-02-11 Martin Rudalics <rudalics@gmx.at>
* frame.el (toggle-frame-maximized, toggle-frame-fullscreen):
diff --git a/lisp/version.el b/lisp/version.el
index 1837cbf0a8..b8555cbb2f 100644
--- a/lisp/version.el
+++ b/lisp/version.el
@@ -56,8 +56,8 @@ to the system configuration; look at `system-configuration' instead."
(interactive "P")
(let ((version-string
(format (if (not (called-interactively-p 'interactive))
- "GNU Emacs %s (%s%s%s)\n of %s on %s"
- "GNU Emacs %s (%s%s%s) of %s on %s")
+ "GNU Emacs %s (%s%s%s%s)\n of %s on %s"
+ "GNU Emacs %s (%s%s%s%s) of %s on %s")
emacs-version
system-configuration
(cond ((featurep 'motif)
@@ -68,6 +68,9 @@ to the system configuration; look at `system-configuration' instead."
((featurep 'ns)
(format ", NS %s" ns-version-string))
(t ""))
+ (if (featurep 'cairo)
+ (format ", cairo version %s" cairo-version-string)
+ "")
(if (and (boundp 'x-toolkit-scroll-bars)
(memq x-toolkit-scroll-bars '(xaw xaw3d)))
(format ", %s scroll bars"
diff --git a/src/ChangeLog b/src/ChangeLog
index f8e65d5d91..e361fe286e 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,141 @@
+2015-02-11 YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
+ Jan Djärv <jan.h.d@swipnet.se>
+
+ * xterm.h: Add include of cairo header files.
+ (x_bitmap_record): Add img if cairo.
+ (x_gc_ext_data): New struct for cairo.
+ (x_display_info): Add ext_codes for cairo.
+ (x_output): Add cr_context and cr_surface for cairo.
+ (x_clear_area): Change arguments from Display*/Window to frame pointer.
+ (x_query_color, x_begin_cr_clip, x_end_cr_clip)
+ (x_set_cr_source_with_gc_foreground, x_set_cr_source_with_gc_background)
+ (x_cr_draw_frame, x_cr_export_frames): Declare.
+
+ * xterm.c (x_clear_area1, x_prepare_for_xlibdraw)
+ (x_set_clip_rectangles, x_reset_clip_rectangles, x_fill_rectangle)
+ (x_draw_rectangle, x_fill_trapezoid_for_relief, x_clear_window)
+ (x_gc_get_ext_data, x_extension_initialize, x_cr_accumulate_data):
+ Declare.
+ (FRAME_CR_CONTEXT, FRAME_CR_SURFACE): New macros.
+ (max_fringe_bmp, fringe_bmp): New variables.
+ (x_gc_get_ext_data, x_extension_initialize)
+ (x_cr_destroy_surface, x_begin_cr_clip, x_end_cr_clip)
+ (x_set_cr_source_with_gc_foreground)
+ (x_set_cr_source_with_gc_background, x_cr_define_fringe_bitmap)
+ (x_cr_destroy_fringe_bitmap, x_cr_draw_image, x_cr_draw_frame)
+ (x_cr_accumulate_data, x_cr_destroy, x_cr_export_frames)
+ (x_prepare_for_xlibdraw, x_set_clip_rectangles)
+ (x_reset_clip_rectangles, x_fill_rectangle, x_draw_rectangle)
+ (x_clear_window, x_fill_trapezoid_for_relief): New functions.
+ (x_update_begin): Create cairo surface if needed.
+ (x_draw_vertical_window_border): Call x_fill_rectangle for cairo.
+ (x_update_end): Paint cairo drawing surface to xlib surface.
+ (x_clear_under_internal_border, x_after_update_window_line): Adjust
+ arguments to x_clear_area.
+ (x_draw_fringe_bitmap): Call x_fill_rectangle. Get GC values and
+ call x_cr_draw_image for cairo. Call x_reset_clip_rectangles instead
+ of XSetClipMask.
+ (x_set_glyph_string_clipping)
+ (x_set_glyph_string_clipping_exactly): Use x_set_clip_rectangles
+ instead of XSetClipRectangles.
+ (x_clear_glyph_string_rect, x_draw_glyph_string_background): Use
+ x_fill_rectangle instead of XFillRectangle.
+ (x_draw_glyph_string_foreground)
+ (x_draw_composite_glyph_string_foreground)
+ (x_draw_glyphless_glyph_string_foreground): Use x_draw_rectangle instead
+ of XDrawRectangle.
+ (x_draw_relief_rect): Add code for USE_CAIRO.
+ Call x_reset_clip_rectangles instead of XSetClipMask.
+ (x_draw_box_rect): x_set_clip_rectangles instead of XSetClipRectangles,
+ x_fill_rectangle instead of XFillRectangle, x_reset_clip_rectangles
+ instead of XSetClipMask.
+ (x_draw_image_foreground, x_draw_image_foreground_1):
+ x_draw_rectangle instead of XDrawRectangle.
+ (x_draw_glyph_string_bg_rect): x_fill_rectangle instead of
+ XFillRectangle.
+ (x_draw_image_glyph_string): If img has cr_data, use it as
+ a cairo surface.
+ (x_draw_stretch_glyph_string): x_set_clip_rectangles instead of
+ XSetClipRectangles, x_fill_rectangle instead of XFillRectangle.
+ (x_draw_glyph_string): x_fill_rectangle instead of XFillRectangle.,
+ x_reset_clip_rectangles instead of XSetClipMask.
+ (x_shift_glyphs_for_insert): Call x_prepare_for_xlibdraw.
+ (x_clear_area1): New function that calls XClearArea.
+ (x_clear_area): Takes frame as parameter, calls x_clear_area1 for
+ non-cairo.
+ (x_clear_frame): x_clear_window instead of XClearWindow.
+ (x_scroll_run): Set frame garbaged if cairo.
+ (XTmouse_position): Initialize *part to 0.
+ (x_scroll_bar_create): Adjust arguments to x_clear_area.
+ (x_scroll_bar_set_handle): x_clear_area1 instead of x_clear_area,
+ x_fill_rectangle instead of XFillRectangle.
+ (XTset_vertical_scroll_bar, XTset_horizontal_scroll_bar): Adjust
+ arguments to x_clear_area.
+ (x_scroll_bar_expose): x_draw_rectangle instead of XDrawRectangle.
+ (handle_one_xevent): Adjust arguments to x_clear_area.
+ Destroy cairo surface for frame if ConfigureNotify.
+ (x_clip_to_row): x_set_clip_rectangles instead of XSetClipRectangles.
+ (x_draw_hollow_cursor): x_draw_rectangle instead of XDrawRectangle,
+ x_reset_clip_rectangles instead of XSetClipMask.
+ (x_draw_bar_cursor): x_fill_rectangle instead of XFillRectangle,
+ x_reset_clip_rectangles instead of XSetClipMask.
+ (x_clear_frame_area): Adjust arguments to x_clear_area.
+ (x_free_frame_resources): Call x_prepare_for_xlibdraw.
+ (x_term_init): Call x_extension_initialize if cairo.
+ (x_redisplay_interface): Add x_cr_define_fringe_bitmap,
+ x_cr_destroy_fringe_bitmap for cairo.
+ (x_initialize): Call x_cr_init_fringe for cairo.
+
+ * xfns.c: New section Printing.
+ (x-export-frames, x-page-setup-dialog, x-get-page-setup)
+ (x-print-frames-dialog): New printing functions.
+ (Fx_create_frame, x_create_tip_frame): Register ftcrfont if
+ cairo.
+ (syms_of_xfns): Defsym Qorientation, Qtop_margin, Qbottom_margin,
+ Qportrait, Qlandscape, Qreverse_portrait, Qreverse_landscape).
+ (syms_of_xfns): Provide cairo and defvar cairo-version-string.
+ defsubr Sx_page_setup_dialog, Sx_get_page_setup, Sx_print_frames_dialog.
+
+ * image.c: Add defined (USE_CAIRO) for PNG.
+ Add !defined USE_CAIRO for W32 PNG code.
+ (x_clear_image): If cairo, destroy the surface in cr_data.
+ (png_load): Add new cairo compatible implementation.
+ (lookup_image_type): Add defined (USE_CAIRO) for define png_type.
+
+ * gtkutil.h (xg_page_setup_dialog, xg_get_page_setup)
+ (xg_print_frames_dialog): Declare.
+
+ * gtkutil.c (xg_clear_under_internal_border)
+ (xg_update_scrollbar_pos, xg_update_horizontal_scrollbar_pos): Only
+ queue_draw if not cairo. Change args to x_clear_area.
+ (xg_get_font): Use Qftcr when using cairo, Qxft otherwise.
+ (xg_page_setup_dialog, xg_get_page_setup, draw_page)
+ (xg_print_frames_dialog): New functions for printing.
+
+ * ftfont.h (ftfont_open2, ftfont_info_size): Declare.
+
+ * ftfont.c (ftfont_info_size); New global variable.
+ (ftfont_open2): New extern function almost the same as old ftfont_open,
+ but takes the font_object as argument.
+ (ftfont_open): Build font object and call ftfont_open2.
+
+ * ftcrfont.c: New font driver for cairo, based on the ftfont driver.
+
+ * fringe.c (x_cr_init_fringe): New function name that shares code
+ with w32_init_fringe.
+
+ * font.h (ftcrfont_driver, syms_of_ftcrfont): Declare
+
+ * font.c (syms_of_font): Call syms_of_ftcrfont for cairo.
+
+ * dispextern.h (struct image): Add cr_data for cairo.
+ (x_cr_init_fringe): Declare.
+
+ * Makefile.in (CAIRO_CFLAGS, CAIRO_LIBS): New variables.
+ (FONT_OBJ): Add comment about ftcrfont.
+ (ALL_CFLAGS): Add CAIRO_CFLAGS.
+ (LIBES): Add CAIRO_LIBS.
+
2015-02-11 Martin Rudalics <rudalics@gmx.at>
* w32term.c (w32_read_socket): In SIZE_MAXIMIZED and
diff --git a/src/Makefile.in b/src/Makefile.in
index 32615c848a..9e7a8a7991 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -218,6 +218,9 @@ CFLAGS_SOUND= @CFLAGS_SOUND@
RSVG_LIBS= @RSVG_LIBS@
RSVG_CFLAGS= @RSVG_CFLAGS@
+CAIRO_LIBS= @CAIRO_LIBS@
+CAIRO_CFLAGS= @CAIRO_CFLAGS@
+
IMAGEMAGICK_LIBS= @IMAGEMAGICK_LIBS@
IMAGEMAGICK_CFLAGS= @IMAGEMAGICK_CFLAGS@
@@ -273,6 +276,7 @@ W32_RES_LINK=@W32_RES_LINK@
## Empty if !HAVE_X_WINDOWS
## xfont.o ftfont.o xftfont.o ftxfont.o if HAVE_XFT
## xfont.o ftfont.o ftxfont.o if HAVE_FREETYPE
+## ftfont.o ftcrfont.o if USE_CAIRO
## else xfont.o
FONT_OBJ=@FONT_OBJ@
@@ -345,7 +349,7 @@ ALL_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \
$(XRANDR_CFLAGS) $(XINERAMA_CFLAGS) $(XFIXES_CFLAGS) \
$(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \
$(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \
- $(LIBGNUTLS_CFLAGS) $(GFILENOTIFY_CFLAGS) \
+ $(LIBGNUTLS_CFLAGS) $(GFILENOTIFY_CFLAGS) $(CAIRO_CFLAGS) \
$(WARN_CFLAGS) $(WERROR_CFLAGS) $(CFLAGS)
ALL_OBJC_CFLAGS=$(ALL_CFLAGS) $(GNU_OBJC_CFLAGS)
@@ -423,7 +427,7 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(LIBX_BASE) $(LIBIMAGE) \
$(RSVG_LIBS) $(IMAGEMAGICK_LIBS) $(LIB_ACL) $(LIB_CLOCK_GETTIME) \
$(LIB_EACCESS) $(LIB_FDATASYNC) $(LIB_TIMER_TIME) $(DBUS_LIBS) \
$(LIB_EXECINFO) $(XRANDR_LIBS) $(XINERAMA_LIBS) $(XFIXES_LIBS) \
- $(LIBXML2_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \
+ $(LIBXML2_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) $(CAIRO_LIBS) \
$(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \
$(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
$(LIBGNUTLS_LIBS) $(LIB_PTHREAD) \
diff --git a/src/dispextern.h b/src/dispextern.h
index 5f730df514..b9db3f808b 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -2939,6 +2939,9 @@ struct image
/* Pixmaps of the image. */
Pixmap pixmap, mask;
+#ifdef USE_CAIRO
+ void *cr_data;
+#endif
#ifdef HAVE_X_WINDOWS
/* X images of the image, corresponding to the above Pixmaps.
Non-NULL means it and its Pixmap counterpart may be out of sync
@@ -3300,6 +3303,9 @@ bool update_window_fringes (struct window *, bool);
void w32_init_fringe (struct redisplay_interface *);
void w32_reset_fringes (void);
#endif
+#ifdef USE_CAIRO
+void x_cr_init_fringe (struct redisplay_interface *);
+#endif
extern unsigned row_hash (struct glyph_row *);
diff --git a/src/font.c b/src/font.c
index b2b43c7971..603e998ed3 100644
--- a/src/font.c
+++ b/src/font.c
@@ -5280,11 +5280,15 @@ EMACS_FONT_LOG is set. Otherwise, it is set to t. */);
#ifdef HAVE_FREETYPE
syms_of_ftfont ();
#ifdef HAVE_X_WINDOWS
+#ifdef USE_CAIRO
+ syms_of_ftcrfont ();
+#else
syms_of_xfont ();
syms_of_ftxfont ();
#ifdef HAVE_XFT
syms_of_xftfont ();
#endif /* HAVE_XFT */
+#endif /* not USE_CAIRO */
#endif /* HAVE_X_WINDOWS */
#else /* not HAVE_FREETYPE */
#ifdef HAVE_X_WINDOWS
diff --git a/src/font.h b/src/font.h
index efc184eef7..43e67e98c0 100644
--- a/src/font.h
+++ b/src/font.h
@@ -844,6 +844,10 @@ extern struct font_driver nsfont_driver;
extern void syms_of_nsfont (void);
extern void syms_of_macfont (void);
#endif /* HAVE_NS */
+#ifdef USE_CAIRO
+extern struct font_driver ftcrfont_driver;
+extern void syms_of_ftcrfont (void);
+#endif
#ifndef FONT_DEBUG
#define FONT_DEBUG
diff --git a/src/fringe.c b/src/fringe.c
index 5e5ec60a48..27b1003555 100644
--- a/src/fringe.c
+++ b/src/fringe.c
@@ -1731,10 +1731,14 @@ init_fringe (void)
fringe_faces = xzalloc (max_fringe_bitmaps * sizeof *fringe_faces);
}
-#ifdef HAVE_NTGUI
+#if defined (HAVE_NTGUI) || defined (USE_CAIRO)
void
+#ifdef HAVE_NTGUI
w32_init_fringe (struct redisplay_interface *rif)
+#else
+x_cr_init_fringe (struct redisplay_interface *rif)
+#endif
{
int bt;
@@ -1747,7 +1751,9 @@ w32_init_fringe (struct redisplay_interface *rif)
rif->define_fringe_bitmap (bt, fb->bits, fb->height, fb->width);
}
}
+#endif
+#ifdef HAVE_NTGUI
void
w32_reset_fringes (void)
{
diff --git a/src/ftcrfont.c b/src/ftcrfont.c
new file mode 100644
index 0000000000..d60c1202b9
--- /dev/null
+++ b/src/ftcrfont.c
@@ -0,0 +1,314 @@
+/* ftcrfont.c -- FreeType font driver on cairo.
+ Copyright (C) 2015 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+GNU Emacs 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
+
+
+#include <config.h>
+#include <stdio.h>
+#include <cairo-ft.h>
+
+#include "lisp.h"
+#include "dispextern.h"
+#include "xterm.h"
+#include "frame.h"
+#include "blockinput.h"
+#include "character.h"
+#include "charset.h"
+#include "fontset.h"
+#include "font.h"
+#include "ftfont.h"
+
+/* FTCR font driver. */
+
+/* The actual structure for ftcr font that can be casted to struct
+ font. */
+
+struct ftcrfont_info
+{
+ struct font font;
+ /* The following six members must be here in this order to be
+ compatible with struct ftfont_info (in ftfont.c). */
+#ifdef HAVE_LIBOTF
+ bool maybe_otf; /* Flag to tell if this may be OTF or not. */
+ OTF *otf;
+#endif /* HAVE_LIBOTF */
+ FT_Size ft_size;
+ int index;
+ FT_Matrix matrix;
+
+ cairo_font_face_t *cr_font_face;
+ /* To prevent cairo from cluttering the activated FT_Size maintained
+ in ftfont.c, we activate this special FT_Size before drawing. */
+ FT_Size ft_size_draw;
+ /* Font metrics cache. */
+ struct font_metrics **metrics;
+ short metrics_nrows;
+};
+
+#define METRICS_NCOLS_PER_ROW (128)
+
+enum metrics_status
+ {
+ METRICS_INVALID = -1, /* metrics entry is invalid */
+ };
+
+#define METRICS_STATUS(metrics) ((metrics)->ascent + (metrics)->descent)
+#define METRICS_SET_STATUS(metrics, status) \
+ ((metrics)->ascent = 0, (metrics)->descent = (status))
+
+/* Prototypes for helper function. */
+static int ftcrfont_glyph_extents (struct font *, unsigned,
+ struct font_metrics *);
+
+/* Prototypes for font-driver methods. */
+static Lisp_Object ftcrfont_list (struct frame*, Lisp_Object);
+static Lisp_Object ftcrfont_match (struct frame*, Lisp_Object);
+static Lisp_Object ftcrfont_open (struct frame*, Lisp_Object, int);
+static void ftcrfont_close (struct font *);
+static void ftcrfont_text_extents (struct font *, unsigned *, int,
+ struct font_metrics *);
+static int ftcrfont_draw (struct glyph_string *, int, int, int, int, bool);
+
+struct font_driver ftcrfont_driver;
+
+static int
+ftcrfont_glyph_extents (struct font *font,
+ unsigned glyph,
+ struct font_metrics *metrics)
+{
+ struct ftcrfont_info *ftcrfont_info = (struct ftcrfont_info *) font;
+ int row, col;
+ struct font_metrics *cache;
+
+ row = glyph / METRICS_NCOLS_PER_ROW;
+ col = glyph % METRICS_NCOLS_PER_ROW;
+ if (row >= ftcrfont_info->metrics_nrows)
+ {
+ ftcrfont_info->metrics =
+ xrealloc (ftcrfont_info->metrics,
+ sizeof (struct font_metrics *) * (row + 1));
+ bzero (ftcrfont_info->metrics + ftcrfont_info->metrics_nrows,
+ (sizeof (struct font_metrics *)
+ * (row + 1 - ftcrfont_info->metrics_nrows)));
+ ftcrfont_info->metrics_nrows = row + 1;
+ }
+ if (ftcrfont_info->metrics[row] == NULL)
+ {
+ struct font_metrics *new;
+ int i;
+
+ new = xmalloc (sizeof (struct font_metrics) * METRICS_NCOLS_PER_ROW);
+ for (i = 0; i < METRICS_NCOLS_PER_ROW; i++)
+ METRICS_SET_STATUS (new + i, METRICS_INVALID);
+ ftcrfont_info->metrics[row] = new;
+ }
+ cache = ftcrfont_info->metrics[row] + col;
+
+ if (METRICS_STATUS (cache) == METRICS_INVALID)
+ ftfont_driver.text_extents (font, &glyph, 1, cache);
+
+ if (metrics)
+ *metrics = *cache;
+
+ return cache->width;
+}
+
+static Lisp_Object
+ftcrfont_list (struct frame *f, Lisp_Object spec)
+{
+ Lisp_Object list = ftfont_driver.list (f, spec), tail;
+
+ for (tail = list; CONSP (tail); tail = XCDR (tail))
+ ASET (XCAR (tail), FONT_TYPE_INDEX, Qftcr);
+ return list;
+}
+
+static Lisp_Object
+ftcrfont_match (struct frame *f, Lisp_Object spec)
+{
+ Lisp_Object entity = ftfont_driver.match (f, spec);
+
+ if (VECTORP (entity))
+ ASET (entity, FONT_TYPE_INDEX, Qftcr);
+ return entity;
+}
+
+extern FT_Face ftfont_get_ft_face (Lisp_Object);
+
+static Lisp_Object
+ftcrfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
+{
+ Lisp_Object font_object;
+ struct font *font;
+ struct ftcrfont_info *ftcrfont_info;
+ FT_Face ft_face;
+ FT_UInt size;
+
+ block_input ();
+ size = XINT (AREF (entity, FONT_SIZE_INDEX));
+ if (size == 0)
+ size = pixel_size;
+ font_object = font_build_object (VECSIZE (struct ftcrfont_info),
+ Qftcr, entity, size);
+ font_object = ftfont_open2 (f, entity, pixel_size, font_object);
+ if (NILP (font_object)) return Qnil;
+
+ font = XFONT_OBJECT (font_object);
+ font->driver = &ftcrfont_driver;
+ ftcrfont_info = (struct ftcrfont_info *) font;
+ ft_face = ftcrfont_info->ft_size->face;
+ FT_New_Size (ft_face, &ftcrfont_info->ft_size_draw);
+ FT_Activate_Size (ftcrfont_info->ft_size_draw);
+ FT_Set_Pixel_Sizes (ft_face, 0, font->pixel_size);
+ ftcrfont_info->cr_font_face =
+ cairo_ft_font_face_create_for_ft_face (ft_face, 0);
+ ftcrfont_info->metrics = NULL;
+ ftcrfont_info->metrics_nrows = 0;
+ unblock_input ();
+
+ return font_object;
+}
+
+static void
+ftcrfont_close (struct font *font)
+{
+ struct ftcrfont_info *ftcrfont_info = (struct ftcrfont_info *) font;
+ int i;
+
+ block_input ();
+ for (i = 0; i < ftcrfont_info->metrics_nrows; i++)
+ if (ftcrfont_info->metrics[i])
+ xfree (ftcrfont_info->metrics[i]);
+ if (ftcrfont_info->metrics)
+ xfree (ftcrfont_info->metrics);
+ FT_Done_Size (ftcrfont_info->ft_size_draw);
+ cairo_font_face_destroy (ftcrfont_info->cr_font_face);
+ unblock_input ();
+
+ ftfont_driver.close (font);
+}
+
+static void
+ftcrfont_text_extents (struct font *font,
+ unsigned *code,
+ int nglyphs,
+ struct font_metrics *metrics)
+{
+ int width, i;
+
+ block_input ();
+ width = ftcrfont_glyph_extents (font, code[0], metrics);
+ for (i = 1; i < nglyphs; i++)
+ {
+ struct font_metrics m;
+ int w = ftcrfont_glyph_extents (font, code[i], metrics ? &m : NULL);
+
+ if (metrics)
+ {
+ if (width + m.lbearing < metrics->lbearing)
+ metrics->lbearing = width + m.lbearing;
+ if (width + m.rbearing > metrics->rbearing)
+ metrics->rbearing = width + m.rbearing;
+ if (m.ascent > metrics->ascent)
+ metrics->ascent = m.ascent;
+ if (m.descent > metrics->descent)
+ metrics->descent = m.descent;
+ }
+ width += w;
+ }
+ unblock_input ();
+
+ if (metrics)
+ metrics->width = width;
+}
+
+static int
+ftcrfont_draw (struct glyph_string *s,
+ int from, int to, int x, int y, bool with_background)
+{
+ struct frame *f = s->f;
+ struct face *face = s->face;
+ struct ftcrfont_info *ftcrfont_info = (struct ftcrfont_info *) s->font;
+ cairo_t *cr;
+ cairo_glyph_t *glyphs;
+ cairo_surface_t *surface;
+ int len = to - from;
+ int i;
+
+ block_input ();
+
+ cr = x_begin_cr_clip (f, s->gc);
+
+ if (with_background)
+ {
+ x_set_cr_source_with_gc_background (f, s->gc);
+ cairo_rectangle (cr, x, y - FONT_BASE (face->font),
+ s->width, FONT_HEIGHT (face->font));
+ cairo_fill (cr);
+ }
+
+ glyphs = alloca (sizeof (cairo_glyph_t) * len);
+ for (i = 0; i < len; i++)
+ {
+ unsigned code = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8)
+ | XCHAR2B_BYTE2 (s->char2b + from + i));
+
+ glyphs[i].index = code;
+ glyphs[i].x = x;
+ glyphs[i].y = y;
+ x += (s->padding_p ? 1 : ftcrfont_glyph_extents (s->font, code, NULL));
+ }
+
+ x_set_cr_source_with_gc_foreground (f, s->gc);
+ cairo_set_font_face (cr, ftcrfont_info->cr_font_face);
+ cairo_set_font_size (cr, s->font->pixel_size);
+ /* cairo_set_font_matrix */
+ /* cairo_set_font_options */
+
+ FT_Activate_Size (ftcrfont_info->ft_size_draw);
+ cairo_show_glyphs (cr, glyphs, len);
+ surface = cairo_get_target (cr);
+ if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_XLIB)
+ cairo_surface_flush (surface);
+
+ x_end_cr_clip (f);
+
+ unblock_input ();
+
+ return len;
+}
+
+
+
+void
+syms_of_ftcrfont (void)
+{
+ if (ftfont_info_size != offsetof (struct ftcrfont_info, cr_font_face))
+ abort ();
+
+ DEFSYM (Qftcr, "ftcr");
+
+ ftcrfont_driver = ftfont_driver;
+ ftcrfont_driver.type = Qftcr;
+ ftcrfont_driver.list = ftcrfont_list;
+ ftcrfont_driver.match = ftcrfont_match;
+ ftcrfont_driver.open = ftcrfont_open;
+ ftcrfont_driver.close = ftcrfont_close;
+ ftcrfont_driver.text_extents = ftcrfont_text_extents;
+ ftcrfont_driver.draw = ftcrfont_draw;
+ register_font_driver (&ftcrfont_driver, NULL);
+}
diff --git a/src/ftfont.c b/src/ftfont.c
index adf188815d..75d59c1629 100644
--- a/src/ftfont.c
+++ b/src/ftfont.c
@@ -67,6 +67,8 @@ struct ftfont_info
FT_Matrix matrix;
};
+size_t ftfont_info_size = sizeof (struct ftfont_info);
+
enum ftfont_cache_for
{
FTFONT_CACHE_FOR_FACE,
@@ -1161,8 +1163,11 @@ ftfont_list_family (struct frame *f)
}
-static Lisp_Object
-ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
+Lisp_Object
+ftfont_open2 (struct frame *f,
+ Lisp_Object entity,
+ int pixel_size,
+ Lisp_Object font_object)
{
struct ftfont_info *ftfont_info;
struct font *font;
@@ -1170,7 +1175,7 @@ ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
FT_Face ft_face;
FT_Size ft_size;
FT_UInt size;
- Lisp_Object val, filename, idx, cache, font_object;
+ Lisp_Object val, filename, idx, cache;
bool scalable;
int spacing;
int i;
@@ -1210,8 +1215,6 @@ ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
return Qnil;
}
- font_object = font_build_object (VECSIZE (struct ftfont_info),
- Qfreetype, entity, size);
ASET (font_object, FONT_FILE_INDEX, filename);
font = XFONT_OBJECT (font_object);
ftfont_info = (struct ftfont_info *) font;
@@ -1294,6 +1297,19 @@ ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
return font_object;
}
+static Lisp_Object
+ftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
+{
+ Lisp_Object font_object;
+ FT_UInt size;
+ size = XINT (AREF (entity, FONT_SIZE_INDEX));
+ if (size == 0)
+ size = pixel_size;
+ font_object = font_build_object (VECSIZE (struct ftfont_info),
+ Qfreetype, entity, size);
+ return ftfont_open2 (f, entity, pixel_size, font_object);
+}
+
static void
ftfont_close (struct font *font)
{
diff --git a/src/ftfont.h b/src/ftfont.h
index 210b634c09..0cfa0ae3e3 100644
--- a/src/ftfont.h
+++ b/src/ftfont.h
@@ -37,6 +37,11 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#endif /* HAVE_LIBOTF */
extern FcCharSet *ftfont_get_fc_charset (Lisp_Object);
+extern Lisp_Object ftfont_open2 (struct frame *f,
+ Lisp_Object entity,
+ int pixel_size,
+ Lisp_Object font_object);
+extern size_t ftfont_info_size;
#endif /* EMACS_FTFONT_H */
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 6f1707894c..f111ea80ce 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -845,22 +845,23 @@ xg_clear_under_internal_border (struct frame *f)
{
if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0)
{
+#ifndef USE_CAIRO
GtkWidget *wfixed = f->output_data.x->edit_widget;
gtk_widget_queue_draw (wfixed);
gdk_window_process_all_updates ();
-
- x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 0, 0,
+#endif
+ x_clear_area (f, 0, 0,
FRAME_PIXEL_WIDTH (f), FRAME_INTERNAL_BORDER_WIDTH (f));
- x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 0, 0,
+ x_clear_area (f, 0, 0,
FRAME_INTERNAL_BORDER_WIDTH (f), FRAME_PIXEL_HEIGHT (f));
- x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 0,
+ x_clear_area (f, 0,
FRAME_PIXEL_HEIGHT (f) - FRAME_INTERNAL_BORDER_WIDTH (f),
FRAME_PIXEL_WIDTH (f), FRAME_INTERNAL_BORDER_WIDTH (f));
- x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ x_clear_area (f,
FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f),
0, FRAME_INTERNAL_BORDER_WIDTH (f), FRAME_PIXEL_HEIGHT (f));
}
@@ -2125,12 +2126,18 @@ xg_get_font (struct frame *f, const char *default_name)
PangoWeight weight = pango_font_description_get_weight (desc);
PangoStyle style = pango_font_description_get_style (desc);
+#ifdef USE_CAIRO
+#define FONT_TYPE_WANTED (Qftcr)
+#else
+#define FONT_TYPE_WANTED (Qxft)
+#endif
font = CALLN (Ffont_spec,
QCname, build_string (name),
QCsize, make_float (pango_units_to_double (size)),
QCweight, XG_WEIGHT_TO_SYMBOL (weight),
QCslant, XG_STYLE_TO_SYMBOL (style),
- QCtype, Qxft);
+ QCtype,
+ FONT_TYPE_WANTED);
pango_font_description_free (desc);
dupstring (&x_last_font_name, name);
@@ -3784,13 +3791,15 @@ xg_update_scrollbar_pos (struct frame *f,
gtk_widget_show_all (wparent);
gtk_widget_set_size_request (wscroll, width, height);
}
+#ifndef USE_CAIRO
gtk_widget_queue_draw (wfixed);
gdk_window_process_all_updates ();
+#endif
if (oldx != -1 && oldw > 0 && oldh > 0)
/* Clear under old scroll bar position. This must be done after
the gtk_widget_queue_draw and gdk_window_process_all_updates
above. */
- x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ x_clear_area (f,
oldx, oldy, oldw, oldh);
/* GTK does not redraw until the main loop is entered again, but
@@ -3856,7 +3865,7 @@ xg_update_horizontal_scrollbar_pos (struct frame *f,
/* Clear under old scroll bar position. This must be done after
the gtk_widget_queue_draw and gdk_window_process_all_updates
above. */
- x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ x_clear_area (f,
oldx, oldy, oldw, oldh);
/* GTK does not redraw until the main loop is entered again, but
@@ -4033,6 +4042,112 @@ xg_event_is_for_scrollbar (struct frame *f, const XEvent *event)
return retval;
}
+
+/***********************************************************************
+ Printing
+ ***********************************************************************/
+#ifdef USE_CAIRO
+static GtkPrintSettings *print_settings = NULL;
+static GtkPageSetup *page_setup = NULL;
+
+void
+xg_page_setup_dialog ()
+{
+ GtkPageSetup *new_page_setup = NULL;
+
+ if (print_settings == NULL)
+ print_settings = gtk_print_settings_new ();
+ new_page_setup = gtk_print_run_page_setup_dialog (NULL, page_setup,
+ print_settings);
+ if (page_setup)
+ g_object_unref (page_setup);
+ page_setup = new_page_setup;
+}
+
+Lisp_Object
+xg_get_page_setup ()
+{
+ Lisp_Object result, orientation_symbol;
+ GtkPageOrientation orientation;
+
+ if (page_setup == NULL)
+ page_setup = gtk_page_setup_new ();
+ result = list4 (Fcons (Qleft_margin,
+ make_float (gtk_page_setup_get_left_margin (page_setup,
+ GTK_UNIT_POINTS))),
+ Fcons (Qright_margin,
+ make_float (gtk_page_setup_get_right_margin (page_setup,
+ GTK_UNIT_POINTS))),
+ Fcons (Qtop_margin,
+ make_float (gtk_page_setup_get_top_margin (page_setup,
+ GTK_UNIT_POINTS))),
+ Fcons (Qbottom_margin,
+ make_float (gtk_page_setup_get_bottom_margin (page_setup,
+ GTK_UNIT_POINTS))));
+ result = Fcons (Fcons (Qheight,
+ make_float (gtk_page_setup_get_page_height (page_setup,
+ GTK_UNIT_POINTS))),
+ result);
+ result = Fcons (Fcons (Qwidth,
+ make_float (gtk_page_setup_get_page_width (page_setup,
+ GTK_UNIT_POINTS))),
+ result);
+ orientation = gtk_page_setup_get_orientation (page_setup);
+ if (orientation == GTK_PAGE_ORIENTATION_PORTRAIT)
+ orientation_symbol = Qportrait;
+ else if (orientation == GTK_PAGE_ORIENTATION_LANDSCAPE)
+ orientation_symbol = Qlandscape;
+ else if (orientation == GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT)
+ orientation_symbol = Qreverse_portrait;
+ else if (orientation == GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE)
+ orientation_symbol = Qreverse_landscape;
+ result = Fcons (Fcons (Qorientation, orientation_symbol), result);
+
+ return result;
+}
+
+static void
+draw_page (operation, context, page_nr, user_data)
+ GtkPrintOperation *operation;
+ GtkPrintContext *context;
+ gint page_nr;
+ gpointer user_data;
+{
+ Lisp_Object frames = *((Lisp_Object *) user_data);
+ struct frame *f = XFRAME (Fnth (make_number (page_nr), frames));
+ cairo_t *cr = gtk_print_context_get_cairo_context (context);
+
+ x_cr_draw_frame (cr, f);
+}
+
+void
+xg_print_frames_dialog (frames)
+ Lisp_Object frames;
+{
+ GtkPrintOperation *print;
+ GtkPrintOperationResult res;
+
+ print = gtk_print_operation_new ();
+ if (print_settings != NULL)
+ gtk_print_operation_set_print_settings (print, print_settings);
+ if (page_setup != NULL)
+ gtk_print_operation_set_default_page_setup (print, page_setup);
+ gtk_print_operation_set_n_pages (print, XINT (Flength (frames)));
+ g_signal_connect (print, "draw-page", G_CALLBACK (draw_page), &frames);
+ res = gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
+ NULL, NULL);
+ if (res == GTK_PRINT_OPERATION_RESULT_APPLY)
+ {
+ if (print_settings != NULL)
+ g_object_unref (print_settings);
+ print_settings =
+ g_object_ref (gtk_print_operation_get_print_settings (print));
+ }
+ g_object_unref (print);
+}
+
+#endif /* USE_CAIRO */
+
/***********************************************************************
diff --git a/src/gtkutil.h b/src/gtkutil.h
index 0ac49ca7db..34338db58f 100644
--- a/src/gtkutil.h
+++ b/src/gtkutil.h
@@ -180,6 +180,12 @@ extern bool xg_prepare_tooltip (struct frame *f,
extern void xg_show_tooltip (struct frame *f, int root_x, int root_y);
extern bool xg_hide_tooltip (struct frame *f);
+#ifdef USE_CAIRO
+extern void xg_page_setup_dialog (void);
+extern Lisp_Object xg_get_page_setup (void);
+extern void xg_print_frames_dialog (Lisp_Object);
+#endif
+
/* Mark all callback data that are Lisp_object:s during GC. */
extern void xg_mark_data (void);
diff --git a/src/image.c b/src/image.c
index df299bbd16..09d068725d 100644
--- a/src/image.c
+++ b/src/image.c
@@ -1299,6 +1299,14 @@ static void
x_clear_image (struct frame *f, struct image *img)
{
block_input ();
+#ifdef USE_CAIRO
+ if (img->cr_data)
+ {
+ cairo_surface_destroy ((cairo_surface_t *)img->cr_data);
+ unblock_input ();
+ return;
+ }
+#endif
x_clear_image_1 (f, img,
CLEAR_IMAGE_PIXMAP | CLEAR_IMAGE_MASK | CLEAR_IMAGE_COLORS);
unblock_input ();
@@ -5403,7 +5411,7 @@ pbm_load (struct frame *f, struct image *img)
PNG
***********************************************************************/
-#if defined (HAVE_PNG) || defined (HAVE_NS)
+#if defined (HAVE_PNG) || defined (HAVE_NS) || defined (USE_CAIRO)
/* Function prototypes. */
@@ -5477,10 +5485,10 @@ png_image_p (Lisp_Object object)
return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
}
-#endif /* HAVE_PNG || HAVE_NS */
+#endif /* HAVE_PNG || HAVE_NS || USE_CAIRO */
-#if defined HAVE_PNG && !defined HAVE_NS
+#if defined HAVE_PNG && !defined HAVE_NS && !defined USE_CAIRO
# ifdef WINDOWSNT
/* PNG library details. */
@@ -6049,7 +6057,44 @@ png_load (struct frame *f, struct image *img)
image_spec_value (img->spec, QCdata, NULL));
}
-#endif /* HAVE_NS */
+#elif defined USE_CAIRO
+
+static bool
+png_load (struct frame *f, struct image *img)
+{
+ Lisp_Object file;
+ Lisp_Object specified_file = image_spec_value (img->spec, QCfile, NULL);
+ cairo_surface_t *surface;
+
+ if (! STRINGP (specified_file))
+ {
+ image_error ("Invalid image spec, file missing `%s'", img->spec, Qnil);
+ return false;
+ }
+
+ file = x_find_image_file (specified_file);
+ if (! STRINGP (file))
+ {
+ image_error ("Cannot find image file `%s'", specified_file, Qnil);
+ return false;
+ }
+
+ surface = cairo_image_surface_create_from_png (SSDATA (file));
+ if (! surface)
+ {
+ image_error ("Error creating surface from file `%s'",
+ specified_file, Qnil);
+ return false;
+ }
+ img->width = cairo_image_surface_get_width (surface);
+ img->height = cairo_image_surface_get_height (surface);
+ img->cr_data = surface;
+ img->pixmap = 0;
+
+ return true;
+}
+
+#endif /* USE_CAIRO */
@@ -9353,7 +9398,7 @@ lookup_image_type (Lisp_Object type)
return define_image_type (&gif_type);
#endif
-#if defined (HAVE_PNG) || defined (HAVE_NS)
+#if defined (HAVE_PNG) || defined (HAVE_NS) || defined (USE_CAIRO)
if (EQ (type, Qpng))
return define_image_type (&png_type);
#endif
diff --git a/src/xfns.c b/src/xfns.c
index 629ac4b26f..23af4388e5 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -3052,6 +3052,9 @@ This function is an internal primitive--use `make-frame' instead. */)
specbind (Qx_resource_name, name);
}
+#ifdef USE_CAIRO
+ register_font_driver (&ftcrfont_driver, f);
+#else
#ifdef HAVE_FREETYPE
#ifdef HAVE_XFT
register_font_driver (&xftfont_driver, f);
@@ -3060,6 +3063,7 @@ This function is an internal primitive--use `make-frame' instead. */)
#endif /* not HAVE_XFT */
#endif /* HAVE_FREETYPE */
register_font_driver (&xfont_driver, f);
+#endif /* not USE_CAIRO */
x_default_parameter (f, parms, Qfont_backend, Qnil,
"fontBackend", "FontBackend", RES_TYPE_STRING);
@@ -5049,6 +5053,9 @@ x_create_tip_frame (struct x_display_info *dpyinfo,
specbind (Qx_resource_name, name);
}
+#ifdef USE_CAIRO
+ register_font_driver (&ftcrfont_driver, f);
+#else
register_font_driver (&xfont_driver, f);
#ifdef HAVE_FREETYPE
#ifdef HAVE_XFT
@@ -5057,6 +5064,7 @@ x_create_tip_frame (struct x_display_info *dpyinfo,
register_font_driver (&ftxfont_driver, f);
#endif /* not HAVE_XFT */
#endif /* HAVE_FREETYPE */
+#endif /* not USE_CAIRO */
x_default_parameter (f, parms, Qfont_backend, Qnil,
"fontBackend", "FontBackend", RES_TYPE_STRING);
@@ -6140,6 +6148,160 @@ present and mapped to the usual X keysyms. */)
/***********************************************************************
+ Printing
+ ***********************************************************************/
+
+#ifdef USE_CAIRO
+DEFUN ("x-export-frames", Fx_export_frames, Sx_export_frames, 0, 2, 0,
+ doc: /* XXX Experimental. Return image data of FRAMES in TYPE format.
+FRAMES should be nil (the selected frame), a frame, or a list of
+frames (each of which corresponds to one page). Optional arg TYPE
+should be either `pdf' (default), `png', `ps', or `svg'. Supported
+types are determined by the compile-time configuration of cairo. */)
+ (frames, type)
+ Lisp_Object frames, type;
+{
+ Lisp_Object result, rest, tmp;
+ cairo_surface_type_t surface_type;
+
+ if (NILP (frames))
+ frames = selected_frame;
+ if (!CONSP (frames))
+ frames = list1 (frames);
+
+ tmp = Qnil;
+ for (rest = frames; CONSP (rest); rest = XCDR (rest))
+ {
+ struct frame *f = XFRAME (XCAR (rest));
+
+ if (! FRAME_LIVE_P (f) || ! FRAME_X_P (f) || ! FRAME_LIVE_P (f))
+ error ("Invalid frame");
+
+ Lisp_Object frame;
+
+ XSETFRAME (frame, f);
+ tmp = Fcons (frame, tmp);
+ }
+ frames = Fnreverse (tmp);
+
+#ifdef CAIRO_HAS_PDF_SURFACE
+ if (NILP (type) || EQ (type, intern ("pdf"))) /* XXX: Qpdf */
+ surface_type = CAIRO_SURFACE_TYPE_PDF;
+ else
+#endif
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+ if (EQ (type, intern ("png")))
+ {
+ if (!NILP (XCDR (frames)))
+ error ("PNG export cannot handle multiple frames.");
+ surface_type = CAIRO_SURFACE_TYPE_IMAGE;
+ }
+ else
+#endif
+#ifdef CAIRO_HAS_PS_SURFACE
+ if (EQ (type, intern ("ps")))
+ surface_type = CAIRO_SURFACE_TYPE_PS;
+ else
+#endif
+#ifdef CAIRO_HAS_SVG_SURFACE
+ if (EQ (type, intern ("svg")))
+ {
+ /* For now, we stick to SVG 1.1. */
+ if (!NILP (XCDR (frames)))
+ error ("SVG export cannot handle multiple frames.");
+ surface_type = CAIRO_SURFACE_TYPE_SVG;
+ }
+ else
+#endif
+ error ("Unsupported export type");
+
+ result = x_cr_export_frames (frames, surface_type);
+
+ return result;
+}
+
+#ifdef USE_GTK
+DEFUN ("x-page-setup-dialog", Fx_page_setup_dialog, Sx_page_setup_dialog, 0, 0, 0,
+ doc: /* Pop up a page setup dialog.
+The current page setup can be obtained using `x-get-page-setup'. */)
+ ()
+{
+ block_input ();
+ xg_page_setup_dialog ();
+ unblock_input ();
+
+ return Qnil;
+}
+
+DEFUN ("x-get-page-setup", Fx_get_page_setup, Sx_get_page_setup, 0, 0, 0,
+ doc: /* Return the value of the current page setup.
+The return value is an alist containing the following keys:
+
+ orientation: page orientation (symbol `portrait', `landscape',
+ `reverse-portrait', or `reverse-landscape').
+ width, height: page width/height in points not including margins.
+ left-margin, right-margin, top-margin, bottom-margin: print margins,
+ which is the parts of the page that the printer cannot print
+ on, in points.
+
+The paper width can be obtained as the sum of width, left-margin, and
+right-margin values. Likewise, the paper height is the sum of height,
+top-margin, and bottom-margin values. */)
+ ()
+{
+ Lisp_Object result;
+
+ block_input ();
+ result = xg_get_page_setup ();
+ unblock_input ();
+
+ return result;
+}
+
+DEFUN ("x-print-frames-dialog", Fx_print_frames_dialog, Sx_print_frames_dialog, 0, 1, "",
+ doc: /* Pop up a print dialog to print the current contents of FRAMES.
+FRAMES should be nil (the selected frame), a frame, or a list of
+frames (each of which corresponds to one page). Each frame should be
+visible. */)
+ (frames)
+ Lisp_Object frames;
+{
+ Lisp_Object rest, tmp;
+
+ if (NILP (frames))
+ frames = selected_frame;
+ if (!CONSP (frames))
+ frames = list1 (frames);
+
+ tmp = Qnil;
+ for (rest = frames; CONSP (rest); rest = XCDR (rest))
+ {
+ struct frame *f = XFRAME (XCAR (rest));
+ if (! FRAME_LIVE_P (f) || ! FRAME_X_P (f) || ! FRAME_LIVE_P (f))
+ error ("Invalid frame");
+ Lisp_Object frame;
+
+ XSETFRAME (frame, f);
+ if (!EQ (Fframe_visible_p (frame), Qt))
+ error ("Frames to be printed must be visible.");
+ tmp = Fcons (frame, tmp);
+ }
+ frames = Fnreverse (tmp);
+
+ /* Make sure the current matrices are up-to-date. */
+ Fredisplay (Qt);
+
+ block_input ();
+ xg_print_frames_dialog (frames);
+ unblock_input ();
+
+ return Qnil;
+}
+#endif /* USE_GTK */
+#endif /* USE_CAIRO */
+
+
+/***********************************************************************
Initialization
***********************************************************************/
@@ -6195,6 +6357,16 @@ syms_of_xfns (void)
DEFSYM (Qcancel_timer, "cancel-timer");
DEFSYM (Qfont_param, "font-parameter");
+#ifdef USE_CAIRO
+ DEFSYM (Qorientation, "orientation");
+ DEFSYM (Qtop_margin, "top-margin");
+ DEFSYM (Qbottom_margin, "bottom-margin");
+ DEFSYM (Qportrait, "portrait");
+ DEFSYM (Qlandscape, "landscape");
+ DEFSYM (Qreverse_portrait, "reverse-portrait");
+ DEFSYM (Qreverse_landscape, "reverse-landscape");
+#endif
+
Fput (Qundefined_color, Qerror_conditions,
listn (CONSTYPE_PURE, 2, Qundefined_color, Qerror));
Fput (Qundefined_color, Qerror_message,
@@ -6335,6 +6507,20 @@ When using Gtk+ tooltips, the tooltip face is not used. */);
}
#endif /* USE_GTK */
+#ifdef USE_CAIRO
+ Fprovide (intern_c_string ("cairo"), Qnil);
+
+ DEFVAR_LISP ("cairo-version-string", Vcairo_version_string,
+ doc: /* Version info for cairo. */);
+ {
+ char cairo_version[sizeof ".." + 3 * INT_STRLEN_BOUND (int)];
+ int len = sprintf (cairo_version, "%d.%d.%d",
+ CAIRO_VERSION_MAJOR, CAIRO_VERSION_MINOR,
+ CAIRO_VERSION_MICRO);
+ Vcairo_version_string = make_pure_string (cairo_version, len, len, false);
+ }
+#endif
+
/* X window properties. */
defsubr (&Sx_change_window_property);
defsubr (&Sx_delete_window_property);
@@ -6385,4 +6571,13 @@ When using Gtk+ tooltips, the tooltip face is not used. */);
#if defined (USE_GTK) && defined (HAVE_FREETYPE)
defsubr (&Sx_select_font);
#endif
+
+#ifdef USE_CAIRO
+ defsubr (&Sx_export_frames);
+#ifdef USE_GTK
+ defsubr (&Sx_page_setup_dialog);
+ defsubr (&Sx_get_page_setup);
+ defsubr (&Sx_print_frames_dialog);
+#endif
+#endif
}
diff --git a/src/xterm.c b/src/xterm.c
index 0b3efe7b4b..1074862ca3 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -220,6 +220,7 @@ static int x_io_error_quitter (Display *);
static struct terminal *x_create_terminal (struct x_display_info *);
static void x_update_end (struct frame *);
static void XTframe_up_to_date (struct frame *);
+static void x_clear_area1 (Display *, Window, int, int, int, int, int);
static void x_clear_frame (struct frame *);
static _Noreturn void x_ins_del_lines (struct frame *, int, int);
static void frame_highlight (struct frame *);
@@ -325,6 +326,555 @@ record_event (char *locus, int type)
#endif
+static void x_prepare_for_xlibdraw (struct frame *);
+static void x_set_clip_rectangles (struct frame *, GC, XRectangle *, int);
+static void x_reset_clip_rectangles (struct frame *, GC);
+static void x_fill_rectangle (struct frame *, GC, int, int,
+ unsigned int, unsigned int);
+static void x_draw_rectangle (struct frame *, GC, int, int,
+ unsigned int, unsigned int);
+static void x_fill_trapezoid_for_relief (struct frame *, GC, int, int,
+ unsigned int, unsigned int, int);
+static void x_clear_window (struct frame *);
+
+#ifdef USE_CAIRO
+static struct x_gc_ext_data *x_gc_get_ext_data (struct frame *, GC, int);
+static void x_extension_initialize (struct x_display_info *);
+static cairo_status_t x_cr_accumulate_data (void *,
+ const unsigned char *,
+ unsigned int);
+
+#define FRAME_CR_CONTEXT(f) ((f)->output_data.x->cr_context)
+#define FRAME_CR_SURFACE(f) ((f)->output_data.x->cr_surface)
+
+static struct x_gc_ext_data *
+x_gc_get_ext_data (f, gc, create_if_not_found_p)
+ struct frame *f;
+ GC gc;
+ int create_if_not_found_p;
+{
+ struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
+ XEDataObject object;
+ XExtData **head, *ext_data;
+
+ object.gc = gc;
+ head = XEHeadOfExtensionList (object);
+ ext_data = XFindOnExtensionList (head, dpyinfo->ext_codes->extension);
+ if (ext_data == NULL)
+ {
+ if (!create_if_not_found_p)
+ return NULL;
+ else
+ {
+ ext_data = xzalloc (sizeof (*ext_data));
+ ext_data->number = dpyinfo->ext_codes->extension;
+ ext_data->private_data = xzalloc (sizeof (struct x_gc_ext_data));
+ XAddToExtensionList (head, ext_data);
+ }
+ }
+ return (struct x_gc_ext_data *) ext_data->private_data;
+}
+
+static void
+x_extension_initialize (dpyinfo)
+ struct x_display_info *dpyinfo;
+{
+ XExtCodes *ext_codes = XAddExtension (dpyinfo->display);
+
+ dpyinfo->ext_codes = ext_codes;
+}
+
+static void
+x_cr_destroy_surface (struct frame *f)
+{
+ if (FRAME_CR_SURFACE (f))
+ {
+ cairo_t *cr = FRAME_CR_CONTEXT (f);
+ cairo_surface_destroy (FRAME_CR_SURFACE (f));
+ FRAME_CR_SURFACE (f) = 0;
+ if (cr) cairo_destroy (cr);
+ FRAME_CR_CONTEXT (f) = NULL;
+ }
+}
+
+cairo_t *
+x_begin_cr_clip (f, gc)
+ struct frame *f;
+ GC gc;
+{
+ cairo_t *cr = FRAME_CR_CONTEXT (f);
+
+ if (!cr)
+ {
+
+ if (! FRAME_CR_SURFACE (f))
+ {
+ cairo_surface_t *surface;
+ surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f),
+ FRAME_X_WINDOW (f),
+ FRAME_DISPLAY_INFO (f)->visual,
+ FRAME_PIXEL_WIDTH (f),
+ FRAME_PIXEL_HEIGHT (f));
+ cr = cairo_create (surface);
+ cairo_surface_destroy (surface);
+ }
+ else
+ cr = cairo_create (FRAME_CR_SURFACE (f));
+ FRAME_CR_CONTEXT (f) = cr;
+ }
+ cairo_save (cr);
+
+ if (gc)
+ {
+ struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0);
+
+ if (gc_ext && gc_ext->n_clip_rects)
+ {
+ int i;
+
+ for (i = 0; i < gc_ext->n_clip_rects; i++)
+ cairo_rectangle (cr, gc_ext->clip_rects[i].x,
+ gc_ext->clip_rects[i].y,
+ gc_ext->clip_rects[i].width,
+ gc_ext->clip_rects[i].height);
+ cairo_clip (cr);
+ }
+ }
+
+ return cr;
+}
+
+void
+x_end_cr_clip (f)
+ struct frame *f;
+{
+ cairo_restore (FRAME_CR_CONTEXT (f));
+}
+
+void
+x_set_cr_source_with_gc_foreground (f, gc)
+ struct frame *f;
+ GC gc;
+{
+ XGCValues xgcv;
+ XColor color;
+
+ XGetGCValues (FRAME_X_DISPLAY (f), gc, GCForeground, &xgcv);
+ color.pixel = xgcv.foreground;
+ x_query_color (f, &color);
+ cairo_set_source_rgb (FRAME_CR_CONTEXT (f), color.red / 65535.0,
+ color.green / 65535.0, color.blue / 65535.0);
+}
+
+void
+x_set_cr_source_with_gc_background (f, gc)
+ struct frame *f;
+ GC gc;
+{
+ XGCValues xgcv;
+ XColor color;
+
+ XGetGCValues (FRAME_X_DISPLAY (f), gc, GCBackground, &xgcv);
+ color.pixel = xgcv.background;
+ x_query_color (f, &color);
+ cairo_set_source_rgb (FRAME_CR_CONTEXT (f), color.red / 65535.0,
+ color.green / 65535.0, color.blue / 65535.0);
+}
+
+/* Fringe bitmaps. */
+
+static int max_fringe_bmp = 0;
+static cairo_pattern_t **fringe_bmp = 0;
+
+static void
+x_cr_define_fringe_bitmap (which, bits, h, wd)
+ int which;
+ unsigned short *bits;
+ int h, wd;
+{
+ int i, stride;
+ cairo_surface_t *surface;
+ unsigned char *data;
+ cairo_pattern_t *pattern;
+
+ if (which >= max_fringe_bmp)
+ {
+ i = max_fringe_bmp;
+ max_fringe_bmp = which + 20;
+ fringe_bmp = (cairo_pattern_t **) xrealloc (fringe_bmp, max_fringe_bmp * sizeof (cairo_pattern_t *));
+ while (i < max_fringe_bmp)
+ fringe_bmp[i++] = 0;
+ }
+
+ block_input ();
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_A1, wd, h);
+ stride = cairo_image_surface_get_stride (surface);
+ data = cairo_image_surface_get_data (surface);
+
+ for (i = 0; i < h; i++)
+ {
+ *((unsigned short *) data) = bits[i];
+ data += stride;
+ }
+
+ pattern = cairo_pattern_create_for_surface (surface);
+ cairo_surface_destroy (surface);
+
+ unblock_input ();
+
+ fringe_bmp[which] = pattern;
+}
+
+static void
+x_cr_destroy_fringe_bitmap (which)
+ int which;
+{
+ if (which >= max_fringe_bmp)
+ return;
+
+ if (fringe_bmp[which])
+ {
+ block_input ();
+ cairo_pattern_destroy (fringe_bmp[which]);
+ unblock_input ();
+ }
+ fringe_bmp[which] = 0;
+}
+
+static void
+x_cr_draw_image (struct frame *f,
+ GC gc,
+ cairo_pattern_t *image,
+ int src_x,
+ int src_y,
+ unsigned int width,
+ unsigned int height,
+ int dest_x,
+ int dest_y,
+ bool overlay_p)
+{
+ cairo_t *cr;
+ cairo_matrix_t matrix;
+ cairo_surface_t *surface;
+ cairo_format_t format;
+
+ cr = x_begin_cr_clip (f, gc);
+ if (overlay_p)
+ cairo_rectangle (cr, dest_x, dest_y, width, height);
+ else
+ {
+ x_set_cr_source_with_gc_background (f, gc);
+ cairo_rectangle (cr, dest_x, dest_y, width, height);
+ cairo_fill_preserve (cr);
+ }
+ cairo_clip (cr);
+ cairo_matrix_init_translate (&matrix, src_x - dest_x, src_y - dest_y);
+ cairo_pattern_set_matrix (image, &matrix);
+ cairo_pattern_get_surface (image, &surface);
+ format = cairo_image_surface_get_format (surface);
+ if (format != CAIRO_FORMAT_A8 && format != CAIRO_FORMAT_A1)
+ {
+ cairo_set_source (cr, image);
+ cairo_fill (cr);
+ }
+ else
+ {
+ x_set_cr_source_with_gc_foreground (f, gc);
+ cairo_mask (cr, image);
+ }
+ x_end_cr_clip (f);
+}
+
+void
+x_cr_draw_frame (cr, f)
+ cairo_t *cr;
+ struct frame *f;
+{
+ int width, height;
+
+ width = FRAME_PIXEL_WIDTH (f);
+ height = FRAME_PIXEL_HEIGHT (f);
+
+ x_prepare_for_xlibdraw (f);
+ FRAME_CR_CONTEXT (f) = cr;
+ x_clear_area (f, 0, 0, width, height);
+ expose_frame (f, 0, 0, width, height);
+ FRAME_CR_CONTEXT (f) = NULL;
+}
+
+static cairo_status_t
+x_cr_accumulate_data (closure, data, length)
+ void *closure;
+ const unsigned char *data;
+ unsigned int length;
+{
+ Lisp_Object *acc = (Lisp_Object *) closure;
+
+ *acc = Fcons (make_unibyte_string (data, length), *acc);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+x_cr_destroy (arg)
+ Lisp_Object arg;
+{
+ cairo_t *cr = (cairo_t *) XSAVE_POINTER (arg, 0);
+
+ block_input ();
+ cairo_destroy (cr);
+ unblock_input ();
+}
+
+Lisp_Object
+x_cr_export_frames (frames, surface_type)
+ Lisp_Object frames;
+ cairo_surface_type_t surface_type;
+{
+ struct frame *f;
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ int width, height;
+ void (*surface_set_size_func) (cairo_surface_t *, double, double) = NULL;
+ Lisp_Object acc = Qnil, args[2];
+ int count = SPECPDL_INDEX ();
+
+ Fredisplay (Qt);
+
+ f = XFRAME (XCAR (frames));
+ frames = XCDR (frames);
+ width = FRAME_PIXEL_WIDTH (f);
+ height = FRAME_PIXEL_HEIGHT (f);
+
+ block_input ();
+#ifdef CAIRO_HAS_PDF_SURFACE
+ if (surface_type == CAIRO_SURFACE_TYPE_PDF)
+ {
+ surface = cairo_pdf_surface_create_for_stream (x_cr_accumulate_data, &acc,
+ width, height);
+ surface_set_size_func = cairo_pdf_surface_set_size;
+ }
+ else
+#endif
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+ if (surface_type == CAIRO_SURFACE_TYPE_IMAGE)
+ surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
+ else
+#endif
+#ifdef CAIRO_HAS_PS_SURFACE
+ if (surface_type == CAIRO_SURFACE_TYPE_PS)
+ {
+ surface = cairo_ps_surface_create_for_stream (x_cr_accumulate_data, &acc,
+ width, height);
+ surface_set_size_func = cairo_ps_surface_set_size;
+ }
+ else
+#endif
+#ifdef CAIRO_HAS_SVG_SURFACE
+ if (surface_type == CAIRO_SURFACE_TYPE_SVG)
+ surface = cairo_svg_surface_create_for_stream (x_cr_accumulate_data, &acc,
+ width, height);
+ else
+#endif
+ abort ();
+
+ cr = cairo_create (surface);
+ cairo_surface_destroy (surface);
+ record_unwind_protect (x_cr_destroy, make_save_ptr (cr));
+ unblock_input ();
+
+ while (1)
+ {
+ QUIT;
+
+ block_input ();
+ x_prepare_for_xlibdraw (f);
+ FRAME_CR_CONTEXT (f) = cr;
+ x_clear_area (f, 0, 0, width, height);
+ expose_frame (f, 0, 0, width, height);
+ FRAME_CR_CONTEXT (f) = NULL;
+ unblock_input ();
+
+ if (NILP (frames))
+ break;
+
+ block_input ();
+ cairo_surface_show_page (surface);
+ f = XFRAME (XCAR (frames));
+ frames = XCDR (frames);
+ width = FRAME_PIXEL_WIDTH (f);
+ height = FRAME_PIXEL_HEIGHT (f);
+ if (surface_set_size_func)
+ (*surface_set_size_func) (surface, width, height);
+ unblock_input ();
+ }
+
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+ if (surface_type == CAIRO_SURFACE_TYPE_IMAGE)
+ {
+ block_input ();
+ cairo_surface_flush (surface);
+ cairo_surface_write_to_png_stream (surface, x_cr_accumulate_data, &acc);
+ unblock_input ();
+ }
+#endif
+ unbind_to (count, Qnil);
+
+ args[0] = intern ("concat");
+ args[1] = Fnreverse (acc);
+ return Fapply (2, args);
+}
+
+#endif /* USE_CAIRO */
+
+static void
+x_prepare_for_xlibdraw (f)
+ struct frame *f;
+{
+#ifdef USE_CAIRO
+ if (f == NULL)
+ {
+ Lisp_Object rest, frame;
+ FOR_EACH_FRAME (rest, frame)
+ if (FRAME_X_P (XFRAME (frame)))
+ x_prepare_for_xlibdraw (XFRAME (frame));
+ }
+ else
+ {
+ cairo_t *cr = FRAME_CR_CONTEXT (f);
+
+ if (cr)
+ {
+ cairo_surface_t *surface = cairo_get_target (cr);
+
+ if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB)
+ {
+ cairo_destroy (cr);
+ FRAME_CR_CONTEXT (f) = NULL;
+ }
+ }
+ }
+#endif
+}
+
+static void
+x_set_clip_rectangles (f, gc, rectangles, n)
+ struct frame *f;
+ GC gc;
+ XRectangle *rectangles;
+ int n;
+{
+ XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, rectangles, n, Unsorted);
+#ifdef USE_CAIRO
+ eassert (n >= 0 && n <= MAX_CLIP_RECTS);
+
+ {
+ struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 1);
+
+ gc_ext->n_clip_rects = n;
+ memcpy (gc_ext->clip_rects, rectangles, sizeof (XRectangle) * n);
+ }
+#endif
+}
+
+static void
+x_reset_clip_rectangles (f, gc)
+ struct frame *f;
+ GC gc;
+{
+ XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
+#ifdef USE_CAIRO
+ {
+ struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0);
+
+ if (gc_ext)
+ gc_ext->n_clip_rects = 0;
+ }
+#endif
+}
+
+static void
+x_fill_rectangle (f, gc, x, y, width, height)
+ struct frame *f;
+ GC gc;
+ int x, y;
+ unsigned int width, height;
+{
+#ifdef USE_CAIRO
+ cairo_t *cr;
+
+ cr = x_begin_cr_clip (f, gc);
+ x_set_cr_source_with_gc_foreground (f, gc);
+ cairo_rectangle (cr, x, y, width, height);
+ cairo_fill (cr);
+ x_end_cr_clip (f);
+#else
+ XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ gc, x, y, width, height);
+#endif
+}
+
+static void
+x_draw_rectangle (f, gc, x, y, width, height)
+ struct frame *f;
+ GC gc;
+ int x, y;
+ unsigned int width, height;
+{
+#ifdef USE_CAIRO
+ cairo_t *cr;
+
+ cr = x_begin_cr_clip (f, gc);
+ x_set_cr_source_with_gc_foreground (f, gc);
+ cairo_rectangle (cr, x + 0.5, y + 0.5, width, height);
+ cairo_set_line_width (cr, 1);
+ cairo_stroke (cr);
+ x_end_cr_clip (f);
+#else
+ XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ gc, x, y, width, height);
+#endif
+}
+
+static void
+x_clear_window (f)
+ struct frame *f;
+{
+#ifdef USE_CAIRO
+ cairo_t *cr;
+
+ cr = x_begin_cr_clip (f, NULL);
+ x_set_cr_source_with_gc_background (f, f->output_data.x->normal_gc);
+ cairo_paint (cr);
+ x_end_cr_clip (f);
+#else
+ XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
+#endif
+}
+
+#ifdef USE_CAIRO
+static void
+x_fill_trapezoid_for_relief (f, gc, x, y, width, height, top_p)
+ struct frame *f;
+ GC gc;
+ int x, y;
+ unsigned int width, height;
+ int top_p;
+{
+ cairo_t *cr;
+
+ cr = x_begin_cr_clip (f, gc);
+ x_set_cr_source_with_gc_foreground (f, gc);
+ cairo_move_to (cr, top_p ? x : x + height, y);
+ cairo_line_to (cr, x, y + height);
+ cairo_line_to (cr, top_p ? x + width - height : x + width, y + height);
+ cairo_line_to (cr, x + width, y);
+ cairo_close_path (cr);
+ cairo_fill (cr);
+ x_end_cr_clip (f);
+}
+#endif
/* Return the struct x_display_info corresponding to DPY. */
@@ -452,9 +1002,38 @@ x_set_frame_alpha (struct frame *f)
static void
x_update_begin (struct frame *f)
{
- /* Nothing to do. */
-}
+#ifdef USE_CAIRO
+ if (! FRAME_CR_SURFACE (f))
+ {
+ int width, height;
+#ifdef USE_GTK
+ if (FRAME_GTK_WIDGET (f))
+ {
+ GdkWindow *w = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
+ width = gdk_window_get_width (w);
+ height = gdk_window_get_height (w);
+ }
+ else
+#endif
+ {
+ width = FRAME_PIXEL_WIDTH (f);
+ height = FRAME_PIXEL_HEIGHT (f);
+ if (! FRAME_EXTERNAL_TOOL_BAR (f))
+ height += FRAME_TOOL_BAR_HEIGHT (f);
+ if (! FRAME_EXTERNAL_MENU_BAR (f))
+ height += FRAME_MENU_BAR_HEIGHT (f);
+ }
+ if (width > 0 && height > 0)
+ {
+ block_input();
+ FRAME_CR_SURFACE (f) = cairo_image_surface_create
+ (CAIRO_FORMAT_ARGB32, width, height);
+ unblock_input();
+ }
+ }
+#endif /* USE_CAIRO */
+}
/* Start update of window W. */
@@ -496,8 +1075,12 @@ x_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
XSetForeground (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
face->foreground);
+#ifdef USE_CAIRO
+ x_fill_rectangle (f, f->output_data.x->normal_gc, x, y0, 1, y1 - y0);
+#else
XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
f->output_data.x->normal_gc, x, y0, x, y1);
+#endif
}
/* Draw a window divider from (x0,y0) to (x1,y1) */
@@ -612,6 +1195,43 @@ x_update_end (struct frame *f)
/* Mouse highlight may be displayed again. */
MOUSE_HL_INFO (f)->mouse_face_defer = false;
+#ifdef USE_CAIRO
+ if (FRAME_CR_SURFACE (f))
+ {
+ cairo_t *cr = 0;
+ block_input();
+#if defined (USE_GTK) && defined (HAVE_GTK3)
+ if (FRAME_GTK_WIDGET (f))
+ {
+ GdkWindow *w = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
+ cr = gdk_cairo_create (w);
+ }
+ else
+#endif
+ {
+ cairo_surface_t *surface;
+ int width = FRAME_PIXEL_WIDTH (f);
+ int height = FRAME_PIXEL_HEIGHT (f);
+ if (! FRAME_EXTERNAL_TOOL_BAR (f))
+ height += FRAME_TOOL_BAR_HEIGHT (f);
+ if (! FRAME_EXTERNAL_MENU_BAR (f))
+ height += FRAME_MENU_BAR_HEIGHT (f);
+ surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f),
+ FRAME_X_WINDOW (f),
+ FRAME_DISPLAY_INFO (f)->visual,
+ width,
+ height);
+ cr = cairo_create (surface);
+ cairo_surface_destroy (surface);
+ }
+
+ cairo_set_source_surface (cr, FRAME_CR_SURFACE (f), 0, 0);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+ unblock_input ();
+ }
+#endif /* USE_CAIRO */
+
#ifndef XFlush
block_input ();
XFlush (FRAME_X_DISPLAY (f));
@@ -638,18 +1258,16 @@ x_clear_under_internal_border (struct frame *f)
{
if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0)
{
- Display *display = FRAME_X_DISPLAY (f);
- Window window = FRAME_X_WINDOW (f);
int border = FRAME_INTERNAL_BORDER_WIDTH (f);
int width = FRAME_PIXEL_WIDTH (f);
int height = FRAME_PIXEL_HEIGHT (f);
int margin = FRAME_TOP_MARGIN_HEIGHT (f);
block_input ();
- x_clear_area (display, window, 0, 0, border, height);
- x_clear_area (display, window, 0, margin, width, border);
- x_clear_area (display, window, width - border, 0, border, height);
- x_clear_area (display, window, 0, height - border, width, border);
+ x_clear_area (f, 0, 0, border, height);
+ x_clear_area (f, 0, margin, width, border);
+ x_clear_area (f, width - border, 0, border, height);
+ x_clear_area (f, 0, height - border, width, border);
unblock_input ();
}
}
@@ -691,11 +1309,8 @@ x_after_update_window_line (struct window *w, struct glyph_row *desired_row)
int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
block_input ();
- x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
- 0, y, width, height);
- x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
- FRAME_PIXEL_WIDTH (f) - width,
- y, width, height);
+ x_clear_area (f, 0, y, width, height);
+ x_clear_area (f, FRAME_PIXEL_WIDTH (f) - width, y, width, height);
unblock_input ();
}
}
@@ -725,13 +1340,29 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fring
else
XSetForeground (display, face->gc, face->background);
- XFillRectangle (display, window, face->gc,
- p->bx, p->by, p->nx, p->ny);
+ x_fill_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny);
if (!face->stipple)
XSetForeground (display, face->gc, face->foreground);
}
+#ifdef USE_CAIRO
+ if (p->which && p->which < max_fringe_bmp)
+ {
+ XGCValues gcv;
+
+ XGetGCValues (display, gc, GCForeground | GCBackground, &gcv);
+ XSetForeground (display, gc, (p->cursor_p
+ ? (p->overlay_p ? face->background
+ : f->output_data.x->cursor_pixel)
+ : face->foreground));
+ XSetBackground (display, gc, face->background);
+ x_cr_draw_image (f, gc, fringe_bmp[p->which], 0, p->dh,
+ p->wd, p->h, p->x, p->y, p->overlay_p);
+ XSetForeground (display, gc, gcv.foreground);
+ XSetBackground (display, gc, gcv.background);
+ }
+#else /* not USE_CAIRO */
if (p->which)
{
char *bits;
@@ -776,8 +1407,9 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fring
XFreePixmap (display, clipmask);
}
}
+#endif /* not USE_CAIRO */
- XSetClipMask (display, gc, None);
+ x_reset_clip_rectangles (f, gc);
}
/***********************************************************************
@@ -985,7 +1617,7 @@ x_set_glyph_string_clipping (struct glyph_string *s)
int n = get_glyph_string_clip_rects (s, r, 2);
if (n > 0)
- XSetClipRectangles (s->display, s->gc, 0, 0, r, n, Unsorted);
+ x_set_clip_rectangles (s->f, s->gc, r, n);
s->num_clips = n;
}
@@ -1005,7 +1637,7 @@ x_set_glyph_string_clipping_exactly (struct glyph_string *src, struct glyph_stri
r.height = src->height;
dst->clip[0] = r;
dst->num_clips = 1;
- XSetClipRectangles (dst->display, dst->gc, 0, 0, &r, 1, Unsorted);
+ x_set_clip_rectangles (dst->f, dst->gc, &r, 1);
}
@@ -1057,7 +1689,7 @@ x_clear_glyph_string_rect (struct glyph_string *s, int x, int y, int w, int h)
XGCValues xgcv;
XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
XSetForeground (s->display, s->gc, xgcv.background);
- XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
+ x_fill_rectangle (s->f, s->gc, x, y, w, h);
XSetForeground (s->display, s->gc, xgcv.foreground);
}
@@ -1081,7 +1713,7 @@ x_draw_glyph_string_background (struct glyph_string *s, bool force_p)
{
/* Fill background with a stipple pattern. */
XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
- XFillRectangle (s->display, s->window, s->gc, s->x,
+ x_fill_rectangle (s->f, s->gc, s->x,
s->y + box_line_width,
s->background_width,
s->height - 2 * box_line_width);
@@ -1124,7 +1756,7 @@ x_draw_glyph_string_foreground (struct glyph_string *s)
for (i = 0; i < s->nchars; ++i)
{
struct glyph *g = s->first_glyph + i;
- XDrawRectangle (s->display, s->window,
+ x_draw_rectangle (s->f,
s->gc, x, s->y, g->pixel_width - 1,
s->height - 1);
x += g->pixel_width;
@@ -1176,7 +1808,7 @@ x_draw_composite_glyph_string_foreground (struct glyph_string *s)
if (s->font_not_found_p)
{
if (s->cmp_from == 0)
- XDrawRectangle (s->display, s->window, s->gc, x, s->y,
+ x_draw_rectangle (s->f, s->gc, x, s->y,
s->width - 1, s->height - 1);
}
else if (! s->first_glyph->u.cmp.automatic)
@@ -1310,7 +1942,7 @@ x_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
false);
}
if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE)
- XDrawRectangle (s->display, s->window, s->gc,
+ x_draw_rectangle (s->f, s->gc,
x, s->ybase - glyph->ascent,
glyph->pixel_width - 1,
glyph->ascent + glyph->descent - 1);
@@ -1882,6 +2514,52 @@ x_draw_relief_rect (struct frame *f,
bool left_p, bool right_p,
XRectangle *clip_rect)
{
+#ifdef USE_CAIRO
+ GC top_left_gc, bottom_right_gc;
+
+ if (raised_p)
+ {
+ top_left_gc = f->output_data.x->white_relief.gc;
+ bottom_right_gc = f->output_data.x->black_relief.gc;
+ }
+ else
+ {
+ top_left_gc = f->output_data.x->black_relief.gc;
+ bottom_right_gc = f->output_data.x->white_relief.gc;
+ }
+
+ x_set_clip_rectangles (f, top_left_gc, clip_rect, 1);
+ x_set_clip_rectangles (f, bottom_right_gc, clip_rect, 1);
+
+ if (left_p)
+ x_fill_rectangle (f, top_left_gc, left_x, top_y,
+ width, bottom_y + 1 - top_y);
+ if (right_p)
+ x_fill_rectangle (f, bottom_right_gc, right_x + 1 - width, top_y,
+ width, bottom_y + 1 - top_y);
+ if (top_p)
+ {
+ if (!right_p)
+ x_fill_rectangle (f, top_left_gc, left_x, top_y,
+ right_x + 1 - left_x, width);
+ else
+ x_fill_trapezoid_for_relief (f, top_left_gc, left_x, top_y,
+ right_x + 1 - left_x, width, 1);
+ }
+ if (bot_p)
+ {
+ if (!left_p)
+ x_fill_rectangle (f, bottom_right_gc, left_x, bottom_y + 1 - width,
+ right_x + 1 - left_x, width);
+ else
+ x_fill_trapezoid_for_relief (f, bottom_right_gc,
+ left_x, bottom_y + 1 - width,
+ right_x + 1 - left_x, width, 0);
+ }
+
+ x_set_clip_rectangles (f, top_left_gc, clip_rect, 1);
+ x_set_clip_rectangles (f, bottom_right_gc, clip_rect, 1);
+#else
Display *dpy = FRAME_X_DISPLAY (f);
Window window = FRAME_X_WINDOW (f);
int i;
@@ -1970,7 +2648,9 @@ x_draw_relief_rect (struct frame *f,
right_x - i, bottom_y + 1 - (i + 1) * bot_p);
}
- XSetClipMask (dpy, gc, None);
+ x_reset_clip_rectangles (f, gc);
+
+#endif
}
@@ -1990,28 +2670,28 @@ x_draw_box_rect (struct glyph_string *s,
XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
XSetForeground (s->display, s->gc, s->face->box_color);
- XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
+ x_set_clip_rectangles (s->f, s->gc, clip_rect, 1);
/* Top. */
- XFillRectangle (s->display, s->window, s->gc,
+ x_fill_rectangle (s->f, s->gc,
left_x, top_y, right_x - left_x + 1, width);
/* Left. */
if (left_p)
- XFillRectangle (s->display, s->window, s->gc,
+ x_fill_rectangle (s->f, s->gc,
left_x, top_y, width, bottom_y - top_y + 1);
/* Bottom. */
- XFillRectangle (s->display, s->window, s->gc,
+ x_fill_rectangle (s->f, s->gc,
left_x, bottom_y - width + 1, right_x - left_x + 1, width);
/* Right. */
if (right_p)
- XFillRectangle (s->display, s->window, s->gc,
+ x_fill_rectangle (s->f, s->gc,
right_x - width + 1, top_y, width, bottom_y - top_y + 1);
XSetForeground (s->display, s->gc, xgcv.foreground);
- XSetClipMask (s->display, s->gc, None);
+ x_reset_clip_rectangles (s->f, s->gc);
}
@@ -2142,7 +2822,7 @@ x_draw_image_foreground (struct glyph_string *s)
if (s->hl == DRAW_CURSOR)
{
int relief = eabs (s->img->relief);
- XDrawRectangle (s->display, s->window, s->gc,
+ x_draw_rectangle (s->f, s->gc,
x - relief, y - relief,
s->slice.width + relief*2 - 1,
s->slice.height + relief*2 - 1);
@@ -2151,7 +2831,7 @@ x_draw_image_foreground (struct glyph_string *s)
}
else
/* Draw a rectangle if image could not be loaded. */
- XDrawRectangle (s->display, s->window, s->gc, x, y,
+ x_draw_rectangle (s->f, s->gc, x, y,
s->slice.width - 1, s->slice.height - 1);
}
@@ -2290,7 +2970,7 @@ x_draw_image_foreground_1 (struct glyph_string *s, Pixmap pixmap)
if (s->hl == DRAW_CURSOR)
{
int r = eabs (s->img->relief);
- XDrawRectangle (s->display, s->window, s->gc, x - r, y - r,
+ x_draw_rectangle (s->f, s->gc, x - r, y - r,
s->slice.width + r*2 - 1,
s->slice.height + r*2 - 1);
}
@@ -2298,7 +2978,7 @@ x_draw_image_foreground_1 (struct glyph_string *s, Pixmap pixmap)
}
else
/* Draw a rectangle if image could not be loaded. */
- XDrawRectangle (s->display, pixmap, s->gc, x, y,
+ x_draw_rectangle (s->f, s->gc, x, y,
s->slice.width - 1, s->slice.height - 1);
}
@@ -2313,7 +2993,7 @@ x_draw_glyph_string_bg_rect (struct glyph_string *s, int x, int y, int w, int h)
{
/* Fill background with a stipple pattern. */
XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
- XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
+ x_fill_rectangle (s->f, s->gc, x, y, w, h);
XSetFillStyle (s->display, s->gc, FillSolid);
}
else
@@ -2422,7 +3102,22 @@ x_draw_image_glyph_string (struct glyph_string *s)
}
/* Draw the foreground. */
- if (pixmap != None)
+ if (s->img->cr_data)
+ {
+ cairo_t *cr = x_begin_cr_clip (s->f, s->gc);
+
+ int x = s->x + s->img->hmargin;
+ int y = s->y + s->img->vmargin;
+ int width = s->background_width;
+
+ cairo_set_source_surface (cr, s->img->cr_data,
+ x - s->slice.x,
+ y - s->slice.y);
+ cairo_rectangle (cr, x, y, width, height);
+ cairo_fill (cr);
+ x_end_cr_clip (s->f);
+ }
+ else if (pixmap != None)
{
x_draw_image_foreground_1 (s, pixmap);
x_set_glyph_string_clipping (s);
@@ -2505,13 +3200,13 @@ x_draw_stretch_glyph_string (struct glyph_string *s)
gc = s->face->gc;
get_glyph_string_clip_rect (s, &r);
- XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
+ x_set_clip_rectangles (s->f, gc, &r, 1);
if (s->face->stipple)
{
/* Fill background with a stipple pattern. */
XSetFillStyle (s->display, gc, FillOpaqueStippled);
- XFillRectangle (s->display, s->window, gc, x, y, w, h);
+ x_fill_rectangle (s->f, gc, x, y, w, h);
XSetFillStyle (s->display, gc, FillSolid);
}
else
@@ -2519,7 +3214,7 @@ x_draw_stretch_glyph_string (struct glyph_string *s)
XGCValues xgcv;
XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
XSetForeground (s->display, gc, xgcv.background);
- XFillRectangle (s->display, s->window, gc, x, y, w, h);
+ x_fill_rectangle (s->f, gc, x, y, w, h);
XSetForeground (s->display, gc, xgcv.foreground);
}
@@ -2778,14 +3473,14 @@ x_draw_glyph_string (struct glyph_string *s)
s->underline_position = position;
y = s->ybase + position;
if (s->face->underline_defaulted_p)
- XFillRectangle (s->display, s->window, s->gc,
+ x_fill_rectangle (s->f, s->gc,
s->x, y, s->width, thickness);
else
{
XGCValues xgcv;
XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
XSetForeground (s->display, s->gc, s->face->underline_color);
- XFillRectangle (s->display, s->window, s->gc,
+ x_fill_rectangle (s->f, s->gc,
s->x, y, s->width, thickness);
XSetForeground (s->display, s->gc, xgcv.foreground);
}
@@ -2797,14 +3492,14 @@ x_draw_glyph_string (struct glyph_string *s)
unsigned long dy = 0, h = 1;
if (s->face->overline_color_defaulted_p)
- XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
+ x_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
s->width, h);
else
{
XGCValues xgcv;
XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
XSetForeground (s->display, s->gc, s->face->overline_color);
- XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
+ x_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
s->width, h);
XSetForeground (s->display, s->gc, xgcv.foreground);
}
@@ -2817,14 +3512,14 @@ x_draw_glyph_string (struct glyph_string *s)
unsigned long dy = (s->height - h) / 2;
if (s->face->strike_through_color_defaulted_p)
- XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
+ x_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
s->width, h);
else
{
XGCValues xgcv;
XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
XSetForeground (s->display, s->gc, s->face->strike_through_color);
- XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
+ x_fill_rectangle (s->f, s->gc, s->x, s->y + dy,
s->width, h);
XSetForeground (s->display, s->gc, xgcv.foreground);
}
@@ -2853,7 +3548,7 @@ x_draw_glyph_string (struct glyph_string *s)
x_draw_glyph_string_foreground (prev);
else
x_draw_composite_glyph_string_foreground (prev);
- XSetClipMask (prev->display, prev->gc, None);
+ x_reset_clip_rectangles (prev->f, prev->gc);
prev->hl = save;
prev->num_clips = 0;
}
@@ -2878,7 +3573,7 @@ x_draw_glyph_string (struct glyph_string *s)
x_draw_glyph_string_foreground (next);
else
x_draw_composite_glyph_string_foreground (next);
- XSetClipMask (next->display, next->gc, None);
+ x_reset_clip_rectangles (next->f, next->gc);
next->hl = save;
next->num_clips = 0;
next->clip_head = s->next;
@@ -2887,7 +3582,7 @@ x_draw_glyph_string (struct glyph_string *s)
}
/* Reset clipping. */
- XSetClipMask (s->display, s->gc, None);
+ x_reset_clip_rectangles (s->f, s->gc);
s->num_clips = 0;
}
@@ -2896,6 +3591,7 @@ x_draw_glyph_string (struct glyph_string *s)
static void
x_shift_glyphs_for_insert (struct frame *f, int x, int y, int width, int height, int shift_by)
{
+ x_prepare_for_xlibdraw (f);
XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
f->output_data.x->normal_gc,
x, y, width, height,
@@ -2915,11 +3611,35 @@ x_delete_glyphs (struct frame *f, register int n)
/* Like XClearArea, but check that WIDTH and HEIGHT are reasonable.
If they are <= 0, this is probably an error. */
+static void
+x_clear_area1 (Display *dpy, Window window,
+ int x, int y, int width, int height, int exposures)
+{
+ eassert (width > 0 && height > 0);
+ XClearArea (dpy, window, x, y, width, height, exposures);
+}
+
+
void
-x_clear_area (Display *dpy, Window window, int x, int y, int width, int height)
+x_clear_area (f, x, y, width, height)
+ struct frame *f;
+ int x, y;
+ int width, height;
{
+#ifdef USE_CAIRO
+ cairo_t *cr;
+
eassert (width > 0 && height > 0);
- XClearArea (dpy, window, x, y, width, height, False);
+
+ cr = x_begin_cr_clip (f, NULL);
+ x_set_cr_source_with_gc_background (f, f->output_data.x->normal_gc);
+ cairo_rectangle (cr, x, y, width, height);
+ cairo_fill (cr);
+ x_end_cr_clip (f);
+#else
+ x_clear_area1 (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ x, y, width, height, False);
+#endif
}
@@ -2934,7 +3654,7 @@ x_clear_frame (struct frame *f)
block_input ();
- XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
+ x_clear_window (f);
/* We have to clear the scroll bars. If we have changed colors or
something like that, then they should be notified. */
@@ -3240,12 +3960,16 @@ x_scroll_run (struct window *w, struct run *run)
/* Cursor off. Will be switched on again in x_update_window_end. */
x_clear_cursor (w);
+#ifdef USE_CAIRO
+ SET_FRAME_GARBAGED (f);
+#else
XCopyArea (FRAME_X_DISPLAY (f),
FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
f->output_data.x->normal_gc,
x, from_y,
width, height,
x, to_y);
+#endif
unblock_input ();
}
@@ -4154,7 +4878,7 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
dpyinfo->last_mouse_glyph_frame = f1;
*bar_window = Qnil;
- *part = scroll_bar_above_handle;
+ *part = 0;
*fp = f1;
XSETINT (*x, win_x);
XSETINT (*y, win_y);
@@ -4248,7 +4972,7 @@ x_window_to_menu_bar (Window window)
#ifdef USE_TOOLKIT_SCROLL_BARS
static void x_send_scroll_bar_event (Lisp_Object, enum scroll_bar_part,
- int, int, bool);
+ int, int, bool);
/* Lisp window being scrolled. Set when starting to interact with
a toolkit scroll bar, reset to nil when ending the interaction. */
@@ -5505,8 +6229,7 @@ x_scroll_bar_create (struct window *w, int top, int left,
for the case that a window has been split horizontally. In
this case, no clear_frame is generated to reduce flickering. */
if (width > 0 && window_box_height (w) > 0)
- x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
- left, top, width, window_box_height (w));
+ x_clear_area (f, left, top, width, window_box_height (w));
window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
/* Position and size of scroll bar. */
@@ -5638,7 +6361,7 @@ x_scroll_bar_set_handle (struct scroll_bar *bar, int start, int end,
/* Draw the empty space above the handle. Note that we can't clear
zero-height areas; that means "clear to end of window." */
if ((inside_width > 0) && (start > 0))
- x_clear_area (FRAME_X_DISPLAY (f), w,
+ x_clear_area1 (FRAME_X_DISPLAY (f), w,
VERTICAL_SCROLL_BAR_LEFT_BORDER,
VERTICAL_SCROLL_BAR_TOP_BORDER,
inside_width, start);
@@ -5649,7 +6372,7 @@ x_scroll_bar_set_handle (struct scroll_bar *bar, int start, int end,
f->output_data.x->scroll_bar_foreground_pixel);
/* Draw the handle itself. */
- XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
+ x_fill_rectangle (f, gc,
/* x, y, width, height */
VERTICAL_SCROLL_BAR_LEFT_BORDER,
VERTICAL_SCROLL_BAR_TOP_BORDER + start,
@@ -5663,7 +6386,7 @@ x_scroll_bar_set_handle (struct scroll_bar *bar, int start, int end,
/* Draw the empty space below the handle. Note that we can't
clear zero-height areas; that means "clear to end of window." */
if ((inside_width > 0) && (end < inside_height))
- x_clear_area (FRAME_X_DISPLAY (f), w,
+ x_clear_area1 (FRAME_X_DISPLAY (f), w,
VERTICAL_SCROLL_BAR_LEFT_BORDER,
VERTICAL_SCROLL_BAR_TOP_BORDER + end,
inside_width, inside_height - end);
@@ -5730,8 +6453,7 @@ XTset_vertical_scroll_bar (struct window *w, int portion, int whole, int positio
if (width > 0 && height > 0)
{
block_input ();
- x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
- left, top, width, height);
+ x_clear_area (f, left, top, width, height);
unblock_input ();
}
@@ -5763,8 +6485,7 @@ XTset_vertical_scroll_bar (struct window *w, int portion, int whole, int positio
/* Since toolkit scroll bars are smaller than the space reserved
for them on the frame, we have to clear "under" them. */
if (width > 0 && height > 0)
- x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
- left, top, width, height);
+ x_clear_area (f, left, top, width, height);
#ifdef USE_GTK
xg_update_scrollbar_pos (f, bar->x_window, top,
left, width, max (height, 1));
@@ -5850,8 +6571,7 @@ XTset_horizontal_scroll_bar (struct window *w, int portion, int whole, int posit
/* Clear also part between window_width and
WINDOW_PIXEL_WIDTH. */
- x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
- left, top, pixel_width, height);
+ x_clear_area (f, left, top, pixel_width, height);
unblock_input ();
}
@@ -5882,7 +6602,7 @@ XTset_horizontal_scroll_bar (struct window *w, int portion, int whole, int posit
/* Since toolkit scroll bars are smaller than the space reserved
for them on the frame, we have to clear "under" them. */
if (width > 0 && height > 0)
- x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ x_clear_area (f,
WINDOW_LEFT_EDGE_X (w), top,
pixel_width - WINDOW_RIGHT_DIVIDER_WIDTH (w), height);
#ifdef USE_GTK
@@ -6128,7 +6848,7 @@ x_scroll_bar_expose (struct scroll_bar *bar, const XEvent *event)
f->output_data.x->scroll_bar_foreground_pixel);
/* Draw a one-pixel border just inside the edges of the scroll bar. */
- XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
+ x_draw_rectangle (f, gc,
/* x, y, width, height */
0, 0, bar->width - 1, bar->height - 1);
@@ -6912,11 +7632,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
}
else
{
-#ifdef USE_GTK
+#if defined (USE_GTK) && ! defined (HAVE_GTK3) && ! defined (USE_CAIRO)
/* This seems to be needed for GTK 2.6 and later, see
http://debbugs.gnu.org/cgi/bugreport.cgi?bug=15398. */
- x_clear_area (event->xexpose.display,
- event->xexpose.window,
+ x_clear_area (f,
event->xexpose.x, event->xexpose.y,
event->xexpose.width, event->xexpose.height);
#endif
@@ -7530,6 +8249,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
case ConfigureNotify:
f = x_top_window_to_frame (dpyinfo, event->xconfigure.window);
+#ifdef USE_CAIRO
+ if (f) x_cr_destroy_surface (f);
+#endif
#ifdef USE_GTK
if (!f
&& (f = any)
@@ -7537,6 +8259,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
{
xg_frame_resized (f, event->xconfigure.width,
event->xconfigure.height);
+ x_cr_destroy_surface (f);
f = 0;
}
#endif
@@ -7946,7 +8669,7 @@ x_clip_to_row (struct window *w, struct glyph_row *row,
clip_rect.width = window_width;
clip_rect.height = row->visible_height;
- XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
+ x_set_clip_rectangles (f, gc, &clip_rect, 1);
}
@@ -7995,8 +8718,8 @@ x_draw_hollow_cursor (struct window *w, struct glyph_row *row)
}
/* Set clipping, draw the rectangle, and reset clipping again. */
x_clip_to_row (w, row, TEXT_AREA, gc);
- XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h - 1);
- XSetClipMask (dpy, gc, None);
+ x_draw_rectangle (f, gc, x, y, wd, h - 1);
+ x_reset_clip_rectangles (f, gc);
}
@@ -8074,7 +8797,7 @@ x_draw_bar_cursor (struct window *w, struct glyph_row *row, int width, enum text
if ((cursor_glyph->resolved_level & 1) != 0)
x += cursor_glyph->pixel_width - width;
- XFillRectangle (dpy, window, gc, x,
+ x_fill_rectangle (f, gc, x,
WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
width, row->height);
}
@@ -8094,13 +8817,13 @@ x_draw_bar_cursor (struct window *w, struct glyph_row *row, int width, enum text
if ((cursor_glyph->resolved_level & 1) != 0
&& cursor_glyph->pixel_width > w->phys_cursor_width - 1)
x += cursor_glyph->pixel_width - w->phys_cursor_width + 1;
- XFillRectangle (dpy, window, gc, x,
- WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
- row->height - width),
- w->phys_cursor_width - 1, width);
+ x_fill_rectangle (f, gc, x,
+ WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
+ row->height - width),
+ w->phys_cursor_width - 1, width);
}
- XSetClipMask (dpy, gc, None);
+ x_reset_clip_rectangles (f, gc);
}
}
@@ -8122,7 +8845,7 @@ x_define_frame_cursor (struct frame *f, Cursor cursor)
static void
x_clear_frame_area (struct frame *f, int x, int y, int width, int height)
{
- x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), x, y, width, height);
+ x_clear_area (f, x, y, width, height);
#ifdef USE_GTK
/* Must queue a redraw, because scroll bars might have been cleared. */
if (FRAME_GTK_WIDGET (f))
@@ -10235,6 +10958,7 @@ x_free_frame_resources (struct frame *f)
free_frame_xic (f);
#endif
+ x_prepare_for_xlibdraw (f);
#ifdef USE_X_TOOLKIT
if (f->output_data.x->widget)
{
@@ -11312,6 +12036,10 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
x_session_initialize (dpyinfo);
#endif
+#ifdef USE_CAIRO
+ x_extension_initialize (dpyinfo);
+#endif
+
unblock_input ();
return dpyinfo;
@@ -11423,8 +12151,13 @@ static struct redisplay_interface x_redisplay_interface =
x_get_glyph_overhangs,
x_fix_overlapping_area,
x_draw_fringe_bitmap,
+#ifdef USE_CAIRO
+ x_cr_define_fringe_bitmap,
+ x_cr_destroy_fringe_bitmap,
+#else
0, /* define_fringe_bitmap */
0, /* destroy_fringe_bitmap */
+#endif
x_compute_glyph_string_overhangs,
x_draw_glyph_string,
x_define_frame_cursor,
@@ -11602,6 +12335,10 @@ x_initialize (void)
#endif
#endif
+#ifdef USE_CAIRO
+ x_cr_init_fringe (&x_redisplay_interface);
+#endif
+
/* Note that there is no real way portable across R3/R4 to get the
original error handler. */
XSetErrorHandler (x_error_handler);
diff --git a/src/xterm.h b/src/xterm.h
index e597227c81..eb8eaae5de 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -70,6 +70,19 @@ typedef GtkWidget *xt_or_gtk_widget;
#define USE_GTK_TOOLTIP
#endif
+#ifdef USE_CAIRO
+#include <cairo-xlib.h>
+#ifdef CAIRO_HAS_PDF_SURFACE
+#include <cairo-pdf.h>
+#endif
+#ifdef CAIRO_HAS_PS_SURFACE
+#include <cairo-ps.h>
+#endif
+#ifdef CAIRO_HAS_SVG_SURFACE
+#include <cairo-svg.h>
+#endif
+#endif
+
#ifdef HAVE_X_I18N
#include <X11/Xlocale.h>
#endif
@@ -115,6 +128,9 @@ struct xim_inst_t
struct x_bitmap_record
{
+#ifdef USE_CAIRO
+ void *img;
+#endif
Pixmap pixmap;
bool have_mask;
Pixmap mask;
@@ -124,6 +140,19 @@ struct x_bitmap_record
int height, width, depth;
};
+#ifdef USE_CAIRO
+struct x_gc_ext_data
+{
+#define MAX_CLIP_RECTS 2
+ /* Number of clipping rectangles. */
+ int n_clip_rects;
+
+ /* Clipping rectangles. */
+ XRectangle clip_rects[MAX_CLIP_RECTS];
+};
+#endif
+
+
/* For each X display, we have a structure that records
information about it. */
@@ -411,6 +440,10 @@ struct x_display_info
/* SM */
Atom Xatom_SM_CLIENT_ID;
+
+#ifdef USE_CAIRO
+ XExtCodes *ext_codes;
+#endif
};
#ifdef HAVE_X_I18N
@@ -645,7 +678,6 @@ struct x_output
/* The offset we need to add to compensate for type A WMs. */
int move_offset_top;
int move_offset_left;
-};
/* Extreme 'short' and 'long' values suitable for libX11. */
#define X_SHRT_MAX 0x7fff
@@ -654,6 +686,14 @@ struct x_output
#define X_LONG_MIN (-1 - X_LONG_MAX)
#define X_ULONG_MAX 0xffffffffUL
+#ifdef USE_CAIRO
+ /* Cairo drawing context. */
+ cairo_t *cr_context;
+ /* Cairo surface for double buffering */
+ cairo_surface_t *cr_surface;
+#endif
+};
+
#define No_Cursor (None)
enum
@@ -1000,7 +1040,8 @@ extern bool x_alloc_lighter_color_for_widget (Widget, Display *, Colormap,
double, int);
#endif
extern bool x_alloc_nearest_color (struct frame *, Colormap, XColor *);
-extern void x_clear_area (Display *, Window, int, int, int, int);
+extern void x_query_color (struct frame *f, XColor *);
+extern void x_clear_area (struct frame *f, int, int, int, int);
#if !defined USE_X_TOOLKIT && !defined USE_GTK
extern void x_mouse_leave (struct x_display_info *);
#endif
@@ -1009,6 +1050,14 @@ extern void x_mouse_leave (struct x_display_info *);
extern int x_dispatch_event (XEvent *, Display *);
#endif
extern int x_x_to_emacs_modifiers (struct x_display_info *, int);
+#ifdef USE_CAIRO
+extern cairo_t *x_begin_cr_clip (struct frame *, GC);
+extern void x_end_cr_clip (struct frame *);
+extern void x_set_cr_source_with_gc_foreground (struct frame *, GC);
+extern void x_set_cr_source_with_gc_background (struct frame *, GC);
+extern void x_cr_draw_frame (cairo_t *, struct frame *);
+extern Lisp_Object x_cr_export_frames (Lisp_Object, cairo_surface_type_t);
+#endif
INLINE int
x_display_pixel_height (struct x_display_info *dpyinfo)