diff --git a/configure.ac b/configure.ac index 29297423f..2a116bfd6 100644 --- a/configure.ac +++ b/configure.ac @@ -117,6 +117,26 @@ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", AC_CANONICAL_HOST +gdk_pixelops_i386=no + +case "$host_cpu" in + i?86) + gdk_pixelops_i386=yes + AC_DEFINE([HAVE_GDK_PIXELOPS_INIT], [1], + [Define if GDK pixel operations require runtime dispatch initialization]) + ;; + x86_64) + AC_DEFINE([GDK_PIXELOPS_X86_64], [1], + [Define if x86-64 SSE2 pixel operations are available]) + ;; +esac + +AM_CONDITIONAL(GDK_PIXELOPS_I386, + test "$gdk_pixelops_i386" = yes) +AM_CONDITIONAL(GDK_PIXELOPS_X86_64, + test "$host_cpu" = x86_64) + + MATH_LIB=-lm AC_MSG_CHECKING([for native Win32]) LIB_EXE_MACHINE_FLAG=X86 @@ -399,6 +419,11 @@ PKG_CHECK_MODULES(BASE_DEPENDENCIES, gdk-pixbuf-2.0 >= gdk_pixbuf_required_version dnl fribidi >= fribidi_required_version]) +PKG_CHECK_EXISTS([atk >= 2.12], + [AC_DEFINE([HAVE_ATK_VALUE_2_12], [1], + [Define if ATK provides the 2.12 AtkValue interface])]) + + ## In addition to checking that cairo is present, we also need to ## check that the correct cairo backend is there. E.g. if the GDK ## target is win32 we need the cairo-win32 backend and so on. @@ -469,7 +494,7 @@ if test "x$enable_rebuilds" = "xyes" && \ fi AC_SUBST(REBUILD) -AC_CHECK_FUNCS(lstat mkstemp flockfile getc_unlocked) +AC_CHECK_FUNCS(lstat mkstemp flockfile getc_unlocked _getc_nolock) AC_CHECK_FUNCS(localtime_r) # _NL_TIME_FIRST_WEEKDAY is an enum and not a define @@ -1594,6 +1619,7 @@ else gtk_save_libs="$LIBS" LIBS="$CUPS_LIBS" AC_CHECK_FUNCS(httpGetAuthString) + AC_CHECK_FUNCS(httpConnect2 httpReconnect2) LIBS="$gtk_save_libs" fi fi diff --git a/docs/reference/gdk/Makefile.am b/docs/reference/gdk/Makefile.am index c0facc151..43a67508c 100644 --- a/docs/reference/gdk/Makefile.am +++ b/docs/reference/gdk/Makefile.am @@ -37,7 +37,7 @@ IGNORE_HFILES= \ # Extra files to add when scanning (relative to $srcdir) EXTRA_HFILES= \ - ../../../gdk/x11/gdkx.h + $(top_srcdir)/gdk/x11/gdkx.h # CFLAGS and LDFLAGS for compiling scan program. Only needed # if $(DOC_MODULE).types is non-empty. diff --git a/docs/reference/gdk/gdk2-sections.txt b/docs/reference/gdk/gdk2-sections.txt index c3d6040b7..4987c31ee 100644 --- a/docs/reference/gdk/gdk2-sections.txt +++ b/docs/reference/gdk/gdk2-sections.txt @@ -335,6 +335,10 @@ gdk_draw_indexed_image gdk_draw_gray_image gdk_draw_rgb_32_image gdk_draw_rgb_32_image_dithalign +gdk_draw_rgb_48_image +gdk_draw_rgb_48_image_dithalign +gdk_draw_rgbx_64_image +gdk_draw_rgbx_64_image_dithalign GdkRgbDither diff --git a/gdk/Makefile.am b/gdk/Makefile.am index 1b186afa1..216437b65 100644 --- a/gdk/Makefile.am +++ b/gdk/Makefile.am @@ -14,6 +14,8 @@ DIST_SUBDIRS = win32 x11 quartz directfb tests CLEANFILES = +noinst_LTLIBRARIES = + EXTRA_DIST += \ keynames.txt \ keyname-table.h \ @@ -115,9 +117,60 @@ gdk_built_private_headers = \ gdk_private_headers = \ gdkinternals.h \ gdkintl.h \ + gdkpixelops.h \ gdkpoly-generic.h \ gdkregion-generic.h +gdk_pixelops_arch_sources = +gdk_pixelops_arch_libs = + +if GDK_PIXELOPS_I386 +gdk_pixelops_arch_sources += gdkpixelops-x86.c + +noinst_LTLIBRARIES += libgdk-pixelops-x86-mmx.la +gdk_pixelops_arch_libs += libgdk-pixelops-x86-mmx.la + +libgdk_pixelops_x86_mmx_la_SOURCES = gdkpixelops-x86-mmx.c +libgdk_pixelops_x86_mmx_la_CFLAGS = \ + $(AM_CFLAGS) \ + -mmmx -mno-sse -mno-sse2 -mno-3dnow + +noinst_LTLIBRARIES += libgdk-pixelops-x86-sse.la +gdk_pixelops_arch_libs += libgdk-pixelops-x86-sse.la + +libgdk_pixelops_x86_sse_la_SOURCES = gdkpixelops-x86-mmx.c +libgdk_pixelops_x86_sse_la_CFLAGS = \ + $(AM_CFLAGS) \ + -mmmx -mno-sse -mno-sse2 -mno-3dnow \ + -DGDK_PIXELOPS_X86_SSE_IMPL + +noinst_LTLIBRARIES += libgdk-pixelops-x86-sse2.la +gdk_pixelops_arch_libs += libgdk-pixelops-x86-sse2.la + +libgdk_pixelops_x86_sse2_la_SOURCES = gdkpixelops-x86-sse2.c +libgdk_pixelops_x86_sse2_la_CFLAGS = \ + $(AM_CFLAGS) \ + -march=i686 -msse2 -mno-sse3 -mno-ssse3 \ + -mno-sse4 -mno-avx -mno-3dnow -mtune=pentium4 + +noinst_LTLIBRARIES += libgdk-pixelops-x86-3dnow.la +gdk_pixelops_arch_libs += libgdk-pixelops-x86-3dnow.la + +libgdk_pixelops_x86_3dnow_la_SOURCES = gdkpixelops-x86-mmx.c +libgdk_pixelops_x86_3dnow_la_CFLAGS = \ + $(AM_CFLAGS) \ + -mmmx -m3dnow -mno-sse -mno-sse2 \ + -DGDK_PIXELOPS_X86_3DNOW_IMPL +endif + +if GDK_PIXELOPS_X86_64 +gdk_pixelops_arch_sources += gdkpixelops-x86-sse2.c +endif + +gdk_pixelops_private_sources = \ + gdkpixelops-generic.c \ + $(gdk_pixelops_arch_sources) + gdk_c_sources = \ $(medialib_sources) \ gdk.c \ @@ -129,6 +182,8 @@ gdk_c_sources = \ gdkdisplaymanager.c \ gdkdnd.c \ gdkdraw.c \ + gdkpixelops.c \ + $(gdk_pixelops_private_sources) \ gdkevents.c \ gdkfont.c \ gdkgc.c \ @@ -174,19 +229,19 @@ common_sources = \ gdkmarshalers.h libgdk_directfb_2_0_la_SOURCES = $(common_sources) -libgdk_directfb_2_0_la_LIBADD = directfb/libgdk-directfb.la $(GDK_DEP_LIBS) +libgdk_directfb_2_0_la_LIBADD = directfb/libgdk-directfb.la $(gdk_pixelops_arch_libs) $(GDK_DEP_LIBS) libgdk_directfb_2_0_la_LDFLAGS = $(LDADD) libgdk_x11_2_0_la_SOURCES = $(common_sources) -libgdk_x11_2_0_la_LIBADD = x11/libgdk-x11.la $(GDK_DEP_LIBS) +libgdk_x11_2_0_la_LIBADD = x11/libgdk-x11.la $(gdk_pixelops_arch_libs) $(GDK_DEP_LIBS) libgdk_x11_2_0_la_LDFLAGS = $(LDADD) libgdk_quartz_2_0_la_SOURCES = $(common_sources) gdkkeynames.c -libgdk_quartz_2_0_la_LIBADD = quartz/libgdk-quartz.la $(GDK_DEP_LIBS) +libgdk_quartz_2_0_la_LIBADD = quartz/libgdk-quartz.la $(gdk_pixelops_arch_libs) $(GDK_DEP_LIBS) libgdk_quartz_2_0_la_LDFLAGS = $(LDADD) libgdk_win32_2_0_la_SOURCES = $(common_sources) gdkkeynames.c -libgdk_win32_2_0_la_LIBADD = win32/libgdk-win32.la $(GDK_DEP_LIBS) +libgdk_win32_2_0_la_LIBADD = win32/libgdk-win32.la $(gdk_pixelops_arch_libs) $(GDK_DEP_LIBS) libgdk_win32_2_0_la_DEPENDENCIES = win32/libgdk-win32.la win32/rc/gdk-win32-res.o gdk.def libgdk_win32_2_0_la_LDFLAGS = -Wl,win32/rc/gdk-win32-res.o -export-symbols $(srcdir)/gdk.def $(LDADD) @@ -194,7 +249,7 @@ if HAVE_INTROSPECTION base_introspection_files = \ $(filter-out gdkkeysyms-compat.h, $(gdk_public_h_sources)) \ - $(gdk_c_sources) \ + $(filter-out $(gdk_pixelops_private_sources), $(gdk_c_sources)) \ gdkkeynames.c \ gdkenumtypes.c \ gdkenumtypes.h @@ -213,6 +268,11 @@ Gdk_2_0_gir_CFLAGS = \ -I$(top_builddir) \ -I$(top_builddir)/gdk \ $(INCLUDES) + +if OS_WIN32 +Gdk_2_0_gir_CFLAGS += -I$(srcdir)/win32 -I$(srcdir) +endif + INTROSPECTION_GIRS += Gdk-2.0.gir if USE_X11 @@ -268,6 +328,69 @@ introspection_files += $(filter-out x11/gdkx.h, $(x11_introspection_files)) endif # USE_X11 +if OS_WIN32 +win32_introspection_files = \ + win32/gdkapplaunchcontext-win32.c \ + win32/gdkcolor-win32.c \ + win32/gdkcursor-win32.c \ + win32/gdkdisplay-win32.c \ + win32/gdkdnd-win32.c \ + win32/gdkdrawable-win32.c \ + win32/gdkdrawable-win32.h \ + win32/gdkevents-win32.c \ + win32/gdkfont-win32.c \ + win32/gdkgc-win32.c \ + win32/gdkgeometry-win32.c \ + win32/gdkglobals-win32.c \ + win32/gdkimage-win32.c \ + win32/gdkim-win32.c \ + win32/gdkinput.c \ + win32/gdkinput-win32.c \ + win32/gdkinput-win32.h \ + win32/gdkkeys-win32.c \ + win32/gdkmain-win32.c \ + win32/gdkpixmap-win32.c \ + win32/gdkpixmap-win32.h \ + win32/gdkprivate-win32.h \ + win32/gdkproperty-win32.c \ + win32/gdkscreen-win32.c \ + win32/gdkselection-win32.c \ + win32/gdkspawn-win32.c \ + win32/gdktestutils-win32.c \ + win32/gdkvisual-win32.c \ + win32/gdkwin32.h \ + win32/gdkwin32id.c \ + win32/gdkwin32keys.h \ + win32/gdkwindow-win32.c \ + win32/gdkwindow-win32.h + +GdkWin32-2.0.gir: $(gdktargetlib) Gdk-2.0.gir Makefile +GdkWin32_2_0_gir_SCANNERFLAGS = --identifier-prefix=Gdk --symbol-prefix=gdk --include-uninstalled=Gdk-2.0.gir +GdkWin32_2_0_gir_INCLUDES = Gio-2.0 GdkPixbuf-2.0 Pango-1.0 +GdkWin32_2_0_gir_LIBS = $(gdktargetlib) +GdkWin32_2_0_gir_FILES = $(filter-out \ + win32/gdkdrawable-win32.h \ + win32/gdkinput-win32.h \ + win32/gdkpixmap-win32.h \ + win32/gdkprivate-win32.h \ + win32/gdkwindow-win32.h, \ + $(win32_introspection_files)) +GdkWin32_2_0_gir_EXPORT_PACKAGES = gdk-win32-2.0 +GdkWin32_2_0_gir_CFLAGS = \ + -DGDK_COMPILATION \ + -I$(top_srcdir) \ + -I$(top_builddir) \ + -I$(top_builddir)/gdk \ + -I$(srcdir)/win32 \ + -I$(srcdir) \ + $(INCLUDES) \ + -L$(top_builddir)/gdk +INTROSPECTION_GIRS += GdkWin32-2.0.gir + +introspection_files += $(filter-out win32/gdkwin32.h, $(win32_introspection_files)) + +endif # OS_WIN32 + girdir = $(datadir)/gir-1.0 gir_DATA = $(INTROSPECTION_GIRS) diff --git a/gdk/gdk.c b/gdk/gdk.c index 63f2b70ef..4c2246808 100644 --- a/gdk/gdk.c +++ b/gdk/gdk.c @@ -32,6 +32,7 @@ #include "gdk.h" #include "gdkinternals.h" #include "gdkintl.h" +#include "gdkpixelops.h" #ifndef HAVE_XCONVERTCASE #include "gdkkeysyms.h" @@ -189,6 +190,8 @@ gdk_pre_parse_libgtk_only (void) { gdk_initialized = TRUE; + _gdk_pixel_ops_init (); + /* We set the fallback program class here, rather than lazily in * gdk_get_program_class, since we don't want -name to override it. */ diff --git a/gdk/gdk.symbols b/gdk/gdk.symbols index ee1bc0c98..7f553df52 100644 --- a/gdk/gdk.symbols +++ b/gdk/gdk.symbols @@ -1118,6 +1118,15 @@ gdk_draw_rgb_image_dithalign #endif #endif +#if IN_HEADER(__GDK_RGB_H__) +#if IN_FILE(__GDK_RGB_C__) +gdk_draw_rgb_48_image +gdk_draw_rgb_48_image_dithalign +gdk_draw_rgbx_64_image +gdk_draw_rgbx_64_image_dithalign +#endif +#endif + #if IN_HEADER(__GDK_SCREEN_H__) #if IN_FILE(__GDK_SCREEN_C__) gdk_screen_get_type G_GNUC_CONST diff --git a/gdk/gdkdraw.c b/gdk/gdkdraw.c index b6b0a5953..7efe560b4 100644 --- a/gdk/gdkdraw.c +++ b/gdk/gdkdraw.c @@ -25,6 +25,7 @@ */ #include "config.h" +#include #include #include #include @@ -34,6 +35,7 @@ #include "gdkwindow.h" #include "gdkscreen.h" #include "gdkpixbuf.h" +#include "gdkpixelops.h" #include "gdkalias.h" static GdkImage* gdk_drawable_real_get_image (GdkDrawable *drawable, @@ -1403,62 +1405,6 @@ composite (guchar *src_buf, } } -static void -composite_0888 (guchar *src_buf, - gint src_rowstride, - guchar *dest_buf, - gint dest_rowstride, - GdkByteOrder dest_byte_order, - gint width, - gint height) -{ - guchar *src = src_buf; - guchar *dest = dest_buf; - - while (height--) - { - gint twidth = width; - guchar *p = src; - guchar *q = dest; - - if (dest_byte_order == GDK_LSB_FIRST) - { - while (twidth--) - { - guint t; - - t = p[3] * p[2] + (255 - p[3]) * q[0] + 0x80; - q[0] = (t + (t >> 8)) >> 8; - t = p[3] * p[1] + (255 - p[3]) * q[1] + 0x80; - q[1] = (t + (t >> 8)) >> 8; - t = p[3] * p[0] + (255 - p[3]) * q[2] + 0x80; - q[2] = (t + (t >> 8)) >> 8; - p += 4; - q += 4; - } - } - else - { - while (twidth--) - { - guint t; - - t = p[3] * p[0] + (255 - p[3]) * q[1] + 0x80; - q[1] = (t + (t >> 8)) >> 8; - t = p[3] * p[1] + (255 - p[3]) * q[2] + 0x80; - q[2] = (t + (t >> 8)) >> 8; - t = p[3] * p[2] + (255 - p[3]) * q[3] + 0x80; - q[3] = (t + (t >> 8)) >> 8; - p += 4; - q += 4; - } - } - - src += src_rowstride; - dest += dest_rowstride; - } -} - #ifdef USE_MEDIALIB static void composite_0888_medialib (guchar *src_buf, @@ -1497,82 +1443,6 @@ composite_0888_medialib (guchar *src_buf, } #endif -static void -composite_565 (guchar *src_buf, - gint src_rowstride, - guchar *dest_buf, - gint dest_rowstride, - GdkByteOrder dest_byte_order, - gint width, - gint height) -{ - guchar *src = src_buf; - guchar *dest = dest_buf; - - while (height--) - { - gint twidth = width; - guchar *p = src; - gushort *q = (gushort *)dest; - - while (twidth--) - { - guchar a = p[3]; - guint tr, tg, tb; - guint tr1, tg1, tb1; - guint tmp = *q; - -#if 1 - /* This is fast, and corresponds to what composite() above does - * if we converted to 8-bit first. - */ - tr = (tmp & 0xf800); - tr1 = a * p[0] + (255 - a) * ((tr >> 8) + (tr >> 13)) + 0x80; - tg = (tmp & 0x07e0); - tg1 = a * p[1] + (255 - a) * ((tg >> 3) + (tg >> 9)) + 0x80; - tb = (tmp & 0x001f); - tb1 = a * p[2] + (255 - a) * ((tb << 3) + (tb >> 2)) + 0x80; - - *q = (((tr1 + (tr1 >> 8)) & 0xf800) | - (((tg1 + (tg1 >> 8)) & 0xfc00) >> 5) | - ((tb1 + (tb1 >> 8)) >> 11)); -#else - /* This version correspond to the result we get with XRENDER - - * a bit of precision is lost since we convert to 8 bit after premultiplying - * instead of at the end - */ - guint tr2, tg2, tb2; - guint tr3, tg3, tb3; - - tr = (tmp & 0xf800); - tr1 = (255 - a) * ((tr >> 8) + (tr >> 13)) + 0x80; - tr2 = a * p[0] + 0x80; - tr3 = ((tr1 + (tr1 >> 8)) >> 8) + ((tr2 + (tr2 >> 8)) >> 8); - - tg = (tmp & 0x07e0); - tg1 = (255 - a) * ((tg >> 3) + (tg >> 9)) + 0x80; - tg2 = a * p[0] + 0x80; - tg3 = ((tg1 + (tg1 >> 8)) >> 8) + ((tg2 + (tg2 >> 8)) >> 8); - - tb = (tmp & 0x001f); - tb1 = (255 - a) * ((tb << 3) + (tb >> 2)) + 0x80; - tb2 = a * p[0] + 0x80; - tb3 = ((tb1 + (tb1 >> 8)) >> 8) + ((tb2 + (tb2 >> 8)) >> 8); - - *q = (((tr3 & 0xf8) << 8) | - ((tg3 & 0xfc) << 3) | - ((tb3 >> 3))); -#endif - - p += 4; - q++; - } - - src += src_rowstride; - dest += dest_rowstride; - } -} - /* Implementation of the old vfunc in terms of the new one in case someone calls it directly (which they shouldn't!) */ static void @@ -1598,6 +1468,114 @@ gdk_drawable_real_draw_drawable (GdkDrawable *drawable, src); } +#ifdef GDK_WINDOWING_X11 +static inline guint +composite_101010_channel (guint src, + guint alpha, + guint dest) +{ + guint sa; + guint da; + guint numerator; + guint q; + guint threshold; + + sa = src * alpha; + da = dest * (255U - alpha); + + numerator = + (sa << 10) - sa + + (da << 8) - da; + + q = numerator / 64961U; + + threshold = + q * 64961U + + ((q * 511U + 1023U) >> 10); + + q -= numerator < threshold; + + /* + * numerator <= 66520575, therefore q is at most 1024. + * Map only that endpoint to 1023 without a branch. + */ + q -= q >> 10; + + return q; +} + +static void +composite_101010_exact (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + GdkByteOrder dest_byte_order, + gint width, + gint height) +{ + guchar *src; + guchar *dest; + + (void) dest_byte_order; + + src = src_buf; + dest = dest_buf; + + while (height--) + { + const guchar *p; + guchar *q; + gint x; + + p = src; + q = dest; + + for (x = 0; x < width; x++) + { + guint32 pixel; + guint alpha; + guint r; + guint g; + guint b; + + memcpy (&pixel, q, sizeof pixel); + + alpha = p[3]; + + r = composite_101010_channel ( + p[0], + alpha, + (pixel >> 20) & 0x3ffU); + + g = composite_101010_channel ( + p[1], + alpha, + (pixel >> 10) & 0x3ffU); + + b = composite_101010_channel ( + p[2], + alpha, + pixel & 0x3ffU); + + pixel = + (pixel & 0xc0000000U) | + (r << 20) | + (g << 10) | + b; + + memcpy (q, &pixel, sizeof pixel); + + p += 4; + q += 4; + } + + src += src_rowstride; + dest += dest_rowstride; + } +} + +#endif /* GDK_WINDOWING_X11 */ + static void gdk_drawable_real_draw_pixbuf (GdkDrawable *drawable, GdkGC *gc, @@ -1728,7 +1706,25 @@ gdk_drawable_real_draw_pixbuf (GdkDrawable *drawable, visual->red_mask == 0xf800 && visual->green_mask == 0x07e0 && visual->blue_mask == 0x001f) - composite_func = composite_565; + { + composite_func = _gdk_pixel_ops.composite_565; + goto composite_selected; + } +#ifdef GDK_WINDOWING_X11 + else if (visual->type == GDK_VISUAL_TRUE_COLOR && + visual->byte_order == + (G_BYTE_ORDER == G_BIG_ENDIAN ? + GDK_MSB_FIRST : GDK_LSB_FIRST) && + visual->depth == 30 && + bits_per_pixel == 32 && + visual->red_mask == 0x3ff00000 && + visual->green_mask == 0x000ffc00 && + visual->blue_mask == 0x000003ff) + { + composite_func = composite_101010_exact; + goto composite_selected; + } +#endif /* GDK_WINDOWING_X11 */ else if (visual->depth == 24 && bits_per_pixel == 32 && visual->red_mask == 0xff0000 && visual->green_mask == 0x00ff00 && @@ -1738,16 +1734,20 @@ gdk_drawable_real_draw_pixbuf (GdkDrawable *drawable, if (_gdk_use_medialib ()) composite_func = composite_0888_medialib; else - composite_func = composite_0888; + composite_func = _gdk_pixel_ops.composite_0888; #else - composite_func = composite_0888; + composite_func = _gdk_pixel_ops.composite_0888; #endif + goto composite_selected; } } + goto no_composite; /* We can't use our composite func if we are required to dither */ - if (composite_func && !(dither == GDK_RGB_DITHER_MAX && visual->depth != 24)) + +composite_selected: + if (!(dither == GDK_RGB_DITHER_MAX && visual->depth != 24)) { gint x0, y0; for (y0 = 0; y0 < height; y0 += GDK_SCRATCH_IMAGE_HEIGHT) @@ -1782,7 +1782,7 @@ gdk_drawable_real_draw_pixbuf (GdkDrawable *drawable, goto out; } - else +no_composite: { /* No special composition func, convert dest to 24 bit RGB data, composite against * that, and convert back. diff --git a/gdk/gdkpixelops-generic.c b/gdk/gdkpixelops-generic.c new file mode 100644 index 000000000..01a97a621 --- /dev/null +++ b/gdk/gdkpixelops-generic.c @@ -0,0 +1,149 @@ +/* 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. + */ + +#include "config.h" + +#include "gdkpixelops.h" + +G_GNUC_INTERNAL void +_gdk_pixel_ops_composite_0888_generic (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + GdkByteOrder dest_byte_order, + gint width, + gint height) +{ + guchar *src = src_buf; + guchar *dest = dest_buf; + + while (height--) + { + gint twidth = width; + guchar *p = src; + guchar *q = dest; + + if (dest_byte_order == GDK_LSB_FIRST) + { + while (twidth--) + { + guint t; + + t = p[3] * p[2] + (255 - p[3]) * q[0] + 0x80; + q[0] = (t + (t >> 8)) >> 8; + t = p[3] * p[1] + (255 - p[3]) * q[1] + 0x80; + q[1] = (t + (t >> 8)) >> 8; + t = p[3] * p[0] + (255 - p[3]) * q[2] + 0x80; + q[2] = (t + (t >> 8)) >> 8; + p += 4; + q += 4; + } + } + else + { + while (twidth--) + { + guint t; + + t = p[3] * p[0] + (255 - p[3]) * q[1] + 0x80; + q[1] = (t + (t >> 8)) >> 8; + t = p[3] * p[1] + (255 - p[3]) * q[2] + 0x80; + q[2] = (t + (t >> 8)) >> 8; + t = p[3] * p[2] + (255 - p[3]) * q[3] + 0x80; + q[3] = (t + (t >> 8)) >> 8; + p += 4; + q += 4; + } + } + + src += src_rowstride; + dest += dest_rowstride; + } +} + +G_GNUC_INTERNAL void +_gdk_pixel_ops_composite_565_generic (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + GdkByteOrder dest_byte_order, + gint width, + gint height) +{ + guchar *src = src_buf; + guchar *dest = dest_buf; + + while (height--) + { + gint twidth = width; + guchar *p = src; + gushort *q = (gushort *)dest; + + while (twidth--) + { + guchar a = p[3]; + guint tr, tg, tb; + guint tr1, tg1, tb1; + guint tmp = *q; + +#if 1 + /* This is fast, and corresponds to what composite() above does + * if we converted to 8-bit first. + */ + tr = (tmp & 0xf800); + tr1 = a * p[0] + (255 - a) * ((tr >> 8) + (tr >> 13)) + 0x80; + tg = (tmp & 0x07e0); + tg1 = a * p[1] + (255 - a) * ((tg >> 3) + (tg >> 9)) + 0x80; + tb = (tmp & 0x001f); + tb1 = a * p[2] + (255 - a) * ((tb << 3) + (tb >> 2)) + 0x80; + + *q = (((tr1 + (tr1 >> 8)) & 0xf800) | + (((tg1 + (tg1 >> 8)) & 0xfc00) >> 5) | + ((tb1 + (tb1 >> 8)) >> 11)); +#else + /* This version correspond to the result we get with XRENDER - + * a bit of precision is lost since we convert to 8 bit after premultiplying + * instead of at the end + */ + guint tr2, tg2, tb2; + guint tr3, tg3, tb3; + + tr = (tmp & 0xf800); + tr1 = (255 - a) * ((tr >> 8) + (tr >> 13)) + 0x80; + tr2 = a * p[0] + 0x80; + tr3 = ((tr1 + (tr1 >> 8)) >> 8) + ((tr2 + (tr2 >> 8)) >> 8); + + tg = (tmp & 0x07e0); + tg1 = (255 - a) * ((tg >> 3) + (tg >> 9)) + 0x80; + tg2 = a * p[0] + 0x80; + tg3 = ((tg1 + (tg1 >> 8)) >> 8) + ((tg2 + (tg2 >> 8)) >> 8); + + tb = (tmp & 0x001f); + tb1 = (255 - a) * ((tb << 3) + (tb >> 2)) + 0x80; + tb2 = a * p[0] + 0x80; + tb3 = ((tb1 + (tb1 >> 8)) >> 8) + ((tb2 + (tb2 >> 8)) >> 8); + + *q = (((tr3 & 0xf8) << 8) | + ((tg3 & 0xfc) << 3) | + ((tb3 >> 3))); +#endif + + p += 4; + q++; + } + + src += src_rowstride; + dest += dest_rowstride; + } +} diff --git a/gdk/gdkpixelops-x86-mmx.c b/gdk/gdkpixelops-x86-mmx.c new file mode 100644 index 000000000..bf7cdd8b2 --- /dev/null +++ b/gdk/gdkpixelops-x86-mmx.c @@ -0,0 +1,347 @@ +/* GDK - The GIMP Drawing Kit + * + * MMX pixel operations for 32-bit x86. + */ + +#include "config.h" + +#include +#include + +#ifdef GDK_PIXELOPS_X86_3DNOW_IMPL +#include +#define GDK_PIXELOPS_COMPOSITE_0888 _gdk_pixel_ops_composite_0888_3dnow +#define GDK_PIXELOPS_COMPOSITE_565 _gdk_pixel_ops_composite_565_3dnow +#define GDK_PIXELOPS_MMX_EMPTY() _m_femms () +#elif defined(GDK_PIXELOPS_X86_SSE_IMPL) +#define GDK_PIXELOPS_COMPOSITE_0888 _gdk_pixel_ops_composite_0888_sse +#define GDK_PIXELOPS_COMPOSITE_565 _gdk_pixel_ops_composite_565_sse +#define GDK_PIXELOPS_MMX_EMPTY() _mm_empty () +#else +#define GDK_PIXELOPS_COMPOSITE_0888 _gdk_pixel_ops_composite_0888_mmx +#define GDK_PIXELOPS_COMPOSITE_565 _gdk_pixel_ops_composite_565_mmx +#define GDK_PIXELOPS_MMX_EMPTY() _mm_empty () +#endif + +#include "gdkpixelops.h" + +#ifndef __i386__ +#error "gdkpixelops-x86-mmx.c requires a 32-bit x86 target" +#endif + +G_GNUC_INTERNAL void +_gdk_pixel_ops_composite_0888_generic (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + GdkByteOrder dest_byte_order, + gint width, + gint height); + +#ifdef GDK_PIXELOPS_X86_3DNOW_IMPL +static __inline__ __m64 +blend_3dnow (__m64 s, + __m64 d, + __m64 a) +{ + __m64 scaled; + __m64 mask; + __m64 coeff; + __m64 delta; + __m64 correction; + __m64 t; + + scaled = _mm_slli_pi16 (a, 8); + mask = _mm_srai_pi16 (scaled, 15); + + coeff = _mm_add_pi16 (a, scaled); + coeff = _mm_sub_pi16 (coeff, mask); + + delta = _mm_sub_pi16 (s, d); + correction = _mm_and_si64 (delta, mask); + + t = _m_pmulhrw (delta, coeff); + t = _mm_add_pi16 (t, correction); + + return _mm_add_pi16 (t, d); +} +#endif + +G_GNUC_INTERNAL void +GDK_PIXELOPS_COMPOSITE_0888 (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + GdkByteOrder dest_byte_order, + gint width, + gint height) +{ + if (dest_byte_order != GDK_LSB_FIRST) + { + _gdk_pixel_ops_composite_0888_generic (src_buf, + src_rowstride, + dest_buf, + dest_rowstride, + dest_byte_order, + width, + height); + return; + } + + { + const __m64 zero = _mm_setzero_si64 (); + const __m64 ones = _mm_cmpeq_pi16 (zero, zero); +#ifndef GDK_PIXELOPS_X86_3DNOW_IMPL + const __m64 ff = _mm_srli_pi16 (ones, 8); + const __m64 bias = _mm_set1_pi16 (0x80); +#endif + const __m64 rgb_mask = _mm_srli_si64 (ones, 16); + guchar *src = src_buf; + guchar *dest = dest_buf; + + while (height--) + { + gint twidth = width; + guchar *p = src; + guchar *q = dest; + + while (twidth--) + { + guint32 sp; + guint32 dp; + guint32 result; + __m64 s; + __m64 d; + __m64 a; +#ifndef GDK_PIXELOPS_X86_3DNOW_IMPL + __m64 ia; +#endif + __m64 t; + __m64 packed; + + memcpy (&sp, p, sizeof sp); + memcpy (&dp, q, sizeof dp); + + sp = ((sp & 0xff00ff00U) | + ((sp & 0x000000ffU) << 16) | + ((sp & 0x00ff0000U) >> 16)); + + s = _mm_cvtsi32_si64 ((int) sp); + d = _mm_cvtsi32_si64 ((int) dp); + + s = _mm_unpacklo_pi8 (s, zero); + d = _mm_unpacklo_pi8 (d, zero); + + a = _mm_srli_si64 (s, 48); + #ifdef GDK_PIXELOPS_X86_SSE_IMPL + __asm__ ("pshufw $0x00,%0,%0" + : "+y" (a)); + #else + a = _mm_unpacklo_pi16 (a, a); + a = _mm_unpacklo_pi32 (a, a); + #endif + a = _mm_and_si64 (a, rgb_mask); + +#ifdef GDK_PIXELOPS_X86_3DNOW_IMPL + t = blend_3dnow (s, d, a); +#else + ia = _mm_sub_pi16 (ff, a); + + t = _mm_add_pi16 (_mm_mullo_pi16 (s, a), + _mm_mullo_pi16 (d, ia)); + + t = _mm_add_pi16 (t, bias); + #ifdef GDK_PIXELOPS_X86_SSE_IMPL + { + __m64 scale = _mm_set1_pi16 (0x0101); + + __asm__ ("pmulhuw %1,%0" + : "+y" (t) + : "y" (scale)); + } + #else + t = _mm_add_pi16 (t, _mm_srli_pi16 (t, 8)); + t = _mm_srli_pi16 (t, 8); + #endif +#endif + + packed = _mm_packs_pu16 (t, t); + result = (guint32) _mm_cvtsi64_si32 (packed); + + memcpy (q, &result, sizeof result); + + p += 4; + q += 4; + } + + src += src_rowstride; + dest += dest_rowstride; + } + + GDK_PIXELOPS_MMX_EMPTY (); + } +} + +static guint32 +expand_565 (guint16 value) +{ + guint32 hi; + + hi = (((guint32) value & 0xf800U) >> 8) | + (((guint32) value & 0x07e0U) << 5) | + (((guint32) value & 0x001fU) << 19); + + return hi | + ((hi >> 5) & 0x00070007U) | + ((hi >> 6) & 0x00000300U); +} + +static guint16 +pack_565 (guint32 rgb) +{ + return (guint16) + (((rgb & 0x000000f8U) << 8) | + ((rgb & 0x0000fc00U) >> 5) | + ((rgb & 0x00f80000U) >> 19)); +} + +static guint32 +blend_565_mmx (__m64 zero, + __m64 ff, + __m64 bias, + guint32 src, + guint32 dest) +{ + __m64 s; + __m64 d; + __m64 a; +#ifndef GDK_PIXELOPS_X86_3DNOW_IMPL + __m64 ia; +#endif + __m64 t; + guint32 result; + + s = _mm_cvtsi32_si64 ((int) src); + d = _mm_cvtsi32_si64 ((int) dest); + + s = _mm_unpacklo_pi8 (s, zero); + d = _mm_unpacklo_pi8 (d, zero); + + a = _mm_srli_si64 (s, 48); + #ifdef GDK_PIXELOPS_X86_SSE_IMPL + __asm__ ("pshufw $0x00,%0,%0" + : "+y" (a)); + #else + a = _mm_unpacklo_pi16 (a, a); + a = _mm_unpacklo_pi32 (a, a); + #endif + +#ifdef GDK_PIXELOPS_X86_3DNOW_IMPL + t = blend_3dnow (s, d, a); +#else + ia = _mm_sub_pi16 (ff, a); + + t = _mm_add_pi16 (_mm_mullo_pi16 (s, a), + _mm_mullo_pi16 (d, ia)); + + t = _mm_add_pi16 (t, bias); + #ifdef GDK_PIXELOPS_X86_SSE_IMPL + { + __m64 scale = _mm_set1_pi16 (0x0101); + + __asm__ ("pmulhuw %1,%0" + : "+y" (t) + : "y" (scale)); + } + #else + t = _mm_add_pi16 (t, _mm_srli_pi16 (t, 8)); + t = _mm_srli_pi16 (t, 8); + #endif +#endif + t = _mm_packs_pu16 (t, t); + + __asm__ ("movd %1,%0" + : "=r" (result) + : "y" (t)); + + return result; +} + +G_GNUC_INTERNAL void +GDK_PIXELOPS_COMPOSITE_565 (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + GdkByteOrder dest_byte_order, + gint width, + gint height) +{ + const __m64 zero = _mm_setzero_si64 (); + const __m64 ones = _mm_cmpeq_pi16 (zero, zero); + const __m64 ff = _mm_srli_pi16 (ones, 8); + const __m64 bias = _mm_set1_pi16 (0x80); + guchar *src = src_buf; + guchar *dest = dest_buf; + + (void) dest_byte_order; + + while (height--) + { + gint pairs = width >> 1; + guchar *p = src; + guchar *q = dest; + + while (pairs--) + { + guint32 sp0; + guint32 sp1; + guint32 dpair; + guint32 dp0; + guint32 dp1; + guint32 rgb0; + guint32 rgb1; + guint32 result; + + memcpy (&sp0, p, sizeof sp0); + memcpy (&sp1, p + 4, sizeof sp1); + memcpy (&dpair, q, sizeof dpair); + + dp0 = expand_565 ((guint16) dpair); + dp1 = expand_565 ((guint16) (dpair >> 16)); + + rgb0 = blend_565_mmx (zero, ff, bias, sp0, dp0); + rgb1 = blend_565_mmx (zero, ff, bias, sp1, dp1); + + result = (guint32) pack_565 (rgb0); + result |= (guint32) pack_565 (rgb1) << 16; + + memcpy (q, &result, sizeof result); + + p += 8; + q += 4; + } + + if (width & 1) + { + guint32 sp; + guint16 dp16; + guint16 result; + guint32 dp; + guint32 rgb; + + memcpy (&sp, p, sizeof sp); + memcpy (&dp16, q, sizeof dp16); + + dp = expand_565 (dp16); + rgb = blend_565_mmx (zero, ff, bias, sp, dp); + result = pack_565 (rgb); + + memcpy (q, &result, sizeof result); + } + + src += src_rowstride; + dest += dest_rowstride; + } + + GDK_PIXELOPS_MMX_EMPTY (); +} diff --git a/gdk/gdkpixelops-x86-sse2.c b/gdk/gdkpixelops-x86-sse2.c new file mode 100644 index 000000000..f502a7e44 --- /dev/null +++ b/gdk/gdkpixelops-x86-sse2.c @@ -0,0 +1,337 @@ +/* GDK - The GIMP Drawing Kit + * + * SSE2 0888 pixel compositing for x86. + */ + +#include "config.h" + +#include "gdkpixelops.h" + +#if !defined(__i386__) && !defined(__x86_64__) +#error "gdkpixelops-x86-sse2.c requires an x86 target" +#endif + +#if defined(__x86_64__) && !defined(__ILP32__) +#define GDK_PIXELOPS_PTR_ADD "addq" +#else +#define GDK_PIXELOPS_PTR_ADD "addl" +#endif + +/* + * Keep this declaration at default visibility. The definition remains + * internal in gdkpixelops-generic.c, allowing compact SSE2 code while + * the final shared object still binds the fallback internally. + */ +void +_gdk_pixel_ops_composite_0888_generic (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + GdkByteOrder dest_byte_order, + gint width, + gint height); + +static const unsigned short asm_rgb_mask[8] + __attribute__ ((aligned (16))) = +{ + 0xffff, 0xffff, 0xffff, 0x0000, + 0xffff, 0xffff, 0xffff, 0x0000 +}; + +static const unsigned short asm_c255[8] + __attribute__ ((aligned (16))) = +{ + 255, 255, 255, 255, + 255, 255, 255, 255 +}; + +static const unsigned short asm_c128[8] + __attribute__ ((aligned (16))) = +{ + 128, 128, 128, 128, + 128, 128, 128, 128 +}; + +static const unsigned short asm_c257[8] + __attribute__ ((aligned (16))) = +{ + 257, 257, 257, 257, + 257, 257, 257, 257 +}; + +static inline void +composite_four_loop_asm (guchar **pp, + guchar **qq, + gint *nn) +{ + guchar *p = *pp; + guchar *q = *qq; + gint n = *nn; + + __asm__ volatile + ( + "1:\n\t" + "cmpl $4, %[n]\n\t" + "jl 2f\n\t" + + "movdqu (%[p]), %%xmm0\n\t" + "movdqu (%[q]), %%xmm1\n\t" + + "movdqa %%xmm0, %%xmm2\n\t" + "pxor %%xmm7, %%xmm7\n\t" + + "punpcklbw %%xmm7, %%xmm0\n\t" + "punpckhbw %%xmm7, %%xmm2\n\t" + + "movdqa %%xmm1, %%xmm3\n\t" + + "punpcklbw %%xmm7, %%xmm1\n\t" + "punpckhbw %%xmm7, %%xmm3\n\t" + + "pshuflw $0xc6, %%xmm0, %%xmm0\n\t" + "pshuflw $0xc6, %%xmm2, %%xmm2\n\t" + + "pshufhw $0xc6, %%xmm0, %%xmm0\n\t" + "pshufhw $0xc6, %%xmm2, %%xmm2\n\t" + + "movdqa %%xmm0, %%xmm4\n\t" + "movdqa %%xmm2, %%xmm5\n\t" + + "pshuflw $0xff, %%xmm4, %%xmm4\n\t" + "pshuflw $0xff, %%xmm5, %%xmm5\n\t" + + "pshufhw $0xff, %%xmm4, %%xmm4\n\t" + "pshufhw $0xff, %%xmm5, %%xmm5\n\t" + + "pand %[mask], %%xmm4\n\t" + "pand %[mask], %%xmm5\n\t" + + "movdqa %%xmm4, %%xmm6\n\t" + "movdqa %%xmm5, %%xmm7\n\t" + + "pxor %[c255], %%xmm6\n\t" + "pxor %[c255], %%xmm7\n\t" + + "pmullw %%xmm4, %%xmm0\n\t" + "pmullw %%xmm5, %%xmm2\n\t" + + GDK_PIXELOPS_PTR_ADD " $16, %[p]\n\t" + GDK_PIXELOPS_PTR_ADD " $16, %[q]\n\t" + "subl $4, %[n]\n\t" + + "pmullw %%xmm6, %%xmm1\n\t" + "pmullw %%xmm7, %%xmm3\n\t" + + "paddw %%xmm1, %%xmm0\n\t" + "paddw %%xmm3, %%xmm2\n\t" + + "paddw %[c128], %%xmm0\n\t" + "paddw %[c128], %%xmm2\n\t" + + "pmulhuw %[c257], %%xmm0\n\t" + "pmulhuw %[c257], %%xmm2\n\t" + + "packuswb %%xmm2, %%xmm0\n\t" + + "movdqu %%xmm0, -16(%[q])\n\t" + + "jmp 1b\n\t" + + "2:\n\t" + + : [p] "+r" (p), + [q] "+r" (q), + [n] "+r" (n) + + : [mask] "m" (asm_rgb_mask), + [c255] "m" (asm_c255), + [c128] "m" (asm_c128), + [c257] "m" (asm_c257) + + : "cc", + "memory", + "xmm0", + "xmm1", + "xmm2", + "xmm3", + "xmm4", + "xmm5", + "xmm6", + "xmm7" + ); + + *pp = p; + *qq = q; + *nn = n; +} + +static inline void +composite_two_asm (guchar **pp, + guchar **qq, + gint *nn) +{ + guchar *p = *pp; + guchar *q = *qq; + gint n = *nn; + + __asm__ volatile + ( + "cmpl $2, %[n]\n\t" + "jl 1f\n\t" + + "movq (%[p]), %%xmm0\n\t" + "pxor %%xmm2, %%xmm2\n\t" + "punpcklbw %%xmm2, %%xmm0\n\t" + + "movq (%[q]), %%xmm1\n\t" + "punpcklbw %%xmm2, %%xmm1\n\t" + + "pshuflw $0xc6, %%xmm0, %%xmm0\n\t" + "pshufhw $0xc6, %%xmm0, %%xmm0\n\t" + + "movdqa %%xmm0, %%xmm2\n\t" + "pshuflw $0xff, %%xmm2, %%xmm2\n\t" + "pshufhw $0xff, %%xmm2, %%xmm2\n\t" + "pand %[mask], %%xmm2\n\t" + + "movdqa %%xmm2, %%xmm3\n\t" + "pxor %[c255], %%xmm3\n\t" + + "pmullw %%xmm2, %%xmm0\n\t" + "pmullw %%xmm3, %%xmm1\n\t" + + GDK_PIXELOPS_PTR_ADD " $8, %[p]\n\t" + GDK_PIXELOPS_PTR_ADD " $8, %[q]\n\t" + "subl $2, %[n]\n\t" + + "paddw %%xmm1, %%xmm0\n\t" + + "paddw %[c128], %%xmm0\n\t" + "pmulhuw %[c257], %%xmm0\n\t" + + "pxor %%xmm1, %%xmm1\n\t" + "packuswb %%xmm1, %%xmm0\n\t" + + "movq %%xmm0, -8(%[q])\n\t" + + "1:\n\t" + + : [p] "+r" (p), + [q] "+r" (q), + [n] "+r" (n) + + : [mask] "m" (asm_rgb_mask), + [c255] "m" (asm_c255), + [c128] "m" (asm_c128), + [c257] "m" (asm_c257) + + : "cc", + "memory", + "xmm0", + "xmm1", + "xmm2", + "xmm3" + ); + + *pp = p; + *qq = q; + *nn = n; +} + +static inline void +composite_one_asm (guchar *p, + guchar *q) +{ + + __asm__ volatile + ( + "movd (%[p]), %%xmm0\n\t" + "pxor %%xmm2, %%xmm2\n\t" + "punpcklbw %%xmm2, %%xmm0\n\t" + + "movd (%[q]), %%xmm1\n\t" + "punpcklbw %%xmm2, %%xmm1\n\t" + + "pshuflw $0xc6, %%xmm0, %%xmm0\n\t" + + "movdqa %%xmm0, %%xmm2\n\t" + "pshuflw $0xff, %%xmm2, %%xmm2\n\t" + "pand %[mask], %%xmm2\n\t" + + "movdqa %%xmm2, %%xmm3\n\t" + "pxor %[c255], %%xmm3\n\t" + + "pmullw %%xmm2, %%xmm0\n\t" + "pmullw %%xmm3, %%xmm1\n\t" + + "paddw %%xmm1, %%xmm0\n\t" + + "paddw %[c128], %%xmm0\n\t" + "pmulhuw %[c257], %%xmm0\n\t" + + "pxor %%xmm1, %%xmm1\n\t" + "packuswb %%xmm1, %%xmm0\n\t" + + "movd %%xmm0, (%[q])\n\t" + + : + : [p] "r" (p), + [q] "r" (q), + [mask] "m" (asm_rgb_mask), + [c255] "m" (asm_c255), + [c128] "m" (asm_c128), + [c257] "m" (asm_c257) + + : "memory", + "xmm0", + "xmm1", + "xmm2", + "xmm3" + ); +} + +G_GNUC_INTERNAL void +_gdk_pixel_ops_composite_0888_sse2 (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + GdkByteOrder dest_byte_order, + gint width, + gint height) +{ + guchar *src = src_buf; + guchar *dest = dest_buf; + + if (width <= 0 || height <= 0) + return; + + if (dest_byte_order != GDK_LSB_FIRST) + { + _gdk_pixel_ops_composite_0888_generic + (src_buf, + src_rowstride, + dest_buf, + dest_rowstride, + dest_byte_order, + width, + height); + return; + } + + while (height--) + { + gint n = width; + guchar *p = src; + guchar *q = dest; + + composite_four_loop_asm (&p, &q, &n); + + composite_two_asm (&p, &q, &n); + + if (__builtin_expect (n != 0, 0)) + composite_one_asm (p, q); + + src += src_rowstride; + dest += dest_rowstride; + } +} diff --git a/gdk/gdkpixelops-x86.c b/gdk/gdkpixelops-x86.c new file mode 100644 index 000000000..77c44ed7e --- /dev/null +++ b/gdk/gdkpixelops-x86.c @@ -0,0 +1,123 @@ +/* GDK - The GIMP Drawing Kit + * + * x86 pixel operation backend. + * + * This file is selected at build time only for x86 targets. + */ + +#include "config.h" + +#include "gdkpixelops.h" + +#if !defined(__i386__) && !defined(__x86_64__) && \ + !defined(_M_IX86) && !defined(_M_X64) +#error "gdkpixelops-x86.c must only be built for an x86 target" +#endif + + +#include + +G_GNUC_INTERNAL void +_gdk_pixel_ops_composite_0888_mmx (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + GdkByteOrder dest_byte_order, + gint width, + gint height); + +G_GNUC_INTERNAL void +_gdk_pixel_ops_composite_565_mmx (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + GdkByteOrder dest_byte_order, + gint width, + gint height); + +G_GNUC_INTERNAL void +_gdk_pixel_ops_composite_0888_sse (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + GdkByteOrder dest_byte_order, + gint width, + gint height); + +G_GNUC_INTERNAL void +_gdk_pixel_ops_composite_565_sse (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + GdkByteOrder dest_byte_order, + gint width, + gint height); + +G_GNUC_INTERNAL void +_gdk_pixel_ops_composite_0888_3dnow (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + GdkByteOrder dest_byte_order, + gint width, + gint height); + +G_GNUC_INTERNAL void +_gdk_pixel_ops_composite_565_3dnow (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + GdkByteOrder dest_byte_order, + gint width, + gint height); + +G_GNUC_INTERNAL void +_gdk_pixel_ops_composite_0888_sse2 (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + GdkByteOrder dest_byte_order, + gint width, + gint height); + +G_GNUC_INTERNAL void +_gdk_pixel_ops_init (void) +{ + unsigned int eax; + unsigned int ebx; + unsigned int ecx; + unsigned int edx; + unsigned int standard_edx; + + if (__get_cpuid (1, &eax, &ebx, &ecx, &edx) && + (edx & bit_MMX) != 0) + { + standard_edx = edx; + + _gdk_pixel_ops.composite_0888 = + _gdk_pixel_ops_composite_0888_mmx; + _gdk_pixel_ops.composite_565 = + _gdk_pixel_ops_composite_565_mmx; + + if ((edx & bit_SSE) != 0) + { + _gdk_pixel_ops.composite_0888 = + _gdk_pixel_ops_composite_0888_sse; + _gdk_pixel_ops.composite_565 = + _gdk_pixel_ops_composite_565_sse; + } + + if (__get_cpuid (0x80000001U, &eax, &ebx, &ecx, &edx) && + (edx & bit_3DNOW) != 0) + { + _gdk_pixel_ops.composite_0888 = + _gdk_pixel_ops_composite_0888_3dnow; + _gdk_pixel_ops.composite_565 = + _gdk_pixel_ops_composite_565_3dnow; + } + + if ((standard_edx & bit_SSE2) != 0) + _gdk_pixel_ops.composite_0888 = + _gdk_pixel_ops_composite_0888_sse2; + } +} diff --git a/gdk/gdkpixelops.c b/gdk/gdkpixelops.c new file mode 100644 index 000000000..ff405a35f --- /dev/null +++ b/gdk/gdkpixelops.c @@ -0,0 +1,55 @@ +/* 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. + */ + +#include "config.h" + +#include "gdkpixelops.h" + +G_GNUC_INTERNAL void +_gdk_pixel_ops_composite_0888_generic (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + GdkByteOrder dest_byte_order, + gint width, + gint height); + +G_GNUC_INTERNAL void +_gdk_pixel_ops_composite_565_generic (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + GdkByteOrder dest_byte_order, + gint width, + gint height); + +#ifdef GDK_PIXELOPS_X86_64 +G_GNUC_INTERNAL void +_gdk_pixel_ops_composite_0888_sse2 (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + GdkByteOrder dest_byte_order, + gint width, + gint height); +#endif + +G_GNUC_INTERNAL GdkPixelOps _gdk_pixel_ops = { +#ifdef GDK_PIXELOPS_X86_64 + _gdk_pixel_ops_composite_0888_sse2, +#else + _gdk_pixel_ops_composite_0888_generic, +#endif + _gdk_pixel_ops_composite_565_generic +}; diff --git a/gdk/gdkpixelops.h b/gdk/gdkpixelops.h new file mode 100644 index 000000000..c070e6a25 --- /dev/null +++ b/gdk/gdkpixelops.h @@ -0,0 +1,37 @@ +/* GDK - The GIMP Drawing Kit + * + * Private pixel operation dispatch. + */ + +#ifndef __GDK_PIXEL_OPS_H__ +#define __GDK_PIXEL_OPS_H__ + +#include "gdktypes.h" + +G_BEGIN_DECLS + +typedef void (*GdkCompositeFunc) (guchar *src_buf, + gint src_rowstride, + guchar *dest_buf, + gint dest_rowstride, + GdkByteOrder dest_byte_order, + gint width, + gint height); + +typedef struct +{ + GdkCompositeFunc composite_0888; + GdkCompositeFunc composite_565; +} GdkPixelOps; + +extern G_GNUC_INTERNAL GdkPixelOps _gdk_pixel_ops; + +#ifdef HAVE_GDK_PIXELOPS_INIT +G_GNUC_INTERNAL void _gdk_pixel_ops_init (void); +#else +#define _gdk_pixel_ops_init() ((void) 0) +#endif + +G_END_DECLS + +#endif /* __GDK_PIXEL_OPS_H__ */ diff --git a/gdk/gdkrgb.c b/gdk/gdkrgb.c index b0ff66833..fd2dee57a 100644 --- a/gdk/gdkrgb.c +++ b/gdk/gdkrgb.c @@ -1357,6 +1357,10 @@ gdk_rgb_convert_8_d (GdkRgbInfo *image_info, GdkImage *image, obuf = ((guchar *)image->mem) + y0 * bpl + x0; for (y = 0; y < height; y++) { +#if GLIB_SIZEOF_VOID_P == 8 && \ + (defined(__x86_64__) || defined(__amd64__) || defined(__aarch64__)) + unsigned int dx = (unsigned int) x_align & (DM_WIDTH - 1); +#endif dmp = DM[(y_align + y) & (DM_HEIGHT - 1)]; bp2 = bptr; obptr = obuf; @@ -1365,7 +1369,13 @@ gdk_rgb_convert_8_d (GdkRgbInfo *image_info, GdkImage *image, r = *bp2++; g = *bp2++; b = *bp2++; +#if GLIB_SIZEOF_VOID_P == 8 && \ + (defined(__x86_64__) || defined(__amd64__) || defined(__aarch64__)) + dith = (dmp[dx] << 2) | 7; + dx = (dx + 1) & (DM_WIDTH - 1); +#else dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) | 7; +#endif r = ((r * rs) + dith) >> 8; g = ((g * gs) + (262 - dith)) >> 8; b = ((b * bs) + dith) >> 8; @@ -1434,7 +1444,12 @@ gdk_rgb_convert_gray8 (GdkRgbInfo *image_info, GdkImage *image, r = *bp2++; g = *bp2++; b = *bp2++; +#if GLIB_SIZEOF_VOID_P == 8 && \ + (defined(__x86_64__) || defined(__amd64__)) + obptr[0] = (r + 2 * g + b) >> 2; +#else obptr[0] = (g + ((b + r) >> 1)) >> 1; +#endif obptr++; } bptr += rowstride; @@ -1464,19 +1479,33 @@ gdk_rgb_convert_gray8_gray (GdkRgbInfo *image_info, GdkImage *image, } } -#if G_BYTE_ORDER == G_LITTLE_ENDIAN -#define HAIRY_CONVERT_565 + +#if G_BYTE_ORDER == G_BIG_ENDIAN +#if defined(__powerpc__) || defined(__powerpc64__) || \ + defined(__ppc__) || defined(__ppc64__) || \ + defined(__PPC__) || defined(__PPC64__) || \ + defined(__POWERPC__) || defined(_ARCH_PPC) +#define GDK_RGB_FAST_BE565_RGB +#define GDK_RGB_FAST_BE565_GRAY +#define GDK_RGB_FAST_BE565_DITHER +#elif defined(__s390x__) +#define GDK_RGB_FAST_BE565_RGB +#elif defined(__aarch64__) +#define GDK_RGB_FAST_BE565_RGB +#define GDK_RGB_FAST_BE565_GRAY +#elif defined(__arm__) && defined(__ARM_ARCH) && \ + __ARM_ARCH >= 5 +#define GDK_RGB_FAST_BE565_RGB +#define GDK_RGB_FAST_BE565_GRAY +#elif defined(__m68k__) +#define GDK_RGB_FAST_BE565_GRAY +#endif #endif -#ifdef HAIRY_CONVERT_565 /* Render a 24-bit RGB image in buf into the GdkImage, without dithering. - This assumes native byte ordering - what should really be done is to - check whether the image byte_order is consistent with the _ENDIAN - config flag, and if not, use a different function. - - This one is even faster than the one below - its inner loop loads 3 - words (i.e. 4 24-bit pixels), does a lot of shifting and masking, - then writes 2 words. */ + The four-pixel inner loop uses compile-time-specialized native word + layouts for little- and big-endian systems. */ +#if G_BYTE_ORDER == G_LITTLE_ENDIAN || defined(GDK_RGB_FAST_BE565_RGB) static void gdk_rgb_convert_565 (GdkRgbInfo *image_info, GdkImage *image, gint x0, gint y0, gint width, gint height, @@ -1520,6 +1549,7 @@ gdk_rgb_convert_565 (GdkRgbInfo *image_info, GdkImage *image, r1b0g0r0 = ((guint32 *)bp2)[0]; g2r2b1g1 = ((guint32 *)bp2)[1]; b3g3r3b2 = ((guint32 *)bp2)[2]; +#if G_BYTE_ORDER == G_LITTLE_ENDIAN ((guint32 *)obptr)[0] = ((r1b0g0r0 & 0xf8) << 8) | ((r1b0g0r0 & 0xfc00) >> 5) | @@ -1534,6 +1564,22 @@ gdk_rgb_convert_565 (GdkRgbInfo *image_info, GdkImage *image, ((b3g3r3b2 & 0xf800) << 16) | ((b3g3r3b2 & 0xfc0000) << 3) | ((b3g3r3b2 & 0xf8000000) >> 11); +#else + ((guint32 *)obptr)[0] = + (r1b0g0r0 & 0xf8000000) | + ((r1b0g0r0 & 0x00fc0000) << 3) | + ((r1b0g0r0 & 0x0000f800) << 5) | + ((r1b0g0r0 & 0x000000f8) << 8) | + ((g2r2b1g1 & 0xfc000000) >> 21) | + ((g2r2b1g1 & 0x00f80000) >> 19); + ((guint32 *)obptr)[1] = + ((g2r2b1g1 & 0x0000f800) << 16) | + ((g2r2b1g1 & 0x000000fc) << 19) | + ((b3g3r3b2 & 0xf8000000) >> 11) | + ((b3g3r3b2 & 0x00f80000) >> 8) | + ((b3g3r3b2 & 0x0000fc00) >> 5) | + ((b3g3r3b2 & 0x000000f8) >> 3); +#endif bp2 += 12; obptr += 8; } @@ -1553,27 +1599,6 @@ gdk_rgb_convert_565 (GdkRgbInfo *image_info, GdkImage *image, } } #else -/* Render a 24-bit RGB image in buf into the GdkImage, without dithering. - This assumes native byte ordering - what should really be done is to - check whether the image byte_order is consistent with the _ENDIAN - config flag, and if not, use a different function. - - This routine is faster than the one included with Gtk 1.0 for a number - of reasons: - - 1. Shifting instead of lookup tables (less memory traffic). - - 2. Much less register pressure, especially because shifts are - in the code. - - 3. A memcpy is avoided (i.e. the transfer function). - - 4. On big-endian architectures, byte swapping is avoided. - - That said, it wouldn't be hard to make it even faster - just make an - inner loop that reads 3 words (i.e. 4 24-bit pixels), does a lot of - shifting and masking, then writes 2 words. -*/ static void gdk_rgb_convert_565 (GdkRgbInfo *image_info, GdkImage *image, gint x0, gint y0, gint width, gint height, @@ -1607,7 +1632,7 @@ gdk_rgb_convert_565 (GdkRgbInfo *image_info, GdkImage *image, } #endif -#ifdef HAIRY_CONVERT_565 +#if G_BYTE_ORDER == G_LITTLE_ENDIAN || defined(GDK_RGB_FAST_BE565_GRAY) static void gdk_rgb_convert_565_gray (GdkRgbInfo *image_info, GdkImage *image, gint x0, gint y0, gint width, gint height, @@ -1645,6 +1670,7 @@ gdk_rgb_convert_565_gray (GdkRgbInfo *image_info, GdkImage *image, guint32 g3g2g1g0; g3g2g1g0 = ((guint32 *)bp2)[0]; +#if G_BYTE_ORDER == G_LITTLE_ENDIAN ((guint32 *)obptr)[0] = ((g3g2g1g0 & 0xf8) << 8) | ((g3g2g1g0 & 0xfc) << 3) | @@ -1659,6 +1685,22 @@ gdk_rgb_convert_565_gray (GdkRgbInfo *image_info, GdkImage *image, (g3g2g1g0 & 0xf8000000) | ((g3g2g1g0 & 0xfc000000) >> 5) | ((g3g2g1g0 & 0xf8000000) >> 11); +#else + ((guint32 *)obptr)[0] = + (g3g2g1g0 & 0xf8000000) | + ((g3g2g1g0 & 0xfc000000) >> 5) | + ((g3g2g1g0 & 0xf8000000) >> 11) | + ((g3g2g1g0 & 0x00f80000) >> 8) | + ((g3g2g1g0 & 0x00fc0000) >> 13) | + ((g3g2g1g0 & 0x00f80000) >> 19); + ((guint32 *)obptr)[1] = + ((g3g2g1g0 & 0x0000f800) << 16) | + ((g3g2g1g0 & 0x0000fc00) << 11) | + ((g3g2g1g0 & 0x0000f800) << 5) | + ((g3g2g1g0 & 0x000000f8) << 8) | + ((g3g2g1g0 & 0x000000fc) << 3) | + ((g3g2g1g0 & 0x000000f8) >> 3); +#endif bp2 += 4; obptr += 8; } @@ -1745,7 +1787,7 @@ gdk_rgb_convert_565_br (GdkRgbInfo *image_info, GdkImage *image, /* Thanks to Ray Lehtiniemi for a patch that resulted in a ~25% speedup in this mode. */ -#ifdef HAIRY_CONVERT_565 +#if G_BYTE_ORDER == G_LITTLE_ENDIAN || defined(GDK_RGB_FAST_BE565_DITHER) static void gdk_rgb_convert_565_d (GdkRgbInfo *image_info, GdkImage *image, gint x0, gint y0, gint width, gint height, @@ -1800,6 +1842,7 @@ gdk_rgb_convert_565_d (GdkRgbInfo *image_info, GdkImage *image, r1b0g0r0 = ((guint32 *)bp2)[0]; g2r2b1g1 = ((guint32 *)bp2)[1]; b3g3r3b2 = ((guint32 *)bp2)[2]; +#if G_BYTE_ORDER == G_LITTLE_ENDIAN rgb02 = ((r1b0g0r0 & 0xff) << 20) + ((r1b0g0r0 & 0xff00) << 2) + @@ -1846,6 +1889,54 @@ gdk_rgb_convert_565_d (GdkRgbInfo *image_info, GdkImage *image, ((rgb13 & 0x0f800000) << 4) | ((rgb13 & 0x0003f000) << 9) | ((rgb13 & 0x000000f8) << 13); +#else + rgb02 = + ((r1b0g0r0 & 0xff000000) >> 4) + + ((r1b0g0r0 & 0x00ff0000) >> 6) + + ((r1b0g0r0 & 0x0000ff00) >> 8) + + dmp[x & (DM_WIDTH - 1)]; + rgb02 += 0x10040100 + - ((rgb02 & 0x1e0001e0) >> 5) + - ((rgb02 & 0x00070000) >> 6); + rgb13 = + ((r1b0g0r0 & 0x000000ff) << 20) + + ((g2r2b1g1 & 0xff000000) >> 14) + + ((g2r2b1g1 & 0x00ff0000) >> 16) + + dmp[(x + 1) & (DM_WIDTH - 1)]; + rgb13 += 0x10040100 + - ((rgb13 & 0x1e0001e0) >> 5) + - ((rgb13 & 0x00070000) >> 6); + ((guint32 *)obptr)[0] = + ((rgb02 & 0x0f800000) << 4) | + ((rgb02 & 0x0003f000) << 9) | + ((rgb02 & 0x000000f8) << 13) | + ((rgb13 & 0x0f800000) >> 12) | + ((rgb13 & 0x0003f000) >> 7) | + ((rgb13 & 0x000000f8) >> 3); + rgb02 = + ((g2r2b1g1 & 0x0000ff00) << 12) + + ((g2r2b1g1 & 0x000000ff) << 10) + + ((b3g3r3b2 & 0xff000000) >> 24) + + dmp[(x + 2) & (DM_WIDTH - 1)]; + rgb02 += 0x10040100 + - ((rgb02 & 0x1e0001e0) >> 5) + - ((rgb02 & 0x00070000) >> 6); + rgb13 = + ((b3g3r3b2 & 0x00ff0000) << 4) + + ((b3g3r3b2 & 0x0000ff00) << 2) + + (b3g3r3b2 & 0x000000ff) + + dmp[(x + 3) & (DM_WIDTH - 1)]; + rgb13 += 0x10040100 + - ((rgb13 & 0x1e0001e0) >> 5) + - ((rgb13 & 0x00070000) >> 6); + ((guint32 *)obptr)[1] = + ((rgb02 & 0x0f800000) << 4) | + ((rgb02 & 0x0003f000) << 9) | + ((rgb02 & 0x000000f8) << 13) | + ((rgb13 & 0x0f800000) >> 12) | + ((rgb13 & 0x0003f000) >> 7) | + ((rgb13 & 0x000000f8) >> 3); +#endif bp2 += 12; obptr += 8; } @@ -1916,6 +2007,10 @@ gdk_rgb_convert_565_d (GdkRgbInfo *image_info, GdkImage *image, } #endif +#undef GDK_RGB_FAST_BE565_RGB +#undef GDK_RGB_FAST_BE565_GRAY +#undef GDK_RGB_FAST_BE565_DITHER + static void gdk_rgb_convert_555 (GdkRgbInfo *image_info, GdkImage *image, gint x0, gint y0, gint width, gint height, @@ -1931,6 +2026,74 @@ gdk_rgb_convert_555 (GdkRgbInfo *image_info, GdkImage *image, bptr = buf; bpl = image->bpl; obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 2; + +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + /* GTK2_NG_WIDE_555 */ + if (width >= 32 && + ((((guintptr) obuf | + (guintptr) bptr | + (guintptr) rowstride | + (guintptr) bpl) & 3) == 0)) + { + for (y = 0; y < height; y++) + { + guchar *obptr; + + bp2 = bptr; + obptr = obuf; + + for (x = 0; x < width - 3; x += 4) + { + guint32 w0; + guint32 w1; + guint32 w2; + + w0 = ((const guint32 *) bp2)[0]; + w1 = ((const guint32 *) bp2)[1]; + w2 = ((const guint32 *) bp2)[2]; + + ((guint32 *) obptr)[0] = + ((w0 & 0x000000f8U) << 7) | + ((w0 & 0x0000f800U) >> 6) | + ((w0 & 0x00f80000U) >> 19) | + ((w0 & 0xf8000000U) >> 1) | + ((w1 & 0x000000f8U) << 18) | + ((w1 & 0x0000f800U) << 5); + + ((guint32 *) obptr)[1] = + ((w1 & 0x00f80000U) >> 9) | + ((w1 & 0xf8000000U) >> 22) | + ((w2 & 0x000000f8U) >> 3) | + ((w2 & 0x0000f800U) << 15) | + ((w2 & 0x00f80000U) << 2) | + ((w2 & 0xf8000000U) >> 11); + + bp2 += 12; + obptr += 8; + } + + for (; x < width; x++) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + + ((guint16 *) obptr)[0] = + ((r & 0xf8) << 7) | + ((g & 0xf8) << 2) | + (b >> 3); + + obptr += 2; + } + + bptr += rowstride; + obuf += bpl; + } + + return; + } +#endif + for (y = 0; y < height; y++) { bp2 = bptr; @@ -2143,10 +2306,21 @@ gdk_rgb_convert_0888 (GdkRgbInfo *image_info, GdkImage *image, w = width; while (w--) { +#if G_BYTE_ORDER == G_LITTLE_ENDIAN && GLIB_SIZEOF_VOID_P == 8 && \ + (defined(__x86_64__) || defined(__amd64__)) + guint32 pixel; + + pixel = 0xff000000U | + ((guint32) bp2[0] << 16) | + ((guint32) bp2[1] << 8) | + (guint32) bp2[2]; + memcpy (p, &pixel, sizeof (pixel)); +#else p[0] = bp2[2]; p[1] = bp2[1]; p[2] = bp2[0]; p[3] = 0xff; +#endif bp2 += 3; p += 4; } @@ -2242,6 +2416,68 @@ gdk_rgb_convert_8880_br (GdkRgbInfo *image_info, GdkImage *image, } } +#define DEFINE_GDK_RGB_CONVERT_101010(name, high, low, to_order) \ +static void \ +name (GdkRgbInfo *image_info, GdkImage *image, \ + gint x0, gint y0, gint width, gint height, \ + const guchar *buf, int rowstride, \ + gint x_align, gint y_align, GdkRgbCmap *cmap) \ +{ \ + int y, w; \ + guchar *obuf, *p; \ + gint bpl; \ + const guchar *bptr, *bp2; \ + guint32 r, g, b; \ + guint32 pixel; \ + guint32 alpha_mask; \ + \ + alpha_mask = image_info->visual->depth == 32 ? 0xc0000000U : 0; \ + \ + bptr = buf; \ + bpl = image->bpl; \ + obuf = ((guchar *) image->mem) + y0 * bpl + x0 * 4; \ + \ + for (y = 0; y < height; y++) \ + { \ + bp2 = bptr; \ + p = obuf; \ + w = width; \ + \ + while (w--) \ + { \ + r = *bp2++; \ + g = *bp2++; \ + b = *bp2++; \ + \ + r = (r << 2) | (r >> 6); \ + g = (g << 2) | (g >> 6); \ + b = (b << 2) | (b >> 6); \ + \ + pixel = alpha_mask | \ + (high << 20) | \ + (g << 10) | \ + low; \ + \ + *((guint32 *) p) = to_order (pixel); \ + p += 4; \ + } \ + \ + bptr += rowstride; \ + obuf += bpl; \ + } \ +} + +DEFINE_GDK_RGB_CONVERT_101010 (gdk_rgb_convert_101010_r_low_lsb, + b, r, GUINT32_TO_LE) +DEFINE_GDK_RGB_CONVERT_101010 (gdk_rgb_convert_101010_b_low_lsb, + r, b, GUINT32_TO_LE) +DEFINE_GDK_RGB_CONVERT_101010 (gdk_rgb_convert_101010_r_low_msb, + b, r, GUINT32_TO_BE) +DEFINE_GDK_RGB_CONVERT_101010 (gdk_rgb_convert_101010_b_low_msb, + r, b, GUINT32_TO_BE) + +#undef DEFINE_GDK_RGB_CONVERT_101010 + /* Generic truecolor/directcolor conversion function. Slow, but these are oddball modes. */ static void @@ -2555,7 +2791,7 @@ gdk_rgb_convert_4_pack (GdkRgbInfo *image_info, GdkImage *image, r = *bp2++; g = *bp2++; b = *bp2++; - dith = (dmp[(x_align + x + 1) & (DM_WIDTH - 1)] << 2) | 3; + dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) | 3; ix = (((r + dith) & 0x100) >> 2) | (((g + 258 - dith) & 0x100) >> 5) | (((b + dith) & 0x100) >> 8); @@ -2564,7 +2800,7 @@ gdk_rgb_convert_4_pack (GdkRgbInfo *image_info, GdkImage *image, obptr++; x++; } - while (x < width) + while (x + 1 < width) { r = *bp2++; g = *bp2++; @@ -2575,14 +2811,11 @@ gdk_rgb_convert_4_pack (GdkRgbInfo *image_info, GdkImage *image, (((b + dith) & 0x100) >> 8); pix0 = (colorcube_d[ix]); x++; - if (x == width) - pix1 = (*obptr & 0x0F); - else { r = *bp2++; g = *bp2++; b = *bp2++; - dith = (dmp[(x_align + x + 1) & (DM_WIDTH - 1)] << 2) | 3; + dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) | 3; ix = (((r + dith) & 0x100) >> 2) | (((g + 258 - dith) & 0x100) >> 5) | (((b + dith) & 0x100) >> 8); @@ -2591,11 +2824,91 @@ gdk_rgb_convert_4_pack (GdkRgbInfo *image_info, GdkImage *image, } *obptr++ = (pix0 << 4) | pix1; } + if (x < width) + { + r = *bp2++; + g = *bp2++; + b = *bp2++; + dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) | 3; + ix = (((r + dith) & 0x100) >> 2) | + (((g + 258 - dith) & 0x100) >> 5) | + (((b + dith) & 0x100) >> 8); + pix0 = (colorcube_d[ix]); + *obptr = (pix0 << 4) | (*obptr & 0x0F); + } bptr += rowstride; obuf += bpl; } } +#ifdef GDK_WINDOWING_X11 +#define GDK_RGB_4_PACK_LSB_PIXEL(pixel) \ + r = *bp2++; g = *bp2++; b = *bp2++; \ + dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) | 3; \ + ix = (((r + dith) & 0x100) >> 2) | \ + (((g + 258 - dith) & 0x100) >> 5) | \ + (((b + dith) & 0x100) >> 8); \ + pixel = colorcube_d[ix] + +static void +gdk_rgb_convert_4_pack_lsb (GdkRgbInfo *image_info, GdkImage *image, + gint x0, gint y0, gint width, gint height, + const guchar *buf, int rowstride, + gint x_align, gint y_align, + GdkRgbCmap *cmap) +{ + int x, y, ix; + gint bpl; + guchar *obuf, *obptr; + const guchar *bptr, *bp2; + gint r, g, b; + const guchar *dmp; + gint dith; + guchar *colorcube_d = image_info->colorcube_d; + guchar pix0, pix1; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + (x0 >> 1); + + for (y = 0; y < height; y++) + { + dmp = DM[(y_align + y) & (DM_HEIGHT - 1)]; + bp2 = bptr; + obptr = obuf; + x = 0; + + if (x0 & 1) + { + GDK_RGB_4_PACK_LSB_PIXEL (pix1); + *obptr = (*obptr & 0x0F) | (pix1 << 4); + obptr++; + x++; + } + + while (x + 1 < width) + { + GDK_RGB_4_PACK_LSB_PIXEL (pix0); + x++; + GDK_RGB_4_PACK_LSB_PIXEL (pix1); + x++; + *obptr++ = (pix1 << 4) | pix0; + } + + if (x < width) + { + GDK_RGB_4_PACK_LSB_PIXEL (pix0); + *obptr = (*obptr & 0xF0) | pix0; + } + + bptr += rowstride; + obuf += bpl; + } +} + +#undef GDK_RGB_4_PACK_LSB_PIXEL +#endif /* GDK_WINDOWING_X11 */ + /* This actually works for depths from 3 to 7 */ static void gdk_rgb_convert_gray4 (GdkRgbInfo *image_info, GdkImage *image, @@ -2644,7 +2957,7 @@ gdk_rgb_convert_gray4_pack (GdkRgbInfo *image_info, GdkImage *image, gint r, g, b; gint shift; guchar pix0, pix1; - /* todo: this is hardcoded to big-endian. Make endian-agile. */ + /* Pixel 0 is stored in the high nibble. */ bptr = buf; bpl = image->bpl; @@ -2690,6 +3003,60 @@ gdk_rgb_convert_gray4_pack (GdkRgbInfo *image_info, GdkImage *image, } } +#ifdef GDK_WINDOWING_X11 +#define GDK_RGB_DEFINE_GRAY4_PACK_LSB(name, DECLS, INIT, ROW, PIXEL) \ +static void \ +name (GdkRgbInfo *image_info, GdkImage *image, \ + gint x0, gint y0, gint width, gint height, \ + const guchar *buf, int rowstride, \ + gint x_align, gint y_align, GdkRgbCmap *cmap) \ +{ \ + int x, y; gint bpl; guchar *obuf, *obptr; \ + const guchar *bptr, *bp2; gint r, g, b; \ + DECLS guchar pix0, pix1; \ + bptr = buf; bpl = image->bpl; \ + obuf = ((guchar *)image->mem) + y0 * bpl + (x0 >> 1); INIT \ + for (y = 0; y < height; y++) \ + { \ + bp2 = bptr; obptr = obuf; ROW x = 0; \ + if (x0 & 1) \ + { \ + PIXEL (pix1); \ + *obptr = (*obptr & 0x0F) | (pix1 << 4); \ + obptr++; x++; \ + } \ + while (x < width) \ + { \ + PIXEL (pix0); x++; \ + if (x == width) \ + pix1 = (*obptr & 0xF0) >> 4; \ + else \ + { PIXEL (pix1); x++; } \ + *obptr++ = (pix1 << 4) | pix0; \ + } \ + bptr += rowstride; obuf += bpl; \ + } \ +} + +#define GDK_RGB_GRAY4_LSB_DECLS gint shift; +#define GDK_RGB_GRAY4_LSB_INIT shift = 9 - image_info->visual->depth; +#define GDK_RGB_GRAY4_LSB_ROW +#define GDK_RGB_GRAY4_LSB_PIXEL(pixel) \ + r = *bp2++; g = *bp2++; b = *bp2++; \ + pixel = (g + ((b + r) >> 1)) >> shift + +GDK_RGB_DEFINE_GRAY4_PACK_LSB (gdk_rgb_convert_gray4_pack_lsb, + GDK_RGB_GRAY4_LSB_DECLS, + GDK_RGB_GRAY4_LSB_INIT, + GDK_RGB_GRAY4_LSB_ROW, + GDK_RGB_GRAY4_LSB_PIXEL) + +#undef GDK_RGB_GRAY4_LSB_PIXEL +#undef GDK_RGB_GRAY4_LSB_ROW +#undef GDK_RGB_GRAY4_LSB_INIT +#undef GDK_RGB_GRAY4_LSB_DECLS +#endif /* GDK_WINDOWING_X11 */ + /* This actually works for depths from 3 to 7 */ static void gdk_rgb_convert_gray4_d (GdkRgbInfo *image_info, GdkImage *image, @@ -2746,7 +3113,7 @@ gdk_rgb_convert_gray4_d_pack (GdkRgbInfo *image_info, GdkImage *image, gint prec, right; gint gray; guchar pix0, pix1; - /* todo: this is hardcoded to big-endian. Make endian-agile. */ + /* Pixel 0 is stored in the high nibble. */ bptr = buf; bpl = image->bpl; @@ -2766,7 +3133,7 @@ gdk_rgb_convert_gray4_d_pack (GdkRgbInfo *image_info, GdkImage *image, g = *bp2++; b = *bp2++; gray = (g + ((b + r) >> 1)) >> 1; - gray += (dmp[(x_align + x + 1) & (DM_WIDTH - 1)] << 2) >> prec; + gray += (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) >> prec; pix1 = (gray - (gray >> prec)) >> right; *obptr = (*obptr & 0xF0) | pix1; obptr++; @@ -2789,7 +3156,7 @@ gdk_rgb_convert_gray4_d_pack (GdkRgbInfo *image_info, GdkImage *image, g = *bp2++; b = *bp2++; gray = (g + ((b + r) >> 1)) >> 1; - gray += (dmp[(x_align + x + 1) & (DM_WIDTH - 1)] << 2) >> prec; + gray += (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) >> prec; pix1 = (gray - (gray >> prec)) >> right; x++; } @@ -2800,6 +3167,32 @@ gdk_rgb_convert_gray4_d_pack (GdkRgbInfo *image_info, GdkImage *image, } } +#ifdef GDK_WINDOWING_X11 +#define GDK_RGB_GRAY4_D_LSB_DECLS \ + const guchar *dmp; gint prec, right, gray; +#define GDK_RGB_GRAY4_D_LSB_INIT \ + prec = image_info->visual->depth; right = 8 - prec; +#define GDK_RGB_GRAY4_D_LSB_ROW \ + dmp = DM[(y_align + y) & (DM_HEIGHT - 1)]; +#define GDK_RGB_GRAY4_D_LSB_PIXEL(pixel) \ + r = *bp2++; g = *bp2++; b = *bp2++; \ + gray = (g + ((b + r) >> 1)) >> 1; \ + gray += (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) >> prec; \ + pixel = (gray - (gray >> prec)) >> right + +GDK_RGB_DEFINE_GRAY4_PACK_LSB (gdk_rgb_convert_gray4_d_pack_lsb, + GDK_RGB_GRAY4_D_LSB_DECLS, + GDK_RGB_GRAY4_D_LSB_INIT, + GDK_RGB_GRAY4_D_LSB_ROW, + GDK_RGB_GRAY4_D_LSB_PIXEL) + +#undef GDK_RGB_GRAY4_D_LSB_PIXEL +#undef GDK_RGB_GRAY4_D_LSB_ROW +#undef GDK_RGB_GRAY4_D_LSB_INIT +#undef GDK_RGB_GRAY4_D_LSB_DECLS +#undef GDK_RGB_DEFINE_GRAY4_PACK_LSB +#endif /* GDK_WINDOWING_X11 */ + static void gdk_rgb_convert_1 (GdkRgbInfo *image_info, GdkImage *image, gint x0, gint y0, gint width, gint height, @@ -2854,6 +3247,83 @@ gdk_rgb_ensure_stage (GdkRgbInfo *image_info) return image_info->stage_buf; } +static void +gdk_rgb_convert_32_0888 (GdkRgbInfo *image_info, GdkImage *image, + gint x0, gint y0, gint width, gint height, + const guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int y, w; + guchar *obuf, *p; + gint bpl; + const guchar *bptr, *bp2; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 4; + for (y = 0; y < height; y++) + { + bp2 = bptr; + p = obuf; + w = width; + while (w--) + { +#if G_BYTE_ORDER == G_LITTLE_ENDIAN && GLIB_SIZEOF_VOID_P == 8 && \ + (defined(__x86_64__) || defined(__amd64__)) + guint32 pixel; + + pixel = 0xff000000U | + ((guint32) bp2[0] << 16) | + ((guint32) bp2[1] << 8) | + (guint32) bp2[2]; + memcpy (p, &pixel, sizeof (pixel)); +#else + p[0] = bp2[2]; + p[1] = bp2[1]; + p[2] = bp2[0]; + p[3] = 0xff; +#endif + bp2 += 4; + p += 4; + } + bptr += rowstride; + obuf += bpl; + } +} + +static void +gdk_rgb_convert_32_0888_br (GdkRgbInfo *image_info, GdkImage *image, + gint x0, gint y0, gint width, gint height, + const guchar *buf, int rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + int y, w; + guchar *obuf, *p; + gint bpl; + const guchar *bptr, *bp2; + + bptr = buf; + bpl = image->bpl; + obuf = ((guchar *)image->mem) + y0 * bpl + x0 * 4; + for (y = 0; y < height; y++) + { + bp2 = bptr; + p = obuf; + w = width; + while (w--) + { + p[0] = 0xff; + p[1] = bp2[0]; + p[2] = bp2[1]; + p[3] = bp2[2]; + bp2 += 4; + p += 4; + } + bptr += rowstride; + obuf += bpl; + } +} + /* This is slow. Speed me up, please. */ static void gdk_rgb_32_to_stage (GdkRgbInfo *image_info, @@ -2945,6 +3415,50 @@ gdk_rgb_gray_to_stage (GdkRgbInfo *image_info, /* Generic gray conversion function - convert to 24bit packed, then go from there. */ +static void +gdk_rgb_convert_gray_0888_native (GdkRgbInfo *image_info, GdkImage *image, + gint x0, gint y0, gint width, gint height, + const guchar *buf, gint rowstride, + gint x_align, gint y_align, GdkRgbCmap *cmap) +{ + gint y, w; + gint bpl = image->bpl; + guchar *obuf = ((guchar *) image->mem) + y0 * bpl + x0 * 4; + + for (y = 0; y < height; y++) + { + const guchar *p = buf; + guchar *q = obuf; + + w = width; + while (w--) + { + guchar g = *p++; + + /* + * Store bytes explicitly here. Word-store performance varies by + * microarchitecture even within one ISA, so keep this generic path + * free of CPU-specific runtime dispatch. + */ +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + q[0] = g; + q[1] = g; + q[2] = g; + q[3] = 0xff; +#else + q[0] = 0xff; + q[1] = g; + q[2] = g; + q[3] = g; +#endif + q += 4; + } + + buf += rowstride; + obuf += bpl; + } +} + static void gdk_rgb_convert_gray_generic (GdkRgbInfo *image_info, GdkImage *image, gint x0, gint y0, gint width, gint height, @@ -3195,6 +3709,34 @@ gdk_rgb_select_conv (GdkRgbInfo *image_info) #endif } #endif + else if (bpp == 32 && (depth == 30 || depth == 32) && + vtype == GDK_VISUAL_TRUE_COLOR && + byte_order == GDK_LSB_FIRST && + red_mask == 0x000003ff && + green_mask == 0x000ffc00 && + blue_mask == 0x3ff00000) + conv = gdk_rgb_convert_101010_r_low_lsb; + else if (bpp == 32 && (depth == 30 || depth == 32) && + vtype == GDK_VISUAL_TRUE_COLOR && + byte_order == GDK_LSB_FIRST && + red_mask == 0x3ff00000 && + green_mask == 0x000ffc00 && + blue_mask == 0x000003ff) + conv = gdk_rgb_convert_101010_b_low_lsb; + else if (bpp == 32 && (depth == 30 || depth == 32) && + vtype == GDK_VISUAL_TRUE_COLOR && + byte_order == GDK_MSB_FIRST && + red_mask == 0x000003ff && + green_mask == 0x000ffc00 && + blue_mask == 0x3ff00000) + conv = gdk_rgb_convert_101010_r_low_msb; + else if (bpp == 32 && (depth == 30 || depth == 32) && + vtype == GDK_VISUAL_TRUE_COLOR && + byte_order == GDK_MSB_FIRST && + red_mask == 0x3ff00000 && + green_mask == 0x000ffc00 && + blue_mask == 0x000003ff) + conv = gdk_rgb_convert_101010_b_low_msb; else if (vtype == GDK_VISUAL_TRUE_COLOR && byte_order == GDK_LSB_FIRST) { conv = gdk_rgb_convert_truecolor_lsb; @@ -3255,15 +3797,28 @@ gdk_rgb_select_conv (GdkRgbInfo *image_info) conv = gdk_rgb_convert_4; } else if (bpp == 4 && depth <= 4 && depth >= 2 && - (vtype == GDK_VISUAL_STATIC_GRAY - || vtype == GDK_VISUAL_GRAYSCALE)) + (vtype == GDK_VISUAL_STATIC_GRAY + || vtype == GDK_VISUAL_GRAYSCALE)) { conv = gdk_rgb_convert_gray4_pack; conv_d = gdk_rgb_convert_gray4_d_pack; +#ifdef GDK_WINDOWING_X11 + if (byte_order == GDK_LSB_FIRST) + { + conv = gdk_rgb_convert_gray4_pack_lsb; + conv_d = gdk_rgb_convert_gray4_d_pack_lsb; + } +#endif + } + else if (bpp == 4 && depth <= 4 && depth >= 2 && + vtype == GDK_VISUAL_STATIC_COLOR) + { + conv = gdk_rgb_convert_4_pack; +#ifdef GDK_WINDOWING_X11 + if (byte_order == GDK_LSB_FIRST) + conv = gdk_rgb_convert_4_pack_lsb; +#endif } - else if (bpp == 4 && depth == 4 && - vtype == GDK_VISUAL_STATIC_COLOR) - conv = gdk_rgb_convert_4_pack; if (!conv) g_error ("Visual type=%d depth=%d, image bpp=%d, %s first\n" @@ -3275,6 +3830,36 @@ gdk_rgb_select_conv (GdkRgbInfo *image_info) if (conv_d == NULL) conv_d = conv; + if (conv == gdk_rgb_convert_0888) + { + conv_32 = gdk_rgb_convert_32_0888; +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + conv_gray = gdk_rgb_convert_gray_0888_native; +#endif + } + else if (conv == gdk_rgb_convert_0888_br) + { + conv_32 = gdk_rgb_convert_32_0888_br; +#if G_BYTE_ORDER == G_BIG_ENDIAN + conv_gray = gdk_rgb_convert_gray_0888_native; +#endif + } + + if (conv_d == gdk_rgb_convert_0888) + { + conv_32_d = gdk_rgb_convert_32_0888; +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + conv_gray_d = gdk_rgb_convert_gray_0888_native; +#endif + } + else if (conv_d == gdk_rgb_convert_0888_br) + { + conv_32_d = gdk_rgb_convert_32_0888_br; +#if G_BYTE_ORDER == G_BIG_ENDIAN + conv_gray_d = gdk_rgb_convert_gray_0888_native; +#endif + } + image_info->conv = conv; image_info->conv_d = conv_d; @@ -3369,6 +3954,696 @@ gdk_rgb_get_info_from_drawable (GdkDrawable *drawable) return gdk_rgb_get_info_from_colormap (cmap); } + +/* High-depth RGB input. */ + +#define GDK_RGB16_STORE_RGB(p, r, g, b, a) G_STMT_START { \ + (p)[0] = (r) >> 8; \ + (p)[1] = (g) >> 8; \ + (p)[2] = (b) >> 8; \ + (p) += 3; \ +} G_STMT_END + +#define GDK_RGB16_STORE_BGR(p, r, g, b, a) G_STMT_START { \ + (p)[0] = (b) >> 8; \ + (p)[1] = (g) >> 8; \ + (p)[2] = (r) >> 8; \ + (p) += 3; \ +} G_STMT_END + +#define GDK_RGB16_STORE_BGRA(p, r, g, b, a) G_STMT_START { \ + (p)[0] = (b) >> 8; \ + (p)[1] = (g) >> 8; \ + (p)[2] = (r) >> 8; \ + (p)[3] = 0xff; \ + (p) += 4; \ +} G_STMT_END + +#define GDK_RGB16_STORE_ARGB(p, r, g, b, a) G_STMT_START { \ + (p)[0] = 0xff; \ + (p)[1] = (r) >> 8; \ + (p)[2] = (g) >> 8; \ + (p)[3] = (b) >> 8; \ + (p) += 4; \ +} G_STMT_END + +#define GDK_RGB16_STORE_RGB0_NATIVE(p, r, g, b, a) G_STMT_START { \ + guint32 pixel__ = (((b) >> 8) << 16) | \ + (((g) >> 8) << 8) | \ + ((r) >> 8); \ + memcpy ((p), &pixel__, sizeof (pixel__)); \ + (p) += 4; \ +} G_STMT_END + +#define GDK_RGB16_STORE_565(p, r, g, b, a) G_STMT_START { \ + guint16 pixel__ = ((r) & 0xf800) | \ + (((g) & 0xfc00) >> 5) | \ + ((b) >> 11); \ + memcpy ((p), &pixel__, sizeof (pixel__)); \ + (p) += 2; \ +} G_STMT_END + +#define GDK_RGB16_STORE_565_BR(p, r, g, b, a) G_STMT_START { \ + guint16 pixel__ = ((r) & 0xf800) | \ + (((g) & 0xfc00) >> 5) | \ + ((b) >> 11); \ + pixel__ = (pixel__ >> 8) | (pixel__ << 8); \ + memcpy ((p), &pixel__, sizeof (pixel__)); \ + (p) += 2; \ +} G_STMT_END + +#define GDK_RGB16_STORE_555(p, r, g, b, a) G_STMT_START { \ + guint16 pixel__ = (((r) & 0xf800) >> 1) | \ + (((g) & 0xf800) >> 6) | \ + ((b) >> 11); \ + memcpy ((p), &pixel__, sizeof (pixel__)); \ + (p) += 2; \ +} G_STMT_END + +#define GDK_RGB16_STORE_555_BR(p, r, g, b, a) G_STMT_START { \ + guint16 pixel__ = (((r) & 0xf800) >> 1) | \ + (((g) & 0xf800) >> 6) | \ + ((b) >> 11); \ + pixel__ = (pixel__ >> 8) | (pixel__ << 8); \ + memcpy ((p), &pixel__, sizeof (pixel__)); \ + (p) += 2; \ +} G_STMT_END + +#define GDK_RGB16_STORE_101010_R_LOW_LE(p, r, g, b, a) \ +G_STMT_START { \ + guint32 pixel__ = (a) | \ + (((b) >> 6) << 20) | \ + (((g) >> 6) << 10) | \ + ((r) >> 6); \ + pixel__ = GUINT32_TO_LE (pixel__); \ + memcpy ((p), &pixel__, sizeof (pixel__)); \ + (p) += 4; \ +} G_STMT_END + +#define GDK_RGB16_STORE_101010_B_LOW_LE(p, r, g, b, a) \ +G_STMT_START { \ + guint32 pixel__ = (a) | \ + (((r) >> 6) << 20) | \ + (((g) >> 6) << 10) | \ + ((b) >> 6); \ + pixel__ = GUINT32_TO_LE (pixel__); \ + memcpy ((p), &pixel__, sizeof (pixel__)); \ + (p) += 4; \ +} G_STMT_END + +#define GDK_RGB16_STORE_101010_R_LOW_BE(p, r, g, b, a) \ +G_STMT_START { \ + guint32 pixel__ = (a) | \ + (((b) >> 6) << 20) | \ + (((g) >> 6) << 10) | \ + ((r) >> 6); \ + pixel__ = GUINT32_TO_BE (pixel__); \ + memcpy ((p), &pixel__, sizeof (pixel__)); \ + (p) += 4; \ +} G_STMT_END + +#define GDK_RGB16_STORE_101010_B_LOW_BE(p, r, g, b, a) \ +G_STMT_START { \ + guint32 pixel__ = (a) | \ + (((r) >> 6) << 20) | \ + (((g) >> 6) << 10) | \ + ((b) >> 6); \ + pixel__ = GUINT32_TO_BE (pixel__); \ + memcpy ((p), &pixel__, sizeof (pixel__)); \ + (p) += 4; \ +} G_STMT_END + +#define DEFINE_GDK_RGB16_CONVERTER(name, words, pixel_bytes, store) \ +static void \ +name (GdkRgbInfo *image_info, \ + GdkImage *image, \ + gint x0, \ + gint y0, \ + gint width, \ + gint height, \ + const guchar *buf, \ + gint rowstride, \ + gint x_align, \ + gint y_align, \ + GdkRgbCmap *cmap) \ +{ \ + const guchar *row = buf; \ + const guint16 *src; \ + guchar *dst_row; \ + guchar *dst; \ + guint32 r, g, b; \ + guint32 alpha_mask; \ + gint x, y; \ + \ + (void) image_info; \ + (void) x_align; \ + (void) y_align; \ + (void) cmap; \ + \ + dst_row = ((guchar *) image->mem) + \ + y0 * image->bpl + x0 * (pixel_bytes); \ + alpha_mask = image->depth == 32 ? 0xc0000000U : 0; \ + (void) alpha_mask; \ + \ + for (y = 0; y < height; y++) \ + { \ + src = (const guint16 *) row; \ + dst = dst_row; \ + \ + for (x = 0; x < width; x++) \ + { \ + r = src[0]; \ + g = src[1]; \ + b = src[2]; \ + src += (words); \ + store (dst, r, g, b, alpha_mask); \ + } \ + \ + row += rowstride; \ + dst_row += image->bpl; \ + } \ +} + +#define DEFINE_GDK_RGB16_PAIR(suffix, pixel_bytes, store) \ + DEFINE_GDK_RGB16_CONVERTER (gdk_rgb48_convert_ ## suffix, \ + 3, pixel_bytes, store) \ + DEFINE_GDK_RGB16_CONVERTER (gdk_rgbx64_convert_ ## suffix, \ + 4, pixel_bytes, store) + +DEFINE_GDK_RGB16_PAIR (rgb, 3, GDK_RGB16_STORE_RGB) +DEFINE_GDK_RGB16_PAIR (bgr, 3, GDK_RGB16_STORE_BGR) +DEFINE_GDK_RGB16_PAIR (bgra, 4, GDK_RGB16_STORE_BGRA) +DEFINE_GDK_RGB16_PAIR (argb, 4, GDK_RGB16_STORE_ARGB) +DEFINE_GDK_RGB16_PAIR (rgb0_native, 4, GDK_RGB16_STORE_RGB0_NATIVE) +DEFINE_GDK_RGB16_PAIR (565, 2, GDK_RGB16_STORE_565) +DEFINE_GDK_RGB16_PAIR (565_br, 2, GDK_RGB16_STORE_565_BR) +DEFINE_GDK_RGB16_PAIR (555, 2, GDK_RGB16_STORE_555) +DEFINE_GDK_RGB16_PAIR (555_br, 2, GDK_RGB16_STORE_555_BR) +DEFINE_GDK_RGB16_PAIR (101010_r_low_le, 4, + GDK_RGB16_STORE_101010_R_LOW_LE) +DEFINE_GDK_RGB16_PAIR (101010_b_low_le, 4, + GDK_RGB16_STORE_101010_B_LOW_LE) +DEFINE_GDK_RGB16_PAIR (101010_r_low_be, 4, + GDK_RGB16_STORE_101010_R_LOW_BE) +DEFINE_GDK_RGB16_PAIR (101010_b_low_be, 4, + GDK_RGB16_STORE_101010_B_LOW_BE) + +#undef DEFINE_GDK_RGB16_PAIR +#undef DEFINE_GDK_RGB16_CONVERTER + +#undef GDK_RGB16_STORE_RGB +#undef GDK_RGB16_STORE_BGR +#undef GDK_RGB16_STORE_BGRA +#undef GDK_RGB16_STORE_ARGB +#undef GDK_RGB16_STORE_RGB0_NATIVE +#undef GDK_RGB16_STORE_565 +#undef GDK_RGB16_STORE_565_BR +#undef GDK_RGB16_STORE_555 +#undef GDK_RGB16_STORE_555_BR +#undef GDK_RGB16_STORE_101010_R_LOW_LE +#undef GDK_RGB16_STORE_101010_B_LOW_LE +#undef GDK_RGB16_STORE_101010_R_LOW_BE +#undef GDK_RGB16_STORE_101010_B_LOW_BE + +static void +gdk_rgb16_to_stage (GdkRgbInfo *image_info, + const guchar *buf, + gint rowstride, + gint width, + gint height, + gint words) +{ + const guchar *row = buf; + const guint16 *src; + guchar *dst_row = gdk_rgb_ensure_stage (image_info); + guchar *dst; + gint x, y; + + for (y = 0; y < height; y++) + { + src = (const guint16 *) row; + dst = dst_row; + + for (x = 0; x < width; x++) + { + *dst++ = src[0] >> 8; + *dst++ = src[1] >> 8; + *dst++ = src[2] >> 8; + src += words; + } + + row += rowstride; + dst_row += STAGE_ROWSTRIDE; + } +} + +static void +gdk_draw_rgb16_fallback (GdkRgbInfo *image_info, + GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y, + gint width, + gint height, + const guchar *buf, + gint words, + gint rowstride, + GdkRgbConvFunc conv, + gint xdith, + gint ydith) +{ + GdkScreen *screen; + GdkImage *image; + const guchar *buf_ptr; + gint depth; + gint x0, y0; + gint xs0, ys0; + gint width1, height1; + + if (image_info->bitmap) + { + if (image_info->own_gc == NULL) + image_info->own_gc = gdk_gc_new (drawable); + + gc = image_info->own_gc; + } + + screen = gdk_drawable_get_screen (drawable); + depth = image_info->visual->depth; + + for (y0 = 0; y0 < height; y0 += GDK_SCRATCH_IMAGE_HEIGHT) + { + height1 = MIN (height - y0, GDK_SCRATCH_IMAGE_HEIGHT); + + for (x0 = 0; x0 < width; x0 += GDK_SCRATCH_IMAGE_WIDTH) + { + width1 = MIN (width - x0, GDK_SCRATCH_IMAGE_WIDTH); + + buf_ptr = buf + (gssize) y0 * rowstride + + x0 * words * sizeof (guint16); + + gdk_rgb16_to_stage (image_info, + buf_ptr, + rowstride, + width1, + height1, + words); + + image = _gdk_image_get_scratch (screen, + width1, + height1, + depth, + &xs0, + &ys0); + + conv (image_info, + image, + xs0, ys0, + width1, height1, + image_info->stage_buf, + STAGE_ROWSTRIDE, + x + x0 + xdith, + y + y0 + ydith, + NULL); + +#ifndef DONT_ACTUALLY_DRAW + gdk_draw_image (drawable, + gc, + image, + xs0, ys0, + x + x0, y + y0, + width1, height1); +#endif + } + } +} + +static GdkRgbConvFunc +gdk_rgb16_select_converter (GdkRgbInfo *image_info, + gboolean is_rgbx) +{ + GdkVisual *visual = image_info->visual; + GdkByteOrder byte_order; + guint32 red_mask, green_mask, blue_mask; + gint depth; + gint bits_per_pixel; + gboolean byte_reversed; + gboolean mask_rgb; + gboolean mask_bgr; + +#define SELECT_PAIR(suffix) \ + return is_rgbx ? gdk_rgbx64_convert_ ## suffix \ + : gdk_rgb48_convert_ ## suffix + + if (visual->type != GDK_VISUAL_TRUE_COLOR) + return NULL; + + depth = visual->depth; + byte_order = visual->byte_order; + red_mask = visual->red_mask; + green_mask = visual->green_mask; + blue_mask = visual->blue_mask; + bits_per_pixel = image_info->bpp * 8; + +#if G_BYTE_ORDER == G_BIG_ENDIAN + byte_reversed = byte_order == GDK_LSB_FIRST; +#else + byte_reversed = byte_order == GDK_MSB_FIRST; +#endif + + mask_rgb = red_mask == 0xff0000 && + green_mask == 0x00ff00 && + blue_mask == 0x0000ff; + + mask_bgr = red_mask == 0x0000ff && + green_mask == 0x00ff00 && + blue_mask == 0xff0000; + + if (bits_per_pixel == 16 && depth == 16 && + red_mask == 0xf800 && green_mask == 0x07e0 && + blue_mask == 0x001f) + { + if (byte_reversed) + SELECT_PAIR (565_br); + SELECT_PAIR (565); + } + + if (bits_per_pixel == 16 && depth == 15 && + red_mask == 0x7c00 && green_mask == 0x03e0 && + blue_mask == 0x001f) + { + if (byte_reversed) + SELECT_PAIR (555_br); + SELECT_PAIR (555); + } + + if (bits_per_pixel == 24 && depth == 24 && + ((mask_rgb && byte_order == GDK_LSB_FIRST) || + (mask_bgr && byte_order == GDK_MSB_FIRST))) + SELECT_PAIR (bgr); + + if (bits_per_pixel == 24 && depth == 24 && + ((mask_rgb && byte_order == GDK_MSB_FIRST) || + (mask_bgr && byte_order == GDK_LSB_FIRST))) + SELECT_PAIR (rgb); + + if (bits_per_pixel == 32 && + (depth == 24 || depth == 32) && + mask_rgb && byte_order == GDK_MSB_FIRST) + SELECT_PAIR (argb); + + if (bits_per_pixel == 32 && + (depth == 24 || depth == 32) && + mask_rgb && byte_order == GDK_LSB_FIRST) + SELECT_PAIR (bgra); + +#if G_BYTE_ORDER == G_BIG_ENDIAN + if (bits_per_pixel == 32 && depth == 24 && + mask_bgr && byte_order == GDK_MSB_FIRST) + SELECT_PAIR (rgb0_native); +#else + if (bits_per_pixel == 32 && depth == 24 && + mask_bgr && byte_order == GDK_LSB_FIRST) + SELECT_PAIR (rgb0_native); +#endif + + if (bits_per_pixel == 32 && + (depth == 30 || depth == 32) && + byte_order == GDK_LSB_FIRST && + red_mask == 0x000003ff && + green_mask == 0x000ffc00 && + blue_mask == 0x3ff00000) + SELECT_PAIR (101010_r_low_le); + + if (bits_per_pixel == 32 && + (depth == 30 || depth == 32) && + byte_order == GDK_LSB_FIRST && + red_mask == 0x3ff00000 && + green_mask == 0x000ffc00 && + blue_mask == 0x000003ff) + SELECT_PAIR (101010_b_low_le); + + if (bits_per_pixel == 32 && + (depth == 30 || depth == 32) && + byte_order == GDK_MSB_FIRST && + red_mask == 0x000003ff && + green_mask == 0x000ffc00 && + blue_mask == 0x3ff00000) + SELECT_PAIR (101010_r_low_be); + + if (bits_per_pixel == 32 && + (depth == 30 || depth == 32) && + byte_order == GDK_MSB_FIRST && + red_mask == 0x3ff00000 && + green_mask == 0x000ffc00 && + blue_mask == 0x000003ff) + SELECT_PAIR (101010_b_low_be); + +#undef SELECT_PAIR + return NULL; +} + +static void +gdk_draw_rgb16_image (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y, + gint width, + gint height, + GdkRgbDither dith, + const guint16 *buf, + gint rowstride, + gint xdith, + gint ydith, + gboolean is_rgbx) +{ + GdkRgbInfo *image_info; + GdkRgbConvFunc converter; + gint words; + gboolean dithered; + + g_return_if_fail (GDK_IS_DRAWABLE (drawable)); + g_return_if_fail (GDK_IS_GC (gc)); + g_return_if_fail (buf != NULL); + g_return_if_fail ((((guintptr) buf) & 1) == 0); + g_return_if_fail ((rowstride & 1) == 0); + + if (width <= 0 || height <= 0) + return; + + image_info = gdk_rgb_get_info_from_drawable (drawable); + if (image_info == NULL) + return; + + words = is_rgbx ? 4 : 3; + converter = NULL; + + if (dith == GDK_RGB_DITHER_NONE || + dith == GDK_RGB_DITHER_NORMAL) + converter = gdk_rgb16_select_converter (image_info, is_rgbx); + + if (converter != NULL) + { + gdk_draw_rgb_image_core (image_info, + drawable, + gc, + x, y, + width, height, + (const guchar *) buf, + words * sizeof (guint16), + rowstride, + converter, + NULL, + xdith, ydith); + return; + } + + dithered = + !(dith == GDK_RGB_DITHER_NONE || + (dith == GDK_RGB_DITHER_NORMAL && + !image_info->dith_default)); + + converter = dithered ? image_info->conv_d + : image_info->conv; + + gdk_draw_rgb16_fallback (image_info, + drawable, + gc, + x, y, + width, height, + (const guchar *) buf, + words, + rowstride, + converter, + xdith, ydith); +} + +/** + * gdk_draw_rgb_48_image: + * @drawable: a #GdkDrawable + * @gc: a #GdkGC + * @x: destination X coordinate + * @y: destination Y coordinate + * @width: image width + * @height: image height + * @dith: dithering mode + * @rgb_buf: host-endian RGB data with three 16-bit channels per pixel + * @rowstride: number of bytes between consecutive rows + * + * Draws 48-bit RGB image data. + **/ +void +gdk_draw_rgb_48_image (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y, + gint width, + gint height, + GdkRgbDither dith, + const guint16 *rgb_buf, + gint rowstride) +{ + gdk_draw_rgb16_image (drawable, + gc, + x, + y, + width, + height, + dith, + rgb_buf, + rowstride, + 0, + 0, + FALSE); +} + +/** + * gdk_draw_rgb_48_image_dithalign: + * @drawable: a #GdkDrawable + * @gc: a #GdkGC + * @x: destination X coordinate + * @y: destination Y coordinate + * @width: image width + * @height: image height + * @dith: dithering mode + * @rgb_buf: host-endian RGB data with three 16-bit channels per pixel + * @rowstride: number of bytes between consecutive rows + * @xdith: X dither offset + * @ydith: Y dither offset + * + * Draws 48-bit RGB image data with explicit dither alignment. + **/ +void +gdk_draw_rgb_48_image_dithalign (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y, + gint width, + gint height, + GdkRgbDither dith, + const guint16 *rgb_buf, + gint rowstride, + gint xdith, + gint ydith) +{ + gdk_draw_rgb16_image (drawable, + gc, + x, + y, + width, + height, + dith, + rgb_buf, + rowstride, + xdith, + ydith, + FALSE); +} + +/** + * gdk_draw_rgbx_64_image: + * @drawable: a #GdkDrawable + * @gc: a #GdkGC + * @x: destination X coordinate + * @y: destination Y coordinate + * @width: image width + * @height: image height + * @dith: dithering mode + * @rgbx_buf: host-endian RGBX data with four 16-bit channels per pixel + * @rowstride: number of bytes between consecutive rows + * + * Draws 64-bit RGBX image data. The X channel is ignored. + **/ +void +gdk_draw_rgbx_64_image (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y, + gint width, + gint height, + GdkRgbDither dith, + const guint16 *rgbx_buf, + gint rowstride) +{ + gdk_draw_rgb16_image (drawable, + gc, + x, + y, + width, + height, + dith, + rgbx_buf, + rowstride, + 0, + 0, + TRUE); +} + +/** + * gdk_draw_rgbx_64_image_dithalign: + * @drawable: a #GdkDrawable + * @gc: a #GdkGC + * @x: destination X coordinate + * @y: destination Y coordinate + * @width: image width + * @height: image height + * @dith: dithering mode + * @rgbx_buf: host-endian RGBX data with four 16-bit channels per pixel + * @rowstride: number of bytes between consecutive rows + * @xdith: X dither offset + * @ydith: Y dither offset + * + * Draws 64-bit RGBX image data with explicit dither alignment. + * The X channel is ignored. + **/ +void +gdk_draw_rgbx_64_image_dithalign (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y, + gint width, + gint height, + GdkRgbDither dith, + const guint16 *rgbx_buf, + gint rowstride, + gint xdith, + gint ydith) +{ + gdk_draw_rgb16_image (drawable, + gc, + x, + y, + width, + height, + dith, + rgbx_buf, + rowstride, + xdith, + ydith, + TRUE); +} + + void gdk_draw_rgb_image (GdkDrawable *drawable, GdkGC *gc, diff --git a/gdk/gdkrgb.h b/gdk/gdkrgb.h index dd71d403f..44c576fb5 100644 --- a/gdk/gdkrgb.h +++ b/gdk/gdkrgb.h @@ -147,6 +147,48 @@ gboolean gdk_rgb_colormap_ditherable (GdkColormap *cmap); #endif #endif /* GDK_DISABLE_DEPRECATED */ +void gdk_draw_rgb_48_image (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y, + gint width, + gint height, + GdkRgbDither dith, + const guint16 *rgb_buf, + gint rowstride); +void gdk_draw_rgb_48_image_dithalign (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y, + gint width, + gint height, + GdkRgbDither dith, + const guint16 *rgb_buf, + gint rowstride, + gint xdith, + gint ydith); +void gdk_draw_rgbx_64_image (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y, + gint width, + gint height, + GdkRgbDither dith, + const guint16 *rgbx_buf, + gint rowstride); +void gdk_draw_rgbx_64_image_dithalign + (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y, + gint width, + gint height, + GdkRgbDither dith, + const guint16 *rgbx_buf, + gint rowstride, + gint xdith, + gint ydith); + G_END_DECLS diff --git a/gdk/makefile.msc b/gdk/makefile.msc index e9f816931..446182bf5 100644 --- a/gdk/makefile.msc +++ b/gdk/makefile.msc @@ -72,6 +72,9 @@ gdk_OBJECTS = \ gdkdisplaymanager.obj \ gdkdnd.obj \ gdkdraw.obj \ + gdkpixelops.obj \ + gdkpixelops-generic.obj \ + gdkpixelops-x86.obj \ gdkenumtypes.obj \ gdkevents.obj \ gdkfont.obj \ diff --git a/gdk/makegdkalias.pl b/gdk/makegdkalias.pl index 97a6e6007..27646cc0a 100755 --- a/gdk/makegdkalias.pl +++ b/gdk/makegdkalias.pl @@ -14,7 +14,7 @@ print < -#ifdef G_HAVE_GNUC_VISIBILITY +#if defined(G_HAVE_GNUC_VISIBILITY) && !defined(__APPLE__) EOF diff --git a/gdk/quartz/GdkQuartzView.c b/gdk/quartz/GdkQuartzView.c index 368e040ec..bad737da2 100644 --- a/gdk/quartz/GdkQuartzView.c +++ b/gdk/quartz/GdkQuartzView.c @@ -599,6 +599,25 @@ gdk_screen_get_rgba_colormap (_gdk_screen); } +-(void)viewWillDraw +{ + /* macOS 11 (Big Sur) and newer may use a higher precision backing + * format for layer contents. For GTK2's 8-bit drawing this can add + * avoidable conversion overhead. Use a dynamic Objective-C call here + * instead of a hard QuartzCore/CALayer dependency, so old SDKs and old + * macOS targets keep building and keep their old behaviour. + */ + if (gdk_quartz_osx_version () >= GDK_OSX_BIG_SUR) + { + id layer = [self layer]; + + if (layer && [layer respondsToSelector: @selector(setContentsFormat:)]) + [layer setValue: @"RGBA8Uint" forKey: @"contentsFormat"]; + } + + [super viewWillDraw]; +} + -(void)drawRect: (NSRect)rect { GdkRectangle gdk_rect; diff --git a/gdk/quartz/gdkdrawable-quartz.c b/gdk/quartz/gdkdrawable-quartz.c index 11dd12737..eb520f08d 100644 --- a/gdk/quartz/gdkdrawable-quartz.c +++ b/gdk/quartz/gdkdrawable-quartz.c @@ -893,7 +893,8 @@ gdk_quartz_drawable_release_context (GdkDrawable *drawable, if (window_impl->in_paint_rect_count == 0) { _gdk_quartz_drawable_flush (drawable); - [window_impl->view unlockFocus]; + if (gdk_quartz_osx_version () < GDK_OSX_MOJAVE) + [window_impl->view unlockFocus]; } } else if (GDK_IS_PIXMAP_IMPL_QUARTZ (drawable)) diff --git a/gdk/quartz/gdkglobals-quartz.c b/gdk/quartz/gdkglobals-quartz.c index f013f2830..4e596eef5 100644 --- a/gdk/quartz/gdkglobals-quartz.c +++ b/gdk/quartz/gdkglobals-quartz.c @@ -34,9 +34,20 @@ gdk_quartz_osx_version (void) if (minor == GDK_OSX_UNSUPPORTED) { - OSErr err = Gestalt (gestaltSystemVersionMinor, (SInt32*)&minor); + gint32 major = GDK_OSX_UNSUPPORTED; + OSErr err = Gestalt (gestaltSystemVersionMajor, (SInt32*)&major); g_return_val_if_fail (err == noErr, GDK_OSX_UNSUPPORTED); + + err = Gestalt (gestaltSystemVersionMinor, (SInt32*)&minor); + g_return_val_if_fail (err == noErr, GDK_OSX_UNSUPPORTED); + + /* GTK2 encodes macOS 10.x releases by their minor version. + * Map macOS 11+ into the same sequence: + * 11 -> 16, 12 -> 17, 13 -> 18, ... + */ + if (major > 10) + minor = major + 5; } if (minor < GDK_OSX_MIN) diff --git a/gdk/quartz/gdkinput.c b/gdk/quartz/gdkinput.c index 100574e9e..3ce3f2470 100644 --- a/gdk/quartz/gdkinput.c +++ b/gdk/quartz/gdkinput.c @@ -235,8 +235,6 @@ gdk_device_set_axis_use (GdkDevice *device, guint index, GdkAxisUse use) { -#if 0 - /* Remapping axes is unsupported for now */ g_return_if_fail (device != NULL); g_return_if_fail (index < device->num_axes); @@ -259,7 +257,6 @@ gdk_device_set_axis_use (GdkDevice *device, device->axes[index].max = 1; break; } -#endif } /** diff --git a/gdk/quartz/gdkquartz.h b/gdk/quartz/gdkquartz.h index 8206db019..42aac50b9 100644 --- a/gdk/quartz/gdkquartz.h +++ b/gdk/quartz/gdkquartz.h @@ -54,7 +54,13 @@ typedef enum GDK_OSX_SIERRA = 12, GDK_OSX_HIGH_SIERRA = 13, GDK_OSX_MOJAVE = 14, - GDK_OSX_CURRENT = 14, + GDK_OSX_CATALINA = 15, + GDK_OSX_BIG_SUR = 16, + GDK_OSX_MONTEREY = 17, + GDK_OSX_VENTURA = 18, + GDK_OSX_SONOMA = 19, + GDK_OSX_SEQUOIA = 20, + GDK_OSX_CURRENT = 20, GDK_OSX_NEW = 99 } GdkOSXVersion; diff --git a/gdk/quartz/gdkwindow-quartz.c b/gdk/quartz/gdkwindow-quartz.c index 6c7a2facb..38ada80b2 100644 --- a/gdk/quartz/gdkwindow-quartz.c +++ b/gdk/quartz/gdkwindow-quartz.c @@ -104,7 +104,8 @@ gdk_window_impl_quartz_get_context (GdkDrawable *drawable, * and for widgets that send fake expose events like the arrow * buttons in spinbuttons or the position marker in rulers. */ - if (window_impl->in_paint_rect_count == 0) + if (window_impl->in_paint_rect_count == 0 && + gdk_quartz_osx_version () < GDK_OSX_MOJAVE) { if (![window_impl->view lockFocusIfCanDraw]) return NULL; @@ -468,7 +469,8 @@ _gdk_windowing_before_process_all_updates (void) { in_process_all_updates = TRUE; - NSDisableScreenUpdates (); + if (gdk_quartz_osx_version () < GDK_OSX_MOJAVE) + NSDisableScreenUpdates (); } void @@ -489,8 +491,9 @@ _gdk_windowing_after_process_all_updates (void) /* 10.14 needs to be told that the view needs to be redrawn, see * https://gitlab.gnome.org/GNOME/gtk/issues/1479 */ - if (gdk_quartz_osx_version() >= GDK_OSX_MOJAVE) - [[nswindow contentView] setNeedsDisplay:YES]; + if (gdk_quartz_osx_version () >= GDK_OSX_MOJAVE && + gdk_quartz_osx_version () < GDK_OSX_BIG_SUR) + [[nswindow contentView] setNeedsDisplay:YES]; [nswindow enableFlushWindow]; [nswindow flushWindow]; [nswindow release]; @@ -502,7 +505,8 @@ _gdk_windowing_after_process_all_updates (void) in_process_all_updates = FALSE; - NSEnableScreenUpdates (); + if (gdk_quartz_osx_version () < GDK_OSX_MOJAVE) + NSEnableScreenUpdates (); } static void diff --git a/gdk/win32/gdkgc-win32.c b/gdk/win32/gdkgc-win32.c index 703e05a58..93d7da14e 100644 --- a/gdk/win32/gdkgc-win32.c +++ b/gdk/win32/gdkgc-win32.c @@ -173,10 +173,10 @@ fixup_pen (GdkGCWin32 *win32_gc) win32_gc->pen_num_dashes = 1; } - if (!(win32_gc->pen_style & PS_TYPE_MASK) == PS_GEOMETRIC && + if (!(win32_gc->pen_style & PS_TYPE_MASK) && win32_gc->pen_dashes[0] == 1 && (win32_gc->pen_num_dashes == 1 || - (win32_gc->pen_num_dashes == 2 && win32_gc->pen_dashes[0] == 1))) + (win32_gc->pen_num_dashes == 2 && win32_gc->pen_dashes[1] == 1))) win32_gc->pen_style |= PS_ALTERNATE; else win32_gc->pen_style |= PS_USERSTYLE; @@ -744,17 +744,21 @@ predraw (GdkGC *gc, static GdkDrawableImplWin32 * get_impl_drawable (GdkDrawable *drawable) { - if (GDK_IS_OFFSCREEN_WINDOW (drawable)) - return _gdk_offscreen_window_get_real_drawable (GDK_OFFSCREEN_WINDOW (drawable)); - if (GDK_IS_DRAWABLE_IMPL_WIN32 (drawable)) - return GDK_DRAWABLE_IMPL_WIN32(drawable); - else if (GDK_IS_WINDOW (drawable)) - return GDK_DRAWABLE_IMPL_WIN32 ((GDK_WINDOW_OBJECT (drawable))->impl); - else if (GDK_IS_PIXMAP (drawable)) - return GDK_DRAWABLE_IMPL_WIN32 ((GDK_PIXMAP_OBJECT (drawable))->impl); - else - g_assert_not_reached (); + if (GDK_IS_WINDOW (drawable)) + drawable = GDK_DRAWABLE ((GDK_WINDOW_OBJECT (drawable))->impl); + if (GDK_IS_OFFSCREEN_WINDOW (drawable)) + drawable = + _gdk_offscreen_window_get_real_drawable + (GDK_OFFSCREEN_WINDOW (drawable)); + + if (GDK_IS_PIXMAP (drawable)) + drawable = GDK_DRAWABLE ((GDK_PIXMAP_OBJECT (drawable))->impl); + + if (GDK_IS_DRAWABLE_IMPL_WIN32 (drawable)) + return GDK_DRAWABLE_IMPL_WIN32 (drawable); + + g_assert_not_reached (); return NULL; } diff --git a/gdk/win32/gdkimage-win32.c b/gdk/win32/gdkimage-win32.c index 8afa53f35..193a7a37f 100644 --- a/gdk/win32/gdkimage-win32.c +++ b/gdk/win32/gdkimage-win32.c @@ -128,33 +128,11 @@ _gdk_win32_new_image (GdkVisual *visual, image->height = height; image->depth = depth; image->bits_per_pixel = _gdk_windowing_get_bits_for_depth (gdk_display_get_default (), depth); - switch (depth) - { - case 1: - case 4: - case 5: - case 6: - case 7: - case 8: - image->bpp = 1; - break; - case 15: - case 16: - image->bpp = 2; - break; - case 24: - image->bpp = image->bits_per_pixel / 8; - break; - case 32: - image->bpp = 4; - break; - default: - g_warning ("_gdk_win32_new_image: depth=%d", image->depth); - g_assert_not_reached (); - } - if (depth == 1) + /* Keep logical depth separate from the native DIB storage size. */ + image->bpp = (image->bits_per_pixel + 7) / 8; + if (image->bits_per_pixel == 1) image->bpl = ((width - 1)/32 + 1)*4; - else if (depth == 4) + else if (image->bits_per_pixel == 4) image->bpl = ((width - 1)/8 + 1)*4; else image->bpl = ((width*image->bpp - 1)/4 + 1)*4; @@ -285,10 +263,10 @@ gdk_image_get_pixel (GdkImage *image, if (!(x >= 0 && x < image->width && y >= 0 && y < image->height)) return 0; - if (image->depth == 1) + if (image->bits_per_pixel == 1) return (((guchar *) image->mem)[y * image->bpl + (x >> 3)] & (1 << (7 - (x & 0x7)))) != 0; - if (image->depth == 4) + if (image->bits_per_pixel == 4) { pixelp = (guchar *) image->mem + y * image->bpl + (x >> 1); if (x&1) @@ -334,12 +312,12 @@ gdk_image_put_pixel (GdkImage *image, return; GdiFlush (); - if (image->depth == 1) + if (image->bits_per_pixel == 1) if (pixel & 1) ((guchar *) image->mem)[y * image->bpl + (x >> 3)] |= (1 << (7 - (x & 0x7))); else ((guchar *) image->mem)[y * image->bpl + (x >> 3)] &= ~(1 << (7 - (x & 0x7))); - else if (image->depth == 4) + else if (image->bits_per_pixel == 4) { pixelp = (guchar *) image->mem + y * image->bpl + (x >> 1); diff --git a/gdk/win32/gdkkeys-win32.c b/gdk/win32/gdkkeys-win32.c index d8ab30347..9a34083c4 100644 --- a/gdk/win32/gdkkeys-win32.c +++ b/gdk/win32/gdkkeys-win32.c @@ -692,6 +692,7 @@ update_keymap (GdkKeymap *gdk_keymap) if (hkls_len != keymap->layout_handles->len) keymap->keysym_tab = g_renew (guint, keymap->keysym_tab, keysym_tab_size); + memset (key_state, 0, sizeof(key_state)); memset (keymap->keysym_tab, 0, keysym_tab_size); g_array_set_size (keymap->layout_handles, hkls_len); g_array_set_size (keymap->options, hkls_len); diff --git a/gdk/win32/gdkpixmap-win32.c b/gdk/win32/gdkpixmap-win32.c index 08f9e9abb..c483c856f 100644 --- a/gdk/win32/gdkpixmap-win32.c +++ b/gdk/win32/gdkpixmap-win32.c @@ -191,6 +191,12 @@ _gdk_pixmap_new (GdkDrawable *drawable, format = CAIRO_FORMAT_A1; break; + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: case 8: format = CAIRO_FORMAT_A8; break; @@ -228,7 +234,7 @@ _gdk_pixmap_new (GdkDrawable *drawable, gdk_drawable_set_colormap (pixmap, cmap); } - if (depth != 15 && depth != 16) + if (depth == 1 || depth == 24 || depth == 32) { dib_surface = cairo_win32_surface_create_with_dib (format, width, height); if (dib_surface == NULL || @@ -238,8 +244,10 @@ _gdk_pixmap_new (GdkDrawable *drawable, return NULL; } - /* We need to have cairo create the dibsection for us, because - creating a cairo surface from a hdc only works for rgb24 format */ + /* + * Let Cairo own storage for the formats that it represents + * directly on Win32. + */ hdc = cairo_win32_surface_get_dc (dib_surface); /* Get the bitmap from the cairo hdc */ @@ -261,71 +269,186 @@ _gdk_pixmap_new (GdkDrawable *drawable, } else { - /* 16 bpp not supported by win32 cairo surface */ struct { - BITMAPINFOHEADER bmiHeader; - union { - WORD bmiIndices[256]; - DWORD bmiMasks[3]; - RGBQUAD bmiColors[256]; - } u; + BITMAPINFOHEADER bmiHeader; + union { + WORD bmiIndices[256]; + DWORD bmiMasks[3]; + RGBQUAD bmiColors[256]; + } u; } bmi; - UINT iUsage; - HWND hwnd; + GdkColormapPrivateWin32 *cmapp; GdkVisual *visual; + HPALETTE holdpal = NULL; + UINT iUsage = DIB_RGB_COLORS; + HWND hwnd; + gint n_colors = 0; + gint i; - if (GDK_IS_WINDOW (drawable)) - hwnd = GDK_WINDOW_HWND (drawable); - else - hwnd = GetDesktopWindow (); - if ((hdc = GetDC (hwnd)) == NULL) - { - WIN32_GDI_FAILED ("GetDC"); - g_object_unref ((GObject *) pixmap); - return NULL; - } - + /* + * Low-depth pixmaps need their native palette layout while + * 15/16-bpp pixmaps need explicit channel masks. Both use the + * same manually allocated DIB/HDC lifecycle. + */ + memset (&bmi.bmiHeader, 0, sizeof (bmi.bmiHeader)); bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); bmi.bmiHeader.biWidth = width; bmi.bmiHeader.biHeight = -height; bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 16; - bmi.bmiHeader.biCompression = BI_BITFIELDS; - bmi.bmiHeader.biSizeImage = 0; - bmi.bmiHeader.biXPelsPerMeter = - bmi.bmiHeader.biYPelsPerMeter = 0; - bmi.bmiHeader.biClrUsed = 0; - bmi.bmiHeader.biClrImportant = 0; - iUsage = DIB_RGB_COLORS; - visual = gdk_visual_get_system (); - bmi.u.bmiMasks[0] = visual->red_mask; - bmi.u.bmiMasks[1] = visual->green_mask; - bmi.u.bmiMasks[2] = visual->blue_mask; + if (depth <= 8) + { + bmi.bmiHeader.biBitCount = + _gdk_windowing_get_bits_for_depth ( + gdk_display_get_default (), depth); + bmi.bmiHeader.biCompression = BI_RGB; + + n_colors = 1 << depth; + bmi.bmiHeader.biClrUsed = n_colors; + } + else + { + bmi.bmiHeader.biBitCount = 16; + bmi.bmiHeader.biCompression = BI_BITFIELDS; + + visual = gdk_visual_get_system (); + + if (visual->depth == depth) + { + bmi.u.bmiMasks[0] = visual->red_mask; + bmi.u.bmiMasks[1] = visual->green_mask; + bmi.u.bmiMasks[2] = visual->blue_mask; + } + else + { + bmi.u.bmiMasks[0] = + depth == 15 ? 0x00007C00 : 0x0000F800; + bmi.u.bmiMasks[1] = + depth == 15 ? 0x000003E0 : 0x000007E0; + bmi.u.bmiMasks[2] = 0x0000001F; + } + } + + if (GDK_IS_WINDOW (drawable)) + hwnd = GDK_WINDOW_HWND (drawable); + else + hwnd = GetDesktopWindow (); + + if ((hdc = GetDC (hwnd)) == NULL) + { + WIN32_GDI_FAILED ("GetDC"); + g_object_unref ((GObject *) pixmap); + return NULL; + } + + if (depth <= 8 && drawable_impl->colormap) + { + cmapp = + GDK_WIN32_COLORMAP_DATA ( + drawable_impl->colormap); + + holdpal = + SelectPalette ( + hdc, + cmapp->hpal, + FALSE); + + if (holdpal == NULL) + WIN32_GDI_FAILED ("SelectPalette"); + else + { + if (RealizePalette (hdc) == GDI_ERROR) + WIN32_GDI_FAILED ("RealizePalette"); + + iUsage = DIB_PAL_COLORS; + + for (i = 0; i < n_colors; i++) + bmi.u.bmiIndices[i] = i; + } + } + + /* + * DIB_RGB_COLORS consumes RGBQUAD entries. Only initialize the + * entries actually used; DIB_PAL_COLORS already has its WORD + * indices filled above. + */ + if (depth <= 8 && iUsage == DIB_RGB_COLORS) + memset (bmi.u.bmiColors, 0, + n_colors * sizeof (bmi.u.bmiColors[0])); + + hbitmap = + CreateDIBSection ( + hdc, + (BITMAPINFO *) &bmi, + iUsage, + (PVOID *) &bits, + NULL, + 0); + + if (hbitmap == NULL) + { + WIN32_GDI_FAILED ("CreateDIBSection"); + + if (holdpal) + SelectPalette (hdc, holdpal, FALSE); + + GDI_CALL (ReleaseDC, (hwnd, hdc)); + g_object_unref ((GObject *) pixmap); + return NULL; + } + + if (holdpal) + SelectPalette (hdc, holdpal, FALSE); - if ((hbitmap = CreateDIBSection (hdc, (BITMAPINFO *) &bmi, - iUsage, (PVOID *) &bits, NULL, 0)) == NULL) - { - WIN32_GDI_FAILED ("CreateDIBSection"); - GDI_CALL (ReleaseDC, (hwnd, hdc)); - g_object_unref ((GObject *) pixmap); - return NULL; - } GDI_CALL (ReleaseDC, (hwnd, hdc)); - dib_surface = cairo_image_surface_create_for_data (bits, - format, width, height, - (width * 2 + 3) & ~3); - hdc = CreateCompatibleDC (NULL); - if (!hdc) - { - WIN32_GDI_FAILED ("CreateCompatibleDC"); - g_object_unref ((GObject *) pixmap); - return NULL; - } - SelectObject (hdc, hbitmap); + if (hdc == NULL) + { + WIN32_GDI_FAILED ("CreateCompatibleDC"); + GDI_CALL (DeleteObject, (hbitmap)); + g_object_unref ((GObject *) pixmap); + return NULL; + } + + if (SelectObject (hdc, hbitmap) == NULL) + { + WIN32_GDI_FAILED ("SelectObject"); + GDI_CALL (DeleteDC, (hdc)); + GDI_CALL (DeleteObject, (hbitmap)); + g_object_unref ((GObject *) pixmap); + return NULL; + } + + if (depth != 16 || + bmi.u.bmiMasks[0] != 0x0000F800 || + bmi.u.bmiMasks[1] != 0x000007E0 || + bmi.u.bmiMasks[2] != 0x0000001F) + dib_surface = + cairo_win32_surface_create (hdc); + else + dib_surface = + cairo_image_surface_create_for_data ( + bits, + format, + width, + height, + (width * 2 + 3) & ~3); + + if (dib_surface == NULL || + cairo_surface_status (dib_surface) != + CAIRO_STATUS_SUCCESS) + { + if (dib_surface) + cairo_surface_destroy (dib_surface); + + GDI_CALL (DeleteDC, (hdc)); + GDI_CALL (DeleteObject, (hbitmap)); + g_object_unref ((GObject *) pixmap); + return NULL; + } + pixmap_impl->is_allocated = TRUE; } diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c index b7ea0404a..1a21a1b67 100644 --- a/gdk/win32/gdkwindow-win32.c +++ b/gdk/win32/gdkwindow-win32.c @@ -2767,6 +2767,10 @@ _gdk_windowing_window_at_pointer (GdkDisplay *display, * WindowFromPoint() can find our windows, we follow similar logic * here, and ignore invisible and disabled windows. */ + UINT cwp_flags = CWP_SKIPDISABLED | + CWP_SKIPINVISIBLE | + CWP_SKIPTRANSPARENT; + hwnd = GetDesktopWindow (); do { window = gdk_win32_handle_table_lookup ((GdkNativeWindow) hwnd); @@ -2777,8 +2781,7 @@ _gdk_windowing_window_at_pointer (GdkDisplay *display, break; screen_to_client (hwnd, screen_pt, &client_pt); - hwndc = ChildWindowFromPointEx (hwnd, client_pt, CWP_SKIPDISABLED | - CWP_SKIPINVISIBLE); + hwndc = ChildWindowFromPointEx (hwnd, client_pt, cwp_flags); /* Verify that we're really inside the client area of the window */ if (hwndc != hwnd) @@ -2789,6 +2792,8 @@ _gdk_windowing_window_at_pointer (GdkDisplay *display, hwndc = hwnd; } + /* Only ignore top-level transparent windows */ + cwp_flags &= ~CWP_SKIPTRANSPARENT; } while (hwndc != hwnd && (hwnd = hwndc, 1)); } diff --git a/gdk/x11/gdkdisplay-x11.h b/gdk/x11/gdkdisplay-x11.h index 45f5834df..76b2e6d18 100644 --- a/gdk/x11/gdkdisplay-x11.h +++ b/gdk/x11/gdkdisplay-x11.h @@ -78,6 +78,7 @@ struct _GdkDisplayX11 gboolean use_xshm; gboolean have_shm_pixmaps; + guint8 bits_per_depth[33]; GdkTristate have_render; gboolean have_xfixes; gint xfixes_event_base; diff --git a/gdk/x11/gdkdrawable-x11.c b/gdk/x11/gdkdrawable-x11.c index d27a03ebb..18758966b 100644 --- a/gdk/x11/gdkdrawable-x11.c +++ b/gdk/x11/gdkdrawable-x11.c @@ -1462,6 +1462,26 @@ draw_with_pixmaps (GdkDrawable *drawable, } #endif +static gboolean +gdk_x11_drawable_can_composite_101010 (GdkDrawable *drawable) +{ + GdkVisual *visual; + + visual = gdk_drawable_get_visual (drawable); + + return visual != NULL && + visual->type == GDK_VISUAL_TRUE_COLOR && + visual->depth == 30 && + _gdk_windowing_get_bits_for_depth ( + gdk_drawable_get_display (drawable), 30) == 32 && + visual->byte_order == + (G_BYTE_ORDER == G_BIG_ENDIAN ? + GDK_MSB_FIRST : GDK_LSB_FIRST) && + visual->red_mask == 0x3ff00000 && + visual->green_mask == 0x000ffc00 && + visual->blue_mask == 0x000003ff; +} + static void gdk_x11_draw_pixbuf (GdkDrawable *drawable, GdkGC *gc, @@ -1488,6 +1508,8 @@ gdk_x11_draw_pixbuf (GdkDrawable *drawable, if (format_type == GDK_X11_FORMAT_NONE || !gdk_pixbuf_get_has_alpha (pixbuf) || + (gdk_drawable_get_depth (drawable) == 30 && + gdk_x11_drawable_can_composite_101010 (drawable)) || gdk_drawable_get_depth (drawable) == 1 || (dither == GDK_RGB_DITHER_MAX && gdk_drawable_get_depth (drawable) != 24) || gdk_x11_drawable_get_picture (drawable) == None) diff --git a/gdk/x11/gdkimage-x11.c b/gdk/x11/gdkimage-x11.c index 65616271e..2e01c204a 100644 --- a/gdk/x11/gdkimage-x11.c +++ b/gdk/x11/gdkimage-x11.c @@ -787,20 +787,34 @@ gdk_x11_image_get_ximage (GdkImage *image) gint _gdk_windowing_get_bits_for_depth (GdkDisplay *display, - gint depth) + gint depth) { + GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display); XPixmapFormatValues *formats; gint count, i; + gint result = -1; + + if ((guint) depth < G_N_ELEMENTS (display_x11->bits_per_depth) && + display_x11->bits_per_depth[depth] != 0) + return display_x11->bits_per_depth[depth]; formats = XListPixmapFormats (GDK_DISPLAY_XDISPLAY (display), &count); for (i = 0; i < count; i++) - if (formats[i].depth == depth) - { - gint result = formats[i].bits_per_pixel; - XFree (formats); - return result; - } + { + if ((guint) formats[i].depth < + G_N_ELEMENTS (display_x11->bits_per_depth)) + display_x11->bits_per_depth[formats[i].depth] = + formats[i].bits_per_pixel; + + if (formats[i].depth == depth) + result = formats[i].bits_per_pixel; + } + + XFree (formats); + + if (result != -1) + return result; g_assert_not_reached (); return -1; diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 8f5e496a3..31cc16730 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -2,6 +2,9 @@ include $(top_srcdir)/Makefile.decl -include $(INTROSPECTION_MAKEFILE) INTROSPECTION_GIRS = +if OS_WIN32 +INTROSPECTION_SCANNER_ENV = PATH="$(builddir):$(builddir)/.libs:$${PATH}" +endif INTROSPECTION_SCANNER_ARGS = \ --warn-all \ --add-include-path=../gdk @@ -1139,7 +1142,7 @@ $(GTK_UPDATE_ICON_CACHE_MANIFEST): echo '' ) >$@ $(GTK_UPDATE_ICON_CACHE_RC): - (echo -e '#include \nCREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST '$(GTK_UPDATE_ICON_CACHE_MANIFEST)) >$@ + (echo -e '#include \nCREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "'$(GTK_UPDATE_ICON_CACHE_MANIFEST)'"') >$@ $(GTK_UPDATE_ICON_CACHE_MANIFEST_OBJECT): $(GTK_UPDATE_ICON_CACHE_RC) $(GTK_UPDATE_ICON_CACHE_MANIFEST) $(WINDRES) --input $< --output $@ --output-format=coff diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c index 2f7007fd2..e4c98c8c2 100644 --- a/gtk/gtkcontainer.c +++ b/gtk/gtkcontainer.c @@ -40,6 +40,9 @@ #include "gtktoolbar.h" #include #include +#ifdef GDK_WINDOWING_QUARTZ +#include "gdk/quartz/gdkquartz.h" +#endif #include "gtkalias.h" @@ -1357,7 +1360,16 @@ gtk_container_idle_sizer (gpointer data) gtk_container_check_resize (GTK_CONTAINER (widget)); } +#ifdef GDK_WINDOWING_QUARTZ + /* macOS 11 and newer can trigger expensive full-window redraws here. + * Keep the traditional update processing path for older Quartz targets, + * but let the normal GDK update idle handle updates on Big Sur and newer. + */ + if (gdk_quartz_osx_version () < GDK_OSX_BIG_SUR) + gdk_window_process_all_updates (); +#else gdk_window_process_all_updates (); +#endif return FALSE; } diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c index 2ce2d6c8f..fabf5913e 100644 --- a/gtk/gtkfilechooserdefault.c +++ b/gtk/gtkfilechooserdefault.c @@ -410,7 +410,8 @@ static void load_remove_timer (GtkFileChooserDefault *impl, LoadState new_load_s static void browse_files_center_selected_row (GtkFileChooserDefault *impl); static void view_mode_set (GtkFileChooserDefault *impl, ViewMode view_mode); -static void view_mode_combo_box_changed_cb (GtkComboBox *combo, +static void icon_view_scale_create (GtkFileChooserDefault *impl); +static void view_mode_toggle_button_toggled_cb (GtkToggleButton *toggle, GtkFileChooserDefault *impl); static void icon_view_scale_value_changed_cb (GtkRange *range, @@ -5208,12 +5209,22 @@ view_mode_set (GtkFileChooserDefault *impl, ViewMode view_mode) return; impl->view_mode = view_mode; - gtk_combo_box_set_active (GTK_COMBO_BOX (impl->view_mode_combo_box), - view_mode); + gtk_toggle_button_set_active ( + GTK_TOGGLE_BUTTON (impl->view_mode_toggle_button), + view_mode == VIEW_MODE_ICON); /* Creating the target view */ if (view_mode == VIEW_MODE_ICON) { + if (!impl->icon_view_scale_hbox) + { + icon_view_scale_create (impl); + gtk_box_pack_end ( + GTK_BOX (impl->browse_path_bar_hbox), + impl->icon_view_scale_hbox, + FALSE, FALSE, 0); + } + create_browse_files_icon_view (impl); impl->browse_files_current_view = impl->browse_files_icon_view; old_view = impl->browse_files_tree_view; @@ -5246,7 +5257,8 @@ view_mode_set (GtkFileChooserDefault *impl, ViewMode view_mode) impl->browse_files_icon_view = NULL; impl->list_icon_renderer = NULL; impl->list_name_renderer = NULL; - gtk_widget_hide (impl->icon_view_scale_hbox); + if (impl->icon_view_scale_hbox) + gtk_widget_hide (impl->icon_view_scale_hbox); } else g_assert_not_reached (); @@ -5264,12 +5276,14 @@ view_mode_set (GtkFileChooserDefault *impl, ViewMode view_mode) browse_files_center_selected_row (impl); } -/* Callback used when view mode combo box active item is changed */ +/* Callback used when the view mode toggle button is toggled. */ static void -view_mode_combo_box_changed_cb (GtkComboBox *combo, +view_mode_toggle_button_toggled_cb (GtkToggleButton *toggle, GtkFileChooserDefault *impl) { - ViewMode target = gtk_combo_box_get_active (combo); + ViewMode target = gtk_toggle_button_get_active (toggle) + ? VIEW_MODE_ICON + : VIEW_MODE_LIST; view_mode_set (impl, target); } @@ -5698,20 +5712,15 @@ location_button_toggled_cb (GtkToggleButton *toggle, location_mode_set (impl, new_mode, FALSE); } -/* Creates a combo box with two items: List View and Icon View. */ +/* Creates the view mode toggle. */ static void -view_mode_combo_box_create (GtkFileChooserDefault *impl) +view_mode_toggle_button_create (GtkFileChooserDefault *impl) { - impl->view_mode_combo_box = gtk_combo_box_text_new (); - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT(impl->view_mode_combo_box), - _("List View")); /* VIEW_MODE_LIST */ - gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT(impl->view_mode_combo_box), - _("Icon View")); /* VIEW_MODE_ICON */ - gtk_combo_box_set_active (GTK_COMBO_BOX(impl->view_mode_combo_box), - VIEW_MODE_LIST); + impl->view_mode_toggle_button = + gtk_toggle_button_new_with_label (_("Icon View")); - g_signal_connect (impl->view_mode_combo_box, "changed", - G_CALLBACK (view_mode_combo_box_changed_cb), impl); + g_signal_connect (impl->view_mode_toggle_button, "toggled", + G_CALLBACK (view_mode_toggle_button_toggled_cb), impl); } /* Creates a hscale for the icon view. */ @@ -5719,46 +5728,48 @@ static void icon_view_scale_create (GtkFileChooserDefault *impl) { GtkObject *adj; + GtkWidget *zoom_icon; GtkWidget *image; impl->icon_view_scale_hbox = gtk_hbox_new (FALSE, 12); - impl->icon_view_scale_zoom_out_icon = gtk_event_box_new (); - gtk_event_box_set_visible_window (GTK_EVENT_BOX (impl->icon_view_scale_zoom_out_icon), FALSE); + zoom_icon = gtk_event_box_new (); + gtk_event_box_set_visible_window (GTK_EVENT_BOX (zoom_icon), FALSE); image = gtk_image_new_from_stock (GTK_STOCK_ZOOM_OUT, GTK_ICON_SIZE_BUTTON); - gtk_container_add (GTK_CONTAINER (impl->icon_view_scale_zoom_out_icon), image); + gtk_container_add (GTK_CONTAINER (zoom_icon), image); gtk_widget_show (image); - g_object_set_data (G_OBJECT (impl->icon_view_scale_zoom_out_icon), + g_object_set_data (G_OBJECT (zoom_icon), "gtk-file-chooser-zoom-direction", GINT_TO_POINTER (-1)); - gtk_widget_set_tooltip_text (impl->icon_view_scale_zoom_out_icon, _("Zoom out")); - g_signal_connect (impl->icon_view_scale_zoom_out_icon, "button-press-event", + gtk_widget_set_tooltip_text (zoom_icon, _("Zoom out")); + g_signal_connect (zoom_icon, "button-press-event", G_CALLBACK (icon_view_zoom_button_press_cb), impl); - gtk_size_group_add_widget (impl->browse_path_bar_size_group, impl->icon_view_scale_zoom_out_icon); - gtk_box_pack_start (GTK_BOX (impl->icon_view_scale_hbox), impl->icon_view_scale_zoom_out_icon, FALSE, FALSE, 0); - gtk_widget_show (impl->icon_view_scale_zoom_out_icon); + gtk_size_group_add_widget (impl->browse_path_bar_size_group, zoom_icon); + gtk_box_pack_start (GTK_BOX (impl->icon_view_scale_hbox), zoom_icon, FALSE, FALSE, 0); + gtk_widget_show (zoom_icon); - adj = gtk_adjustment_new (32, 32, 256, 16, 16, 0); + adj = gtk_adjustment_new (impl->icon_view_icon_size, + 32, 256, 16, 16, 0); impl->icon_view_scale = gtk_hscale_new (GTK_ADJUSTMENT (adj)); gtk_scale_set_draw_value (GTK_SCALE (impl->icon_view_scale), FALSE); gtk_widget_set_size_request (impl->icon_view_scale, 100, -1); gtk_box_pack_start (GTK_BOX (impl->icon_view_scale_hbox), impl->icon_view_scale, FALSE, FALSE, 0); gtk_widget_show (impl->icon_view_scale); - impl->icon_view_scale_zoom_in_icon = gtk_event_box_new (); - gtk_event_box_set_visible_window (GTK_EVENT_BOX (impl->icon_view_scale_zoom_in_icon), FALSE); + zoom_icon = gtk_event_box_new (); + gtk_event_box_set_visible_window (GTK_EVENT_BOX (zoom_icon), FALSE); image = gtk_image_new_from_stock (GTK_STOCK_ZOOM_IN, GTK_ICON_SIZE_BUTTON); - gtk_container_add (GTK_CONTAINER (impl->icon_view_scale_zoom_in_icon), image); + gtk_container_add (GTK_CONTAINER (zoom_icon), image); gtk_widget_show (image); - g_object_set_data (G_OBJECT (impl->icon_view_scale_zoom_in_icon), + g_object_set_data (G_OBJECT (zoom_icon), "gtk-file-chooser-zoom-direction", GINT_TO_POINTER (1)); - gtk_widget_set_tooltip_text (impl->icon_view_scale_zoom_in_icon, _("Zoom in")); - g_signal_connect (impl->icon_view_scale_zoom_in_icon, "button-press-event", + gtk_widget_set_tooltip_text (zoom_icon, _("Zoom in")); + g_signal_connect (zoom_icon, "button-press-event", G_CALLBACK (icon_view_zoom_button_press_cb), impl); - gtk_size_group_add_widget (impl->browse_path_bar_size_group, impl->icon_view_scale_zoom_in_icon); - gtk_box_pack_start (GTK_BOX (impl->icon_view_scale_hbox), impl->icon_view_scale_zoom_in_icon, FALSE, FALSE, 0); - gtk_widget_show (impl->icon_view_scale_zoom_in_icon); + gtk_size_group_add_widget (impl->browse_path_bar_size_group, zoom_icon); + gtk_box_pack_start (GTK_BOX (impl->icon_view_scale_hbox), zoom_icon, FALSE, FALSE, 0); + gtk_widget_show (zoom_icon); g_signal_connect (impl->icon_view_scale, "value-changed", G_CALLBACK (icon_view_scale_value_changed_cb), impl); @@ -5883,9 +5894,9 @@ path_bar_widgets_create (GtkFileChooserDefault *impl) impl->browse_path_bar_size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL); gtk_size_group_set_ignore_hidden (impl->browse_path_bar_size_group, FALSE); - /* View mode combo box */ - view_mode_combo_box_create (impl); - gtk_box_pack_start (GTK_BOX (impl->browse_path_bar_hbox), impl->view_mode_combo_box, FALSE, FALSE, 0); + /* View mode selector */ + view_mode_toggle_button_create (impl); + gtk_box_pack_start (GTK_BOX (impl->browse_path_bar_hbox), impl->view_mode_toggle_button, FALSE, FALSE, 0); /* Location button */ location_button_create (impl); @@ -5908,10 +5919,6 @@ path_bar_widgets_create (GtkFileChooserDefault *impl) /* Widgets for special modes (recently-used in Open mode, Search mode) */ special_mode_widgets_create (impl); - /* Icon view scale */ - icon_view_scale_create (impl); - gtk_box_pack_end (GTK_BOX (impl->browse_path_bar_hbox), impl->icon_view_scale_hbox, FALSE, FALSE, 0); - /* Create Folder */ impl->browse_new_folder_button = gtk_button_new_with_mnemonic (_("Create Fo_lder")); g_signal_connect (impl->browse_new_folder_button, "clicked", @@ -6477,9 +6484,9 @@ update_appearance (GtkFileChooserDefault *impl) if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN || impl->action == GTK_FILE_CHOOSER_ACTION_SAVE) - gtk_widget_show (impl->view_mode_combo_box); + gtk_widget_show (impl->view_mode_toggle_button); else - gtk_widget_hide (impl->view_mode_combo_box); + gtk_widget_hide (impl->view_mode_toggle_button); if (impl->location_entry) _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->action); @@ -7043,13 +7050,16 @@ settings_load (GtkFileChooserDefault *impl) location_mode_set (impl, location_mode, TRUE); - g_signal_handlers_block_by_func (impl->icon_view_scale, - G_CALLBACK (icon_view_scale_value_changed_cb), - impl); - gtk_range_set_value (GTK_RANGE (impl->icon_view_scale), icon_view_scale); - g_signal_handlers_unblock_by_func (impl->icon_view_scale, - G_CALLBACK (icon_view_scale_value_changed_cb), - impl); + if (impl->icon_view_scale) + { + g_signal_handlers_block_by_func (impl->icon_view_scale, + G_CALLBACK (icon_view_scale_value_changed_cb), + impl); + gtk_range_set_value (GTK_RANGE (impl->icon_view_scale), icon_view_scale); + g_signal_handlers_unblock_by_func (impl->icon_view_scale, + G_CALLBACK (icon_view_scale_value_changed_cb), + impl); + } view_mode_set (impl, view_mode); diff --git a/gtk/gtkfilechooserprivate.h b/gtk/gtkfilechooserprivate.h index 193dea2e3..6e3456bc6 100644 --- a/gtk/gtkfilechooserprivate.h +++ b/gtk/gtkfilechooserprivate.h @@ -227,11 +227,9 @@ struct _GtkFileChooserDefault GtkWidget *extra_align; GtkWidget *extra_widget; - GtkWidget *view_mode_combo_box; + GtkWidget *view_mode_toggle_button; GtkWidget *icon_view_scale_hbox; GtkWidget *icon_view_scale; - GtkWidget *icon_view_scale_zoom_in_icon; - GtkWidget *icon_view_scale_zoom_out_icon; guint icon_view_scale_timeout_id; guint icon_view_scale_visible_timeout_id; guint icon_view_scale_after_layout_id; diff --git a/gtk/gtkfontbutton.c b/gtk/gtkfontbutton.c index 08aea103e..68df02b8d 100644 --- a/gtk/gtkfontbutton.c +++ b/gtk/gtkfontbutton.c @@ -889,7 +889,8 @@ gtk_font_button_update_font_info (GtkFontButton *font_button) if (style == NULL || !g_ascii_strcasecmp (style, "Regular")) family_style = g_strdup (family); else - family_style = g_strdup_printf ("%s %s", family, style); + family_style = g_strdup_printf ("%s %s", family, + _gtk_font_style_name_translate (style)); gtk_label_set_text (GTK_LABEL (font_button->priv->font_label), family_style); diff --git a/gtk/gtkfontsel.c b/gtk/gtkfontsel.c index 701d22841..28ede4eb4 100644 --- a/gtk/gtkfontsel.c +++ b/gtk/gtkfontsel.c @@ -76,6 +76,91 @@ #define DEFAULT_FONT_NAME "Sans 10" +#ifdef ENABLE_NLS +/* Pango uses these standard English names for common font faces. + * Keep the msgids explicit for gettext, but only translate exact matches: + * font-specific face names must remain untouched. + */ +#define FONT_STYLE_ULTRA_LIGHT N_("Ultra-Light") +#define FONT_STYLE_LIGHT N_("Light") +#define FONT_STYLE_MEDIUM N_("Medium") +#define FONT_STYLE_NORMAL N_("Normal") +#define FONT_STYLE_REGULAR N_("Regular") +#define FONT_STYLE_ITALIC N_("Italic") +#define FONT_STYLE_OBLIQUE N_("Oblique") +#define FONT_STYLE_SEMI_BOLD N_("Semi-Bold") +#define FONT_STYLE_BOLD N_("Bold") +#define FONT_STYLE_ULTRA_BOLD N_("Ultra-Bold") +#define FONT_STYLE_HEAVY N_("Heavy") +#define FONT_STYLE_BOLD_ITALIC N_("Bold Italic") + +const gchar * +_gtk_font_style_name_translate (const gchar *name) +{ + switch (name[0]) + { + case 'B': + if (strcmp (name, FONT_STYLE_BOLD) == 0) + return _(FONT_STYLE_BOLD); + if (strcmp (name, FONT_STYLE_BOLD_ITALIC) == 0) + return _(FONT_STYLE_BOLD_ITALIC); + break; + + case 'H': + if (strcmp (name, FONT_STYLE_HEAVY) == 0) + return _(FONT_STYLE_HEAVY); + break; + + case 'I': + if (strcmp (name, FONT_STYLE_ITALIC) == 0) + return _(FONT_STYLE_ITALIC); + break; + + case 'L': + if (strcmp (name, FONT_STYLE_LIGHT) == 0) + return _(FONT_STYLE_LIGHT); + break; + + case 'M': + if (strcmp (name, FONT_STYLE_MEDIUM) == 0) + return _(FONT_STYLE_MEDIUM); + break; + + case 'N': + if (strcmp (name, FONT_STYLE_NORMAL) == 0) + return _(FONT_STYLE_NORMAL); + break; + + case 'O': + if (strcmp (name, FONT_STYLE_OBLIQUE) == 0) + return _(FONT_STYLE_OBLIQUE); + break; + + case 'R': + if (strcmp (name, FONT_STYLE_REGULAR) == 0) + return _(FONT_STYLE_REGULAR); + break; + + case 'S': + if (strcmp (name, FONT_STYLE_SEMI_BOLD) == 0) + return _(FONT_STYLE_SEMI_BOLD); + break; + + case 'U': + if (strcmp (name, FONT_STYLE_ULTRA_LIGHT) == 0) + return _(FONT_STYLE_ULTRA_LIGHT); + if (strcmp (name, FONT_STYLE_ULTRA_BOLD) == 0) + return _(FONT_STYLE_ULTRA_BOLD); + break; + + default: + break; + } + + return name; +} +#endif /* ENABLE_NLS */ + /* This is the initial and maximum height of the preview entry (it expands when large font sizes are selected). Initial height is also the minimum. */ #define INITIAL_PREVIEW_HEIGHT 44 @@ -869,7 +954,7 @@ gtk_font_selection_show_available_styles (GtkFontSelection *fontsel) gtk_list_store_append (model, &iter); gtk_list_store_set (model, &iter, FACE_COLUMN, faces[i], - FACE_NAME_COLUMN, str, + FACE_NAME_COLUMN, _gtk_font_style_name_translate (str), -1); if (i == 0) diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c index 0d4435c72..f8aaf9a3b 100644 --- a/gtk/gtkicontheme.c +++ b/gtk/gtkicontheme.c @@ -2945,6 +2945,10 @@ icon_info_ensure_scale_and_pixbuf (GtkIconInfo *icon_info, if (mime_type && strcmp (mime_type, "image/svg+xml") == 0) is_svg = TRUE; +#ifdef G_OS_WIN32 + else if (content_type && strcmp (content_type, ".svg") == 0) + is_svg = TRUE; +#endif } g_object_unref (file_info); diff --git a/gtk/gtkimmodule.c b/gtk/gtkimmodule.c index a3a77c474..07c38f0b4 100644 --- a/gtk/gtkimmodule.c +++ b/gtk/gtkimmodule.c @@ -309,11 +309,186 @@ add_builtin_module (const gchar *module_name, return module; } +/* + * Keep IM module parsing independent of Pango's deprecated helpers. + */ + +/* + * Use unlocked input for the privately owned module-cache stream. + */ +#if defined(HAVE_GETC_UNLOCKED) +#define GTK_IM_MODULE_GETC(stream) getc_unlocked (stream) +#elif defined(HAVE__GETC_NOLOCK) +#define GTK_IM_MODULE_GETC(stream) _getc_nolock (stream) +#else +#define GTK_IM_MODULE_GETC(stream) getc (stream) +#endif + +static gchar * +gtk_im_module_scan_string (const gchar **pos) +{ + const gchar *p; + const gchar *q; + gchar *result; + gchar *out; + gsize len; + + p = *pos; + + while (g_ascii_isspace (*p)) + p++; + + if (*p != '"') + return NULL; + + p++; + q = p; + len = 0; + + while (*q && *q != '"') + { + if (*q == '\\') + { + q++; + + if (!*q) + return NULL; + } + + q++; + len++; + } + + if (*q != '"') + return NULL; + + result = g_malloc (len + 1); + out = result; + + while (p < q) + { + gchar c; + + c = *p++; + + if (c == '\\') + { + c = *p++; + + switch (c) + { + case 'b': c = '\b'; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'v': c = '\v'; break; + default: break; + } + } + + *out++ = c; + } + + *out = '\0'; + *pos = q + 1; + + return result; +} + +static gboolean +gtk_im_module_skip_space (const gchar **pos) +{ + while (g_ascii_isspace (**pos)) + (*pos)++; + + return **pos != '\0'; +} + +static gint +gtk_im_module_read_line (FILE *stream, + GString *str) +{ + gboolean escaped; + gboolean comment; + gint n_read; + gint lines; + gint c; + gint next_c; + + escaped = FALSE; + comment = FALSE; + n_read = 0; + lines = 1; + + g_string_truncate (str, 0); + + while (TRUE) + { + c = GTK_IM_MODULE_GETC (stream); + + if (c == EOF) + { + if (escaped) + g_string_append_c (str, '\\'); + + break; + } + + n_read++; + + if (c == '\r' || c == '\n') + { + next_c = GTK_IM_MODULE_GETC (stream); + + if (next_c != EOF && + !((c == '\r' && next_c == '\n') || + (c == '\n' && next_c == '\r'))) + ungetc (next_c, stream); + + if (escaped) + { + escaped = FALSE; + lines++; + continue; + } + + break; + } + + if (escaped) + { + escaped = FALSE; + + if (c == '#') + g_string_append_c (str, '#'); + else + { + g_string_append_c (str, '\\'); + g_string_append_c (str, c); + } + } + else if (!comment) + { + if (c == '#') + comment = TRUE; + else if (c == '\\') + escaped = TRUE; + else + g_string_append_c (str, c); + } + } + + + return n_read > 0 ? lines : 0; +} + +#undef GTK_IM_MODULE_GETC + static void gtk_im_module_initialize (void) { GString *line_buf = g_string_new (NULL); - GString *tmp_buf = g_string_new (NULL); gchar *filename = gtk_rc_get_im_module_file(); FILE *file; gboolean have_error = FALSE; @@ -387,18 +562,17 @@ gtk_im_module_initialize (void) * we allow no file at all. */ g_string_free (line_buf, TRUE); - g_string_free (tmp_buf, TRUE); g_free (filename); return; } - while (!have_error && pango_read_line (file, line_buf)) + while (!have_error && gtk_im_module_read_line (file, line_buf)) { const char *p; p = line_buf->str; - if (!pango_skip_space (&p)) + if (!gtk_im_module_skip_space (&p)) { /* Blank line marking the end of a module */ @@ -413,61 +587,62 @@ gtk_im_module_initialize (void) } if (!module) - { - /* Read a module location - */ - module = g_object_new (GTK_TYPE_IM_MODULE, NULL); + { + /* Read a module location + */ + module = g_object_new (GTK_TYPE_IM_MODULE, NULL); + module->path = gtk_im_module_scan_string (&p); - if (!pango_scan_string (&p, tmp_buf) || - pango_skip_space (&p)) - { - g_warning ("Error parsing context info in '%s'\n %s", - filename, line_buf->str); - have_error = TRUE; - } + if (!module->path || gtk_im_module_skip_space (&p)) + { + g_warning ("Error parsing context info in '%s'\n %s", + filename, line_buf->str); + have_error = TRUE; + continue; + } - module->path = g_strdup (tmp_buf->str); #ifdef G_OS_WIN32 - correct_libdir_prefix (&module->path); + correct_libdir_prefix (&module->path); #endif - g_type_module_set_name (G_TYPE_MODULE (module), module->path); - } + g_type_module_set_name (G_TYPE_MODULE (module), module->path); + } else { GtkIMContextInfo *info = g_new0 (GtkIMContextInfo, 1); /* Read information about a context type */ - if (!pango_scan_string (&p, tmp_buf)) - goto context_error; - info->context_id = g_strdup (tmp_buf->str); + info->context_id = gtk_im_module_scan_string (&p); + if (!info->context_id) + goto context_error; - if (!pango_scan_string (&p, tmp_buf)) - goto context_error; - info->context_name = g_strdup (tmp_buf->str); + info->context_name = gtk_im_module_scan_string (&p); + if (!info->context_name) + goto context_error; - if (!pango_scan_string (&p, tmp_buf)) - goto context_error; - info->domain = g_strdup (tmp_buf->str); + info->domain = gtk_im_module_scan_string (&p); + if (!info->domain) + goto context_error; - if (!pango_scan_string (&p, tmp_buf)) - goto context_error; - info->domain_dirname = g_strdup (tmp_buf->str); + info->domain_dirname = gtk_im_module_scan_string (&p); + if (!info->domain_dirname) + goto context_error; #ifdef G_OS_WIN32 correct_localedir_prefix ((char **) &info->domain_dirname); #endif - if (!pango_scan_string (&p, tmp_buf)) - goto context_error; - info->default_locales = g_strdup (tmp_buf->str); + info->default_locales = gtk_im_module_scan_string (&p); + if (!info->default_locales) + goto context_error; - if (pango_skip_space (&p)) + if (gtk_im_module_skip_space (&p)) goto context_error; infos = g_slist_prepend (infos, info); continue; context_error: + free_info (info); g_warning ("Error parsing context info in '%s'\n %s", filename, line_buf->str); have_error = TRUE; @@ -491,7 +666,6 @@ gtk_im_module_initialize (void) fclose (file); g_string_free (line_buf, TRUE); - g_string_free (tmp_buf, TRUE); g_free (filename); } diff --git a/gtk/gtkmodules.c b/gtk/gtkmodules.c index da5568ffa..a325b3e56 100644 --- a/gtk/gtkmodules.c +++ b/gtk/gtkmodules.c @@ -192,7 +192,7 @@ _gtk_get_module_path (const gchar *type) result = g_new (gchar *, count * 5 + 1); count = 0; - for (path = get_module_path (); *path; path++) + for (path = paths; *path; path++) { gint use_version, use_host; diff --git a/gtk/gtkprintunixdialog.c b/gtk/gtkprintunixdialog.c index da9010b96..af64a5a37 100644 --- a/gtk/gtkprintunixdialog.c +++ b/gtk/gtkprintunixdialog.c @@ -796,7 +796,9 @@ printer_status_cb (GtkPrintBackend *backend, /* When the pause state change then we need to update sensitive property * of GTK_RESPONSE_OK button inside of selected_printer_changed function. */ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview)); + priv->internal_printer_change = TRUE; selected_printer_changed (selection, dialog); + priv->internal_printer_change = FALSE; if (gtk_print_backend_printer_list_is_done (backend) && gtk_printer_is_default (printer) && diff --git a/gtk/gtkprivate.h b/gtk/gtkprivate.h index b2c2df999..cc1b50dfa 100644 --- a/gtk/gtkprivate.h +++ b/gtk/gtkprivate.h @@ -134,6 +134,13 @@ const gchar *_gtk_get_data_prefix (); #endif /* G_OS_WIN32 */ +#ifdef ENABLE_NLS +G_GNUC_INTERNAL +const gchar *_gtk_font_style_name_translate (const gchar *name); +#else +#define _gtk_font_style_name_translate(name) (name) +#endif + gboolean _gtk_fnmatch (const char *pattern, const char *string, gboolean no_leading_period); diff --git a/gtk/gtkquartz.c b/gtk/gtkquartz.c index 87ba87745..caf8404f8 100644 --- a/gtk/gtkquartz.c +++ b/gtk/gtkquartz.c @@ -67,7 +67,10 @@ _gtk_quartz_create_image_from_pixbuf (GdkPixbuf *pixbuf) } [nsimage lockFocus]; - context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; + if (gdk_quartz_osx_version () < GDK_OSX_YOSEMITE) + context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; + else + context = [[NSGraphicsContext currentContext] CGContext]; CGContextDrawImage (context, CGRectMake (0, 0, pixbuf_width, pixbuf_height), image); [nsimage unlockFocus]; diff --git a/gtk/gtkrc.c b/gtk/gtkrc.c index 7bfbea85c..d316a0d90 100644 --- a/gtk/gtkrc.c +++ b/gtk/gtkrc.c @@ -808,6 +808,8 @@ gtk_rc_parse_named (GtkRcContext *context, gchar *path = NULL; const gchar *home_dir; gchar *subpath; + const gchar * const *xdg_data_dirs; + gint i; if (type) subpath = g_strconcat ("gtk-2.0-", type, @@ -829,6 +831,22 @@ gtk_rc_parse_named (GtkRcContext *context, } } + if (!path) + { + xdg_data_dirs = g_get_system_data_dirs (); + for (i = 0; xdg_data_dirs[i]; i++) + { + path = g_build_filename (xdg_data_dirs[i], "themes", name, subpath, NULL); + if (g_file_test (path, G_FILE_TEST_EXISTS)) + break; + else + { + g_free (path); + path = NULL; + } + } + } + if (!path) { gchar *theme_dir = gtk_rc_get_theme_dir (); diff --git a/gtk/gtktooltips.h b/gtk/gtktooltips.h index eb1e0a0be..fbafd9939 100644 --- a/gtk/gtktooltips.h +++ b/gtk/gtktooltips.h @@ -74,7 +74,11 @@ struct _GtkTooltips guint have_grab : 1; guint use_sticky_delay : 1; gint timer_tag; - GTimeVal last_popdown; + struct + { + glong tv_sec; + glong tv_usec; + } last_popdown; }; struct _GtkTooltipsClass diff --git a/gtk/gtktrayicon.h b/gtk/gtktrayicon.h index 9ad1c54f2..ab4eda2f5 100644 --- a/gtk/gtktrayicon.h +++ b/gtk/gtktrayicon.h @@ -46,12 +46,12 @@ struct _GtkTrayIconClass { GtkPlugClass parent_class; - void (*__gtk_reserved1); - void (*__gtk_reserved2); - void (*__gtk_reserved3); - void (*__gtk_reserved4); - void (*__gtk_reserved5); - void (*__gtk_reserved6); + void (*__gtk_reserved1) (void); + void (*__gtk_reserved2) (void); + void (*__gtk_reserved3) (void); + void (*__gtk_reserved4) (void); + void (*__gtk_reserved5) (void); + void (*__gtk_reserved6) (void); }; GType gtk_tray_icon_get_type (void) G_GNUC_CONST; diff --git a/gtk/makegtkalias.pl b/gtk/makegtkalias.pl index 3f956b05e..67ec7c973 100755 --- a/gtk/makegtkalias.pl +++ b/gtk/makegtkalias.pl @@ -14,7 +14,7 @@ print < -#ifdef G_HAVE_GNUC_VISIBILITY +#if defined(G_HAVE_GNUC_VISIBILITY) && !defined(__APPLE__) EOF diff --git a/gtk/queryimmodules.c b/gtk/queryimmodules.c index d20637e10..e118b9c19 100644 --- a/gtk/queryimmodules.c +++ b/gtk/queryimmodules.c @@ -159,9 +159,6 @@ query_module (const char *dir, const char *name, GString *contents) { void (*list) (const GtkIMContextInfo ***contexts, guint *n_contexts); - G_GNUC_UNUSED void (*init) (GTypeModule *type_module); - G_GNUC_UNUSED void (*exit) (void); - G_GNUC_UNUSED GtkIMContext *(*create) (const gchar *context_id); gpointer list_ptr; gpointer init_ptr; @@ -196,9 +193,6 @@ query_module (const char *dir, const char *name, GString *contents) int i; list = list_ptr; - init = init_ptr; - exit = exit_ptr; - create = create_ptr; print_escaped (contents, path); g_string_append_c (contents, '\n'); diff --git a/gtk/tests/builder.c b/gtk/tests/builder.c index ebba220e9..121012704 100644 --- a/gtk/tests/builder.c +++ b/gtk/tests/builder.c @@ -132,7 +132,7 @@ static int object = 0; static int object_after = 0; void /* exported for GtkBuilder */ -signal_normal (GtkWindow *window, GParamSpec spec) +signal_normal (GtkWindow *window, GParamSpec *spec) { g_assert (GTK_IS_WINDOW (window)); g_assert (normal == 0); @@ -142,7 +142,7 @@ signal_normal (GtkWindow *window, GParamSpec spec) } void /* exported for GtkBuilder */ -signal_after (GtkWindow *window, GParamSpec spec) +signal_after (GtkWindow *window, GParamSpec *spec) { g_assert (GTK_IS_WINDOW (window)); g_assert (normal == 1); @@ -152,7 +152,7 @@ signal_after (GtkWindow *window, GParamSpec spec) } void /* exported for GtkBuilder */ -signal_object (GtkButton *button, GParamSpec spec) +signal_object (GtkButton *button, GParamSpec *spec) { g_assert (GTK_IS_BUTTON (button)); g_assert (object == 0); @@ -162,7 +162,7 @@ signal_object (GtkButton *button, GParamSpec spec) } void /* exported for GtkBuilder */ -signal_object_after (GtkButton *button, GParamSpec spec) +signal_object_after (GtkButton *button, GParamSpec *spec) { g_assert (GTK_IS_BUTTON (button)); g_assert (object == 1); @@ -172,28 +172,28 @@ signal_object_after (GtkButton *button, GParamSpec spec) } void /* exported for GtkBuilder */ -signal_first (GtkButton *button, GParamSpec spec) +signal_first (GtkButton *button, GParamSpec *spec) { g_assert (normal == 0); normal = 10; } void /* exported for GtkBuilder */ -signal_second (GtkButton *button, GParamSpec spec) +signal_second (GtkButton *button, GParamSpec *spec) { g_assert (normal == 10); normal = 20; } void /* exported for GtkBuilder */ -signal_extra (GtkButton *button, GParamSpec spec) +signal_extra (GtkButton *button, GParamSpec *spec) { g_assert (normal == 20); normal = 30; } void /* exported for GtkBuilder */ -signal_extra2 (GtkButton *button, GParamSpec spec) +signal_extra2 (GtkButton *button, GParamSpec *spec) { g_assert (normal == 30); normal = 40; diff --git a/modules/other/gail/Makefile.am b/modules/other/gail/Makefile.am index 991512dea..1b9a4c6bd 100644 --- a/modules/other/gail/Makefile.am +++ b/modules/other/gail/Makefile.am @@ -72,6 +72,7 @@ libgailincludedir=$(includedir)/gail-1.0/gail gail_private_h_sources = \ gail.h \ + gailvalue.h \ gailadjustment.h \ gailarrow.h \ gailbooleancell.h \ diff --git a/modules/other/gail/gailadjustment.c b/modules/other/gail/gailadjustment.c index f1bb53f2b..021b79357 100644 --- a/modules/other/gail/gailadjustment.c +++ b/modules/other/gail/gailadjustment.c @@ -22,6 +22,7 @@ #include #include #include "gailadjustment.h" +#include "gailvalue.h" static void gail_adjustment_class_init (GailAdjustmentClass *klass); @@ -32,16 +33,25 @@ static void gail_adjustment_real_initialize (AtkObject *obj, static void atk_value_interface_init (AtkValueIface *iface); -static void gail_adjustment_get_current_value (AtkValue *obj, - GValue *value); -static void gail_adjustment_get_maximum_value (AtkValue *obj, - GValue *value); -static void gail_adjustment_get_minimum_value (AtkValue *obj, - GValue *value); -static void gail_adjustment_get_minimum_increment (AtkValue *obj, - GValue *value); -static gboolean gail_adjustment_set_current_value (AtkValue *obj, - const GValue *value); + +#ifdef HAVE_ATK_VALUE_2_12 +GAIL_DEFINE_ADJUSTMENT_VALUE_READERS ( + gail_adjustment, GAIL_ADJUSTMENT (obj)->adjustment, + adjustment->value, adjustment->upper) +GAIL_DEFINE_ADJUSTMENT_VALUE_INCREMENT ( + gail_adjustment, GAIL_ADJUSTMENT (obj)->adjustment, + GAIL_VALUE_MINIMUM_INCREMENT (adjustment)) + +static void +gail_adjustment_set_value (AtkValue *obj, gdouble value) +{ + GtkAdjustment *adjustment; + + adjustment = GAIL_ADJUSTMENT (obj)->adjustment; + if (adjustment != NULL) + gtk_adjustment_set_value (adjustment, value); +} +#endif static void gail_adjustment_destroyed (GtkAdjustment *adjustment, GailAdjustment *gail_adjustment); @@ -105,9 +115,15 @@ atk_value_interface_init (AtkValueIface *iface) iface->get_minimum_value = gail_adjustment_get_minimum_value; iface->get_minimum_increment = gail_adjustment_get_minimum_increment; iface->set_current_value = gail_adjustment_set_current_value; +#ifdef HAVE_ATK_VALUE_2_12 + iface->get_value_and_text = gail_adjustment_get_value_and_text; + iface->get_range = gail_adjustment_get_range; + iface->get_increment = gail_adjustment_get_increment; + iface->set_value = gail_adjustment_set_value; +#endif } -static void +void gail_adjustment_get_current_value (AtkValue *obj, GValue *value) { @@ -127,7 +143,7 @@ gail_adjustment_get_current_value (AtkValue *obj, g_value_set_double (value,current_value); } -static void +void gail_adjustment_get_maximum_value (AtkValue *obj, GValue *value) { @@ -147,7 +163,7 @@ gail_adjustment_get_maximum_value (AtkValue *obj, g_value_set_double (value, maximum_value); } -static void +void gail_adjustment_get_minimum_value (AtkValue *obj, GValue *value) { @@ -167,48 +183,20 @@ gail_adjustment_get_minimum_value (AtkValue *obj, g_value_set_double (value, minimum_value); } -static void -gail_adjustment_get_minimum_increment (AtkValue *obj, - GValue *value) +void +gail_adjustment_get_minimum_increment (AtkValue *obj, GValue *value) { - GtkAdjustment* adjustment; - gdouble minimum_increment; + GtkAdjustment *adjustment = GAIL_ADJUSTMENT (obj)->adjustment; - adjustment = GAIL_ADJUSTMENT (obj)->adjustment; if (adjustment == NULL) - { - /* State is defunct */ return; - } - if (adjustment->step_increment != 0 && - adjustment->page_increment != 0) - { - if (ABS (adjustment->step_increment) < ABS (adjustment->page_increment)) - minimum_increment = adjustment->step_increment; - else - minimum_increment = adjustment->page_increment; - } - else if (adjustment->step_increment == 0 && - adjustment->page_increment == 0) - { - minimum_increment = 0; - } - else if (adjustment->step_increment == 0) - { - minimum_increment = adjustment->page_increment; - } - else - { - minimum_increment = adjustment->step_increment; - } - - memset (value, 0, sizeof (GValue)); + memset (value, 0, sizeof (GValue)); g_value_init (value, G_TYPE_DOUBLE); - g_value_set_double (value, minimum_increment); + g_value_set_double (value, GAIL_VALUE_MINIMUM_INCREMENT (adjustment)); } -static gboolean +gboolean gail_adjustment_set_current_value (AtkValue *obj, const GValue *value) { diff --git a/modules/other/gail/gailadjustment.h b/modules/other/gail/gailadjustment.h index 790534dc9..0135b3d91 100644 --- a/modules/other/gail/gailadjustment.h +++ b/modules/other/gail/gailadjustment.h @@ -50,6 +50,22 @@ struct _GailAdjustmentClass AtkObject *gail_adjustment_new (GtkAdjustment *adjustment); +G_GNUC_INTERNAL void +gail_adjustment_get_current_value (AtkValue *obj, + GValue *value); +G_GNUC_INTERNAL void +gail_adjustment_get_maximum_value (AtkValue *obj, + GValue *value); +G_GNUC_INTERNAL void +gail_adjustment_get_minimum_value (AtkValue *obj, + GValue *value); +G_GNUC_INTERNAL void +gail_adjustment_get_minimum_increment (AtkValue *obj, + GValue *value); +G_GNUC_INTERNAL gboolean +gail_adjustment_set_current_value (AtkValue *obj, + const GValue *value); + G_END_DECLS #endif /* __GAIL_ADJUSTMENT_H__ */ diff --git a/modules/other/gail/gailpaned.c b/modules/other/gail/gailpaned.c index 5ac2d2340..42ac248da 100644 --- a/modules/other/gail/gailpaned.c +++ b/modules/other/gail/gailpaned.c @@ -22,6 +22,7 @@ #include #include #include "gailpaned.h" +#include "gailvalue.h" static void gail_paned_class_init (GailPanedClass *klass); @@ -44,6 +45,35 @@ static void gail_paned_get_minimum_value (AtkValue *obj, static gboolean gail_paned_set_current_value (AtkValue *obj, const GValue *value); +#ifdef HAVE_ATK_VALUE_2_12 +static void +gail_paned_get_value_and_text (AtkValue *obj, gdouble *value, gchar **text) +{ + GtkWidget *widget = GTK_ACCESSIBLE (obj)->widget; + + if (text != NULL) + *text = NULL; + if (value != NULL) + *value = widget != NULL + ? gtk_paned_get_position (GTK_PANED (widget)) : 0.0; +} + +static AtkRange * +gail_paned_get_range (AtkValue *obj) +{ + GtkWidget *widget = GTK_ACCESSIBLE (obj)->widget; + GtkPaned *paned; + + if (widget == NULL) + return NULL; + paned = GTK_PANED (widget); + return atk_range_new (paned->min_position, paned->max_position, NULL); +} + +GAIL_DEFINE_WIDGET_VALUE_SETTER ( + gail_paned, GTK_PANED, gtk_paned_set_position, (gint) value) +#endif + G_DEFINE_TYPE_WITH_CODE (GailPaned, gail_paned, GAIL_TYPE_CONTAINER, G_IMPLEMENT_INTERFACE (ATK_TYPE_VALUE, atk_value_interface_init)) @@ -112,6 +142,11 @@ atk_value_interface_init (AtkValueIface *iface) iface->get_maximum_value = gail_paned_get_maximum_value; iface->get_minimum_value = gail_paned_get_minimum_value; iface->set_current_value = gail_paned_set_current_value; +#ifdef HAVE_ATK_VALUE_2_12 + iface->get_value_and_text = gail_paned_get_value_and_text; + iface->get_range = gail_paned_get_range; + iface->set_value = gail_paned_set_value; +#endif } static void diff --git a/modules/other/gail/gailprogressbar.c b/modules/other/gail/gailprogressbar.c index d70c139be..6a0df280e 100644 --- a/modules/other/gail/gailprogressbar.c +++ b/modules/other/gail/gailprogressbar.c @@ -26,6 +26,7 @@ #include #include "gailprogressbar.h" +#include "gailvalue.h" #include "gailadjustment.h" static void gail_progress_bar_class_init (GailProgressBarClass *klass); @@ -50,6 +51,13 @@ static void gail_progress_bar_get_minimum_value (AtkValue *obj, static void gail_progress_bar_value_changed (GtkAdjustment *adjustment, gpointer data); +#ifdef HAVE_ATK_VALUE_2_12 +GAIL_DEFINE_ADJUSTMENT_VALUE_READERS ( + gail_progress_bar, + GAIL_VALUE_ADJUSTMENT (GAIL_PROGRESS_BAR (obj)->adjustment), + adjustment->value, adjustment->upper) +#endif + G_DEFINE_TYPE_WITH_CODE (GailProgressBar, gail_progress_bar, GAIL_TYPE_WIDGET, G_IMPLEMENT_INTERFACE (ATK_TYPE_VALUE, atk_value_interface_init)) @@ -108,6 +116,10 @@ atk_value_interface_init (AtkValueIface *iface) iface->get_current_value = gail_progress_bar_get_current_value; iface->get_maximum_value = gail_progress_bar_get_maximum_value; iface->get_minimum_value = gail_progress_bar_get_minimum_value; +#ifdef HAVE_ATK_VALUE_2_12 + iface->get_value_and_text = gail_progress_bar_get_value_and_text; + iface->get_range = gail_progress_bar_get_range; +#endif } static void @@ -125,7 +137,7 @@ gail_progress_bar_get_current_value (AtkValue *obj, */ return; - atk_value_get_current_value (ATK_VALUE (progress_bar->adjustment), value); + gail_adjustment_get_current_value (ATK_VALUE (progress_bar->adjustment), value); } static void @@ -143,7 +155,7 @@ gail_progress_bar_get_maximum_value (AtkValue *obj, */ return; - atk_value_get_maximum_value (ATK_VALUE (progress_bar->adjustment), value); + gail_adjustment_get_maximum_value (ATK_VALUE (progress_bar->adjustment), value); } static void @@ -161,7 +173,7 @@ gail_progress_bar_get_minimum_value (AtkValue *obj, */ return; - atk_value_get_minimum_value (ATK_VALUE (progress_bar->adjustment), value); + gail_adjustment_get_minimum_value (ATK_VALUE (progress_bar->adjustment), value); } static void diff --git a/modules/other/gail/gailrange.c b/modules/other/gail/gailrange.c index 9a91bb333..8170d86d0 100644 --- a/modules/other/gail/gailrange.c +++ b/modules/other/gail/gailrange.c @@ -23,6 +23,7 @@ #include #include #include "gailrange.h" +#include "gailvalue.h" #include "gailadjustment.h" #include "gail-private-macros.h" @@ -70,6 +71,28 @@ static gboolean gail_range_set_description (AtkAction *action, gint i, const gchar *desc); +#ifdef HAVE_ATK_VALUE_2_12 +#define GAIL_RANGE_ADJUSTMENT(obj) \ + (GTK_ACCESSIBLE (obj)->widget != NULL \ + ? GAIL_VALUE_ADJUSTMENT (GAIL_RANGE (obj)->adjustment) : NULL) +#define GAIL_RANGE_UPPER(obj, adjustment) \ + (gtk_range_get_restrict_to_fill_level ( \ + GTK_RANGE (GTK_ACCESSIBLE (obj)->widget)) \ + ? MIN ((adjustment)->upper - (adjustment)->page_size, \ + gtk_range_get_fill_level ( \ + GTK_RANGE (GTK_ACCESSIBLE (obj)->widget))) \ + : (adjustment)->upper - (adjustment)->page_size) + +GAIL_DEFINE_ADJUSTMENT_VALUE_READERS ( + gail_range, GAIL_RANGE_ADJUSTMENT (obj), adjustment->value, + GAIL_RANGE_UPPER (obj, adjustment)) +GAIL_DEFINE_ADJUSTMENT_VALUE_INCREMENT ( + gail_range, GAIL_RANGE_ADJUSTMENT (obj), + GAIL_VALUE_MINIMUM_INCREMENT (adjustment)) +GAIL_DEFINE_WIDGET_VALUE_SETTER ( + gail_range, GTK_RANGE, gtk_range_set_value, value) +#endif + G_DEFINE_TYPE_WITH_CODE (GailRange, gail_range, GAIL_TYPE_WIDGET, G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init) G_IMPLEMENT_INTERFACE (ATK_TYPE_VALUE, atk_value_interface_init)) @@ -163,6 +186,12 @@ atk_value_interface_init (AtkValueIface *iface) iface->get_minimum_value = gail_range_get_minimum_value; iface->get_minimum_increment = gail_range_get_minimum_increment; iface->set_current_value = gail_range_set_current_value; +#ifdef HAVE_ATK_VALUE_2_12 + iface->get_value_and_text = gail_range_get_value_and_text; + iface->get_range = gail_range_get_range; + iface->get_increment = gail_range_get_increment; + iface->set_value = gail_range_set_value; +#endif } static void @@ -180,7 +209,7 @@ gail_range_get_current_value (AtkValue *obj, */ return; - atk_value_get_current_value (ATK_VALUE (range->adjustment), value); + gail_adjustment_get_current_value (ATK_VALUE (range->adjustment), value); } static void @@ -201,7 +230,7 @@ gail_range_get_maximum_value (AtkValue *obj, */ return; - atk_value_get_maximum_value (ATK_VALUE (range->adjustment), value); + gail_adjustment_get_maximum_value (ATK_VALUE (range->adjustment), value); gtk_range = GTK_RANGE (gtk_accessible_get_widget (GTK_ACCESSIBLE (range))); g_return_if_fail (gtk_range); @@ -231,7 +260,7 @@ gail_range_get_minimum_value (AtkValue *obj, */ return; - atk_value_get_minimum_value (ATK_VALUE (range->adjustment), value); + gail_adjustment_get_minimum_value (ATK_VALUE (range->adjustment), value); } static void @@ -248,7 +277,7 @@ gail_range_get_minimum_increment (AtkValue *obj, GValue *value) */ return; - atk_value_get_minimum_increment (ATK_VALUE (range->adjustment), value); + gail_adjustment_get_minimum_increment (ATK_VALUE (range->adjustment), value); } static gboolean gail_range_set_current_value (AtkValue *obj, @@ -519,5 +548,3 @@ gail_range_set_description (AtkAction *action, else return FALSE; } - - diff --git a/modules/other/gail/gailscalebutton.c b/modules/other/gail/gailscalebutton.c index f04c69046..75915e43d 100644 --- a/modules/other/gail/gailscalebutton.c +++ b/modules/other/gail/gailscalebutton.c @@ -21,6 +21,7 @@ #include #include "gailscalebutton.h" +#include "gailvalue.h" #include "gailadjustment.h" #include "gail-private-macros.h" @@ -65,6 +66,24 @@ static void gail_scale_button_get_minimum_increment (AtkValue *obj, static gboolean gail_scale_button_set_current_value (AtkValue *obj, const GValue *value); +#ifdef HAVE_ATK_VALUE_2_12 +#define GAIL_SCALE_BUTTON_ADJUSTMENT(obj) \ + (GTK_ACCESSIBLE (obj)->widget != NULL \ + ? gtk_scale_button_get_adjustment ( \ + GTK_SCALE_BUTTON (GTK_ACCESSIBLE (obj)->widget)) : NULL) + +GAIL_DEFINE_ADJUSTMENT_VALUE_READERS ( + gail_scale_button, GAIL_SCALE_BUTTON_ADJUSTMENT (obj), + gtk_scale_button_get_value ( + GTK_SCALE_BUTTON (GTK_ACCESSIBLE (obj)->widget)), + adjustment->upper) +GAIL_DEFINE_ADJUSTMENT_VALUE_INCREMENT ( + gail_scale_button, GAIL_SCALE_BUTTON_ADJUSTMENT (obj), + adjustment->step_increment) +GAIL_DEFINE_WIDGET_VALUE_SETTER ( + gail_scale_button, GTK_SCALE_BUTTON, gtk_scale_button_set_value, value) +#endif + G_DEFINE_TYPE_WITH_CODE (GailScaleButton, gail_scale_button, GAIL_TYPE_BUTTON, G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init) G_IMPLEMENT_INTERFACE (ATK_TYPE_VALUE, atk_value_interface_init)); @@ -181,6 +200,12 @@ atk_value_interface_init (AtkValueIface *iface) iface->get_minimum_value = gail_scale_button_get_minimum_value; iface->get_minimum_increment = gail_scale_button_get_minimum_increment; iface->set_current_value = gail_scale_button_set_current_value; +#ifdef HAVE_ATK_VALUE_2_12 + iface->get_value_and_text = gail_scale_button_get_value_and_text; + iface->get_range = gail_scale_button_get_range; + iface->get_increment = gail_scale_button_get_increment; + iface->set_value = gail_scale_button_set_value; +#endif } static void @@ -295,5 +320,3 @@ gail_scale_button_notify_gtk (GObject *obj, GAIL_WIDGET_CLASS (gail_scale_button_parent_class)->notify_gtk (obj, pspec); } } - - diff --git a/modules/other/gail/gailspinbutton.c b/modules/other/gail/gailspinbutton.c index 709a413c0..36f2ffa32 100644 --- a/modules/other/gail/gailspinbutton.c +++ b/modules/other/gail/gailspinbutton.c @@ -22,6 +22,7 @@ #include #include #include "gailspinbutton.h" +#include "gailvalue.h" #include "gailadjustment.h" #include "gail-private-macros.h" @@ -49,6 +50,19 @@ static gboolean gail_spin_button_set_current_value (AtkValue *obj, static void gail_spin_button_value_changed (GtkAdjustment *adjustment, gpointer data); +#ifdef HAVE_ATK_VALUE_2_12 +GAIL_DEFINE_ADJUSTMENT_VALUE_READERS ( + gail_spin_button, + GAIL_VALUE_ADJUSTMENT (GAIL_SPIN_BUTTON (obj)->adjustment), + adjustment->value, adjustment->upper) +GAIL_DEFINE_ADJUSTMENT_VALUE_INCREMENT ( + gail_spin_button, + GAIL_VALUE_ADJUSTMENT (GAIL_SPIN_BUTTON (obj)->adjustment), + GAIL_VALUE_MINIMUM_INCREMENT (adjustment)) +GAIL_DEFINE_WIDGET_VALUE_SETTER ( + gail_spin_button, GTK_SPIN_BUTTON, gtk_spin_button_set_value, value) +#endif + G_DEFINE_TYPE_WITH_CODE (GailSpinButton, gail_spin_button, GAIL_TYPE_ENTRY, G_IMPLEMENT_INTERFACE (ATK_TYPE_VALUE, atk_value_interface_init)) @@ -110,6 +124,12 @@ atk_value_interface_init (AtkValueIface *iface) iface->get_minimum_value = gail_spin_button_get_minimum_value; iface->get_minimum_increment = gail_spin_button_get_minimum_increment; iface->set_current_value = gail_spin_button_set_current_value; +#ifdef HAVE_ATK_VALUE_2_12 + iface->get_value_and_text = gail_spin_button_get_value_and_text; + iface->get_range = gail_spin_button_get_range; + iface->get_increment = gail_spin_button_get_increment; + iface->set_value = gail_spin_button_set_value; +#endif } static void @@ -127,7 +147,7 @@ gail_spin_button_get_current_value (AtkValue *obj, */ return; - atk_value_get_current_value (ATK_VALUE (spin_button->adjustment), value); + gail_adjustment_get_current_value (ATK_VALUE (spin_button->adjustment), value); } static void @@ -145,7 +165,7 @@ gail_spin_button_get_maximum_value (AtkValue *obj, */ return; - atk_value_get_maximum_value (ATK_VALUE (spin_button->adjustment), value); + gail_adjustment_get_maximum_value (ATK_VALUE (spin_button->adjustment), value); } static void @@ -163,7 +183,7 @@ gail_spin_button_get_minimum_value (AtkValue *obj, */ return; - atk_value_get_minimum_value (ATK_VALUE (spin_button->adjustment), value); + gail_adjustment_get_minimum_value (ATK_VALUE (spin_button->adjustment), value); } static void @@ -180,7 +200,7 @@ gail_spin_button_get_minimum_increment (AtkValue *obj, GValue *value) */ return; - atk_value_get_minimum_increment (ATK_VALUE (spin_button->adjustment), value); + gail_adjustment_get_minimum_increment (ATK_VALUE (spin_button->adjustment), value); } static gboolean @@ -198,7 +218,7 @@ gail_spin_button_set_current_value (AtkValue *obj, */ return FALSE; - return atk_value_set_current_value (ATK_VALUE (spin_button->adjustment), value); + return gail_adjustment_set_current_value (ATK_VALUE (spin_button->adjustment), value); } static void @@ -264,4 +284,3 @@ gail_spin_button_value_changed (GtkAdjustment *adjustment, g_object_notify (G_OBJECT (spin_button), "accessible-value"); } - diff --git a/modules/other/gail/gailvalue.h b/modules/other/gail/gailvalue.h new file mode 100644 index 000000000..498453424 --- /dev/null +++ b/modules/other/gail/gailvalue.h @@ -0,0 +1,56 @@ +/* GAIL - The GNOME Accessibility Implementation Library + * + * 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. + */ +#ifndef __GAIL_VALUE_H__ +#define __GAIL_VALUE_H__ + +#include + +#define GAIL_VALUE_ADJUSTMENT(accessible) \ + ((accessible) != NULL ? GAIL_ADJUSTMENT (accessible)->adjustment : NULL) +#define GAIL_VALUE_MINIMUM_INCREMENT(a) \ + ((a)->step_increment == 0.0 ? (a)->page_increment : \ + (a)->page_increment == 0.0 ? (a)->step_increment : \ + ABS ((a)->step_increment) < ABS ((a)->page_increment) \ + ? (a)->step_increment : (a)->page_increment) + +#ifdef HAVE_ATK_VALUE_2_12 +#define GAIL_DEFINE_ADJUSTMENT_VALUE_READERS(prefix, a_expr, value_expr, max_expr) \ +static void prefix##_get_value_and_text (AtkValue *obj, gdouble *value, gchar **text) \ +{ \ + GtkAdjustment *adjustment = (a_expr); \ + if (text != NULL) *text = NULL; \ + if (value != NULL) *value = adjustment != NULL ? (value_expr) : 0.0; \ +} \ +static AtkRange *prefix##_get_range (AtkValue *obj) \ +{ \ + GtkAdjustment *adjustment = (a_expr); \ + return adjustment != NULL \ + ? atk_range_new (adjustment->lower, (max_expr), NULL) : NULL; \ +} + +#define GAIL_DEFINE_ADJUSTMENT_VALUE_INCREMENT(prefix, a_expr, increment_expr) \ +static gdouble prefix##_get_increment (AtkValue *obj) \ +{ \ + GtkAdjustment *adjustment = (a_expr); \ + return adjustment != NULL ? (increment_expr) : 0.0; \ +} + +#define GAIL_DEFINE_WIDGET_VALUE_SETTER(prefix, cast, setter, value_expr) \ +static void prefix##_set_value (AtkValue *obj, gdouble value) \ +{ \ + GtkWidget *widget = GTK_ACCESSIBLE (obj)->widget; \ + if (widget != NULL) setter (cast (widget), (value_expr)); \ +} +#endif + +#endif /* __GAIL_VALUE_H__ */ diff --git a/modules/other/gail/tests/Makefile.am b/modules/other/gail/tests/Makefile.am index 993249558..0f0e02317 100644 --- a/modules/other/gail/tests/Makefile.am +++ b/modules/other/gail/tests/Makefile.am @@ -12,6 +12,8 @@ module_LTLIBRARIES = \ libferret.la endif +noinst_HEADERS = testvalue.h + noinst_LTLIBRARIES = \ libtestaction.la \ libtestbutton.la \ diff --git a/modules/other/gail/tests/ferret.c b/modules/other/gail/tests/ferret.c index 711852af0..39eaef441 100644 --- a/modules/other/gail/tests/ferret.c +++ b/modules/other/gail/tests/ferret.c @@ -16,6 +16,7 @@ #include #include "testlib.h" +#include "testvalue.h" typedef enum { @@ -1389,7 +1390,8 @@ _print_text_attributes (AtkText *aobject) static gint _print_value (AtkValue *aobject) { - GValue *value_back, val; + GValue val = { 0, }; + GValue *value_back; gint group_num; TabNumber tab_n = VALUE; @@ -1398,11 +1400,11 @@ _print_value (AtkValue *aobject) group_num = _print_groupname(tab_n, VALUE_INTERFACE, "Value Interface"); - atk_value_get_current_value(aobject, value_back); + gail_test_value_get_current_value(aobject, value_back); _print_value_type(group_num, "Value", value_back); - atk_value_get_minimum_value(aobject, value_back); + gail_test_value_get_minimum_value(aobject, value_back); _print_value_type(group_num, "Minimum Value", value_back); - atk_value_get_maximum_value(aobject, value_back); + gail_test_value_get_maximum_value(aobject, value_back); _print_value_type(group_num, "Maximum Value", value_back); return(group_num); } diff --git a/modules/other/gail/tests/testpaned.c b/modules/other/gail/tests/testpaned.c index 300031955..7e1f27f1c 100644 --- a/modules/other/gail/tests/testpaned.c +++ b/modules/other/gail/tests/testpaned.c @@ -2,6 +2,7 @@ #include #include #include +#include "testvalue.h" static gint _test_paned (gpointer data); static void _check_paned (AtkObject *obj); @@ -31,17 +32,17 @@ static void _property_change_handler (AtkObject *obj, value = &val; memset (value, 0, sizeof (GValue)); - atk_value_get_current_value (ATK_VALUE (obj), value); + gail_test_value_get_current_value (ATK_VALUE (obj), value); g_return_if_fail (G_VALUE_HOLDS_INT (value)); position = g_value_get_int (value); g_print ("Position is %d previous position was %d\n", position, last_position); last_position = position; - atk_value_get_minimum_value (ATK_VALUE (obj), value); + gail_test_value_get_minimum_value (ATK_VALUE (obj), value); g_return_if_fail (G_VALUE_HOLDS_INT (value)); position = g_value_get_int (value); g_print ("Minimum Value is %d\n", position); - atk_value_get_maximum_value (ATK_VALUE (obj), value); + gail_test_value_get_maximum_value (ATK_VALUE (obj), value); g_return_if_fail (G_VALUE_HOLDS_INT (value)); position = g_value_get_int (value); g_print ("Maximum Value is %d\n", position); @@ -61,14 +62,14 @@ static gint _test_paned (gpointer data) value = &val; memset (value, 0, sizeof (GValue)); - atk_value_get_current_value (ATK_VALUE (obj), value); + gail_test_value_get_current_value (ATK_VALUE (obj), value); g_return_val_if_fail (G_VALUE_HOLDS_INT (value), FALSE); position = g_value_get_int (value); g_print ("Position is : %d\n", position); last_position = position; position *= 2; g_value_set_int (value, position); - atk_value_set_current_value (ATK_VALUE (obj), value); + gail_test_value_set_current_value (ATK_VALUE (obj), value); times++; } if (times < 4) diff --git a/modules/other/gail/tests/testvalue.h b/modules/other/gail/tests/testvalue.h new file mode 100644 index 000000000..735278318 --- /dev/null +++ b/modules/other/gail/tests/testvalue.h @@ -0,0 +1,98 @@ +#ifndef __GAIL_TEST_VALUE_H__ +#define __GAIL_TEST_VALUE_H__ + +#include "config.h" + +#include + +#ifdef HAVE_ATK_VALUE_2_12 + +static void +gail_test_value_store_number (AtkValue *value, + GValue *result, + gdouble number) +{ + if (G_VALUE_TYPE (result) == 0) + g_value_init (result, + atk_object_get_role (ATK_OBJECT (value)) == + ATK_ROLE_SPLIT_PANE ? G_TYPE_INT : G_TYPE_DOUBLE); + + if (G_VALUE_HOLDS_INT (result)) + g_value_set_int (result, (gint) number); + else + { + g_return_if_fail (G_VALUE_HOLDS_DOUBLE (result)); + g_value_set_double (result, number); + } +} + +static void +gail_test_value_get_current_value (AtkValue *value, + GValue *result) +{ + gdouble number; + + atk_value_get_value_and_text (value, &number, NULL); + gail_test_value_store_number (value, result, number); +} + +static void +gail_test_value_get_limit (AtkValue *value, + GValue *result, + gboolean upper) +{ + AtkRange *range; + gdouble number; + + range = atk_value_get_range (value); + g_return_if_fail (range != NULL); + + if (upper) + number = atk_range_get_upper_limit (range); + else + number = atk_range_get_lower_limit (range); + + atk_range_free (range); + gail_test_value_store_number (value, result, number); +} + +#define gail_test_value_get_minimum_value(value, result) \ + gail_test_value_get_limit ((value), (result), FALSE) + +#define gail_test_value_get_maximum_value(value, result) \ + gail_test_value_get_limit ((value), (result), TRUE) + +#define GAIL_TEST_VALUE_NUMBER(value) \ + (G_VALUE_HOLDS_INT (value) \ + ? (gdouble) g_value_get_int (value) \ + : g_value_get_double (value)) + +#define gail_test_value_set_current_value(value, new_value) \ + (atk_value_set_value ((value), \ + GAIL_TEST_VALUE_NUMBER (new_value)), \ + TRUE) + +#else + +#define GAIL_TEST_VALUE_IFACE(value) \ + ATK_VALUE_GET_IFACE (value) + +#define gail_test_value_get_current_value(value, result) \ + (GAIL_TEST_VALUE_IFACE (value)->get_current_value ( \ + (value), (result))) + +#define gail_test_value_get_minimum_value(value, result) \ + (GAIL_TEST_VALUE_IFACE (value)->get_minimum_value ( \ + (value), (result))) + +#define gail_test_value_get_maximum_value(value, result) \ + (GAIL_TEST_VALUE_IFACE (value)->get_maximum_value ( \ + (value), (result))) + +#define gail_test_value_set_current_value(value, new_value) \ + (GAIL_TEST_VALUE_IFACE (value)->set_current_value ( \ + (value), (new_value))) + +#endif + +#endif /* __GAIL_TEST_VALUE_H__ */ diff --git a/modules/other/gail/tests/testvalues.c b/modules/other/gail/tests/testvalues.c index 34d91a25a..37155855c 100644 --- a/modules/other/gail/tests/testvalues.c +++ b/modules/other/gail/tests/testvalues.c @@ -1,6 +1,7 @@ #include #include #include +#include "testvalue.h" static void _traverse_children (AtkObject *obj); static void _add_handler (AtkObject *obj); @@ -14,8 +15,8 @@ static void _value_change_handler (AtkObject *obj, AtkPropertyValues *values) { const gchar *type_name = g_type_name (G_TYPE_FROM_INSTANCE (obj)); - GValue *value_back, val; - + GValue val = { 0, }; + GValue *value_back; value_back = &val; if (!ATK_IS_VALUE (obj)) { @@ -33,17 +34,17 @@ static void _value_change_handler (AtkObject *obj, g_print("Now calling the AtkValue interface functions\n"); - atk_value_get_current_value (ATK_VALUE(obj), value_back); + gail_test_value_get_current_value (ATK_VALUE(obj), value_back); g_return_if_fail (G_VALUE_HOLDS_DOUBLE (value_back)); g_print ("atk_value_get_current_value returns %f\n", g_value_get_double (value_back) ); - atk_value_get_maximum_value (ATK_VALUE (obj), value_back); + gail_test_value_get_maximum_value (ATK_VALUE (obj), value_back); g_return_if_fail (G_VALUE_HOLDS_DOUBLE (value_back)); g_print ("atk_value_get_maximum returns %f\n", g_value_get_double (value_back)); - atk_value_get_minimum_value (ATK_VALUE (obj), value_back); + gail_test_value_get_minimum_value (ATK_VALUE (obj), value_back); g_return_if_fail (G_VALUE_HOLDS_DOUBLE (value_back)); g_print ("atk_value_get_minimum returns %f\n", g_value_get_double (value_back)); @@ -103,7 +104,8 @@ static void _add_handler (AtkObject *obj) static void _set_values (AtkObject *obj) { - GValue *value_back, val; + GValue val = { 0, }; + GValue *value_back; static gint count = 0; gdouble double_value; @@ -125,7 +127,7 @@ static void _set_values (AtkObject *obj) { text = "5.7"; atk_editable_text_set_text_contents(ATK_EDITABLE_TEXT(obj),text); g_print("Set text to %s\n",text); - atk_value_get_current_value(ATK_VALUE(obj), value_back); + gail_test_value_get_current_value(ATK_VALUE(obj), value_back); g_return_if_fail (G_VALUE_HOLDS_DOUBLE (value_back)); g_print("atk_value_get_current_value returns %f\n", g_value_get_double( value_back)); @@ -134,7 +136,7 @@ static void _set_values (AtkObject *obj) { memset (value_back, 0, sizeof (GValue)); g_value_init (value_back, G_TYPE_DOUBLE); g_value_set_double (value_back, 10.0); - if (atk_value_set_current_value (ATK_VALUE (obj), value_back)) + if (gail_test_value_set_current_value (ATK_VALUE (obj), value_back)) { double_value = g_value_get_double (value_back); g_print("atk_value_set_current_value returns %f\n", diff --git a/modules/printbackends/cups/gtkcupsutils.c b/modules/printbackends/cups/gtkcupsutils.c index fdfe21e91..f96b7a5b5 100644 --- a/modules/printbackends/cups/gtkcupsutils.c +++ b/modules/printbackends/cups/gtkcupsutils.c @@ -34,6 +34,11 @@ typedef void (*GtkCupsRequestStateFunc) (GtkCupsRequest *request); +static http_t *gtk_cups_http_connect (const char *host, + int port, + http_encryption_t encryption); +static int gtk_cups_http_reconnect (http_t *http); + static void _connect (GtkCupsRequest *request); static void _post_send (GtkCupsRequest *request); static void _post_write_request (GtkCupsRequest *request); @@ -171,7 +176,7 @@ gtk_cups_request_new_with_username (http_t *connection, else { request->http = NULL; - request->http = httpConnectEncrypt (request->server, + request->http = gtk_cups_http_connect (request->server, ippPort (), cupsEncryption ()); @@ -681,6 +686,29 @@ gtk_cups_request_set_ipp_version (GtkCupsRequest *request, ippSetVersion (request->ipp_request, major, minor); } + +static http_t * +gtk_cups_http_connect (const char *host, + int port, + http_encryption_t encryption) +{ +#ifdef HAVE_HTTPCONNECT2 + return httpConnect2 (host, port, NULL, AF_UNSPEC, encryption, 1, 30000, NULL); +#else + return httpConnectEncrypt (host, port, encryption); +#endif +} + +static int +gtk_cups_http_reconnect (http_t *http) +{ +#ifdef HAVE_HTTPRECONNECT2 + return httpReconnect2 (http, 30000, NULL); +#else + return httpReconnect (http); +#endif +} + static void _connect (GtkCupsRequest *request) { @@ -689,7 +717,7 @@ _connect (GtkCupsRequest *request) if (request->http == NULL) { - request->http = httpConnectEncrypt (request->server, + request->http = gtk_cups_http_connect (request->server, ippPort (), cupsEncryption ()); @@ -744,7 +772,7 @@ _post_send (GtkCupsRequest *request) if (httpPost (request->http, request->resource)) { - if (httpReconnect (request->http)) + if (gtk_cups_http_reconnect (request->http)) { request->state = GTK_CUPS_POST_DONE; request->poll_state = GTK_CUPS_HTTP_IDLE; @@ -1046,7 +1074,7 @@ _post_check (GtkCupsRequest *request) } if (auth_result || - httpReconnect (request->http)) + gtk_cups_http_reconnect (request->http)) { /* if the password has been used, reset password_state * so that we ask for a new one next time around @@ -1105,7 +1133,7 @@ _post_check (GtkCupsRequest *request) request->state = GTK_CUPS_POST_CONNECT; /* Reconnect... */ - httpReconnect (request->http); + gtk_cups_http_reconnect (request->http); /* Upgrade with encryption... */ httpEncryption (request->http, HTTP_ENCRYPT_REQUIRED); @@ -1232,7 +1260,7 @@ _get_send (GtkCupsRequest *request) if (httpGet (request->http, request->resource)) { - if (httpReconnect (request->http)) + if (gtk_cups_http_reconnect (request->http)) { request->state = GTK_CUPS_GET_DONE; request->poll_state = GTK_CUPS_HTTP_IDLE; @@ -1341,7 +1369,7 @@ _get_check (GtkCupsRequest *request) } if (auth_result || - httpReconnect (request->http)) + gtk_cups_http_reconnect (request->http)) { /* if the password has been used, reset password_state * so that we ask for a new one next time around @@ -1373,7 +1401,7 @@ _get_check (GtkCupsRequest *request) request->state = GTK_CUPS_GET_CONNECT; /* Reconnect... */ - httpReconnect (request->http); + gtk_cups_http_reconnect (request->http); /* Upgrade with encryption... */ httpEncryption (request->http, HTTP_ENCRYPT_REQUIRED); diff --git a/modules/printbackends/cups/gtkprintbackendcups.c b/modules/printbackends/cups/gtkprintbackendcups.c index e17d97d21..d07d1bc7a 100644 --- a/modules/printbackends/cups/gtkprintbackendcups.c +++ b/modules/printbackends/cups/gtkprintbackendcups.c @@ -489,6 +489,44 @@ cups_free_print_stream_data (CupsPrintStreamData *data) g_free (data); } + +static http_t * +gtk_cups_backend_http_connect (const char *host, + int port) +{ +#ifdef HAVE_HTTPCONNECT2 + return httpConnect2 (host, + port, + NULL, + AF_UNSPEC, + HTTP_ENCRYPT_IF_REQUESTED, + 1, + 30000, + NULL); +#else + return httpConnect (host, port); +#endif +} + +static http_t * +gtk_cups_backend_http_connect_encrypt (const char *host, + int port, + http_encryption_t encryption) +{ +#ifdef HAVE_HTTPCONNECT2 + return httpConnect2 (host, + port, + NULL, + AF_UNSPEC, + encryption, + 1, + 30000, + NULL); +#else + return httpConnectEncrypt (host, port, encryption); +#endif +} + static void cups_print_cb (GtkPrintBackendCups *print_backend, GtkCupsResult *result, @@ -636,7 +674,9 @@ gtk_print_backend_cups_print_stream (GtkPrintBackend *print_backend, { http_t *http; - http = httpConnect (cups_printer->hostname, cups_printer->port); + http = gtk_cups_backend_http_connect ( + cups_printer->hostname, + cups_printer->port); if (http) { request = gtk_cups_request_new_with_username (http, @@ -2555,7 +2595,7 @@ cups_request_avahi_printer_info (const gchar *printer_uri, AvahiService *service; http_t *http; - http = httpConnect (host, port); + http = gtk_cups_backend_http_connect (host, port); if (http) { service = (AvahiService *) g_new0 (AvahiService, 1); @@ -3438,7 +3478,7 @@ cups_request_ppd (GtkPrinter *printer) } } - http = httpConnectEncrypt (cups_printer->hostname, + http = gtk_cups_backend_http_connect_encrypt (cups_printer->hostname, cups_printer->port, cupsEncryption ());