diff --git a/configure.ac b/configure.ac index 29297423f..553ea001c 100644 --- a/configure.ac +++ b/configure.ac @@ -399,6 +399,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 +474,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 @@ -1533,6 +1538,11 @@ LIBS="$old_LIBS" # Printing system checks ################################################################ +AC_ARG_ENABLE(cups-secret-service, + [AS_HELP_STRING([--disable-cups-secret-service] + [disable Secret Service support in the cups print backend])],, + [enable_cups_secret_service=yes]) + AC_ARG_ENABLE(cups, [AS_HELP_STRING([--disable-cups] [disable cups print backend])],, @@ -1579,6 +1589,17 @@ else AM_CONDITIONAL(HAVE_CUPS, true) + if test "x$enable_cups_secret_service" != "xno"; then + PKG_CHECK_EXISTS([libsecret-1], [], + [AC_MSG_ERROR([ +*** libsecret-1 is required when CUPS Secret Service support is enabled. +*** Install the libsecret development files or configure +*** with --disable-cups-secret-service. +])]) + AC_DEFINE([HAVE_CUPS_SECRET_SERVICE], [1], + [Define to 1 if CUPS Secret Service support is enabled]) + fi + gtk_save_cflags="$CFLAGS" CFLAGS="$CUPS_CFLAGS" AC_COMPILE_IFELSE( @@ -1594,6 +1615,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..2b68f98a6 100644 --- a/gdk/Makefile.am +++ b/gdk/Makefile.am @@ -145,6 +145,7 @@ gdk_c_sources = \ gdkrectangle.c \ gdkregion-generic.c \ gdkrgb.c \ + gdkrgb16.c \ gdkscreen.c \ gdkselection.c \ gdkvisual.c \ @@ -213,6 +214,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 +274,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.symbols b/gdk/gdk.symbols index ee1bc0c98..b48eac70b 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_RGB16_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/gdkrgb.c b/gdk/gdkrgb.c index b0ff66833..e4f63ddaf 100644 --- a/gdk/gdkrgb.c +++ b/gdk/gdkrgb.c @@ -1464,19 +1464,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 +1534,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 +1549,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 +1584,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 +1617,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 +1655,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 +1670,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 +1772,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 +1827,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 +1874,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 +1992,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, @@ -2242,6 +2322,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 +2697,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 +2706,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 +2717,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,6 +2730,18 @@ 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; } @@ -3195,6 +3346,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; @@ -3261,7 +3440,7 @@ gdk_rgb_select_conv (GdkRgbInfo *image_info) conv = gdk_rgb_convert_gray4_pack; conv_d = gdk_rgb_convert_gray4_d_pack; } - else if (bpp == 4 && depth == 4 && + else if (bpp == 4 && depth <= 4 && depth >= 2 && vtype == GDK_VISUAL_STATIC_COLOR) conv = gdk_rgb_convert_4_pack; 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/gdkrgb16.c b/gdk/gdkrgb16.c new file mode 100644 index 000000000..2564ef0d8 --- /dev/null +++ b/gdk/gdkrgb16.c @@ -0,0 +1,742 @@ +/* GTK - The GIMP Toolkit + * High-precision GdkRGB image conversion + * + * 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. + */ + +#include "config.h" + +#include + +#include "gdkinternals.h" +#include "gdkrgb.h" +#include "gdkscreen.h" +#include "gdkalias.h" + +typedef void (*GdkRgb16ConvFunc) (GdkImage *image, + gint x0, + gint y0, + gint width, + gint height, + const guint16 *buf, + gint rowstride); + +#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 (GdkImage *image, \ + gint x0, \ + gint y0, \ + gint width, \ + gint height, \ + const guint16 *buf, \ + gint rowstride) \ +{ \ + const guchar *row; \ + const guint16 *src; \ + guchar *dst_row; \ + guchar *dst; \ + guint32 r, g, b; \ + guint32 alpha_mask; \ + gint x, y; \ + \ + row = (const guchar *) buf; \ + 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 GdkRgb16ConvFunc +gdk_rgb16_select_converter (GdkDrawable *drawable, + gboolean is_rgbx, + GdkRgbDither dith) +{ + GdkVisual *visual; + GdkByteOrder byte_order; + GdkScreen *screen; + 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 + + /* + * Preserve the existing GdkRGB dither path for maximum dithering + * and for unknown future values. + */ + if (dith != GDK_RGB_DITHER_NONE && + dith != GDK_RGB_DITHER_NORMAL) + return NULL; + + visual = gdk_drawable_get_visual (drawable); + if (visual == NULL) + return NULL; + + if (gdk_visual_get_visual_type (visual) != GDK_VISUAL_TRUE_COLOR) + return NULL; + + screen = gdk_visual_get_screen (visual); + depth = gdk_visual_get_depth (visual); + byte_order = gdk_visual_get_byte_order (visual); + + gdk_visual_get_red_pixel_details (visual, &red_mask, NULL, NULL); + gdk_visual_get_green_pixel_details (visual, &green_mask, NULL, NULL); + gdk_visual_get_blue_pixel_details (visual, &blue_mask, NULL, NULL); + + bits_per_pixel = _gdk_windowing_get_bits_for_depth + (gdk_screen_get_display (screen), depth); + +#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_rgb16_draw_direct (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y, + gint width, + gint height, + const guint16 *buf, + gint pixel_words, + gint rowstride, + GdkRgb16ConvFunc converter) +{ + GdkScreen *screen; + GdkImage *image; + const guint16 *tile; + gint depth; + gint x0, y0; + gint xs0, ys0; + gint width1, height1; + + screen = gdk_drawable_get_screen (drawable); + depth = gdk_drawable_get_depth (drawable); + + 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); + + tile = (const guint16 *) + ((const guchar *) buf + + y0 * rowstride + + x0 * pixel_words * sizeof (guint16)); + + image = _gdk_image_get_scratch (screen, + width1, + height1, + depth, + &xs0, + &ys0); + + converter (image, + xs0, + ys0, + width1, + height1, + tile, + rowstride); + + gdk_draw_image (drawable, + gc, + image, + xs0, + ys0, + x + x0, + y + y0, + width1, + height1); + } + } +} + +static void +gdk_rgb16_draw_fallback (GdkDrawable *drawable, + GdkGC *gc, + gint x, + gint y, + gint width, + gint height, + GdkRgbDither dith, + const guint16 *buf, + gint pixel_words, + gint rowstride, + gint xdith, + gint ydith) +{ + const guchar *input_row; + const guint16 *input; + guchar *stage; + guchar *output; + gint stage_rowstride; + gint x0, y0; + gint x1, y1; + gint width1, height1; + + stage = g_malloc (MIN (width, GDK_SCRATCH_IMAGE_WIDTH) * + MIN (height, GDK_SCRATCH_IMAGE_HEIGHT) * 3); + + 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); + stage_rowstride = width1 * 3; + + input_row = (const guchar *) buf + + y0 * rowstride + + x0 * pixel_words * sizeof (guint16); + output = stage; + + for (y1 = 0; y1 < height1; y1++) + { + input = (const guint16 *) input_row; + + for (x1 = 0; x1 < width1; x1++) + { + *output++ = input[0] >> 8; + *output++ = input[1] >> 8; + *output++ = input[2] >> 8; + input += pixel_words; + } + + input_row += rowstride; + } + + gdk_draw_rgb_image_dithalign (drawable, + gc, + x + x0, + y + y0, + width1, + height1, + dith, + stage, + stage_rowstride, + xdith, + ydith); + } + } + + g_free (stage); +} + +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) +{ + GdkRgb16ConvFunc converter; + gint pixel_words; + + 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; + + pixel_words = is_rgbx ? 4 : 3; + converter = gdk_rgb16_select_converter (drawable, is_rgbx, dith); + + if (converter != NULL) + gdk_rgb16_draw_direct (drawable, + gc, + x, + y, + width, + height, + buf, + pixel_words, + rowstride, + converter); + else + gdk_rgb16_draw_fallback (drawable, + gc, + x, + y, + width, + height, + dith, + buf, + pixel_words, + rowstride, + 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); +} + +#define __GDK_RGB16_C__ +#include "gdkaliasdef.c" diff --git a/gdk/makefile.msc b/gdk/makefile.msc index e9f816931..6175c3f21 100644 --- a/gdk/makefile.msc +++ b/gdk/makefile.msc @@ -92,6 +92,7 @@ gdk_OBJECTS = \ gdkrectangle.obj \ gdkregion-generic.obj \ gdkrgb.obj \ + gdkrgb16.obj \ gdkscreen.obj \ gdkselection.obj \ gdkvisual.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/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/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/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/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/gtkprintbackend.c b/gtk/gtkprintbackend.c index 66f5b41a9..5efd124e5 100644 --- a/gtk/gtkprintbackend.c +++ b/gtk/gtkprintbackend.c @@ -48,8 +48,22 @@ struct _GtkPrintBackendPrivate GtkPrintBackendStatus status; char **auth_info_required; char **auth_info; +#ifdef HAVE_CUPS_SECRET_SERVICE + guint store_auth_info : 1; +#endif }; +#ifdef HAVE_CUPS_SECRET_SERVICE +typedef gboolean (*GtkPrintBackendCanStoreAuthInfoFunc) + (GtkPrintBackend *backend); + +typedef void (*GtkPrintBackendSetPasswordFullFunc) + (GtkPrintBackend *backend, + gchar **auth_info_required, + gchar **auth_info, + gboolean store_auth_info); +#endif + enum { PRINTER_LIST_CHANGED, PRINTER_LIST_DONE, @@ -459,6 +473,9 @@ gtk_print_backend_init (GtkPrintBackend *backend) (GDestroyNotify) g_object_unref); priv->auth_info_required = NULL; priv->auth_info = NULL; +#ifdef HAVE_CUPS_SECRET_SERVICE + priv->store_auth_info = FALSE; +#endif } static void @@ -675,6 +692,41 @@ gtk_print_backend_set_password (GtkPrintBackend *backend, GTK_PRINT_BACKEND_GET_CLASS (backend)->set_password (backend, auth_info_required, auth_info); } + +#ifdef HAVE_CUPS_SECRET_SERVICE +static void +gtk_print_backend_set_password_full (GtkPrintBackend *backend, + gchar **auth_info_required, + gchar **auth_info, + gboolean store_auth_info) +{ + GtkPrintBackendClass *class; + + class = GTK_PRINT_BACKEND_GET_CLASS (backend); + + if (class->_gtk_reserved2 != NULL) + ((GtkPrintBackendSetPasswordFullFunc) class->_gtk_reserved2) + (backend, + auth_info_required, + auth_info, + store_auth_info); + else + gtk_print_backend_set_password (backend, + auth_info_required, + auth_info); +} + + +static void +store_auth_info_toggled (GtkToggleButton *button, + GtkPrintBackend *backend) +{ + backend->priv->store_auth_info = + gtk_toggle_button_get_active (button); +} +#endif + + static void store_entry (GtkEntry *entry, gpointer user_data) @@ -698,10 +750,23 @@ password_dialog_response (GtkWidget *dialog, GtkPrintBackendPrivate *priv = backend->priv; gint i; +#ifdef HAVE_CUPS_SECRET_SERVICE + if (response_id == GTK_RESPONSE_OK) + gtk_print_backend_set_password_full (backend, + priv->auth_info_required, + priv->auth_info, + priv->store_auth_info); + else + gtk_print_backend_set_password_full (backend, + priv->auth_info_required, + NULL, + FALSE); +#else if (response_id == GTK_RESPONSE_OK) gtk_print_backend_set_password (backend, priv->auth_info_required, priv->auth_info); else gtk_print_backend_set_password (backend, priv->auth_info_required, NULL); +#endif for (i = 0; i < g_strv_length (priv->auth_info_required); i++) if (priv->auth_info[i] != NULL) @@ -738,10 +803,23 @@ request_password (GtkPrintBackend *backend, gchar **ai_default = (gchar **) auth_info_default; gchar **ai_display = (gchar **) auth_info_display; gboolean *ai_visible = (gboolean *) auth_info_visible; +#ifdef HAVE_CUPS_SECRET_SERVICE + GtkPrintBackendClass *class; + gboolean can_store_auth_info = FALSE; +#endif priv->auth_info_required = g_strdupv (ai_required); length = g_strv_length (ai_required); priv->auth_info = g_new0 (gchar *, length + 1); +#ifdef HAVE_CUPS_SECRET_SERVICE + priv->store_auth_info = FALSE; + + class = GTK_PRINT_BACKEND_GET_CLASS (backend); + if (class->_gtk_reserved1 != NULL) + can_store_auth_info = + ((GtkPrintBackendCanStoreAuthInfoFunc) class->_gtk_reserved1) + (backend); +#endif dialog = gtk_dialog_new_with_buttons ( _("Authentication"), NULL, GTK_DIALOG_MODAL, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, @@ -810,6 +888,18 @@ request_password (GtkPrintBackend *backend, } } +#ifdef HAVE_CUPS_SECRET_SERVICE + if (can_store_auth_info) + { + GtkWidget *remember; + + remember = gtk_check_button_new_with_mnemonic (_("_Remember password")); + gtk_box_pack_start (GTK_BOX (vbox), remember, FALSE, FALSE, 6); + g_signal_connect (remember, "toggled", + G_CALLBACK (store_auth_info_toggled), backend); + } +#endif + if (focus != NULL) { gtk_widget_grab_focus (focus); 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..c417ba88e 100644 --- a/modules/printbackends/cups/gtkprintbackendcups.c +++ b/modules/printbackends/cups/gtkprintbackendcups.c @@ -61,7 +61,6 @@ #include "gtkcupsutils.h" - typedef struct _GtkPrintBackendCupsClass GtkPrintBackendCupsClass; #define GTK_PRINT_BACKEND_CUPS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_BACKEND_CUPS, GtkPrintBackendCupsClass)) @@ -144,6 +143,11 @@ struct _GtkPrintBackendCups GHashTable *auth; gchar *username; gboolean authentication_lock; +#ifdef HAVE_CUPS_SECRET_SERVICE + gchar *store_auth_info_uri; + guint secrets_service_available : 1; + guint store_auth_info_allowed : 1; +#endif #ifdef HAVE_CUPS_API_1_6 GDBusConnection *dbus_connection; gchar *avahi_default_printer; @@ -213,10 +217,21 @@ static cairo_surface_t * cups_printer_create_cairo_surface (GtkPrinter static void gtk_print_backend_cups_set_password (GtkPrintBackend *backend, gchar **auth_info_required, gchar **auth_info); +#ifdef HAVE_CUPS_SECRET_SERVICE +static void gtk_print_backend_cups_set_password_full (GtkPrintBackend *backend, + gchar **auth_info_required, + gchar **auth_info, + gboolean store_auth_info); +static gboolean gtk_print_backend_cups_can_store_auth_info + (GtkPrintBackend *backend); +#endif void overwrite_and_free (gpointer data); static gboolean is_address_local (const gchar *address); static gboolean request_auth_info (gpointer data); +#ifdef HAVE_CUPS_SECRET_SERVICE +static void lookup_auth_info (gpointer data); +#endif #ifdef HAVE_CUPS_API_1_6 static void avahi_request_printer_list (GtkPrintBackendCups *cups_backend); @@ -341,6 +356,12 @@ gtk_print_backend_cups_class_init (GtkPrintBackendCupsClass *class) backend_class->printer_get_hard_margins = cups_printer_get_hard_margins; backend_class->printer_get_capabilities = cups_printer_get_capabilities; backend_class->set_password = gtk_print_backend_cups_set_password; +#ifdef HAVE_CUPS_SECRET_SERVICE + backend_class->_gtk_reserved1 = + (void (*) (void)) gtk_print_backend_cups_can_store_auth_info; + backend_class->_gtk_reserved2 = + (void (*) (void)) gtk_print_backend_cups_set_password_full; +#endif } static cairo_status_t @@ -489,6 +510,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 +695,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, @@ -767,6 +828,11 @@ gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups) backend_cups->requests = NULL; backend_cups->auth = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, overwrite_and_free); backend_cups->authentication_lock = FALSE; +#ifdef HAVE_CUPS_SECRET_SERVICE + backend_cups->store_auth_info_uri = NULL; + backend_cups->secrets_service_available = FALSE; + backend_cups->store_auth_info_allowed = FALSE; +#endif backend_cups->covers = NULL; backend_cups->number_of_covers = 0; @@ -813,6 +879,10 @@ gtk_print_backend_cups_finalize (GObject *object) g_free (backend_cups->username); +#ifdef HAVE_CUPS_SECRET_SERVICE + g_free (backend_cups->store_auth_info_uri); +#endif + #ifdef HAVE_CUPS_API_1_6 g_clear_object (&backend_cups->avahi_cancellable); g_free (backend_cups->avahi_default_printer); @@ -932,62 +1002,74 @@ httpGetHostname(http_t *http, } #endif +#ifdef HAVE_CUPS_SECRET_SERVICE +static void cups_secret_store (gchar **auth_info, + gchar **auth_info_labels, + const gchar *printer_uri); + +static void +gtk_print_backend_cups_set_password_full (GtkPrintBackend *backend, + gchar **auth_info_required, + gchar **auth_info, + gboolean store_auth_info) +#else static void gtk_print_backend_cups_set_password (GtkPrintBackend *backend, gchar **auth_info_required, gchar **auth_info) +#endif { GtkPrintBackendCups *cups_backend = GTK_PRINT_BACKEND_CUPS (backend); GList *l; - char dispatch_hostname[HTTP_MAX_URI]; - gchar *key; - gchar *username = NULL; - gchar *hostname = NULL; - gchar *password = NULL; - gint length; + gchar *key = NULL; + const gchar *username = NULL; + const gchar *hostname = NULL; + const gchar *password = NULL; gint i; - length = g_strv_length (auth_info_required); - if (auth_info != NULL) - for (i = 0; i < length; i++) + for (i = 0; auth_info_required[i] != NULL; i++) { if (g_strcmp0 (auth_info_required[i], "username") == 0) - username = g_strdup (auth_info[i]); + username = auth_info[i]; else if (g_strcmp0 (auth_info_required[i], "hostname") == 0) - hostname = g_strdup (auth_info[i]); + hostname = auth_info[i]; else if (g_strcmp0 (auth_info_required[i], "password") == 0) - password = g_strdup (auth_info[i]); + password = auth_info[i]; } if (hostname != NULL && username != NULL && password != NULL) { key = g_strconcat (username, "@", hostname, NULL); - g_hash_table_insert (cups_backend->auth, key, g_strdup (password)); + g_hash_table_replace (cups_backend->auth, key, g_strdup (password)); + + GTK_NOTE (PRINTING, + g_print ("CUPS backend: storing password for %s\n", key)); } g_free (cups_backend->username); cups_backend->username = g_strdup (username); - GTK_NOTE (PRINTING, - g_print ("CUPS backend: storing password for %s\n", key)); +#ifdef HAVE_CUPS_SECRET_SERVICE + if (store_auth_info && + password != NULL && + cups_backend->store_auth_info_uri != NULL) + cups_secret_store (auth_info, + auth_info_required, + cups_backend->store_auth_info_uri); + + g_free (cups_backend->store_auth_info_uri); + cups_backend->store_auth_info_uri = NULL; +#endif for (l = cups_backend->requests; l; l = l->next) { GtkPrintCupsDispatchWatch *dispatch = l->data; - httpGetHostname (dispatch->request->http, dispatch_hostname, sizeof (dispatch_hostname)); - if (is_address_local (dispatch_hostname)) - strcpy (dispatch_hostname, "localhost"); - if (dispatch->request->need_auth_info) { if (auth_info != NULL) - { - dispatch->request->auth_info = g_new0 (gchar *, length + 1); - for (i = 0; i < length; i++) - dispatch->request->auth_info[i] = g_strdup (auth_info[i]); - } + dispatch->request->auth_info = g_strdupv (auth_info); dispatch->backend->authentication_lock = FALSE; dispatch->request->need_auth_info = FALSE; } @@ -1003,6 +1085,33 @@ gtk_print_backend_cups_set_password (GtkPrintBackend *backend, } } + +#ifdef HAVE_CUPS_SECRET_SERVICE +static void +gtk_print_backend_cups_set_password (GtkPrintBackend *backend, + gchar **auth_info_required, + gchar **auth_info) +{ + gtk_print_backend_cups_set_password_full (backend, + auth_info_required, + auth_info, + FALSE); +} + + +static gboolean +gtk_print_backend_cups_can_store_auth_info (GtkPrintBackend *backend) +{ + GtkPrintBackendCups *cups_backend; + + cups_backend = GTK_PRINT_BACKEND_CUPS (backend); + + return cups_backend->secrets_service_available && + cups_backend->store_auth_info_allowed; +} +#endif + + static gboolean request_password (gpointer data) { @@ -1012,12 +1121,14 @@ request_password (gpointer data) gchar *prompt = NULL; gchar *key = NULL; char hostname[HTTP_MAX_URI]; - gchar **auth_info_required; - gchar **auth_info_default; - gchar **auth_info_display; - gboolean *auth_info_visible; - gint length = 3; - gint i; + const gchar *auth_info_required[4] = + { "hostname", "username", "password", NULL }; + const gchar *auth_info_default[4] = + { NULL, NULL, NULL, NULL }; + const gchar *auth_info_display[4] = + { NULL, NULL, NULL, NULL }; + gboolean auth_info_visible[4] = + { FALSE, TRUE, FALSE, FALSE }; if (dispatch->backend->authentication_lock) return FALSE; @@ -1031,21 +1142,11 @@ request_password (gpointer data) else username = cupsUser (); - auth_info_required = g_new0 (gchar*, length + 1); - auth_info_required[0] = g_strdup ("hostname"); - auth_info_required[1] = g_strdup ("username"); - auth_info_required[2] = g_strdup ("password"); + auth_info_default[0] = hostname; + auth_info_default[1] = username; - auth_info_default = g_new0 (gchar*, length + 1); - auth_info_default[0] = g_strdup (hostname); - auth_info_default[1] = g_strdup (username); - - auth_info_display = g_new0 (gchar*, length + 1); - auth_info_display[1] = g_strdup (_("Username:")); - auth_info_display[2] = g_strdup (_("Password:")); - - auth_info_visible = g_new0 (gboolean, length + 1); - auth_info_visible[1] = TRUE; + auth_info_display[1] = _("Username:"); + auth_info_display[2] = _("Password:"); key = g_strconcat (username, "@", hostname, NULL); password = g_hash_table_lookup (dispatch->backend->auth, key); @@ -1065,10 +1166,10 @@ request_password (gpointer data) { const char *job_title = gtk_cups_request_ipp_get_string (dispatch->request, IPP_TAG_NAME, "job-name"); const char *printer_uri = gtk_cups_request_ipp_get_string (dispatch->request, IPP_TAG_URI, "printer-uri"); - char *printer_name = NULL; + const char *printer_name = NULL; if (printer_uri != NULL && strrchr (printer_uri, '/') != NULL) - printer_name = g_strdup (strrchr (printer_uri, '/') + 1); + printer_name = strrchr (printer_uri, '/') + 1; if (dispatch->request->password_state == GTK_CUPS_PASSWORD_NOT_VALID) g_hash_table_remove (dispatch->backend->auth, key); @@ -1112,25 +1213,12 @@ request_password (gpointer data) break; } - g_free (printer_name); - g_signal_emit_by_name (dispatch->backend, "request-password", auth_info_required, auth_info_default, auth_info_display, auth_info_visible, prompt); g_free (prompt); } - for (i = 0; i < length; i++) - { - g_free (auth_info_required[i]); - g_free (auth_info_default[i]); - g_free (auth_info_display[i]); - } - - g_free (auth_info_required); - g_free (auth_info_default); - g_free (auth_info_display); - g_free (auth_info_visible); g_free (key); return FALSE; @@ -1223,6 +1311,845 @@ check_auth_info (gpointer user_data) return TRUE; } + +#ifdef HAVE_CUPS_SECRET_SERVICE + +#define CUPS_SECRET_BUS "org.freedesktop.secrets" +#define CUPS_SECRET_PATH "/org/freedesktop/secrets" +#define CUPS_SECRET_DEFAULT_COLLECTION \ + "/org/freedesktop/secrets/aliases/default" +#define CUPS_SECRET_IFACE(x) "org.freedesktop.Secret." x +#define CUPS_SECRET_TIMEOUT 5000 + +typedef enum +{ + CUPS_SECRET_SEARCH, + CUPS_SECRET_UNLOCK, + CUPS_SECRET_PROMPT, + CUPS_SECRET_PROMPT_WAIT, + CUPS_SECRET_ATTRIBUTES, + CUPS_SECRET_SESSION, + CUPS_SECRET_VALUE, + CUPS_SECRET_CREATE +} CupsSecretStep; + +typedef struct +{ + GDBusConnection *connection; + GtkPrintCupsDispatchWatch *dispatch; + gchar *item_path; + gchar *session_path; + gchar *prompt_path; + gchar **auth_info; + GVariant *store_properties; + gchar *store_password; + guint prompt_subscription; + guint length; + guint prompt_completed : 1; + guint prompt_dismissed : 1; + guint store : 1; + guint create_prompt : 1; + gint password_field; + CupsSecretStep step; +} CupsSecretLookup; + + +static void cups_secret_reply (GObject *, GAsyncResult *, gpointer); + + +static void +cups_secret_call (CupsSecretLookup *lookup, + const gchar *path, + const gchar *interface, + const gchar *method, + GVariant *parameters, + const GVariantType *reply_type, + CupsSecretStep step) +{ + lookup->step = step; + + g_dbus_connection_call (lookup->connection, + CUPS_SECRET_BUS, + path, + interface, + method, + parameters, + reply_type, + G_DBUS_CALL_FLAGS_NONE, + CUPS_SECRET_TIMEOUT, + NULL, + cups_secret_reply, + lookup); +} + + +static void +cups_secret_free (CupsSecretLookup *lookup) +{ + guint i; + + if (lookup->prompt_subscription != 0) + g_dbus_connection_signal_unsubscribe (lookup->connection, + lookup->prompt_subscription); + + if (lookup->session_path != NULL) + g_dbus_connection_call (lookup->connection, + CUPS_SECRET_BUS, + lookup->session_path, + CUPS_SECRET_IFACE ("Session"), + "Close", + NULL, + G_VARIANT_TYPE ("()"), + G_DBUS_CALL_FLAGS_NONE, + CUPS_SECRET_TIMEOUT, + NULL, + NULL, + NULL); + + if (lookup->auth_info != NULL) + { + for (i = 0; i < lookup->length; i++) + overwrite_and_free (lookup->auth_info[i]); + + g_free (lookup->auth_info); + } + + if (lookup->store_properties != NULL) + g_variant_unref (lookup->store_properties); + + if (lookup->store_password != NULL) + overwrite_and_free (lookup->store_password); + + g_free (lookup->item_path); + g_free (lookup->session_path); + g_free (lookup->prompt_path); + + if (lookup->connection != NULL) + g_object_unref (lookup->connection); + + g_free (lookup); +} + + +static void +cups_secret_done (CupsSecretLookup *lookup, + gboolean found, + GError *error) +{ + GtkPrintCupsDispatchWatch *dispatch; + + if (lookup->store) + { + if (error != NULL) + { + GTK_NOTE (PRINTING, + g_print ("CUPS backend: failed to remember password: %s\n", + error->message)); + g_error_free (error); + } + + cups_secret_free (lookup); + return; + } + + dispatch = lookup->dispatch; + + dispatch->backend->secrets_service_available = + error == NULL; + + if (error != NULL) + { + GTK_NOTE (PRINTING, + g_print ("CUPS backend: Secret Service lookup failed: %s\n", + error->message)); + g_error_free (error); + } + + if (found) + gtk_print_backend_cups_set_password ( + GTK_PRINT_BACKEND (dispatch->backend), + dispatch->request->auth_info_required, + lookup->auth_info); + else + dispatch->backend->authentication_lock = FALSE; + + cups_secret_free (lookup); + + if (found) + check_auth_info (dispatch); + else + request_auth_info (dispatch); +} + + + +static void +cups_secret_get_attributes (CupsSecretLookup *lookup) +{ + cups_secret_call (lookup, + lookup->item_path, + "org.freedesktop.DBus.Properties", + "Get", + g_variant_new ("(ss)", + CUPS_SECRET_IFACE ("Item"), + "Attributes"), + G_VARIANT_TYPE ("(v)"), + CUPS_SECRET_ATTRIBUTES); +} + + +static void +cups_secret_open_session (CupsSecretLookup *lookup) +{ + cups_secret_call ( + lookup, + CUPS_SECRET_PATH, + CUPS_SECRET_IFACE ("Service"), + "OpenSession", + g_variant_new ("(sv)", + "plain", + g_variant_new_string ("")), + G_VARIANT_TYPE ("(vo)"), + CUPS_SECRET_SESSION); +} + + +static void +cups_secret_create_item (CupsSecretLookup *lookup) +{ + GVariant *properties; + GVariant *secret; + + if (lookup->store_properties == NULL || + lookup->store_password == NULL || + lookup->session_path == NULL) + { + cups_secret_done (lookup, FALSE, NULL); + return; + } + + properties = lookup->store_properties; + lookup->store_properties = NULL; + + secret = g_variant_new ( + "(oay@ays)", + lookup->session_path, + NULL, + g_variant_new_bytestring (lookup->store_password), + "text/plain"); + + cups_secret_call ( + lookup, + CUPS_SECRET_DEFAULT_COLLECTION, + CUPS_SECRET_IFACE ("Collection"), + "CreateItem", + g_variant_new ("(@a{sv}@(oayays)b)", + properties, + secret, + TRUE), + G_VARIANT_TYPE ("(oo)"), + CUPS_SECRET_CREATE); +} + + +static void +cups_secret_after_prompt (CupsSecretLookup *lookup, + gboolean dismissed) +{ + if (dismissed) + { + cups_secret_done (lookup, FALSE, NULL); + return; + } + + if (!lookup->store) + { + cups_secret_get_attributes (lookup); + return; + } + + if (lookup->create_prompt) + { + cups_secret_done (lookup, TRUE, NULL); + return; + } + + cups_secret_open_session (lookup); +} + + + +static void +cups_secret_prompt_completed (GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + CupsSecretLookup *lookup = user_data; + gboolean dismissed; + + (void) connection; + (void) sender_name; + (void) object_path; + (void) interface_name; + (void) signal_name; + + g_dbus_connection_signal_unsubscribe ( + lookup->connection, + lookup->prompt_subscription); + + lookup->prompt_subscription = 0; + + g_free (lookup->prompt_path); + lookup->prompt_path = NULL; + + if (!g_variant_is_of_type (parameters, + G_VARIANT_TYPE ("(bv)"))) + { + cups_secret_done (lookup, FALSE, NULL); + return; + } + + g_variant_get (parameters, "(bv)", + &dismissed, NULL); + + if (lookup->step == CUPS_SECRET_PROMPT) + { + lookup->prompt_completed = TRUE; + lookup->prompt_dismissed = dismissed; + return; + } + + cups_secret_after_prompt (lookup, dismissed); +} + + +static void +cups_secret_prompt (CupsSecretLookup *lookup) +{ + lookup->prompt_completed = FALSE; + lookup->prompt_dismissed = FALSE; + + lookup->prompt_subscription = + g_dbus_connection_signal_subscribe ( + lookup->connection, + NULL, + CUPS_SECRET_IFACE ("Prompt"), + "Completed", + lookup->prompt_path, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + cups_secret_prompt_completed, + lookup, + NULL); + + cups_secret_call ( + lookup, + lookup->prompt_path, + CUPS_SECRET_IFACE ("Prompt"), + "Prompt", + g_variant_new ("(s)", "0"), + G_VARIANT_TYPE ("()"), + CUPS_SECRET_PROMPT); +} + + + +static void +cups_secret_reply (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + CupsSecretLookup *lookup = user_data; + GError *error = NULL; + GVariant *output; + + output = g_dbus_connection_call_finish ( + G_DBUS_CONNECTION (source_object), res, &error); + + if (output == NULL) + { + cups_secret_done (lookup, FALSE, error); + return; + } + + switch (lookup->step) + { + case CUPS_SECRET_SEARCH: + { + const gchar **unlocked; + const gchar **locked; + const gchar *path; + gboolean is_locked; + + g_variant_get (output, "(^a&o^a&o)", + &unlocked, &locked); + g_variant_unref (output); + + if (unlocked[0] != NULL) + { + path = unlocked[0]; + is_locked = FALSE; + } + else + { + path = locked[0]; + is_locked = TRUE; + } + + if (path != NULL) + lookup->item_path = g_strdup (path); + + g_free (unlocked); + g_free (locked); + + if (lookup->item_path == NULL) + { + cups_secret_done (lookup, FALSE, NULL); + return; + } + + if (!is_locked) + { + cups_secret_get_attributes (lookup); + return; + } + + { + const gchar *paths[2] = + { lookup->item_path, NULL }; + + cups_secret_call (lookup, + CUPS_SECRET_PATH, + CUPS_SECRET_IFACE ("Service"), + "Unlock", + g_variant_new ("(^ao)", paths), + G_VARIANT_TYPE ("(aoo)"), + CUPS_SECRET_UNLOCK); + } + + return; + } + + case CUPS_SECRET_UNLOCK: + { + g_variant_get (output, "(@aoo)", + NULL, &lookup->prompt_path); + g_variant_unref (output); + + if (strcmp (lookup->prompt_path, "/") == 0) + { + g_free (lookup->prompt_path); + lookup->prompt_path = NULL; + cups_secret_after_prompt (lookup, FALSE); + return; + } + + cups_secret_prompt (lookup); + return; + } + + case CUPS_SECRET_PROMPT: + g_variant_unref (output); + + if (lookup->prompt_completed) + cups_secret_after_prompt (lookup, + lookup->prompt_dismissed); + else + lookup->step = CUPS_SECRET_PROMPT_WAIT; + + return; + + case CUPS_SECRET_PROMPT_WAIT: + break; + + case CUPS_SECRET_ATTRIBUTES: + { + GVariant *attributes; + gchar **required; + const gchar *value; + guint i; + + g_variant_get (output, "(v)", &attributes); + g_variant_unref (output); + + if (!g_variant_is_of_type (attributes, + G_VARIANT_TYPE ("a{ss}"))) + { + g_variant_unref (attributes); + cups_secret_done (lookup, FALSE, NULL); + return; + } + + required = lookup->dispatch->request->auth_info_required; + lookup->auth_info = + g_new0 (gchar *, lookup->length + 1); + lookup->password_field = -1; + + for (i = 0; i < lookup->length; i++) + { + value = NULL; + + if (strcmp (required[i], "password") == 0) + { + lookup->password_field = i; + continue; + } + + if (strcmp (required[i], "username") == 0) + { + if (!g_variant_lookup (attributes, + "user", + "&s", + &value)) + g_variant_lookup (attributes, + "username", + "&s", + &value); + } + else if (strcmp (required[i], "hostname") == 0) + { + if (!g_variant_lookup (attributes, + "server", + "&s", + &value)) + g_variant_lookup (attributes, + "hostname", + "&s", + &value); + } + else if (strcmp (required[i], "domain") == 0) + { + g_variant_lookup (attributes, + "domain", + "&s", + &value); + } + + if (value == NULL) + { + g_variant_unref (attributes); + cups_secret_done (lookup, FALSE, NULL); + return; + } + + lookup->auth_info[i] = g_strdup (value); + } + + g_variant_unref (attributes); + + if (lookup->password_field < 0) + { + cups_secret_done (lookup, FALSE, NULL); + return; + } + + cups_secret_open_session (lookup); + return; + } + + case CUPS_SECRET_SESSION: + { + g_variant_get (output, "(vo)", + NULL, &lookup->session_path); + g_variant_unref (output); + + if (strcmp (lookup->session_path, "/") == 0) + { + cups_secret_done (lookup, FALSE, NULL); + return; + } + + if (lookup->store) + { + cups_secret_create_item (lookup); + return; + } + + cups_secret_call ( + lookup, + lookup->item_path, + CUPS_SECRET_IFACE ("Item"), + "GetSecret", + g_variant_new ("(o)", + lookup->session_path), + G_VARIANT_TYPE ("((oayays))"), + CUPS_SECRET_VALUE); + + return; + } + + case CUPS_SECRET_VALUE: + { + GVariant *value; + gconstpointer password; + gsize length; + guint i; + + g_variant_get (output, + "((o@ay@ays))", + NULL, NULL, &value, NULL); + g_variant_unref (output); + + password = g_variant_get_fixed_array ( + value, &length, sizeof (guchar)); + + if (password != NULL) + lookup->auth_info[lookup->password_field] = + g_strndup (password, length); + + g_variant_unref (value); + + for (i = 0; i < lookup->length; i++) + if (lookup->auth_info[i] == NULL) + { + cups_secret_done (lookup, FALSE, NULL); + return; + } + + cups_secret_done (lookup, TRUE, NULL); + return; + } + + case CUPS_SECRET_CREATE: + { + const gchar *item; + const gchar *prompt; + + g_variant_get (output, "(&o&o)", + &item, &prompt); + + if (strcmp (item, "/") != 0) + { + g_variant_unref (output); + cups_secret_done (lookup, TRUE, NULL); + return; + } + + if (strcmp (prompt, "/") == 0) + { + g_variant_unref (output); + cups_secret_done (lookup, FALSE, NULL); + return; + } + + g_free (lookup->prompt_path); + lookup->prompt_path = g_strdup (prompt); + lookup->create_prompt = TRUE; + + g_variant_unref (output); + + cups_secret_prompt (lookup); + return; + } + } + + g_variant_unref (output); + cups_secret_done (lookup, FALSE, NULL); +} + + +static void +cups_secret_connection (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + CupsSecretLookup *lookup = user_data; + GVariantBuilder builder; + GError *error = NULL; + const gchar *uri; + + (void) source_object; + + lookup->connection = g_bus_get_finish (res, &error); + + if (lookup->connection == NULL) + { + cups_secret_done (lookup, FALSE, error); + return; + } + + if (lookup->store) + { + const gchar *paths[2] = + { CUPS_SECRET_DEFAULT_COLLECTION, NULL }; + + cups_secret_call ( + lookup, + CUPS_SECRET_PATH, + CUPS_SECRET_IFACE ("Service"), + "Unlock", + g_variant_new ("(^ao)", paths), + G_VARIANT_TYPE ("(aoo)"), + CUPS_SECRET_UNLOCK); + + return; + } + + uri = gtk_cups_request_ipp_get_string ( + lookup->dispatch->request, + IPP_TAG_URI, + "printer-uri"); + + if (uri == NULL) + { + cups_secret_done (lookup, FALSE, NULL); + return; + } + + g_variant_builder_init (&builder, + G_VARIANT_TYPE ("a{ss}")); + g_variant_builder_add (&builder, + "{ss}", + "uri", + uri); + + cups_secret_call ( + lookup, + CUPS_SECRET_PATH, + CUPS_SECRET_IFACE ("Service"), + "SearchItems", + g_variant_new ("(@a{ss})", + g_variant_builder_end (&builder)), + G_VARIANT_TYPE ("(aoao)"), + CUPS_SECRET_SEARCH); +} + + +static void +lookup_auth_info (gpointer data) +{ + GtkPrintCupsDispatchWatch *dispatch = data; + CupsSecretLookup *lookup; + gchar **required; + guint i; + + if (dispatch->backend->authentication_lock) + return; + + required = dispatch->request->auth_info_required; + + for (i = 0; required[i] != NULL; i++) + if (strcmp (required[i], "password") == 0) + break; + + if (required[i] == NULL || + gtk_cups_request_ipp_get_string ( + dispatch->request, + IPP_TAG_URI, + "printer-uri") == NULL) + { + request_auth_info (dispatch); + return; + } + + lookup = g_new0 (CupsSecretLookup, 1); + lookup->dispatch = dispatch; + lookup->length = g_strv_length (required); + + dispatch->backend->authentication_lock = TRUE; + + g_bus_get (G_BUS_TYPE_SESSION, + NULL, + cups_secret_connection, + lookup); +} + + +static void +cups_secret_store (gchar **auth_info, + gchar **auth_info_labels, + const gchar *printer_uri) +{ + CupsSecretLookup *lookup; + GVariantBuilder attributes; + GVariantBuilder properties; + const gchar *password = NULL; + const gchar *key; + guint i; + + if (auth_info == NULL || + auth_info_labels == NULL || + printer_uri == NULL) + return; + + g_variant_builder_init (&attributes, + G_VARIANT_TYPE ("a{ss}")); + + g_variant_builder_add (&attributes, + "{ss}", + "uri", + printer_uri); + + for (i = 0; auth_info_labels[i] != NULL; i++) + { + if (auth_info[i] == NULL) + continue; + + key = NULL; + + if (strcmp (auth_info_labels[i], "password") == 0) + { + password = auth_info[i]; + continue; + } + + if (strcmp (auth_info_labels[i], "username") == 0) + key = "user"; + else if (strcmp (auth_info_labels[i], "hostname") == 0) + key = "server"; + else if (strcmp (auth_info_labels[i], "domain") == 0) + key = "domain"; + + if (key != NULL) + g_variant_builder_add (&attributes, + "{ss}", + key, + auth_info[i]); + } + + if (password == NULL) + { + g_variant_builder_clear (&attributes); + return; + } + + g_variant_builder_init (&properties, + G_VARIANT_TYPE ("a{sv}")); + + g_variant_builder_add ( + &properties, + "{sv}", + CUPS_SECRET_IFACE ("Item.Label"), + g_variant_new_string (printer_uri)); + + g_variant_builder_add ( + &properties, + "{sv}", + CUPS_SECRET_IFACE ("Item.Attributes"), + g_variant_builder_end (&attributes)); + + lookup = g_new0 (CupsSecretLookup, 1); + lookup->store = TRUE; + + lookup->store_properties = + g_variant_ref_sink ( + g_variant_builder_end (&properties)); + + lookup->store_password = + g_strdup (password); + + g_bus_get (G_BUS_TYPE_SESSION, + NULL, + cups_secret_connection, + lookup); +} +#endif + + static gboolean request_auth_info (gpointer user_data) { @@ -1230,12 +2157,12 @@ request_auth_info (gpointer user_data) const char *job_title; const char *printer_uri; gchar *prompt = NULL; - char *printer_name = NULL; + const char *printer_name = NULL; gint length; gint i; gboolean *auth_info_visible = NULL; - gchar **auth_info_default = NULL; - gchar **auth_info_display = NULL; + const gchar **auth_info_default = NULL; + const gchar **auth_info_display = NULL; dispatch = (GtkPrintCupsDispatchWatch *) user_data; @@ -1247,35 +2174,35 @@ request_auth_info (gpointer user_data) length = g_strv_length (dispatch->request->auth_info_required); auth_info_visible = g_new0 (gboolean, length); - auth_info_default = g_new0 (gchar *, length + 1); - auth_info_display = g_new0 (gchar *, length + 1); + auth_info_default = g_new0 (const gchar *, length + 1); + auth_info_display = g_new0 (const gchar *, length + 1); for (i = 0; i < length; i++) { if (g_strcmp0 (dispatch->request->auth_info_required[i], "domain") == 0) { - auth_info_display[i] = g_strdup (_("Domain:")); - auth_info_default[i] = g_strdup ("WORKGROUP"); + auth_info_display[i] = _("Domain:"); + auth_info_default[i] = "WORKGROUP"; auth_info_visible[i] = TRUE; } else if (g_strcmp0 (dispatch->request->auth_info_required[i], "username") == 0) { - auth_info_display[i] = g_strdup (_("Username:")); + auth_info_display[i] = _("Username:"); if (dispatch->backend->username != NULL) - auth_info_default[i] = g_strdup (dispatch->backend->username); + auth_info_default[i] = dispatch->backend->username; else - auth_info_default[i] = g_strdup (cupsUser ()); + auth_info_default[i] = cupsUser (); auth_info_visible[i] = TRUE; } else if (g_strcmp0 (dispatch->request->auth_info_required[i], "password") == 0) { - auth_info_display[i] = g_strdup (_("Password:")); + auth_info_display[i] = _("Password:"); auth_info_visible[i] = FALSE; } } if (printer_uri != NULL && strrchr (printer_uri, '/') != NULL) - printer_name = g_strdup (strrchr (printer_uri, '/') + 1); + printer_name = strrchr (printer_uri, '/') + 1; dispatch->backend->authentication_lock = TRUE; @@ -1294,6 +2221,18 @@ request_auth_info (gpointer user_data) prompt = g_strdup ( _("Authentication is required to print this document")); } +#ifdef HAVE_CUPS_SECRET_SERVICE + g_free (dispatch->backend->store_auth_info_uri); + dispatch->backend->store_auth_info_uri = NULL; + + dispatch->backend->store_auth_info_allowed = + dispatch->backend->secrets_service_available && + printer_uri != NULL; + + if (dispatch->backend->store_auth_info_allowed) + dispatch->backend->store_auth_info_uri = g_strdup (printer_uri); +#endif + g_signal_emit_by_name (dispatch->backend, "request-password", dispatch->request->auth_info_required, auth_info_default, @@ -1301,15 +2240,13 @@ request_auth_info (gpointer user_data) auth_info_visible, prompt); - for (i = 0; i < length; i++) - { - g_free (auth_info_default[i]); - g_free (auth_info_display[i]); - } +#ifdef HAVE_CUPS_SECRET_SERVICE + dispatch->backend->store_auth_info_allowed = FALSE; +#endif g_free (auth_info_default); g_free (auth_info_display); - g_free (printer_name); + g_free (auth_info_visible); g_free (prompt); g_idle_add (check_auth_info, user_data); @@ -1514,7 +2451,11 @@ cups_request_execute (GtkPrintBackendCups *print_backend, { dispatch->callback = callback; dispatch->callback_data = user_data; +#ifdef HAVE_CUPS_SECRET_SERVICE + lookup_auth_info (dispatch); +#else request_auth_info (dispatch); +#endif } else { @@ -2555,7 +3496,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 +4379,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 ());