Transfer the Mac SDK bockbuild profiles & resources inside the Mono repository.
authorAlexis Christoforides <alexis@thenull.net>
Thu, 29 Sep 2016 11:31:39 +0000 (14:31 +0300)
committerAlexis Christoforides <alexis@thenull.net>
Fri, 14 Oct 2016 07:48:28 +0000 (03:48 -0400)
This includes all distributable packages,patches etc. Toolchain packages remain part of the bockbuild repository.

The profiles were also renamed:
'mono-mac-release' -> 'mac-sdk'
'mono-mac-xamarin' -> 'mac-sdk-xamarin'

195 files changed:
bockbuild/mac-sdk-xamarin/mono-extensions.py [new file with mode: 0644]
bockbuild/mac-sdk-xamarin/packaging [new symlink]
bockbuild/mac-sdk-xamarin/profile.py [new file with mode: 0755]
bockbuild/mac-sdk/atk.py [new file with mode: 0644]
bockbuild/mac-sdk/cairo.py [new file with mode: 0644]
bockbuild/mac-sdk/expat.py [new file with mode: 0644]
bockbuild/mac-sdk/fontconfig.py [new file with mode: 0644]
bockbuild/mac-sdk/freetype.py [new file with mode: 0644]
bockbuild/mac-sdk/fsharp.py [new file with mode: 0644]
bockbuild/mac-sdk/gdk-pixbuf.py [new file with mode: 0644]
bockbuild/mac-sdk/gdk-pixbuf/0001-pixbuf-Add-getter-setter-for-the-2x-variants.patch [new file with mode: 0644]
bockbuild/mac-sdk/gdk-pixbuf/0001-pixbuf-load-2x-variants-as-pixbuf-gobject-data.patch [new file with mode: 0644]
bockbuild/mac-sdk/gettext.py [new file with mode: 0644]
bockbuild/mac-sdk/glib.py [new file with mode: 0644]
bockbuild/mac-sdk/gtk+.py [new file with mode: 0644]
bockbuild/mac-sdk/gtk-engines.py [new file with mode: 0644]
bockbuild/mac-sdk/gtk-quartz-engine.py [new file with mode: 0644]
bockbuild/mac-sdk/gtk-sharp.py [new file with mode: 0644]
bockbuild/mac-sdk/gtkrc [new file with mode: 0644]
bockbuild/mac-sdk/hicolor-icon-theme.py [new file with mode: 0644]
bockbuild/mac-sdk/ige-mac-integration.py [new file with mode: 0644]
bockbuild/mac-sdk/intltool.py [new file with mode: 0644]
bockbuild/mac-sdk/ironlangs.py [new file with mode: 0644]
bockbuild/mac-sdk/libcroco.py [new file with mode: 0644]
bockbuild/mac-sdk/libffi.py [new file with mode: 0644]
bockbuild/mac-sdk/libgdiplus.py [new file with mode: 0644]
bockbuild/mac-sdk/libgif.py [new file with mode: 0644]
bockbuild/mac-sdk/libglade.py [new file with mode: 0644]
bockbuild/mac-sdk/libjpeg.py [new file with mode: 0644]
bockbuild/mac-sdk/libpng.py [new file with mode: 0644]
bockbuild/mac-sdk/librsvg.py [new file with mode: 0644]
bockbuild/mac-sdk/libtiff.py [new file with mode: 0644]
bockbuild/mac-sdk/libxml2.py [new file with mode: 0644]
bockbuild/mac-sdk/mono-basic.py [new file with mode: 0644]
bockbuild/mac-sdk/mono-llvm.py [new file with mode: 0644]
bockbuild/mac-sdk/mono.py [new file with mode: 0644]
bockbuild/mac-sdk/msbuild.py [new file with mode: 0644]
bockbuild/mac-sdk/murrine.py [new file with mode: 0644]
bockbuild/mac-sdk/nuget.py [new file with mode: 0644]
bockbuild/mac-sdk/packaging/Info.plist [new file with mode: 0644]
bockbuild/mac-sdk/packaging/Info_sdk.plist [new file with mode: 0644]
bockbuild/mac-sdk/packaging/mdk_blacklist.sh [new file with mode: 0755]
bockbuild/mac-sdk/packaging/resources/License.rtf [new file with mode: 0644]
bockbuild/mac-sdk/packaging/resources/ReadMe.rtf [new file with mode: 0644]
bockbuild/mac-sdk/packaging/resources/Welcome.rtf [new file with mode: 0644]
bockbuild/mac-sdk/packaging/resources/distribution.xml [new file with mode: 0644]
bockbuild/mac-sdk/packaging/resources/postinstall [new file with mode: 0755]
bockbuild/mac-sdk/packaging/resources/version.plist [new file with mode: 0644]
bockbuild/mac-sdk/packaging/resources/whitelist.txt [new file with mode: 0644]
bockbuild/mac-sdk/packaging/uninstallMono.sh [new file with mode: 0755]
bockbuild/mac-sdk/pango.py [new file with mode: 0644]
bockbuild/mac-sdk/patches/cairo-cglayer.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/cairo-fix-CGFontGetGlyphPath-deprecation.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/cairo-fix-color-bitmap-fonts.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/cairo-quartz-crash.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/find-unused-patches.sh [new file with mode: 0755]
bockbuild/mac-sdk/patches/fsharp-assemblysearchpath-fix.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gdk-quartz-set-fix-modifiers-hack-v3.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gettext-no-samples.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/glib-recursive-poll.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/glib/config.h.ed [new file with mode: 0644]
bockbuild/mac-sdk/patches/glib/patch-configure.diff [new file with mode: 0644]
bockbuild/mac-sdk/patches/glib/patch-gi18n.h.diff [new file with mode: 0644]
bockbuild/mac-sdk/patches/glib/patch-gio_gdbusprivate.c.diff [new file with mode: 0644]
bockbuild/mac-sdk/patches/glib/patch-gio_xdgmime_xdgmime.c.diff [new file with mode: 0644]
bockbuild/mac-sdk/patches/glib/patch-glib-2.0.pc.in.diff [new file with mode: 0644]
bockbuild/mac-sdk/patches/glib/patch-glib_gunicollate.c.diff [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk-gestures.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk-quartz-move-drag.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0001-Add-invariant-that-a-child-is-unmapped-if-parent-is-.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0002-Maintain-map-unmap-invariants-in-GtkRecentChooserDia.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0003-GtkPlug-preserve-map-unmap-invariants.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0004-Add-gdk_screen_get_monitor_workarea-and-use-it-all-o.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0005-gtk-don-t-scroll-combo-box-menus-if-less-than-3-item.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0006-gtk-paint-only-the-exposed-region-in-gdk_window_expo.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0007-Implement-gtk-enable-overlay-scrollbars-GtkSetting.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0008-Smooth-scrolling.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0009-gtk-Add-a-way-to-do-event-capture.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0010-gtk-don-t-let-insensitive-children-eat-scroll-events.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0011-scrolledwindow-Kinetic-scrolling-support.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0012-gtk-paint-to-the-right-windows-in-gtk_scrolled_windo.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0013-GtkScrolledWindow-add-overlay-scrollbars.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0014-gtk-add-event-handling-to-GtkScrolledWindow-s-overla.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0015-Use-gtk-enable-overlay-scrollbars-in-GtkScrolledWind.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0016-gtk-correctly-handle-toggling-of-the-scrollbar-visib.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0017-gtk-handle-gtk-primary-button-warps-slider-for-the-o.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0018-Introduce-phase-field-in-GdkEventScroll.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0019-Add-hack-to-lock-flow-of-scroll-events-to-window-whe.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0020-Introduce-a-background-window.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0021-Make-scrolled-window-work-well-with-Mac-touchpad.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0022-Use-start-end-phase-in-event-handling.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0023-Improve-overshooting-behavior.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0024-Cancel-out-smaller-delta-component.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0025-quartz-Add-a-dummy-NSView-serving-as-layer-view.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0026-gtk-port-overlay-scrollbars-to-native-CALayers.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0027-Refrain-from-starting-fading-out-while-a-gesture-is-.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0028-gtk-don-t-show-the-olverlay-scrollbars-if-only-the-s.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0029-Reclamp-unclamped-adjustments-after-resize.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0030-gtk-fix-size_request-of-scrolled-window.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0031-Hackish-fix-for-bug-8493-Min-size-of-GtkScrolledWind.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0032-Add-momentum_phase-to-GdkEventScroll.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0033-Never-intervene-in-the-event-stream-for-legacy-mice.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0034-Do-not-start-overshooting-for-legacy-mouse-scroll-ev.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0035-gtk-remove-the-overlay-scrollbar-grab-on-unrealize.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0036-gtk-add-GtkScrolledWindow-API-to-disable-overshoot-p.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0037-quartz-return-events-on-embedded-foreign-NSViews-bac.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0038-quartz-don-t-forward-events-to-the-toplevel-nswindow.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0039-gdk-add-a-move-native-children-signal-to-GdkWindow.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0040-gtk-add-new-widget-GtkNSView-which-alows-to-embed-an.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0041-tests-add-a-notebook-to-testnsview.c.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0042-gtk-connect-GtkNSView-to-move-native-children-and-re.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0043-tests-add-a-scrolled-window-test-widget-to-testnsvie.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0044-gtknsview-clip-drawRect-to-a-parent-GtkViewport-s-wi.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0045-gtk-clip-NSViews-to-the-scrolled-window-s-overshoot_.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0046-gtk-implement-clipping-to-multiple-parent-viewports-.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0047-gtk-first-attempt-to-also-clip-NSWindow-s-field-edit.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0048-gtk-also-clip-the-NSView-s-subviews.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0049-nsview-also-swizzle-DidAddSubview-and-clip-all-subvi.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0050-nsview-clip-text-field-cursor-drawing.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0051-nsview-factor-out-almost-all-code-from-the-overridde.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0052-nsview-also-focus-the-GtkNSView-if-a-focussable-subv.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0053-gtk-add-an-overlay-policy-API-to-GtkScrolledWindow.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0054-quartz-add-gdk_screen_-and-gdk_window_get_scale_fact.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0055-gtk-add-gtk_widget_get_scale_factor.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0056-iconfactory-Add-_scaled-variants.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0057-widget-Add-_scaled-variants-for-icon-rendering.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0058-icontheme-Add-support-for-high-resolution-icons.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0059-iconfactory-Add-scale-info-to-GtkIconSource.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0060-iconfactory-Add-gtk_cairo_set_source_icon_set.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0061-image-Use-scaled-icons-on-windows-with-a-scaling-fac.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0062-cellrendererpixbuf-Use-scaled-icons-on-windows-with-.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0063-entry-Use-scaled-icons-on-windows-with-a-scale-facto.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0064-gdk-Lookup-double-scaled-variants-on-pixbufs.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0065-Make-usual-calls-to-get-a-GdkPixbuf-attach-a-2x-vari.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0066-cellrendererpixbuf-let-2x-variants-go-through-pixel-.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0067-quartz-Make-event-loop-deal-with-recursive-poll-invo.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0068-nsview-implement-a-few-text-view-command-accelerator.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0069-menu-scrolling.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0070-tooltips-focus.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0071-light-and-dark-overlay-scrollbars.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0072-let-global-keyboard-shortcuts-pass-through.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0073-disable-combobox-scrolling.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0074-fix-NULL-pointer-in-clipboard.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0075-filechooserwidget-location-entry-activation.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/0076-iconfactory-treat-gt-1-0-icons-as-2-0.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/bgo702841-fix-kana-eisu-keys.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/bxc-41657.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/bxc2158_workaround_crash_triggering_context_menu.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/bxc3457_more_standard_keyboard_shortcuts.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/bxc_10256_window_tools_get_confused.diff [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/combobox-crossing-events.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/create-accessibility-object.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/disable-eye-dropper.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/dont-call-CopySymbolicHotKeys-so-much.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/embedded-nstextview-has-focus.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/emit-container-add.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/enable-swizzle-property.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/fix-imquartz-crasher.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/flip-command-mask-between-mod1-and-mod2.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/gtk-check-grab_toplevel-is-destroyed.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/gtk-imquartz-defer-signals-in-output_result.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/gtknsview-defer-map-and-lock-in-clipping.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/gtknsview-fix-invalid-casts.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/gtknsview-forward-cmdz-to-textview-undo-manager.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/gtknsview-getter.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/gtknsview-only-unset-first-responder-if-it-is-our-view.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/gtknsview-timeout-fix.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/make-gtkpaned-emit-signals.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/nsview-check-for-superview.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/nsview-embedding-fix-keyboard-routing.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/nsview-embedding.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/quartz-call-undo-redo-on-cmdz.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/remove-demos-from-build.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/remove-mouse-scrolling-from-GtkNotebook-tabs.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/gtk/scrolled-window-draw-child-bg.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/mcs-pkgconfig.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/murrine-osx.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/pango-coretext-astral-plane-1.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/pango-coretext-astral-plane-2.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/pango-coretext-condensed-trait.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/pango-coretext-fix-yosemite-crasher.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/pango-disable-ligatures.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/pango-fix-ct_font_descriptor_get_weight-crasher.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/pango-relative-config-file.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/pango-system-font-check-version.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/pango-system-font-single.patch [new file with mode: 0644]
bockbuild/mac-sdk/patches/tiff-4.0.2-macosx-2.patch [new file with mode: 0644]
bockbuild/mac-sdk/pcl-reference-assemblies.py [new file with mode: 0644]
bockbuild/mac-sdk/pixman.py [new file with mode: 0644]
bockbuild/mac-sdk/pkg-config.py [new file with mode: 0644]
bockbuild/mac-sdk/profile.py [new file with mode: 0755]
bockbuild/mac-sdk/sqlite.py [new file with mode: 0644]
bockbuild/mac-sdk/xamarin-gtk-theme.py [new file with mode: 0644]
bockbuild/mac-sdk/xsp.py [new file with mode: 0644]
external/bockbuild

diff --git a/bockbuild/mac-sdk-xamarin/mono-extensions.py b/bockbuild/mac-sdk-xamarin/mono-extensions.py
new file mode 100644 (file)
index 0000000..2d52fda
--- /dev/null
@@ -0,0 +1,25 @@
+from bockbuild.package import Package
+
+
+class MonoExtensionsPackage(Package):
+
+    def __init__(self):
+        Package.__init__(self, 'mono-extensions', None,
+                         sources=['git@github.com:xamarin/mono-extensions.git'],
+                         git_branch=self.profile.release_packages[
+                             'mono'].git_branch
+                         )
+        self.source_dir_name = 'mono-extensions'
+
+        # Mono pull requests won't have mono-extensions branches
+        if not self.git_branch or 'pull/' in self.git_branch:
+            warn('Using master branch for mono_extensions')
+            self.git_branch = 'master'
+
+    def build(self):
+        pass
+
+    def install(self):
+        pass
+
+MonoExtensionsPackage()
diff --git a/bockbuild/mac-sdk-xamarin/packaging b/bockbuild/mac-sdk-xamarin/packaging
new file mode 120000 (symlink)
index 0000000..4fff358
--- /dev/null
@@ -0,0 +1 @@
+../mono-mac-release/packaging
\ No newline at end of file
diff --git a/bockbuild/mac-sdk-xamarin/profile.py b/bockbuild/mac-sdk-xamarin/profile.py
new file mode 100755 (executable)
index 0000000..72f8cb2
--- /dev/null
@@ -0,0 +1,107 @@
+#!/usr/bin/python -u -OO
+
+import itertools
+import os
+import re
+import shutil
+import string
+import sys
+import tempfile
+import traceback
+
+from glob import glob
+
+if __name__ == "__main__":
+    sys.path.append(os.path.realpath('../..'))
+    sys.path.append(os.path.realpath('../../packages'))
+    sys.path.append(os.path.realpath('../mono-mac'))
+
+from MonoReleaseProfile import MonoReleaseProfile
+from bockbuild.util.util import *
+
+
+class MonoXamarinPackageProfile(MonoReleaseProfile):
+
+    def __init__(self):
+        MonoReleaseProfile.__init__(self)
+
+        # add the private stuff
+        self.packages_to_build.extend(['mono-extensions'])
+
+        if self.cmd_options.release_build:
+            self.setup_codesign()
+        else:
+            info("'--release' option not set, will not attempt to sign package!")
+
+        self.cache_host = 'http://storage.bos.xamarin.com/bockbuild_cache/'
+
+    def setup_codesign(self):
+        self.identity = "Developer ID Installer: Xamarin Inc"
+
+        output = backtick("security -v find-identity")
+        if self.identity not in " ".join(output):
+            error("Identity '%s' was not found. You can create an unsigned package by removing '--release' to your command line." % self.identity)
+
+        password = os.getenv("CODESIGN_KEYCHAIN_PASSWORD")
+        if password:
+            print "Unlocking the keychain"
+            run_shell("security unlock-keychain -p %s" % password)
+        else:
+            error("CODESIGN_KEYCHAIN_PASSWORD needs to be defined.")
+
+    def setup_release(self):
+        MonoReleaseProfile.setup_release(self)
+        self.release_packages['mono'].configure_flags.extend(
+            ['--enable-extension-module=xamarin --enable-native-types --enable-pecrypt'])
+        info('Xamarin extensions enabled')
+
+    def run_pkgbuild(self, working_dir, package_type):
+        output = MonoReleaseProfile.run_pkgbuild(
+            self, working_dir, package_type)
+
+        output_unsigned = os.path.join(os.path.dirname(
+            output), os.path.basename(output).replace('.pkg', '.UNSIGNED.pkg'))
+        shutil.move(output, output_unsigned)
+
+        if not self.cmd_options.release_build:
+            return output_unsigned
+
+        productsign = "/usr/bin/productsign"
+        productsign_cmd = ' '.join([productsign,
+                                    "-s '%s'" % self.identity,
+                                    "'%s'" % output_unsigned,
+                                    "'%s'" % output])
+        run_shell(productsign_cmd)
+        os.remove(output_unsigned)
+        self.verify_codesign(output)
+
+        return output
+
+    def verify_codesign(self, pkg):
+        oldcwd = os.getcwd()
+        try:
+            name = os.path.basename(pkg)
+            pkgdir = os.path.dirname(pkg)
+            os.chdir(pkgdir)
+            spctl = "/usr/sbin/spctl"
+            spctl_cmd = ' '.join(
+                [spctl, "-vvv", "--assess", "--type install", name, "2>&1"])
+            output = backtick(spctl_cmd)
+
+            if "accepted" in " ".join(output):
+                warn("%s IS SIGNED" % pkg)
+            else:
+                error("%s IS NOT SIGNED:" % pkg)
+        finally:
+            os.chdir(oldcwd)
+
+if __name__ == "__main__":
+    try:
+        MonoXamarinPackageProfile().build()
+    except Exception as e:
+        exc_type, exc_value, exc_traceback = sys.exc_info()
+        error('%s (%s)' % (e, exc_type.__name__), more_output=True)
+        error(('%s:%s @%s\t\t"%s"' % p for p in traceback.extract_tb(
+            exc_traceback)[-3:]), more_output=True)
+    except KeyboardInterrupt:
+        error('Interrupted.')
diff --git a/bockbuild/mac-sdk/atk.py b/bockbuild/mac-sdk/atk.py
new file mode 100644 (file)
index 0000000..dd56323
--- /dev/null
@@ -0,0 +1 @@
+GnomeXzPackage('atk', version_major='2.8', version_minor='0')
diff --git a/bockbuild/mac-sdk/cairo.py b/bockbuild/mac-sdk/cairo.py
new file mode 100644 (file)
index 0000000..9a3aa92
--- /dev/null
@@ -0,0 +1,40 @@
+class CairoPackage (CairoGraphicsXzPackage):
+
+    def __init__(self):
+        CairoGraphicsXzPackage.__init__(self, 'cairo', '1.12.14')
+        self.sources.extend([
+            'patches/cairo-quartz-crash.patch',
+            'patches/cairo-fix-color-bitmap-fonts.patch',
+            'patches/cairo-fix-CGFontGetGlyphPath-deprecation.patch',
+            #                  'patches/cairo-cglayer.patch',
+        ])
+
+    def prep(self):
+        Package.prep(self)
+
+        if Package.profile.name == 'darwin':
+            for p in range(1, len(self.local_sources)):
+                self.sh('patch -p1 < "%{local_sources[' + str(p) + ']}"')
+
+    def build(self):
+        self.configure_flags = [
+            '--enable-pdf',
+        ]
+
+        if Package.profile.name == 'darwin':
+            self.configure_flags.extend([
+                '--enable-quartz',
+                '--enable-quartz-font',
+                '--enable-quartz-image',
+                '--disable-xlib',
+                '--without-x'
+            ])
+        elif Package.profile.name == 'linux':
+            self.configure_flags.extend([
+                '--disable-quartz',
+                '--with-x'
+            ])
+
+        Package.build(self)
+
+CairoPackage()
diff --git a/bockbuild/mac-sdk/expat.py b/bockbuild/mac-sdk/expat.py
new file mode 100644 (file)
index 0000000..57b52d6
--- /dev/null
@@ -0,0 +1 @@
+SourceForgePackage('expat', 'expat', '2.0.1')
diff --git a/bockbuild/mac-sdk/fontconfig.py b/bockbuild/mac-sdk/fontconfig.py
new file mode 100644 (file)
index 0000000..8d890be
--- /dev/null
@@ -0,0 +1,22 @@
+class FontConfigPackage (Package):
+
+    def __init__(self):
+        Package.__init__(self, 'fontconfig', '2.10.2',
+                         configure_flags=['--disable-docs'],
+                         sources=[
+                             'http://www.fontconfig.org/release/%{name}-%{version}.tar.gz'
+                         ],
+                         # note: a non-empty DESTDIR keeps fc-cache from running at
+                         # install-time
+                         )
+
+    def build(self):
+        if Package.profile.name == 'darwin':
+            self.configure_flags.extend([
+                '--with-cache-dir="~/Library/Caches/com.xamarin.fontconfig"',
+                '--with-default-fonts=/System/Library/Fonts',
+                '--with-add-fonts=/Library/Fonts,/Network/Library/Fonts,/System/Library/Fonts'
+            ])
+        Package.build(self)
+
+FontConfigPackage()
diff --git a/bockbuild/mac-sdk/freetype.py b/bockbuild/mac-sdk/freetype.py
new file mode 100644 (file)
index 0000000..c7e86f6
--- /dev/null
@@ -0,0 +1 @@
+SourceForgePackage('%{name}', 'freetype', '2.5.0.1')
diff --git a/bockbuild/mac-sdk/fsharp.py b/bockbuild/mac-sdk/fsharp.py
new file mode 100644 (file)
index 0000000..9e53489
--- /dev/null
@@ -0,0 +1,24 @@
+class FsharpPackage(GitHubTarballPackage):
+
+    def __init__(self):
+        GitHubTarballPackage.__init__(self,
+                                      'fsharp', 'fsharp',
+                                      '4.0.1.9',
+                                      '0a6c66a8f18eb8a5c4d0bfac61d883b6994a918a',
+                                      configure='./configure --prefix="%{package_prefix}"')
+
+        self.extra_stage_files = [
+            'lib/mono/xbuild/Microsoft/VisualStudio/v/FSharp/Microsoft.FSharp.Targets']
+
+    def prep(self):
+        Package.prep(self)
+
+        for p in range(1, len(self.sources)):
+            self.sh('patch -p1 < "%{local_sources[' + str(p) + ']}"')
+
+    def build(self):
+        self.sh('autoreconf')
+        Package.configure(self)
+        Package.make(self)
+
+FsharpPackage()
diff --git a/bockbuild/mac-sdk/gdk-pixbuf.py b/bockbuild/mac-sdk/gdk-pixbuf.py
new file mode 100644 (file)
index 0000000..e28ecb3
--- /dev/null
@@ -0,0 +1,34 @@
+class GdkPixbufPackage (GnomeXzPackage):
+
+    def __init__(self):
+        GnomeXzPackage.__init__(
+            self,
+            'gdk-pixbuf',
+            version_major='2.28',
+            version_minor='2')
+
+        if Package.profile.name == 'darwin':
+            self.sources.extend([
+                'patches/gdk-pixbuf/0001-pixbuf-load-2x-variants-as-pixbuf-gobject-data.patch',
+                'patches/gdk-pixbuf/0001-pixbuf-Add-getter-setter-for-the-2x-variants.patch',
+            ])
+
+        self.configure_flags.extend(['--enable-gtk-doc-html=no'])
+
+    def prep(self):
+        Package.prep(self)
+        if Package.profile.name == 'darwin':
+            for p in range(1, len(self.local_sources)):
+                self.sh(
+                    'patch -p1 --ignore-whitespace < "%{local_sources[' + str(p) + ']}"')
+
+    def deploy(self):
+        self.loaders_cache = 'lib/gdk-pixbuf-2.0/2.10.0/loaders.cache'
+        self.sh('gdk-pixbuf-query-loaders --update-cache ')
+
+        # mark the file for destaging
+        self.sh(
+            'cp %{staged_profile}/%{loaders_cache} %{staged_profile}/%{loaders_cache}.release')
+        self.extra_stage_files = [self.loaders_cache]
+
+GdkPixbufPackage()
diff --git a/bockbuild/mac-sdk/gdk-pixbuf/0001-pixbuf-Add-getter-setter-for-the-2x-variants.patch b/bockbuild/mac-sdk/gdk-pixbuf/0001-pixbuf-Add-getter-setter-for-the-2x-variants.patch
new file mode 100644 (file)
index 0000000..2ca1c6a
--- /dev/null
@@ -0,0 +1,56 @@
+From f6d2db5a0c105785ee6f03717966ef0dbb1421f6 Mon Sep 17 00:00:00 2001
+From: Carlos Garnacho <carlosg@gnome.org>
+Date: Tue, 16 Jul 2013 10:32:11 +0200
+Subject: [PATCH] pixbuf: Add getter/setter for the 2x variants
+
+---
+ gdk-pixbuf/gdk-pixbuf-core.h |  3 +++
+ gdk-pixbuf/gdk-pixbuf.c      | 22 ++++++++++++++++++++++
+ 2 files changed, 25 insertions(+)
+
+diff --git a/gdk-pixbuf/gdk-pixbuf-core.h b/gdk-pixbuf/gdk-pixbuf-core.h
+index eb4d0a1..60c4ea3 100644
+--- a/gdk-pixbuf/gdk-pixbuf-core.h
++++ b/gdk-pixbuf/gdk-pixbuf-core.h
+@@ -474,6 +474,9 @@ GdkPixbuf *gdk_pixbuf_apply_embedded_orientation (GdkPixbuf *src);
+ const gchar * gdk_pixbuf_get_option (GdkPixbuf   *pixbuf,
+                                               const gchar *key);
+
++GdkPixbuf * gdk_pixbuf_get_hires_variant (GdkPixbuf *pixbuf);
++void        gdk_pixbuf_set_hires_variant (GdkPixbuf *pixbuf,
++                                          GdkPixbuf *hires);
+
+ G_END_DECLS
+
+diff --git a/gdk-pixbuf/gdk-pixbuf.c b/gdk-pixbuf/gdk-pixbuf.c
+index 0e13f27..d61f2c7 100644
+--- a/gdk-pixbuf/gdk-pixbuf.c
++++ b/gdk-pixbuf/gdk-pixbuf.c
+@@ -990,3 +990,25 @@ gdk_pixbuf_get_property (GObject         *object,
+                   break;
+           }
+ }
++
++GdkPixbuf *
++gdk_pixbuf_get_hires_variant (GdkPixbuf *pixbuf)
++{
++        g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
++
++        return g_object_get_data (G_OBJECT (pixbuf),
++                                  "gdk-pixbuf-2x-variant");
++}
++
++void
++gdk_pixbuf_set_hires_variant (GdkPixbuf *pixbuf,
++                              GdkPixbuf *hires)
++{
++        g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
++        g_return_if_fail (GDK_IS_PIXBUF (hires));
++
++        g_object_set_data_full (G_OBJECT (pixbuf),
++                                "gdk-pixbuf-2x-variant",
++                                g_object_ref (hires),
++                                (GDestroyNotify) g_object_unref);
++}
+--
+1.8.3.2
diff --git a/bockbuild/mac-sdk/gdk-pixbuf/0001-pixbuf-load-2x-variants-as-pixbuf-gobject-data.patch b/bockbuild/mac-sdk/gdk-pixbuf/0001-pixbuf-load-2x-variants-as-pixbuf-gobject-data.patch
new file mode 100644 (file)
index 0000000..80d3d39
--- /dev/null
@@ -0,0 +1,99 @@
+>From de5d91aa15cc98795a68c8e553eb4baadaa0e501 Mon Sep 17 00:00:00 2001
+From: Carlos Garnacho <carlosg@gnome.org>
+Date: Fri, 17 May 2013 15:56:28 +0200
+Subject: [PATCH] pixbuf: load "@2x" variants as pixbuf gobject data
+
+if a variant of the filename is found that has a "@2x" appended
+to the file name (before the extension), such file is loaded
+and added as GObject data to the pixbuf
+---
+ gdk-pixbuf/gdk-pixbuf-io.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 55 insertions(+)
+
+diff --git a/gdk-pixbuf/gdk-pixbuf-io.c b/gdk-pixbuf/gdk-pixbuf-io.c
+index dac21b8..ed98cd3 100644
+--- a/gdk-pixbuf/gdk-pixbuf-io.c
++++ b/gdk-pixbuf/gdk-pixbuf-io.c
+@@ -1025,6 +1025,40 @@ _gdk_pixbuf_generic_image_load (GdkPixbufModule *module,
+         return pixbuf;
+ }
+
++static gboolean
++_gdk_pixbuf_file_is_scaled (const gchar *filename)
++{
++      gchar *basename, *ext;
++
++      basename = g_path_get_basename (filename);
++      ext = strrchr (basename, '.');
++
++      if (!ext)
++              ext = &basename[strlen(basename)];
++
++      if (ext > basename + 3 && strncmp (ext - 3, "@2x", 3) == 0)
++              return TRUE;
++
++      return FALSE;
++}
++
++static gchar *
++_gdk_pixbuf_compose_scaled_filename (const gchar *filename)
++{
++      gchar *ext, *first, *composed;
++
++      ext = strrchr (filename, '.');
++
++      if (!ext)
++              return NULL;
++
++      first = g_strndup (filename, ext - filename);
++      composed = g_strdup_printf ("%s@2x%s", first, ext);
++      g_free (first);
++
++      return composed;
++}
++
+ /**
+  * gdk_pixbuf_new_from_file:
+  * @filename: Name of file to load, in the GLib file name encoding
+@@ -1049,11 +1083,13 @@ gdk_pixbuf_new_from_file (const char *filename,
+         guchar buffer[SNIFF_BUFFER_SIZE];
+         GdkPixbufModule *image_module;
+         gchar *display_name;
++      gboolean filename_is_scaled;
+
+         g_return_val_if_fail (filename != NULL, NULL);
+         g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+         display_name = g_filename_display_name (filename);
++      filename_is_scaled = _gdk_pixbuf_file_is_scaled (filename);
+
+         f = g_fopen (filename, "rb");
+         if (!f) {
+@@ -1097,6 +1133,25 @@ gdk_pixbuf_new_from_file (const char *filename,
+         pixbuf = _gdk_pixbuf_generic_image_load (image_module, f, error);
+         fclose (f);
+
++      if (pixbuf && !filename_is_scaled) {
++              GdkPixbuf *scaled_pixbuf = NULL;
++              gchar *scaled_filename;
++
++              scaled_filename = _gdk_pixbuf_compose_scaled_filename (filename);
++
++              if (scaled_filename) {
++                      scaled_pixbuf = gdk_pixbuf_new_from_file (scaled_filename, NULL);
++                      g_free (scaled_filename);
++              }
++
++              if (scaled_pixbuf) {
++                      g_object_set_data_full (G_OBJECT (pixbuf),
++                                                "gdk-pixbuf-2x-variant",
++                                                scaled_pixbuf,
++                                                (GDestroyNotify) g_object_unref);
++              }
++      }
++
+         if (pixbuf == NULL && error != NULL && *error == NULL) {
+
+                 /* I don't trust these crufty longjmp()'ing image libs
+--
+1.8.3.rc1
diff --git a/bockbuild/mac-sdk/gettext.py b/bockbuild/mac-sdk/gettext.py
new file mode 100644 (file)
index 0000000..78cc861
--- /dev/null
@@ -0,0 +1,31 @@
+class GettextPackage (GnuPackage):
+
+    def __init__(self):
+        GnuPackage.__init__(self, 'gettext', '0.18.2',
+                            configure_flags=[
+                                '--disable-java',
+                                '--disable-libasprintf',
+                                '--disable-openmp',
+                                '--with-included-glib'
+                            ]
+                            )
+
+        if Package.profile.name == 'darwin':
+            self.configure_flags.extend([
+                # only build the tools, osx has the lib
+                # https://github.com/mxcl/homebrew/blob/master/Library/Formula/gettext.rb
+                #'--without-included-gettext',
+            ])
+            self.sources.extend([
+                # Don't build samples
+                # https://trac.macports.org/export/79183/trunk/dports/devel/gettext/files/patch-gettext-tools-Makefile.in
+                'patches/gettext-no-samples.patch',
+            ])
+
+    def prep(self):
+        Package.prep(self)
+        if Package.profile.name == 'darwin':
+            for p in range(1, len(self.local_sources)):
+                self.sh('patch -p1 < "%{local_sources[' + str(p) + ']}"')
+
+GettextPackage()
diff --git a/bockbuild/mac-sdk/glib.py b/bockbuild/mac-sdk/glib.py
new file mode 100644 (file)
index 0000000..bd9cd3d
--- /dev/null
@@ -0,0 +1,79 @@
+class GlibPackage (GnomeXzPackage):
+
+    def __init__(self):
+        GnomeXzPackage.__init__(self,
+                                'glib',
+                                version_major='2.36',
+                                version_minor='4')
+
+        self.darwin = Package.profile.name == 'darwin'
+
+        if self.darwin:
+            # link to specific revisions for glib 2.30.x
+            self.sources.extend([
+                # https://trac.macports.org/export/91680/trunk/dports/devel/glib2/files/config.h.ed
+                'patches/glib/config.h.ed',
+                # https://trac.macports.org/export/98985/trunk/dports/devel/glib2/files/patch-configure.diff
+                'patches/glib/patch-configure.diff',
+                # https://trac.macports.org/export/42728/trunk/dports/devel/glib2/files/patch-gi18n.h.diff
+                'patches/glib/patch-gi18n.h.diff',
+                # https://trac.macports.org/export/92608/trunk/dports/devel/glib2/files/patch-gio_gdbusprivate.c.diff
+                'patches/glib/patch-gio_gdbusprivate.c.diff',
+                # https://trac.macports.org/export/49466/trunk/dports/devel/glib2/files/patch-gio_xdgmime_xdgmime.c.diff
+                'patches/glib/patch-gio_xdgmime_xdgmime.c.diff',
+                # https://trac.macports.org/export/91680/trunk/dports/devel/glib2/files/patch-glib-2.0.pc.in.diff
+                'patches/glib/patch-glib-2.0.pc.in.diff',
+                # https://trac.macports.org/export/64476/trunk/dports/devel/glib2/files/patch-glib_gunicollate.c.diff
+                'patches/glib/patch-glib_gunicollate.c.diff',
+
+                # Bug 6156 - [gtk] Quitting the application with unsaved file and answering Cancel results in crash
+                # https://bugzilla.xamarin.com/attachment.cgi?id=2214
+                'patches/glib-recursive-poll.patch',
+            ])
+
+    def prep(self):
+        Package.prep(self)
+        if self.darwin:
+            for p in range(2, 8):
+                self.sh('patch -p0 < %{local_sources[' + str(p) + ']}')
+            for p in range(8, len(self.local_sources)):
+                self.sh(
+                    'patch --ignore-whitespace -p1 < %{local_sources[' + str(p) + ']}')
+
+    def arch_build(self, arch):
+        if arch == 'darwin-universal':  # multi-arch  build pass
+            self.local_ld_flags = ['-arch i386', '-arch x86_64']
+            self.local_gcc_flags = ['-arch i386', '-arch x86_64', '-Os']
+            self.local_configure_flags = ['--disable-dependency-tracking']
+        else:
+            Package.arch_build(self, arch)
+
+        if self.darwin:
+            self.local_configure_flags.extend(['--disable-compile-warnings'])
+
+    def build(self):
+        # modified build for darwin
+        if self.darwin:
+            self.local_configure_flags.extend(['--disable-compile-warnings'])
+            Package.configure(self)
+            self.sh([
+                # 'autoconf',
+                    #'%{configure} --disable-compile-warnings',
+                    'ed - config.h < %{local_sources[1]}',
+                    # work around
+                    # https://bugzilla.gnome.org/show_bug.cgi?id=700350
+                    'touch docs/reference/*/Makefile.in',
+                    'touch docs/reference/*/*/Makefile.in',
+                    #'%{make}'
+                    ])
+            Package.make(self)
+        else:
+            Package.build(self)
+
+    def install(self):
+        Package.install(self)
+        if self.darwin:
+            # FIXME: necessary?
+            self.sh('rm -f %{staged_prefix}/lib/charset.alias')
+
+GlibPackage()
diff --git a/bockbuild/mac-sdk/gtk+.py b/bockbuild/mac-sdk/gtk+.py
new file mode 100644 (file)
index 0000000..e9c2d77
--- /dev/null
@@ -0,0 +1,213 @@
+class GtkPackage (GnomeGitPackage):
+
+    def __init__(self):
+        GnomeGitPackage.__init__(self, 'gtk+', '2.24', '280fc402be5fb46b66bcd32056963bb1afb8b54b',
+                                 configure_flags=[
+                                     '--with-gdktarget=%{gdk_target}',
+                                     #                         '--disable-cups',
+                                 ]
+                                 )
+        self.gdk_target = 'x11'
+
+        if Package.profile.name == 'darwin':
+            self.gdk_target = 'quartz'
+            self.sources.extend([
+                # Custom gtkrc
+                'patches/gtkrc',
+
+                # smooth scrolling, scrollbars, overscroll, retina,
+                # gtknsview
+                'patches/gtk/0001-Add-invariant-that-a-child-is-unmapped-if-parent-is-.patch',
+                'patches/gtk/0002-Maintain-map-unmap-invariants-in-GtkRecentChooserDia.patch',
+                'patches/gtk/0003-GtkPlug-preserve-map-unmap-invariants.patch',
+                'patches/gtk/0004-Add-gdk_screen_get_monitor_workarea-and-use-it-all-o.patch',
+                'patches/gtk/0005-gtk-don-t-scroll-combo-box-menus-if-less-than-3-item.patch',
+                'patches/gtk/0006-gtk-paint-only-the-exposed-region-in-gdk_window_expo.patch',
+                'patches/gtk/0007-Implement-gtk-enable-overlay-scrollbars-GtkSetting.patch',
+                'patches/gtk/0008-Smooth-scrolling.patch',
+                'patches/gtk/0009-gtk-Add-a-way-to-do-event-capture.patch',
+                'patches/gtk/0010-gtk-don-t-let-insensitive-children-eat-scroll-events.patch',
+                'patches/gtk/0011-scrolledwindow-Kinetic-scrolling-support.patch',
+                'patches/gtk/0012-gtk-paint-to-the-right-windows-in-gtk_scrolled_windo.patch',
+                'patches/gtk/0013-GtkScrolledWindow-add-overlay-scrollbars.patch',
+                'patches/gtk/0014-gtk-add-event-handling-to-GtkScrolledWindow-s-overla.patch',
+                'patches/gtk/0015-Use-gtk-enable-overlay-scrollbars-in-GtkScrolledWind.patch',
+                'patches/gtk/0016-gtk-correctly-handle-toggling-of-the-scrollbar-visib.patch',
+                'patches/gtk/0017-gtk-handle-gtk-primary-button-warps-slider-for-the-o.patch',
+                'patches/gtk/0018-Introduce-phase-field-in-GdkEventScroll.patch',
+                'patches/gtk/0019-Add-hack-to-lock-flow-of-scroll-events-to-window-whe.patch',
+                'patches/gtk/0020-Introduce-a-background-window.patch',
+                'patches/gtk/0021-Make-scrolled-window-work-well-with-Mac-touchpad.patch',
+                'patches/gtk/0022-Use-start-end-phase-in-event-handling.patch',
+                'patches/gtk/0023-Improve-overshooting-behavior.patch',
+                'patches/gtk/0024-Cancel-out-smaller-delta-component.patch',
+                'patches/gtk/0025-quartz-Add-a-dummy-NSView-serving-as-layer-view.patch',
+                'patches/gtk/0026-gtk-port-overlay-scrollbars-to-native-CALayers.patch',
+                'patches/gtk/0027-Refrain-from-starting-fading-out-while-a-gesture-is-.patch',
+                'patches/gtk/0028-gtk-don-t-show-the-olverlay-scrollbars-if-only-the-s.patch',
+                'patches/gtk/0029-Reclamp-unclamped-adjustments-after-resize.patch',
+                'patches/gtk/0030-gtk-fix-size_request-of-scrolled-window.patch',
+                'patches/gtk/0031-Hackish-fix-for-bug-8493-Min-size-of-GtkScrolledWind.patch',
+                'patches/gtk/0032-Add-momentum_phase-to-GdkEventScroll.patch',
+                'patches/gtk/0033-Never-intervene-in-the-event-stream-for-legacy-mice.patch',
+                'patches/gtk/0034-Do-not-start-overshooting-for-legacy-mouse-scroll-ev.patch',
+                'patches/gtk/0035-gtk-remove-the-overlay-scrollbar-grab-on-unrealize.patch',
+                'patches/gtk/0036-gtk-add-GtkScrolledWindow-API-to-disable-overshoot-p.patch',
+                'patches/gtk/0037-quartz-return-events-on-embedded-foreign-NSViews-bac.patch',
+                'patches/gtk/0038-quartz-don-t-forward-events-to-the-toplevel-nswindow.patch',
+                'patches/gtk/0039-gdk-add-a-move-native-children-signal-to-GdkWindow.patch',
+                'patches/gtk/0040-gtk-add-new-widget-GtkNSView-which-alows-to-embed-an.patch',
+                'patches/gtk/0041-tests-add-a-notebook-to-testnsview.c.patch',
+                'patches/gtk/0042-gtk-connect-GtkNSView-to-move-native-children-and-re.patch',
+                'patches/gtk/0043-tests-add-a-scrolled-window-test-widget-to-testnsvie.patch',
+                'patches/gtk/0044-gtknsview-clip-drawRect-to-a-parent-GtkViewport-s-wi.patch',
+                'patches/gtk/0045-gtk-clip-NSViews-to-the-scrolled-window-s-overshoot_.patch',
+                'patches/gtk/0046-gtk-implement-clipping-to-multiple-parent-viewports-.patch',
+                'patches/gtk/0047-gtk-first-attempt-to-also-clip-NSWindow-s-field-edit.patch',
+                'patches/gtk/0048-gtk-also-clip-the-NSView-s-subviews.patch',
+                'patches/gtk/0049-nsview-also-swizzle-DidAddSubview-and-clip-all-subvi.patch',
+                'patches/gtk/0050-nsview-clip-text-field-cursor-drawing.patch',
+                'patches/gtk/0051-nsview-factor-out-almost-all-code-from-the-overridde.patch',
+                'patches/gtk/0052-nsview-also-focus-the-GtkNSView-if-a-focussable-subv.patch',
+                'patches/gtk/0053-gtk-add-an-overlay-policy-API-to-GtkScrolledWindow.patch',
+                'patches/gtk/0054-quartz-add-gdk_screen_-and-gdk_window_get_scale_fact.patch',
+                'patches/gtk/0055-gtk-add-gtk_widget_get_scale_factor.patch',
+                'patches/gtk/0056-iconfactory-Add-_scaled-variants.patch',
+                'patches/gtk/0057-widget-Add-_scaled-variants-for-icon-rendering.patch',
+                'patches/gtk/0058-icontheme-Add-support-for-high-resolution-icons.patch',
+                'patches/gtk/0059-iconfactory-Add-scale-info-to-GtkIconSource.patch',
+                'patches/gtk/0060-iconfactory-Add-gtk_cairo_set_source_icon_set.patch',
+                'patches/gtk/0061-image-Use-scaled-icons-on-windows-with-a-scaling-fac.patch',
+                'patches/gtk/0062-cellrendererpixbuf-Use-scaled-icons-on-windows-with-.patch',
+                'patches/gtk/0063-entry-Use-scaled-icons-on-windows-with-a-scale-facto.patch',
+                'patches/gtk/0064-gdk-Lookup-double-scaled-variants-on-pixbufs.patch',
+                'patches/gtk/0065-Make-usual-calls-to-get-a-GdkPixbuf-attach-a-2x-vari.patch',
+                'patches/gtk/0066-cellrendererpixbuf-let-2x-variants-go-through-pixel-.patch',
+                'patches/gtk/0067-quartz-Make-event-loop-deal-with-recursive-poll-invo.patch',
+                'patches/gtk/0068-nsview-implement-a-few-text-view-command-accelerator.patch',
+                'patches/gtk/0069-menu-scrolling.patch',
+                'patches/gtk/0070-tooltips-focus.patch',
+                'patches/gtk/0071-light-and-dark-overlay-scrollbars.patch',
+                'patches/gtk/0072-let-global-keyboard-shortcuts-pass-through.patch',
+                'patches/gtk/0073-disable-combobox-scrolling.patch',
+                'patches/gtk/0074-fix-NULL-pointer-in-clipboard.patch',
+                'patches/gtk/0075-filechooserwidget-location-entry-activation.patch',
+                'patches/gtk/0076-iconfactory-treat-gt-1-0-icons-as-2-0.patch',
+
+                # Bug 702841 - GdkQuartz does not distinguish Eisu, Kana and Space keys on Japanese keyrboard
+                # https://bugzilla.gnome.org/show_bug.cgi?id=702841
+                'patches/gtk/bgo702841-fix-kana-eisu-keys.patch',
+
+                # make new modifier behviour opt-in, so as not to break old
+                # versions of MonoDevelop
+                'patches/gdk-quartz-set-fix-modifiers-hack-v3.patch',
+
+                # attempt to work around 2158 - [GTK] crash triggering context menu
+                # also prints some warnings that may help to debug the real issue
+                # https://bugzilla.xamarin.com/attachment.cgi?id=1644
+                'patches/gtk/bxc2158_workaround_crash_triggering_context_menu.patch',
+
+                # Zoom, rotate, swipe events
+                'patches/gtk-gestures.patch',
+
+                # Fix gtk_window_begin_move_drag on Quartz
+                'patches/gtk-quartz-move-drag.patch',
+
+                # Bug 3457 - [GTK] Support more standard keyboard shortcuts in dialogs
+                # https://bugzilla.xamarin.com/attachment.cgi?id=2240
+                'patches/gtk/bxc3457_more_standard_keyboard_shortcuts.patch',
+
+                # Bug  10256 - Mac window manipulation tools get confused by Xamarin Studio
+                # https://bugzilla.xamarin.com/attachment.cgi?id=3465
+                'patches/gtk/bxc_10256_window_tools_get_confused.diff',
+
+                #                                'patches/gtk/gdk-pixmap-get-cgimage-2.patch',
+
+                # https://bugzilla.xamarin.com/show_bug.cgi?id=18157
+                'patches/gtk/gtk-check-grab_toplevel-is-destroyed.patch',
+
+                # https://bugzilla.xamarin.com/show_bug.cgi?id=18241
+                # https://bugzilla.xamarin.com/show_bug.cgi?id=17631
+                # https://bugzilla.xamarin.com/show_bug.cgi?id=17692
+                'patches/gtk/gtk-imquartz-defer-signals-in-output_result.patch',
+
+                # https://bugzilla.xamarin.com/show_bug.cgi?id=17401
+                'patches/gtk/gtknsview-defer-map-and-lock-in-clipping.patch',
+                'patches/gtk/gtknsview-timeout-fix.patch',
+
+                'patches/gtk/nsview-embedding.patch',
+
+                'patches/gtk/enable-swizzle-property.patch',
+
+                # https://bugzilla.xamarin.com/show_bug.cgi?id=12618
+                'patches/gtk/disable-eye-dropper.patch',
+
+                # https://bugzilla.xamarin.com/show_bug.cgi?id=13100
+                'patches/gtk/flip-command-mask-between-mod1-and-mod2.patch',
+                'patches/gtk/nsview-embedding-fix-keyboard-routing.patch',
+                'patches/gtk/nsview-check-for-superview.patch',
+
+                'patches/gtk/gtknsview-forward-cmdz-to-textview-undo-manager.patch',
+
+                # https://bugzilla.xamarin.com/show_bug.cgi?id=20732
+                'patches/gtk/embedded-nstextview-has-focus.patch',
+                'patches/gtk/remove-demos-from-build.patch',
+
+                # This fixes an issue in where in some situations the user needed
+                # to click a native text entry twice in order to be able to
+                # focus it.
+                'patches/gtk/gtknsview-only-unset-first-responder-if-it-is-our-view.patch',
+
+                # For the test framework to be able to traverse down the
+                # NSView hierarchy
+                'patches/gtk/gtknsview-getter.patch',
+
+                # https://bugzilla.xamarin.com/show_bug.cgi?id=29301#c3
+                'patches/gtk/gtknsview-fix-invalid-casts.patch',
+
+                # https://bugzilla.xamarin.com/show_bug.cgi?id=29001
+                'patches/gtk/quartz-call-undo-redo-on-cmdz.patch',
+
+                'patches/gtk/scrolled-window-draw-child-bg.patch',
+
+                # https://bugzilla.xamarin.com/show_bug.cgi?id=37239
+                'patches/gtk/fix-imquartz-crasher.patch',
+
+                # https://bugzilla.gnome.org/show_bug.cgi?id=630226
+                # https://bugzilla.xamarin.com/show_bug.cgi?id=34973
+                'patches/gtk/remove-mouse-scrolling-from-GtkNotebook-tabs.patch',
+
+                # https://bugzilla.xamarin.com/show_bug.cgi?id=37951
+                'patches/gtk/dont-call-CopySymbolicHotKeys-so-much.patch',
+
+                # https://bugzilla.xamarin.com/show_bug.cgi?id=38664
+                'patches/gtk/combobox-crossing-events.patch',
+
+                # https://bugzilla.xamarin.com/show_bug.cgi?id=41657
+                'patches/gtk/bxc-41657.patch',
+
+                'patches/gtk/emit-container-add.patch',
+                'patches/gtk/create-accessibility-object.patch',
+                'patches/gtk/make-gtkpaned-emit-signals.patch'
+            ])
+
+    def prep(self):
+        Package.prep(self)
+        if Package.profile.name == 'darwin':
+            for p in range(2, len(self.local_sources)):
+                self.sh(
+                    'patch -p1 --ignore-whitespace < "%{local_sources[' + str(p) + ']}"')
+
+    def install(self):
+        Package.install(self)
+        if Package.profile.name == 'darwin':
+            self.install_gtkrc()
+
+    def install_gtkrc(self):
+        gtkrc = self.local_sources[1]
+        destdir = os.path.join(self.staged_prefix, "etc", "gtk-2.0")
+        if not os.path.exists(destdir):
+            os.makedirs(destdir)
+        self.sh('cp %s %s' % (gtkrc, destdir))
+
+GtkPackage()
diff --git a/bockbuild/mac-sdk/gtk-engines.py b/bockbuild/mac-sdk/gtk-engines.py
new file mode 100644 (file)
index 0000000..d3a6d4a
--- /dev/null
@@ -0,0 +1,2 @@
+GnomePackage('gtk-engines', version_major='2.20', version_minor='2',
+             configure_flags=[''])
diff --git a/bockbuild/mac-sdk/gtk-quartz-engine.py b/bockbuild/mac-sdk/gtk-quartz-engine.py
new file mode 100644 (file)
index 0000000..a55a5af
--- /dev/null
@@ -0,0 +1,13 @@
+class GtkQuartzEnginePackage (Package):
+
+    def __init__(self):
+        Package.__init__(self, 'gtk-quartz-engine',
+                         sources=[
+                             'git://github.com/mono/gtk-quartz-engine.git'],
+                         override_properties={
+                             'configure': './autogen.sh --prefix=%{package_prefix}',
+                             'needs_lipo': True
+                         },
+                         revision='9555a08f0c9c98d02153c9d77b54a2dd83ce5d6f')
+
+GtkQuartzEnginePackage()
diff --git a/bockbuild/mac-sdk/gtk-sharp.py b/bockbuild/mac-sdk/gtk-sharp.py
new file mode 100644 (file)
index 0000000..815b2e4
--- /dev/null
@@ -0,0 +1,14 @@
+class GtkSharp212ReleasePackage (Package):
+
+    def __init__(self):
+        Package.__init__(self, 'gtk-sharp',
+                         sources=['git://github.com/mono/gtk-sharp.git'],
+                         git_branch='gtk-sharp-2-12-branch',
+                         revision='f092864bce996c4ac51a13281069067d1e7e6d4b',
+                         override_properties={
+                             'configure': './bootstrap-2.12 --prefix=%{package_prefix}',
+                         }
+                         )
+        self.make = 'make CSC=mcs'
+
+GtkSharp212ReleasePackage()
diff --git a/bockbuild/mac-sdk/gtkrc b/bockbuild/mac-sdk/gtkrc
new file mode 100644 (file)
index 0000000..b1168d6
--- /dev/null
@@ -0,0 +1,216 @@
+include "/Library/Frameworks/Mono.framework/Versions/Current/share/themes/Clearlooks/gtk-2.0/gtkrc"
+#gtk-icon-theme-name = "OSX"
+gtk-icon-theme-name = "Tango"
+gtk_color_scheme = "fg_color:#222\nbg_color:#e6e6e6\nbase_color:#f9f9f9\ntext_color:#222\nselected_bg_color:#788ab0\nselected_fg_color:#fff"
+gtk-menu-popup-delay = 1
+gtk-button-images = 0
+gtk-menu-images = 0
+gtk-enable-mnemonics = 0
+
+style "theme-default"
+{
+    GtkButton      ::default_border    = { 0, 0, 0, 0 }
+    GtkRange       ::trough_border     = 0
+    GtkPaned       ::handle_size       = 8
+    GtkRange       ::slider_width      = 15
+    GtkRange       ::stepper_size      = 15
+    GtkScrollbar   ::min_slider_length = 30
+    GtkCheckButton ::indicator_size    = 14
+    GtkMenuBar     ::internal-padding  = 0
+    GtkTreeView    ::expander_size     = 12
+    GtkExpander    ::expander_size     = 14
+
+    xthickness = 2
+    ythickness = 2
+
+    fg[NORMAL]        = @fg_color #"#000000" # black
+    fg[PRELIGHT]      = @fg_color #"#000000" # black
+    fg[SELECTED]      = @selected_fg_color #"#ffffff" # white
+    fg[ACTIVE]        = @fg_color #"#000000" # black
+    fg[INSENSITIVE]   = darker (@bg_color) #"#b5b3ac" # dark beige
+
+    bg[NORMAL]        = @bg_color # "#ede9e3"
+    bg[PRELIGHT]      = shade (1.02, @bg_color) #"#f9f7f3" # very light beige
+    bg[SELECTED]      = @selected_bg_color # "#5598d7" # deepsky
+    bg[INSENSITIVE]   = @bg_color # "#efebe5" # beige
+    bg[ACTIVE]        = shade (0.9, @bg_color) #"#dcd4c9" #"#d7d3ca" # dark beige
+
+    base[NORMAL]      = @base_color # "#ffffff" # white
+    base[PRELIGHT]    = shade (0.95, @bg_color) # "#5f8ec4" # dark beige
+    base[ACTIVE]      = shade (0.9, @selected_bg_color) # "#a69f91" # darker deepsky
+    base[SELECTED]    = @selected_bg_color # "#5598d7" # deepsky
+    base[INSENSITIVE] = @bg_color # "#e8e5de" # beige
+
+    text[NORMAL]      = @text_color # "#000000" # black
+    text[PRELIGHT]    = @text_color # "#000000" # black
+    text[ACTIVE]      = @selected_fg_color # "#ffffff" # white
+    text[SELECTED]    = @selected_fg_color # "#ffffff" # white
+    text[INSENSITIVE] = darker (@bg_color) # "#b5b3ac" # dark beige
+
+    engine "clearlooks"  {
+      style               = GUMMY   # gummy look
+      toolbarstyle        = 0       # flat toolbars
+      animation           = TRUE    # animated progressbars
+      menubarstyle        = 2       # rounded menus
+      colorize_scrollbar  = TRUE    # colored slider
+    }
+
+    font              = "Lucida Grande 14"
+}
+
+style "theme-wide" = "theme-default"
+{
+    xthickness = 3
+    ythickness = 3
+}
+
+style "theme-text" = "theme-default"
+{
+    #base[SELECTED]     = "#fc9747"  # Outline?
+}
+
+style "theme-toolbar" = "theme-default"
+{
+    #top and bottom border
+    bg[NORMAL] = @bg_color
+}
+
+style "theme-scrollbar" = "theme-default"
+{
+    bg[SELECTED] = shade (1.1, @selected_bg_color)
+}
+
+style "theme-tasklist" = "theme-default"
+{
+    xthickness = 5
+    ythickness = 3
+}
+
+style "theme-menu" = "theme-default"
+{
+    xthickness = 3
+    ythickness = 3
+    bg[NORMAL] = shade (1.1,@bg_color)
+}
+
+style "theme-menu-item" = "theme-default"
+{
+    xthickness = 2
+    ythickness = 4
+    fg[PRELIGHT] = @selected_fg_color
+    text[PRELIGHT] = @selected_fg_color
+    base[PRELIGHT] = @selected_bg_color # Selection color
+}
+
+style "theme-menu-itembar" = "theme-default"
+{
+    xthickness = 0
+    ythickness = 0
+}
+
+style "theme-tree" = "theme-default"
+{
+    xthickness = 2
+    ythickness = 2
+    GtkTreeView::odd-row-color = shade(0.9, @base_color)
+    GtkTreeView::even-row-color = @base_color
+}
+
+style "theme-frame-title" = "theme-default"
+{
+    #fg[NORMAL] = "#f00" #button frames
+}
+
+style "theme-tooltips" = "theme-default"
+{
+    xthickness = 4
+    ythickness = 4
+    bg[NORMAL] = { 1.0,1.0,0.75 }
+}
+
+style "theme-progressbar" = "theme-default"
+{
+    xthickness = 1
+    ythickness = 1
+    fg[PRELIGHT]  = @base_color
+}
+
+style "theme-combo" = "theme-default"
+{
+    xthickness = 2
+    ythickness = 4
+}
+
+style "theme-button" = "theme-wide"
+{
+    bg[NORMAL] = @bg_color
+    bg[PRELIGHT] = shade (1.1, @bg_color)
+    bg[ACTIVE] = shade (0.9, @bg_color)
+    #xthickness = 4
+    #ythickness = 2
+}
+
+style "theme-check" = "theme-button"
+{
+}
+
+style "theme-panel" = "theme-default"
+{
+    xthickness = 3
+    ythickness = 3
+    bg[ACTIVE] = shade (1.1, @selected_bg_color)
+    fg[ACTIVE] = @selected_fg_color
+}
+
+style "theme-notebook" = "theme-wide"
+{
+    base[SELECTED]    = @selected_bg_color  # Tab selection color
+    bg[ACTIVE]        = shade(0.9, @bg_color)  # Unselected tabs
+
+#    engine "clearlooks" {
+#        style = CLASSIC
+#    }
+}
+
+# widget styles
+class "GtkWidget" style "theme-default"
+class "GtkButton" style "theme-button"
+class "GtkCombo"  style "theme-button"
+class "GtkRange"  style "theme-wide"
+class "GtkFrame"  style "theme-wide"
+class "GtkMenu"   style "theme-menu"
+class "GtkEntry"  style "theme-button"
+class "GtkMenuItem"    style "theme-menu-item"
+class "GtkStatusbar"   style "theme-wide"
+class "GtkNotebook"    style "theme-notebook"
+class "GtkProgressBar" style "theme-progressbar"
+class "GtkCheckButton" style "theme-check"
+class "GtkRadioButton" style "theme-check"
+class "GtkToolbar" style "theme-toolbar"
+
+widget_class "*MenuItem.*" style "theme-menu-item"
+
+# combobox stuff
+widget_class "*.GtkComboBox.GtkButton" style "theme-combo"
+widget_class "*.GtkCombo.GtkButton"    style "theme-combo"
+
+# tooltips stuff
+widget_class "*.tooltips.*.GtkToggleButton" style "theme-tasklist"
+widget "gtk-tooltips" style "theme-tooltips"
+
+# treeview stuff
+widget "*GtkTreeView*" style "theme-tree"
+widget_class "*.GtkTreeView.GtkButton" style "theme-tree"
+widget_class "*.GtkCTree.GtkButton" style "theme-tree"
+widget_class "*.GtkList.GtkButton" style "theme-tree"
+widget_class "*.GtkCList.GtkButton" style "theme-tree"
+widget_class "*.GtkFrame.GtkLabel" style "theme-frame-title"
+
+# notebook stuff
+widget_class "*.GtkNotebook.*.GtkEventBox" style "theme-notebook"
+widget_class "*.GtkNotebook.*.GtkViewport" style "theme-notebook"
+
+# scrollbar stuff
+class "GtkScrollbar" style "theme-scrollbar"
+
+gtk-font-name = "Lucida Grande 12"
diff --git a/bockbuild/mac-sdk/hicolor-icon-theme.py b/bockbuild/mac-sdk/hicolor-icon-theme.py
new file mode 100644 (file)
index 0000000..7387aa0
--- /dev/null
@@ -0,0 +1 @@
+FreeDesktopPackage('icon-theme', 'hicolor-icon-theme', '0.12')
diff --git a/bockbuild/mac-sdk/ige-mac-integration.py b/bockbuild/mac-sdk/ige-mac-integration.py
new file mode 100644 (file)
index 0000000..e381a9e
--- /dev/null
@@ -0,0 +1,3 @@
+SourceForgePackage('gtk-osx', 'ige-mac-integration', '0.9.4', ['--without-compile-warnings'],
+                   override_properties={'configure': './configure --prefix="%{staged_prefix}"',
+                                        'makeinstall': 'make install'})
diff --git a/bockbuild/mac-sdk/intltool.py b/bockbuild/mac-sdk/intltool.py
new file mode 100644 (file)
index 0000000..4550fb1
--- /dev/null
@@ -0,0 +1,10 @@
+class IntltoolPackage (Package):
+
+    def __init__(self):
+        Package.__init__(self, 'intltool', '0.50.2',
+                         sources=[
+                             'https://launchpad.net/%{name}/trunk/%{version}/+download/%{name}-%{version}.tar.gz'
+                         ]
+                         )
+
+IntltoolPackage()
diff --git a/bockbuild/mac-sdk/ironlangs.py b/bockbuild/mac-sdk/ironlangs.py
new file mode 100644 (file)
index 0000000..0d4e336
--- /dev/null
@@ -0,0 +1,66 @@
+import os
+import string
+
+
+class IronLanguagesPackage(GitHubTarballPackage):
+
+    def __init__(self):
+        GitHubTarballPackage.__init__(self,
+                                      'IronLanguages', 'iron-languages',
+                                      '2.11',
+                                      'de63773744ccf9873c1826470730ae0446fd64d7',
+                                      configure='')
+
+        # override: avoid naming the package 'main' because of the repo name
+        self.sources = [
+            'https://github.com/%{organization}/main/tarball/%{revision}']
+        self.source_dir_name = '%s-%s-%s' % (
+            self.organization, 'main', self.revision[:7])
+
+    def build(self):
+        self.ironruby = os.path.join(
+            self.workspace, 'ironruby', 'bin') + os.sep
+        self.ironpython = os.path.join(
+            self.workspace, 'ironpython', 'bin') + os.sep
+        self.sh(
+            'xbuild /p:Configuration=Release /p:OutDir="%{ironruby}" Solutions/Ruby.sln')
+        self.sh(
+            'xbuild /p:Configuration=Release /p:OutDir="%{ironpython}" Solutions/IronPython.Mono.sln')
+
+    def install_ruby_scripts(self, path, installdir):
+        for cmd, ext in map(os.path.splitext, os.listdir(path)):
+            if ext != '.exe':
+                continue
+            wrapper = os.path.join(self.staged_prefix, "bin", cmd)
+            with open(wrapper, "w") as output:
+                output.write("#!/bin/sh\n")
+                output.write(
+                    "exec {0}/bin/mono {0}/lib/{1}/{2}.exe \"$@\"\n".format(
+                        self.staged_prefix, installdir, cmd))
+            os.chmod(wrapper, 0o755)
+
+    def install_python_scripts(self, path, installdir):
+        for cmd, ext in map(os.path.splitext, os.listdir(path)):
+            if ext != '.exe':
+                continue
+            wrapper = os.path.join(self.staged_prefix, "bin", cmd)
+            with open(wrapper, "w") as output:
+                output.write("#!/bin/sh\n")
+                output.write(
+                    'export IRONPYTHONPATH=/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/\n')
+                output.write(
+                    "exec {0}/bin/mono {0}/lib/{1}/{2}.exe \"$@\"\n".format(
+                        self.staged_prefix, installdir, cmd))
+            os.chmod(wrapper, 0o755)
+
+    def install(self):
+        self.sh("mkdir -p %{staged_prefix}/lib/ironruby/")
+        self.sh("mkdir -p %{staged_prefix}/bin/")
+        self.sh("cp -R %{ironruby} %{staged_prefix}/lib/ironruby/")
+        self.install_ruby_scripts(self.ironruby, 'ironruby')
+
+        self.sh("mkdir -p %{staged_prefix}/lib/ironpython/")
+        self.sh("cp -R %{ironpython} %{staged_prefix}/lib/ironpython/")
+        self.install_python_scripts(self.ironpython, 'ironpython')
+
+IronLanguagesPackage()
diff --git a/bockbuild/mac-sdk/libcroco.py b/bockbuild/mac-sdk/libcroco.py
new file mode 100644 (file)
index 0000000..45ff45c
--- /dev/null
@@ -0,0 +1,6 @@
+GnomeXzPackage('libcroco', version_major='0.6', version_minor='8',
+               configure_flags=[
+                   '--host=i386-apple-darwin',
+                   '--disable-Bsymbolic',
+                   '--enable-gtk-doc-html=no'
+               ])
diff --git a/bockbuild/mac-sdk/libffi.py b/bockbuild/mac-sdk/libffi.py
new file mode 100644 (file)
index 0000000..1aecc54
--- /dev/null
@@ -0,0 +1,7 @@
+class LibFfiPackage (Package):
+
+    def __init__(self):
+        Package.__init__(self, 'libffi', '3.0.13', sources=[
+            'ftp://sourceware.org/pub/%{name}/%{name}-%{version}.tar.gz'])
+
+LibFfiPackage()
diff --git a/bockbuild/mac-sdk/libgdiplus.py b/bockbuild/mac-sdk/libgdiplus.py
new file mode 100644 (file)
index 0000000..e40baac
--- /dev/null
@@ -0,0 +1,8 @@
+GitHubTarballPackage(
+    'mono',
+    'libgdiplus',
+    '2.11',
+    '4e7ab0f555a13a6b2f954c714c4ee5213954ff79',
+    configure='CFLAGS="%{gcc_flags} %{local_gcc_flags} -I/opt/X11/include" ./autogen.sh --prefix="%{package_prefix}"',
+    override_properties={
+        'make': 'C_INCLUDE_PATH="" make'})
diff --git a/bockbuild/mac-sdk/libgif.py b/bockbuild/mac-sdk/libgif.py
new file mode 100644 (file)
index 0000000..0ae053c
--- /dev/null
@@ -0,0 +1 @@
+SourceForgePackage('giflib', 'giflib', '4.1.6')
diff --git a/bockbuild/mac-sdk/libglade.py b/bockbuild/mac-sdk/libglade.py
new file mode 100644 (file)
index 0000000..7553ebf
--- /dev/null
@@ -0,0 +1 @@
+GnomePackage('libglade', '2.6', '4')
diff --git a/bockbuild/mac-sdk/libjpeg.py b/bockbuild/mac-sdk/libjpeg.py
new file mode 100644 (file)
index 0000000..5fd850f
--- /dev/null
@@ -0,0 +1,8 @@
+class LibJpegPackage (Package):
+
+    def __init__(self):
+        Package.__init__(self, 'libjpeg', '8', sources=[
+                         'http://www.ijg.org/files/jpegsrc.v8.tar.gz'])
+        self.source_dir_name = 'jpeg-8'
+
+LibJpegPackage()
diff --git a/bockbuild/mac-sdk/libpng.py b/bockbuild/mac-sdk/libpng.py
new file mode 100644 (file)
index 0000000..5224e58
--- /dev/null
@@ -0,0 +1,9 @@
+class LibPngPackage (Package):
+
+    def __init__(self):
+        Package.__init__(self, 'libpng', '1.4.12',
+                         sources=[
+                             'http://downloads.sourceforge.net/project/libpng/libpng14/older-releases/1.4.12/libpng-1.4.12.tar.xz'],
+                         configure_flags=['--enable-shared'])
+
+LibPngPackage()
diff --git a/bockbuild/mac-sdk/librsvg.py b/bockbuild/mac-sdk/librsvg.py
new file mode 100644 (file)
index 0000000..a45c7f6
--- /dev/null
@@ -0,0 +1,27 @@
+class LibrsvgPackage(GnomeXzPackage):
+
+    def __init__(self):
+        GnomeXzPackage.__init__(self, 'librsvg', version_major='2.37', version_minor='0',
+                                configure_flags=['--disable-Bsymbolic', '--disable-introspection'])
+
+        make = 'make DESTDIR=%{stage_root}'
+
+    def install(self):
+        # handle some mislocation
+        misdir = '%s%s' % (self.stage_root, self.staged_profile)
+        unprotect_dir(self.stage_root)
+
+        Package.install(self)
+        # scoop up
+        if not os.path.exists(misdir):
+            error('Could not find mislocated libsrvg files')
+
+        self.sh(
+            'rsync -a --ignore-existing %s/* %s' %
+            (misdir, self.staged_prefix))
+        self.sh('rm -rf %s/*' % misdir)
+
+    def deploy(self):
+        self.sh('gdk-pixbuf-query-loaders --update-cache')
+
+LibrsvgPackage()
diff --git a/bockbuild/mac-sdk/libtiff.py b/bockbuild/mac-sdk/libtiff.py
new file mode 100644 (file)
index 0000000..844c5c3
--- /dev/null
@@ -0,0 +1,26 @@
+class LibTiffPackage (Package):
+
+    def __init__(self):
+        Package.__init__(self, 'tiff', '4.0.3',
+                         configure_flags=[
+                         ],
+                         sources=[
+                             'http://download.osgeo.org/libtiff/tiff-%{version}.tar.gz',
+                         ])
+
+        self.needs_lipo = True
+
+        if Package.profile.name == 'darwin':
+            self.sources.extend([
+                # Fix Snow Leopard build
+                # http://jira.freeswitch.org/secure/attachment/17487/tiff-4.0.2-macosx-2.patch
+                'patches/tiff-4.0.2-macosx-2.patch'
+            ])
+
+    def prep(self):
+        Package.prep(self)
+        if Package.profile.name == 'darwin':
+            for p in range(1, len(self.local_sources)):
+                self.sh('patch -p1 < "%{local_sources[' + str(p) + ']}"')
+
+LibTiffPackage()
diff --git a/bockbuild/mac-sdk/libxml2.py b/bockbuild/mac-sdk/libxml2.py
new file mode 100644 (file)
index 0000000..fb45650
--- /dev/null
@@ -0,0 +1,19 @@
+class LibXmlPackage (Package):
+
+    def __init__(self):
+        Package.__init__(self,
+                         'libxml2',
+                         '2.9.1',
+                         configure_flags=['--with-python=no'],
+                         sources=[
+                             'ftp://xmlsoft.org/%{name}/%{name}-%{version}.tar.gz',
+                         ]
+                         )
+
+    def prep(self):
+        Package.prep(self)
+        if Package.profile.name == 'darwin':
+            for p in range(1, len(self.local_sources)):
+                self.sh('patch -p1 < "%{local_sources[' + str(p) + ']}"')
+
+LibXmlPackage()
diff --git a/bockbuild/mac-sdk/mono-basic.py b/bockbuild/mac-sdk/mono-basic.py
new file mode 100644 (file)
index 0000000..ffdbde0
--- /dev/null
@@ -0,0 +1,12 @@
+
+class MonoBasicPackage (GitHubTarballPackage):
+
+    def __init__(self):
+        GitHubTarballPackage.__init__(self, 'mono', 'mono-basic', '4.6', 'c93133db1d511f994918391f429fee29b9250004',
+                                      configure='./configure --prefix="%{staged_profile}"')
+
+    def install(self):
+        self.sh('./configure --prefix="%{staged_prefix}"')
+        self.sh('make install')
+
+MonoBasicPackage()
diff --git a/bockbuild/mac-sdk/mono-llvm.py b/bockbuild/mac-sdk/mono-llvm.py
new file mode 100644 (file)
index 0000000..cf9e89b
--- /dev/null
@@ -0,0 +1,35 @@
+import os
+
+
+class MonoLlvmPackage (GitHubPackage):
+
+    def __init__(self):
+        GitHubPackage.__init__(self, 'mono', 'llvm', '3.0',
+                               revision='8b1520c8aae53e219cf80cdc0f02ad96600887d6',
+                               configure_flags=[
+                                   '--enable-optimized',
+                                   '--enable-assertions=no',
+                                   '--enable-targets="x86,x86_64"']
+                               )
+
+        # This package would like to be lipoed.
+        self.needs_lipo = True
+
+        # TODO: find out which flags are causing issues. reset ld_flags for the
+        # package
+        self.ld_flags = []
+        self.cpp_flags = []
+
+    def arch_build(self, arch):
+        if arch == 'darwin-64':  # 64-bit  build pass
+            self.local_configure_flags = ['--build=x86_64-apple-darwin11.2.0']
+
+        if arch == 'darwin-32':
+            self.local_configure_flags = ['--build=i386-apple-darwin11.2.0']
+
+        # LLVM says that libstdc++4.6 is broken and we should use libstdc++4.7.
+        # This switches it to the right libstdc++.
+        if Package.profile.name == 'darwin':
+            self.local_configure_flags.extend(['--enable-libcpp=yes'])
+
+MonoLlvmPackage()
diff --git a/bockbuild/mac-sdk/mono.py b/bockbuild/mac-sdk/mono.py
new file mode 100644 (file)
index 0000000..8227a33
--- /dev/null
@@ -0,0 +1,114 @@
+import os
+import re
+
+from bockbuild.package import Package
+from bockbuild.util.util import *
+
+
+class MonoMasterPackage(Package):
+
+    def __init__(self):
+        Package.__init__(self, 'mono', None,
+                         sources=[
+                             Package.profile.git_root],
+                         git_branch=os.getenv('MONO_BRANCH') or None,
+                         revision=os.getenv('MONO_BUILD_REVISION'),
+                         configure_flags=[
+                             '--enable-nls=no',
+                             '--with-ikvm=yes'
+                         ]
+                         )
+        self.source_dir_name = 'mono'
+        # This package would like to be lipoed.
+        self.needs_lipo = True
+
+        # Don't clean the workspace, so we can run 'make check' afterwards
+        self.dont_clean = True
+
+        if Package.profile.name == 'darwin':
+            self.configure_flags.extend([
+                '--with-libgdiplus=%s/lib/libgdiplus.dylib' % Package.profile.staged_prefix,
+                '--enable-loadedllvm',
+                'CXXFLAGS=-stdlib=libc++'
+            ])
+
+            self.sources.extend([
+                # Fixes up pkg-config usage on the Mac
+                'patches/mcs-pkgconfig.patch'
+            ])
+        else:
+            self.configure_flags.extend([
+                '--with-libgdiplus=%s/lib/libgdiplus.so' % Package.profile.staged_prefix
+            ])
+
+        self.gcc_flags.extend(['-O2'])
+
+        self.configure = './autogen.sh --prefix="%{package_prefix}"'
+
+        self.extra_stage_files = ['etc/mono/config']
+
+    def build(self):
+        self.make = '%s EXTERNAL_MCS=%s EXTERNAL_RUNTIME=%s' % (
+            self.make, self.profile.env.system_mcs, self.profile.env.system_mono)
+        Package.build(self)
+
+    def prep(self):
+        Package.prep(self)
+        for p in range(1, len(self.local_sources)):
+            self.sh('patch -p1 < "%{local_sources[' + str(p) + ']}"')
+
+    def arch_build(self, arch):
+        if arch == 'darwin-64':  # 64-bit build pass
+            self.local_gcc_flags = ['-m64']
+            self.local_configure_flags = ['--build=x86_64-apple-darwin11.2.0']
+
+        if arch == 'darwin-32':  # 32-bit build pass
+            self.local_gcc_flags = ['-m32']
+            self.local_configure_flags = ['--build=i386-apple-darwin11.2.0']
+
+        self.local_configure_flags.extend(
+            ['--cache-file=%s/%s-%s.cache' % (self.profile.build_root, self.name, arch)])
+
+    def install(self):
+        Package.install(self)
+
+        registry_dir = os.path.join(
+            self.staged_prefix,
+            "etc",
+            "mono",
+            "registry",
+            "LocalMachine")
+        ensure_dir(registry_dir)
+
+        # Add ImportBefore/ImportAfter files from xbuild to the msbuild
+        # directories
+        xbuild_dir = os.path.join(self.staged_prefix, 'lib/mono/xbuild')
+        new_xbuild_tv_dir = os.path.join(xbuild_dir, self.version)
+        os.makedirs(new_xbuild_tv_dir)
+
+        self.sh('cp -R %s/14.0/Imports %s' % (xbuild_dir, new_xbuild_tv_dir))
+        self.sh(
+            'cp -R %s/14.0/Microsoft.Common.targets %s' %
+            (xbuild_dir, new_xbuild_tv_dir))
+
+    def deploy(self):
+        if self.profile.arch == 'darwin-universal':
+            os.symlink('mono-sgen64', '%s/bin/mono64' % self.staged_profile)
+            os.symlink('mono-sgen32', '%s/bin/mono32' % self.staged_profile)
+
+        text = " ".join(open('%s/bin/mcs' % self.staged_profile).readlines())
+        regex = os.path.join(
+            self.profile.MONO_ROOT,
+            "Versions",
+            r"(\d+\.\d+\.\d+)")
+        match = re.search(regex, text)
+        if match is None:
+            return
+        token = match.group(1)
+
+        trace(token)
+        trace(self.package_prefix)
+        if self.package_prefix not in match:
+            error("%s references Mono %s\n%s" % ('mcs', match, text))
+
+MonoMasterPackage()
diff --git a/bockbuild/mac-sdk/msbuild.py b/bockbuild/mac-sdk/msbuild.py
new file mode 100644 (file)
index 0000000..0e16af1
--- /dev/null
@@ -0,0 +1,44 @@
+import fileinput
+
+
+class MSBuild (GitHubPackage):
+
+    def __init__(self):
+        GitHubPackage.__init__(self, 'mono', 'msbuild', '15.0',
+                               git_branch='xplat-c8p')
+
+    def build(self):
+        self.sh('./cibuild.sh --scope Compile --target Mono --host Mono')
+
+    def install(self):
+        # adjusted from 'install-mono-prefix.sh'
+
+        build_output = 'bin/Debug-MONO/OSX_Deployment'
+        new_location = os.path.join(
+            self.staged_prefix,
+            'lib/mono/msbuild/%s/bin' %
+            self.version)
+        bindir = os.path.join(self.staged_prefix, 'bin')
+
+        os.makedirs(new_location)
+        self.sh('cp -R %s/* %s' % (build_output, new_location))
+
+        os.makedirs(bindir)
+
+        self.sh('cp msbuild-mono-deploy.in %s/msbuild' % bindir)
+
+        for line in fileinput.input('%s/msbuild' % bindir, inplace=True):
+            line = line.replace('@bindir@', '%s/bin' % self.staged_prefix)
+            line = line.replace(
+                '@mono_instdir@',
+                '%s/lib/mono' %
+                self.staged_prefix)
+            print line
+
+        for excluded in glob.glob("%s/*UnitTests*" % new_location):
+            self.rm(excluded)
+
+        for excluded in glob.glob("%s/*xunit*" % new_location):
+            self.rm(excluded)
+
+MSBuild()
diff --git a/bockbuild/mac-sdk/murrine.py b/bockbuild/mac-sdk/murrine.py
new file mode 100644 (file)
index 0000000..5c84ff4
--- /dev/null
@@ -0,0 +1,15 @@
+class MurrinePackage (GnomeXzPackage):
+
+    def __init__(self):
+        GnomePackage.__init__(self,
+                              'murrine',
+                              version_major='0.98',
+                              version_minor='2')
+
+        # FIXME: this may need porting
+        # self.sources.append ('patches/murrine-osx.patch')
+
+    def prep(self):
+        Package.prep(self)
+
+MurrinePackage()
diff --git a/bockbuild/mac-sdk/nuget.py b/bockbuild/mac-sdk/nuget.py
new file mode 100644 (file)
index 0000000..321bedf
--- /dev/null
@@ -0,0 +1,18 @@
+
+class NuGetPackage(GitHubPackage):
+
+    def __init__(self):
+        GitHubPackage.__init__(self,
+                               'mono', 'nuget',
+                               '2.12.0',
+                               '9e2d2c1cc09d2a40eeb72e8c5db789e3b9bf2586',
+                               configure='')
+
+    def build(self):
+        self.sh('%{make} update_submodules')
+        self.sh('%{make} PREFIX=%{package_prefix}')
+
+    def install(self):
+        self.sh('%{makeinstall} PREFIX=%{staged_prefix}')
+
+NuGetPackage()
diff --git a/bockbuild/mac-sdk/packaging/Info.plist b/bockbuild/mac-sdk/packaging/Info.plist
new file mode 100644 (file)
index 0000000..8c3799d
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+        <key>CFBundleGetInfoString</key>
+        <string>@@MONO_VERSION_RELEASE@@</string>
+        <key>CFBundleIdentifier</key>
+        <string>com.ximian.mono-@@MONO_VERSION@@</string>
+        <key>CFBundleName</key>
+        <string>Mono.framework</string>
+        <key>CFBundleShortVersionString</key>
+        <string>@@MONO_VERSION@@</string>
+        <key>IFPkgFlagAllowBackRev</key>
+        <true/>
+        <key>IFPkgFlagAuthorizationAction</key>
+        <string>AdminAuthorization</string>
+        <key>IFPkgFlagDefaultLocation</key>
+        <string>/</string>
+        <key>IFPkgFlagInstallFat</key>
+        <false/>
+        <key>IFPkgFlagIsRequired</key>
+        <false/>
+        <key>IFPkgFlagRelocatable</key>
+        <false/>
+        <key>IFPkgFlagRestartAction</key>
+        <string>NoRestart</string>
+        <key>IFPkgFlagRootVolumeOnly</key>
+        <true/>
+        <key>IFPkgFlagUpdateInstalledLanguages</key>
+        <false/>
+        <key>IFPkgFormatVersion</key>
+        <real>0.10000000149011612</real>
+</dict>
+</plist>
diff --git a/bockbuild/mac-sdk/packaging/Info_sdk.plist b/bockbuild/mac-sdk/packaging/Info_sdk.plist
new file mode 100644 (file)
index 0000000..7d75b1a
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+        <key>CFBundleGetInfoString</key>
+        <string>@@MONO_VERSION_RELEASE@@</string>
+        <key>CFBundleIdentifier</key>
+        <string>com.ximian.mono-@@MONO_VERSION@@-csdk</string>
+        <key>CFBundleName</key>
+        <string>Mono.framework</string>
+        <key>CFBundleShortVersionString</key>
+        <string>@@MONO_VERSION@@</string>
+        <key>IFPkgFlagAllowBackRev</key>
+        <true/>
+        <key>IFPkgFlagAuthorizationAction</key>
+        <string>AdminAuthorization</string>
+        <key>IFPkgFlagDefaultLocation</key>
+        <string>/</string>
+        <key>IFPkgFlagInstallFat</key>
+        <false/>
+        <key>IFPkgFlagIsRequired</key>
+        <false/>
+        <key>IFPkgFlagRelocatable</key>
+        <false/>
+        <key>IFPkgFlagRestartAction</key>
+        <string>NoRestart</string>
+        <key>IFPkgFlagRootVolumeOnly</key>
+        <true/>
+        <key>IFPkgFlagUpdateInstalledLanguages</key>
+        <false/>
+        <key>IFPkgFormatVersion</key>
+        <real>0.10000000149011612</real>
+</dict>
+</plist>
diff --git a/bockbuild/mac-sdk/packaging/mdk_blacklist.sh b/bockbuild/mac-sdk/packaging/mdk_blacklist.sh
new file mode 100755 (executable)
index 0000000..ab426a7
--- /dev/null
@@ -0,0 +1,135 @@
+#!/bin/bash
+
+if test x$1 = x; then
+   echo usage is cleanup MONODIR
+   exit 1
+fi
+
+MONODIR=$1
+
+cd $MONODIR
+rm -rf lib/gtk-2.0/2.10.0/engines/libcrux-engine.so
+rm -rf lib/gtk-2.0/2.10.0/engines/libglide.so
+rm -rf lib/gtk-2.0/2.10.0/engines/libhcengine.so
+rm -rf lib/gtk-2.0/2.10.0/engines/libindustrial.so
+rm -rf lib/gtk-2.0/2.10.0/engines/libmist.so
+rm -rf lib/gtk-2.0/2.10.0/engines/libpixmap.so
+rm -rf lib/gtk-2.0/2.10.0/engines/libredmond95.so
+rm -rf lib/gtk-2.0/2.10.0/engines/libthinice.so
+rm -rf gtk-2.0/modules/libferret.*
+rm -rf gtk-2.0/modules/libgail.*
+rm -rf share/gtk-2.0/demo/*
+rm -rf share/man/man1/oldmono.1
+rm -rf share/themes/Crux
+rm -rf share/themes/Default
+rm -rf share/themes/Emacs
+rm -rf share/themes/Industrial
+rm -rf share/themes/Mist
+rm -rf share/themes/Raleigh
+rm -rf share/themes/Redmond
+rm -rf share/themes/ThinIce
+rm -rf share/info
+rm -rf share/icons/gnome
+rm -rf share/icons/hicolor
+rm -rf share/gtk-doc
+rm -rf share/gettext/*.class
+rm -rf share/doc
+rm -rf share/emacs
+rm -rf share/strings
+rm -rf share/pixmaps
+rm -rf share/intltool
+rm -rf var/cache/fontconfig
+
+# delete most of the *.a files
+rm -rf lib/cairo/libcairo-trace.a
+rm -rf lib/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-svg.a
+rm -rf lib/gtk-2.0/2.10.0/engines/libsvg.a
+rm -rf lib/libCompilerDriver.a
+rm -rf lib/libEnhancedDisassembly.a
+rm -rf lib/libLLVMAnalysis.a
+rm -rf lib/libLLVMArchive.a
+rm -rf lib/libLLVMAsmParser.a
+rm -rf lib/libLLVMAsmPrinter.a
+rm -rf lib/libLLVMBitReader.a
+rm -rf lib/libLLVMBitWriter.a
+rm -rf lib/libLLVMCodeGen.a
+rm -rf lib/libLLVMCore.a
+rm -rf lib/libLLVMExecutionEngine.a
+rm -rf lib/libLLVMInstCombine.a
+rm -rf lib/libLLVMInstrumentation.a
+rm -rf lib/libLLVMInterpreter.a
+rm -rf lib/libLLVMJIT.a
+rm -rf lib/libLLVMLinker.a
+rm -rf lib/libLLVMMC.a
+rm -rf lib/libLLVMMCDisassembler.a
+rm -rf lib/libLLVMMCJIT.a
+rm -rf lib/libLLVMMCParser.a
+rm -rf lib/libLLVMObject.a
+rm -rf lib/libLLVMScalarOpts.a
+rm -rf lib/libLLVMSelectionDAG.a
+rm -rf lib/libLLVMSupport.a
+rm -rf lib/libLLVMTarget.a
+rm -rf lib/libLLVMTransformUtils.a
+rm -rf lib/libLLVMX86AsmParser.a
+rm -rf lib/libLLVMX86AsmPrinter.a
+rm -rf lib/libLLVMX86CodeGen.a
+rm -rf lib/libLLVMX86Disassembler.a
+rm -rf lib/libLLVMX86Info.a
+rm -rf lib/libLLVMipa.a
+rm -rf lib/libLLVMipo.a
+rm -rf lib/libLTO.a
+# rm -rf lib/libMonoPosixHelper.a
+# rm -rf lib/libMonoSupportW.a
+rm -rf lib/libUnitTestMain.a
+rm -rf lib/libatksharpglue-2.a
+rm -rf lib/libcairo-gobject.a
+rm -rf lib/libcairo-script-interpreter.a
+rm -rf lib/libcairo.a
+rm -rf lib/libcroco-0.6.a
+rm -rf lib/libexpat.a
+rm -rf lib/libffi.a
+rm -rf lib/libfontconfig.a
+rm -rf lib/libfreetype.a
+rm -rf lib/libgdiplus.a
+rm -rf lib/libgdksharpglue-2.a
+rm -rf lib/libgettextpo.a
+rm -rf lib/libgif.a
+rm -rf lib/libglade-2.0.a
+rm -rf lib/libgladesharpglue-2.a
+rm -rf lib/libglibsharpglue-2.a
+rm -rf lib/libgtksharpglue-2.a
+rm -rf lib/libikvm-native.a
+rm -rf lib/libintl.a
+rm -rf lib/libjpeg.a
+rm -rf lib/liblzma.a
+# rm -rf lib/libmono-2.0.a
+# rm -rf lib/libmono-llvm.a
+# rm -rf lib/libmono-profiler-aot.a
+# rm -rf lib/libmono-profiler-cov.a
+# rm -rf lib/libmono-profiler-iomap.a
+# rm -rf lib/libmono-profiler-log.a
+# rm -rf lib/libmonosgen-2.0.a
+rm -rf lib/libpangosharpglue-2.a
+rm -rf lib/libpixman-1.a
+rm -rf lib/libpng.a
+rm -rf lib/libpng14.a
+rm -rf lib/librsvg-2.a
+rm -rf lib/libsqlite3.a
+rm -rf lib/libtiff.a
+rm -rf lib/libtiffxx.a
+rm -rf lib/libxml2.a
+
+# we don't need any of the llvm executables except llc and opt
+rm -rf bin/bugpoint
+rm -rf bin/lli
+rm -rf bin/llvm-*
+rm -rf bin/macho-dump
+rm -rf bin/ccache
+
+#
+# 14:39 <baulig> the install script needs to be modified not to
+#                install .mdb's for these
+# 14:39 <baulig> System.Windows.dll, System.Xml.Serialization.dll and
+#                everything in Facades
+
+find ./lib/mono/4.5/Facades -name "*.mdb" -delete
diff --git a/bockbuild/mac-sdk/packaging/resources/License.rtf b/bockbuild/mac-sdk/packaging/resources/License.rtf
new file mode 100644 (file)
index 0000000..ab13fe4
--- /dev/null
@@ -0,0 +1,26 @@
+{\rtf1\mac\ansicpg10000\cocoartf102
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\margl1440\margr1440\vieww9000\viewh9000\viewkind0
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
+
+\f0\fs24 \cf0 The software included in the package is licensed under several different agreements.\
+\
+MIT License:\
+\
+http://www.opensource.org/licenses/mit-license.php\
+\
+LGPL:\
+\
+http://www.opensource.org/licenses/lgpl-2.1.php\
+\
+GPL:\
+\
+http://www.opensource.org/licenses/gpl-2.0.php\
+\
+You can develop commercial applications and redistribute the code in this package.
+You only need to obtain a commercial license if you wish to make changes to Mono or
+if you are using Mono as an embedded runtime into your application.\
+\
+Contact contact@xamarin.com if you think you need a license.
+}
diff --git a/bockbuild/mac-sdk/packaging/resources/ReadMe.rtf b/bockbuild/mac-sdk/packaging/resources/ReadMe.rtf
new file mode 100644 (file)
index 0000000..704571f
--- /dev/null
@@ -0,0 +1,41 @@
+{\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\margl1440\margr1440\vieww15940\viewh15760\viewkind0
+\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640
+
+\f0\fs24 \cf0 This README is for
+\b  Mono.framework @@MONO_VERSION_RELEASE@@
+\b0 .\
+\
+This is the Mono Runtime and Development Platform (http://www.mono-project.com/).\
+\
+This package installs Mono and all of its dependencies inside of /Library/Frameworks/Mono.framework.  This behavior is likely to change with a future release so that dependancies will get their own frameworks.\
+\
+The following components are included inside Mono.framework:\
+@@PACKAGES@@\
+\
+Other packages used to build Mono.framework:\
+@@DEP_PACKAGES@@\
+If you want to build native Mac applications with Mono, you can use the MonoMac bindings, an add-on to this product available from http://www.mono-project.com/MonoMac\
+\
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720
+\cf0 \
+\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640
+\cf0 \
+\
+A simple uninstallMono.sh script is included in the disk image.  This is shell script that must be run as root, and it will remove the Mono.framework and the links in /usr/bin.\
+\
+This package was created by the Mono team.  Major contributors to this team include (in alphabetical order): \
+\
+Wade Berrier\
+Adhamh Findlay\
+Miguel de Icaza\
+Urs Muff\
+Geoff Norton\
+Andy Satori\
+\
+Questions or problems related directly to the Mono.framework should be addressed to mono-osx@lists.xamarin.com.\
+\
+Questions about Mono should be directed to an appropriate resource that can be found on http://www.mono-project.com/about. \
+}
\ No newline at end of file
diff --git a/bockbuild/mac-sdk/packaging/resources/Welcome.rtf b/bockbuild/mac-sdk/packaging/resources/Welcome.rtf
new file mode 100644 (file)
index 0000000..200bc99
--- /dev/null
@@ -0,0 +1,12 @@
+{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
+{\fonttbl\f0\fnil\fcharset0 HelveticaNeue;}
+{\colortbl;\red255\green255\blue255;}
+\margl1440\margr1440\vieww9000\viewh9000\viewkind0
+\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural
+
+\f0\fs32 \cf0 Welcome to
+\b Mono.framework @@MONO_VERSION_RELEASE@@
+\b0  for OS X.
+\fs36 \
+\
+}
\ No newline at end of file
diff --git a/bockbuild/mac-sdk/packaging/resources/distribution.xml b/bockbuild/mac-sdk/packaging/resources/distribution.xml
new file mode 100644 (file)
index 0000000..39926f9
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<installer-gui-script minSpecVersion="1">
+    <title>Mono Framework</title>
+    <license file="License.rtf" mime-type="application/rtf" />
+    <readme file="ReadMe.rtf" mime-type="application/rtf" />
+    <pkg-ref id="mono">
+        <bundle-version/>
+    </pkg-ref>
+    <choices-outline>
+        <line choice="default">
+            <line choice="mono"/>
+        </line>
+    </choices-outline>
+    <choice id="default"/>
+    <choice id="mono" visible="false">
+        <pkg-ref id="mono"/>
+    </choice>
+    <pkg-ref id="mono">#mono.pkg</pkg-ref>
+</installer-gui-script>
diff --git a/bockbuild/mac-sdk/packaging/resources/postinstall b/bockbuild/mac-sdk/packaging/resources/postinstall
new file mode 100755 (executable)
index 0000000..fe01a53
--- /dev/null
@@ -0,0 +1,106 @@
+#!/bin/sh -x
+
+FW=/Library/Frameworks/Mono.framework
+FW_CURRENT=${FW}/Versions/Current
+CURRENT=`basename $(readlink ${FW_CURRENT})`
+
+# Remove PCL assemblies that we installed from Mono 3.1.1
+LICENSE="Portable Class Library Reference Assemblies License-07JUN2013.docx"
+if [ -f "$FW/External/xbuild-frameworks/.NETPortable/$LICENSE" ]; then
+    echo "Removing PCL because we're upgrading from 3.1.1" >> /tmp/mono-installation
+    rm -rf $FW/External/xbuild-frameworks/.NETPortable
+fi
+
+# Remove /usr/local/bin/pkg-config if it's a symlink to the Mono-installed one
+PKG_CONFIG_LINK="/usr/local/bin/pkg-config"
+if [ -L $PKG_CONFIG_LINK ]; then
+    location=`readlink $PKG_CONFIG_LINK`
+    case "$location" in
+    *Mono.framework*) rm $PKG_CONFIG_LINK;;
+    esac
+fi
+
+WHITELIST=$(cat "$(dirname "$0")/whitelist.txt")
+MONO_COMMANDS_FILE=/etc/paths.d/mono-commands
+FW_WHITELISTED_COMMANDS=${FW_CURRENT}/Commands
+
+mkdir ${FW_WHITELISTED_COMMANDS}
+
+if test -e ${MONO_COMMANDS_FILE}; then
+    rm "${MONO_COMMANDS_FILE}"
+fi
+
+echo "${FW_WHITELISTED_COMMANDS}" >> "${MONO_COMMANDS_FILE}"
+
+if [ -d "${FW}"/Commands ]; then
+    for i in ${WHITELIST}; do
+        if test -e "${FW}/Commands/${i}"; then
+            ln -s "${FW}/Commands/${i}" "${FW_WHITELISTED_COMMANDS}/${i}"
+        fi
+    done;
+else
+    echo "${FW}/Commands does not exist"
+    echo "Can not add command links to $PATH."
+fi
+
+if [ -d ${FW_CURRENT} ]; then
+    cd ${FW_CURRENT}/share/man
+    for i in ${WHITELIST}; do
+        for j in $(ls man*/${i}.*); do
+            if test ! -e "/usr/local/share/man/${j}"; then
+                ln -sf "${FW_CURRENT}/share/man/${j}" "/usr/local/share/man/${j}"
+            fi
+        done
+    done
+
+    cd ${FW_CURRENT}/etc
+    # Make sure we run the files we lay down, and not other stuff installed on the system
+    export PATH=${FW_CURRENT}/bin:$PATH
+    # gtk+ setup
+    gdk-pixbuf-query-loaders --update-cache
+    # pango setup
+    mkdir -p pango
+    pango-querymodules >  pango/pango.modules
+    pango-querymodules --update-cache
+    fc-cache
+
+    cd ${FW_CURRENT}/lib/gtk-2.0/2.10.0
+    gtk-query-immodules-2.0 > immodules.cache
+fi
+
+# Delete older Monos
+#
+# - keep if the major version is different
+# - keep if 'Versions/x.y.z/keep' exists
+# - Keep if it is greater than $CURRENT
+#
+echo "Current:" $CURRENT >> /tmp/mono-installation
+
+pushd ${FW}/Versions
+for i in `ls -d *`; do
+    result=`echo "${i:0:1} == ${CURRENT:0:1}" | bc`
+    if [ $result -ne 1 ]; then
+        echo "keeping" $i "because it has a different major version" >> /tmp/mono-installation
+        continue
+    fi
+
+    if [ -f $i/keep ]; then
+        echo "Keeping" $i "because of keep file" >> /tmp/mono-installation
+        continue
+    fi
+
+    # A magical bit of Perl: http://stackoverflow.com/a/7366753/494990
+    result=$(perl -e '($a,$b)=@ARGV; for ($a,$b) {s/(\d+)/sprintf "%5d", $1/ge}; print $a cmp $b;' $i $CURRENT)
+    if [ $result -ge 0 ]; then
+        echo "Skipping" $i "because $i >= $CURRENT" >> /tmp/mono-installation
+        continue
+
+    else
+        echo "rm -rf" $i >> /tmp/mono-installation
+        rm -rf $i
+    fi
+done
+popd
+
+# Mono framework should be owned by root
+chown -R root:admin ${FW}
diff --git a/bockbuild/mac-sdk/packaging/resources/version.plist b/bockbuild/mac-sdk/packaging/resources/version.plist
new file mode 100644 (file)
index 0000000..df2e67c
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+        <key>BuildVersion</key>
+        <string>@@MONO_VERSION_RELEASE@@</string>
+        <key>CFBundleShortVersionString</key>
+        <string>@@MONO_VERSION_RELEASE@@</string>
+        <key>CFBundleVersion</key>
+        <string>@@MONO_VERSION_RELEASE@@</string>
+        <key>ProjectName</key>
+        <string>Mono</string>
+        <key>SourceVersion</key>
+        <string>@@MONO_VERSION_RELEASE@@</string>
+</dict>
+</plist>
diff --git a/bockbuild/mac-sdk/packaging/resources/whitelist.txt b/bockbuild/mac-sdk/packaging/resources/whitelist.txt
new file mode 100644 (file)
index 0000000..7d329a9
--- /dev/null
@@ -0,0 +1,129 @@
+al
+al2
+asp-state
+asp-state2
+asp-state4
+booc
+booi
+booish
+caspol
+ccrewrite
+cccheck
+cert2spc
+certmgr
+chktrust
+ClassInitGenerator
+csharp
+csharp2
+dbsessmgr
+dbsessmgr2
+dbsessmgr4
+disco
+dmcs
+dtd2rng
+dtd2xsd
+fastcgi-mono-server
+fastcgi-mono-server2
+fastcgi-mono-server4
+fsharpc
+fsharpc2
+fsharpi
+fsharpi2
+gacutil
+gacutil2
+gapi2-codegen
+gapi2-fixup
+gapi2-parser
+genxs
+gmcs
+httpcfg
+ikdasm
+ilasm
+installvst
+ipy
+ipy64
+ipyw
+ipyw64
+ir
+ir64
+IronRuby.Tests
+irw
+irw64
+lc
+macpack
+makecert
+mautil
+mconfig
+mcs
+mdassembler
+mdoc
+mdoc-assemble
+mdoc-export-html
+mdoc-export-msxdoc
+mdoc-update
+mdoc-validate
+mdvalidater
+mkbundle
+mod
+mod-mono-server
+mod-mono-server2
+mod-mono-server4
+mono
+mono64
+mono-boehm
+mono-api-info
+mono-api-html
+mono-cil-strip
+mono-configuration-crypto
+monodis
+monodocer
+monodocs2html
+monodocs2slashdoc
+mono-find-provides
+mono-find-requires
+mono-gdb.py
+monograph
+mono-heapviz
+monolinker
+monop
+monop2
+mono-service
+mono-service2
+mono-sgen
+mono-shlib-cop
+mono-symbolicate
+mono-test-install
+mono-xmltool
+mozroots
+mprof-report
+msbuild
+nant
+nuget
+nunit-console
+nunit-console2
+nunit-console4
+pdb2mdb
+pedump
+permview
+peverify
+prj2make
+resgen
+resgen2
+secutil
+setreg
+sgen
+signcode
+sn
+soapsuds
+sqlmetal
+sqlsharp
+svcutil
+vbnc
+vbnc2
+wsdl
+wsdl2
+xbuild
+xsd
+xsp
+xsp2
+xsp4
diff --git a/bockbuild/mac-sdk/packaging/uninstallMono.sh b/bockbuild/mac-sdk/packaging/uninstallMono.sh
new file mode 100755 (executable)
index 0000000..9e88ad1
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh -x
+
+#This script removes Mono from an OS X System.  It must be run as root
+
+rm -r /Library/Frameworks/Mono.framework
+
+# In 10.6+ the receipts are stored here
+rm /var/db/receipts/com.ximian.mono*
+
+for dir in /usr/local/bin; do
+   (cd ${dir};
+    for i in `ls -al | grep /Library/Frameworks/Mono.framework/ | awk '{print $9}'`; do
+      rm ${i}
+    done);
+done
diff --git a/bockbuild/mac-sdk/pango.py b/bockbuild/mac-sdk/pango.py
new file mode 100644 (file)
index 0000000..0691078
--- /dev/null
@@ -0,0 +1,51 @@
+class PangoPackage (GnomeXzPackage):
+
+    def __init__(self):
+        GnomePackage.__init__(self,
+                              'pango',
+                              version_major='1.35',
+                              version_minor='0',
+                              configure_flags=[
+                                  '--without-x',
+                                  '--enable-gtk-doc-html=no'
+                              ]
+                              )
+
+        self.sources.extend([
+            # 1
+            # Bug 321419 - Allow environment var substitution in Pango config
+            # https://bugzilla.gnome.org/show_bug.cgi?id=321419
+            'patches/pango-relative-config-file.patch',
+
+            # BXC 10257 - Characters outside the Basic Multilingual Plane don't render correctly
+            # https://bugzilla.xamarin.com/show_bug.cgi?id=10257
+            'patches/pango-coretext-astral-plane-1.patch',
+            'patches/pango-coretext-astral-plane-2.patch',
+
+            # Bug 15787 - Caret position is wrong when there are ligatures
+            # https://bugzilla.xamarin.com/show_bug.cgi?id=15787
+            'patches/pango-disable-ligatures.patch',
+
+            # https://bugzilla.xamarin.com/show_bug.cgi?id=22199
+            'patches/pango-fix-ct_font_descriptor_get_weight-crasher.patch',
+
+            # https://bugzilla.gnome.org/show_bug.cgi?id=734372
+            'patches/pango-coretext-condensed-trait.patch',
+
+            # https://bugzilla.xamarin.com/show_bug.cgi?id=32938
+            'patches/pango-coretext-fix-yosemite-crasher.patch',
+
+            'patches/pango-system-font-single.patch',
+            'patches/pango-system-font-check-version.patch'
+        ])
+
+    def prep(self):
+        GnomePackage.prep(self)
+        if Package.profile.name == 'darwin':
+            for p in range(1, len(self.local_sources)):
+                self.sh('patch -p1 < "%{local_sources[' + str(p) + ']}"')
+
+    def deploy(self):
+        self.sh('pango-querymodules --update-cache')
+
+PangoPackage()
diff --git a/bockbuild/mac-sdk/patches/cairo-cglayer.patch b/bockbuild/mac-sdk/patches/cairo-cglayer.patch
new file mode 100644 (file)
index 0000000..4965d60
--- /dev/null
@@ -0,0 +1,2187 @@
+--- a/src/cairo-quartz-font.c  2012-11-13 18:20:00.000000000 -0800
++++ b/src/cairo-quartz-font.c  2012-11-13 18:06:56.000000000 -0800
+@@ -90,8 +90,9 @@ static int (*CGFontGetAscentPtr) (CGFont
+ static int (*CGFontGetDescentPtr) (CGFontRef fontRef) = NULL;
+ static int (*CGFontGetLeadingPtr) (CGFontRef fontRef) = NULL;
+
+-/* Not public anymore in 64-bits nor in 10.7 */
+-static ATSFontRef (*FMGetATSFontRefFromFontPtr) (FMFont iFont) = NULL;
++/* CTFontCreateWithGraphicsFont is not public until 10.5. */
++typedef const struct __CTFontDescriptor *CTFontDescriptorRef;
++static CTFontRef (*CTFontCreateWithGraphicsFontPtr) (CGFontRef, CGFloat, const CGAffineTransform *, CTFontDescriptorRef) = NULL;
+
+ static cairo_bool_t _cairo_quartz_font_symbol_lookup_done = FALSE;
+ static cairo_bool_t _cairo_quartz_font_symbols_present = FALSE;
+@@ -130,7 +131,7 @@ quartz_font_ensure_symbols(void)
+     CGContextGetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");
+     CGContextSetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing");
+
+-    FMGetATSFontRefFromFontPtr = dlsym(RTLD_DEFAULT, "FMGetATSFontRefFromFont");
++    CTFontCreateWithGraphicsFontPtr = dlsym(RTLD_DEFAULT, "CTFontCreateWithGraphicsFont");
+
+     if ((CGFontCreateWithFontNamePtr || CGFontCreateWithNamePtr) &&
+       CGFontGetGlyphBBoxesPtr &&
+@@ -155,6 +156,7 @@ struct _cairo_quartz_font_face {
+     cairo_font_face_t base;
+
+     CGFontRef cgFont;
++    CTFontRef ctFont;
+ };
+
+ /*
+@@ -239,6 +241,10 @@ _cairo_quartz_font_face_destroy (void *a
+ {
+     cairo_quartz_font_face_t *font_face = (cairo_quartz_font_face_t*) abstract_face;
+
++    if (font_face->ctFont) {
++        CFRelease (font_face->ctFont);
++    }
++
+     CGFontRelease (font_face->cgFont);
+ }
+
+@@ -363,6 +369,12 @@ cairo_quartz_font_face_create_for_cgfont
+
+     font_face->cgFont = CGFontRetain (font);
+
++    if (CTFontCreateWithGraphicsFontPtr) {
++        font_face->ctFont = CTFontCreateWithGraphicsFontPtr (font, 1.0, NULL, NULL);
++    } else {
++        font_face->ctFont = NULL;
++    }
++
+     _cairo_font_face_init (&font_face->base, &_cairo_quartz_font_face_backend);
+
+     return &font_face->base;
+@@ -782,49 +794,10 @@ _cairo_quartz_scaled_font_get_cg_font_re
+     return ffont->cgFont;
+ }
+
+-/*
+- * compat with old ATSUI backend
+- */
+-
+-/**
+- * cairo_quartz_font_face_create_for_atsu_font_id
+- * @font_id: an ATSUFontID for the font.
+- *
+- * Creates a new font for the Quartz font backend based on an
+- * #ATSUFontID. This font can then be used with
+- * cairo_set_font_face() or cairo_scaled_font_create().
+- *
+- * Return value: a newly created #cairo_font_face_t. Free with
+- *  cairo_font_face_destroy() when you are done using it.
+- *
+- * Since: 1.6
+- **/
+-cairo_font_face_t *
+-cairo_quartz_font_face_create_for_atsu_font_id (ATSUFontID font_id)
++CTFontRef
++_cairo_quartz_scaled_font_get_ct_font_ref (cairo_scaled_font_t *abstract_font)
+ {
+-    quartz_font_ensure_symbols();
+-
+-    if (FMGetATSFontRefFromFontPtr != NULL) {
+-      ATSFontRef atsFont = FMGetATSFontRefFromFontPtr (font_id);
+-      CGFontRef cgFont = CGFontCreateWithPlatformFont (&atsFont);
+-      cairo_font_face_t *ff;
+-
+-      ff = cairo_quartz_font_face_create_for_cgfont (cgFont);
+-
+-      CGFontRelease (cgFont);
+-
+-      return ff;
+-    } else {
+-      _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+-      return (cairo_font_face_t *)&_cairo_font_face_nil;
+-    }
+-}
+-
+-/* This is the old name for the above function, exported for compat purposes */
+-cairo_font_face_t *cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id);
++    cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(abstract_font);
+
+-cairo_font_face_t *
+-cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id)
+-{
+-    return cairo_quartz_font_face_create_for_atsu_font_id (font_id);
++    return ffont->ctFont;
+ }
+--- a/src/cairo-quartz-image-surface.c 2010-06-18 04:47:13.000000000 -0700
++++ b/src/cairo-quartz-image-surface.c 2012-11-13 18:06:56.000000000 -0800
+@@ -148,6 +148,8 @@ _cairo_quartz_image_surface_flush (void
+     surface->image = newImage;
+     CGImageRelease (oldImage);
+
++    surface->base.is_clear = surface->imageSurface->base.is_clear;
++
+     return CAIRO_STATUS_SUCCESS;
+ }
+
+@@ -270,6 +272,8 @@ cairo_quartz_image_surface_create (cairo
+     qisurf->image = image;
+     qisurf->imageSurface = image_surface;
+
++    qisurf->base.is_clear = image_surface->base.is_clear;
++
+     return &qisurf->base;
+ }
+
+--- a/src/cairo-quartz-private.h       2010-12-25 06:21:34.000000000 -0800
++++ b/src/cairo-quartz-private.h       2012-11-13 18:06:56.000000000 -0800
+@@ -50,6 +50,9 @@ typedef CGFloat cairo_quartz_float_t;
+ typedef float cairo_quartz_float_t;
+ #endif
+
++/* define CTFontRef for pre-10.5 SDKs */
++typedef const struct __CTFont *CTFontRef;
++
+ typedef struct cairo_quartz_surface {
+     cairo_surface_t base;
+
+@@ -60,21 +63,22 @@ typedef struct cairo_quartz_surface {
+     cairo_surface_t *imageSurfaceEquiv;
+
+     cairo_surface_clipper_t clipper;
+-    cairo_rectangle_int_t extents;
+
+-    /* These are stored while drawing operations are in place, set up
+-     * by quartz_setup_source() and quartz_finish_source()
++    /**
++     * If non-null, this is a CGImage representing the contents of the surface.
++     * We clear this out before any painting into the surface, so that we
++     * don't force a copy to be created.
+      */
+-    CGAffineTransform sourceTransform;
++    CGImageRef bitmapContextImage;
+
+-    CGImageRef sourceImage;
+-    cairo_surface_t *sourceImageSurface;
+-    CGRect sourceImageRect;
++    /**
++     * If non-null, this is the CGLayer for the surface.
++     */
++    CGLayerRef cgLayer;
+
+-    CGShadingRef sourceShading;
+-    CGPatternRef sourcePattern;
++    cairo_rectangle_int_t extents;
+
+-    CGInterpolationQuality oldInterpolationQuality;
++    cairo_bool_t ownsData;
+ } cairo_quartz_surface_t;
+
+ typedef struct cairo_quartz_image_surface {
+@@ -103,6 +107,9 @@ _cairo_quartz_create_cgimage (cairo_form
+ CGFontRef
+ _cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *sfont);
+
++CTFontRef
++_cairo_quartz_scaled_font_get_ct_font_ref (cairo_scaled_font_t *sfont);
++
+ #else
+
+ # error Cairo was not compiled with support for the quartz backend
+--- a/src/cairo-quartz-surface.c       2012-11-13 18:20:00.000000000 -0800
++++ b/src/cairo-quartz-surface.c       2012-11-13 18:06:56.000000000 -0800
+@@ -41,6 +41,8 @@
+
+ #include "cairo-error-private.h"
+ #include "cairo-surface-clipper-private.h"
++#include "cairo-gstate-private.h"
++#include "cairo-private.h"
+
+ #include <dlfcn.h>
+
+@@ -77,6 +79,11 @@
+  * This macro can be used to conditionally compile backend-specific code.
+  */
+
++/* Here are some of the differences between cairo and CoreGraphics
++   - cairo has only a single source active at once vs. CoreGraphics having
++     separate sources for stroke and fill
++*/
++
+ /* This method is private, but it exists.  Its params are are exposed
+  * as args to the NS* method, but not as CG.
+  */
+@@ -126,6 +133,12 @@ static void (*CGContextSetShouldAntialia
+ static void (*CGContextSetAllowsFontSmoothingPtr) (CGContextRef, bool) = NULL;
+ static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL;
+ static CGPathRef (*CGContextCopyPathPtr) (CGContextRef) = NULL;
++static CGFloat (*CGContextGetAlphaPtr) (CGContextRef) = NULL;
++
++/* CTFontDrawGlyphs is not available until 10.7 */
++static void (*CTFontDrawGlyphsPtr) (CTFontRef, const CGGlyph[], const CGPoint[], size_t, CGContextRef) = NULL;
++
++static SInt32 _cairo_quartz_osx_version = 0x0;
+
+ static cairo_bool_t _cairo_quartz_symbol_lookup_done = FALSE;
+
+@@ -160,6 +173,14 @@ static void quartz_ensure_symbols(void)
+     CGContextCopyPathPtr = dlsym(RTLD_DEFAULT, "CGContextCopyPath");
+     CGContextGetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");
+     CGContextSetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing");
++    CGContextGetAlphaPtr = dlsym(RTLD_DEFAULT, "CGContextGetAlpha");
++
++    CTFontDrawGlyphsPtr = dlsym(RTLD_DEFAULT, "CTFontDrawGlyphs");
++
++    if (Gestalt(gestaltSystemVersion, &_cairo_quartz_osx_version) != noErr) {
++        // assume 10.5
++        _cairo_quartz_osx_version = 0x1050;
++    }
+
+     _cairo_quartz_symbol_lookup_done = TRUE;
+ }
+@@ -430,6 +446,7 @@ _cairo_quartz_cairo_operator_to_quartz_c
+       case CAIRO_OPERATOR_HSL_LUMINOSITY:
+         default:
+           assert (0);
++          return kPrivateCGCompositeClear;
+     }
+ }
+
+@@ -598,10 +615,13 @@ _cairo_quartz_cairo_matrix_to_quartz (co
+ typedef struct {
+     bool isClipping;
+     CGGlyph *cg_glyphs;
+-    CGSize *cg_advances;
++    union {
++      CGSize *cg_advances;
++      CGPoint *cg_positions;
++    } u;
+     size_t nglyphs;
+     CGAffineTransform textTransform;
+-    CGFontRef font;
++    cairo_scaled_font_t *scaled_font;
+     CGPoint origin;
+ } unbounded_show_glyphs_t;
+
+@@ -679,12 +699,6 @@ _cairo_quartz_fixup_unbounded_operation
+       else
+           CGContextEOFillPath (cgc);
+     } else if (op->op == UNBOUNDED_SHOW_GLYPHS) {
+-      CGContextSetFont (cgc, op->u.show_glyphs.font);
+-      CGContextSetFontSize (cgc, 1.0);
+-      CGContextSetTextMatrix (cgc, CGAffineTransformIdentity);
+-      CGContextTranslateCTM (cgc, op->u.show_glyphs.origin.x, op->u.show_glyphs.origin.y);
+-      CGContextConcatCTM (cgc, op->u.show_glyphs.textTransform);
+-
+       if (op->u.show_glyphs.isClipping) {
+           /* Note that the comment in show_glyphs about kCGTextClip
+            * and the text transform still applies here; however, the
+@@ -693,12 +707,25 @@ _cairo_quartz_fixup_unbounded_operation
+           CGContextSetTextDrawingMode (cgc, kCGTextClip);
+           CGContextSaveGState (cgc);
+       }
++        CGContextTranslateCTM (cgc, op->u.show_glyphs.origin.x, op->u.show_glyphs.origin.y);
++        CGContextConcatCTM (cgc, op->u.show_glyphs.textTransform);
++        if (CTFontDrawGlyphsPtr) {
++            CTFontDrawGlyphsPtr (_cairo_quartz_scaled_font_get_ct_font_ref (op->u.show_glyphs.scaled_font),
++                                 op->u.show_glyphs.cg_glyphs,
++                                 op->u.show_glyphs.u.cg_positions,
++                                 op->u.show_glyphs.nglyphs,
++                                 cgc);
++        } else {
++          CGContextSetFont (cgc, _cairo_quartz_scaled_font_get_cg_font_ref (op->u.show_glyphs.scaled_font));
++          CGContextSetFontSize (cgc, 1.0);
++          CGContextSetTextMatrix (cgc, CGAffineTransformIdentity);
++
++          CGContextShowGlyphsWithAdvances (cgc,
++                                           op->u.show_glyphs.cg_glyphs,
++                                           op->u.show_glyphs.u.cg_advances,
++                                           op->u.show_glyphs.nglyphs);
+
+-      CGContextShowGlyphsWithAdvances (cgc,
+-                                       op->u.show_glyphs.cg_glyphs,
+-                                       op->u.show_glyphs.cg_advances,
+-                                       op->u.show_glyphs.nglyphs);
+-
++        }
+       if (op->u.show_glyphs.isClipping) {
+           CGContextClearRect (cgc, clipBoxRound);
+           CGContextRestoreGState (cgc);
+@@ -1102,12 +1129,12 @@ DataProviderReleaseCallback (void *info,
+ {
+     quartz_source_image_t *source_img = info;
+     _cairo_surface_release_source_image (source_img->surface, source_img->image_out, source_img->image_extra);
++    cairo_surface_destroy (source_img->surface);
+     free (source_img);
+ }
+
+ static cairo_status_t
+-_cairo_surface_to_cgimage (cairo_surface_t *target,
+-                         cairo_surface_t *source,
++_cairo_surface_to_cgimage (cairo_surface_t *source,
+                          CGImageRef *image_out)
+ {
+     cairo_status_t status;
+@@ -1127,9 +1154,14 @@ _cairo_surface_to_cgimage (cairo_surface
+       }
+
+       if (_cairo_quartz_is_cgcontext_bitmap_context (surface->cgContext)) {
+-          *image_out = CGBitmapContextCreateImage (surface->cgContext);
+-          if (*image_out)
+-              return CAIRO_STATUS_SUCCESS;
++          if (!surface->bitmapContextImage) {
++              surface->bitmapContextImage =
++                  CGBitmapContextCreateImage (surface->cgContext);
++          }
++          if (surface->bitmapContextImage) {
++                *image_out = CGImageRetain (surface->bitmapContextImage);
++                return CAIRO_STATUS_SUCCESS;
++            }
+       }
+     }
+
+@@ -1137,10 +1169,11 @@ _cairo_surface_to_cgimage (cairo_surface
+     if (source_img == NULL)
+       return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+-    source_img->surface = source;
++    source_img->surface = cairo_surface_reference(source);
+
+     status = _cairo_surface_acquire_source_image (source_img->surface, &source_img->image_out, &source_img->image_extra);
+     if (status) {
++      cairo_surface_destroy (source_img->surface);
+       free (source_img);
+       return status;
+     }
+@@ -1251,7 +1284,7 @@ _cairo_quartz_cairo_repeating_surface_pa
+     is_bounded = _cairo_surface_get_extents (pat_surf, &extents);
+     assert (is_bounded);
+
+-    status = _cairo_surface_to_cgimage ((cairo_surface_t*) dest, pat_surf, &image);
++    status = _cairo_surface_to_cgimage (pat_surf, &image);
+     if (status)
+       return status;
+     if (image == NULL)
+@@ -1322,16 +1355,43 @@ typedef enum {
+     DO_SHADING,
+     DO_PATTERN,
+     DO_IMAGE,
++    DO_TILED_IMAGE,
++    DO_LAYER,
+     DO_UNSUPPORTED,
+-    DO_NOTHING,
+-    DO_TILED_IMAGE
++    DO_NOTHING
+ } cairo_quartz_action_t;
+
+-static cairo_quartz_action_t
++/* State used during a drawing operation. */
++typedef struct {
++    CGContextRef context;
++    cairo_quartz_action_t action;
++
++    // Used with DO_SHADING, DO_IMAGE, DO_TILED_IMAGE and DO_LAYER
++    CGAffineTransform transform;
++
++    // Used with DO_IMAGE and DO_TILED_IMAGE
++    CGImageRef image;
++    cairo_surface_t *imageSurface;
++
++    // Used with DO_IMAGE, DO_TILED_IMAGE and DO_LAYER
++    CGRect imageRect;
++
++    // Used with DO_LAYER
++    CGLayerRef layer;
++
++    // Used with DO_SHADING
++    CGShadingRef shading;
++
++    // Used with DO_PATTERN
++    CGPatternRef pattern;
++} cairo_quartz_drawing_state_t;
++
++static void
+ _cairo_quartz_setup_fallback_source (cairo_quartz_surface_t *surface,
+-                                   const cairo_pattern_t *source)
++                                   const cairo_pattern_t *source,
++                                   cairo_quartz_drawing_state_t *state)
+ {
+-    CGRect clipBox = CGContextGetClipBoundingBox (surface->cgContext);
++    CGRect clipBox = CGContextGetClipBoundingBox (state->context);
+     double x0, y0, w, h;
+
+     cairo_surface_t *fallback;
+@@ -1340,8 +1400,10 @@ _cairo_quartz_setup_fallback_source (cai
+     cairo_status_t status;
+
+     if (clipBox.size.width == 0.0f ||
+-      clipBox.size.height == 0.0f)
+-      return DO_NOTHING;
++      clipBox.size.height == 0.0f) {
++      state->action = DO_NOTHING;
++      return;
++    }
+
+     x0 = floor(clipBox.origin.x);
+     y0 = floor(clipBox.origin.y);
+@@ -1384,18 +1446,21 @@ _cairo_quartz_setup_fallback_source (cai
+     }
+ #endif
+
+-    status = _cairo_surface_to_cgimage (&surface->base, fallback, &img);
+-    if (status)
+-      return DO_UNSUPPORTED;
+-    if (img == NULL)
+-      return DO_NOTHING;
+-
+-    surface->sourceImageRect = CGRectMake (0.0, 0.0, w, h);
+-    surface->sourceImage = img;
+-    surface->sourceImageSurface = fallback;
+-    surface->sourceTransform = CGAffineTransformMakeTranslation (x0, y0);
++    status = _cairo_surface_to_cgimage (fallback, &img);
++    if (status) {
++        state->action = DO_UNSUPPORTED;
++      return;
++    }
++    if (img == NULL) {
++        state->action = DO_NOTHING;
++      return;
++    }
+
+-    return DO_IMAGE;
++    state->imageRect = CGRectMake (0.0, 0.0, w, h);
++    state->image = img;
++    state->imageSurface = fallback;
++    state->transform = CGAffineTransformMakeTranslation (x0, y0);
++    state->action = DO_IMAGE;
+ }
+
+ /*
+@@ -1411,10 +1476,11 @@ based on the extents of the object (the
+ we don't want the rasterization of the entire gradient to depend on the
+ clip region).
+ */
+-static cairo_quartz_action_t
++static void
+ _cairo_quartz_setup_linear_source (cairo_quartz_surface_t *surface,
+                                  const cairo_linear_pattern_t *lpat,
+-                                 cairo_rectangle_int_t *extents)
++                                 cairo_rectangle_int_t *extents,
++                                 cairo_quartz_drawing_state_t *state)
+ {
+     const cairo_pattern_t *abspat = &lpat->base.base;
+     cairo_matrix_t mat;
+@@ -1424,9 +1490,10 @@ _cairo_quartz_setup_linear_source (cairo
+     bool extend = abspat->extend == CAIRO_EXTEND_PAD;
+
+     if (lpat->base.n_stops == 0) {
+-      CGContextSetRGBStrokeColor (surface->cgContext, 0., 0., 0., 0.);
+-      CGContextSetRGBFillColor (surface->cgContext, 0., 0., 0., 0.);
+-      return DO_SOLID;
++      CGContextSetRGBStrokeColor (state->context, 0., 0., 0., 0.);
++      CGContextSetRGBFillColor (state->context, 0., 0., 0., 0.);
++      state->action = DO_SOLID;
++      return;
+     }
+
+     if (lpat->p1.x == lpat->p2.x &&
+@@ -1436,12 +1503,13 @@ _cairo_quartz_setup_linear_source (cairo
+        * Whatever the correct behaviour is, let's at least have only pixman's
+        * implementation to worry about.
+        */
+-      return _cairo_quartz_setup_fallback_source (surface, abspat);
++      _cairo_quartz_setup_fallback_source (surface, abspat, state);
++      return;
+     }
+
+     mat = abspat->matrix;
+     cairo_matrix_invert (&mat);
+-    _cairo_quartz_cairo_matrix_to_quartz (&mat, &surface->sourceTransform);
++    _cairo_quartz_cairo_matrix_to_quartz (&mat, &state->transform);
+
+     rgb = CGColorSpaceCreateDeviceRGB();
+
+@@ -1461,21 +1529,22 @@ _cairo_quartz_setup_linear_source (cairo
+                                                         extents);
+     }
+
+-    surface->sourceShading = CGShadingCreateAxial (rgb,
+-                                                 start, end,
+-                                                 gradFunc,
+-                                                 extend, extend);
++    state->shading = CGShadingCreateAxial (rgb,
++                                         start, end,
++                                         gradFunc,
++                                         extend, extend);
+
+     CGColorSpaceRelease(rgb);
+     CGFunctionRelease(gradFunc);
+
+-    return DO_SHADING;
++    state->action = DO_SHADING;
+ }
+
+-static cairo_quartz_action_t
++static void
+ _cairo_quartz_setup_radial_source (cairo_quartz_surface_t *surface,
+                                  const cairo_radial_pattern_t *rpat,
+-                                 cairo_rectangle_int_t *extents)
++                                 cairo_rectangle_int_t *extents,
++                                 cairo_quartz_drawing_state_t *state)
+ {
+     const cairo_pattern_t *abspat = &rpat->base.base;
+     cairo_matrix_t mat;
+@@ -1494,9 +1563,10 @@ _cairo_quartz_setup_radial_source (cairo
+     double centerDistance = sqrt (dx*dx + dy*dy);
+
+     if (rpat->base.n_stops == 0) {
+-      CGContextSetRGBStrokeColor (surface->cgContext, 0., 0., 0., 0.);
+-      CGContextSetRGBFillColor (surface->cgContext, 0., 0., 0., 0.);
+-      return DO_SOLID;
++      CGContextSetRGBStrokeColor (state->context, 0., 0., 0., 0.);
++      CGContextSetRGBFillColor (state->context, 0., 0., 0., 0.);
++      state->action = DO_SOLID;
++      return;
+     }
+
+     if (r2 <= centerDistance + r1 + 1e-6 && /* circle 2 doesn't contain circle 1 */
+@@ -1507,12 +1577,13 @@ _cairo_quartz_setup_radial_source (cairo
+        * implementation to worry about.
+        * Note that this also catches the cases where r1 == r2.
+        */
+-      return _cairo_quartz_setup_fallback_source (surface, abspat);
++      _cairo_quartz_setup_fallback_source (surface, abspat, state);
++      return;
+     }
+
+     mat = abspat->matrix;
+     cairo_matrix_invert (&mat);
+-    _cairo_quartz_cairo_matrix_to_quartz (&mat, &surface->sourceTransform);
++    _cairo_quartz_cairo_matrix_to_quartz (&mat, &state->transform);
+
+     rgb = CGColorSpaceCreateDeviceRGB();
+
+@@ -1531,90 +1602,79 @@ _cairo_quartz_setup_radial_source (cairo
+                                                         extents);
+     }
+
+-    surface->sourceShading = CGShadingCreateRadial (rgb,
+-                                                  start,
+-                                                  r1,
+-                                                  end,
+-                                                  r2,
+-                                                  gradFunc,
+-                                                  extend, extend);
++    state->shading = CGShadingCreateRadial (rgb,
++                                          start,
++                                          r1,
++                                          end,
++                                          r2,
++                                          gradFunc,
++                                          extend, extend);
+
+     CGColorSpaceRelease(rgb);
+     CGFunctionRelease(gradFunc);
+
+-    return DO_SHADING;
++    state->action = DO_SHADING;
+ }
+
+-static cairo_quartz_action_t
+-_cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
+-                          const cairo_pattern_t *source,
+-                          cairo_rectangle_int_t *extents)
++static void
++_cairo_quartz_setup_surface_source (cairo_quartz_surface_t *surface,
++                                  const cairo_surface_pattern_t *spat,
++                                  cairo_rectangle_int_t *extents,
++                                  cairo_quartz_drawing_state_t *state)
+ {
+-    assert (!(surface->sourceImage || surface->sourceShading || surface->sourcePattern));
+-
+-    surface->oldInterpolationQuality = CGContextGetInterpolationQuality (surface->cgContext);
+-    CGContextSetInterpolationQuality (surface->cgContext, _cairo_quartz_filter_to_quartz (source->filter));
++    const cairo_pattern_t *source = &spat->base;
++    CGContextRef context = state->context;
+
+-    if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
+-      cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
+-
+-      CGContextSetRGBStrokeColor (surface->cgContext,
+-                                  solid->color.red,
+-                                  solid->color.green,
+-                                  solid->color.blue,
+-                                  solid->color.alpha);
+-      CGContextSetRGBFillColor (surface->cgContext,
+-                                solid->color.red,
+-                                solid->color.green,
+-                                solid->color.blue,
+-                                solid->color.alpha);
+-
+-      return DO_SOLID;
+-    }
+-
+-    if (source->type == CAIRO_PATTERN_TYPE_LINEAR) {
+-      const cairo_linear_pattern_t *lpat = (const cairo_linear_pattern_t *)source;
+-      return _cairo_quartz_setup_linear_source (surface, lpat, extents);
+-    }
+-
+-    if (source->type == CAIRO_PATTERN_TYPE_RADIAL) {
+-      const cairo_radial_pattern_t *rpat = (const cairo_radial_pattern_t *)source;
+-      return _cairo_quartz_setup_radial_source (surface, rpat, extents);
+-    }
+-
+-    if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
+-      (source->extend == CAIRO_EXTEND_NONE || (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT)))
++    if (source->extend == CAIRO_EXTEND_NONE || source->extend == CAIRO_EXTEND_PAD ||
++        (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT))
+     {
+-      const cairo_surface_pattern_t *spat = (const cairo_surface_pattern_t *) source;
+       cairo_surface_t *pat_surf = spat->surface;
+       CGImageRef img;
+       cairo_matrix_t m = spat->base.matrix;
+       cairo_rectangle_int_t extents;
+-      cairo_status_t status;
+       CGAffineTransform xform;
+       CGRect srcRect;
+       cairo_fixed_t fw, fh;
+       cairo_bool_t is_bounded;
++      cairo_bool_t repeat = source->extend == CAIRO_EXTEND_REPEAT;
++        cairo_status_t status;
+
+-      status = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf, &img);
+-      if (status)
+-          return DO_UNSUPPORTED;
+-      if (img == NULL)
+-          return DO_NOTHING;
++        cairo_matrix_invert(&m);
++        _cairo_quartz_cairo_matrix_to_quartz (&m, &state->transform);
+
+-      CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 1);
++        /* Draw nonrepeating CGLayer surface using DO_LAYER */
++        if (!repeat && cairo_surface_get_type (pat_surf) == CAIRO_SURFACE_TYPE_QUARTZ) {
++            cairo_quartz_surface_t *quartz_surf = (cairo_quartz_surface_t *) pat_surf;
++            if (quartz_surf->cgLayer) {
++              state->imageRect = CGRectMake (0, 0, quartz_surf->extents.width, quartz_surf->extents.height);
++                state->layer = quartz_surf->cgLayer;
++                state->action = DO_LAYER;
++                return;
++            }
++        }
++
++      status = _cairo_surface_to_cgimage (pat_surf, &img);
++        if (status) {
++            state->action = DO_UNSUPPORTED;
++          return;
++        }
++        if (img == NULL) {
++            state->action = DO_NOTHING;
++          return;
++        }
+
+-      surface->sourceImage = img;
++        /* XXXroc what is this for? */
++      CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 1);
+
+-      cairo_matrix_invert(&m);
+-      _cairo_quartz_cairo_matrix_to_quartz (&m, &surface->sourceTransform);
++      state->image = img;
+
+       is_bounded = _cairo_surface_get_extents (pat_surf, &extents);
+       assert (is_bounded);
+
+-      if (source->extend == CAIRO_EXTEND_NONE) {
+-          surface->sourceImageRect = CGRectMake (0, 0, extents.width, extents.height);
+-          return DO_IMAGE;
++      if (!repeat) {
++          state->imageRect = CGRectMake (0, 0, extents.width, extents.height);
++          state->action = DO_IMAGE;
++          return;
+       }
+
+       /* Quartz seems to tile images at pixel-aligned regions only -- this
+@@ -1624,8 +1684,8 @@ _cairo_quartz_setup_source (cairo_quartz
+        * epsilon), and if not, fall back to the CGPattern type.
+        */
+
+-      xform = CGAffineTransformConcat (CGContextGetCTM (surface->cgContext),
+-                                       surface->sourceTransform);
++      xform = CGAffineTransformConcat (CGContextGetCTM (context),
++                                       state->transform);
+
+       srcRect = CGRectMake (0, 0, extents.width, extents.height);
+       srcRect = CGRectApplyAffineTransform (srcRect, xform);
+@@ -1646,101 +1706,218 @@ _cairo_quartz_setup_source (cairo_quartz
+
+           srcRect = CGRectApplyAffineTransform (srcRect, xform);
+
+-          surface->sourceImageRect = srcRect;
+-
+-          return DO_TILED_IMAGE;
++          state->imageRect = srcRect;
++            state->action = DO_TILED_IMAGE;
++            return;
+       }
+
+       /* Fall through to generic SURFACE case */
+     }
+
+-    if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
+-      cairo_quartz_float_t patternAlpha = 1.0f;
+-      CGColorSpaceRef patternSpace;
+-      CGPatternRef pattern;
+-      cairo_int_status_t status;
+-
+-      status = _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (surface, source, &pattern);
+-      if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
+-          return DO_NOTHING;
+-      if (status)
+-          return DO_UNSUPPORTED;
+-
+-      // Save before we change the pattern, colorspace, etc. so that
+-      // we can restore and make sure that quartz releases our
+-      // pattern (which may be stack allocated)
+-      CGContextSaveGState(surface->cgContext);
+-
+-      patternSpace = CGColorSpaceCreatePattern(NULL);
+-      CGContextSetFillColorSpace (surface->cgContext, patternSpace);
+-      CGContextSetFillPattern (surface->cgContext, pattern, &patternAlpha);
+-      CGContextSetStrokeColorSpace (surface->cgContext, patternSpace);
+-      CGContextSetStrokePattern (surface->cgContext, pattern, &patternAlpha);
+-      CGColorSpaceRelease (patternSpace);
+-
+-      /* Quartz likes to munge the pattern phase (as yet unexplained
+-       * why); force it to 0,0 as we've already baked in the correct
+-       * pattern translation into the pattern matrix
+-       */
+-      CGContextSetPatternPhase (surface->cgContext, CGSizeMake(0,0));
+-
+-      surface->sourcePattern = pattern;
++    CGFloat patternAlpha = 1.0f;
++    CGColorSpaceRef patternSpace;
++    CGPatternRef pattern;
++    cairo_int_status_t status;
+
+-      return DO_PATTERN;
++    status = _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (surface, source, &pattern);
++    if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) {
++        state->action = DO_NOTHING;
++      return;
++    }
++    if (status) {
++      state->action = DO_UNSUPPORTED;
++      return;
+     }
+
+-    return DO_UNSUPPORTED;
++    patternSpace = CGColorSpaceCreatePattern (NULL);
++    CGContextSetFillColorSpace (context, patternSpace);
++    CGContextSetFillPattern (context, pattern, &patternAlpha);
++    CGContextSetStrokeColorSpace (context, patternSpace);
++    CGContextSetStrokePattern (context, pattern, &patternAlpha);
++    CGColorSpaceRelease (patternSpace);
++
++    /* Quartz likes to munge the pattern phase (as yet unexplained
++     * why); force it to 0,0 as we've already baked in the correct
++     * pattern translation into the pattern matrix
++     */
++    CGContextSetPatternPhase (context, CGSizeMake(0,0));
++
++    state->pattern = pattern;
++    state->action = DO_PATTERN;
++    return;
+ }
+
++/**
++ * Call this before any operation that can modify the contents of a
++ * cairo_quartz_surface_t.
++ */
+ static void
+-_cairo_quartz_teardown_source (cairo_quartz_surface_t *surface,
+-                             const cairo_pattern_t *source)
++_cairo_quartz_surface_will_change (cairo_quartz_surface_t *surface)
+ {
+-    CGContextSetInterpolationQuality (surface->cgContext, surface->oldInterpolationQuality);
++    if (surface->bitmapContextImage) {
++        CGImageRelease (surface->bitmapContextImage);
++        surface->bitmapContextImage = NULL;
++    }
++}
+
+-    if (surface->sourceImage) {
+-      CGImageRelease(surface->sourceImage);
+-      surface->sourceImage = NULL;
++/**
++ * Sets up internal state to be used to draw the source mask, stored in
++ * cairo_quartz_state_t. Guarantees to call CGContextSaveGState on
++ * surface->cgContext.
++ */
++static cairo_quartz_drawing_state_t
++_cairo_quartz_setup_state (cairo_quartz_surface_t *surface,
++                         const cairo_pattern_t *source,
++                         cairo_operator_t op,
++                         cairo_rectangle_int_t *extents)
++{
++    CGContextRef context = surface->cgContext;
++    cairo_quartz_drawing_state_t state;
++    cairo_status_t status;
+
+-      cairo_surface_destroy(surface->sourceImageSurface);
+-      surface->sourceImageSurface = NULL;
++    state.context = context;
++    state.image = NULL;
++    state.imageSurface = NULL;
++    state.layer = NULL;
++    state.shading = NULL;
++    state.pattern = NULL;
++
++    _cairo_quartz_surface_will_change (surface);
++
++    // Save before we change the pattern, colorspace, etc. so that
++    // we can restore and make sure that quartz releases our
++    // pattern (which may be stack allocated)
++    CGContextSaveGState(context);
++
++    CGContextSetInterpolationQuality (context, _cairo_quartz_filter_to_quartz (source->filter));
++
++    status = _cairo_quartz_surface_set_cairo_operator (surface, op);
++    if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) {
++        state.action = DO_NOTHING;
++        return state;
++    }
++    if (status) {
++        state.action = DO_UNSUPPORTED;
++        return state;
+     }
+
+-    if (surface->sourceShading) {
+-      CGShadingRelease(surface->sourceShading);
+-      surface->sourceShading = NULL;
++    if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
++      cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
++
++      CGContextSetRGBStrokeColor (context,
++                                  solid->color.red,
++                                  solid->color.green,
++                                  solid->color.blue,
++                                  solid->color.alpha);
++      CGContextSetRGBFillColor (context,
++                                solid->color.red,
++                                solid->color.green,
++                                solid->color.blue,
++                                solid->color.alpha);
++
++        state.action = DO_SOLID;
++        return state;
++    }
++
++    if (source->type == CAIRO_PATTERN_TYPE_LINEAR) {
++      const cairo_linear_pattern_t *lpat = (const cairo_linear_pattern_t *)source;
++      _cairo_quartz_setup_linear_source (surface, lpat, extents, &state);
++      return state;
++    }
++
++    if (source->type == CAIRO_PATTERN_TYPE_RADIAL) {
++      const cairo_radial_pattern_t *rpat = (const cairo_radial_pattern_t *)source;
++      _cairo_quartz_setup_radial_source (surface, rpat, extents, &state);
++      return state;
+     }
+
+-    if (surface->sourcePattern) {
+-      CGPatternRelease(surface->sourcePattern);
+-      // To tear down the pattern and colorspace
+-      CGContextRestoreGState(surface->cgContext);
++    if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
++        if (op == CAIRO_OPERATOR_OVER && _cairo_pattern_is_opaque (source, NULL) &&
++            CGContextGetAlphaPtr &&
++            CGContextGetAlphaPtr (surface->cgContext) == 1.0) {
++            // Quartz won't touch pixels outside the bounds of the
++            // source surface, so we can just go ahead and use Copy here
++            // to accelerate things.
++            // Quartz won't necessarily be able to do this optimization internally;
++            // for CGLayer surfaces, we can know all the pixels are opaque
++            // (because it's CONTENT_COLOR), but Quartz won't know.
++            CGContextSetCompositeOperation (context, kPrivateCGCompositeCopy);
++        }
+
+-      surface->sourcePattern = NULL;
++      const cairo_surface_pattern_t *spat = (const cairo_surface_pattern_t *) source;
++        _cairo_quartz_setup_surface_source (surface, spat, extents, &state);
++        return state;
+     }
+-}
+
++    state.action = DO_UNSUPPORTED;
++    return state;
++}
+
++/**
++ * 1) Tears down internal state used to draw the source
++ * 2) Does CGContextRestoreGState(state->context)
++ */
+ static void
+-_cairo_quartz_draw_image (cairo_quartz_surface_t *surface, cairo_operator_t op,  cairo_quartz_action_t action)
++_cairo_quartz_teardown_state (cairo_quartz_drawing_state_t *state)
+ {
+-    assert (surface && surface->sourceImage && (action == DO_IMAGE || action == DO_TILED_IMAGE));
++    if (state->image) {
++      CGImageRelease(state->image);
++    }
+
+-    CGContextConcatCTM (surface->cgContext, surface->sourceTransform);
+-    CGContextTranslateCTM (surface->cgContext, 0, surface->sourceImageRect.size.height);
+-    CGContextScaleCTM (surface->cgContext, 1, -1);
+-
+-    if (action == DO_IMAGE) {
+-      CGContextDrawImage (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
+-      if (!_cairo_operator_bounded_by_source(op)) {
+-          CGContextBeginPath (surface->cgContext);
+-          CGContextAddRect (surface->cgContext, surface->sourceImageRect);
+-          CGContextAddRect (surface->cgContext, CGContextGetClipBoundingBox (surface->cgContext));
+-          CGContextSetRGBFillColor (surface->cgContext, 0, 0, 0, 0);
+-          CGContextEOFillPath (surface->cgContext);
++    if (state->imageSurface) {
++      cairo_surface_destroy(state->imageSurface);
++    }
++
++    if (state->shading) {
++      CGShadingRelease(state->shading);
++    }
++
++    if (state->pattern) {
++      CGPatternRelease(state->pattern);
++    }
++
++    CGContextRestoreGState(state->context);
++}
++
++
++static void
++_cairo_quartz_draw_image (cairo_quartz_drawing_state_t *state, cairo_operator_t op)
++{
++    assert (state &&
++            ((state->image && (state->action == DO_IMAGE || state->action == DO_TILED_IMAGE)) ||
++             (state->layer && state->action == DO_LAYER)));
++
++    CGContextConcatCTM (state->context, state->transform);
++    CGContextTranslateCTM (state->context, 0, state->imageRect.size.height);
++    CGContextScaleCTM (state->context, 1, -1);
++
++    if (state->action == DO_TILED_IMAGE) {
++      CGContextDrawTiledImagePtr (state->context, state->imageRect, state->image);
++      /* no need to worry about unbounded operators, since tiled images
++         fill the entire clip region */
++    } else {
++        if (state->action == DO_LAYER) {
++            /* Note that according to Apple docs it's completely legal
++             * to draw a CGLayer to any CGContext, even one it wasn't
++             * created for.
++             */
++            CGContextSetInterpolationQuality (state->context, kCGInterpolationNone);
++            CGContextDrawLayerAtPoint (state->context, state->imageRect.origin,
++                                       state->layer);
++        } else {
++            CGContextDrawImage (state->context, state->imageRect, state->image);
++        }
++
++      /* disable this EXTEND_NONE correctness code because we use this path
++       * for both EXTEND_NONE and EXTEND_PAD */
++      if (0 && !_cairo_operator_bounded_by_source (op)) {
++          CGContextBeginPath (state->context);
++          CGContextAddRect (state->context, state->imageRect);
++          CGContextAddRect (state->context, CGContextGetClipBoundingBox (state->context));
++          CGContextSetRGBFillColor (state->context, 0, 0, 0, 0);
++          CGContextEOFillPath (state->context);
+       }
+-    } else
+-      CGContextDrawTiledImagePtr (surface->cgContext, surface->sourceImageRect, surface->sourceImage);
++    }
+ }
+
+
+@@ -1762,6 +1939,7 @@ _cairo_quartz_get_image (cairo_quartz_su
+     }
+
+     if (surface->imageSurfaceEquiv) {
++      CGContextFlush(surface->cgContext);
+       *image_out = (cairo_image_surface_t*) cairo_surface_reference(surface->imageSurfaceEquiv);
+       return CAIRO_STATUS_SUCCESS;
+     }
+@@ -1773,6 +1951,7 @@ _cairo_quartz_get_image (cairo_quartz_su
+       CGColorSpaceRef colorspace;
+       unsigned int color_comps;
+
++      CGContextFlush(surface->cgContext);
+       imageData = (unsigned char *) CGBitmapContextGetData(surface->cgContext);
+
+ #ifdef USE_10_3_WORKAROUNDS
+@@ -1860,53 +2039,79 @@ _cairo_quartz_surface_finish (void *abst
+
+     surface->cgContext = NULL;
+
++    if (surface->bitmapContextImage) {
++        CGImageRelease (surface->bitmapContextImage);
++        surface->bitmapContextImage = NULL;
++    }
++
+     if (surface->imageSurfaceEquiv) {
++        if (surface->ownsData)
++            _cairo_image_surface_assume_ownership_of_data (surface->imageSurfaceEquiv);
+       cairo_surface_destroy (surface->imageSurfaceEquiv);
+       surface->imageSurfaceEquiv = NULL;
++    } else if (surface->imageData && surface->ownsData) {
++        free (surface->imageData);
+     }
+
+-    if (surface->imageData) {
+-      free (surface->imageData);
+-      surface->imageData = NULL;
++    surface->imageData = NULL;
++
++    if (surface->cgLayer) {
++        CGLayerRelease (surface->cgLayer);
+     }
+
+     return CAIRO_STATUS_SUCCESS;
+ }
+
+ static cairo_status_t
+-_cairo_quartz_surface_acquire_source_image (void *abstract_surface,
+-                                           cairo_image_surface_t **image_out,
+-                                           void **image_extra)
++_cairo_quartz_surface_acquire_image (void *abstract_surface,
++                                     cairo_image_surface_t **image_out,
++                                     void **image_extra)
+ {
+     cairo_int_status_t status;
+     cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
+
+-    //ND((stderr, "%p _cairo_quartz_surface_acquire_source_image\n", surface));
+-
+-    status = _cairo_quartz_get_image (surface, image_out);
+-    if (status)
+-      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+-
+     *image_extra = NULL;
+
+-    return CAIRO_STATUS_SUCCESS;
+-}
++    /* ND((stderr, "%p _cairo_quartz_surface_acquire_image\n", surface)); */
+
+-static cairo_surface_t *
+-_cairo_quartz_surface_snapshot (void *abstract_surface)
+-{
+-    cairo_int_status_t status;
+-    cairo_quartz_surface_t *surface = abstract_surface;
+-    cairo_image_surface_t *image;
++    status = _cairo_quartz_get_image (surface, image_out);
+
+-    if (surface->imageSurfaceEquiv)
+-      return NULL;
++    if (status == CAIRO_INT_STATUS_UNSUPPORTED && surface->cgLayer) {
++        /* copy the layer into a Quartz bitmap context so we can get the data */
++        cairo_surface_t *tmp =
++            cairo_quartz_surface_create (CAIRO_FORMAT_ARGB32,
++                                         surface->extents.width,
++                                         surface->extents.height);
++        cairo_quartz_surface_t *tmp_surface = (cairo_quartz_surface_t *) tmp;
++
++        /* if surface creation failed, we won't have a Quartz surface here */
++        if (cairo_surface_get_type (tmp) == CAIRO_SURFACE_TYPE_QUARTZ &&
++            tmp_surface->imageSurfaceEquiv) {
++            CGContextSaveGState (tmp_surface->cgContext);
++            CGContextTranslateCTM (tmp_surface->cgContext, 0, surface->extents.height);
++            CGContextScaleCTM (tmp_surface->cgContext, 1, -1);
++            /* Note that according to Apple docs it's completely legal
++             * to draw a CGLayer to any CGContext, even one it wasn't
++             * created for.
++             */
++            CGContextDrawLayerAtPoint (tmp_surface->cgContext,
++                                       CGPointMake (0.0, 0.0),
++                                       surface->cgLayer);
++            CGContextRestoreGState (tmp_surface->cgContext);
++
++            *image_out = (cairo_image_surface_t*)
++                cairo_surface_reference(tmp_surface->imageSurfaceEquiv);
++            *image_extra = tmp;
++            status = CAIRO_STATUS_SUCCESS;
++        } else {
++            cairo_surface_destroy (tmp);
++        }
++    }
+
+-    status = _cairo_quartz_get_image (surface, &image);
+-    if (unlikely (status))
+-        return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
++    if (status)
++      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+-    return &image->base;
++    return CAIRO_STATUS_SUCCESS;
+ }
+
+ static void
+@@ -1915,6 +2120,10 @@ _cairo_quartz_surface_release_source_ima
+                                            void *image_extra)
+ {
+     cairo_surface_destroy ((cairo_surface_t *) image);
++
++    if (image_extra) {
++        cairo_surface_destroy ((cairo_surface_t *) image_extra);
++    }
+ }
+
+
+@@ -1926,18 +2135,16 @@ _cairo_quartz_surface_acquire_dest_image
+                                         void **image_extra)
+ {
+     cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
+-    cairo_int_status_t status;
+
+     ND((stderr, "%p _cairo_quartz_surface_acquire_dest_image\n", surface));
+
+-    status = _cairo_quartz_get_image (surface, image_out);
+-    if (status)
+-      return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+-
+     *image_rect = surface->extents;
+     *image_extra = NULL;
+
+-    return CAIRO_STATUS_SUCCESS;
++    _cairo_quartz_surface_will_change (surface);
++
++    return _cairo_quartz_surface_acquire_image (abstract_surface,
++        image_out, image_extra);
+ }
+
+ static void
+@@ -1947,11 +2154,31 @@ _cairo_quartz_surface_release_dest_image
+                                         cairo_rectangle_int_t *image_rect,
+                                         void *image_extra)
+ {
+-    //cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
+-
+-    //ND((stderr, "%p _cairo_quartz_surface_release_dest_image\n", surface));
++    /* ND((stderr, "%p _cairo_quartz_surface_release_dest_image\n", surface)); */
+
+     cairo_surface_destroy ((cairo_surface_t *) image);
++
++    if (image_extra) {
++        /* we need to write the data from the temp surface back to the layer */
++        cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
++        cairo_quartz_surface_t *tmp_surface = (cairo_quartz_surface_t *) image_extra;
++        CGImageRef img;
++        cairo_status_t status = _cairo_surface_to_cgimage (&tmp_surface->base, &img);
++        if (status) {
++            cairo_surface_destroy (&tmp_surface->base);
++            return;
++        }
++
++        CGContextSaveGState (surface->cgContext);
++        CGContextTranslateCTM (surface->cgContext, 0, surface->extents.height);
++        CGContextScaleCTM (surface->cgContext, 1, -1);
++        CGContextDrawImage (surface->cgContext,
++                            CGRectMake (0.0, 0.0, surface->extents.width, surface->extents.height),
++                            img);
++        CGContextRestoreGState (surface->cgContext);
++
++        cairo_surface_destroy (&tmp_surface->base);
++    }
+ }
+
+ static cairo_surface_t *
+@@ -1960,10 +2187,13 @@ _cairo_quartz_surface_create_similar (vo
+                                      int width,
+                                      int height)
+ {
+-    /*cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;*/
+-
++    cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
+     cairo_format_t format;
+
++    if (surface->cgLayer)
++        return cairo_quartz_surface_create_cg_layer (abstract_surface, content,
++                                                     width, height);
++
+     if (content == CAIRO_CONTENT_COLOR_ALPHA)
+       format = CAIRO_FORMAT_ARGB32;
+     else if (content == CAIRO_CONTENT_COLOR)
+@@ -2027,7 +2257,7 @@ _cairo_quartz_surface_clone_similar (voi
+       }
+     }
+
+-    status = _cairo_surface_to_cgimage ((cairo_surface_t*) abstract_surface, src, &quartz_image);
++    status = _cairo_surface_to_cgimage (src, &quartz_image);
+     if (status)
+       return CAIRO_INT_STATUS_UNSUPPORTED;
+
+@@ -2087,7 +2317,7 @@ _cairo_quartz_surface_paint_cg (void *ab
+ {
+     cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
+     cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
+-    cairo_quartz_action_t action;
++    cairo_quartz_drawing_state_t state;
+
+     ND((stderr, "%p _cairo_quartz_surface_paint op %d source->type %d\n", surface, op, source->type));
+
+@@ -2098,31 +2328,24 @@ _cairo_quartz_surface_paint_cg (void *ab
+     if (unlikely (rv))
+       return rv;
+
+-    rv = _cairo_quartz_surface_set_cairo_operator (surface, op);
+-    if (unlikely (rv))
+-      return rv == CAIRO_INT_STATUS_NOTHING_TO_DO ? CAIRO_STATUS_SUCCESS : rv;
++    state = _cairo_quartz_setup_state (surface, source, op, NULL);
+
+-    action = _cairo_quartz_setup_source (surface, source, NULL);
+-
+-    if (action == DO_SOLID || action == DO_PATTERN) {
+-      CGContextFillRect (surface->cgContext, CGRectMake(surface->extents.x,
+-                                                        surface->extents.y,
+-                                                        surface->extents.width,
+-                                                        surface->extents.height));
+-    } else if (action == DO_SHADING) {
+-      CGContextSaveGState (surface->cgContext);
+-      CGContextConcatCTM (surface->cgContext, surface->sourceTransform);
+-      CGContextDrawShading (surface->cgContext, surface->sourceShading);
+-      CGContextRestoreGState (surface->cgContext);
+-    } else if (action == DO_IMAGE || action == DO_TILED_IMAGE) {
+-      CGContextSaveGState (surface->cgContext);
+-      _cairo_quartz_draw_image (surface, op, action);
+-      CGContextRestoreGState (surface->cgContext);
+-    } else if (action != DO_NOTHING) {
++    if (state.action == DO_SOLID || state.action == DO_PATTERN) {
++      CGContextFillRect (state.context, CGRectMake(surface->extents.x,
++                                                   surface->extents.y,
++                                                   surface->extents.width,
++                                                   surface->extents.height));
++    } else if (state.action == DO_SHADING) {
++      CGContextConcatCTM (state.context, state.transform);
++      CGContextDrawShading (state.context, state.shading);
++    } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE ||
++               state.action == DO_LAYER) {
++      _cairo_quartz_draw_image (&state, op);
++    } else if (state.action != DO_NOTHING) {
+       rv = CAIRO_INT_STATUS_UNSUPPORTED;
+     }
+
+-    _cairo_quartz_teardown_source (surface, source);
++    _cairo_quartz_teardown_state (&state);
+
+     ND((stderr, "-- paint\n"));
+     return rv;
+@@ -2186,7 +2409,7 @@ _cairo_quartz_surface_fill_cg (void *abs
+ {
+     cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
+     cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
+-    cairo_quartz_action_t action;
++    cairo_quartz_drawing_state_t state;
+     CGPathRef path_for_unbounded = NULL;
+
+     ND((stderr, "%p _cairo_quartz_surface_fill op %d source->type %d\n", surface, op, source->type));
+@@ -2198,14 +2421,6 @@ _cairo_quartz_surface_fill_cg (void *abs
+     if (unlikely (rv))
+       return rv;
+
+-    rv = _cairo_quartz_surface_set_cairo_operator (surface, op);
+-    if (unlikely (rv))
+-      return rv == CAIRO_INT_STATUS_NOTHING_TO_DO ? CAIRO_STATUS_SUCCESS : rv;
+-
+-    CGContextSaveGState (surface->cgContext);
+-
+-    CGContextSetShouldAntialias (surface->cgContext, (antialias != CAIRO_ANTIALIAS_NONE));
+-
+     if (_cairo_quartz_source_needs_extents (source))
+     {
+         /* We don't need precise extents since these are only used to
+@@ -2213,46 +2428,47 @@ _cairo_quartz_surface_fill_cg (void *abs
+            object. */
+         cairo_rectangle_int_t path_extents;
+         _cairo_path_fixed_approximate_fill_extents (path, &path_extents);
+-        action = _cairo_quartz_setup_source (surface, source, &path_extents);
++        state = _cairo_quartz_setup_state (surface, source, op, &path_extents);
+     } else {
+-        action = _cairo_quartz_setup_source (surface, source, NULL);
++        state = _cairo_quartz_setup_state (surface, source, op, NULL);
+     }
+
+-    _cairo_quartz_cairo_path_to_quartz_context (path, surface->cgContext);
++    CGContextSetShouldAntialias (state.context, (antialias != CAIRO_ANTIALIAS_NONE));
++
++    _cairo_quartz_cairo_path_to_quartz_context (path, state.context);
+
+     if (!_cairo_operator_bounded_by_mask(op) && CGContextCopyPathPtr)
+-      path_for_unbounded = CGContextCopyPathPtr (surface->cgContext);
++      path_for_unbounded = CGContextCopyPathPtr (state.context);
+
+-    if (action == DO_SOLID || action == DO_PATTERN) {
++    if (state.action == DO_SOLID || state.action == DO_PATTERN) {
+       if (fill_rule == CAIRO_FILL_RULE_WINDING)
+-          CGContextFillPath (surface->cgContext);
++          CGContextFillPath (state.context);
+       else
+-          CGContextEOFillPath (surface->cgContext);
+-    } else if (action == DO_SHADING) {
++          CGContextEOFillPath (state.context);
++    } else if (state.action == DO_SHADING) {
+
+       // we have to clip and then paint the shading; we can't fill
+       // with the shading
+       if (fill_rule == CAIRO_FILL_RULE_WINDING)
+-          CGContextClip (surface->cgContext);
++          CGContextClip (state.context);
+       else
+-          CGContextEOClip (surface->cgContext);
++            CGContextEOClip (state.context);
+
+-      CGContextConcatCTM (surface->cgContext, surface->sourceTransform);
+-      CGContextDrawShading (surface->cgContext, surface->sourceShading);
+-    } else if (action == DO_IMAGE || action == DO_TILED_IMAGE) {
++      CGContextConcatCTM (state.context, state.transform);
++      CGContextDrawShading (state.context, state.shading);
++    } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE ||
++               state.action == DO_LAYER) {
+       if (fill_rule == CAIRO_FILL_RULE_WINDING)
+-          CGContextClip (surface->cgContext);
++          CGContextClip (state.context);
+       else
+-          CGContextEOClip (surface->cgContext);
++          CGContextEOClip (state.context);
+
+-      _cairo_quartz_draw_image (surface, op, action);
+-    } else if (action != DO_NOTHING) {
++      _cairo_quartz_draw_image (&state, op);
++    } else if (state.action != DO_NOTHING) {
+       rv = CAIRO_INT_STATUS_UNSUPPORTED;
+     }
+
+-    _cairo_quartz_teardown_source (surface, source);
+-
+-    CGContextRestoreGState (surface->cgContext);
++    _cairo_quartz_teardown_state (&state);
+
+     if (path_for_unbounded) {
+       unbounded_op_data_t ub;
+@@ -2319,7 +2535,7 @@ _cairo_quartz_surface_stroke_cg (void *a
+ {
+     cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
+     cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
+-    cairo_quartz_action_t action;
++    cairo_quartz_drawing_state_t state;
+     CGAffineTransform origCTM, strokeTransform;
+     CGPathRef path_for_unbounded = NULL;
+
+@@ -2336,16 +2552,25 @@ _cairo_quartz_surface_stroke_cg (void *a
+     if (unlikely (rv))
+       return rv == CAIRO_INT_STATUS_NOTHING_TO_DO ? CAIRO_STATUS_SUCCESS : rv;
+
++    if (_cairo_quartz_source_needs_extents (source))
++    {
++      cairo_rectangle_int_t path_extents;
++      _cairo_path_fixed_approximate_stroke_extents (path, style, ctm, &path_extents);
++      state = _cairo_quartz_setup_state (surface, source, op, &path_extents);
++    } else {
++      state = _cairo_quartz_setup_state (surface, source, op, NULL);
++    }
++
+     // Turning antialiasing off used to cause misrendering with
+     // single-pixel lines (e.g. 20,10.5 -> 21,10.5 end up being rendered as 2 pixels).
+     // That's been since fixed in at least 10.5, and in the latest 10.4 dot releases.
+-    CGContextSetShouldAntialias (surface->cgContext, (antialias != CAIRO_ANTIALIAS_NONE));
+-    CGContextSetLineWidth (surface->cgContext, style->line_width);
+-    CGContextSetLineCap (surface->cgContext, _cairo_quartz_cairo_line_cap_to_quartz (style->line_cap));
+-    CGContextSetLineJoin (surface->cgContext, _cairo_quartz_cairo_line_join_to_quartz (style->line_join));
+-    CGContextSetMiterLimit (surface->cgContext, style->miter_limit);
++    CGContextSetShouldAntialias (state.context, (antialias != CAIRO_ANTIALIAS_NONE));
++    CGContextSetLineWidth (state.context, style->line_width);
++    CGContextSetLineCap (state.context, _cairo_quartz_cairo_line_cap_to_quartz (style->line_cap));
++    CGContextSetLineJoin (state.context, _cairo_quartz_cairo_line_join_to_quartz (style->line_join));
++    CGContextSetMiterLimit (state.context, style->miter_limit);
+
+-    origCTM = CGContextGetCTM (surface->cgContext);
++    origCTM = CGContextGetCTM (state.context);
+
+     if (style->dash && style->num_dashes) {
+ #define STATIC_DASH 32
+@@ -2368,72 +2593,62 @@ _cairo_quartz_surface_stroke_cg (void *a
+       if (fdash != sdash)
+           free (fdash);
+     } else
+-      CGContextSetLineDash (surface->cgContext, 0, NULL, 0);
++      CGContextSetLineDash (state.context, 0, NULL, 0);
+
+-    CGContextSaveGState (surface->cgContext);
+
++    _cairo_quartz_cairo_path_to_quartz_context (path, state.context);
+
+-    if (_cairo_quartz_source_needs_extents (source))
+-    {
+-        cairo_rectangle_int_t path_extents;
+-        _cairo_path_fixed_approximate_stroke_extents (path, style, ctm, &path_extents);
+-        action = _cairo_quartz_setup_source (surface, source, &path_extents);
+-    } else {
+-        action = _cairo_quartz_setup_source (surface, source, NULL);
+-    }
+-
+-    _cairo_quartz_cairo_path_to_quartz_context (path, surface->cgContext);
++    _cairo_quartz_cairo_matrix_to_quartz (ctm, &strokeTransform);
++    CGContextConcatCTM (state.context, strokeTransform);
+
+     if (!_cairo_operator_bounded_by_mask (op) && CGContextCopyPathPtr)
+-      path_for_unbounded = CGContextCopyPathPtr (surface->cgContext);
+-
+-    _cairo_quartz_cairo_matrix_to_quartz (ctm, &strokeTransform);
+-    CGContextConcatCTM (surface->cgContext, strokeTransform);
++      path_for_unbounded = CGContextCopyPathPtr (state.context);
+
+-    if (action == DO_SOLID || action == DO_PATTERN) {
+-      CGContextStrokePath (surface->cgContext);
+-    } else if (action == DO_IMAGE || action == DO_TILED_IMAGE) {
+-      CGContextReplacePathWithStrokedPath (surface->cgContext);
+-      CGContextClip (surface->cgContext);
+-
+-      CGContextSetCTM (surface->cgContext, origCTM);
+-      _cairo_quartz_draw_image (surface, op, action);
+-    } else if (action == DO_SHADING) {
+-      CGContextReplacePathWithStrokedPath (surface->cgContext);
+-      CGContextClip (surface->cgContext);
+-
+-      CGContextSetCTM (surface->cgContext, origCTM);
+-
+-      CGContextConcatCTM (surface->cgContext, surface->sourceTransform);
+-      CGContextDrawShading (surface->cgContext, surface->sourceShading);
+-    } else if (action != DO_NOTHING) {
++    if (state.action == DO_SOLID || state.action == DO_PATTERN) {
++      CGContextStrokePath (state.context);
++    } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE ||
++               state.action == DO_LAYER) {
++      CGContextReplacePathWithStrokedPath (state.context);
++      CGContextClip (state.context);
++
++      CGContextSetCTM (state.context, origCTM);
++      _cairo_quartz_draw_image (&state, op);
++    } else if (state.action == DO_SHADING) {
++      CGContextReplacePathWithStrokedPath (state.context);
++      CGContextClip (state.context);
++
++      CGContextSetCTM (state.context, origCTM);
++
++      CGContextConcatCTM (state.context, state.transform);
++      CGContextDrawShading (state.context, state.shading);
++    } else if (state.action != DO_NOTHING) {
+       rv = CAIRO_INT_STATUS_UNSUPPORTED;
++      goto BAIL;
+     }
+
+-    _cairo_quartz_teardown_source (surface, source);
+-
+-    CGContextRestoreGState (surface->cgContext);
+-
+     if (path_for_unbounded) {
+       unbounded_op_data_t ub;
+       ub.op = UNBOUNDED_STROKE_FILL;
+       ub.u.stroke_fill.fill_rule = CAIRO_FILL_RULE_WINDING;
+
+-      CGContextBeginPath (surface->cgContext);
+-      CGContextAddPath (surface->cgContext, path_for_unbounded);
++      CGContextBeginPath (state.context);
++      CGContextAddPath (state.context, path_for_unbounded);
+       CGPathRelease (path_for_unbounded);
+
+-      CGContextSaveGState (surface->cgContext);
+-      CGContextConcatCTM (surface->cgContext, strokeTransform);
+-      CGContextReplacePathWithStrokedPath (surface->cgContext);
+-      CGContextRestoreGState (surface->cgContext);
++      CGContextSaveGState (state.context);
++      CGContextConcatCTM (state.context, strokeTransform);
++      CGContextReplacePathWithStrokedPath (state.context);
++      CGContextRestoreGState (state.context);
+
+-      ub.u.stroke_fill.cgPath = CGContextCopyPathPtr (surface->cgContext);
++      ub.u.stroke_fill.cgPath = CGContextCopyPathPtr (state.context);
+
+       _cairo_quartz_fixup_unbounded_operation (surface, &ub, antialias);
+       CGPathRelease (ub.u.stroke_fill.cgPath);
+     }
+
++  BAIL:
++    _cairo_quartz_teardown_state (&state);
++
+     ND((stderr, "-- stroke\n"));
+     return rv;
+ }
+@@ -2490,18 +2705,22 @@ _cairo_quartz_surface_show_glyphs_cg (vo
+     CGGlyph glyphs_static[STATIC_BUF_SIZE];
+     CGSize cg_advances_static[STATIC_BUF_SIZE];
+     CGGlyph *cg_glyphs = &glyphs_static[0];
++    /* We'll use the cg_advances array for either advances or positions,
++       depending which API we're using to actually draw. The types involved
++       have the same size, so this is safe. */
+     CGSize *cg_advances = &cg_advances_static[0];
+
+     cairo_rectangle_int_t glyph_extents;
+     cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
+     cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
+-    cairo_quartz_action_t action;
++    cairo_quartz_drawing_state_t state;
+     cairo_quartz_float_t xprev, yprev;
+     int i;
+     CGFontRef cgfref = NULL;
+
+     cairo_bool_t isClipping = FALSE;
+     cairo_bool_t didForceFontSmoothing = FALSE;
++    cairo_antialias_t effective_antialiasing;
+
+     if (IS_EMPTY(surface))
+       return CAIRO_STATUS_SUCCESS;
+@@ -2516,54 +2735,51 @@ _cairo_quartz_surface_show_glyphs_cg (vo
+     if (unlikely (rv))
+       return rv;
+
+-    rv = _cairo_quartz_surface_set_cairo_operator (surface, op);
+-    if (unlikely (rv))
+-      return rv == CAIRO_INT_STATUS_NOTHING_TO_DO ? CAIRO_STATUS_SUCCESS : rv;
+-
+-    CGContextSaveGState (surface->cgContext);
+-
+     if (_cairo_quartz_source_needs_extents (source) &&
+       !_cairo_scaled_font_glyph_device_extents (scaled_font, glyphs, num_glyphs,
+                                                 &glyph_extents, NULL))
+     {
+-        action = _cairo_quartz_setup_source (surface, source, &glyph_extents);
++        state = _cairo_quartz_setup_state (surface, source, op, &glyph_extents);
+     } else {
+-        action = _cairo_quartz_setup_source (surface, source, NULL);
++        state = _cairo_quartz_setup_state (surface, source, op, NULL);
+     }
+
+-    if (action == DO_SOLID || action == DO_PATTERN) {
+-      CGContextSetTextDrawingMode (surface->cgContext, kCGTextFill);
+-    } else if (action == DO_IMAGE || action == DO_TILED_IMAGE || action == DO_SHADING) {
+-      CGContextSetTextDrawingMode (surface->cgContext, kCGTextClip);
++    if (state.action == DO_SOLID || state.action == DO_PATTERN) {
++      CGContextSetTextDrawingMode (state.context, kCGTextFill);
++    } else if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE ||
++               state.action == DO_SHADING || state.action == DO_LAYER) {
++      CGContextSetTextDrawingMode (state.context, kCGTextClip);
+       isClipping = TRUE;
+     } else {
+-      if (action != DO_NOTHING)
++      if (state.action != DO_NOTHING)
+           rv = CAIRO_INT_STATUS_UNSUPPORTED;
+       goto BAIL;
+     }
+
+     /* this doesn't addref */
+     cgfref = _cairo_quartz_scaled_font_get_cg_font_ref (scaled_font);
+-    CGContextSetFont (surface->cgContext, cgfref);
+-    CGContextSetFontSize (surface->cgContext, 1.0);
++    CGContextSetFont (state.context, cgfref);
++    CGContextSetFontSize (state.context, 1.0);
++
++    effective_antialiasing = scaled_font->options.antialias;
+
+     switch (scaled_font->options.antialias) {
+       case CAIRO_ANTIALIAS_SUBPIXEL:
+-          CGContextSetShouldAntialias (surface->cgContext, TRUE);
+-          CGContextSetShouldSmoothFonts (surface->cgContext, TRUE);
++          CGContextSetShouldAntialias (state.context, TRUE);
++          CGContextSetShouldSmoothFonts (state.context, TRUE);
+           if (CGContextSetAllowsFontSmoothingPtr &&
+-              !CGContextGetAllowsFontSmoothingPtr (surface->cgContext))
++              !CGContextGetAllowsFontSmoothingPtr (state.context))
+           {
+               didForceFontSmoothing = TRUE;
+-              CGContextSetAllowsFontSmoothingPtr (surface->cgContext, TRUE);
++              CGContextSetAllowsFontSmoothingPtr (state.context, TRUE);
+           }
+           break;
+       case CAIRO_ANTIALIAS_NONE:
+-          CGContextSetShouldAntialias (surface->cgContext, FALSE);
++          CGContextSetShouldAntialias (state.context, FALSE);
+           break;
+       case CAIRO_ANTIALIAS_GRAY:
+-          CGContextSetShouldAntialias (surface->cgContext, TRUE);
+-          CGContextSetShouldSmoothFonts (surface->cgContext, FALSE);
++          CGContextSetShouldAntialias (state.context, TRUE);
++          CGContextSetShouldSmoothFonts (state.context, FALSE);
+           break;
+       case CAIRO_ANTIALIAS_DEFAULT:
+           /* Don't do anything */
+@@ -2584,57 +2800,84 @@ _cairo_quartz_surface_show_glyphs_cg (vo
+       }
+     }
+
++    /* scale(1,-1) * scaled_font->scale */
+     textTransform = CGAffineTransformMake (scaled_font->scale.xx,
+                                          scaled_font->scale.yx,
+                                          -scaled_font->scale.xy,
+                                          -scaled_font->scale.yy,
+                                          0, 0);
+-    _cairo_quartz_cairo_matrix_to_quartz (&scaled_font->scale_inverse, &invTextTransform);
+
+-    CGContextSetTextMatrix (surface->cgContext, CGAffineTransformIdentity);
++    /* scaled_font->scale_inverse * scale(1,-1) */
++    invTextTransform = CGAffineTransformMake (scaled_font->scale_inverse.xx,
++                                            -scaled_font->scale_inverse.yx,
++                                            scaled_font->scale_inverse.xy,
++                                            -scaled_font->scale_inverse.yy,
++                                            0.0, 0.0);
+
+-    /* Convert our glyph positions to glyph advances.  We need n-1 advances,
+-     * since the advance at index 0 is applied after glyph 0. */
+-    xprev = glyphs[0].x;
+-    yprev = glyphs[0].y;
+-
+-    cg_glyphs[0] = glyphs[0].index;
+-
+-    for (i = 1; i < num_glyphs; i++) {
+-      cairo_quartz_float_t xf = glyphs[i].x;
+-      cairo_quartz_float_t yf = glyphs[i].y;
+-      cg_glyphs[i] = glyphs[i].index;
+-      cg_advances[i - 1] = CGSizeApplyAffineTransform(CGSizeMake (xf - xprev, yf - yprev), invTextTransform);
+-      xprev = xf;
+-      yprev = yf;
+-    }
++    CGContextSetTextMatrix (state.context, CGAffineTransformIdentity);
+
+     /* Translate to the first glyph's position before drawing */
+-    ctm = CGContextGetCTM (surface->cgContext);
+-    CGContextTranslateCTM (surface->cgContext, glyphs[0].x, glyphs[0].y);
+-    CGContextConcatCTM (surface->cgContext, textTransform);
+-
+-    CGContextShowGlyphsWithAdvances (surface->cgContext,
+-                                   cg_glyphs,
+-                                   cg_advances,
+-                                   num_glyphs);
+-
+-    CGContextSetCTM (surface->cgContext, ctm);
++    ctm = CGContextGetCTM (state.context);
++    CGContextTranslateCTM (state.context, glyphs[0].x, glyphs[0].y);
++    CGContextConcatCTM (state.context, textTransform);
++
++    if (CTFontDrawGlyphsPtr) {
++        /* If CTFontDrawGlyphs is available (i.e. OS X 10.7 or later), we want to use
++         * that in preference to CGContextShowGlyphsWithAdvances so that colored-bitmap
++         * fonts like Apple Color Emoji will render properly.
++         * For this, we need to convert our glyph positions to Core Graphics's CGPoint.
++         * We borrow the cg_advances array, as CGPoint and CGSize are the same size. */
++
++        CGPoint *cg_positions = (CGPoint*) cg_advances;
++        cairo_quartz_float_t origin_x = glyphs[0].x;
++        cairo_quartz_float_t origin_y = glyphs[0].y;
++
++        for (i = 0; i < num_glyphs; i++) {
++            CGPoint pt = CGPointMake (glyphs[i].x - origin_x, glyphs[i].y - origin_y);
++            cg_positions[i] = CGPointApplyAffineTransform (pt, invTextTransform);
++            cg_glyphs[i] = glyphs[i].index;
++        }
+
+-    if (action == DO_IMAGE || action == DO_TILED_IMAGE) {
+-      _cairo_quartz_draw_image (surface, op, action);
+-    } else if (action == DO_SHADING) {
+-      CGContextConcatCTM (surface->cgContext, surface->sourceTransform);
+-      CGContextDrawShading (surface->cgContext, surface->sourceShading);
++        CTFontDrawGlyphsPtr (_cairo_quartz_scaled_font_get_ct_font_ref (scaled_font),
++                             cg_glyphs, cg_positions, num_glyphs, state.context);
++    } else {
++        /* Convert our glyph positions to glyph advances.  We need n-1 advances,
++         * since the advance at index 0 is applied after glyph 0. */
++        xprev = glyphs[0].x;
++        yprev = glyphs[0].y;
++
++        cg_glyphs[0] = glyphs[0].index;
++
++        for (i = 1; i < num_glyphs; i++) {
++          cairo_quartz_float_t xf = glyphs[i].x;
++          cairo_quartz_float_t yf = glyphs[i].y;
++          cg_glyphs[i] = glyphs[i].index;
++          cg_advances[i - 1] = CGSizeApplyAffineTransform(CGSizeMake (xf - xprev, yf - yprev), invTextTransform);
++          xprev = xf;
++          yprev = yf;
++        }
++
++        CGContextShowGlyphsWithAdvances (state.context,
++                                       cg_glyphs,
++                                       cg_advances,
++                                       num_glyphs);
++    }
++
++    CGContextSetCTM (state.context, ctm);
++
++    if (state.action == DO_IMAGE || state.action == DO_TILED_IMAGE ||
++        state.action == DO_LAYER) {
++      _cairo_quartz_draw_image (&state, op);
++    } else if (state.action == DO_SHADING) {
++      CGContextConcatCTM (state.context, state.transform);
++      CGContextDrawShading (state.context, state.shading);
+     }
+
+ BAIL:
+-    _cairo_quartz_teardown_source (surface, source);
+-
+     if (didForceFontSmoothing)
+-      CGContextSetAllowsFontSmoothingPtr (surface->cgContext, FALSE);
++        CGContextSetAllowsFontSmoothingPtr (state.context, FALSE);
+
+-    CGContextRestoreGState (surface->cgContext);
++    _cairo_quartz_teardown_state (&state);
+
+     if (rv == CAIRO_STATUS_SUCCESS &&
+       cgfref &&
+@@ -2645,10 +2888,17 @@ BAIL:
+
+       ub.u.show_glyphs.isClipping = isClipping;
+       ub.u.show_glyphs.cg_glyphs = cg_glyphs;
+-      ub.u.show_glyphs.cg_advances = cg_advances;
++      if (CTFontDrawGlyphsPtr) {
++          /* we're using Core Text API: the cg_advances array was
++             reused (above) for glyph positions */
++            CGPoint *cg_positions = (CGPoint*) cg_advances;
++          ub.u.show_glyphs.u.cg_positions = cg_positions;
++      } else {
++          ub.u.show_glyphs.u.cg_advances = cg_advances;
++      }
+       ub.u.show_glyphs.nglyphs = num_glyphs;
+       ub.u.show_glyphs.textTransform = textTransform;
+-      ub.u.show_glyphs.font = cgfref;
++      ub.u.show_glyphs.scaled_font = scaled_font;
+       ub.u.show_glyphs.origin = CGPointMake (glyphs[0].x, glyphs[0].y);
+
+       _cairo_quartz_fixup_unbounded_operation (surface, &ub, scaled_font->options.antialias);
+@@ -2717,7 +2967,7 @@ _cairo_quartz_surface_mask_with_surface
+     cairo_status_t status = CAIRO_STATUS_SUCCESS;
+     CGAffineTransform ctm, mask_matrix;
+
+-    status = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf, &img);
++    status = _cairo_surface_to_cgimage (pat_surf, &img);
+     if (status)
+       return status;
+     if (img == NULL) {
+@@ -2820,7 +3070,9 @@ _cairo_quartz_surface_mask_cg (void *abs
+     if (unlikely (rv))
+       return rv;
+
+-    if (mask->type == CAIRO_PATTERN_TYPE_SOLID) {
++    /* Using CGContextSetAlpha to implement mask alpha doesn't work for all operators. */
++    if (mask->type == CAIRO_PATTERN_TYPE_SOLID &&
++        op == CAIRO_OPERATOR_OVER) {
+       /* This is easy; we just need to paint with the alpha. */
+       cairo_solid_pattern_t *solid_mask = (cairo_solid_pattern_t *) mask;
+
+@@ -2834,8 +3086,11 @@ _cairo_quartz_surface_mask_cg (void *abs
+     /* If we have CGContextClipToMask, we can do more complex masks */
+     if (CGContextClipToMaskPtr) {
+       /* For these, we can skip creating a temporary surface, since we already have one */
+-      if (mask->type == CAIRO_PATTERN_TYPE_SURFACE && mask->extend == CAIRO_EXTEND_NONE)
++      /* For some reason this doesn't work reliably on OS X 10.5.  See bug 721663. */
++      if (_cairo_quartz_osx_version >= 0x1060 && mask->type == CAIRO_PATTERN_TYPE_SURFACE &&
++          mask->extend == CAIRO_EXTEND_NONE) {
+           return _cairo_quartz_surface_mask_with_surface (surface, op, source, (cairo_surface_pattern_t *) mask, clip);
++      }
+
+       return _cairo_quartz_surface_mask_with_generic (surface, op, source, mask, clip);
+     }
+@@ -2920,13 +3175,24 @@ _cairo_quartz_surface_clipper_intersect_
+     return CAIRO_STATUS_SUCCESS;
+ }
+
++static cairo_status_t
++_cairo_quartz_surface_mark_dirty_rectangle (void *abstract_surface,
++                                          int x, int y,
++                                          int width, int height)
++{
++    cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
++    _cairo_quartz_surface_will_change (surface);
++    return CAIRO_STATUS_SUCCESS;
++}
++
++
+ // XXXtodo implement show_page; need to figure out how to handle begin/end
+
+ static const struct _cairo_surface_backend cairo_quartz_surface_backend = {
+     CAIRO_SURFACE_TYPE_QUARTZ,
+     _cairo_quartz_surface_create_similar,
+     _cairo_quartz_surface_finish,
+-    _cairo_quartz_surface_acquire_source_image,
++    _cairo_quartz_surface_acquire_image,
+     _cairo_quartz_surface_release_source_image,
+     _cairo_quartz_surface_acquire_dest_image,
+     _cairo_quartz_surface_release_dest_image,
+@@ -2942,7 +3208,7 @@ static const struct _cairo_surface_backe
+     NULL, /* old_show_glyphs */
+     NULL, /* get_font_options */
+     NULL, /* flush */
+-    NULL, /* mark_dirty_rectangle */
++    _cairo_quartz_surface_mark_dirty_rectangle,
+     NULL, /* scaled_font_fini */
+     NULL, /* scaled_glyph_fini */
+
+@@ -2952,7 +3218,7 @@ static const struct _cairo_surface_backe
+     _cairo_quartz_surface_fill,
+     _cairo_quartz_surface_show_glyphs,
+
+-    _cairo_quartz_surface_snapshot,
++    NULL, /* snapshot */
+     NULL, /* is_similar */
+     NULL  /* fill_stroke */
+ };
+@@ -3004,6 +3270,9 @@ _cairo_quartz_surface_create_internal (C
+
+     surface->imageData = NULL;
+     surface->imageSurfaceEquiv = NULL;
++    surface->bitmapContextImage = NULL;
++    surface->cgLayer = NULL;
++    surface->ownsData = TRUE;
+
+     return surface;
+ }
+@@ -3056,6 +3325,81 @@ cairo_quartz_surface_create_for_cg_conte
+ }
+
+ /**
++ * cairo_quartz_cglayer_surface_create_similar
++ * @surface: The returned surface can be efficiently drawn into this
++ * destination surface (if tiling is not used)."
++ * @content: the content type of the surface
++ * @width: width of the surface, in pixels
++ * @height: height of the surface, in pixels
++ *
++ * Creates a Quartz surface backed by a CGLayer, if the given surface
++ * is a Quartz surface; the CGLayer is created to match the surface's
++ * Quartz context. Otherwise just calls cairo_surface_create_similar.
++ * The returned surface can be efficiently blitted to the given surface,
++ * but tiling and 'extend' modes other than NONE are not so efficient.
++ *
++ * Return value: the newly created surface.
++ *
++ * Since: 1.10
++ **/
++cairo_surface_t *
++cairo_quartz_surface_create_cg_layer (cairo_surface_t *surface,
++                                      cairo_content_t content,
++                                      unsigned int width,
++                                      unsigned int height)
++{
++    cairo_quartz_surface_t *surf;
++    CGLayerRef layer;
++    CGContextRef ctx;
++    CGContextRef cgContext;
++
++    cgContext = cairo_quartz_surface_get_cg_context (surface);
++    if (!cgContext)
++      return cairo_surface_create_similar (surface, content,
++                                             width, height);
++
++
++    if (!_cairo_quartz_verify_surface_size(width, height))
++        return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
++
++    /* If we pass zero width or height into CGLayerCreateWithContext below,
++     * it will fail.
++     */
++    if (width == 0 || height == 0) {
++        return (cairo_surface_t*)
++            _cairo_quartz_surface_create_internal (NULL, content,
++                                                   width, height);
++    }
++
++    layer = CGLayerCreateWithContext (cgContext,
++                                      CGSizeMake (width, height),
++                                      NULL);
++    if (!layer)
++      return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
++
++    ctx = CGLayerGetContext (layer);
++    CGContextSetInterpolationQuality (ctx, kCGInterpolationNone);
++    /* Flip it when we draw into it, so that when we finally composite it
++     * to a flipped target, the directions match and Quartz will optimize
++     * the composition properly
++     */
++    CGContextTranslateCTM (ctx, 0, height);
++    CGContextScaleCTM (ctx, 1, -1);
++
++    CGContextRetain (ctx);
++    surf = _cairo_quartz_surface_create_internal (ctx, content,
++                                                  width, height);
++    if (surf->base.status) {
++        CGLayerRelease (layer);
++        // create_internal will have set an error
++        return (cairo_surface_t*) surf;
++    }
++    surf->cgLayer = layer;
++
++    return (cairo_surface_t *) surf;
++}
++
++/**
+  * cairo_quartz_surface_create
+  * @format: format of pixels in the surface to create
+  * @width: width of the surface, in pixels
+@@ -3075,13 +3419,93 @@ cairo_quartz_surface_create (cairo_forma
+                            unsigned int width,
+                            unsigned int height)
+ {
++    int stride;
++    unsigned char *data;
++
++    if (!_cairo_quartz_verify_surface_size(width, height))
++      return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
++
++    if (width == 0 || height == 0) {
++      return (cairo_surface_t*) _cairo_quartz_surface_create_internal (NULL, _cairo_content_from_format (format),
++                                                                       width, height);
++    }
++
++    if (format == CAIRO_FORMAT_ARGB32 ||
++      format == CAIRO_FORMAT_RGB24)
++    {
++      stride = width * 4;
++    } else if (format == CAIRO_FORMAT_A8) {
++      stride = width;
++    } else if (format == CAIRO_FORMAT_A1) {
++      /* I don't think we can usefully support this, as defined by
++       * cairo_format_t -- these are 1-bit pixels stored in 32-bit
++       * quantities.
++       */
++      return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
++    } else {
++      return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
++    }
++
++    /* The Apple docs say that for best performance, the stride and the data
++     * pointer should be 16-byte aligned.  malloc already aligns to 16-bytes,
++     * so we don't have to anything special on allocation.
++     */
++    stride = (stride + 15) & ~15;
++
++    data = _cairo_malloc_ab (height, stride);
++    if (!data) {
++      return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
++    }
++
++    /* zero the memory to match the image surface behaviour */
++    memset (data, 0, height * stride);
++
++    cairo_quartz_surface_t *surf;
++    surf = (cairo_quartz_surface_t *) cairo_quartz_surface_create_for_data
++                                           (data, format, width, height, stride);
++    if (surf->base.status) {
++        free (data);
++        return (cairo_surface_t *) surf;
++    }
++
++    // We created this data, so we can delete it.
++    surf->ownsData = TRUE;
++
++    return (cairo_surface_t *) surf;
++}
++
++/**
++ * cairo_quartz_surface_create_for_data
++ * @data: a pointer to a buffer supplied by the application in which
++ *     to write contents. This pointer must be suitably aligned for any
++ *     kind of variable, (for example, a pointer returned by malloc).
++ * @format: format of pixels in the surface to create
++ * @width: width of the surface, in pixels
++ * @height: height of the surface, in pixels
++ *
++ * Creates a Quartz surface backed by a CGBitmap.  The surface is
++ * created using the Device RGB (or Device Gray, for A8) color space.
++ * All Cairo operations, including those that require software
++ * rendering, will succeed on this surface.
++ *
++ * Return value: the newly created surface.
++ *
++ * Since: 1.12
++ **/
++cairo_surface_t *
++cairo_quartz_surface_create_for_data (unsigned char *data,
++                                    cairo_format_t format,
++                                    unsigned int width,
++                                    unsigned int height,
++                                    unsigned int stride)
++{
+     cairo_quartz_surface_t *surf;
+     CGContextRef cgc;
+     CGColorSpaceRef cgColorspace;
+     CGBitmapInfo bitinfo;
+-    void *imageData;
+-    int stride;
++    void *imageData = data;
+     int bitsPerComponent;
++    unsigned int i;
+
+     // verify width and height of surface
+     if (!_cairo_quartz_verify_surface_size(width, height))
+@@ -3102,10 +3526,8 @@ cairo_quartz_surface_create (cairo_forma
+       else
+           bitinfo |= kCGImageAlphaNoneSkipFirst;
+       bitsPerComponent = 8;
+-      stride = width * 4;
+     } else if (format == CAIRO_FORMAT_A8) {
+       cgColorspace = NULL;
+-      stride = width;
+       bitinfo = kCGImageAlphaOnly;
+       bitsPerComponent = 8;
+     } else if (format == CAIRO_FORMAT_A1) {
+@@ -3118,21 +3540,6 @@ cairo_quartz_surface_create (cairo_forma
+       return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
+     }
+
+-    /* The Apple docs say that for best performance, the stride and the data
+-     * pointer should be 16-byte aligned.  malloc already aligns to 16-bytes,
+-     * so we don't have to anything special on allocation.
+-     */
+-    stride = (stride + 15) & ~15;
+-
+-    imageData = _cairo_malloc_ab (height, stride);
+-    if (!imageData) {
+-      CGColorSpaceRelease (cgColorspace);
+-      return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+-    }
+-
+-    /* zero the memory to match the image surface behaviour */
+-    memset (imageData, 0, height * stride);
+-
+     cgc = CGBitmapContextCreate (imageData,
+                                width,
+                                height,
+@@ -3161,7 +3568,19 @@ cairo_quartz_surface_create (cairo_forma
+     }
+
+     surf->imageData = imageData;
+-    surf->imageSurfaceEquiv = cairo_image_surface_create_for_data (imageData, format, width, height, stride);
++
++    cairo_surface_t* tmpImageSurfaceEquiv =
++      cairo_image_surface_create_for_data (imageData, format,
++                                           width, height, stride);
++
++    if (cairo_surface_status (tmpImageSurfaceEquiv)) {
++        // Tried & failed to create an imageSurfaceEquiv!
++        cairo_surface_destroy (tmpImageSurfaceEquiv);
++        surf->imageSurfaceEquiv = NULL;
++    } else {
++        surf->imageSurfaceEquiv = tmpImageSurfaceEquiv;
++        surf->ownsData = FALSE;
++    }
+
+     return (cairo_surface_t *) surf;
+ }
+@@ -3193,6 +3612,74 @@ _cairo_surface_is_quartz (const cairo_su
+     return surface->backend == &cairo_quartz_surface_backend;
+ }
+
++CGContextRef
++cairo_quartz_get_cg_context_with_clip (cairo_t *cr)
++{
++
++    cairo_surface_t *surface = cr->gstate->target;
++    cairo_clip_t *clip = &cr->gstate->clip;
++    cairo_status_t status;
++
++    cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t*)surface;
++
++    if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_QUARTZ)
++      return NULL;
++
++    if (!clip->path) {
++      if (clip->all_clipped) {
++          /* Save the state before we set an empty clip rect so that
++           * our previous clip will be restored */
++
++          /* _cairo_surface_clipper_set_clip doesn't deal with
++           * clip->all_clipped because drawing is normally discarded earlier */
++          CGRect empty = {{0,0}, {0,0}};
++          CGContextClipToRect (quartz->cgContext, empty);
++          CGContextSaveGState (quartz->cgContext);
++
++          return quartz->cgContext;
++      }
++
++      /* an empty clip is represented by NULL */
++      clip = NULL;
++    }
++
++    status = _cairo_surface_clipper_set_clip (&quartz->clipper, clip);
++
++    /* Save the state after we set the clip so that it persists
++     * after we restore */
++    CGContextSaveGState (quartz->cgContext);
++
++    if (unlikely (status))
++      return NULL;
++
++    return quartz->cgContext;
++}
++
++void
++cairo_quartz_finish_cg_context_with_clip (cairo_t *cr)
++{
++    cairo_surface_t *surface = cr->gstate->target;
++
++    cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t*)surface;
++
++    if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_QUARTZ)
++      return;
++
++    CGContextRestoreGState (quartz->cgContext);
++}
++
++cairo_surface_t *
++cairo_quartz_surface_get_image (cairo_surface_t *surface)
++{
++    cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t *)surface;
++    cairo_image_surface_t *image;
++
++    if (_cairo_quartz_get_image(quartz, &image))
++        return NULL;
++
++    return (cairo_surface_t *)image;
++}
++
+ /* Debug stuff */
+
+ #ifdef QUARTZ_DEBUG
+--- a/src/cairo-quartz.h       2012-11-13 18:20:00.000000000 -0800
++++ b/src/cairo-quartz.h       2012-11-13 18:06:56.000000000 -0800
+@@ -50,6 +50,19 @@ cairo_quartz_surface_create (cairo_forma
+                              unsigned int height);
+
+ cairo_public cairo_surface_t *
++cairo_quartz_surface_create_for_data (unsigned char *data,
++                                    cairo_format_t format,
++                                    unsigned int width,
++                                    unsigned int height,
++                                    unsigned int stride);
++
++cairo_public cairo_surface_t *
++cairo_quartz_surface_create_cg_layer (cairo_surface_t *surface,
++                                      cairo_content_t content,
++                                      unsigned int width,
++                                      unsigned int height);
++
++cairo_public cairo_surface_t *
+ cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext,
+                                             unsigned int width,
+                                             unsigned int height);
+@@ -57,6 +70,15 @@ cairo_quartz_surface_create_for_cg_conte
+ cairo_public CGContextRef
+ cairo_quartz_surface_get_cg_context (cairo_surface_t *surface);
+
++cairo_public CGContextRef
++cairo_quartz_get_cg_context_with_clip (cairo_t *cr);
++
++cairo_public void
++cairo_quartz_finish_cg_context_with_clip (cairo_t *cr);
++
++cairo_public cairo_surface_t *
++cairo_quartz_surface_get_image (cairo_surface_t *surface);
++
+ #if CAIRO_HAS_QUARTZ_FONT
+
+ /*
+@@ -66,8 +88,10 @@ cairo_quartz_surface_get_cg_context (cai
+ cairo_public cairo_font_face_t *
+ cairo_quartz_font_face_create_for_cgfont (CGFontRef font);
+
++#ifndef __LP64__
+ cairo_public cairo_font_face_t *
+ cairo_quartz_font_face_create_for_atsu_font_id (ATSUFontID font_id);
++#endif
+
+ #endif /* CAIRO_HAS_QUARTZ_FONT */
\ No newline at end of file
diff --git a/bockbuild/mac-sdk/patches/cairo-fix-CGFontGetGlyphPath-deprecation.patch b/bockbuild/mac-sdk/patches/cairo-fix-CGFontGetGlyphPath-deprecation.patch
new file mode 100644 (file)
index 0000000..66dc48a
--- /dev/null
@@ -0,0 +1,67 @@
+From 9d460070fca2c0a61aac60ba7cad6f9a6af82309 Mon Sep 17 00:00:00 2001
+From: Andrea Canciani <ranma42@gmail.com>
+Date: Tue, 9 Dec 2014 16:13:00 +0100
+Subject: [PATCH] quartz: Remove call to obsolete CGFontGetGlyphPath
+
+CGFontGetGlyphPath was not public and is not available anymore on
+modern OSX/iOS systems. The same functionality is available through
+the CoreText API since OSX 10.5.
+
+Based on a patch by Simon Cozens.
+
+Fixes https://bugs.freedesktop.org/show_bug.cgi?id=84324
+---
+ src/cairo-quartz-font.c | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+diff --git a/src/cairo-quartz-font.c b/src/cairo-quartz-font.c
+index e6a379a..02f3426 100644
+--- a/src/cairo-quartz-font.c
++++ b/src/cairo-quartz-font.c
+@@ -81,9 +81,6 @@ static void (*CGFontGetGlyphsForUnicharsPtr) (CGFontRef, const UniChar[], const
+ static void (*CGContextSetAllowsFontSmoothingPtr) (CGContextRef, bool) = NULL;
+ static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL;
+
+-/* Not public in the least bit */
+-static CGPathRef (*CGFontGetGlyphPathPtr) (CGFontRef fontRef, CGAffineTransform *textTransform, int unknown, CGGlyph glyph) = NULL;
+-
+ /* CGFontGetHMetrics isn't public, but the other functions are public/present in 10.5 */
+ typedef struct {
+     int ascent;
+@@ -127,7 +124,6 @@ quartz_font_ensure_symbols(void)
+     /* These have the same name in 10.4 and 10.5 */
+     CGFontGetUnitsPerEmPtr = dlsym(RTLD_DEFAULT, "CGFontGetUnitsPerEm");
+     CGFontGetGlyphAdvancesPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphAdvances");
+-    CGFontGetGlyphPathPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphPath");
+
+     CGFontGetHMetricsPtr = dlsym(RTLD_DEFAULT, "CGFontGetHMetrics");
+     CGFontGetAscentPtr = dlsym(RTLD_DEFAULT, "CGFontGetAscent");
+@@ -144,7 +140,6 @@ quartz_font_ensure_symbols(void)
+       CGFontGetGlyphsForUnicharsPtr &&
+       CGFontGetUnitsPerEmPtr &&
+       CGFontGetGlyphAdvancesPtr &&
+-      CGFontGetGlyphPathPtr &&
+       (CGFontGetHMetricsPtr || (CGFontGetAscentPtr && CGFontGetDescentPtr && CGFontGetLeadingPtr)))
+       _cairo_quartz_font_symbols_present = TRUE;
+
+@@ -550,6 +545,7 @@ _cairo_quartz_init_glyph_path (cairo_quartz_scaled_font_t *font,
+     CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph);
+     CGAffineTransform textMatrix;
+     CGPathRef glyphPath;
++    CTFontRef ctFont;
+     cairo_path_fixed_t *path;
+
+     if (glyph == INVALID_GLYPH) {
+@@ -564,7 +560,9 @@ _cairo_quartz_init_glyph_path (cairo_quartz_scaled_font_t *font,
+                                       -font->base.scale.yy,
+                                       0, 0);
+
+-    glyphPath = CGFontGetGlyphPathPtr (font_face->cgFont, &textMatrix, 0, glyph);
++    ctFont = CTFontCreateWithGraphicsFont (font_face->cgFont, 1.0, NULL, NULL);
++    glyphPath = CTFontCreatePathForGlyph (ctFont, glyph, &textMatrix);
++    CFRelease (ctFont);
+     if (!glyphPath)
+       return CAIRO_INT_STATUS_UNSUPPORTED;
+
+--
+1.9.3 (Apple Git-50)
diff --git a/bockbuild/mac-sdk/patches/cairo-fix-color-bitmap-fonts.patch b/bockbuild/mac-sdk/patches/cairo-fix-color-bitmap-fonts.patch
new file mode 100644 (file)
index 0000000..3860cc6
--- /dev/null
@@ -0,0 +1,189 @@
+diff --git a/src/cairo-quartz-font.c b/src/cairo-quartz-font.c
+index a9bbbdc..48eb071 100644
+--- a/src/cairo-quartz-font.c
++++ b/src/cairo-quartz-font.c
+@@ -95,6 +95,10 @@ static int (*CGFontGetAscentPtr) (CGFontRef fontRef) = NULL;
+ static int (*CGFontGetDescentPtr) (CGFontRef fontRef) = NULL;
+ static int (*CGFontGetLeadingPtr) (CGFontRef fontRef) = NULL;
+
++/* CTFontCreateWithGraphicsFont is not public until 10.5. */
++typedef const struct __CTFontDescriptor *CTFontDescriptorRef;
++static CTFontRef (*CTFontCreateWithGraphicsFontPtr) (CGFontRef, CGFloat, const CGAffineTransform *, CTFontDescriptorRef) = NULL;
++
+ /* Not public anymore in 64-bits nor in 10.7 */
+ static ATSFontRef (*FMGetATSFontRefFromFontPtr) (FMFont iFont) = NULL;
+
+@@ -137,6 +141,8 @@ quartz_font_ensure_symbols(void)
+     CGContextGetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");
+     CGContextSetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing");
+
++    CTFontCreateWithGraphicsFontPtr = dlsym(RTLD_DEFAULT, "CTFontCreateWithGraphicsFont");
++
+     FMGetATSFontRefFromFontPtr = dlsym(RTLD_DEFAULT, "FMGetATSFontRefFromFont");
+
+     if ((CGFontCreateWithFontNamePtr || CGFontCreateWithNamePtr) &&
+@@ -162,6 +168,7 @@ struct _cairo_quartz_font_face {
+     cairo_font_face_t base;
+
+     CGFontRef cgFont;
++    CTFontRef ctFont;
+ };
+
+ /*
+@@ -246,6 +253,10 @@ _cairo_quartz_font_face_destroy (void *abstract_face)
+ {
+     cairo_quartz_font_face_t *font_face = (cairo_quartz_font_face_t*) abstract_face;
+
++    if (font_face->ctFont) {
++        CFRelease (font_face->ctFont);
++    }
++
+     CGFontRelease (font_face->cgFont);
+ }
+
+@@ -370,6 +381,12 @@ cairo_quartz_font_face_create_for_cgfont (CGFontRef font)
+
+     font_face->cgFont = CGFontRetain (font);
+
++    if (CTFontCreateWithGraphicsFontPtr) {
++        font_face->ctFont = CTFontCreateWithGraphicsFontPtr (font, 1.0, NULL, NULL);
++    } else {
++        font_face->ctFont = NULL;
++    }
++
+     _cairo_font_face_init (&font_face->base, &_cairo_quartz_font_face_backend);
+
+     return &font_face->base;
+@@ -812,6 +829,14 @@ _cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *abstract_font)
+     return ffont->cgFont;
+ }
+
++CTFontRef
++_cairo_quartz_scaled_font_get_ct_font_ref (cairo_scaled_font_t *abstract_font)
++{
++    cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(abstract_font);
++
++    return ffont->ctFont;
++}
++
+ /*
+  * compat with old ATSUI backend
+  */
+diff --git a/src/cairo-quartz-private.h b/src/cairo-quartz-private.h
+index f841a49..3c1e5aa 100644
+--- a/src/cairo-quartz-private.h
++++ b/src/cairo-quartz-private.h
+@@ -57,6 +57,9 @@ typedef enum {
+     DO_TILED_IMAGE
+ } cairo_quartz_action_t;
+
++/* define CTFontRef for pre-10.5 SDKs */
++typedef const struct __CTFont *CTFontRef;
++
+ typedef struct cairo_quartz_surface {
+     cairo_surface_t base;
+
+@@ -97,6 +100,9 @@ CairoQuartzCreateCGImage (cairo_format_t format,
+ cairo_private CGFontRef
+ _cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *sfont);
+
++CTFontRef
++_cairo_quartz_scaled_font_get_ct_font_ref (cairo_scaled_font_t *sfont);
++
+ #else
+
+ # error Cairo was not compiled with support for the quartz backend
+diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
+index 1e2bbec..417255c 100644
+--- a/src/cairo-quartz-surface.c
++++ b/src/cairo-quartz-surface.c
+@@ -123,6 +123,9 @@ static void (*CGContextSetAllowsFontSmoothingPtr) (CGContextRef, bool) = NULL;
+ static unsigned int (*CGContextGetTypePtr) (CGContextRef) = NULL;
+ static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL;
+
++/* CTFontDrawGlyphs is not available until 10.7 */
++static void (*CTFontDrawGlyphsPtr) (CTFontRef, const CGGlyph[], const CGPoint[], size_t, CGContextRef) = NULL;
++
+ static cairo_bool_t _cairo_quartz_symbol_lookup_done = FALSE;
+
+ /*
+@@ -155,6 +158,8 @@ static void quartz_ensure_symbols (void)
+     CGContextGetAllowsFontSmoothingPtr = dlsym (RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");
+     CGContextSetAllowsFontSmoothingPtr = dlsym (RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing");
+
++    CTFontDrawGlyphsPtr = dlsym(RTLD_DEFAULT, "CTFontDrawGlyphs");
++
+     _cairo_quartz_symbol_lookup_done = TRUE;
+ }
+
+@@ -2026,30 +2031,50 @@ _cairo_quartz_cg_glyphs (const cairo_compositor_t *compositor,
+     CGContextSetTextPosition (state.cgMaskContext, 0.0, 0.0);
+     CGContextSetTextMatrix (state.cgMaskContext, CGAffineTransformIdentity);
+
+-    /* Convert our glyph positions to glyph advances.  We need n-1 advances,
+-     * since the advance at index 0 is applied after glyph 0. */
+-    xprev = glyphs[0].x;
+-    yprev = glyphs[0].y;
+-
+-    cg_glyphs[0] = glyphs[0].index;
+-
+-    for (i = 1; i < num_glyphs; i++) {
+-      cairo_quartz_float_t xf = glyphs[i].x;
+-      cairo_quartz_float_t yf = glyphs[i].y;
+-      cg_glyphs[i] = glyphs[i].index;
+-      cg_advances[i - 1] = CGSizeApplyAffineTransform (CGSizeMake (xf - xprev, yf - yprev), invTextTransform);
+-      xprev = xf;
+-      yprev = yf;
+-    }
+-
+     /* Translate to the first glyph's position before drawing */
+     CGContextTranslateCTM (state.cgMaskContext, glyphs[0].x, glyphs[0].y);
+     CGContextConcatCTM (state.cgMaskContext, textTransform);
+
+-    CGContextShowGlyphsWithAdvances (state.cgMaskContext,
+-                                   cg_glyphs,
+-                                   cg_advances,
+-                                   num_glyphs);
++    if (CTFontDrawGlyphsPtr) {
++        /* If CTFontDrawGlyphs is available (i.e. OS X 10.7 or later), we want to use
++         * that in preference to CGContextShowGlyphsWithAdvances so that colored-bitmap
++         * fonts like Apple Color Emoji will render properly.
++         * For this, we need to convert our glyph positions to Core Graphics's CGPoint.
++         * We borrow the cg_advances array, as CGPoint and CGSize are the same size. */
++
++        CGPoint *cg_positions = (CGPoint*) cg_advances;
++        cairo_quartz_float_t origin_x = glyphs[0].x;
++        cairo_quartz_float_t origin_y = glyphs[0].y;
++
++        for (i = 0; i < num_glyphs; i++) {
++            CGPoint pt = CGPointMake (glyphs[i].x - origin_x, glyphs[i].y - origin_y);
++            cg_positions[i] = CGPointApplyAffineTransform (pt, invTextTransform);
++            cg_glyphs[i] = glyphs[i].index;
++        }
++
++        CTFontDrawGlyphsPtr (_cairo_quartz_scaled_font_get_ct_font_ref (scaled_font),
++                             cg_glyphs, cg_positions, num_glyphs, state.cgMaskContext);
++    } else {
++        /* Convert our glyph positions to glyph advances.  We need n-1 advances,
++         * since the advance at index 0 is applied after glyph 0. */
++        xprev = glyphs[0].x;
++        yprev = glyphs[0].y;
++
++        cg_glyphs[0] = glyphs[0].index;
++
++        for (i = 1; i < num_glyphs; i++) {
++            cairo_quartz_float_t xf = glyphs[i].x;
++            cairo_quartz_float_t yf = glyphs[i].y;
++            cg_glyphs[i] = glyphs[i].index;
++            cg_advances[i - 1] = CGSizeApplyAffineTransform (CGSizeMake (xf - xprev, yf - yprev), invTextTransform);
++            xprev = xf;
++            yprev = yf;
++        }
++        CGContextShowGlyphsWithAdvances (state.cgMaskContext,
++                                         cg_glyphs,
++                                         cg_advances,
++                                         num_glyphs);
++    }
+
+     CGContextConcatCTM (state.cgMaskContext, invTextTransform);
+     CGContextTranslateCTM (state.cgMaskContext, -glyphs[0].x, -glyphs[0].y);
diff --git a/bockbuild/mac-sdk/patches/cairo-quartz-crash.patch b/bockbuild/mac-sdk/patches/cairo-quartz-crash.patch
new file mode 100644 (file)
index 0000000..a1e64f1
--- /dev/null
@@ -0,0 +1,9 @@
+--- a/src/cairo-quartz-surface.c       2013-03-28 19:19:15.000000000 -0400
++++ b/src/cairo-quartz-surface.c       2013-03-28 19:19:28.000000000 -0400
+@@ -1379,7 +1379,6 @@
+       CGContextDrawLayerInRect (surface->cgContext,
+                                 state->clipRect,
+                                 state->layer);
+-      CGContextRelease (state->cgDrawContext);
+       CGLayerRelease (state->layer);
+     }
diff --git a/bockbuild/mac-sdk/patches/find-unused-patches.sh b/bockbuild/mac-sdk/patches/find-unused-patches.sh
new file mode 100755 (executable)
index 0000000..b758c97
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+for f in *.patch; do grep $f ../*.py > /dev/null || echo $f; done
+for f in */*.patch; do grep $f ../*.py > /dev/null || echo $f; done
diff --git a/bockbuild/mac-sdk/patches/fsharp-assemblysearchpath-fix.patch b/bockbuild/mac-sdk/patches/fsharp-assemblysearchpath-fix.patch
new file mode 100644 (file)
index 0000000..305904b
--- /dev/null
@@ -0,0 +1,132 @@
+From b02965711a387b015a6af4b9d26bbdabf10fc5b4 Mon Sep 17 00:00:00 2001
+From: Mikayla Hutchinson <m.j.hutchinson@gmail.com>
+Date: Mon, 1 Aug 2016 13:47:41 -0400
+Subject: [PATCH 1/2] Remove xbuild workarounds
+
+They do not work Mono 4.6+ where the underlying bug is fixed
+---
+ src/FSharpSource.targets | 8 --------
+ 1 file changed, 8 deletions(-)
+
+diff --git a/src/FSharpSource.targets b/src/FSharpSource.targets
+index eb57269..ea3656f 100755
+--- a/src/FSharpSource.targets
++++ b/src/FSharpSource.targets
+@@ -306,8 +306,6 @@ Some other NuGET monikers to support in the future, see http://docs.nuget.org/do
+     <DefineConstants>$(DefineConstants);PUT_TYPE_PROVIDERS_IN_FSCORE</DefineConstants>
+     <DefineConstants>$(DefineConstants);QUERIES_IN_FSLIB</DefineConstants>
+
+-    <!-- An explicit search path seems to be needed on Mono 3.4.0 otherwise the reference assemblies for the profile aren't found -->
+-    <AssemblySearchPaths Condition="Exists('$(MSBuildExtensionsPath32)\..\xbuild-frameworks\.NETPortable\v4.0\mscorlib.dll')">$(MSBuildExtensionsPath32)\..\xbuild-frameworks\.NETPortable\v4.0</AssemblySearchPaths>
+   </PropertyGroup>
+
+   <!-- Target Portable -->
+@@ -348,8 +346,6 @@ Some other NuGET monikers to support in the future, see http://docs.nuget.org/do
+     <TargetProfile>netcore</TargetProfile>
+     <TargetFrameworkProfile>Profile7</TargetFrameworkProfile>
+     <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+-    <!-- An explicit search path seems to be needed on Mono 3.4.0 otherwise the reference assemblies for the profile aren't found -->
+-    <AssemblySearchPaths Condition="Exists('$(MSBuildExtensionsPath32)\..\xbuild-frameworks\.NETPortable\v4.5\System.Runtime.dll')">$(MSBuildExtensionsPath32)\..\xbuild-frameworks\.NETPortable\v4.5</AssemblySearchPaths>
+     <OtherFlags>$(OtherFlags) --targetprofile:netcore</OtherFlags>
+   </PropertyGroup>
+
+@@ -389,8 +385,6 @@ Some other NuGET monikers to support in the future, see http://docs.nuget.org/do
+     <TargetProfile>netcore</TargetProfile>
+     <TargetFrameworkProfile>Profile78</TargetFrameworkProfile>
+     <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+-    <!-- An explicit search path seems to be needed on Mono 3.4.0 otherwise the reference assemblies for the profile aren't found -->
+-    <AssemblySearchPaths Condition="Exists('$(MSBuildExtensionsPath32)\..\xbuild-frameworks\.NETPortable\v4.5\System.Runtime.dll')">$(MSBuildExtensionsPath32)\..\xbuild-frameworks\.NETPortable\v4.5</AssemblySearchPaths>
+     <OtherFlags>$(OtherFlags) --targetprofile:netcore</OtherFlags>
+   </PropertyGroup>
+
+@@ -430,8 +424,6 @@ Some other NuGET monikers to support in the future, see http://docs.nuget.org/do
+     <TargetProfile>netcore</TargetProfile>
+     <TargetFrameworkProfile>Profile259</TargetFrameworkProfile>
+     <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+-    <!-- An explicit search path seems to be needed on Mono 3.4.0 otherwise the reference assemblies for the profile aren't found -->
+-    <AssemblySearchPaths Condition="Exists('$(MSBuildExtensionsPath32)\..\xbuild-frameworks\.NETPortable\v4.5\System.Runtime.dll')">$(MSBuildExtensionsPath32)\..\xbuild-frameworks\.NETPortable\v4.5</AssemblySearchPaths>
+     <OtherFlags>$(OtherFlags) --targetprofile:netcore</OtherFlags>
+   </PropertyGroup>
+
+--
+2.7.4 (Apple Git-66)
+
+
+From e57cb16ee7927bb31b2c9b63e1b2e394bf9f9932 Mon Sep 17 00:00:00 2001
+From: Mikayla Hutchinson <m.j.hutchinson@gmail.com>
+Date: Mon, 1 Aug 2016 13:48:23 -0400
+Subject: [PATCH 2/2] Remove dead code
+
+Remove Mono workarounds for missing files. Mono has been
+shipping the files for some time now.
+---
+ .../FSharp.Build/Microsoft.Portable.FSharp.Targets | 52 ----------------------
+ 1 file changed, 52 deletions(-)
+
+diff --git a/src/fsharp/FSharp.Build/Microsoft.Portable.FSharp.Targets b/src/fsharp/FSharp.Build/Microsoft.Portable.FSharp.Targets
+index 8c99ab6..ee5f9b1 100644
+--- a/src/fsharp/FSharp.Build/Microsoft.Portable.FSharp.Targets
++++ b/src/fsharp/FSharp.Build/Microsoft.Portable.FSharp.Targets
+@@ -24,60 +24,8 @@ Copyright (C) Microsoft Corporation. All rights reserved.
+                 Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\Portable\v4.0\Microsoft.Portable.Common.targets') AND
+                            !Exists('$(MSBuildExtensionsPath32)\Microsoft\Portable\Microsoft.Portable.Core.props')"/>
+
+-
+-    <!-- Try to do it ourselves - Explicitly include contents of Microsoft.Portable.Core.props + Microsoft.FSharp.Targets + Microsoft.Portable.Core.targets -->
+-    <!-- START MONO 3.2.7 WORKAROUND PART 1 -->
+-        <PropertyGroup
+-                Condition="(!Exists('$(MSBuildExtensionsPath32)\Microsoft\Portable\v4.0\Microsoft.Portable.Common.targets')) AND
+-                           (!Exists('$(MSBuildExtensionsPath32)\Microsoft\Portable\Microsoft.Portable.Core.props'))">
+-              <AvailablePlatforms>Any CPU</AvailablePlatforms>
+-
+-              <TargetPlatformIdentifier>Portable</TargetPlatformIdentifier>
+-              <TargetFrameworkIdentifier>.NETPortable</TargetFrameworkIdentifier>
+-              <TargetFrameworkMonikerDisplayName>.NET Portable Subset</TargetFrameworkMonikerDisplayName>
+-
+-              <AddAdditionalExplicitAssemblyReferences>false</AddAdditionalExplicitAssemblyReferences>
+-              <NoStdLib>true</NoStdLib>
+-
+-              <ImplicitlyExpandTargetFramework Condition="'$(ImplicitlyExpandTargetFramework)' == '' ">true</ImplicitlyExpandTargetFramework>
+-      </PropertyGroup>
+-        <!-- END MONO 3.2.7 WORKAROUND PART 1 -->
+-
+-
+       <Import Project="$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.1\Framework\v4.0\Microsoft.FSharp.Targets" />
+
+-
+-    <!-- START MONO 3.2.7 WORKAROUND PART 2 -->
+-      <PropertyGroup
+-                Condition="(!Exists('$(MSBuildExtensionsPath32)\Microsoft\Portable\v4.0\Microsoft.Portable.Common.targets')) AND
+-                           (!Exists('$(MSBuildExtensionsPath32)\Microsoft\Portable\Microsoft.Portable.Core.props'))" >
+-              <ResolveReferencesDependsOn>
+-                      $(ResolveReferencesDependsOn);
+-                      ImplicitlyExpandTargetFramework;
+-              </ResolveReferencesDependsOn>
+-
+-              <ImplicitlyExpandTargetFrameworkDependsOn>
+-                      $(ImplicitlyExpandTargetFrameworkDependsOn);
+-                      GetReferenceAssemblyPaths
+-              </ImplicitlyExpandTargetFrameworkDependsOn>
+-      </PropertyGroup>
+-
+-      <Target Name="ImplicitlyExpandTargetFramework"
+-              DependsOnTargets="$(ImplicitlyExpandTargetFrameworkDependsOn)"
+-                Condition="(!Exists('$(MSBuildExtensionsPath32)\Microsoft\Portable\v4.0\Microsoft.Portable.Common.targets')) AND
+-                           (!Exists('$(MSBuildExtensionsPath32)\Microsoft\Portable\Microsoft.Portable.Core.props'))" >
+-
+-              <ItemGroup>
+-                      <ReferenceAssemblyPaths Include="$(_TargetFrameworkDirectories)"/>
+-                      <ReferencePath Include="%(ReferenceAssemblyPaths.Identity)\*.dll">
+-                              <CopyLocal>false</CopyLocal>
+-                              <ResolvedFrom>ImplicitlyExpandTargetFramework</ResolvedFrom>
+-                              <IsSystemReference>True</IsSystemReference>
+-                      </ReferencePath>
+-              </ItemGroup>
+-      </Target>
+-        <!-- END MONO 3.2.7 WORKAROUND PART 2 -->
+-
+       <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\Microsoft.Portable.Core.targets"
+                 Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\Portable\Microsoft.Portable.Core.props')"/>
+
+--
+2.7.4 (Apple Git-66)
diff --git a/bockbuild/mac-sdk/patches/gdk-quartz-set-fix-modifiers-hack-v3.patch b/bockbuild/mac-sdk/patches/gdk-quartz-set-fix-modifiers-hack-v3.patch
new file mode 100644 (file)
index 0000000..cbeb429
--- /dev/null
@@ -0,0 +1,178 @@
+diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
+index a8800f7..ec6a893 100644
+--- a/gdk/quartz/gdkevents-quartz.c
++++ b/gdk/quartz/gdkevents-quartz.c
+@@ -292,10 +292,19 @@ get_keyboard_modifiers_from_ns_flags (NSUInteger nsflags)
+     modifiers |= GDK_SHIFT_MASK;
+   if (nsflags & NSControlKeyMask)
+     modifiers |= GDK_CONTROL_MASK;
+-  if (nsflags & NSAlternateKeyMask)
+-    modifiers |= GDK_MOD1_MASK;
+-  if (nsflags & NSCommandKeyMask)
+-    modifiers |= GDK_MOD2_MASK;
++
++  if (gdk_quartz_get_fix_modifiers ())
++    {
++      if (nsflags & NSAlternateKeyMask)
++        modifiers |= GDK_MOD1_MASK;
++      if (nsflags & NSCommandKeyMask)
++        modifiers |= GDK_MOD2_MASK;
++    }
++  else
++    {
++      if (nsflags & NSCommandKeyMask)
++        modifiers |= GDK_MOD1_MASK;
++    }
+
+   return modifiers;
+ }
+@@ -930,7 +939,7 @@ fill_key_event (GdkWindow    *window,
+         {
+         case GDK_Meta_R:
+         case GDK_Meta_L:
+-          mask = GDK_MOD2_MASK;
++          mask = gdk_quartz_get_fix_modifiers () ? GDK_MOD2_MASK : GDK_MOD1_MASK;
+           break;
+         case GDK_Shift_R:
+         case GDK_Shift_L:
+@@ -941,7 +950,7 @@ fill_key_event (GdkWindow    *window,
+           break;
+         case GDK_Alt_R:
+         case GDK_Alt_L:
+-          mask = GDK_MOD1_MASK;
++          mask = gdk_quartz_get_fix_modifiers () ? GDK_MOD1_MASK : GDK_MOD2_MASK;
+           break;
+         case GDK_Control_R:
+         case GDK_Control_L:
+@@ -1089,9 +1098,9 @@ _gdk_quartz_events_get_current_keyboard_modifiers (void)
+       if (carbon_modifiers & controlKey)
+         modifiers |= GDK_CONTROL_MASK;
+       if (carbon_modifiers & optionKey)
+-        modifiers |= GDK_MOD1_MASK;
++        modifiers |= (gdk_quartz_get_fix_modifiers () ? GDK_MOD1_MASK : GDK_MOD2_MASK);
+       if (carbon_modifiers & cmdKey)
+-        modifiers |= GDK_MOD2_MASK;
++        modifiers |= (gdk_quartz_get_fix_modifiers () ? GDK_MOD2_MASK : GDK_MOD1_MASK);
+
+       return modifiers;
+     }
+diff --git a/gdk/quartz/gdkglobals-quartz.c b/gdk/quartz/gdkglobals-quartz.c
+index 53c6d5e..31dbab1 100644
+--- a/gdk/quartz/gdkglobals-quartz.c
++++ b/gdk/quartz/gdkglobals-quartz.c
+@@ -41,3 +41,17 @@ gdk_quartz_osx_version (void)
+   else
+     return minor;
+ }
++
++static gboolean fix_modifiers = FALSE;
++
++void
++gdk_quartz_set_fix_modifiers (gboolean fix)
++{
++  fix_modifiers = fix;
++}
++
++gboolean
++gdk_quartz_get_fix_modifiers (void)
++{
++  return fix_modifiers;
++}
+diff --git a/gdk/quartz/gdkkeys-quartz.c b/gdk/quartz/gdkkeys-quartz.c
+index 19a20f5..c7ceec6 100644
+--- a/gdk/quartz/gdkkeys-quartz.c
++++ b/gdk/quartz/gdkkeys-quartz.c
+@@ -693,11 +693,11 @@ gdk_keymap_translate_keyboard_state (GdkKeymap       *keymap,
+   for (bit = GDK_SHIFT_MASK; bit < GDK_BUTTON1_MASK; bit <<= 1)
+     {
+       if (translate_keysym (hardware_keycode,
+-                            (bit == GDK_MOD1_MASK) ? 0 : group,
++                            (bit == (gdk_quartz_get_fix_modifiers () ? GDK_MOD1_MASK : GDK_MOD2_MASK)) ? 0 : group,
+                             state & ~bit,
+                             NULL, NULL) !=
+         translate_keysym (hardware_keycode,
+-                            (bit == GDK_MOD1_MASK) ? 1 : group,
++                            (bit == (gdk_quartz_get_fix_modifiers () ? GDK_MOD1_MASK : GDK_MOD2_MASK)) ? 1 : group,
+                             state | bit,
+                             NULL, NULL))
+       tmp_modifiers |= bit;
+@@ -718,16 +718,32 @@ void
+ gdk_keymap_add_virtual_modifiers (GdkKeymap       *keymap,
+                                   GdkModifierType *state)
+ {
+-  if (*state & GDK_MOD2_MASK)
+-    *state |= GDK_META_MASK;
++  if (gdk_quartz_get_fix_modifiers ())
++    {
++      if (*state & GDK_MOD2_MASK)
++        *state |= GDK_META_MASK;
++    }
++  else
++    {
++      if (*state & GDK_MOD1_MASK)
++        *state |= GDK_META_MASK;
++    }
+ }
+
+ gboolean
+ gdk_keymap_map_virtual_modifiers (GdkKeymap       *keymap,
+                                   GdkModifierType *state)
+ {
+-  if (*state & GDK_META_MASK)
+-    *state |= GDK_MOD2_MASK;
++  if (gdk_quartz_get_fix_modifiers ())
++    {
++      if (*state & GDK_META_MASK)
++        *state |= GDK_MOD2_MASK;
++    }
++  else
++    {
++      if (*state & GDK_META_MASK)
++        *state |= GDK_MOD1_MASK;
++    }
+
+   return TRUE;
+ }
+diff --git a/gdk/quartz/gdkquartz.h b/gdk/quartz/gdkquartz.h
+index 742d651..ed0ba35 100644
+--- a/gdk/quartz/gdkquartz.h
++++ b/gdk/quartz/gdkquartz.h
+@@ -58,6 +58,9 @@ id        gdk_quartz_drag_context_get_dragging_info_libgtk_only (GdkDragContext
+ NSEvent  *gdk_quartz_event_get_nsevent                          (GdkEvent       *event);
+ GdkOSXVersion gdk_quartz_osx_version                            (void);
+
++void      gdk_quartz_set_fix_modifiers (gboolean fix);
++gboolean  gdk_quartz_get_fix_modifiers (void);
++
+ G_END_DECLS
+
+ #endif /* __GDK_QUARTZ_H__ */
+diff --git a/gtk/gtkprivate.h b/gtk/gtkprivate.h
+index 6386c32..aa1cc74 100644
+--- a/gtk/gtkprivate.h
++++ b/gtk/gtkprivate.h
+@@ -122,7 +122,7 @@ gboolean _gtk_fnmatch (const char *pattern,
+ #ifndef GDK_WINDOWING_QUARTZ
+ #define GTK_NO_TEXT_INPUT_MOD_MASK (GDK_MOD1_MASK | GDK_CONTROL_MASK)
+ #else
+-#define GTK_NO_TEXT_INPUT_MOD_MASK (GDK_MOD2_MASK | GDK_CONTROL_MASK)
++#define GTK_NO_TEXT_INPUT_MOD_MASK (gdk_quartz_get_fix_modifiers () ? (GDK_MOD2_MASK | GDK_CONTROL_MASK) : (GDK_MOD1_MASK | GDK_CONTROL_MASK))
+ #endif
+
+ #ifndef GDK_WINDOWING_QUARTZ
+@@ -130,13 +130,13 @@ gboolean _gtk_fnmatch (const char *pattern,
+ #define GTK_MODIFY_SELECTION_MOD_MASK GDK_CONTROL_MASK
+ #else
+ #define GTK_EXTEND_SELECTION_MOD_MASK GDK_SHIFT_MASK
+-#define GTK_MODIFY_SELECTION_MOD_MASK GDK_MOD2_MASK
++#define GTK_MODIFY_SELECTION_MOD_MASK (gdk_quartz_get_fix_modifiers () ? GDK_MOD2_MASK : GDK_MOD1_MASK)
+ #endif
+
+ #ifndef GDK_WINDOWING_QUARTZ
+ #define GTK_TOGGLE_GROUP_MOD_MASK 0
+ #else
+-#define GTK_TOGGLE_GROUP_MOD_MASK GDK_MOD1_MASK
++#define GTK_TOGGLE_GROUP_MOD_MASK (gdk_quartz_get_fix_modifiers () ? GDK_MOD1_MASK : 0)
+ #endif
+
+ gboolean _gtk_button_event_triggers_context_menu (GdkEventButton *event);
diff --git a/bockbuild/mac-sdk/patches/gettext-no-samples.patch b/bockbuild/mac-sdk/patches/gettext-no-samples.patch
new file mode 100644 (file)
index 0000000..80c198f
--- /dev/null
@@ -0,0 +1,10 @@
+--- a/gettext-tools/Makefile.in.orig   2010-06-03 16:38:55.000000000 -0500
++++ b/gettext-tools/Makefile.in        2010-06-04 01:16:07.000000000 -0500
+@@ -1248,7 +1248,7 @@
+ top_srcdir = @top_srcdir@
+ AUTOMAKE_OPTIONS = 1.5 gnu no-dependencies
+ ACLOCAL_AMFLAGS = -I m4 -I ../gettext-runtime/m4 -I ../m4 -I gnulib-m4 -I libgrep/gnulib-m4 -I libgettextpo/gnulib-m4
+-SUBDIRS = doc intl gnulib-lib libgrep src libgettextpo po projects styles misc man m4 tests gnulib-tests examples
++SUBDIRS = doc intl gnulib-lib libgrep src libgettextpo po projects styles misc man m4 tests gnulib-tests
+
+ # Allow users to use "gnulib-tool --update".
diff --git a/bockbuild/mac-sdk/patches/glib-recursive-poll.patch b/bockbuild/mac-sdk/patches/glib-recursive-poll.patch
new file mode 100644 (file)
index 0000000..b84c9d0
--- /dev/null
@@ -0,0 +1,73 @@
+From 5dfd206b09f91cba45fa8e2b66e1b57aafe30868 Mon Sep 17 00:00:00 2001
+From: Kristian Rietveld <kris@lanedo.com>
+Date: Mon, 8 Jul 2013 12:02:00 +0200
+Subject: [PATCH] Make g_main_context_iterate resilient to recursion in poll
+
+On OS X, main loop recursion may happen during the call the poll.
+As a result, the allocated poll array may be re-allocated (note that
+it is always enlarged, never shrunk). By always using cached_poll_array
+after the poll function, reads from bad memory are avoided.
+---
+ glib/gmain.c |   28 +++++++++++++++-------------
+ 1 file changed, 15 insertions(+), 13 deletions(-)
+
+diff --git a/glib/gmain.c b/glib/gmain.c
+index 077a935..529f2b6 100644
+--- a/glib/gmain.c
++++ b/glib/gmain.c
+@@ -3065,8 +3065,7 @@ g_main_context_iterate (GMainContext *context,
+   gint max_priority;
+   gint timeout;
+   gboolean some_ready;
+-  gint nfds, allocated_nfds;
+-  GPollFD *fds = NULL;
++  gint nfds;
+
+   UNLOCK_CONTEXT (context);
+
+@@ -3095,29 +3094,32 @@ g_main_context_iterate (GMainContext *context,
+       context->cached_poll_array = g_new (GPollFD, context->n_poll_records);
+     }
+
+-  allocated_nfds = context->cached_poll_array_size;
+-  fds = context->cached_poll_array;
+-
+   UNLOCK_CONTEXT (context);
+
+   g_main_context_prepare (context, &max_priority);
+
+-  while ((nfds = g_main_context_query (context, max_priority, &timeout, fds,
+-                                     allocated_nfds)) > allocated_nfds)
++  while ((nfds = g_main_context_query (context, max_priority, &timeout,
++                                       context->cached_poll_array,
++                                       context->cached_poll_array_size))
++         > context->cached_poll_array_size)
+     {
+       LOCK_CONTEXT (context);
+-      g_free (fds);
+-      context->cached_poll_array_size = allocated_nfds = nfds;
+-      context->cached_poll_array = fds = g_new (GPollFD, nfds);
++      g_free (context->cached_poll_array);
++      context->cached_poll_array_size = nfds;
++      context->cached_poll_array = g_new (GPollFD, nfds);
+       UNLOCK_CONTEXT (context);
+     }
+
+   if (!block)
+     timeout = 0;
+
+-  g_main_context_poll (context, timeout, max_priority, fds, nfds);
+-
+-  some_ready = g_main_context_check (context, max_priority, fds, nfds);
++  g_main_context_poll (context, timeout, max_priority,
++                       context->cached_poll_array,
++                       nfds);
++
++  some_ready = g_main_context_check (context, max_priority,
++                                     context->cached_poll_array,
++                                     nfds);
+
+   if (dispatch)
+     g_main_context_dispatch (context);
+--
+1.7.10
diff --git a/bockbuild/mac-sdk/patches/glib/config.h.ed b/bockbuild/mac-sdk/patches/glib/config.h.ed
new file mode 100644 (file)
index 0000000..bbf6cf4
--- /dev/null
@@ -0,0 +1,32 @@
+/ AC_APPLE_UNIVERSAL_BUILD /c
+/* #undef AC_APPLE_UNIVERSAL_BUILD */
+.
+/ G_VA_COPY_AS_ARRAY /c
+#ifdef __LP64__
+#define G_VA_COPY_AS_ARRAY 1
+#else
+/* #undef G_VA_COPY_AS_ARRAY */
+#endif
+.
+/ SIZEOF_LONG /c
+#ifdef __LP64__
+#define SIZEOF_LONG 8
+#else
+#define SIZEOF_LONG 4
+#endif
+.
+/ SIZEOF_SIZE_T /c
+#ifdef __LP64__
+#define SIZEOF_SIZE_T 8
+#else
+#define SIZEOF_SIZE_T 4
+#endif
+.
+/ SIZEOF_VOID_P /c
+#ifdef __LP64__
+#define SIZEOF_VOID_P 8
+#else
+#define SIZEOF_VOID_P 4
+#endif
+.
+w
diff --git a/bockbuild/mac-sdk/patches/glib/patch-configure.diff b/bockbuild/mac-sdk/patches/glib/patch-configure.diff
new file mode 100644 (file)
index 0000000..09848ac
--- /dev/null
@@ -0,0 +1,203 @@
+--- configure.orig     2012-10-15 19:29:14.000000000 -0500
++++ configure  2012-10-22 17:29:31.000000000 -0500
+@@ -5602,7 +5602,7 @@
+ fi
+
+ GLIB_RUNTIME_LIBDIR="$with_runtime_libdir"
+-ABS_GLIB_RUNTIME_LIBDIR="`readlink -f $libdir/$with_runtime_libdir`"
++ABS_GLIB_RUNTIME_LIBDIR="`readlink $libdir/$with_runtime_libdir`"
+
+
+  if test "x$with_runtime_libdir" != "x"; then
+@@ -30649,10 +30649,10 @@
+ *)                    glib_vacopy=''
+ esac
+
+-if test x$glib_cv_va_val_copy = xno; then
+   glib_vacopy="\$glib_vacopy
+-#define G_VA_COPY_AS_ARRAY 1"
+-fi
++#ifdef __LP64__
++#define G_VA_COPY_AS_ARRAY 1
++#endif"
+
+ if test x$glib_cv_hasinline = xyes; then
+     glib_inline='#define G_HAVE_INLINE 1'
+@@ -32411,18 +32411,32 @@
+       cat >>$outfile <<_______EOF
+ #define G_HAVE_GINT64 1          /* deprecated, always true */
+
+-${glib_extension}typedef signed $gint64 gint64;
+-${glib_extension}typedef unsigned $gint64 guint64;
++#ifdef __LP64__
++${glib_extension}typedef signed long gint64;
++${glib_extension}typedef unsigned long guint64;
+
+-#define G_GINT64_CONSTANT(val)        $gint64_constant
+-#define G_GUINT64_CONSTANT(val)       $guint64_constant
++#define G_GINT64_CONSTANT(val)        (val##L)
++#define G_GUINT64_CONSTANT(val)       (val##UL)
++#else
++${glib_extension}typedef signed long long gint64;
++${glib_extension}typedef unsigned long long guint64;
++
++#define G_GINT64_CONSTANT(val)        (G_GNUC_EXTENSION (val##LL))
++#define G_GUINT64_CONSTANT(val)       (G_GNUC_EXTENSION (val##ULL))
++#endif
+ _______EOF
+
+       if test x$gint64_format != x ; then
+         cat >>$outfile <<_______EOF
+-#define G_GINT64_MODIFIER $gint64_modifier
+-#define G_GINT64_FORMAT $gint64_format
+-#define G_GUINT64_FORMAT $guint64_format
++#ifdef __LP64__
++#define G_GINT64_MODIFIER "l"
++#define G_GINT64_FORMAT "li"
++#define G_GUINT64_FORMAT "lu"
++#else
++#define G_GINT64_MODIFIER "ll"
++#define G_GINT64_FORMAT "lli"
++#define G_GUINT64_FORMAT "llu"
++#endif
+ _______EOF
+         else
+         cat >>$outfile <<_______EOF
+@@ -32434,9 +32448,15 @@
+
+         cat >>$outfile <<_______EOF
+
+-#define GLIB_SIZEOF_VOID_P $glib_void_p
+-#define GLIB_SIZEOF_LONG   $glib_long
+-#define GLIB_SIZEOF_SIZE_T $glib_size_t
++#ifdef __LP64__
++#define GLIB_SIZEOF_VOID_P 8
++#define GLIB_SIZEOF_LONG   8
++#define GLIB_SIZEOF_SIZE_T 8
++#else
++#define GLIB_SIZEOF_VOID_P 4
++#define GLIB_SIZEOF_LONG   4
++#define GLIB_SIZEOF_SIZE_T 4
++#endif
+
+ _______EOF
+
+@@ -32464,18 +32484,33 @@
+       if test -z "$glib_unknown_void_p"; then
+         cat >>$outfile <<_______EOF
+
+-#define GPOINTER_TO_INT(p)    ((gint)  ${glib_gpi_cast} (p))
+-#define GPOINTER_TO_UINT(p)   ((guint) ${glib_gpui_cast} (p))
++#ifdef __LP64__
++#define GPOINTER_TO_INT(p)    ((gint)  (glong) (p))
++#define GPOINTER_TO_UINT(p)   ((guint) (gulong) (p))
++
++#define GINT_TO_POINTER(i)    ((gpointer) (glong) (i))
++#define GUINT_TO_POINTER(u)   ((gpointer) (gulong) (u))
++
++typedef signed long gintptr;
++typedef unsigned long guintptr;
++
++#define G_GINTPTR_MODIFIER      "l"
++#define G_GINTPTR_FORMAT        "li"
++#define G_GUINTPTR_FORMAT       "lu"
++#else
++#define GPOINTER_TO_INT(p)    ((gint)   (p))
++#define GPOINTER_TO_UINT(p)   ((guint)  (p))
+
+-#define GINT_TO_POINTER(i)    ((gpointer) ${glib_gpi_cast} (i))
+-#define GUINT_TO_POINTER(u)   ((gpointer) ${glib_gpui_cast} (u))
++#define GINT_TO_POINTER(i)    ((gpointer)  (i))
++#define GUINT_TO_POINTER(u)   ((gpointer)  (u))
+
+-typedef signed $glib_intptr_type_define gintptr;
+-typedef unsigned $glib_intptr_type_define guintptr;
++typedef signed int gintptr;
++typedef unsigned int guintptr;
+
+-#define G_GINTPTR_MODIFIER      $gintptr_modifier
+-#define G_GINTPTR_FORMAT        $gintptr_format
+-#define G_GUINTPTR_FORMAT       $guintptr_format
++#define G_GINTPTR_MODIFIER      ""
++#define G_GINTPTR_FORMAT        "i"
++#define G_GUINTPTR_FORMAT       "u"
++#endif
+ _______EOF
+       else
+         echo '#error SIZEOF_VOID_P unknown - This should never happen' >>$outfile
+@@ -32588,7 +32623,9 @@
+
+       if test x"$g_memory_barrier_needed" != xno; then
+         echo >>$outfile
++        echo "#ifdef __BIG_ENDIAN__" >>$outfile
+         echo "#define G_ATOMIC_OP_MEMORY_BARRIER_NEEDED 1" >>$outfile
++        echo "#endif" >>$outfile
+       fi
+       if test x"$g_atomic_lock_free" = xyes; then
+           echo >>$outfile
+@@ -32598,27 +32635,52 @@
+       g_bit_sizes="16 32 64"
+       for bits in $g_bit_sizes; do
+         cat >>$outfile <<_______EOF
+-#define GINT${bits}_TO_${g_bs_native}(val)    ((gint${bits}) (val))
+-#define GUINT${bits}_TO_${g_bs_native}(val)   ((guint${bits}) (val))
+-#define GINT${bits}_TO_${g_bs_alien}(val)     ((gint${bits}) GUINT${bits}_SWAP_LE_BE (val))
+-#define GUINT${bits}_TO_${g_bs_alien}(val)    (GUINT${bits}_SWAP_LE_BE (val))
++#ifdef __BIG_ENDIAN__
++#define GINT${bits}_TO_BE(val)        ((gint${bits}) (val))
++#define GUINT${bits}_TO_BE(val)       ((guint${bits}) (val))
++#define GINT${bits}_TO_LE(val)        ((gint${bits}) GUINT${bits}_SWAP_LE_BE (val))
++#define GUINT${bits}_TO_LE(val)       (GUINT${bits}_SWAP_LE_BE (val))
++#else
++#define GINT${bits}_TO_LE(val)        ((gint${bits}) (val))
++#define GUINT${bits}_TO_LE(val)       ((guint${bits}) (val))
++#define GINT${bits}_TO_BE(val)        ((gint${bits}) GUINT${bits}_SWAP_LE_BE (val))
++#define GUINT${bits}_TO_BE(val)       (GUINT${bits}_SWAP_LE_BE (val))
++#endif
+ _______EOF
+       done
+
+       cat >>$outfile <<_______EOF
+-#define GLONG_TO_LE(val)      ((glong) GINT${glongbits}_TO_LE (val))
+-#define GULONG_TO_LE(val)     ((gulong) GUINT${glongbits}_TO_LE (val))
+-#define GLONG_TO_BE(val)      ((glong) GINT${glongbits}_TO_BE (val))
+-#define GULONG_TO_BE(val)     ((gulong) GUINT${glongbits}_TO_BE (val))
++#ifdef __LP64__
++#define GLONG_TO_LE(val)      ((glong) GINT64_TO_LE (val))
++#define GULONG_TO_LE(val)     ((gulong) GUINT64_TO_LE (val))
++#define GLONG_TO_BE(val)      ((glong) GINT64_TO_BE (val))
++#define GULONG_TO_BE(val)     ((gulong) GUINT64_TO_BE (val))
++#else
++#define GLONG_TO_LE(val)      ((glong) GINT32_TO_LE (val))
++#define GULONG_TO_LE(val)     ((gulong) GUINT32_TO_LE (val))
++#define GLONG_TO_BE(val)      ((glong) GINT32_TO_BE (val))
++#define GULONG_TO_BE(val)     ((gulong) GUINT32_TO_BE (val))
++#endif
+ #define GINT_TO_LE(val)               ((gint) GINT${gintbits}_TO_LE (val))
+ #define GUINT_TO_LE(val)      ((guint) GUINT${gintbits}_TO_LE (val))
+ #define GINT_TO_BE(val)               ((gint) GINT${gintbits}_TO_BE (val))
+ #define GUINT_TO_BE(val)      ((guint) GUINT${gintbits}_TO_BE (val))
+-#define GSIZE_TO_LE(val)      ((gsize) GUINT${gsizebits}_TO_LE (val))
+-#define GSSIZE_TO_LE(val)     ((gssize) GINT${gsizebits}_TO_LE (val))
+-#define GSIZE_TO_BE(val)      ((gsize) GUINT${gsizebits}_TO_BE (val))
+-#define GSSIZE_TO_BE(val)     ((gssize) GINT${gsizebits}_TO_BE (val))
+-#define G_BYTE_ORDER $g_byte_order
++#ifdef __LP64__
++#define GSIZE_TO_LE(val)      ((gsize) GUINT64_TO_LE (val))
++#define GSSIZE_TO_LE(val)     ((gssize) GINT64_TO_LE (val))
++#define GSIZE_TO_BE(val)      ((gsize) GUINT64_TO_BE (val))
++#define GSSIZE_TO_BE(val)     ((gssize) GINT64_TO_BE (val))
++#else
++#define GSIZE_TO_LE(val)      ((gsize) GUINT32_TO_LE (val))
++#define GSSIZE_TO_LE(val)     ((gssize) GINT32_TO_LE (val))
++#define GSIZE_TO_BE(val)      ((gsize) GUINT32_TO_BE (val))
++#define GSSIZE_TO_BE(val)     ((gssize) GINT32_TO_BE (val))
++#endif
++#ifdef __BIG_ENDIAN__
++#define G_BYTE_ORDER G_BIG_ENDIAN
++#else
++#define G_BYTE_ORDER G_LITTLE_ENDIAN
++#endif
+
+ #define GLIB_SYSDEF_POLLIN =$g_pollin
+ #define GLIB_SYSDEF_POLLOUT =$g_pollout
diff --git a/bockbuild/mac-sdk/patches/glib/patch-gi18n.h.diff b/bockbuild/mac-sdk/patches/glib/patch-gi18n.h.diff
new file mode 100644 (file)
index 0000000..3d3821b
--- /dev/null
@@ -0,0 +1,11 @@
+--- glib/gi18n.h.orig  2008-11-23 23:45:23.000000000 -0600
++++ glib/gi18n.h       2008-11-25 23:59:29.000000000 -0600
+@@ -27,7 +27,9 @@
+
+ #define  _(String) gettext (String)
+ #define Q_(String) g_dpgettext (NULL, String, 0)
++#ifndef N_
+ #define N_(String) (String)
++#endif
+ #define C_(Context,String) g_dpgettext (NULL, Context "\004" String, strlen (Context) + 1)
+ #define NC_(Context, String) (String)
diff --git a/bockbuild/mac-sdk/patches/glib/patch-gio_gdbusprivate.c.diff b/bockbuild/mac-sdk/patches/glib/patch-gio_gdbusprivate.c.diff
new file mode 100644 (file)
index 0000000..5c77d56
--- /dev/null
@@ -0,0 +1,20 @@
+--- gio/gdbusprivate.c.orig    2012-04-30 11:24:02.000000000 -0500
++++ gio/gdbusprivate.c 2012-05-02 01:57:47.000000000 -0500
+@@ -2094,7 +2094,7 @@
+   /* TODO: use PACKAGE_LOCALSTATEDIR ? */
+   ret = NULL;
+   first_error = NULL;
+-  if (!g_file_get_contents ("/var/lib/dbus/machine-id",
++  if (!g_file_get_contents ("@@PREFIX@@/var/lib/dbus/machine-id",
+                             &ret,
+                             NULL,
+                             &first_error) &&
+@@ -2104,7 +2104,7 @@
+                             NULL))
+     {
+       g_propagate_prefixed_error (error, first_error,
+-                                  _("Unable to load /var/lib/dbus/machine-id or /etc/machine-id: "));
++                                  _("Unable to load @@PREFIX@@/var/lib/dbus/machine-id or /etc/machine-id: "));
+     }
+   else
+     {
diff --git a/bockbuild/mac-sdk/patches/glib/patch-gio_xdgmime_xdgmime.c.diff b/bockbuild/mac-sdk/patches/glib/patch-gio_xdgmime_xdgmime.c.diff
new file mode 100644 (file)
index 0000000..feaaed4
--- /dev/null
@@ -0,0 +1,10 @@
+--- gio/xdgmime/xdgmime.c.orig 2009-03-12 22:09:52.000000000 -0600
++++ gio/xdgmime/xdgmime.c      2009-04-09 23:41:01.000000000 -0600
+@@ -257,7 +257,7 @@
+
+   xdg_data_dirs = getenv ("XDG_DATA_DIRS");
+   if (xdg_data_dirs == NULL)
+-    xdg_data_dirs = "/usr/local/share/:/usr/share/";
++    xdg_data_dirs = "@@PREFIX@@/share/:/usr/share/";
+
+   ptr = xdg_data_dirs;
diff --git a/bockbuild/mac-sdk/patches/glib/patch-glib-2.0.pc.in.diff b/bockbuild/mac-sdk/patches/glib/patch-glib-2.0.pc.in.diff
new file mode 100644 (file)
index 0000000..b15274e
--- /dev/null
@@ -0,0 +1,8 @@
+--- glib-2.0.pc.in.orig        2012-01-15 21:12:06.000000000 -0600
++++ glib-2.0.pc.in     2012-01-19 22:29:43.000000000 -0600
+@@ -13,4 +13,4 @@
+ Requires.private: @PCRE_REQUIRES@
+ Libs: -L${libdir} -lglib-2.0 @INTLLIBS@
+ Libs.private: @G_THREAD_LIBS@ @G_LIBS_EXTRA@ @PCRE_LIBS@ @INTLLIBS@ @ICONV_LIBS@
+-Cflags: -I${includedir}/glib-2.0 -I${libdir}/glib-2.0/include @GLIB_EXTRA_CFLAGS@
++Cflags: -I${includedir}/glib-2.0 -I${libdir}/glib-2.0/include -I${includedir} @GLIB_EXTRA_CFLAGS@
diff --git a/bockbuild/mac-sdk/patches/glib/patch-glib_gunicollate.c.diff b/bockbuild/mac-sdk/patches/glib/patch-glib_gunicollate.c.diff
new file mode 100644 (file)
index 0000000..2a49282
--- /dev/null
@@ -0,0 +1,12 @@
+--- glib/gunicollate.c.orig    2009-03-31 18:04:20.000000000 -0500
++++ glib/gunicollate.c 2010-03-06 17:59:08.000000000 -0600
+@@ -26,6 +26,9 @@
+ #include <wchar.h>
+ #endif
+
++/* Carbon is not available on 64-bit */
++#undef HAVE_CARBON
++
+ #ifdef HAVE_CARBON
+ #include <CoreServices/CoreServices.h>
+ #endif
diff --git a/bockbuild/mac-sdk/patches/gtk-gestures.patch b/bockbuild/mac-sdk/patches/gtk-gestures.patch
new file mode 100644 (file)
index 0000000..3bc316c
--- /dev/null
@@ -0,0 +1,735 @@
+diff --git a/gdk/gdkevents.h b/gdk/gdkevents.h
+index e6c516c..f3fa26a 100644
+--- a/gdk/gdkevents.h
++++ b/gdk/gdkevents.h
+@@ -65,6 +65,11 @@ typedef struct _GdkEventWindowState GdkEventWindowState;
+ typedef struct _GdkEventSetting     GdkEventSetting;
+ typedef struct _GdkEventGrabBroken  GdkEventGrabBroken;
+
++/* OS X specific gesture events */
++typedef struct _GdkEventGestureMagnify GdkEventGestureMagnify;
++typedef struct _GdkEventGestureRotate  GdkEventGestureRotate;
++typedef struct _GdkEventGestureSwipe   GdkEventGestureSwipe;
++
+ typedef union  _GdkEvent          GdkEvent;
+
+ typedef void (*GdkEventFunc) (GdkEvent *event,
+@@ -152,6 +157,9 @@ typedef enum
+   GDK_OWNER_CHANGE      = 34,
+   GDK_GRAB_BROKEN       = 35,
+   GDK_DAMAGE            = 36,
++  GDK_GESTURE_MAGNIFY   = 37,
++  GDK_GESTURE_ROTATE    = 38,
++  GDK_GESTURE_SWIPE     = 39,
+   GDK_EVENT_LAST        /* helper variable for decls */
+ } GdkEventType;
+
+@@ -488,6 +496,52 @@ struct _GdkEventDND {
+   gshort x_root, y_root;
+ };
+
++/* Event types for OS X gestures */
++
++struct _GdkEventGestureMagnify
++{
++  GdkEventType type;
++  GdkWindow *window;
++  gint8 send_event;
++  guint32 time;
++  gdouble x;
++  gdouble y;
++  guint state;
++  gdouble magnification;
++  GdkDevice *device;
++  gdouble x_root, y_root;
++};
++
++struct _GdkEventGestureRotate
++{
++  GdkEventType type;
++  GdkWindow *window;
++  gint8 send_event;
++  guint32 time;
++  gdouble x;
++  gdouble y;
++  guint state;
++  gdouble rotation;
++  GdkDevice *device;
++  gdouble x_root, y_root;
++};
++
++struct _GdkEventGestureSwipe
++{
++  GdkEventType type;
++  GdkWindow *window;
++  gint8 send_event;
++  guint32 time;
++  gdouble x;
++  gdouble y;
++  guint state;
++  gdouble delta_x;
++  gdouble delta_y;
++  GdkDevice *device;
++  gdouble x_root, y_root;
++};
++
++
+ union _GdkEvent
+ {
+   GdkEventType                    type;
+@@ -511,6 +565,9 @@ union _GdkEvent
+   GdkEventWindowState       window_state;
+   GdkEventSetting           setting;
+   GdkEventGrabBroken        grab_broken;
++  GdkEventGestureMagnify    magnify;
++  GdkEventGestureRotate     rotate;
++  GdkEventGestureSwipe      swipe;
+ };
+
+ GType     gdk_event_get_type            (void) G_GNUC_CONST;
+diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
+index d20b424..fb89451 100644
+--- a/gdk/gdkwindow.c
++++ b/gdk/gdkwindow.c
+@@ -9813,6 +9813,9 @@ static const guint type_masks[] = {
+   0, /* GDK_OWNER_CHANGE = 34 */
+   0, /* GDK_GRAB_BROKEN = 35 */
+   0, /* GDK_DAMAGE = 36 */
++  0, /* GDK_GESTURE_MAGNIFY = 37 */
++  0, /* GDK_GESTURE_ROTATE = 38 */
++  0, /* GDK_GESTURE_SWIPE = 39 */
+ };
+ G_STATIC_ASSERT (G_N_ELEMENTS (type_masks) == GDK_EVENT_LAST);
+
+diff --git a/gdk/quartz/GdkQuartzView.c b/gdk/quartz/GdkQuartzView.c
+index 2c897fb..cdae2f1 100644
+--- a/gdk/quartz/GdkQuartzView.c
++++ b/gdk/quartz/GdkQuartzView.c
+@@ -190,4 +190,37 @@
+     [self updateTrackingRect];
+ }
+
++/* Handle OS X gesture events. The Apple documentation is explicit
++ * that these events should not be captured through a tracking loop (which
++ * is how we handle usual event handling), so we fallback to overriding
++ * NSResponder methods.
++ */
++
++-(void)magnifyWithEvent:(NSEvent *)event
++{
++  GdkEvent *gdk_event;
++
++  gdk_event = _gdk_quartz_events_create_magnify_event (event);
++  if (gdk_event)
++    _gdk_event_queue_append (gdk_display_get_default (), gdk_event);
++}
++
++-(void)rotateWithEvent:(NSEvent *)event
++{
++  GdkEvent *gdk_event;
++
++  gdk_event = _gdk_quartz_events_create_rotate_event (event);
++  if (gdk_event)
++    _gdk_event_queue_append (gdk_display_get_default (), gdk_event);
++}
++
++-(void)swipeWithEvent:(NSEvent *)event
++{
++  GdkEvent *gdk_event;
++
++  gdk_event = _gdk_quartz_events_create_swipe_event (event);
++  if (gdk_event)
++    _gdk_event_queue_append (gdk_display_get_default (), gdk_event);
++}
++
+ @end
+diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
+index 9478c16..128c794 100644
+--- a/gdk/quartz/gdkevents-quartz.c
++++ b/gdk/quartz/gdkevents-quartz.c
+@@ -374,6 +374,11 @@ get_event_mask_from_ns_event (NSEvent *nsevent)
+     case NSMouseExited:
+       return GDK_LEAVE_NOTIFY_MASK;
+
++    case NSEventTypeMagnify:
++    case NSEventTypeRotate:
++    case NSEventTypeSwipe:
++      return 0;
++
+     default:
+       g_assert_not_reached ();
+     }
+@@ -752,6 +757,11 @@ find_window_for_ns_event (NSEvent *nsevent,
+
+       return toplevel;
+
++    case NSEventTypeMagnify:
++    case NSEventTypeRotate:
++    case NSEventTypeSwipe:
++      return toplevel;
++
+     default:
+       /* Ignore everything else. */
+       break;
+@@ -1011,6 +1021,139 @@ fill_key_event (GdkWindow    *window,
+         event->key.keyval));
+ }
+
++
++static GdkWindow *
++find_window_for_ns_gesture_event (NSEvent *nsevent,
++                                  gint    *_x,
++                                  gint    *_y,
++                                  gint    *x_root,
++                                  gint    *y_root)
++{
++  GdkDisplay *display = _gdk_display;
++  GdkWindow *toplevel_window = NULL, *pointer_window = NULL;
++  gdouble found_x, found_y;
++  gint x, y;
++
++  toplevel_window = find_window_for_ns_event (nsevent, &x, &y, x_root, y_root);
++  if (!toplevel_window)
++    return NULL;
++
++  if (toplevel_window == display->pointer_info.toplevel_under_pointer)
++    pointer_window = _gdk_window_find_descendant_at (toplevel_window,
++                                                     x, y,
++                                                     &found_x, &found_y);
++  else
++    pointer_window = NULL;
++
++  *_x = found_x;
++  *_y = found_y;
++
++  return pointer_window;
++}
++
++
++GdkEvent *
++_gdk_quartz_events_create_magnify_event (NSEvent *nsevent)
++{
++  GdkEvent *event;
++  GdkWindow *window = NULL;
++  gint x, y, x_root, y_root;
++
++  window = find_window_for_ns_gesture_event (nsevent,
++                                             &x, &y,
++                                             &x_root, &y_root);
++
++  if (!window)
++    return NULL;
++
++  event = gdk_event_new (GDK_GESTURE_MAGNIFY);
++
++  event->any.type = GDK_GESTURE_MAGNIFY;
++  event->magnify.window = window;
++  event->magnify.time = get_time_from_ns_event (nsevent);
++  event->magnify.x = x;
++  event->magnify.y = y;
++  event->magnify.x_root = x_root;
++  event->magnify.y_root = y_root;
++  event->magnify.magnification = [nsevent magnification];
++  event->magnify.state = get_keyboard_modifiers_from_ns_event (nsevent) |
++                        _gdk_quartz_events_get_current_mouse_modifiers ();
++  event->magnify.device = _gdk_display->core_pointer;
++
++  fixup_event (event);
++
++  return event;
++}
++
++GdkEvent *
++_gdk_quartz_events_create_rotate_event (NSEvent *nsevent)
++{
++  GdkEvent *event;
++  GdkWindow *window;
++  gint x, y, x_root, y_root;
++
++  window = find_window_for_ns_gesture_event (nsevent,
++                                             &x, &y,
++                                             &x_root, &y_root);
++
++  if (!window)
++    return NULL;
++
++  event = gdk_event_new (GDK_GESTURE_ROTATE);
++
++  event->any.type = GDK_GESTURE_ROTATE;
++  event->rotate.window = window;
++  event->rotate.time = get_time_from_ns_event (nsevent);
++  event->rotate.x = x;
++  event->rotate.y = y;
++  event->rotate.x_root = x_root;
++  event->rotate.y_root = y_root;
++  event->rotate.rotation = [nsevent rotation];
++  event->rotate.state = get_keyboard_modifiers_from_ns_event (nsevent) |
++                        _gdk_quartz_events_get_current_mouse_modifiers ();
++  event->rotate.device = _gdk_display->core_pointer;
++
++  fixup_event (event);
++
++  return event;
++}
++
++GdkEvent *
++_gdk_quartz_events_create_swipe_event (NSEvent *nsevent)
++{
++  GdkEvent *event;
++  GdkWindow *window;
++  gint x, y, x_root, y_root;
++
++  window = find_window_for_ns_gesture_event (nsevent,
++                                             &x, &y,
++                                             &x_root, &y_root);
++
++  if (!window)
++    return NULL;
++
++  event = gdk_event_new (GDK_GESTURE_SWIPE);
++
++  event->any.type = GDK_GESTURE_SWIPE;
++  event->swipe.window = window;
++  event->swipe.time = get_time_from_ns_event (nsevent);
++  event->swipe.x = x;
++  event->swipe.y = y;
++  event->swipe.x_root = x_root;
++  event->swipe.y_root = y_root;
++  event->swipe.delta_x = [nsevent deltaX];
++  event->swipe.delta_y = [nsevent deltaY];
++  event->swipe.state = get_keyboard_modifiers_from_ns_event (nsevent) |
++                        _gdk_quartz_events_get_current_mouse_modifiers ();
++  event->swipe.device = _gdk_display->core_pointer;
++
++  fixup_event (event);
++
++  return event;
++}
++
++
++
+ static gboolean
+ synthesize_crossing_event (GdkWindow *window,
+                            GdkEvent  *event,
+@@ -1392,6 +1535,13 @@ gdk_event_translate (GdkEvent *event,
+       }
+       break;
+
++    /* Gesture events are handled through GdkQuartzView, because the
++     * Apple documentation states very clearly that such events should
++     * not be handled through a tracking loop (like GDK uses).
++     * Experiments show that gesture events do not get through our
++     * tracking loop either.
++     */
++
+     default:
+       /* Ignore everything elsee. */
+       return_val = FALSE;
+diff --git a/gdk/quartz/gdkglobals-quartz.c b/gdk/quartz/gdkglobals-quartz.c
+index 53c6d5e..6d01b59 100644
+--- a/gdk/quartz/gdkglobals-quartz.c
++++ b/gdk/quartz/gdkglobals-quartz.c
+@@ -41,3 +41,9 @@ gdk_quartz_osx_version (void)
+   else
+     return minor;
+ }
++
++gboolean
++gdk_quartz_supports_gesture_events (void)
++{
++  return TRUE;
++}
+diff --git a/gdk/quartz/gdkprivate-quartz.h b/gdk/quartz/gdkprivate-quartz.h
+index c1b3083..03a3857 100644
+--- a/gdk/quartz/gdkprivate-quartz.h
++++ b/gdk/quartz/gdkprivate-quartz.h
+@@ -179,6 +179,10 @@ GdkModifierType _gdk_quartz_events_get_current_mouse_modifiers    (void);
+ void         _gdk_quartz_events_send_enter_notify_event (GdkWindow *window);
+ void         _gdk_quartz_events_break_all_grabs         (guint32    time);
+
++GdkEvent    *_gdk_quartz_events_create_magnify_event    (NSEvent   *event);
++GdkEvent    *_gdk_quartz_events_create_rotate_event     (NSEvent   *event);
++GdkEvent    *_gdk_quartz_events_create_swipe_event      (NSEvent   *event);
++
+ /* Event loop */
+ gboolean   _gdk_quartz_event_loop_check_pending (void);
+ NSEvent *  _gdk_quartz_event_loop_get_pending   (void);
+diff --git a/gdk/quartz/gdkquartz.h b/gdk/quartz/gdkquartz.h
+index 742d651..f79d04a 100644
+--- a/gdk/quartz/gdkquartz.h
++++ b/gdk/quartz/gdkquartz.h
+@@ -57,6 +57,7 @@ NSImage  *gdk_quartz_pixbuf_to_ns_image_libgtk_only             (GdkPixbuf
+ id        gdk_quartz_drag_context_get_dragging_info_libgtk_only (GdkDragContext *context);
+ NSEvent  *gdk_quartz_event_get_nsevent                          (GdkEvent       *event);
+ GdkOSXVersion gdk_quartz_osx_version                            (void);
++gboolean  gdk_quartz_supports_gesture_events                    (void);
+
+ G_END_DECLS
+
+diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
+index 5a88679..db77675 100644
+--- a/gtk/gtkmain.c
++++ b/gtk/gtkmain.c
+@@ -1636,6 +1636,9 @@ gtk_main_do_event (GdkEvent *event)
+     case GDK_WINDOW_STATE:
+     case GDK_GRAB_BROKEN:
+     case GDK_DAMAGE:
++    case GDK_GESTURE_MAGNIFY:
++    case GDK_GESTURE_ROTATE:
++    case GDK_GESTURE_SWIPE:
+       if (!_gtk_widget_captured_event (event_widget, event))
+         gtk_widget_event (event_widget, event);
+       break;
+diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
+index 9a43d27..2d11e09 100644
+--- a/gtk/gtkwidget.c
++++ b/gtk/gtkwidget.c
+@@ -197,6 +197,9 @@ enum {
+   KEYNAV_FAILED,
+   DRAG_FAILED,
+   DAMAGE_EVENT,
++  GESTURE_MAGNIFY_EVENT,
++  GESTURE_ROTATE_EVENT,
++  GESTURE_SWIPE_EVENT,
+   LAST_SIGNAL
+ };
+
+@@ -2242,6 +2245,70 @@ gtk_widget_class_init (GtkWidgetClass *klass)
+                 _gtk_marshal_BOOLEAN__BOXED,
+                 G_TYPE_BOOLEAN, 1,
+                 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
++  /**
++   * GtkWidget::gesture-magnify-event:
++   * @widget: the object which received the signal
++   * @event: the #GdkEventGestureMagnify event
++   *
++   * Emitted when a magnify event is received on @widget's window.
++   *
++   * Returns: %TRUE to stop other handlers from being invoked for the event.
++   *   %FALSE to propagate the event further.
++   *
++   * Since: 2.24 Xamarin specific.
++   */
++  widget_signals[GESTURE_MAGNIFY_EVENT] =
++    g_signal_new (I_("gesture-magnify-event"),
++                G_TYPE_FROM_CLASS (gobject_class),
++                G_SIGNAL_RUN_LAST,
++                  0,
++                _gtk_boolean_handled_accumulator, NULL,
++                _gtk_marshal_BOOLEAN__BOXED,
++                G_TYPE_BOOLEAN, 1,
++                GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
++  /**
++   * GtkWidget::gesture-rotate-event:
++   * @widget: the object which received the signal
++   * @event: the #GdkEventGestureRotate event
++   *
++   * Emitted when a rotation event is received on @widget's window.
++   *
++   * Returns: %TRUE to stop other handlers from being invoked for the event.
++   *   %FALSE to propagate the event further.
++   *
++   * Since: 2.24 Xamarin specific.
++   */
++  widget_signals[GESTURE_ROTATE_EVENT] =
++    g_signal_new (I_("gesture-rotate-event"),
++                G_TYPE_FROM_CLASS (gobject_class),
++                G_SIGNAL_RUN_LAST,
++                  0,
++                _gtk_boolean_handled_accumulator, NULL,
++                _gtk_marshal_BOOLEAN__BOXED,
++                G_TYPE_BOOLEAN, 1,
++                GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
++  /**
++   * GtkWidget::gesture-swipe-event:
++   * @widget: the object which received the signal
++   * @event: the #GdkEventGestureSwipe event
++   *
++   * Emitted when a swipe event is received on @widget's window.
++   *
++   * Returns: %TRUE to stop other handlers from being invoked for the event.
++   *   %FALSE to propagate the event further.
++   *
++   * Since: 2.24 Xamarin specific.
++   */
++  widget_signals[GESTURE_SWIPE_EVENT] =
++    g_signal_new (I_("gesture-swipe-event"),
++                G_TYPE_FROM_CLASS (gobject_class),
++                G_SIGNAL_RUN_LAST,
++                  0,
++                _gtk_boolean_handled_accumulator, NULL,
++                _gtk_marshal_BOOLEAN__BOXED,
++                G_TYPE_BOOLEAN, 1,
++                GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
++
+ /**
+    * GtkWidget::grab-broken-event:
+    * @widget: the object which received the signal
+@@ -4975,6 +5042,15 @@ gtk_widget_event_internal (GtkWidget *widget,
+       case GDK_DAMAGE:
+         signal_num = DAMAGE_EVENT;
+         break;
++        case GDK_GESTURE_MAGNIFY:
++          signal_num = GESTURE_MAGNIFY_EVENT;
++          break;
++        case GDK_GESTURE_ROTATE:
++          signal_num = GESTURE_ROTATE_EVENT;
++          break;
++        case GDK_GESTURE_SWIPE:
++          signal_num = GESTURE_SWIPE_EVENT;
++          break;
+       default:
+         g_warning ("gtk_widget_event(): unhandled event type: %d", event->type);
+         signal_num = -1;
+diff --git a/tests/Makefile.am b/tests/Makefile.am
+index 3888826..68a0a79 100644
+--- a/tests/Makefile.am
++++ b/tests/Makefile.am
+@@ -88,7 +88,8 @@ noinst_PROGRAMS =  $(TEST_PROGS)     \
+       testactions                     \
+       testgrouping                    \
+       testtooltips                    \
+-      testvolumebutton
++      testvolumebutton                \
++      testgestures
+
+ if HAVE_CXX
+ noinst_PROGRAMS += autotestkeywords
+@@ -165,6 +166,7 @@ testgrouping_DEPENDENCIES = $(TEST_DEPS)
+ testtooltips_DEPENDENCIES = $(TEST_DEPS)
+ testvolumebutton_DEPENDENCIES = $(TEST_DEPS)
+ testwindows_DEPENDENCIES = $(TEST_DEPS)
++testgestures_DEPENDENCIES = $(TEST_DEPS)
+
+ testentrycompletion_SOURCES =         \
+       prop-editor.c           \
+@@ -273,6 +275,9 @@ testoffscreenwindow_SOURCES =      \
+ testwindows_SOURCES =         \
+       testwindows.c
+
++testgestures_SOURCES =        \
++      testgestures.c
++
+ EXTRA_DIST +=                         \
+       prop-editor.h           \
+       testgtk.1               \
+diff --git a/tests/testgestures.c b/tests/testgestures.c
+new file mode 100644
+index 0000000..ae3ab99
+--- /dev/null
++++ b/tests/testgestures.c
+@@ -0,0 +1,214 @@
++#include <gtk/gtk.h>
++#include <math.h>
++
++
++typedef struct
++{
++  gdouble width;
++  gdouble height;
++
++  gdouble angle;
++
++  GtkWidget *widget;
++  gint offset_x;
++  gint offset_y;
++  gdouble progress;
++  gboolean increasing;
++}
++RectangleInfo;
++
++
++
++static gboolean
++handle_expose_event (GtkWidget      *widget,
++                     GdkEventExpose *expose,
++                     gpointer        user_data)
++{
++  cairo_t *cr;
++  int center_x, center_y;
++  RectangleInfo *rect = (RectangleInfo *)user_data;
++
++  cr = gdk_cairo_create (widget->window);
++
++  cairo_save (cr);
++
++  /* Background */
++  cairo_rectangle (cr, 0, 0,
++                   widget->allocation.width,
++                   widget->allocation.height);
++  cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
++  cairo_fill (cr);
++
++  cairo_restore (cr);
++
++  /* Rectangle */
++  center_x = (widget->allocation.width - rect->width) / 2;
++  center_y = (widget->allocation.height - rect->height) / 2;
++
++  if (rect->progress != 0.0f)
++    {
++      cairo_translate (cr, rect->offset_x * rect->progress,
++                       rect->offset_y * rect->progress);
++    }
++
++  cairo_save (cr);
++
++  cairo_translate (cr, widget->allocation.width / 2,
++                   widget->allocation.height / 2);
++  cairo_rotate (cr, rect->angle * M_PI / 180.0);
++  cairo_translate (cr, -widget->allocation.width / 2,
++                   -widget->allocation.height / 2);
++
++
++  cairo_rectangle (cr,
++                   center_x, center_y,
++                   rect->width, rect->height);
++  cairo_set_source_rgb (cr, 0.9, 0.0, 0.0);
++  cairo_stroke (cr);
++
++  cairo_rectangle (cr,
++                   center_x, center_y,
++                   rect->width, rect->height);
++  cairo_set_source_rgba (cr, 0.9, 0.0, 0.0, 0.3);
++  cairo_fill (cr);
++
++  cairo_restore (cr);
++
++
++  cairo_destroy (cr);
++
++  return FALSE;
++}
++
++static gboolean
++handle_gesture_magnify_event (GtkWidget              *widget,
++                              GdkEventGestureMagnify *magnify,
++                              gpointer                user_data)
++{
++  RectangleInfo *rect = (RectangleInfo *)user_data;
++
++  rect->width += rect->width * magnify->magnification;
++  if (rect->width < 5)
++    rect->width = 5;
++
++  rect->height += rect->height * magnify->magnification;
++  if (rect->height < 5)
++    rect->height = 5;
++
++  gtk_widget_queue_draw (widget);
++
++  return TRUE;
++}
++
++static gboolean
++handle_gesture_rotate_event (GtkWidget             *widget,
++                             GdkEventGestureRotate *rotate,
++                             gpointer               user_data)
++{
++  RectangleInfo *rect = (RectangleInfo *)user_data;
++
++  rect->angle -= rotate->rotation;
++
++  gtk_widget_queue_draw (widget);
++
++  return TRUE;
++}
++
++
++static gboolean
++bounce_timeout (gpointer user_data)
++{
++  gboolean retval = TRUE;
++  RectangleInfo *rect = (RectangleInfo *)user_data;
++
++  if (rect->increasing)
++    rect->progress += 0.10f;
++  else
++    rect->progress -= 0.10f;
++
++  if (rect->progress > 1.0f)
++    {
++      rect->progress = 0.90f;
++      rect->increasing = FALSE;
++    }
++  else if (rect->progress <= 0.0f)
++    {
++      rect->progress = 0.0f;
++      retval = FALSE;
++    }
++
++  gtk_widget_queue_draw (rect->widget);
++
++  return retval;
++}
++
++static void
++bounce (RectangleInfo *rect,
++        int            offset_x,
++        int            offset_y)
++{
++  if (rect->progress != 0.0f)
++    return;
++
++  rect->progress = 0.10f;
++  rect->increasing = TRUE;
++  rect->offset_x = offset_x;
++  rect->offset_y = offset_y;
++  gtk_widget_queue_draw (rect->widget);
++
++  gdk_threads_add_timeout (25, bounce_timeout, rect);
++}
++
++static gboolean
++handle_gesture_swipe_event (GtkWidget             *widget,
++                            GdkEventGestureSwipe  *swipe,
++                            gpointer               user_data)
++{
++  int offset_x = 150, offset_y = 150;
++  RectangleInfo *rect = (RectangleInfo *)user_data;
++
++  offset_x *= -1.0 * swipe->delta_x;
++  offset_y *= -1.0 * swipe->delta_y;
++
++  bounce (rect, offset_x, offset_y);
++
++  return TRUE;
++}
++
++int
++main (int argc, char **argv)
++{
++  GtkWidget *window;
++  GtkWidget *drawing_area;
++  RectangleInfo rect;
++
++  gtk_init (&argc, &argv);
++
++  rect.width = 40.0;
++  rect.height = 40.0;
++  rect.angle = 0.0;
++  rect.progress = 0.0f;
++
++  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
++  gtk_window_set_default_size (GTK_WINDOW (window), 640, 480);
++  g_signal_connect (window, "delete-event",
++                    G_CALLBACK (gtk_main_quit), NULL);
++
++  drawing_area = gtk_drawing_area_new ();
++  rect.widget = drawing_area;
++  g_signal_connect (drawing_area, "expose-event",
++                    G_CALLBACK (handle_expose_event), &rect);
++  g_signal_connect (drawing_area, "gesture-magnify-event",
++                    G_CALLBACK (handle_gesture_magnify_event), &rect);
++  g_signal_connect (drawing_area, "gesture-rotate-event",
++                    G_CALLBACK (handle_gesture_rotate_event), &rect);
++  g_signal_connect (drawing_area, "gesture-swipe-event",
++                    G_CALLBACK (handle_gesture_swipe_event), &rect);
++  gtk_container_add (GTK_CONTAINER (window), drawing_area);
++
++  gtk_widget_show_all (window);
++
++  gtk_main ();
++
++  return 0;
++}
diff --git a/bockbuild/mac-sdk/patches/gtk-quartz-move-drag.patch b/bockbuild/mac-sdk/patches/gtk-quartz-move-drag.patch
new file mode 100644 (file)
index 0000000..e98f14a
--- /dev/null
@@ -0,0 +1,13 @@
+diff --git a/gdk/quartz/GdkQuartzWindow.c b/gdk/quartz/GdkQuartzWindow.c
+index 06d11cf..c11924c 100644
+--- a/gdk/quartz/GdkQuartzWindow.c
++++ b/gdk/quartz/GdkQuartzWindow.c
+@@ -412,7 +412,7 @@
+
+ -(BOOL)isInManualResize
+ {
+-  return inManualResize;
++  return inManualResize || inManualMove;
+ }
+
+ -(void)beginManualResize
diff --git a/bockbuild/mac-sdk/patches/gtk/0001-Add-invariant-that-a-child-is-unmapped-if-parent-is-.patch b/bockbuild/mac-sdk/patches/gtk/0001-Add-invariant-that-a-child-is-unmapped-if-parent-is-.patch
new file mode 100644 (file)
index 0000000..603454d
--- /dev/null
@@ -0,0 +1,104 @@
+From fdbef10f94b9e16618b75e7e12184befcd178852 Mon Sep 17 00:00:00 2001
+From: Havoc Pennington <hp@pobox.com>
+Date: Mon, 20 Dec 2010 12:58:04 -0500
+Subject: [PATCH 01/68] Add invariant that a child is unmapped if parent is
+ unmapped
+
+Requires fixes to GtkContainer and GtkWindow to unmap their
+children, rather than just withdrawing or hiding the container
+window.
+
+Requires fix to GtkHandleBox to chain up to GtkContainer unmap.
+
+Historically we avoided these unmaps for efficiency reasons,
+but these days it's a bigger problem that there's no way
+for child widgets to know that one of their ancestors has
+become unmapped.
+(cherry picked from commit b67c5af55bf611c013b2c43e6878281abd773530)
+---
+ docs/widget_system.txt |    2 +-
+ gtk/gtkcontainer.c     |   15 ++++++++++-----
+ gtk/gtkhandlebox.c     |    2 ++
+ gtk/gtkwindow.c        |    7 ++++++-
+ 4 files changed, 19 insertions(+), 7 deletions(-)
+
+diff --git a/docs/widget_system.txt b/docs/widget_system.txt
+index 1c2867c..9463f10 100644
+--- a/docs/widget_system.txt
++++ b/docs/widget_system.txt
+@@ -255,7 +255,7 @@ In the following
+
+    widget->parent && GTK_WIDGET_MAPPED (widget->parent) &&
+      GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_CHILD_VISIBLE
+-       => GTK_WIDGET_MAPPED (widget)
++       <=> GTK_WIDGET_MAPPED (widget)
+
+ Note:, the definition
+
+diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c
+index 9aaa7d9..7105724 100644
+--- a/gtk/gtkcontainer.c
++++ b/gtk/gtkcontainer.c
+@@ -2694,12 +2694,17 @@ gtk_container_unmap (GtkWidget *widget)
+ {
+   gtk_widget_set_mapped (widget, FALSE);
+
++  /* hide our window first so user doesn't see all the child windows
++   * vanishing one by one.  (only matters these days if one of the
++   * children has an actual native window instead of client-side
++   * window, e.g. a GtkSocket would)
++   */
+   if (gtk_widget_get_has_window (widget))
+-    gdk_window_hide (widget->window);
+-  else
+-    gtk_container_forall (GTK_CONTAINER (widget),
+-                        (GtkCallback)gtk_widget_unmap,
+-                        NULL);
++    gdk_window_hide (gtk_widget_get_window (widget));
++
++  gtk_container_forall (GTK_CONTAINER (widget),
++                        (GtkCallback)gtk_widget_unmap,
++                        NULL);
+ }
+
+ /**
+diff --git a/gtk/gtkhandlebox.c b/gtk/gtkhandlebox.c
+index 667371f..557d2de 100644
+--- a/gtk/gtkhandlebox.c
++++ b/gtk/gtkhandlebox.c
+@@ -383,6 +383,8 @@ gtk_handle_box_unmap (GtkWidget *widget)
+       gdk_window_hide (hb->float_window);
+       hb->float_window_mapped = FALSE;
+     }
++
++  GTK_WIDGET_CLASS (gtk_handle_box_parent_class)->unmap (widget);
+ }
+
+ static void
+diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
+index 4de3215..8f174c6 100644
+--- a/gtk/gtkwindow.c
++++ b/gtk/gtkwindow.c
+@@ -4690,7 +4690,8 @@ gtk_window_unmap (GtkWidget *widget)
+ {
+   GtkWindow *window = GTK_WINDOW (widget);
+   GtkWindowPrivate *priv = GTK_WINDOW_GET_PRIVATE (widget);
+-  GtkWindowGeometryInfo *info;
++  GtkWindowGeometryInfo *info;
++  GtkWidget *child;
+   GdkWindowState state;
+
+   gtk_widget_set_mapped (widget, FALSE);
+@@ -4721,6 +4722,10 @@ gtk_window_unmap (GtkWidget *widget)
+   window->stick_initially = (state & GDK_WINDOW_STATE_STICKY) != 0;
+   priv->above_initially = (state & GDK_WINDOW_STATE_ABOVE) != 0;
+   priv->below_initially = (state & GDK_WINDOW_STATE_BELOW) != 0;
++
++  child = gtk_bin_get_child (&(window->bin));
++  if (child)
++    gtk_widget_unmap (child);
+ }
+
+ static void
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0002-Maintain-map-unmap-invariants-in-GtkRecentChooserDia.patch b/bockbuild/mac-sdk/patches/gtk/0002-Maintain-map-unmap-invariants-in-GtkRecentChooserDia.patch
new file mode 100644 (file)
index 0000000..c74d358
--- /dev/null
@@ -0,0 +1,81 @@
+From 4f27e87d62b480a49dcffc232e246295c32113ca Mon Sep 17 00:00:00 2001
+From: Kjell Ahlstedt <kjell.ahlstedt@bredband.net>
+Date: Wed, 16 Nov 2011 09:03:12 +0100
+Subject: [PATCH 02/68] Maintain map/unmap invariants in
+ GtkRecentChooserDialog
+
+We used to explicitly map and unmap the child GtkRecentChooserWidget when
+mapping and unmapping the dialog, respectively. Now that GtkContainer actually
+unmaps child widgets (instead of avoiding that), we can assume that the
+child GtkRecentChooserWidget will be unmapped when we want it to be.
+
+This fixes a warning from gtk_widget_verify_invariants(), as we were mapping
+our child widget before calling our parent class' ::map() handler. Bug #659257.
+(cherry picked from commit e8bb2e4545365d83261381a14920b773aba4a678)
+---
+ gtk/gtkrecentchooserdialog.c |   30 ------------------------------
+ 1 file changed, 30 deletions(-)
+
+diff --git a/gtk/gtkrecentchooserdialog.c b/gtk/gtkrecentchooserdialog.c
+index 058439a..1c67b7a 100644
+--- a/gtk/gtkrecentchooserdialog.c
++++ b/gtk/gtkrecentchooserdialog.c
+@@ -55,9 +55,6 @@ static void gtk_recent_chooser_dialog_get_property (GObject      *object,
+                                                   GValue       *value,
+                                                   GParamSpec   *pspec);
+
+-static void gtk_recent_chooser_dialog_map       (GtkWidget *widget);
+-static void gtk_recent_chooser_dialog_unmap     (GtkWidget *widget);
+-
+ G_DEFINE_TYPE_WITH_CODE (GtkRecentChooserDialog,
+                        gtk_recent_chooser_dialog,
+                        GTK_TYPE_DIALOG,
+@@ -68,16 +65,12 @@ static void
+ gtk_recent_chooser_dialog_class_init (GtkRecentChooserDialogClass *klass)
+ {
+   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+-  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+   gobject_class->set_property = gtk_recent_chooser_dialog_set_property;
+   gobject_class->get_property = gtk_recent_chooser_dialog_get_property;
+   gobject_class->constructor = gtk_recent_chooser_dialog_constructor;
+   gobject_class->finalize = gtk_recent_chooser_dialog_finalize;
+
+-  widget_class->map = gtk_recent_chooser_dialog_map;
+-  widget_class->unmap = gtk_recent_chooser_dialog_unmap;
+-
+   _gtk_recent_chooser_install_properties (gobject_class);
+
+   g_type_class_add_private (klass, sizeof (GtkRecentChooserDialogPrivate));
+@@ -224,29 +217,6 @@ gtk_recent_chooser_dialog_finalize (GObject *object)
+   G_OBJECT_CLASS (gtk_recent_chooser_dialog_parent_class)->finalize (object);
+ }
+
+-static void
+-gtk_recent_chooser_dialog_map (GtkWidget *widget)
+-{
+-  GtkRecentChooserDialog *dialog = GTK_RECENT_CHOOSER_DIALOG (widget);
+-  GtkRecentChooserDialogPrivate *priv = dialog->priv;
+-
+-  if (!gtk_widget_get_mapped (priv->chooser))
+-    gtk_widget_map (priv->chooser);
+-
+-  GTK_WIDGET_CLASS (gtk_recent_chooser_dialog_parent_class)->map (widget);
+-}
+-
+-static void
+-gtk_recent_chooser_dialog_unmap (GtkWidget *widget)
+-{
+-  GtkRecentChooserDialog *dialog = GTK_RECENT_CHOOSER_DIALOG (widget);
+-  GtkRecentChooserDialogPrivate *priv = dialog->priv;
+-
+-  GTK_WIDGET_CLASS (gtk_recent_chooser_dialog_parent_class)->unmap (widget);
+-
+-  gtk_widget_unmap (priv->chooser);
+-}
+-
+ static GtkWidget *
+ gtk_recent_chooser_dialog_new_valist (const gchar      *title,
+                                     GtkWindow        *parent,
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0003-GtkPlug-preserve-map-unmap-invariants.patch b/bockbuild/mac-sdk/patches/gtk/0003-GtkPlug-preserve-map-unmap-invariants.patch
new file mode 100644 (file)
index 0000000..85d0c53
--- /dev/null
@@ -0,0 +1,57 @@
+From 41c694a884284280c8ac766e636dd344493509e4 Mon Sep 17 00:00:00 2001
+From: Matthias Clasen <mclasen@redhat.com>
+Date: Fri, 2 Sep 2011 21:40:42 -0400
+Subject: [PATCH 03/68] GtkPlug: preserve map/unmap invariants (cherry picked
+ from commit be152f9b6196849c99c54afe5a0f651d08bf4626)
+
+---
+ gtk/gtkplug.c |   19 +++++++++++++------
+ 1 file changed, 13 insertions(+), 6 deletions(-)
+
+diff --git a/gtk/gtkplug.c b/gtk/gtkplug.c
+index 99af62a..86dd85e 100644
+--- a/gtk/gtkplug.c
++++ b/gtk/gtkplug.c
+@@ -708,13 +708,15 @@ gtk_plug_map (GtkWidget *widget)
+     {
+       GtkBin *bin = GTK_BIN (widget);
+       GtkPlug *plug = GTK_PLUG (widget);
+-
++      GtkWidget *child;
++
+       gtk_widget_set_mapped (widget, TRUE);
+
+-      if (bin->child &&
+-        gtk_widget_get_visible (bin->child) &&
+-        !gtk_widget_get_mapped (bin->child))
+-      gtk_widget_map (bin->child);
++      child = gtk_bin_get_child (bin);
++      if (child != NULL &&
++          gtk_widget_get_visible (child) &&
++          !gtk_widget_get_mapped (child))
++        gtk_widget_map (child);
+
+       _gtk_plug_windowing_map_toplevel (plug);
+
+@@ -732,13 +734,18 @@ gtk_plug_unmap (GtkWidget *widget)
+   if (gtk_widget_is_toplevel (widget))
+     {
+       GtkPlug *plug = GTK_PLUG (widget);
++      GtkWidget *child;
+
+       gtk_widget_set_mapped (widget, FALSE);
+
+       gdk_window_hide (widget->window);
+
++      child = gtk_bin_get_child (GTK_BIN (widget));
++      if (child != NULL)
++        gtk_widget_unmap (child);
++
+       _gtk_plug_windowing_unmap_toplevel (plug);
+-
++
+       gdk_synthesize_window_state (widget->window,
+                                  0,
+                                  GDK_WINDOW_STATE_WITHDRAWN);
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0004-Add-gdk_screen_get_monitor_workarea-and-use-it-all-o.patch b/bockbuild/mac-sdk/patches/gtk/0004-Add-gdk_screen_get_monitor_workarea-and-use-it-all-o.patch
new file mode 100644 (file)
index 0000000..a89f294
--- /dev/null
@@ -0,0 +1,368 @@
+From 8636b3d980cdef4c12f53779f708cc4a674d1054 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Fri, 23 Nov 2012 15:24:36 +0100
+Subject: [PATCH 04/68] Add gdk_screen_get_monitor_workarea() and use it all
+ over the place
+
+---
+ gdk/gdk.symbols               |    1 +
+ gdk/gdkscreen.h               |    3 +++
+ gdk/quartz/gdkscreen-quartz.c |   30 ++++++++++++++++++++++++++++++
+ gtk/gtkcombobox.c             |    4 ++--
+ gtk/gtkentry.c                |    2 +-
+ gtk/gtkentrycompletion.c      |    2 +-
+ gtk/gtkfilechooserdefault.c   |    2 +-
+ gtk/gtklinkbutton.c           |    2 +-
+ gtk/gtkmenu.c                 |    6 +++---
+ gtk/gtkmenuitem.c             |    2 +-
+ gtk/gtkmenutoolbutton.c       |    2 +-
+ gtk/gtkrecentchooserdefault.c |    4 ++--
+ gtk/gtkscalebutton.c          |    2 +-
+ gtk/gtkstatusicon.c           |    4 ++--
+ gtk/gtktextview.c             |    2 +-
+ gtk/gtktoolbar.c              |    2 +-
+ gtk/gtktooltip.c              |    2 +-
+ gtk/gtktreeview.c             |    2 +-
+ gtk/gtkwindow.c               |    6 +++---
+ 19 files changed, 57 insertions(+), 23 deletions(-)
+
+diff --git a/gdk/gdk.symbols b/gdk/gdk.symbols
+index d4f2072..feed787 100644
+--- a/gdk/gdk.symbols
++++ b/gdk/gdk.symbols
+@@ -1169,6 +1169,7 @@ gdk_screen_get_default_colormap
+ gdk_screen_set_default_colormap
+ gdk_screen_get_n_monitors
+ gdk_screen_get_monitor_geometry
++gdk_screen_get_monitor_workarea
+ gdk_screen_get_monitor_width_mm
+ gdk_screen_get_monitor_height_mm
+ gdk_screen_get_monitor_plug_name
+diff --git a/gdk/gdkscreen.h b/gdk/gdkscreen.h
+index 418cecf..d3d4fe9 100644
+--- a/gdk/gdkscreen.h
++++ b/gdk/gdkscreen.h
+@@ -95,6 +95,9 @@ gint          gdk_screen_get_primary_monitor   (GdkScreen *screen);
+ void          gdk_screen_get_monitor_geometry  (GdkScreen *screen,
+                                               gint       monitor_num,
+                                               GdkRectangle *dest);
++void          gdk_screen_get_monitor_workarea  (GdkScreen    *screen,
++                                                gint          monitor_num,
++                                                GdkRectangle *dest);
+ gint          gdk_screen_get_monitor_at_point  (GdkScreen *screen,
+                                               gint       x,
+                                               gint       y);
+diff --git a/gdk/quartz/gdkscreen-quartz.c b/gdk/quartz/gdkscreen-quartz.c
+index 796fcb5..4bb573b 100644
+--- a/gdk/quartz/gdkscreen-quartz.c
++++ b/gdk/quartz/gdkscreen-quartz.c
+@@ -464,6 +464,36 @@ gdk_screen_get_monitor_geometry (GdkScreen    *screen,
+   *dest = GDK_SCREEN_QUARTZ (screen)->screen_rects[monitor_num];
+ }
+
++void
++gdk_screen_get_monitor_workarea (GdkScreen    *screen,
++                                 gint          monitor_num,
++                                 GdkRectangle *dest)
++{
++  GdkScreenQuartz *quartz_screen;
++  NSArray *array;
++  NSScreen *nsscreen;
++  NSRect rect;
++
++  g_return_if_fail (GDK_IS_SCREEN (screen));
++  g_return_if_fail (monitor_num < gdk_screen_get_n_monitors (screen));
++  g_return_if_fail (monitor_num >= 0);
++
++  quartz_screen = GDK_SCREEN_QUARTZ (screen);
++
++  GDK_QUARTZ_ALLOC_POOL;
++
++  array = [NSScreen screens];
++  nsscreen = [array objectAtIndex:monitor_num];
++  rect = [nsscreen visibleFrame];
++
++  dest->x = rect.origin.x - quartz_screen->min_x;
++  dest->y = quartz_screen->height - (rect.origin.y + rect.size.height) + quartz_screen->min_y;
++  dest->width = rect.size.width;
++  dest->height = rect.size.height;
++
++  GDK_QUARTZ_RELEASE_POOL;
++}
++
+ gchar *
+ gdk_screen_make_display_name (GdkScreen *screen)
+ {
+diff --git a/gtk/gtkcombobox.c b/gtk/gtkcombobox.c
+index dc912a3..d997d0d 100644
+--- a/gtk/gtkcombobox.c
++++ b/gtk/gtkcombobox.c
+@@ -1667,7 +1667,7 @@ gtk_combo_box_menu_position_below (GtkMenu  *menu,
+   screen = gtk_widget_get_screen (GTK_WIDGET (combo_box));
+   monitor_num = gdk_screen_get_monitor_at_window (screen,
+                                                 GTK_WIDGET (combo_box)->window);
+-  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
++  gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
+
+   if (*x < monitor.x)
+     *x = monitor.x;
+@@ -1836,7 +1836,7 @@ gtk_combo_box_list_position (GtkComboBox *combo_box,
+   screen = gtk_widget_get_screen (GTK_WIDGET (combo_box));
+   monitor_num = gdk_screen_get_monitor_at_window (screen,
+                                                 GTK_WIDGET (combo_box)->window);
+-  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
++  gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
+
+   if (*x < monitor.x)
+     *x = monitor.x;
+diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c
+index e2999a3..0d16d71 100644
+--- a/gtk/gtkentry.c
++++ b/gtk/gtkentry.c
+@@ -8614,7 +8614,7 @@ popup_position_func (GtkMenu   *menu,
+     monitor_num = 0;
+   gtk_menu_set_monitor (menu, monitor_num);
+
+-  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
++  gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
+   gtk_widget_size_request (entry->popup_menu, &menu_req);
+   height = gdk_window_get_height (entry->text_area);
+   gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &strong_x, NULL);
+diff --git a/gtk/gtkentrycompletion.c b/gtk/gtkentrycompletion.c
+index 2fa7b56..a8deace 100644
+--- a/gtk/gtkentrycompletion.c
++++ b/gtk/gtkentrycompletion.c
+@@ -1409,7 +1409,7 @@ _gtk_entry_completion_resize_popup (GtkEntryCompletion *completion)
+   screen = gtk_widget_get_screen (GTK_WIDGET (completion->priv->entry));
+   monitor_num = gdk_screen_get_monitor_at_window (screen,
+                                                 GTK_WIDGET (completion->priv->entry)->window);
+-  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
++  gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
+
+
+
+diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c
+index 2a75365..f94f4d6 100644
+--- a/gtk/gtkfilechooserdefault.c
++++ b/gtk/gtkfilechooserdefault.c
+@@ -4100,7 +4100,7 @@ popup_position_func (GtkMenu   *menu,
+
+   monitor_num = gdk_screen_get_monitor_at_point (screen, *x, *y);
+   gtk_menu_set_monitor (menu, monitor_num);
+-  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
++  gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
+
+   *x = CLAMP (*x, monitor.x, monitor.x + MAX (0, monitor.width - req.width));
+   *y = CLAMP (*y, monitor.y, monitor.y + MAX (0, monitor.height - req.height));
+diff --git a/gtk/gtklinkbutton.c b/gtk/gtklinkbutton.c
+index bae8ec3..45d64b2 100644
+--- a/gtk/gtklinkbutton.c
++++ b/gtk/gtklinkbutton.c
+@@ -374,7 +374,7 @@ popup_position_func (GtkMenu  *menu,
+
+   monitor_num = gdk_screen_get_monitor_at_point (screen, *x, *y);
+   gtk_menu_set_monitor (menu, monitor_num);
+-  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
++  gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
+
+   *x = CLAMP (*x, monitor.x, monitor.x + MAX (0, monitor.width - req.width));
+   *y = CLAMP (*y, monitor.y, monitor.y + MAX (0, monitor.height - req.height));
+diff --git a/gtk/gtkmenu.c b/gtk/gtkmenu.c
+index fc25098..44972b2 100644
+--- a/gtk/gtkmenu.c
++++ b/gtk/gtkmenu.c
+@@ -993,7 +993,7 @@ gtk_menu_window_size_request (GtkWidget      *window,
+       GdkScreen *screen = gtk_widget_get_screen (window);
+       GdkRectangle monitor;
+
+-      gdk_screen_get_monitor_geometry (screen, private->monitor_num, &monitor);
++      gdk_screen_get_monitor_workarea (screen, private->monitor_num, &monitor);
+
+       if (private->y + requisition->height > monitor.y + monitor.height)
+       requisition->height = monitor.y + monitor.height - private->y;
+@@ -4231,7 +4231,7 @@ gtk_menu_position (GtkMenu *menu)
+       if (private->monitor_num < 0)
+       private->monitor_num = gdk_screen_get_monitor_at_point (screen, x, y);
+
+-      gdk_screen_get_monitor_geometry (screen, private->monitor_num, &monitor);
++      gdk_screen_get_monitor_workarea (screen, private->monitor_num, &monitor);
+     }
+   else
+     {
+@@ -4260,7 +4260,7 @@ gtk_menu_position (GtkMenu *menu)
+        * Positioning in the vertical direction is similar: first try below
+        * mouse cursor, then above.
+        */
+-      gdk_screen_get_monitor_geometry (screen, private->monitor_num, &monitor);
++      gdk_screen_get_monitor_workarea (screen, private->monitor_num, &monitor);
+
+       space_left = x - monitor.x;
+       space_right = monitor.x + monitor.width - x - 1;
+diff --git a/gtk/gtkmenuitem.c b/gtk/gtkmenuitem.c
+index 8f23b75..ffc2db6 100644
+--- a/gtk/gtkmenuitem.c
++++ b/gtk/gtkmenuitem.c
+@@ -1717,7 +1717,7 @@ gtk_menu_item_position_menu (GtkMenu  *menu,
+   monitor_num = gdk_screen_get_monitor_at_window (screen, menu_item->event_window);
+   if (monitor_num < 0)
+     monitor_num = 0;
+-  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
++  gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
+
+   if (!gdk_window_get_origin (widget->window, &tx, &ty))
+     {
+diff --git a/gtk/gtkmenutoolbutton.c b/gtk/gtkmenutoolbutton.c
+index 0c464e8..e254e1b 100644
+--- a/gtk/gtkmenutoolbutton.c
++++ b/gtk/gtkmenutoolbutton.c
+@@ -287,7 +287,7 @@ menu_position_func (GtkMenu           *menu,
+   monitor_num = gdk_screen_get_monitor_at_window (screen, widget->window);
+   if (monitor_num < 0)
+     monitor_num = 0;
+-  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
++  gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
+
+   if (orientation == GTK_ORIENTATION_HORIZONTAL)
+     {
+diff --git a/gtk/gtkrecentchooserdefault.c b/gtk/gtkrecentchooserdefault.c
+index 1ab48e2..fe2a772 100644
+--- a/gtk/gtkrecentchooserdefault.c
++++ b/gtk/gtkrecentchooserdefault.c
+@@ -951,7 +951,7 @@ set_default_size (GtkRecentChooserDefault *impl)
+   screen = gtk_widget_get_screen (widget);
+   monitor_num = gdk_screen_get_monitor_at_window (screen, widget->window);
+
+-  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
++  gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
+
+   width = MIN (width, monitor.width * 3 / 4);
+   height = MIN (height, monitor.height * 3 / 4);
+@@ -1849,7 +1849,7 @@ popup_position_func (GtkMenu   *menu,
+
+   monitor_num = gdk_screen_get_monitor_at_point (screen, *x, *y);
+   gtk_menu_set_monitor (menu, monitor_num);
+-  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
++  gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
+
+   *x = CLAMP (*x, monitor.x, monitor.x + MAX (0, monitor.width - req.width));
+   *y = CLAMP (*y, monitor.y, monitor.y + MAX (0, monitor.height - req.height));
+diff --git a/gtk/gtkscalebutton.c b/gtk/gtkscalebutton.c
+index df9b574..3c6fc85 100644
+--- a/gtk/gtkscalebutton.c
++++ b/gtk/gtkscalebutton.c
+@@ -1000,7 +1000,7 @@ gtk_scale_popup (GtkWidget *widget,
+       monitor = gdk_screen_get_monitor_at_point (screen,
+                                                button_event->x_root,
+                                                button_event->y_root);
+-      gdk_screen_get_monitor_geometry (screen, monitor, &rect);
++      gdk_screen_get_monitor_workarea (screen, monitor, &rect);
+
+       if (priv->orientation == GTK_ORIENTATION_VERTICAL)
+         y += button_event->y;
+diff --git a/gtk/gtkstatusicon.c b/gtk/gtkstatusicon.c
+index 77d93da..c6d3097 100644
+--- a/gtk/gtkstatusicon.c
++++ b/gtk/gtkstatusicon.c
+@@ -648,7 +648,7 @@ build_button_event (GtkStatusIconPrivate *priv,
+   GdkRectangle monitor0;
+
+   /* We know that gdk/win32 puts the primary monitor at index 0 */
+-  gdk_screen_get_monitor_geometry (gdk_screen_get_default (), 0, &monitor0);
++  gdk_screen_get_monitor_workarea (gdk_screen_get_default (), 0, &monitor0);
+   e->window = g_object_ref (gdk_get_default_root_window ());
+   e->send_event = TRUE;
+   e->time = GetTickCount ();
+@@ -2512,7 +2512,7 @@ gtk_status_icon_position_menu (GtkMenu  *menu,
+     monitor_num = 0;
+   gtk_menu_set_monitor (menu, monitor_num);
+
+-  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
++  gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
+
+   gdk_window_get_origin (widget->window, x, y);
+
+diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c
+index 9ddddec..419cced 100644
+--- a/gtk/gtktextview.c
++++ b/gtk/gtktextview.c
+@@ -7845,7 +7845,7 @@ popup_position_func (GtkMenu   *menu,
+
+   monitor_num = gdk_screen_get_monitor_at_point (screen, *x, *y);
+   gtk_menu_set_monitor (menu, monitor_num);
+-  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
++  gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
+
+   *x = CLAMP (*x, monitor.x, monitor.x + MAX (0, monitor.width - req.width));
+   *y = CLAMP (*y, monitor.y, monitor.y + MAX (0, monitor.height - req.height));
+diff --git a/gtk/gtktoolbar.c b/gtk/gtktoolbar.c
+index b2c4b15..fc1e588 100644
+--- a/gtk/gtktoolbar.c
++++ b/gtk/gtktoolbar.c
+@@ -2618,7 +2618,7 @@ menu_position_func (GtkMenu  *menu,
+   monitor_num = gdk_screen_get_monitor_at_window (screen, priv->arrow_button->window);
+   if (monitor_num < 0)
+     monitor_num = 0;
+-  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
++  gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
+
+   gdk_window_get_origin (GTK_BUTTON (priv->arrow_button)->event_window, x, y);
+   if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
+diff --git a/gtk/gtktooltip.c b/gtk/gtktooltip.c
+index 9918165..fb6e869 100644
+--- a/gtk/gtktooltip.c
++++ b/gtk/gtktooltip.c
+@@ -1139,7 +1139,7 @@ gtk_tooltip_position (GtkTooltip *tooltip,
+                                &requisition);
+
+       monitor_num = gdk_screen_get_monitor_at_point (screen, x, y);
+-      gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
++      gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
+
+       if (x + requisition.width > monitor.x + monitor.width)
+         x -= x - (monitor.x + monitor.width) + requisition.width;
+diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c
+index eccd20c..cca1d3d 100644
+--- a/gtk/gtktreeview.c
++++ b/gtk/gtktreeview.c
+@@ -14251,7 +14251,7 @@ gtk_tree_view_search_position_func (GtkTreeView *tree_view,
+   GdkRectangle monitor;
+
+   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
+-  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
++  gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
+
+   gtk_widget_realize (search_dialog);
+
+diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
+index 8f174c6..7094eb6 100644
+--- a/gtk/gtkwindow.c
++++ b/gtk/gtkwindow.c
+@@ -5771,7 +5771,7 @@ center_window_on_monitor (GtkWindow *window,
+   if (monitor_num == -1)
+     monitor_num = get_center_monitor_of_window (window);
+
+-  gdk_screen_get_monitor_geometry (gtk_window_check_screen (window),
++  gdk_screen_get_monitor_workarea (gtk_window_check_screen (window),
+                                  monitor_num, &monitor);
+
+   *x = (monitor.width - w) / 2 + monitor.x;
+@@ -5917,7 +5917,7 @@ gtk_window_compute_configure_request (GtkWindow    *window,
+              */
+             if (monitor_num >= 0)
+               {
+-                gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
++                gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
+                 clamp_window_to_rectangle (&x, &y, w, h, &monitor);
+               }
+           }
+@@ -5952,7 +5952,7 @@ gtk_window_compute_configure_request (GtkWindow    *window,
+              */
+             if (monitor_num >= 0)
+               {
+-                gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
++                gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
+                 clamp_window_to_rectangle (&x, &y, w, h, &monitor);
+               }
+           }
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0005-gtk-don-t-scroll-combo-box-menus-if-less-than-3-item.patch b/bockbuild/mac-sdk/patches/gtk/0005-gtk-don-t-scroll-combo-box-menus-if-less-than-3-item.patch
new file mode 100644 (file)
index 0000000..c2c0ba5
--- /dev/null
@@ -0,0 +1,61 @@
+From df766e7dc27c8bc373dd5eaeaa5bddb7702605fd Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Fri, 23 Nov 2012 15:28:26 +0100
+Subject: [PATCH 05/68] gtk: don't scroll combo box menus if less than 3
+ itemss are visible
+
+---
+ gtk/gtkcombobox.c |   38 ++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 38 insertions(+)
+
+diff --git a/gtk/gtkcombobox.c b/gtk/gtkcombobox.c
+index d997d0d..3b58f32 100644
+--- a/gtk/gtkcombobox.c
++++ b/gtk/gtkcombobox.c
+@@ -1781,6 +1781,44 @@ gtk_combo_box_menu_position (GtkMenu  *menu,
+                                   menu_item);
+
+       gtk_combo_box_menu_position_over (menu, x, y, push_in, user_data);
++
++      if (menu_item)
++        {
++          GdkScreen *screen;
++          GtkWidget *widget = GTK_WIDGET (combo_box);
++          gint monitor_num;
++          GdkRectangle monitor;
++          gint px, py;
++          gint menu_height;
++          gint scroll_offset = 0;
++
++          screen = gtk_widget_get_screen (widget);
++          gdk_display_get_pointer (gdk_screen_get_display (screen),
++                                   NULL, &px, &py, NULL);
++
++          monitor_num = gdk_screen_get_monitor_at_point (screen, px, py);
++
++          gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
++
++          menu_height = GTK_WIDGET (menu)->requisition.height;
++
++          if (*y + menu_height > monitor.y + monitor.height)
++            {
++              scroll_offset -= *y + menu_height - (monitor.y + monitor.height);
++            }
++          else if (*y < monitor.y)
++            {
++              scroll_offset += monitor.y - *y;
++            }
++
++          /* don't scroll the menu if less than 3 items would be visible,
++           * use 4 to roughly take the scroll buttons into account
++           */
++          if (scroll_offset != 0 &&
++              (menu->toplevel->requisition.height - ABS (scroll_offset) <
++               5 * menu_item->requisition.height))
++            gtk_combo_box_menu_position_below (menu, x, y, push_in, user_data);
++        }
+     }
+
+   if (!gtk_widget_get_visible (GTK_MENU (priv->popup_widget)->toplevel))
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0006-gtk-paint-only-the-exposed-region-in-gdk_window_expo.patch b/bockbuild/mac-sdk/patches/gtk/0006-gtk-paint-only-the-exposed-region-in-gdk_window_expo.patch
new file mode 100644 (file)
index 0000000..c3e47b6
--- /dev/null
@@ -0,0 +1,47 @@
+From 37f07504f203aec1345a75abeb07172259bd5973 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Sun, 27 May 2012 22:51:33 +0200
+Subject: [PATCH 06/68] gtk: paint only the exposed region in
+ gdk_window_expose()
+
+---
+ gtk/gtkwindow.c |   19 +++++++++++++++++--
+ 1 file changed, 17 insertions(+), 2 deletions(-)
+
+diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
+index 7094eb6..89c91da 100644
+--- a/gtk/gtkwindow.c
++++ b/gtk/gtkwindow.c
+@@ -6631,13 +6631,28 @@ gtk_window_paint (GtkWidget     *widget,
+                     GTK_SHADOW_NONE, area, widget, "base", 0, 0, -1, -1);
+ }
+
++static void
++gtk_window_paint_region (GtkWidget *widget,
++                         GdkRegion *region)
++{
++  int i, n_rectangles;
++  GdkRectangle *rectangles = NULL;
++
++  gdk_region_get_rectangles (region, &rectangles, &n_rectangles);
++
++  for (i = 0; i < n_rectangles; i++)
++    gtk_window_paint (widget, &rectangles[i]);
++
++  g_free (rectangles);
++}
++
+ static gint
+ gtk_window_expose (GtkWidget      *widget,
+                  GdkEventExpose *event)
+ {
+   if (!gtk_widget_get_app_paintable (widget))
+-    gtk_window_paint (widget, &event->area);
+-
++    gtk_window_paint_region (widget, event->region);
++
+   if (GTK_WIDGET_CLASS (gtk_window_parent_class)->expose_event)
+     return GTK_WIDGET_CLASS (gtk_window_parent_class)->expose_event (widget, event);
+
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0007-Implement-gtk-enable-overlay-scrollbars-GtkSetting.patch b/bockbuild/mac-sdk/patches/gtk/0007-Implement-gtk-enable-overlay-scrollbars-GtkSetting.patch
new file mode 100644 (file)
index 0000000..b3a6542
--- /dev/null
@@ -0,0 +1,133 @@
+From 4c79075b4d396ba009b0f0e70d05c1c253cc3da6 Mon Sep 17 00:00:00 2001
+From: Kristian Rietveld <kris@lanedo.com>
+Date: Fri, 24 Aug 2012 12:12:04 +0200
+Subject: [PATCH 07/68] Implement gtk-enable-overlay-scrollbars GtkSetting
+
+And set this up such that on OS X
+NSPreferredScrollerDidChangeNotification is followed.
+---
+ gdk/quartz/gdkevents-quartz.c |   56 ++++++++++++++++++++++++++++++++++++++++-
+ gtk/gtksettings.c             |   20 ++++++++++++++-
+ 2 files changed, 74 insertions(+), 2 deletions(-)
+
+diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
+index 53f1962..c99a2c9 100644
+--- a/gdk/quartz/gdkevents-quartz.c
++++ b/gdk/quartz/gdkevents-quartz.c
+@@ -85,6 +85,10 @@ gdk_quartz_ns_notification_callback (CFNotificationCenterRef  center,
+                        CFSTR("AppleNoRedisplayAppearancePreferenceChanged"),
+                        0) == kCFCompareEqualTo)
+     new_event.setting.name = "gtk-primary-button-warps-slider";
++  else if (CFStringCompare (name,
++                            CFSTR("NSPreferredScrollerStyleDidChangeNotification"),
++                            0) == kCFCompareEqualTo)
++    new_event.setting.name = "gtk-enable-overlay-scrollbars";
+
+   if (!new_event.setting.name)
+     return;
+@@ -114,6 +118,20 @@ gdk_quartz_events_init_notifications (void)
+                                    CFSTR ("AppleNoRedisplayAppearancePreferenceChanged"),
+                                    NULL,
+                                    CFNotificationSuspensionBehaviorDeliverImmediately);
++
++  /* The preferred scroller notification and property are only available on Lion
++   * and higher. Also, beware that the notification will only start working after the
++   * property has been queried for the first time!.
++   */
++  if (gdk_quartz_osx_version () >= GDK_OSX_LION)
++    {
++      CFNotificationCenterAddObserver (CFNotificationCenterGetLocalCenter (),
++                                       NULL,
++                                       &gdk_quartz_ns_notification_callback,
++                                       CFSTR ("NSPreferredScrollerStyleDidChangeNotification"),
++                                       NULL,
++                                       CFNotificationSuspensionBehaviorDeliverImmediately);
++    }
+ }
+
+ void
+@@ -1686,7 +1704,43 @@ gdk_screen_get_setting (GdkScreen   *screen,
+
+       return TRUE;
+     }
+-
++  else if (strcmp (name, "gtk-enable-overlay-scrollbars") == 0)
++    {
++      gboolean enabled = FALSE;
++
++      GDK_QUARTZ_ALLOC_POOL;
++
++      if (gdk_quartz_osx_version () >= GDK_OSX_LION)
++        {
++          /* Use an integer instead of NSScrollerStyle to allow things to be compiled
++           * on < 10.7 systems.
++           */
++          int setting = (int)[NSScroller preferredScrollerStyle];
++
++          if (setting == 1)
++            /* 1 == NSScrollerStyleOverlay */
++            enabled = TRUE;
++          else
++            enabled = FALSE;
++        }
++      else
++        {
++          /* On systems prior to Lion, default to legacy scrolling. */
++          enabled = FALSE;
++        }
++
++      g_value_set_boolean (value, enabled);
++
++      /* Initialize after quering the property for the first theme,
++       * notifications are otherwise not received!
++       */
++      gdk_quartz_events_init_notifications ();
++
++      GDK_QUARTZ_RELEASE_POOL;
++
++      return TRUE;
++    }
++
+   /* FIXME: Add more settings */
+
+   return FALSE;
+diff --git a/gtk/gtksettings.c b/gtk/gtksettings.c
+index 3fbbf00..1455db1 100644
+--- a/gtk/gtksettings.c
++++ b/gtk/gtksettings.c
+@@ -139,7 +139,8 @@ enum {
+   PROP_LABEL_SELECT_ON_FOCUS,
+   PROP_COLOR_PALETTE,
+   PROP_IM_PREEDIT_STYLE,
+-  PROP_IM_STATUS_STYLE
++  PROP_IM_STATUS_STYLE,
++  PROP_ENABLE_OVERLAY_SCROLLBARS
+ };
+
+ /* --- prototypes --- */
+@@ -1205,6 +1206,23 @@ gtk_settings_class_init (GtkSettingsClass *class)
+                                                                 GTK_PARAM_READWRITE),
+                                              gtk_rc_property_parse_enum);
+   g_assert (result == PROP_IM_STATUS_STYLE);
++
++  /**
++   * GtkSettings:gtk-enable-overlay-scrollbars:
++   *
++   * Whether overlay scrollbars should be enabled.
++   *
++   * Since: Xamarin specific API.
++   */
++  result = settings_install_property_parser (class,
++                                             g_param_spec_boolean ("gtk-enable-overlay-scrollbars",
++                                                                   P_("Enable Overlay Scrollbars"),
++                                                                   P_("Whether to enable overlay scrollbars."),
++                                                                   FALSE,
++                                                                   GTK_PARAM_READWRITE),
++                                             NULL);
++
++  g_assert (result == PROP_ENABLE_OVERLAY_SCROLLBARS);
+ }
+
+ static void
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0008-Smooth-scrolling.patch b/bockbuild/mac-sdk/patches/gtk/0008-Smooth-scrolling.patch
new file mode 100644 (file)
index 0000000..3b660d7
--- /dev/null
@@ -0,0 +1,418 @@
+From ab426801023babba7513d9e27a4dbdd44bdbc318 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Tue, 8 May 2012 14:11:50 +0200
+Subject: [PATCH 08/68] Smooth scrolling
+
+---
+ gdk/gdkevents.c               |   32 +++++++++++++++++
+ gdk/gdkevents.h               |    6 ++++
+ gdk/gdkwindow.c               |    3 ++
+ gdk/quartz/gdkevents-quartz.c |   80 +++++++++++++++++++++++++++++++----------
+ gtk/gtkrange.c                |   51 +++++++++++++++++++-------
+ gtk/gtkrange.h                |    4 +--
+ gtk/gtkscrolledwindow.c       |   74 ++++++++++++++++++++++++++++++--------
+ 7 files changed, 203 insertions(+), 47 deletions(-)
+
+diff --git a/gdk/gdkevents.c b/gdk/gdkevents.c
+index 53833a0..0f8bba2 100644
+--- a/gdk/gdkevents.c
++++ b/gdk/gdkevents.c
+@@ -392,6 +392,8 @@ gdk_event_new (GdkEventType type)
+       new_event->scroll.y = 0.;
+       new_event->scroll.x_root = 0.;
+       new_event->scroll.y_root = 0.;
++      new_event->scroll.delta_x = 0.;
++      new_event->scroll.delta_y = 0.;
+       break;
+     case GDK_ENTER_NOTIFY:
+     case GDK_LEAVE_NOTIFY:
+@@ -845,6 +847,36 @@ gdk_event_get_root_coords (const GdkEvent *event,
+   return fetched;
+ }
+
++gboolean
++gdk_event_get_scroll_deltas (const GdkEvent *event,
++                             gdouble        *delta_x,
++                             gdouble        *delta_y)
++{
++  gboolean fetched = TRUE;
++  gdouble dx = 0.0;
++  gdouble dy = 0.0;
++
++  switch (event->type)
++    {
++    case GDK_SCROLL:
++      fetched = event->scroll.has_deltas;
++      dx = event->scroll.delta_x;
++      dy = event->scroll.delta_y;
++      break;
++    default:
++      fetched = FALSE;
++      break;
++    }
++
++  if (delta_x)
++    *delta_x = dx;
++
++  if (delta_y)
++    *delta_y = dy;
++
++  return fetched;
++}
++
+ /**
+  * gdk_event_get_axis:
+  * @event: a #GdkEvent
+diff --git a/gdk/gdkevents.h b/gdk/gdkevents.h
+index 0602bd0..f6b4e04 100644
+--- a/gdk/gdkevents.h
++++ b/gdk/gdkevents.h
+@@ -337,6 +337,9 @@ struct _GdkEventScroll
+   GdkScrollDirection direction;
+   GdkDevice *device;
+   gdouble x_root, y_root;
++  gboolean has_deltas;
++  gdouble delta_x;
++  gdouble delta_y;
+ };
+
+ struct _GdkEventKey
+@@ -537,6 +540,9 @@ gboolean  gdk_event_get_coords             (const GdkEvent  *event,
+ gboolean  gdk_event_get_root_coords   (const GdkEvent  *event,
+                                        gdouble         *x_root,
+                                        gdouble         *y_root);
++gboolean  gdk_event_get_scroll_deltas   (const GdkEvent *event,
++                                         gdouble         *delta_x,
++                                         gdouble         *delta_y);
+ gboolean  gdk_event_get_axis            (const GdkEvent  *event,
+                                          GdkAxisUse       axis_use,
+                                          gdouble         *value);
+diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
+index f5f0339..d48751e 100644
+--- a/gdk/gdkwindow.c
++++ b/gdk/gdkwindow.c
+@@ -10800,6 +10800,9 @@ proxy_button_event (GdkEvent *source_event,
+       event->scroll.y_root = source_event->scroll.y_root;
+       event->scroll.state = state;
+       event->scroll.device = source_event->scroll.device;
++      event->scroll.has_deltas = source_event->scroll.has_deltas;
++      event->scroll.delta_x = source_event->scroll.delta_x;
++      event->scroll.delta_y = source_event->scroll.delta_y;
+       return TRUE;
+
+     default:
+diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
+index c99a2c9..e7d97dc 100644
+--- a/gdk/quartz/gdkevents-quartz.c
++++ b/gdk/quartz/gdkevents-quartz.c
+@@ -57,6 +57,13 @@ static GdkWindow *find_toplevel_under_pointer   (GdkDisplay *display,
+                                                  gint       *x,
+                                                  gint       *y);
+
++/* Protocol to build cleanly for OSX < 10.7 */
++@protocol PreciseDeltas
++- (BOOL) hasPreciseScrollingDeltas;
++- (CGFloat) scrollingDeltaX;
++- (CGFloat) scrollingDeltaY;
++@end
++
+
+ NSEvent *
+ gdk_quartz_event_get_nsevent (GdkEvent *event)
+@@ -980,6 +987,9 @@ fill_scroll_event (GdkWindow          *window,
+                    gint                y,
+                    gint                x_root,
+                    gint                y_root,
++                   gboolean            has_deltas,
++                   gdouble             delta_x,
++                   gdouble             delta_y,
+                    GdkScrollDirection  direction)
+ {
+   GdkWindowObject *private;
+@@ -999,6 +1009,9 @@ fill_scroll_event (GdkWindow          *window,
+   event->scroll.state = get_keyboard_modifiers_from_ns_event (nsevent);
+   event->scroll.direction = direction;
+   event->scroll.device = _gdk_display->core_pointer;
++  event->scroll.has_deltas = has_deltas;
++  event->scroll.delta_x = delta_x;
++  event->scroll.delta_y = delta_y;
+ }
+
+ static void
+@@ -1471,28 +1484,59 @@ gdk_event_translate (GdkEvent *event,
+
+     case NSScrollWheel:
+       {
+-      float dx = [nsevent deltaX];
+-      float dy = [nsevent deltaY];
+-      GdkScrollDirection direction;
+-
+-        if (dy != 0)
+-          {
+-            if (dy < 0.0)
+-              direction = GDK_SCROLL_DOWN;
+-            else
+-              direction = GDK_SCROLL_UP;
++        GdkScrollDirection direction;
++      float dx;
++      float dy;
+
+-            fill_scroll_event (window, event, nsevent, x, y, x_root, y_root, direction);
+-          }
++      if (gdk_quartz_osx_version() >= GDK_OSX_LION &&
++          [(id <PreciseDeltas>) nsevent hasPreciseScrollingDeltas])
++        {
++          dx = [(id <PreciseDeltas>) nsevent scrollingDeltaX];
++          dy = [(id <PreciseDeltas>) nsevent scrollingDeltaY];
+
+-        if (dx != 0)
+-          {
+-            if (dx < 0.0)
+-              direction = GDK_SCROLL_RIGHT;
++            if (fabs (dy) > fabs (dx))
++              {
++                if (dy < 0.0)
++                  direction = GDK_SCROLL_DOWN;
++                else
++                  direction = GDK_SCROLL_UP;
++              }
+             else
+-              direction = GDK_SCROLL_LEFT;
++              {
++                if (dx < 0.0)
++                  direction = GDK_SCROLL_RIGHT;
++                else
++                  direction = GDK_SCROLL_LEFT;
++              }
+
+-            fill_scroll_event (window, event, nsevent, x, y, x_root, y_root, direction);
++            fill_scroll_event (window, event, nsevent, x, y, x_root, y_root,
++                               TRUE, -dx, -dy, direction);
++        }
++      else
++        {
++          dx = [nsevent deltaX];
++          dy = [nsevent deltaY];
++
++            if (dy != 0.0)
++              {
++                if (dy < 0.0)
++                  direction = GDK_SCROLL_DOWN;
++                else
++                  direction = GDK_SCROLL_UP;
++
++                fill_scroll_event (window, event, nsevent, x, y, x_root, y_root,
++                                   FALSE, 0.0, fabs (dy), direction);
++              }
++            else if (dx != 0.0)
++              {
++                if (dx < 0.0)
++                  direction = GDK_SCROLL_RIGHT;
++                else
++                  direction = GDK_SCROLL_LEFT;
++
++                fill_scroll_event (window, event, nsevent, x, y, x_root, y_root,
++                                   FALSE, fabs (dx), 0.0, direction);
++              }
+           }
+       }
+       break;
+diff --git a/gtk/gtkrange.c b/gtk/gtkrange.c
+index 245fbf6..d39f045 100644
+--- a/gtk/gtkrange.c
++++ b/gtk/gtkrange.c
+@@ -2561,7 +2561,7 @@ gtk_range_button_release (GtkWidget      *widget,
+ /**
+  * _gtk_range_get_wheel_delta:
+  * @range: a #GtkRange
+- * @direction: A #GdkScrollDirection
++ * @event: A #GdkEventScroll
+  *
+  * Returns a good step value for the mouse wheel.
+  *
+@@ -2570,27 +2570,52 @@ gtk_range_button_release (GtkWidget      *widget,
+  * Since: 2.4
+  **/
+ gdouble
+-_gtk_range_get_wheel_delta (GtkRange           *range,
+-                          GdkScrollDirection  direction)
++_gtk_range_get_wheel_delta (GtkRange       *range,
++                            GdkEventScroll *event)
+ {
+   GtkAdjustment *adj = range->adjustment;
++  gdouble dx, dy;
+   gdouble delta;
+
+-  if (GTK_IS_SCROLLBAR (range))
+-    delta = pow (adj->page_size, 2.0 / 3.0);
++  if (gdk_event_get_scroll_deltas ((GdkEvent *) event, &dx, &dy))
++    {
++      GtkAllocation allocation;
++
++      gtk_widget_get_allocation (GTK_WIDGET (range), &allocation);
++
++      if (gtk_orientable_get_orientation (GTK_ORIENTABLE (range)) == GTK_ORIENTATION_HORIZONTAL)
++        {
++          if (GTK_IS_SCROLLBAR (range) && adj->page_size > 0)
++            delta = dx * adj->page_size / allocation.width;
++          else
++            delta = dx * (adj->upper - adj->lower) / allocation.width;
++        }
++      else
++        {
++          if (GTK_IS_SCROLLBAR (range) && adj->page_size > 0)
++            delta = dy * adj->page_size / allocation.height;
++          else
++            delta = dy * (adj->upper - adj->lower) / allocation.height;
++        }
++    }
+   else
+-    delta = adj->step_increment * 2;
+-
+-  if (direction == GDK_SCROLL_UP ||
+-      direction == GDK_SCROLL_LEFT)
+-    delta = - delta;
+-
++    {
++      if (GTK_IS_SCROLLBAR (range))
++        delta = pow (adj->page_size, 2.0 / 3.0);
++      else
++        delta = adj->step_increment * 2;
++
++      if (event->direction == GDK_SCROLL_UP ||
++          event->direction == GDK_SCROLL_LEFT)
++        delta = - delta;
++    }
++
+   if (range->inverted)
+     delta = - delta;
+
+   return delta;
+ }
+-
++
+ static gboolean
+ gtk_range_scroll_event (GtkWidget      *widget,
+                       GdkEventScroll *event)
+@@ -2603,7 +2628,7 @@ gtk_range_scroll_event (GtkWidget      *widget,
+       gdouble delta;
+       gboolean handled;
+
+-      delta = _gtk_range_get_wheel_delta (range, event->direction);
++      delta = _gtk_range_get_wheel_delta (range, event);
+
+       g_signal_emit (range, signals[CHANGE_VALUE], 0,
+                      GTK_SCROLL_JUMP, adj->value + delta,
+diff --git a/gtk/gtkrange.h b/gtk/gtkrange.h
+index 5463140..c672acb 100644
+--- a/gtk/gtkrange.h
++++ b/gtk/gtkrange.h
+@@ -199,8 +199,8 @@ gint                gtk_range_get_round_digits             (GtkRange      *range
+
+
+ /* internal API */
+-gdouble            _gtk_range_get_wheel_delta              (GtkRange      *range,
+-                                                            GdkScrollDirection direction);
++gdouble            _gtk_range_get_wheel_delta              (GtkRange       *range,
++                                                            GdkEventScroll *event);
+
+ void               _gtk_range_set_stop_values              (GtkRange      *range,
+                                                             gdouble       *values,
+diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
+index 1704d3c..2288b2f 100644
+--- a/gtk/gtkscrolledwindow.c
++++ b/gtk/gtkscrolledwindow.c
+@@ -1565,31 +1565,77 @@ static gboolean
+ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+                                 GdkEventScroll *event)
+ {
+-  GtkWidget *range;
++  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
++  gboolean handled = FALSE;
++  gdouble delta_x;
++  gdouble delta_y;
+
+   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (widget), FALSE);
+   g_return_val_if_fail (event != NULL, FALSE);
+
+-  if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_DOWN)
+-    range = GTK_SCROLLED_WINDOW (widget)->vscrollbar;
+-  else
+-    range = GTK_SCROLLED_WINDOW (widget)->hscrollbar;
++  if (gdk_event_get_scroll_deltas ((GdkEvent *) event, &delta_x, &delta_y))
++    {
++      if (delta_x != 0.0 && scrolled_window->hscrollbar &&
++          gtk_widget_get_visible (scrolled_window->hscrollbar))
++        {
++          GtkAdjustment *adj;
++          gdouble new_value;
++
++          adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
++
++          new_value = CLAMP (gtk_adjustment_get_value (adj) + delta_x,
++                             gtk_adjustment_get_lower (adj),
++                             gtk_adjustment_get_upper (adj) -
++                             gtk_adjustment_get_page_size (adj));
++
++          gtk_adjustment_set_value (adj, new_value);
++
++          handled = TRUE;
++        }
++
++      if (delta_y != 0.0 && scrolled_window->vscrollbar &&
++          gtk_widget_get_visible (scrolled_window->vscrollbar))
++        {
++          GtkAdjustment *adj;
++          gdouble new_value;
++
++          adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
++
++          new_value = CLAMP (gtk_adjustment_get_value (adj) + delta_y,
++                             gtk_adjustment_get_lower (adj),
++                             gtk_adjustment_get_upper (adj) -
++                             gtk_adjustment_get_page_size (adj));
+
+-  if (range && gtk_widget_get_visible (range))
++          gtk_adjustment_set_value (adj, new_value);
++
++          handled = TRUE;
++        }
++    }
++  else
+     {
+-      GtkAdjustment *adj = GTK_RANGE (range)->adjustment;
+-      gdouble delta, new_value;
++      GtkWidget *range;
+
+-      delta = _gtk_range_get_wheel_delta (GTK_RANGE (range), event->direction);
++      if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_DOWN)
++        range = scrolled_window->vscrollbar;
++      else
++        range = scrolled_window->hscrollbar;
+
+-      new_value = CLAMP (adj->value + delta, adj->lower, adj->upper - adj->page_size);
+-
+-      gtk_adjustment_set_value (adj, new_value);
++      if (range && gtk_widget_get_visible (range))
++        {
++          GtkAdjustment *adj = GTK_RANGE (range)->adjustment;
++          gdouble delta, new_value;
+
+-      return TRUE;
++          delta = _gtk_range_get_wheel_delta (GTK_RANGE (range), event);
++
++          new_value = CLAMP (adj->value + delta, adj->lower, adj->upper - adj->page_size);
++
++          gtk_adjustment_set_value (adj, new_value);
++
++          handled = TRUE;
++        }
+     }
+
+-  return FALSE;
++  return handled;
+ }
+
+ static gboolean
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0009-gtk-Add-a-way-to-do-event-capture.patch b/bockbuild/mac-sdk/patches/gtk/0009-gtk-Add-a-way-to-do-event-capture.patch
new file mode 100644 (file)
index 0000000..30c5138
--- /dev/null
@@ -0,0 +1,471 @@
+From a484a0af1fc0ab98694c13970a308edeb52f39a6 Mon Sep 17 00:00:00 2001
+From: Carlos Garcia Campos <cgarcia@igalia.com>
+Date: Tue, 8 Feb 2011 14:49:31 +0100
+Subject: [PATCH 09/68] gtk: Add a way to do event capture
+
+This patch adds a capture phase to GTK+'s event propagation
+model. Events are first propagated from the toplevel (or the
+grab widget, if a grab is in place) down to the target widget
+ and then back up. The second phase is using the existing
+::event signal, the new capture phase is using a private
+API instead of a public signal for now.
+
+This mechanism can be used in many places where we currently
+have to prevent child widgets from getting events by putting
+an input-only window over them. It will also be used to implement
+kinetic scrolling in subsequent patches.
+
+http://bugzilla.gnome.org/show_bug.cgi?id=641836
+
+We automatically request more motion events in behalf of
+the original widget if it listens to motion hints. So
+the capturing widget doesn't need to handle such
+implementation details.
+
+We are not making event capture part of the public API for 3.4,
+which is why there is no ::captured-event signal.
+
+Conflicts:
+
+       gtk/gtkmain.c
+       gtk/gtkwidget.c
+       gtk/gtkwidgetprivate.h
+---
+ gtk/gtkmain.c    |  268 +++++++++++++++++++++++++++++++++++-------------------
+ gtk/gtkprivate.h |   14 +++
+ gtk/gtkwidget.c  |   53 +++++++++++
+ 3 files changed, 241 insertions(+), 94 deletions(-)
+
+diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
+index 56c92db..21345ed 100644
+--- a/gtk/gtkmain.c
++++ b/gtk/gtkmain.c
+@@ -1490,7 +1490,8 @@ void
+ gtk_main_do_event (GdkEvent *event)
+ {
+   GtkWidget *event_widget;
+-  GtkWidget *grab_widget;
++  GtkWidget *grab_widget = NULL;
++  GtkWidget *topmost_widget = NULL;
+   GtkWindowGroup *window_group;
+   GdkEvent *rewritten_event = NULL;
+   GList *tmp_list;
+@@ -1552,7 +1553,14 @@ gtk_main_do_event (GdkEvent *event)
+   if (window_group->grabs)
+     {
+       grab_widget = window_group->grabs->data;
+-
++
++      /* Find out the topmost widget where captured event propagation
++       * should start, which is the widget holding the GTK+ grab
++       * if any, otherwise it's left NULL and events are emitted
++       * from the toplevel (or topmost parentless parent).
++       */
++      topmost_widget = grab_widget;
++
+       /* If the grab widget is an ancestor of the event widget
+        *  then we send the event to the original event widget.
+        *  This is the key to implementing modality.
+@@ -1636,14 +1644,16 @@ gtk_main_do_event (GdkEvent *event)
+     case GDK_WINDOW_STATE:
+     case GDK_GRAB_BROKEN:
+     case GDK_DAMAGE:
+-      gtk_widget_event (event_widget, event);
++      if (!_gtk_widget_captured_event (event_widget, event))
++        gtk_widget_event (event_widget, event);
+       break;
+
+     case GDK_SCROLL:
+     case GDK_BUTTON_PRESS:
+     case GDK_2BUTTON_PRESS:
+     case GDK_3BUTTON_PRESS:
+-      gtk_propagate_event (grab_widget, event);
++      if (!_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
++        gtk_propagate_event (grab_widget, event);
+       break;
+
+     case GDK_KEY_PRESS:
+@@ -1682,19 +1692,22 @@ gtk_main_do_event (GdkEvent *event)
+     case GDK_BUTTON_RELEASE:
+     case GDK_PROXIMITY_IN:
+     case GDK_PROXIMITY_OUT:
+-      gtk_propagate_event (grab_widget, event);
++      if (!_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
++        gtk_propagate_event (grab_widget, event);
+       break;
+
+     case GDK_ENTER_NOTIFY:
+       GTK_PRIVATE_SET_FLAG (event_widget, GTK_HAS_POINTER);
+       _gtk_widget_set_pointer_window (event_widget, event->any.window);
+-      if (gtk_widget_is_sensitive (grab_widget))
++      if (gtk_widget_is_sensitive (grab_widget) &&
++          !_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
+       gtk_widget_event (grab_widget, event);
+       break;
+
+     case GDK_LEAVE_NOTIFY:
+       GTK_PRIVATE_UNSET_FLAG (event_widget, GTK_HAS_POINTER);
+-      if (gtk_widget_is_sensitive (grab_widget))
++      if (gtk_widget_is_sensitive (grab_widget) &&
++          !_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
+       gtk_widget_event (grab_widget, event);
+       break;
+
+@@ -2400,44 +2413,96 @@ gtk_quit_invoke_function (GtkQuitFunction *quitf)
+     }
+ }
+
+-/**
+- * gtk_propagate_event:
+- * @widget: a #GtkWidget
+- * @event: an event
+- *
+- * Sends an event to a widget, propagating the event to parent widgets
+- * if the event remains unhandled. Events received by GTK+ from GDK
+- * normally begin in gtk_main_do_event(). Depending on the type of
+- * event, existence of modal dialogs, grabs, etc., the event may be
+- * propagated; if so, this function is used. gtk_propagate_event()
+- * calls gtk_widget_event() on each widget it decides to send the
+- * event to.  So gtk_widget_event() is the lowest-level function; it
+- * simply emits the "event" and possibly an event-specific signal on a
+- * widget.  gtk_propagate_event() is a bit higher-level, and
+- * gtk_main_do_event() is the highest level.
+- *
+- * All that said, you most likely don't want to use any of these
+- * functions; synthesizing events is rarely needed. Consider asking on
+- * the mailing list for better ways to achieve your goals. For
+- * example, use gdk_window_invalidate_rect() or
+- * gtk_widget_queue_draw() instead of making up expose events.
+- *
+- **/
+-void
+-gtk_propagate_event (GtkWidget *widget,
+-                   GdkEvent  *event)
++static gboolean
++propagate_event_up (GtkWidget *widget,
++                    GdkEvent  *event,
++                    GtkWidget *topmost)
+ {
+-  gint handled_event;
+-
+-  g_return_if_fail (GTK_IS_WIDGET (widget));
+-  g_return_if_fail (event != NULL);
+-
+-  handled_event = FALSE;
++  gboolean handled_event = FALSE;
+
+-  g_object_ref (widget);
+-
+-  if ((event->type == GDK_KEY_PRESS) ||
+-      (event->type == GDK_KEY_RELEASE))
++  /* Propagate event up the widget tree so that
++   * parents can see the button and motion
++   * events of the children.
++   */
++  while (TRUE)
++    {
++      GtkWidget *tmp;
++
++      g_object_ref (widget);
++
++      /* Scroll events are special cased here because it
++       * feels wrong when scrolling a GtkViewport, say,
++       * to have children of the viewport eat the scroll
++       * event
++       */
++      if (!gtk_widget_is_sensitive (widget))
++        handled_event = event->type != GDK_SCROLL;
++      else
++        handled_event = gtk_widget_event (widget, event);
++
++      tmp = gtk_widget_get_parent (widget);
++      g_object_unref (widget);
++
++      if (widget == topmost)
++        break;
++
++      widget = tmp;
++
++      if (handled_event || !widget)
++        break;
++    }
++
++  return handled_event;
++}
++
++static gboolean
++propagate_event_down (GtkWidget *widget,
++                      GdkEvent  *event,
++                      GtkWidget *topmost)
++{
++  gint handled_event = FALSE;
++  GList *widgets = NULL;
++  GList *l;
++
++  widgets = g_list_prepend (widgets, g_object_ref (widget));
++  while (widget && widget != topmost)
++    {
++      widget = gtk_widget_get_parent (widget);
++      if (!widget)
++        break;
++
++      widgets = g_list_prepend (widgets, g_object_ref (widget));
++
++      if (widget == topmost)
++        break;
++    }
++
++  for (l = widgets; l && !handled_event; l = g_list_next (l))
++    {
++      widget = (GtkWidget *)l->data;
++
++      if (!gtk_widget_is_sensitive (widget))
++        handled_event = TRUE;
++      else
++        handled_event = _gtk_widget_captured_event (widget, event);
++    }
++  g_list_free_full (widgets, (GDestroyNotify)g_object_unref);
++
++  return handled_event;
++}
++
++static gboolean
++propagate_event (GtkWidget *widget,
++                 GdkEvent  *event,
++                 gboolean   captured,
++                 GtkWidget *topmost)
++{
++  gboolean handled_event = FALSE;
++  gboolean (* propagate_func) (GtkWidget *widget, GdkEvent  *event);
++
++  propagate_func = captured ? _gtk_widget_captured_event : gtk_widget_event;
++
++  if (event->type == GDK_KEY_PRESS || event->type == GDK_KEY_RELEASE)
+     {
+       /* Only send key events within Window widgets to the Window
+        *  The Window widget will in turn pass the
+@@ -2448,60 +2513,75 @@ gtk_propagate_event (GtkWidget *widget,
+
+       window = gtk_widget_get_toplevel (widget);
+       if (GTK_IS_WINDOW (window))
+-      {
+-        /* If there is a grab within the window, give the grab widget
+-         * a first crack at the key event
+-         */
+-        if (widget != window && gtk_widget_has_grab (widget))
+-          handled_event = gtk_widget_event (widget, event);
+-
+-        if (!handled_event)
+-          {
+-            window = gtk_widget_get_toplevel (widget);
+-            if (GTK_IS_WINDOW (window))
+-              {
+-                if (gtk_widget_is_sensitive (window))
+-                  gtk_widget_event (window, event);
+-              }
+-          }
+-
+-        handled_event = TRUE; /* don't send to widget */
+-      }
++        {
++          g_object_ref (widget);
++          /* If there is a grab within the window, give the grab widget
++           * a first crack at the key event
++           */
++          if (widget != window && gtk_widget_has_grab (widget))
++            handled_event = propagate_func (widget, event);
++
++          if (!handled_event)
++            {
++              window = gtk_widget_get_toplevel (widget);
++              if (GTK_IS_WINDOW (window))
++                {
++                  if (gtk_widget_is_sensitive (window))
++                    handled_event = propagate_func (window, event);
++                }
++            }
++
++          g_object_unref (widget);
++          return handled_event;
++        }
+     }
+-
+-  /* Other events get propagated up the widget tree
+-   *  so that parents can see the button and motion
+-   *  events of the children.
+-   */
+-  if (!handled_event)
+-    {
+-      while (TRUE)
+-      {
+-        GtkWidget *tmp;
+
+-        /* Scroll events are special cased here because it
+-         * feels wrong when scrolling a GtkViewport, say,
+-         * to have children of the viewport eat the scroll
+-         * event
+-         */
+-        if (!gtk_widget_is_sensitive (widget))
+-          handled_event = event->type != GDK_SCROLL;
+-        else
+-          handled_event = gtk_widget_event (widget, event);
+-
+-        tmp = widget->parent;
+-        g_object_unref (widget);
++  /* Other events get propagated up/down the widget tree */
++  return captured ?
++    propagate_event_down (widget, event, topmost) :
++    propagate_event_up (widget, event, topmost);
++}
+
+-        widget = tmp;
+-
+-        if (!handled_event && widget)
+-          g_object_ref (widget);
+-        else
+-          break;
+-      }
+-    }
+-  else
+-    g_object_unref (widget);
++/**
++ * gtk_propagate_event:
++ * @widget: a #GtkWidget
++ * @event: an event
++ *
++ * Sends an event to a widget, propagating the event to parent widgets
++ * if the event remains unhandled.
++ *
++ * Events received by GTK+ from GDK normally begin in gtk_main_do_event().
++ * Depending on the type of event, existence of modal dialogs, grabs, etc.,
++ * the event may be propagated; if so, this function is used.
++ *
++ * gtk_propagate_event() calls gtk_widget_event() on each widget it
++ * decides to send the event to. So gtk_widget_event() is the lowest-level
++ * function; it simply emits the #GtkWidget::event and possibly an
++ * event-specific signal on a widget. gtk_propagate_event() is a bit
++ * higher-level, and gtk_main_do_event() is the highest level.
++ *
++ * All that said, you most likely don't want to use any of these
++ * functions; synthesizing events is rarely needed. There are almost
++ * certainly better ways to achieve your goals. For example, use
++ * gdk_window_invalidate_rect() or gtk_widget_queue_draw() instead
++ * of making up expose events.
++ */
++void
++gtk_propagate_event (GtkWidget *widget,
++                     GdkEvent  *event)
++{
++  g_return_if_fail (GTK_IS_WIDGET (widget));
++  g_return_if_fail (event != NULL);
++
++  propagate_event (widget, event, FALSE, NULL);
++}
++
++gboolean
++_gtk_propagate_captured_event (GtkWidget *widget,
++                               GdkEvent  *event,
++                               GtkWidget *topmost)
++{
++  return propagate_event (widget, event, TRUE, topmost);
+ }
+
+ #if 0
+diff --git a/gtk/gtkprivate.h b/gtk/gtkprivate.h
+index 6386c32..3865a67 100644
+--- a/gtk/gtkprivate.h
++++ b/gtk/gtkprivate.h
+@@ -152,6 +152,20 @@ gboolean _gtk_translate_keyboard_accel_state     (GdkKeymap       *keymap,
+                                                   GdkModifierType *consumed_modifiers);
+
+
++gboolean        _gtk_propagate_captured_event  (GtkWidget       *widget,
++                                                GdkEvent        *event,
++                                                GtkWidget       *topmost);
++
++typedef gboolean (*GtkCapturedEventHandler) (GtkWidget *widget, GdkEvent *event);
++
++void              _gtk_widget_set_captured_event_handler (GtkWidget               *widget,
++                                                          GtkCapturedEventHandler  handler);
++
++gboolean          _gtk_widget_captured_event               (GtkWidget *widget,
++                                                            GdkEvent  *event);
++
++
++
+ G_END_DECLS
+
+ #endif /* __GTK_PRIVATE_H__ */
+diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
+index 1d1f6bb..8e38ee1 100644
+--- a/gtk/gtkwidget.c
++++ b/gtk/gtkwidget.c
+@@ -351,6 +351,7 @@ static void gtk_widget_set_usize_internal (GtkWidget *widget,
+                                          gint       height);
+ static void gtk_widget_get_draw_rectangle (GtkWidget    *widget,
+                                          GdkRectangle *rect);
++static gboolean event_window_is_still_viewable (GdkEvent *event);
+
+
+ /* --- variables --- */
+@@ -4807,6 +4808,58 @@ gtk_widget_event (GtkWidget *widget,
+   return gtk_widget_event_internal (widget, event);
+ }
+
++void
++_gtk_widget_set_captured_event_handler (GtkWidget               *widget,
++                                        GtkCapturedEventHandler  callback)
++{
++  g_object_set_data (G_OBJECT (widget), "captured-event-handler", callback);
++}
++
++gboolean
++_gtk_widget_captured_event (GtkWidget *widget,
++                            GdkEvent  *event)
++{
++  gboolean return_val = FALSE;
++  GtkCapturedEventHandler handler;
++
++  g_return_val_if_fail (GTK_IS_WIDGET (widget), TRUE);
++  g_return_val_if_fail (WIDGET_REALIZED_FOR_EVENT (widget, event), TRUE);
++
++  if (event->type == GDK_EXPOSE)
++    {
++      g_warning ("Events of type GDK_EXPOSE cannot be synthesized. To get "
++               "the same effect, call gdk_window_invalidate_rect/region(), "
++               "followed by gdk_window_process_updates().");
++      return TRUE;
++    }
++
++  if (!event_window_is_still_viewable (event))
++    return TRUE;
++
++  handler = g_object_get_data (G_OBJECT (widget), "captured-event-handler");
++  if (!handler)
++    return FALSE;
++
++  g_object_ref (widget);
++
++  return_val = handler (widget, event);
++  return_val |= !WIDGET_REALIZED_FOR_EVENT (widget, event);
++
++  /* The widget that was originally to receive the event
++   * handles motion hints, but the capturing widget might
++   * not, so ensure we get further motion events.
++   */
++  if (return_val &&
++      event->type == GDK_MOTION_NOTIFY &&
++      event->motion.is_hint &&
++      (gdk_window_get_events (event->any.window) &
++       GDK_POINTER_MOTION_HINT_MASK) != 0)
++    gdk_event_request_motions (&event->motion);
++
++  g_object_unref (widget);
++
++  return return_val;
++}
+
+ /**
+  * gtk_widget_send_expose:
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0010-gtk-don-t-let-insensitive-children-eat-scroll-events.patch b/bockbuild/mac-sdk/patches/gtk/0010-gtk-don-t-let-insensitive-children-eat-scroll-events.patch
new file mode 100644 (file)
index 0000000..b9d2639
--- /dev/null
@@ -0,0 +1,36 @@
+From c0447e2741b3f9c966e337e6c7baf34cb66b0591 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@lanedo.com>
+Date: Thu, 22 Nov 2012 13:37:58 +0100
+Subject: [PATCH 10/68] gtk: don't let insensitive children eat scroll events
+ when bubbling down
+
+When event capturing is enabled, stop propagating scroll events
+at insensitive widgets, but don't handle them (don't return TRUE),
+so they can bubble up again and reach their handling widgets.
+---
+ gtk/gtkmain.c |   10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
+index 21345ed..5ca0993 100644
+--- a/gtk/gtkmain.c
++++ b/gtk/gtkmain.c
+@@ -2482,7 +2482,15 @@ propagate_event_down (GtkWidget *widget,
+       widget = (GtkWidget *)l->data;
+
+       if (!gtk_widget_is_sensitive (widget))
+-        handled_event = TRUE;
++        {
++          /* stop propagating on SCROLL, but don't handle the event, so it
++           * can propagate up again and reach its handling widget
++           */
++          if (event->type == GDK_SCROLL)
++            break;
++          else
++            handled_event = TRUE;
++        }
+       else
+         handled_event = _gtk_widget_captured_event (widget, event);
+     }
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0011-scrolledwindow-Kinetic-scrolling-support.patch b/bockbuild/mac-sdk/patches/gtk/0011-scrolledwindow-Kinetic-scrolling-support.patch
new file mode 100644 (file)
index 0000000..0a27ac3
--- /dev/null
@@ -0,0 +1,1333 @@
+From 5001b3d9a9b6445ac199156c0f91f28c2112e262 Mon Sep 17 00:00:00 2001
+From: Carlos Garcia Campos <cgarcia@igalia.com>
+Date: Fri, 11 Feb 2011 13:43:56 +0100
+Subject: [PATCH 11/68] scrolledwindow: Kinetic scrolling support
+
+If the scrolling doesn't start after a long press, the scrolling is
+cancelled and events are handled by child widgets normally.
+
+When clicked again close to the previous button press location
+(assuming it had ~0 movement), the scrolled window will allow
+the child to handle the events immediately.
+
+This is so the user doesn't have to wait to the press-and-hold
+timeout in order to operate on the scrolledwindow child.
+
+The innermost scrolled window always gets to capture the events, all
+scrolled windows above it just let the event go through. Ideally
+reaching a limit on the innermost scrolled window would propagate
+the dragging up the hierarchy in order to keep following the touch
+coords, although that'd involve rather evil hacks just to cater
+for broken UIs.
+
+Conflicts:
+
+       docs/reference/gtk/gtk3-sections.txt
+       gtk/gtk.symbols
+       gtk/gtkscrolledwindow.c
+       gtk/gtkscrolledwindow.h
+---
+ gtk/gtk.symbols         |    4 +
+ gtk/gtkscrolledwindow.c | 1061 ++++++++++++++++++++++++++++++++++++++++++++++-
+ gtk/gtkscrolledwindow.h |    8 +
+ 3 files changed, 1058 insertions(+), 15 deletions(-)
+
+diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
+index 6d5d5b6..d13ca41 100644
+--- a/gtk/gtk.symbols
++++ b/gtk/gtk.symbols
+@@ -3730,6 +3730,8 @@ gtk_scrollbar_get_type G_GNUC_CONST
+ gtk_scrolled_window_add_with_viewport
+ gtk_scrolled_window_get_hadjustment
+ gtk_scrolled_window_get_hscrollbar
++gtk_scrolled_window_get_kinetic_scrolling
++gtk_scrolled_window_get_capture_button_press
+ gtk_scrolled_window_get_placement
+ gtk_scrolled_window_get_policy
+ gtk_scrolled_window_get_shadow_type
+@@ -3738,6 +3740,8 @@ gtk_scrolled_window_get_vadjustment
+ gtk_scrolled_window_get_vscrollbar
+ gtk_scrolled_window_new
+ gtk_scrolled_window_set_hadjustment
++gtk_scrolled_window_set_kinetic_scrolling
++gtk_scrolled_window_set_capture_button_press
+ gtk_scrolled_window_set_placement
+ gtk_scrolled_window_set_policy
+ gtk_scrolled_window_set_shadow_type
+diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
+index 2288b2f..694d20a 100644
+--- a/gtk/gtkscrolledwindow.c
++++ b/gtk/gtkscrolledwindow.c
+@@ -33,6 +33,8 @@
+ #include "gtkwindow.h"
+ #include "gtkprivate.h"
+ #include "gtkintl.h"
++#include "gtkmain.h"
++#include "gtkdnd.h"
+ #include "gtkalias.h"
+
+
+@@ -72,14 +74,58 @@
+  */
+
+ #define DEFAULT_SCROLLBAR_SPACING  3
++#define TOUCH_BYPASS_CAPTURED_THRESHOLD 30
++
++/* Kinetic scrolling */
++#define FRAME_INTERVAL (1000 / 60)
++#define MAX_OVERSHOOT_DISTANCE 50
++#define FRICTION_DECELERATION 0.003
++#define OVERSHOOT_INVERSE_ACCELERATION 0.003
++#define RELEASE_EVENT_TIMEOUT 1000
+
+ typedef struct {
+-      gboolean window_placement_set;
+-      GtkCornerType real_window_placement;
++  gboolean window_placement_set;
++  GtkCornerType real_window_placement;
++
++  /* Kinetic scrolling */
++  GdkEvent              *button_press_event;
++  GdkWindow             *overshoot_window;
++  guint                  pointer_grabbed           : 1;
++  guint                  kinetic_scrolling         : 1;
++  guint                  capture_button_press      : 1;
++  guint                  in_drag                   : 1;
++  guint                  last_button_event_valid   : 1;
++
++  guint                  release_timeout_id;
++  guint                  deceleration_id;
++
++  gdouble                last_button_event_x_root;
++  gdouble                last_button_event_y_root;
++
++  gdouble                last_motion_event_x_root;
++  gdouble                last_motion_event_y_root;
++  guint32                last_motion_event_time;
++
++  gdouble                x_velocity;
++  gdouble                y_velocity;
++
++  gdouble                unclamped_hadj_value;
++  gdouble                unclamped_vadj_value;
+ } GtkScrolledWindowPrivate;
+
+ #define GTK_SCROLLED_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_SCROLLED_WINDOW, GtkScrolledWindowPrivate))
+
++typedef struct
++{
++  GtkScrolledWindow     *scrolled_window;
++  gint64                 last_deceleration_time;
++
++  gdouble                x_velocity;
++  gdouble                y_velocity;
++  gdouble                vel_cosine;
++  gdouble                vel_sine;
++} KineticScrollData;
++
+ enum {
+   PROP_0,
+   PROP_HADJUSTMENT,
+@@ -88,7 +134,8 @@ enum {
+   PROP_VSCROLLBAR_POLICY,
+   PROP_WINDOW_PLACEMENT,
+   PROP_WINDOW_PLACEMENT_SET,
+-  PROP_SHADOW_TYPE
++  PROP_SHADOW_TYPE,
++  PROP_KINETIC_SCROLLING
+ };
+
+ /* Signals */
+@@ -119,6 +166,8 @@ static void     gtk_scrolled_window_size_allocate      (GtkWidget         *widge
+                                                         GtkAllocation     *allocation);
+ static gboolean gtk_scrolled_window_scroll_event       (GtkWidget         *widget,
+                                                         GdkEventScroll    *event);
++static gboolean gtk_scrolled_window_captured_event     (GtkWidget         *widget,
++                                                        GdkEvent          *event);
+ static gboolean gtk_scrolled_window_focus              (GtkWidget         *widget,
+                                                         GtkDirectionType   direction);
+ static void     gtk_scrolled_window_add                (GtkContainer      *container,
+@@ -139,9 +188,24 @@ static void     gtk_scrolled_window_relative_allocation(GtkWidget         *widge
+                                                         GtkAllocation     *allocation);
+ static void     gtk_scrolled_window_adjustment_changed (GtkAdjustment     *adjustment,
+                                                         gpointer           data);
++static void     gtk_scrolled_window_adjustment_value_changed (GtkAdjustment     *adjustment,
++                                                              gpointer           data);
+
+ static void  gtk_scrolled_window_update_real_placement (GtkScrolledWindow *scrolled_window);
+
++static void  gtk_scrolled_window_realize               (GtkWidget           *widget);
++static void  gtk_scrolled_window_unrealize             (GtkWidget           *widget);
++static void  gtk_scrolled_window_map                   (GtkWidget           *widget);
++static void  gtk_scrolled_window_unmap                 (GtkWidget           *widget);
++static void  gtk_scrolled_window_grab_notify           (GtkWidget           *widget,
++                                                        gboolean             was_grabbed);
++
++static gboolean _gtk_scrolled_window_set_adjustment_value      (GtkScrolledWindow *scrolled_window,
++                                                                GtkAdjustment     *adjustment,
++                                                                gdouble            value,
++                                                                gboolean           allow_overshooting,
++                                                                gboolean           snap_to_border);
++
+ static guint signals[LAST_SIGNAL] = {0};
+
+ G_DEFINE_TYPE (GtkScrolledWindow, gtk_scrolled_window, GTK_TYPE_BIN)
+@@ -202,6 +266,11 @@ gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
+   widget_class->size_allocate = gtk_scrolled_window_size_allocate;
+   widget_class->scroll_event = gtk_scrolled_window_scroll_event;
+   widget_class->focus = gtk_scrolled_window_focus;
++  widget_class->realize = gtk_scrolled_window_realize;
++  widget_class->unrealize = gtk_scrolled_window_unrealize;
++  widget_class->map = gtk_scrolled_window_map;
++  widget_class->unmap = gtk_scrolled_window_unmap;
++  widget_class->grab_notify = gtk_scrolled_window_grab_notify;
+
+   container_class->add = gtk_scrolled_window_add;
+   container_class->remove = gtk_scrolled_window_remove;
+@@ -301,6 +370,22 @@ gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
+                                                            GTK_PARAM_READABLE));
+
+   /**
++   * GtkScrolledWindow:kinetic-scrolling:
++   *
++   * The kinetic scrolling behavior flags.
++   *
++   * Since: X.XX
++   */
++  g_object_class_install_property (gobject_class,
++                                   PROP_KINETIC_SCROLLING,
++                                   g_param_spec_boolean ("kinetic-scrolling",
++                                                         P_("Kinetic Scrolling"),
++                                                         P_("Kinetic scrolling mode."),
++                                                         TRUE,
++                                                         GTK_PARAM_READABLE |
++                                                         GTK_PARAM_WRITABLE));
++
++  /**
+    * GtkScrolledWindow::scroll-child:
+    * @scrolled_window: a #GtkScrolledWindow
+    * @scroll: a #GtkScrollType describing how much to scroll
+@@ -371,6 +456,12 @@ gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
+   scrolled_window->focus_out = FALSE;
+   scrolled_window->window_placement = GTK_CORNER_TOP_LEFT;
+   gtk_scrolled_window_update_real_placement (scrolled_window);
++
++  if (g_getenv ("GTK2_KINETIC_SCROLLING"))
++    {
++      gtk_scrolled_window_set_kinetic_scrolling (scrolled_window, TRUE);
++      gtk_scrolled_window_set_capture_button_press (scrolled_window, TRUE);
++    }
+ }
+
+ /**
+@@ -458,8 +549,13 @@ gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
+                   "changed",
+                   G_CALLBACK (gtk_scrolled_window_adjustment_changed),
+                   scrolled_window);
++  g_signal_connect (hadjustment,
++                  "value-changed",
++                  G_CALLBACK (gtk_scrolled_window_adjustment_value_changed),
++                  scrolled_window);
+   gtk_scrolled_window_adjustment_changed (hadjustment, scrolled_window);
+-
++  gtk_scrolled_window_adjustment_value_changed (hadjustment, scrolled_window);
++
+   if (bin->child)
+     gtk_widget_set_scroll_adjustments (bin->child,
+                                      gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
+@@ -519,7 +615,12 @@ gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
+                   "changed",
+                   G_CALLBACK (gtk_scrolled_window_adjustment_changed),
+                   scrolled_window);
++  g_signal_connect (vadjustment,
++                  "value-changed",
++                  G_CALLBACK (gtk_scrolled_window_adjustment_value_changed),
++                  scrolled_window);
+   gtk_scrolled_window_adjustment_changed (vadjustment, scrolled_window);
++  gtk_scrolled_window_adjustment_value_changed (vadjustment, scrolled_window);
+
+   if (bin->child)
+     gtk_widget_set_scroll_adjustments (bin->child,
+@@ -842,10 +943,135 @@ gtk_scrolled_window_get_shadow_type (GtkScrolledWindow *scrolled_window)
+   return scrolled_window->shadow_type;
+ }
+
++/**
++ * gtk_scrolled_window_set_kinetic_scrolling:
++ * @scrolled_window: a #GtkScrolledWindow
++ * @kinetic_scrolling: %TRUE to enable kinetic scrolling
++ *
++ * Turns kinetic scrolling on or off.
++ * Kinetic scrolling only applies to devices with source
++ * %GDK_SOURCE_TOUCHSCREEN.
++ *
++ * Since: X.XX
++ **/
++void
++gtk_scrolled_window_set_kinetic_scrolling (GtkScrolledWindow *scrolled_window,
++                                           gboolean           kinetic_scrolling)
++{
++  GtkScrolledWindowPrivate *priv;
++
++  g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
++
++  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  if (priv->kinetic_scrolling == kinetic_scrolling)
++    return;
++
++  priv->kinetic_scrolling = kinetic_scrolling;
++  if (priv->kinetic_scrolling)
++    {
++      _gtk_widget_set_captured_event_handler (GTK_WIDGET (scrolled_window),
++                                              gtk_scrolled_window_captured_event);
++    }
++  else
++    {
++      _gtk_widget_set_captured_event_handler (GTK_WIDGET (scrolled_window), NULL);
++      if (priv->release_timeout_id)
++        {
++          g_source_remove (priv->release_timeout_id);
++          priv->release_timeout_id = 0;
++        }
++      if (priv->deceleration_id)
++        {
++          g_source_remove (priv->deceleration_id);
++          priv->deceleration_id = 0;
++        }
++    }
++  g_object_notify (G_OBJECT (scrolled_window), "kinetic-scrolling");
++}
++
++/**
++ * gtk_scrolled_window_get_kinetic_scrolling:
++ * @scrolled_window: a #GtkScrolledWindow
++ *
++ * Returns the specified kinetic scrolling behavior.
++ *
++ * Return value: the scrolling behavior flags.
++ *
++ * Since: X.XX
++ */
++gboolean
++gtk_scrolled_window_get_kinetic_scrolling (GtkScrolledWindow *scrolled_window)
++{
++  GtkScrolledWindowPrivate *priv;
++
++  g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), FALSE);
++
++  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  return priv->kinetic_scrolling;
++}
++
++/**
++ * gtk_scrolled_window_set_capture_button_press:
++ * @scrolled_window: a #GtkScrolledWindow
++ * @capture_button_press: %TRUE to capture button presses
++ *
++ * Changes the behaviour of @scrolled_window wrt. to the initial
++ * event that possibly starts kinetic scrolling. When @capture_button_press
++ * is set to %TRUE, the event is captured by the scrolled window, and
++ * then later replayed if it is meant to go to the child widget.
++ *
++ * This should be enabled if any child widgets perform non-reversible
++ * actions on #GtkWidget::button-press-event. If they don't, and handle
++ * additionally handle #GtkWidget::grab-broken-event, it might be better
++ * to set @capture_button_press to %FALSE.
++ *
++ * This setting only has an effect if kinetic scrolling is enabled.
++ *
++ * Since: X.XX
++ */
++void
++gtk_scrolled_window_set_capture_button_press (GtkScrolledWindow *scrolled_window,
++                                              gboolean           capture_button_press)
++{
++  GtkScrolledWindowPrivate *priv;
++
++  g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
++
++  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++  priv->capture_button_press = capture_button_press;
++}
++
++/**
++ * gtk_scrolled_window_get_capture_button_press:
++ * @scrolled_window: a #GtkScrolledWindow
++ *
++ * Return whether button presses are captured during kinetic
++ * scrolling. See gtk_scrolled_window_set_capture_button_press().
++ *
++ * Returns: %TRUE if button presses are captured during kinetic scrolling
++ *
++ * Since: X.XX
++ */
++gboolean
++gtk_scrolled_window_get_capture_button_press (GtkScrolledWindow *scrolled_window)
++{
++  GtkScrolledWindowPrivate *priv;
++
++  g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), FALSE);
++
++  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  return priv->capture_button_press;
++}
++
++
+ static void
+ gtk_scrolled_window_destroy (GtkObject *object)
+ {
+   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object);
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+
+   if (scrolled_window->hscrollbar)
+     {
+@@ -868,6 +1094,23 @@ gtk_scrolled_window_destroy (GtkObject *object)
+       scrolled_window->vscrollbar = NULL;
+     }
+
++  if (priv->release_timeout_id)
++    {
++      g_source_remove (priv->release_timeout_id);
++      priv->release_timeout_id = 0;
++    }
++  if (priv->deceleration_id)
++    {
++      g_source_remove (priv->deceleration_id);
++      priv->deceleration_id = 0;
++    }
++
++  if (priv->button_press_event)
++    {
++      gdk_event_free (priv->button_press_event);
++      priv->button_press_event = NULL;
++    }
++
+   GTK_OBJECT_CLASS (gtk_scrolled_window_parent_class)->destroy (object);
+ }
+
+@@ -912,6 +1155,10 @@ gtk_scrolled_window_set_property (GObject      *object,
+       gtk_scrolled_window_set_shadow_type (scrolled_window,
+                                          g_value_get_enum (value));
+       break;
++    case PROP_KINETIC_SCROLLING:
++      gtk_scrolled_window_set_kinetic_scrolling (scrolled_window,
++                                                 g_value_get_boolean (value));
++      break;
+     default:
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       break;
+@@ -952,6 +1199,9 @@ gtk_scrolled_window_get_property (GObject    *object,
+     case PROP_SHADOW_TYPE:
+       g_value_set_enum (value, scrolled_window->shadow_type);
+       break;
++    case PROP_KINETIC_SCROLLING:
++      g_value_set_boolean (value, priv->kinetic_scrolling);
++      break;
+     default:
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       break;
+@@ -1019,10 +1269,10 @@ gtk_scrolled_window_paint (GtkWidget    *widget,
+                          GdkRectangle *area)
+ {
+   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
++  GtkAllocation relative_allocation;
+
+   if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
+     {
+-      GtkAllocation relative_allocation;
+       gboolean scrollbars_within_bevel;
+
+       gtk_widget_style_get (widget, "scrollbars-within-bevel", &scrollbars_within_bevel, NULL);
+@@ -1378,6 +1628,111 @@ gtk_scrolled_window_relative_allocation (GtkWidget     *widget,
+     }
+ }
+
++static gboolean
++_gtk_scrolled_window_get_overshoot (GtkScrolledWindow *scrolled_window,
++                                    gint              *overshoot_x,
++                                    gint              *overshoot_y)
++{
++  GtkScrolledWindowPrivate *priv;
++  GtkAdjustment *vadjustment, *hadjustment;
++  gdouble lower, upper, x, y;
++
++  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  /* Vertical overshoot */
++  vadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
++  lower = gtk_adjustment_get_lower (vadjustment);
++  upper = gtk_adjustment_get_upper (vadjustment) -
++    gtk_adjustment_get_page_size (vadjustment);
++
++  if (priv->unclamped_vadj_value < lower)
++    y = priv->unclamped_vadj_value - lower;
++  else if (priv->unclamped_vadj_value > upper)
++    y = priv->unclamped_vadj_value - upper;
++  else
++    y = 0;
++
++  /* Horizontal overshoot */
++  hadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
++  lower = gtk_adjustment_get_lower (hadjustment);
++  upper = gtk_adjustment_get_upper (hadjustment) -
++    gtk_adjustment_get_page_size (hadjustment);
++
++  if (priv->unclamped_hadj_value < lower)
++    x = priv->unclamped_hadj_value - lower;
++  else if (priv->unclamped_hadj_value > upper)
++    x = priv->unclamped_hadj_value - upper;
++  else
++    x = 0;
++
++  if (overshoot_x)
++    *overshoot_x = x;
++
++  if (overshoot_y)
++    *overshoot_y = y;
++
++  return (x != 0 || y != 0);
++}
++
++static void
++_gtk_scrolled_window_allocate_overshoot_window (GtkScrolledWindow *scrolled_window)
++{
++  GtkAllocation window_allocation, relative_allocation, allocation;
++  GtkScrolledWindowPrivate *priv;
++  GtkWidget *widget = GTK_WIDGET (scrolled_window);
++  gint overshoot_x, overshoot_y;
++
++  if (!gtk_widget_get_realized (widget))
++    return;
++
++  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  gtk_widget_get_allocation (widget, &allocation);
++  gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
++  _gtk_scrolled_window_get_overshoot (scrolled_window,
++                                      &overshoot_x, &overshoot_y);
++
++  window_allocation = relative_allocation;
++  window_allocation.x += allocation.x;
++  window_allocation.y += allocation.y;
++
++  if (overshoot_x < 0)
++    window_allocation.x += -overshoot_x;
++
++  if (overshoot_y < 0)
++    window_allocation.y += -overshoot_y;
++
++  window_allocation.width -= ABS (overshoot_x);
++  window_allocation.height -= ABS (overshoot_y);
++
++  gdk_window_move_resize (priv->overshoot_window,
++                          window_allocation.x, window_allocation.y,
++                          window_allocation.width, window_allocation.height);
++}
++
++static void
++gtk_scrolled_window_allocate_child (GtkScrolledWindow *swindow,
++                                  GtkAllocation     *relative_allocation)
++{
++  GtkWidget     *widget = GTK_WIDGET (swindow), *child;
++  GtkAllocation  allocation;
++  GtkAllocation  child_allocation;
++  gint           overshoot_x, overshoot_y;
++
++  child = gtk_bin_get_child (GTK_BIN (widget));
++
++  gtk_widget_get_allocation (widget, &allocation);
++
++  gtk_scrolled_window_relative_allocation (widget, relative_allocation);
++  _gtk_scrolled_window_get_overshoot (swindow, &overshoot_x, &overshoot_y);
++
++  child_allocation.x = child_allocation.y = 0;
++  child_allocation.width = relative_allocation->width;
++  child_allocation.height = relative_allocation->height;
++
++  gtk_widget_size_allocate (child, &child_allocation);
++}
++
+ static void
+ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
+                                  GtkAllocation *allocation)
+@@ -1389,7 +1744,7 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
+   GtkAllocation child_allocation;
+   gboolean scrollbars_within_bevel;
+   gint scrollbar_spacing;
+-
++
+   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
+   g_return_if_fail (allocation != NULL);
+
+@@ -1420,17 +1775,9 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
+
+       do
+       {
+-        gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
+-
+-        child_allocation.x = relative_allocation.x + allocation->x;
+-        child_allocation.y = relative_allocation.y + allocation->y;
+-        child_allocation.width = relative_allocation.width;
+-        child_allocation.height = relative_allocation.height;
+-
+         previous_hvis = scrolled_window->hscrollbar_visible;
+         previous_vvis = scrolled_window->vscrollbar_visible;
+-
+-        gtk_widget_size_allocate (bin->child, &child_allocation);
++          gtk_scrolled_window_allocate_child (scrolled_window, &relative_allocation);
+
+         /* If, after the first iteration, the hscrollbar and the
+          * vscrollbar flip visiblity, then we need both.
+@@ -1442,6 +1789,8 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
+             scrolled_window->hscrollbar_visible = TRUE;
+             scrolled_window->vscrollbar_visible = TRUE;
+
++              gtk_scrolled_window_allocate_child (scrolled_window, &relative_allocation);
++
+             /* a new resize is already queued at this point,
+              * so we will immediatedly get reinvoked
+              */
+@@ -1559,6 +1908,8 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
+     }
+   else if (gtk_widget_get_visible (scrolled_window->vscrollbar))
+     gtk_widget_hide (scrolled_window->vscrollbar);
++
++  _gtk_scrolled_window_allocate_overshoot_window (scrolled_window);
+ }
+
+ static gboolean
+@@ -1639,6 +1990,555 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+ }
+
+ static gboolean
++_gtk_scrolled_window_set_adjustment_value (GtkScrolledWindow *scrolled_window,
++                                           GtkAdjustment     *adjustment,
++                                           gdouble            value,
++                                           gboolean           allow_overshooting,
++                                           gboolean           snap_to_border)
++{
++  GtkScrolledWindowPrivate *priv;
++  gdouble lower, upper, *prev_value;
++
++  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  lower = gtk_adjustment_get_lower (adjustment);
++  upper = gtk_adjustment_get_upper (adjustment) -
++    gtk_adjustment_get_page_size (adjustment);
++
++  if (adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)))
++    prev_value = &priv->unclamped_hadj_value;
++  else if (adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)))
++    prev_value = &priv->unclamped_vadj_value;
++  else
++    return FALSE;
++
++  if (snap_to_border)
++    {
++      if (*prev_value < 0 && value > 0)
++        value = 0;
++      else if (*prev_value > upper && value < upper)
++        value = upper;
++    }
++
++  if (allow_overshooting)
++    {
++      lower -= MAX_OVERSHOOT_DISTANCE;
++      upper += MAX_OVERSHOOT_DISTANCE;
++    }
++
++  *prev_value = CLAMP (value, lower, upper);
++  gtk_adjustment_set_value (adjustment, *prev_value);
++
++  return (*prev_value != value);
++}
++
++static gboolean
++scrolled_window_deceleration_cb (gpointer user_data)
++{
++  KineticScrollData *data = user_data;
++  GtkScrolledWindow *scrolled_window = data->scrolled_window;
++  GtkScrolledWindowPrivate *priv;
++  GtkAdjustment *hadjustment, *vadjustment;
++  gint old_overshoot_x, old_overshoot_y, overshoot_x, overshoot_y;
++  gdouble value;
++  gint64 current_time;
++  guint elapsed;
++
++  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++  hadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
++  vadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
++
++  _gtk_scrolled_window_get_overshoot (scrolled_window,
++                                      &old_overshoot_x, &old_overshoot_y);
++
++  current_time = g_get_monotonic_time ();
++  elapsed = (current_time - data->last_deceleration_time) / 1000;
++  data->last_deceleration_time = current_time;
++
++  if (hadjustment && scrolled_window->hscrollbar_visible)
++    {
++      value = priv->unclamped_hadj_value + (data->x_velocity * elapsed);
++
++      if (_gtk_scrolled_window_set_adjustment_value (scrolled_window,
++                                                     hadjustment,
++                                                     value, TRUE, TRUE))
++        data->x_velocity = 0;
++    }
++  else
++    data->x_velocity = 0;
++
++  if (vadjustment && scrolled_window->vscrollbar_visible)
++    {
++      value = priv->unclamped_vadj_value + (data->y_velocity * elapsed);
++
++      if (_gtk_scrolled_window_set_adjustment_value (scrolled_window,
++                                                     vadjustment,
++                                                     value, TRUE, TRUE))
++        data->y_velocity = 0;
++    }
++  else
++    data->y_velocity = 0;
++
++  _gtk_scrolled_window_get_overshoot (scrolled_window,
++                                      &overshoot_x, &overshoot_y);
++
++  if (overshoot_x == 0)
++    {
++      if (old_overshoot_x != 0)
++        {
++          /* Overshooting finished snapping back */
++          data->x_velocity = 0;
++        }
++      else if (data->x_velocity > 0)
++        {
++          data->x_velocity -= FRICTION_DECELERATION * elapsed * data->vel_sine;
++          data->x_velocity = MAX (0, data->x_velocity);
++        }
++      else if (data->x_velocity < 0)
++        {
++          data->x_velocity += FRICTION_DECELERATION * elapsed * data->vel_sine;
++          data->x_velocity = MIN (0, data->x_velocity);
++        }
++    }
++  else if (overshoot_x < 0)
++    data->x_velocity += OVERSHOOT_INVERSE_ACCELERATION * elapsed;
++  else if (overshoot_x > 0)
++    data->x_velocity -= OVERSHOOT_INVERSE_ACCELERATION * elapsed;
++
++  if (overshoot_y == 0)
++    {
++      if (old_overshoot_y != 0)
++        {
++          /* Overshooting finished snapping back */
++          data->y_velocity = 0;
++        }
++      else if (data->y_velocity > 0)
++        {
++          data->y_velocity -= FRICTION_DECELERATION * elapsed * data->vel_cosine;
++          data->y_velocity = MAX (0, data->y_velocity);
++        }
++      else if (data->y_velocity < 0)
++        {
++          data->y_velocity += FRICTION_DECELERATION * elapsed * data->vel_cosine;
++          data->y_velocity = MIN (0, data->y_velocity);
++        }
++    }
++  else if (overshoot_y < 0)
++    data->y_velocity += OVERSHOOT_INVERSE_ACCELERATION * elapsed;
++  else if (overshoot_y > 0)
++    data->y_velocity -= OVERSHOOT_INVERSE_ACCELERATION * elapsed;
++
++  if (old_overshoot_x != overshoot_x ||
++      old_overshoot_y != overshoot_y)
++    _gtk_scrolled_window_allocate_overshoot_window (scrolled_window);
++
++  if (overshoot_x != 0 || overshoot_y != 0 ||
++      data->x_velocity != 0 || data->y_velocity != 0)
++    return TRUE;
++  else
++    {
++      priv->deceleration_id = 0;
++      return FALSE;
++    }
++}
++
++static void
++gtk_scrolled_window_cancel_deceleration (GtkScrolledWindow *scrolled_window)
++{
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  if (priv->deceleration_id)
++    {
++      g_source_remove (priv->deceleration_id);
++      priv->deceleration_id = 0;
++    }
++}
++
++static void
++gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
++{
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++  KineticScrollData *data;
++  gdouble angle;
++
++  data = g_new0 (KineticScrollData, 1);
++  data->scrolled_window = scrolled_window;
++  data->last_deceleration_time = g_get_monotonic_time ();
++  data->x_velocity = priv->x_velocity;
++  data->y_velocity = priv->y_velocity;
++
++  /* We use sine/cosine as a factor to deceleration x/y components
++   * of the vector, so we care about the sign later.
++   */
++  angle = atan2 (ABS (data->x_velocity), ABS (data->y_velocity));
++  data->vel_cosine = cos (angle);
++  data->vel_sine = sin (angle);
++
++  priv->deceleration_id =
++    gdk_threads_add_timeout_full (G_PRIORITY_DEFAULT,
++                                  FRAME_INTERVAL,
++                                  scrolled_window_deceleration_cb,
++                                  data, (GDestroyNotify) g_free);
++}
++
++static gboolean
++gtk_scrolled_window_release_captured_event (GtkScrolledWindow *scrolled_window)
++{
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  /* Cancel the scrolling and send the button press
++   * event to the child widget
++   */
++  if (!priv->button_press_event)
++    return FALSE;
++
++  if (priv->pointer_grabbed)
++    {
++      gtk_grab_remove (GTK_WIDGET (scrolled_window));
++      priv->pointer_grabbed = FALSE;
++    }
++
++  if (priv->capture_button_press)
++    {
++      GtkWidget *event_widget;
++
++      event_widget = gtk_get_event_widget (priv->button_press_event);
++
++      if (!_gtk_propagate_captured_event (event_widget,
++                                          priv->button_press_event,
++                                          gtk_bin_get_child (GTK_BIN (scrolled_window))))
++        gtk_propagate_event (event_widget, priv->button_press_event);
++
++      gdk_event_free (priv->button_press_event);
++      priv->button_press_event = NULL;
++    }
++
++  if (_gtk_scrolled_window_get_overshoot (scrolled_window, NULL, NULL))
++    gtk_scrolled_window_start_deceleration (scrolled_window);
++
++  return FALSE;
++}
++
++static gboolean
++gtk_scrolled_window_calculate_velocity (GtkScrolledWindow *scrolled_window,
++                                      GdkEvent          *event)
++{
++  GtkScrolledWindowPrivate *priv;
++  gdouble x_root, y_root;
++  guint32 _time;
++
++#define STILL_THRESHOLD 40
++
++  if (!gdk_event_get_root_coords (event, &x_root, &y_root))
++    return FALSE;
++
++  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++  _time = gdk_event_get_time (event);
++
++  if (priv->last_motion_event_x_root != x_root ||
++      priv->last_motion_event_y_root != y_root ||
++      ABS (_time - priv->last_motion_event_time) > STILL_THRESHOLD)
++    {
++      priv->x_velocity = (priv->last_motion_event_x_root - x_root) /
++        (gdouble) (_time - priv->last_motion_event_time);
++      priv->y_velocity = (priv->last_motion_event_y_root - y_root) /
++        (gdouble) (_time - priv->last_motion_event_time);
++    }
++
++  priv->last_motion_event_x_root = x_root;
++  priv->last_motion_event_y_root = y_root;
++  priv->last_motion_event_time = _time;
++
++#undef STILL_THRESHOLD
++
++  return TRUE;
++}
++
++static gboolean
++gtk_scrolled_window_captured_button_release (GtkWidget *widget,
++                                             GdkEvent  *event)
++{
++  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
++  GtkScrolledWindowPrivate *priv;
++  GtkWidget *child;
++  gboolean overshoot;
++  gdouble x_root, y_root;
++
++  if (event->button.button != 1)
++    return FALSE;
++
++  child = gtk_bin_get_child (GTK_BIN (widget));
++  if (!child)
++    return FALSE;
++
++  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++  gtk_grab_remove (widget);
++  priv->pointer_grabbed = FALSE;
++
++  if (priv->release_timeout_id)
++    {
++      g_source_remove (priv->release_timeout_id);
++      priv->release_timeout_id = 0;
++    }
++
++  overshoot = _gtk_scrolled_window_get_overshoot (scrolled_window, NULL, NULL);
++
++  if (priv->in_drag)
++    gdk_pointer_ungrab (gdk_event_get_time (event));
++  else
++    {
++      /* There hasn't been scrolling at all, so just let the
++       * child widget handle the button press normally
++       */
++      gtk_scrolled_window_release_captured_event (scrolled_window);
++
++      if (!overshoot)
++        return FALSE;
++    }
++  priv->in_drag = FALSE;
++
++  if (priv->button_press_event)
++    {
++      gdk_event_free (priv->button_press_event);
++      priv->button_press_event = NULL;
++    }
++
++  gtk_scrolled_window_calculate_velocity (scrolled_window, event);
++
++  /* Zero out vector components without a visible scrollbar */
++  if (!scrolled_window->hscrollbar_visible)
++    priv->x_velocity = 0;
++  if (!scrolled_window->vscrollbar_visible)
++    priv->y_velocity = 0;
++
++  if (priv->x_velocity != 0 || priv->y_velocity != 0 || overshoot)
++    {
++      gtk_scrolled_window_start_deceleration (scrolled_window);
++      priv->x_velocity = priv->y_velocity = 0;
++      priv->last_button_event_valid = FALSE;
++    }
++  else
++    {
++      gdk_event_get_root_coords (event, &x_root, &y_root);
++      priv->last_button_event_x_root = x_root;
++      priv->last_button_event_y_root = y_root;
++      priv->last_button_event_valid = TRUE;
++    }
++
++  if (priv->capture_button_press)
++    return TRUE;
++  else
++    return FALSE;
++}
++
++static gboolean
++gtk_scrolled_window_captured_motion_notify (GtkWidget *widget,
++                                            GdkEvent  *event)
++{
++  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
++  GtkScrolledWindowPrivate *priv;
++  gint old_overshoot_x, old_overshoot_y;
++  gint new_overshoot_x, new_overshoot_y;
++  GtkWidget *child;
++  GtkAdjustment *hadjustment;
++  GtkAdjustment *vadjustment;
++  gdouble dx, dy;
++  GdkModifierType state;
++  gdouble x_root, y_root;
++
++  gdk_event_get_state (event, &state);
++  if (!(state & GDK_BUTTON1_MASK))
++    return FALSE;
++
++  child = gtk_bin_get_child (GTK_BIN (widget));
++  if (!child)
++    return FALSE;
++
++  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  /* Check if we've passed the drag threshold */
++  gdk_event_get_root_coords (event, &x_root, &y_root);
++  if (!priv->in_drag)
++    {
++      if (gtk_drag_check_threshold (widget,
++                                    priv->last_button_event_x_root,
++                                    priv->last_button_event_y_root,
++                                    x_root, y_root))
++        {
++          if (priv->release_timeout_id)
++            {
++              g_source_remove (priv->release_timeout_id);
++              priv->release_timeout_id = 0;
++            }
++
++          priv->last_button_event_valid = FALSE;
++          priv->in_drag = TRUE;
++        }
++      else
++        return TRUE;
++    }
++
++  gdk_pointer_grab (gtk_widget_get_window (widget),
++                    TRUE,
++                    GDK_BUTTON_RELEASE_MASK | GDK_BUTTON1_MOTION_MASK,
++                    NULL, NULL,
++                    gdk_event_get_time (event));
++
++  priv->last_button_event_valid = FALSE;
++
++  if (priv->button_press_event)
++    {
++      gdk_event_free (priv->button_press_event);
++      priv->button_press_event = NULL;
++    }
++
++  _gtk_scrolled_window_get_overshoot (scrolled_window,
++                                      &old_overshoot_x, &old_overshoot_y);
++
++  hadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
++  if (hadjustment && scrolled_window->hscrollbar_visible)
++    {
++      dx = (priv->last_motion_event_x_root - x_root) + priv->unclamped_hadj_value;
++      _gtk_scrolled_window_set_adjustment_value (scrolled_window, hadjustment,
++                                                 dx, TRUE, FALSE);
++    }
++
++  vadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
++  if (vadjustment && scrolled_window->vscrollbar_visible)
++    {
++      dy = (priv->last_motion_event_y_root - y_root) + priv->unclamped_vadj_value;
++      _gtk_scrolled_window_set_adjustment_value (scrolled_window, vadjustment,
++                                                 dy, TRUE, FALSE);
++    }
++
++  _gtk_scrolled_window_get_overshoot (scrolled_window,
++                                      &new_overshoot_x, &new_overshoot_y);
++
++  if (old_overshoot_x != new_overshoot_x ||
++      old_overshoot_y != new_overshoot_y)
++    _gtk_scrolled_window_allocate_overshoot_window (scrolled_window);
++
++  gtk_scrolled_window_calculate_velocity (scrolled_window, event);
++
++  return TRUE;
++}
++
++static gboolean
++gtk_scrolled_window_captured_button_press (GtkWidget *widget,
++                                           GdkEvent  *event)
++{
++  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
++  GtkScrolledWindowPrivate *priv;
++  GtkWidget *child;
++  GtkWidget *event_widget;
++  gdouble x_root, y_root;
++
++  /* If scrollbars are not visible, we don't do kinetic scrolling */
++  if (!scrolled_window->vscrollbar_visible &&
++      !scrolled_window->hscrollbar_visible)
++    return FALSE;
++
++  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  event_widget = gtk_get_event_widget (event);
++
++  /* If there's another scrolled window between the widget
++   * receiving the event and this capturing scrolled window,
++   * let it handle the events.
++   */
++  if (widget != gtk_widget_get_ancestor (event_widget, GTK_TYPE_SCROLLED_WINDOW))
++    return FALSE;
++
++  /* Check whether the button press is close to the previous one,
++   * take that as a shortcut to get the child widget handle events
++   */
++  gdk_event_get_root_coords (event, &x_root, &y_root);
++  if (priv->last_button_event_valid &&
++      ABS (x_root - priv->last_button_event_x_root) < TOUCH_BYPASS_CAPTURED_THRESHOLD &&
++      ABS (y_root - priv->last_button_event_y_root) < TOUCH_BYPASS_CAPTURED_THRESHOLD)
++    {
++      priv->last_button_event_valid = FALSE;
++      return FALSE;
++    }
++
++  priv->last_button_event_x_root = priv->last_motion_event_x_root = x_root;
++  priv->last_button_event_y_root = priv->last_motion_event_y_root = y_root;
++  priv->last_motion_event_time = gdk_event_get_time (event);
++  priv->last_button_event_valid = TRUE;
++
++  if (event->button.button != 1)
++    return FALSE;
++
++  child = gtk_bin_get_child (GTK_BIN (widget));
++  if (!child)
++    return FALSE;
++
++  if (scrolled_window->hscrollbar == event_widget ||
++      scrolled_window->vscrollbar == event_widget)
++    return FALSE;
++
++  priv->pointer_grabbed = TRUE;
++  gtk_grab_add (widget);
++
++  gtk_scrolled_window_cancel_deceleration (scrolled_window);
++
++  /* Only set the timeout if we're going to store an event */
++  if (priv->capture_button_press)
++    priv->release_timeout_id =
++      gdk_threads_add_timeout (RELEASE_EVENT_TIMEOUT,
++                               (GSourceFunc) gtk_scrolled_window_release_captured_event,
++                               scrolled_window);
++
++  priv->in_drag = FALSE;
++
++  if (priv->capture_button_press)
++    {
++      /* Store the button press event in
++       * case we need to propagate it later
++       */
++      priv->button_press_event = gdk_event_copy (event);
++      return TRUE;
++    }
++  else
++    return FALSE;
++}
++
++static gboolean
++gtk_scrolled_window_captured_event (GtkWidget *widget,
++                                    GdkEvent  *event)
++{
++  gboolean retval = FALSE;
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (widget);
++
++  switch (event->type)
++    {
++    case GDK_BUTTON_PRESS:
++      retval = gtk_scrolled_window_captured_button_press (widget, event);
++      break;
++    case GDK_BUTTON_RELEASE:
++      if (priv->pointer_grabbed)
++        retval = gtk_scrolled_window_captured_button_release (widget, event);
++      else
++        priv->last_button_event_valid = FALSE;
++      break;
++    case GDK_MOTION_NOTIFY:
++      if (priv->pointer_grabbed)
++        retval = gtk_scrolled_window_captured_motion_notify (widget, event);
++      break;
++    case GDK_LEAVE_NOTIFY:
++    case GDK_ENTER_NOTIFY:
++      if (priv->in_drag &&
++          event->crossing.mode != GDK_CROSSING_GRAB)
++        retval = TRUE;
++      break;
++    default:
++      break;
++    }
++
++  return retval;
++}
++
++static gboolean
+ gtk_scrolled_window_focus (GtkWidget        *widget,
+                          GtkDirectionType  direction)
+ {
+@@ -1714,17 +2614,42 @@ gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
+ }
+
+ static void
++gtk_scrolled_window_adjustment_value_changed (GtkAdjustment *adjustment,
++                                              gpointer       user_data)
++{
++  GtkScrolledWindow *scrolled_window = user_data;
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  /* Allow overshooting for kinetic scrolling operations */
++  if (priv->pointer_grabbed || priv->deceleration_id)
++    return;
++
++  /* Ensure GtkAdjustment and unclamped values are in sync */
++  if (scrolled_window->vscrollbar &&
++      adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)))
++    priv->unclamped_vadj_value = gtk_adjustment_get_value (adjustment);
++  else if (scrolled_window->hscrollbar &&
++           adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)))
++    priv->unclamped_hadj_value = gtk_adjustment_get_value (adjustment);
++}
++
++static void
+ gtk_scrolled_window_add (GtkContainer *container,
+                        GtkWidget    *child)
+ {
+   GtkScrolledWindow *scrolled_window;
++  GtkScrolledWindowPrivate *priv;
+   GtkBin *bin;
+
+   bin = GTK_BIN (container);
++  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (container);
+   g_return_if_fail (bin->child == NULL);
+
+   scrolled_window = GTK_SCROLLED_WINDOW (container);
+
++  if (gtk_widget_get_realized (GTK_WIDGET (bin)))
++    gtk_widget_set_parent_window (child, priv->overshoot_window);
++
+   bin->child = child;
+   gtk_widget_set_parent (child, GTK_WIDGET (bin));
+
+@@ -1837,5 +2762,111 @@ _gtk_scrolled_window_get_scrollbar_spacing (GtkScrolledWindow *scrolled_window)
+     }
+ }
+
++static void
++gtk_scrolled_window_realize (GtkWidget *widget)
++{
++  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++  GtkAllocation allocation, relative_allocation;
++  GdkWindowAttr attributes;
++  GtkWidget *child_widget;
++  gint attributes_mask;
++
++  gtk_widget_set_realized (widget, TRUE);
++  gtk_widget_get_allocation (widget, &allocation);
++  gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
++
++  attributes.window_type = GDK_WINDOW_CHILD;
++  attributes.x = allocation.x + relative_allocation.x;
++  attributes.y = allocation.y + relative_allocation.y;
++  attributes.width = relative_allocation.width;
++  attributes.height = relative_allocation.height;
++  attributes.wclass = GDK_INPUT_OUTPUT;
++  attributes.visual = gtk_widget_get_visual (widget);
++  attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK |
++    GDK_BUTTON_MOTION_MASK;
++
++  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
++
++  priv->overshoot_window =
++    gdk_window_new (gtk_widget_get_parent_window (widget),
++                    &attributes, attributes_mask);
++
++  gdk_window_set_user_data (priv->overshoot_window, widget);
++
++  child_widget = gtk_bin_get_child (GTK_BIN (widget));
++
++  if (child_widget)
++    gtk_widget_set_parent_window (child_widget,
++                                  priv->overshoot_window);
++
++  GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->realize (widget);
++}
++
++static void
++gtk_scrolled_window_unrealize (GtkWidget *widget)
++{
++  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  gdk_window_set_user_data (priv->overshoot_window, NULL);
++  gdk_window_destroy (priv->overshoot_window);
++  priv->overshoot_window = NULL;
++
++  gtk_widget_set_realized (widget, FALSE);
++
++  GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->unrealize (widget);
++}
++
++static void
++gtk_scrolled_window_map (GtkWidget *widget)
++{
++  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  gdk_window_show (priv->overshoot_window);
++
++  GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->map (widget);
++}
++
++static void
++gtk_scrolled_window_unmap (GtkWidget *widget)
++{
++  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  gdk_window_hide (priv->overshoot_window);
++
++  GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->unmap (widget);
++}
++
++static void
++gtk_scrolled_window_grab_notify (GtkWidget *widget,
++                                 gboolean   was_grabbed)
++{
++  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  if (priv->pointer_grabbed && !was_grabbed)
++    {
++      gdk_pointer_ungrab (gtk_get_current_event_time ());
++      priv->pointer_grabbed = FALSE;
++      priv->in_drag = FALSE;
++
++      if (priv->release_timeout_id)
++        {
++          g_source_remove (priv->release_timeout_id);
++          priv->release_timeout_id = 0;
++        }
++
++      if (_gtk_scrolled_window_get_overshoot (scrolled_window, NULL, NULL))
++        gtk_scrolled_window_start_deceleration (scrolled_window);
++      else
++        gtk_scrolled_window_cancel_deceleration (scrolled_window);
++
++      priv->last_button_event_valid = FALSE;
++    }
++}
++
+ #define __GTK_SCROLLED_WINDOW_C__
+ #include "gtkaliasdef.c"
+diff --git a/gtk/gtkscrolledwindow.h b/gtk/gtkscrolledwindow.h
+index 5407547..1f555e0 100644
+--- a/gtk/gtkscrolledwindow.h
++++ b/gtk/gtkscrolledwindow.h
+@@ -127,6 +127,14 @@ GtkShadowType  gtk_scrolled_window_get_shadow_type   (GtkScrolledWindow *scrolle
+ void         gtk_scrolled_window_add_with_viewport (GtkScrolledWindow *scrolled_window,
+                                                     GtkWidget         *child);
+
++void           gtk_scrolled_window_set_kinetic_scrolling  (GtkScrolledWindow        *scrolled_window,
++                                                           gboolean                  kinetic_scrolling);
++gboolean       gtk_scrolled_window_get_kinetic_scrolling  (GtkScrolledWindow        *scrolled_window);
++
++void           gtk_scrolled_window_set_capture_button_press (GtkScrolledWindow      *scrolled_window,
++                                                             gboolean                capture_button_press);
++gboolean       gtk_scrolled_window_get_capture_button_press (GtkScrolledWindow      *scrolled_window);
++
+ gint _gtk_scrolled_window_get_scrollbar_spacing (GtkScrolledWindow *scrolled_window);
+
+
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0012-gtk-paint-to-the-right-windows-in-gtk_scrolled_windo.patch b/bockbuild/mac-sdk/patches/gtk/0012-gtk-paint-to-the-right-windows-in-gtk_scrolled_windo.patch
new file mode 100644 (file)
index 0000000..178af07
--- /dev/null
@@ -0,0 +1,35 @@
+From f8b99185c4fe6a281f2075c5780bc71b35b46de9 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Thu, 14 Jun 2012 09:27:09 +0200
+Subject: [PATCH 12/68] gtk: paint to the right windows in
+ gtk_scrolled_window_expose()
+
+so we don't paint everything twice.
+---
+ gtk/gtkscrolledwindow.c |    9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
+index 694d20a..821981f 100644
+--- a/gtk/gtkscrolledwindow.c
++++ b/gtk/gtkscrolledwindow.c
+@@ -1310,11 +1310,14 @@ static gboolean
+ gtk_scrolled_window_expose (GtkWidget      *widget,
+                           GdkEventExpose *event)
+ {
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (widget);
++
+   if (gtk_widget_is_drawable (widget))
+     {
+-      gtk_scrolled_window_paint (widget, &event->area);
+-
+-      GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->expose_event (widget, event);
++      if (event->window == priv->overshoot_window)
++        GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->expose_event (widget, event);
++      else
++        gtk_scrolled_window_paint (widget, &event->area);
+     }
+
+   return FALSE;
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0013-GtkScrolledWindow-add-overlay-scrollbars.patch b/bockbuild/mac-sdk/patches/gtk/0013-GtkScrolledWindow-add-overlay-scrollbars.patch
new file mode 100644 (file)
index 0000000..0a9b34c
--- /dev/null
@@ -0,0 +1,2097 @@
+From b7ce8de6d7b964eef99aa46ee90a09605acdd5ed Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Fri, 1 Jun 2012 13:08:26 +0200
+Subject: [PATCH 13/68] GtkScrolledWindow: add overlay scrollbars
+
+based on code from gnome-builder by Christian Hergert.
+---
+ gtk/Makefile.am         |    4 +
+ gtk/gb-animation.c      |  998 +++++++++++++++++++++++++++++++++++++++++++++++
+ gtk/gb-animation.h      |   87 +++++
+ gtk/gb-frame-source.c   |  134 +++++++
+ gtk/gb-frame-source.h   |   32 ++
+ gtk/gtkscrolledwindow.c |  577 +++++++++++++++++++++++++--
+ 6 files changed, 1806 insertions(+), 26 deletions(-)
+ create mode 100644 gtk/gb-animation.c
+ create mode 100644 gtk/gb-animation.h
+ create mode 100644 gtk/gb-frame-source.c
+ create mode 100644 gtk/gb-frame-source.h
+
+diff --git a/gtk/Makefile.am b/gtk/Makefile.am
+index 7fbe429..31dfd19 100644
+--- a/gtk/Makefile.am
++++ b/gtk/Makefile.am
+@@ -361,6 +361,8 @@ gtk_semi_private_h_sources =    \
+
+ # GTK+ header files that don't get installed
+ gtk_private_h_sources =               \
++      gb-animation.h          \
++      gb-frame-source.h       \
+       gtkquery.h              \
+       gtksearchengine.h       \
+       gtksearchenginesimple.h \
+@@ -411,6 +413,8 @@ gtk_private_h_sources =            \
+
+ # GTK+ C sources to build the library from
+ gtk_base_c_sources =            \
++      gb-animation.c          \
++      gb-frame-source.c       \
+       gtkquery.c              \
+       gtksearchengine.c       \
+       gtksearchenginesimple.c \
+diff --git a/gtk/gb-animation.c b/gtk/gb-animation.c
+new file mode 100644
+index 0000000..9452b4a
+--- /dev/null
++++ b/gtk/gb-animation.c
+@@ -0,0 +1,998 @@
++/* gb-animation.c
++ *
++ * Copyright (C) 2010 Christian Hergert <christian@hergert.me>
++ *
++ * 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.1 of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public icense along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
++ */
++
++#include <glib/gi18n.h>
++#include <gobject/gvaluecollector.h>
++#include <gtk/gtk.h>
++#include <string.h>
++
++#include "gb-animation.h"
++#include "gb-frame-source.h"
++
++G_DEFINE_TYPE(GbAnimation, _gb_animation, G_TYPE_INITIALLY_UNOWNED)
++
++typedef gdouble (*AlphaFunc) (gdouble       offset);
++typedef void    (*TweenFunc) (const GValue *begin,
++                              const GValue *end,
++                              GValue       *value,
++                              gdouble       offset);
++
++typedef struct
++{
++   gboolean    is_child; /* Does GParamSpec belong to parent widget */
++   GParamSpec *pspec;    /* GParamSpec of target property */
++   GValue      begin;    /* Begin value in animation */
++   GValue      end;      /* End value in animation */
++} Tween;
++
++
++struct _GbAnimationPrivate
++{
++   gpointer  target;        /* Target object to animate */
++   guint64   begin_msec;    /* Time in which animation started */
++   guint     duration_msec; /* Duration of animation */
++   guint     mode;          /* Tween mode */
++   guint     tween_handler; /* GSource performing tweens */
++   GArray   *tweens;        /* Array of tweens to perform */
++   guint     frame_rate;    /* The frame-rate to use */
++   guint     frame_count;   /* Counter for debugging frames rendered */
++};
++
++
++enum
++{
++   PROP_0,
++   PROP_DURATION,
++   PROP_FRAME_RATE,
++   PROP_MODE,
++   PROP_TARGET,
++   LAST_PROP
++};
++
++
++enum
++{
++   TICK,
++   LAST_SIGNAL
++};
++
++
++/*
++ * Helper macros.
++ */
++#define TIMEVAL_TO_MSEC(t) (((t).tv_sec * 1000UL) + ((t).tv_usec / 1000UL))
++#define LAST_FUNDAMENTAL 64
++#define TWEEN(type)                                         \
++    static void                                             \
++    tween_##type (const GValue *begin,                      \
++                  const GValue *end,                        \
++                  GValue *value,                            \
++                  gdouble offset)                           \
++    {                                                       \
++      g##type x = g_value_get_##type(begin);              \
++      g##type y = g_value_get_##type(end);                \
++      g_value_set_##type(value, x + ((y - x) * offset));  \
++    }
++
++
++/*
++ * Globals.
++ */
++static AlphaFunc   gAlphaFuncs[GB_ANIMATION_LAST];
++static gboolean    gDebug;
++static GParamSpec *gParamSpecs[LAST_PROP];
++static guint       gSignals[LAST_SIGNAL];
++static TweenFunc   gTweenFuncs[LAST_FUNDAMENTAL];
++
++
++/*
++ * Tweeners for basic types.
++ */
++TWEEN(int);
++TWEEN(uint);
++TWEEN(long);
++TWEEN(ulong);
++TWEEN(float);
++TWEEN(double);
++
++
++/**
++ * _gb_animation_alpha_ease_in_cubic:
++ * @offset: (in): The position within the animation; 0.0 to 1.0.
++ *
++ * An alpha function to transform the offset within the animation.
++ * @GB_ANIMATION_CUBIC means the valu ewill be transformed into
++ * cubic acceleration (x * x * x).
++ */
++static gdouble
++_gb_animation_alpha_ease_in_cubic (gdouble offset)
++{
++   return offset * offset * offset;
++}
++
++
++/**
++ * _gb_animation_alpha_linear:
++ * @offset: (in): The position within the animation; 0.0 to 1.0.
++ *
++ * An alpha function to transform the offset within the animation.
++ * @GB_ANIMATION_LINEAR means no tranformation will be made.
++ *
++ * Returns: @offset.
++ * Side effects: None.
++ */
++static gdouble
++_gb_animation_alpha_linear (gdouble offset)
++{
++   return offset;
++}
++
++
++/**
++ * _gb_animation_alpha_ease_in_quad:
++ * @offset: (in): The position within the animation; 0.0 to 1.0.
++ *
++ * An alpha function to transform the offset within the animation.
++ * @GB_ANIMATION_EASE_IN_QUAD means that the value will be transformed
++ * into a quadratic acceleration.
++ *
++ * Returns: A tranformation of @offset.
++ * Side effects: None.
++ */
++static gdouble
++_gb_animation_alpha_ease_in_quad (gdouble offset)
++{
++   return offset * offset;
++}
++
++
++/**
++ * _gb_animation_alpha_ease_out_quad:
++ * @offset: (in): The position within the animation; 0.0 to 1.0.
++ *
++ * An alpha function to transform the offset within the animation.
++ * @GB_ANIMATION_EASE_OUT_QUAD means that the value will be transformed
++ * into a quadratic deceleration.
++ *
++ * Returns: A tranformation of @offset.
++ * Side effects: None.
++ */
++static gdouble
++_gb_animation_alpha_ease_out_quad (gdouble offset)
++{
++   return -1.0 * offset * (offset - 2.0);
++}
++
++
++/**
++ * _gb_animation_alpha_ease_in_out_quad:
++ * @offset: (in): The position within the animation; 0.0 to 1.0.
++ *
++ * An alpha function to transform the offset within the animation.
++ * @GB_ANIMATION_EASE_IN_OUT_QUAD means that the value will be transformed
++ * into a quadratic acceleration for the first half, and quadratic
++ * deceleration the second half.
++ *
++ * Returns: A tranformation of @offset.
++ * Side effects: None.
++ */
++static gdouble
++_gb_animation_alpha_ease_in_out_quad (gdouble offset)
++{
++   offset *= 2.0;
++   if (offset < 1.0) {
++      return 0.5 * offset * offset;
++   }
++   offset -= 1.0;
++   return -0.5 * (offset * (offset - 2.0) - 1.0);
++}
++
++
++/**
++ * _gb_animation_load_begin_values:
++ * @animation: (in): A #GbAnimation.
++ *
++ * Load the begin values for all the properties we are about to
++ * animate.
++ *
++ * Returns: None.
++ * Side effects: None.
++ */
++static void
++_gb_animation_load_begin_values (GbAnimation *animation)
++{
++   GbAnimationPrivate *priv;
++   GtkContainer *container;
++   Tween *tween;
++   gint i;
++
++   g_return_if_fail(GB_IS_ANIMATION(animation));
++
++   priv = animation->priv;
++
++   for (i = 0; i < priv->tweens->len; i++) {
++      tween = &g_array_index(priv->tweens, Tween, i);
++      g_value_reset(&tween->begin);
++      if (tween->is_child) {
++         container = GTK_CONTAINER(gtk_widget_get_parent(priv->target));
++         gtk_container_child_get_property(container, priv->target,
++                                          tween->pspec->name,
++                                          &tween->begin);
++      } else {
++         g_object_get_property(priv->target, tween->pspec->name,
++                               &tween->begin);
++      }
++   }
++}
++
++
++/**
++ * _gb_animation_unload_begin_values:
++ * @animation: (in): A #GbAnimation.
++ *
++ * Unloads the begin values for the animation. This might be particularly
++ * useful once we support pointer types.
++ *
++ * Returns: None.
++ * Side effects: None.
++ */
++static void
++_gb_animation_unload_begin_values (GbAnimation *animation)
++{
++   GbAnimationPrivate *priv;
++   Tween *tween;
++   gint i;
++
++   g_return_if_fail(GB_IS_ANIMATION(animation));
++
++   priv = animation->priv;
++
++   for (i = 0; i < priv->tweens->len; i++) {
++      tween = &g_array_index(priv->tweens, Tween, i);
++      g_value_reset(&tween->begin);
++   }
++}
++
++
++/**
++ * _gb_animation_get_offset:
++ * @animation: (in): A #GbAnimation.
++ *
++ * Retrieves the position within the animation from 0.0 to 1.0. This
++ * value is calculated using the msec of the beginning of the animation
++ * and the current time.
++ *
++ * Returns: The offset of the animation from 0.0 to 1.0.
++ * Side effects: None.
++ */
++static gdouble
++_gb_animation_get_offset (GbAnimation *animation)
++{
++   GbAnimationPrivate *priv;
++   GTimeVal now;
++   guint64 msec;
++   gdouble offset;
++
++   g_return_val_if_fail(GB_IS_ANIMATION(animation), 0.0);
++
++   priv = animation->priv;
++
++   g_get_current_time(&now);
++   msec = TIMEVAL_TO_MSEC(now);
++   offset = (gdouble)(msec - priv->begin_msec)
++          / (gdouble)priv->duration_msec;
++   return CLAMP(offset, 0.0, 1.0);
++}
++
++
++/**
++ * _gb_animation_update_property:
++ * @animation: (in): A #GbAnimation.
++ * @target: (in): A #GObject.
++ * @tween: (in): a #Tween containing the property.
++ * @value: (in) The new value for the property.
++ *
++ * Updates the value of a property on an object using @value.
++ *
++ * Returns: None.
++ * Side effects: The property of @target is updated.
++ */
++static void
++_gb_animation_update_property (GbAnimation *animation,
++                               gpointer      target,
++                               Tween        *tween,
++                               const GValue *value)
++{
++   g_object_set_property(target, tween->pspec->name, value);
++}
++
++
++/**
++ * _gb_animation_update_child_property:
++ * @animation: (in): A #GbAnimation.
++ * @target: (in): A #GObject.
++ * @tween: (in): A #Tween containing the property.
++ * @value: (in): The new value for the property.
++ *
++ * Updates the value of the parent widget of the target to @value.
++ *
++ * Returns: None.
++ * Side effects: The property of @target<!-- -->'s parent widget is updated.
++ */
++static void
++_gb_animation_update_child_property (GbAnimation *animation,
++                                     gpointer      target,
++                                     Tween        *tween,
++                                     const GValue *value)
++{
++   GtkWidget *parent = gtk_widget_get_parent(GTK_WIDGET(target));
++   gtk_container_child_set_property(GTK_CONTAINER(parent), target,
++                                    tween->pspec->name, value);
++}
++
++
++/**
++ * _gb_animation_get_value_at_offset:
++ * @animation: (in): A #GbAnimation.
++ * @offset: (in): The offset in the animation from 0.0 to 1.0.
++ * @tween: (in): A #Tween containing the property.
++ * @value: (out): A #GValue in which to store the property.
++ *
++ * Retrieves a value for a particular position within the animation.
++ *
++ * Returns: None.
++ * Side effects: None.
++ */
++static void
++_gb_animation_get_value_at_offset (GbAnimation *animation,
++                                   gdouble       offset,
++                                   Tween        *tween,
++                                   GValue       *value)
++{
++   g_return_if_fail(GB_IS_ANIMATION(animation));
++   g_return_if_fail(offset >= 0.0);
++   g_return_if_fail(offset <= 1.0);
++   g_return_if_fail(tween != NULL);
++   g_return_if_fail(value != NULL);
++   g_return_if_fail(value->g_type == tween->pspec->value_type);
++
++   if (value->g_type < LAST_FUNDAMENTAL) {
++      /*
++       * If you hit the following assertion, you need to add a function
++       * to create the new value at the given offset.
++       */
++      g_assert(gTweenFuncs[value->g_type]);
++      gTweenFuncs[value->g_type](&tween->begin, &tween->end, value, offset);
++   } else {
++      /*
++       * TODO: Support complex transitions.
++       */
++      if (offset >= 1.0) {
++         g_value_copy(&tween->end, value);
++      }
++   }
++}
++
++
++/**
++ * _gb_animation_tick:
++ * @animation: (in): A #GbAnimation.
++ *
++ * Moves the object properties to the next position in the animation.
++ *
++ * Returns: %TRUE if the animation has not completed; otherwise %FALSE.
++ * Side effects: None.
++ */
++static gboolean
++_gb_animation_tick (GbAnimation *animation)
++{
++   GbAnimationPrivate *priv;
++   GdkWindow *window;
++   gdouble offset;
++   gdouble alpha;
++   GValue value = { 0 };
++   Tween *tween;
++   gint i;
++
++   g_return_val_if_fail(GB_IS_ANIMATION(animation), FALSE);
++
++   priv = animation->priv;
++
++   priv->frame_count++;
++   offset = _gb_animation_get_offset(animation);
++   alpha = gAlphaFuncs[priv->mode](offset);
++
++   /*
++    * Update property values.
++    */
++   for (i = 0; i < priv->tweens->len; i++) {
++      tween = &g_array_index(priv->tweens, Tween, i);
++      g_value_init(&value, tween->pspec->value_type);
++      _gb_animation_get_value_at_offset(animation, alpha, tween, &value);
++      if (!tween->is_child) {
++         _gb_animation_update_property(animation, priv->target,
++                                       tween, &value);
++      } else {
++         _gb_animation_update_child_property(animation, priv->target,
++                                             tween, &value);
++      }
++      g_value_unset(&value);
++   }
++
++   /*
++    * Notify anyone interested in the tick signal.
++    */
++   g_signal_emit(animation, gSignals[TICK], 0);
++
++   /*
++    * Flush any outstanding events to the graphics server (in the case of X).
++    */
++   if (GTK_IS_WIDGET(priv->target)) {
++      if ((window = gtk_widget_get_window(GTK_WIDGET(priv->target)))) {
++         gdk_window_flush(window);
++      }
++   }
++
++   return (offset < 1.0);
++}
++
++
++/**
++ * _gb_animation_timeout:
++ * @data: (in): A #GbAnimation.
++ *
++ * Timeout from the main loop to move to the next step of the animation.
++ *
++ * Returns: %TRUE until the animation has completed; otherwise %FALSE.
++ * Side effects: None.
++ */
++static gboolean
++_gb_animation_timeout (gpointer data)
++{
++   GbAnimation *animation = (GbAnimation *)data;
++   gboolean ret;
++
++   if (!(ret = _gb_animation_tick(animation))) {
++      _gb_animation_stop(animation);
++   }
++
++   return ret;
++}
++
++
++/**
++ * _gb_animation_start:
++ * @animation: (in): A #GbAnimation.
++ *
++ * Start the animation. When the animation stops, the internal reference will
++ * be dropped and the animation may be finalized.
++ *
++ * Returns: None.
++ * Side effects: None.
++ */
++void
++_gb_animation_start (GbAnimation *animation)
++{
++   GbAnimationPrivate *priv;
++   GTimeVal now;
++
++   g_return_if_fail(GB_IS_ANIMATION(animation));
++   g_return_if_fail(!animation->priv->tween_handler);
++
++   priv = animation->priv;
++
++   g_get_current_time(&now);
++   g_object_ref_sink(animation);
++   _gb_animation_load_begin_values(animation);
++
++   priv->begin_msec = TIMEVAL_TO_MSEC(now);
++   priv->tween_handler = _gb_frame_source_add(priv->frame_rate,
++                                              _gb_animation_timeout,
++                                              animation);
++}
++
++
++/**
++ * _gb_animation_stop:
++ * @animation: (in): A #GbAnimation.
++ *
++ * Stops a running animation. The internal reference to the animation is
++ * dropped and therefore may cause the object to finalize.
++ *
++ * Returns: None.
++ * Side effects: None.
++ */
++void
++_gb_animation_stop (GbAnimation *animation)
++{
++   GbAnimationPrivate *priv;
++
++   g_return_if_fail(GB_IS_ANIMATION(animation));
++
++   priv = animation->priv;
++
++   if (priv->tween_handler) {
++      g_source_remove(priv->tween_handler);
++      priv->tween_handler = 0;
++      _gb_animation_unload_begin_values(animation);
++      g_object_unref(animation);
++   }
++}
++
++
++/**
++ * _gb_animation_add_property:
++ * @animation: (in): A #GbAnimation.
++ * @pspec: (in): A #ParamSpec of @target or a #GtkWidget<!-- -->'s parent.
++ * @value: (in): The new value for the property at the end of the animation.
++ *
++ * Adds a new property to the set of properties to be animated during the
++ * lifetime of the animation.
++ *
++ * Returns: None.
++ * Side effects: None.
++ */
++void
++_gb_animation_add_property (GbAnimation  *animation,
++                            GParamSpec   *pspec,
++                            const GValue *value)
++{
++   GbAnimationPrivate *priv;
++   Tween tween = { 0 };
++   GType type;
++
++   g_return_if_fail(GB_IS_ANIMATION(animation));
++   g_return_if_fail(pspec != NULL);
++   g_return_if_fail(value != NULL);
++   g_return_if_fail(value->g_type);
++   g_return_if_fail(animation->priv->target);
++   g_return_if_fail(!animation->priv->tween_handler);
++
++   priv = animation->priv;
++
++   type = G_TYPE_FROM_INSTANCE(priv->target);
++   tween.is_child = !g_type_is_a(type, pspec->owner_type);
++   if (tween.is_child) {
++      if (!GTK_IS_WIDGET(priv->target)) {
++         g_critical("Cannot locate property %s in class %s",
++                    pspec->name, g_type_name(type));
++         return;
++      }
++   }
++
++   tween.pspec = g_param_spec_ref(pspec);
++   g_value_init(&tween.begin, pspec->value_type);
++   g_value_init(&tween.end, pspec->value_type);
++   g_value_copy(value, &tween.end);
++   g_array_append_val(priv->tweens, tween);
++}
++
++
++/**
++ * _gb_animation_dispose:
++ * @object: (in): A #GbAnimation.
++ *
++ * Releases any object references the animation contains.
++ *
++ * Returns: None.
++ * Side effects: None.
++ */
++static void
++_gb_animation_dispose (GObject *object)
++{
++   GbAnimationPrivate *priv = GB_ANIMATION(object)->priv;
++   gpointer instance;
++
++   if ((instance = priv->target)) {
++      priv->target = NULL;
++      g_object_unref(instance);
++   }
++
++   G_OBJECT_CLASS(_gb_animation_parent_class)->dispose(object);
++}
++
++
++/**
++ * _gb_animation_finalize:
++ * @object: (in): A #GbAnimation.
++ *
++ * Finalizes the object and releases any resources allocated.
++ *
++ * Returns: None.
++ * Side effects: None.
++ */
++static void
++_gb_animation_finalize (GObject *object)
++{
++   GbAnimationPrivate *priv = GB_ANIMATION(object)->priv;
++   Tween *tween;
++   gint i;
++
++   for (i = 0; i < priv->tweens->len; i++) {
++      tween = &g_array_index(priv->tweens, Tween, i);
++      g_value_unset(&tween->begin);
++      g_value_unset(&tween->end);
++      g_param_spec_unref(tween->pspec);
++   }
++
++   g_array_unref(priv->tweens);
++
++   if (gDebug) {
++      g_print("Rendered %d frames in %d msec animation.\n",
++              priv->frame_count, priv->duration_msec);
++   }
++
++   G_OBJECT_CLASS(_gb_animation_parent_class)->finalize(object);
++}
++
++
++/**
++ * _gb_animation_set_property:
++ * @object: (in): A #GObject.
++ * @prop_id: (in): The property identifier.
++ * @value: (in): The given property.
++ * @pspec: (in): A #ParamSpec.
++ *
++ * Set a given #GObject property.
++ */
++static void
++_gb_animation_set_property (GObject      *object,
++                            guint         prop_id,
++                            const GValue *value,
++                            GParamSpec   *pspec)
++{
++   GbAnimation *animation = GB_ANIMATION(object);
++
++   switch (prop_id) {
++   case PROP_DURATION:
++      animation->priv->duration_msec = g_value_get_uint(value);
++      break;
++   case PROP_FRAME_RATE:
++      animation->priv->frame_rate = g_value_get_uint(value);
++      break;
++   case PROP_MODE:
++      animation->priv->mode = g_value_get_enum(value);
++      break;
++   case PROP_TARGET:
++      animation->priv->target = g_value_dup_object(value);
++      break;
++   default:
++      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
++   }
++}
++
++
++/**
++ * _gb_animation_class_init:
++ * @klass: (in): A #GbAnimationClass.
++ *
++ * Initializes the GObjectClass.
++ *
++ * Returns: None.
++ * Side effects: Properties, signals, and vtables are initialized.
++ */
++static void
++_gb_animation_class_init (GbAnimationClass *klass)
++{
++   GObjectClass *object_class;
++
++   gDebug = !!g_getenv("GB_ANIMATION_DEBUG");
++
++   object_class = G_OBJECT_CLASS(klass);
++   object_class->dispose = _gb_animation_dispose;
++   object_class->finalize = _gb_animation_finalize;
++   object_class->set_property = _gb_animation_set_property;
++   g_type_class_add_private(object_class, sizeof(GbAnimationPrivate));
++
++   /**
++    * GbAnimation:duration:
++    *
++    * The "duration" property is the total number of milliseconds that the
++    * animation should run before being completed.
++    */
++   gParamSpecs[PROP_DURATION] =
++      g_param_spec_uint("duration",
++                        _("Duration"),
++                        _("The duration of the animation"),
++                        0,
++                        G_MAXUINT,
++                        250,
++                        G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
++   g_object_class_install_property(object_class, PROP_DURATION,
++                                   gParamSpecs[PROP_DURATION]);
++
++   /**
++    * GbAnimation:mode:
++    *
++    * The "mode" property is the Alpha function that should be used to
++    * determine the offset within the animation based on the current
++    * offset in the animations duration.
++    */
++   gParamSpecs[PROP_MODE] =
++      g_param_spec_enum("mode",
++                        _("Mode"),
++                        _("The animation mode"),
++                        GB_TYPE_ANIMATION_MODE,
++                        GB_ANIMATION_LINEAR,
++                        G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
++   g_object_class_install_property(object_class, PROP_MODE,
++                                   gParamSpecs[PROP_MODE]);
++
++   /**
++    * GbAnimation:target:
++    *
++    * The "target" property is the #GObject that should have it's properties
++    * animated.
++    */
++   gParamSpecs[PROP_TARGET] =
++      g_param_spec_object("target",
++                          _("Target"),
++                          _("The target of the animation"),
++                          G_TYPE_OBJECT,
++                          G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
++   g_object_class_install_property(object_class, PROP_TARGET,
++                                   gParamSpecs[PROP_TARGET]);
++
++   /**
++    * GbAnimation:frame-rate:
++    *
++    * The "frame-rate" is the number of frames that the animation should
++    * try to perform per-second. The default is 60 frames-per-second.
++    */
++   gParamSpecs[PROP_FRAME_RATE] =
++      g_param_spec_uint("frame-rate",
++                          _("Frame Rate"),
++                          _("The number of frames per second."),
++                          1,
++                          G_MAXUINT,
++                          60,
++                          G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
++   g_object_class_install_property(object_class, PROP_FRAME_RATE,
++                                   gParamSpecs[PROP_FRAME_RATE]);
++
++   /**
++    * GbAnimation::tick:
++    *
++    * The "tick" signal is emitted on each frame in the animation.
++    */
++   gSignals[TICK] = g_signal_new("tick",
++                                 GB_TYPE_ANIMATION,
++                                 G_SIGNAL_RUN_FIRST,
++                                 0,
++                                 NULL,
++                                 NULL,
++                                 g_cclosure_marshal_VOID__VOID,
++                                 G_TYPE_NONE,
++                                 0);
++
++#define SET_ALPHA(_T, _t) \
++   gAlphaFuncs[GB_ANIMATION_##_T] = _gb_animation_alpha_##_t
++
++   SET_ALPHA(LINEAR, linear);
++   SET_ALPHA(EASE_IN_QUAD, ease_in_quad);
++   SET_ALPHA(EASE_OUT_QUAD, ease_out_quad);
++   SET_ALPHA(EASE_IN_OUT_QUAD, ease_in_out_quad);
++   SET_ALPHA(EASE_IN_CUBIC, ease_in_cubic);
++
++#define SET_TWEEN(_T, _t) \
++   G_STMT_START { \
++      guint idx = G_TYPE_##_T; \
++      gTweenFuncs[idx] = tween_##_t; \
++   } G_STMT_END
++
++   SET_TWEEN(INT, int);
++   SET_TWEEN(UINT, uint);
++   SET_TWEEN(LONG, long);
++   SET_TWEEN(ULONG, ulong);
++   SET_TWEEN(FLOAT, float);
++   SET_TWEEN(DOUBLE, double);
++}
++
++
++/**
++ * _gb_animation_init:
++ * @animation: (in): A #GbAnimation.
++ *
++ * Initializes the #GbAnimation instance.
++ *
++ * Returns: None.
++ * Side effects: Everything.
++ */
++static void
++_gb_animation_init (GbAnimation *animation)
++{
++   GbAnimationPrivate *priv;
++
++   priv = G_TYPE_INSTANCE_GET_PRIVATE(animation, GB_TYPE_ANIMATION,
++                                      GbAnimationPrivate);
++   animation->priv = priv;
++
++   priv->duration_msec = 250;
++   priv->frame_rate = 60;
++   priv->mode = GB_ANIMATION_LINEAR;
++   priv->tweens = g_array_new(FALSE, FALSE, sizeof(Tween));
++}
++
++
++/**
++ * _gb_animation_mode_get_type:
++ *
++ * Retrieves the GType for #GbAnimationMode.
++ *
++ * Returns: A GType.
++ * Side effects: GType registered on first call.
++ */
++GType
++_gb_animation_mode_get_type (void)
++{
++   static GType type_id = 0;
++   static const GEnumValue values[] = {
++      { GB_ANIMATION_LINEAR, "GB_ANIMATION_LINEAR", "LINEAR" },
++      { GB_ANIMATION_EASE_IN_QUAD, "GB_ANIMATION_EASE_IN_QUAD", "EASE_IN_QUAD" },
++      { GB_ANIMATION_EASE_IN_OUT_QUAD, "GB_ANIMATION_EASE_IN_OUT_QUAD", "EASE_IN_OUT_QUAD" },
++      { GB_ANIMATION_EASE_OUT_QUAD, "GB_ANIMATION_EASE_OUT_QUAD", "EASE_OUT_QUAD" },
++      { GB_ANIMATION_EASE_IN_CUBIC, "GB_ANIMATION_EASE_IN_CUBIC", "EASE_IN_CUBIC" },
++      { 0 }
++   };
++
++   if (G_UNLIKELY(!type_id)) {
++      type_id = g_enum_register_static("GbAnimationMode", values);
++   }
++   return type_id;
++}
++
++/**
++ * _gb_object_animatev:
++ * Returns: (transfer none): A #GbAnimation.
++ */
++GbAnimation*
++_gb_object_animatev (gpointer         object,
++                     GbAnimationMode  mode,
++                     guint            duration_msec,
++                     guint            frame_rate,
++                     const gchar     *first_property,
++                     va_list          args)
++{
++   GbAnimation *animation;
++   GObjectClass *klass;
++   GObjectClass *pklass;
++   const gchar *name;
++   GParamSpec *pspec;
++   GtkWidget *parent;
++   GValue value = { 0 };
++   gchar *error = NULL;
++   GType type;
++   GType ptype;
++
++   g_return_val_if_fail(first_property != NULL, NULL);
++   g_return_val_if_fail(mode < GB_ANIMATION_LAST, NULL);
++
++   name = first_property;
++   type = G_TYPE_FROM_INSTANCE(object);
++   klass = G_OBJECT_GET_CLASS(object);
++   animation = g_object_new(GB_TYPE_ANIMATION,
++                            "duration", duration_msec,
++                            "frame-rate", frame_rate ? frame_rate : 60,
++                            "mode", mode,
++                            "target", object,
++                            NULL);
++
++   do {
++      /*
++       * First check for the property on the object. If that does not exist
++       * then check if the object has a parent and look at its child
++       * properties (if its a GtkWidget).
++       */
++      if (!(pspec = g_object_class_find_property(klass, name))) {
++         if (!g_type_is_a(type, GTK_TYPE_WIDGET)) {
++            g_critical("Failed to find property %s in %s",
++                       name, g_type_name(type));
++            goto failure;
++         }
++         if (!(parent = gtk_widget_get_parent(object))) {
++            g_critical("Failed to find property %s in %s",
++                       name, g_type_name(type));
++            goto failure;
++         }
++         pklass = G_OBJECT_GET_CLASS(parent);
++         ptype = G_TYPE_FROM_INSTANCE(parent);
++         if (!(pspec = gtk_container_class_find_child_property(pklass, name))) {
++            g_critical("Failed to find property %s in %s or parent %s",
++                       name, g_type_name(type), g_type_name(ptype));
++            goto failure;
++         }
++      }
++
++      g_value_init(&value, pspec->value_type);
++      G_VALUE_COLLECT(&value, args, 0, &error);
++      if (error != NULL) {
++         g_critical("Failed to retrieve va_list value: %s", error);
++         g_free(error);
++         goto failure;
++      }
++
++      _gb_animation_add_property(animation, pspec, &value);
++      g_value_unset(&value);
++   } while ((name = va_arg(args, const gchar *)));
++
++   _gb_animation_start(animation);
++
++   return animation;
++
++failure:
++   g_object_ref_sink(animation);
++   g_object_unref(animation);
++   return NULL;
++}
++
++/**
++ * _gb_object_animate:
++ * @object: (in): A #GObject.
++ * @mode: (in): The animation mode.
++ * @duration_msec: (in): The duration in milliseconds.
++ * @first_property: (in): The first property to animate.
++ *
++ * Animates the properties of @object. The can be set in a similar
++ * manner to g_object_set(). They will be animated from their current
++ * value to the target value over the time period.
++ *
++ * Return value: (transfer none): A #GbAnimation.
++ * Side effects: None.
++ */
++GbAnimation*
++_gb_object_animate (gpointer         object,
++                    GbAnimationMode  mode,
++                    guint            duration_msec,
++                    const gchar     *first_property,
++                    ...)
++{
++   GbAnimation *animation;
++   va_list args;
++
++   va_start(args, first_property);
++   animation = _gb_object_animatev(object, mode, duration_msec, 0,
++                                   first_property, args);
++   va_end(args);
++   return animation;
++}
++
++/**
++ * _gb_object_animate_full:
++ *
++ * Return value: (transfer none): A #GbAnimation.
++ */
++GbAnimation*
++_gb_object_animate_full (gpointer         object,
++                         GbAnimationMode  mode,
++                         guint            duration_msec,
++                         guint            frame_rate,
++                         GDestroyNotify   notify,
++                         gpointer         notify_data,
++                         const gchar     *first_property,
++                         ...)
++{
++   GbAnimation *animation;
++   va_list args;
++
++   va_start(args, first_property);
++   animation = _gb_object_animatev(object, mode, duration_msec,
++                                   frame_rate, first_property, args);
++   va_end(args);
++   g_object_weak_ref(G_OBJECT(animation), (GWeakNotify)notify, notify_data);
++   return animation;
++}
+diff --git a/gtk/gb-animation.h b/gtk/gb-animation.h
+new file mode 100644
+index 0000000..bf9268d
+--- /dev/null
++++ b/gtk/gb-animation.h
+@@ -0,0 +1,87 @@
++/* gb-animation.h
++ *
++ * Copyright (C) 2010 Christian Hergert <chris@dronelabs.com>
++ *
++ * This program is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef GB_ANIMATION_H
++#define GB_ANIMATION_H
++
++#include <glib-object.h>
++
++G_BEGIN_DECLS
++
++#define GB_TYPE_ANIMATION            (_gb_animation_get_type())
++#define GB_TYPE_ANIMATION_MODE       (_gb_animation_mode_get_type())
++#define GB_ANIMATION(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_ANIMATION, GbAnimation))
++#define GB_ANIMATION_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GB_TYPE_ANIMATION, GbAnimation const))
++#define GB_ANIMATION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GB_TYPE_ANIMATION, GbAnimationClass))
++#define GB_IS_ANIMATION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GB_TYPE_ANIMATION))
++#define GB_IS_ANIMATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GB_TYPE_ANIMATION))
++#define GB_ANIMATION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GB_TYPE_ANIMATION, GbAnimationClass))
++
++typedef struct _GbAnimation        GbAnimation;
++typedef struct _GbAnimationClass   GbAnimationClass;
++typedef struct _GbAnimationPrivate GbAnimationPrivate;
++typedef enum   _GbAnimationMode    GbAnimationMode;
++
++enum _GbAnimationMode
++{
++      GB_ANIMATION_LINEAR,
++      GB_ANIMATION_EASE_IN_QUAD,
++      GB_ANIMATION_EASE_OUT_QUAD,
++      GB_ANIMATION_EASE_IN_OUT_QUAD,
++      GB_ANIMATION_EASE_IN_CUBIC,
++
++      GB_ANIMATION_LAST
++};
++
++struct _GbAnimation
++{
++      GInitiallyUnowned parent;
++
++      /*< private >*/
++      GbAnimationPrivate *priv;
++};
++
++struct _GbAnimationClass
++{
++      GInitiallyUnownedClass parent_class;
++};
++
++GType _gb_animation_get_type         (void) G_GNUC_CONST;
++GType _gb_animation_mode_get_type    (void) G_GNUC_CONST;
++void  _gb_animation_start            (GbAnimation      *animation);
++void  _gb_animation_stop             (GbAnimation      *animation);
++void  _gb_animation_add_property     (GbAnimation      *animation,
++                                      GParamSpec       *pspec,
++                                      const GValue     *value);
++GbAnimation* _gb_object_animate      (gpointer          object,
++                                      GbAnimationMode   mode,
++                                      guint             duration_msec,
++                                      const gchar      *first_property,
++                                      ...) G_GNUC_NULL_TERMINATED;
++GbAnimation* _gb_object_animate_full (gpointer          object,
++                                      GbAnimationMode   mode,
++                                      guint             duration_msec,
++                                      guint             frame_rate,
++                                      GDestroyNotify    notify,
++                                      gpointer          notify_data,
++                                      const gchar      *first_property,
++                                      ...) G_GNUC_NULL_TERMINATED;
++
++G_END_DECLS
++
++#endif /* GB_ANIMATION_H */
+diff --git a/gtk/gb-frame-source.c b/gtk/gb-frame-source.c
+new file mode 100644
+index 0000000..be04c1b
+--- /dev/null
++++ b/gtk/gb-frame-source.c
+@@ -0,0 +1,134 @@
++/*
++ * Based upon code from Clutter:
++ *
++ * Authored By Neil Roberts <neil@linux.intel.com>
++ *
++ * Copyright (C) 2009 Intel Corporation.
++ * Copyright (C) 2012 Christian Hergert.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include "gb-frame-source.h"
++
++typedef struct
++{
++   GSource parent;
++   guint   fps;
++   guint   frame_count;
++   gint64  start_time;
++} GbFrameSource;
++
++static gboolean
++gb_frame_source_prepare (GSource *source,
++                         gint    *timeout_)
++{
++   GbFrameSource *fsource = (GbFrameSource *)source;
++   gint64 current_time;
++   guint elapsed_time;
++   guint new_frame_num;
++   guint frame_time;
++
++   current_time = g_source_get_time(source) / 1000;
++   elapsed_time = current_time - fsource->start_time;
++   new_frame_num = elapsed_time * fsource->fps / 1000;
++
++   /* If time has gone backwards or the time since the last frame is
++    * greater than the two frames worth then reset the time and do a
++    * frame now */
++   if (new_frame_num < fsource->frame_count ||
++       new_frame_num - fsource->frame_count > 2) {
++      /* Get the frame time rounded up to the nearest ms */
++      frame_time = (1000 + fsource->fps - 1) / fsource->fps;
++
++      /* Reset the start time */
++      fsource->start_time = current_time;
++
++      /* Move the start time as if one whole frame has elapsed */
++      fsource->start_time -= frame_time;
++      fsource->frame_count = 0;
++      *timeout_ = 0;
++      return TRUE;
++   } else if (new_frame_num > fsource->frame_count) {
++      *timeout_ = 0;
++      return TRUE;
++   } else {
++      *timeout_ = (fsource->frame_count + 1) * 1000 / fsource->fps - elapsed_time;
++      return FALSE;
++   }
++}
++
++static gboolean
++gb_frame_source_check (GSource *source)
++{
++   gint timeout_;
++   return gb_frame_source_prepare(source, &timeout_);
++}
++
++static gboolean
++gb_frame_source_dispatch (GSource     *source,
++                          GSourceFunc  source_func,
++                          gpointer     user_data)
++{
++   GbFrameSource *fsource = (GbFrameSource *)source;
++   gboolean ret;
++
++   if ((ret = source_func(user_data)))
++      fsource->frame_count++;
++   return ret;
++}
++
++static GSourceFuncs source_funcs = {
++   gb_frame_source_prepare,
++   gb_frame_source_check,
++   gb_frame_source_dispatch,
++};
++
++/**
++ * gb_frame_source_add:
++ * @frames_per_sec: (in): Target frames per second.
++ * @callback: (in) (scope notified): A #GSourceFunc to execute.
++ * @user_data: (in): User data for @callback.
++ *
++ * Creates a new frame source that will execute when the timeout interval
++ * for the source has elapsed. The timing will try to synchronize based
++ * on the end time of the animation.
++ *
++ * Returns: A source id that can be removed with g_source_remove().
++ */
++guint
++_gb_frame_source_add (guint       frames_per_sec,
++                      GSourceFunc callback,
++                      gpointer    user_data)
++{
++   GbFrameSource *fsource;
++   GSource *source;
++   guint ret;
++
++   g_return_val_if_fail(frames_per_sec > 0, 0);
++   g_return_val_if_fail(frames_per_sec < 120, 0);
++
++   source = g_source_new(&source_funcs, sizeof(GbFrameSource));
++   fsource = (GbFrameSource *)source;
++   fsource->fps = frames_per_sec;
++   fsource->frame_count = 0;
++   fsource->start_time = g_get_monotonic_time() / 1000;
++   g_source_set_callback(source, callback, user_data, NULL);
++   g_source_set_name(source, "GbFrameSource");
++
++   ret = g_source_attach(source, NULL);
++   g_source_unref(source);
++
++   return ret;
++}
+diff --git a/gtk/gb-frame-source.h b/gtk/gb-frame-source.h
+new file mode 100644
+index 0000000..502d86e
+--- /dev/null
++++ b/gtk/gb-frame-source.h
+@@ -0,0 +1,32 @@
++/* gb-frame-source.h
++ *
++ * Copyright (C) 2012 Christian Hergert <chris@dronelabs.com>
++ *
++ * This program is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef GB_FRAME_SOURCE_H
++#define GB_FRAME_SOURCE_H
++
++#include <glib.h>
++
++G_BEGIN_DECLS
++
++guint _gb_frame_source_add (guint       frames_per_sec,
++                            GSourceFunc callback,
++                            gpointer    user_data);
++
++G_END_DECLS
++
++#endif /* GB_FRAME_SOURCE_H */
+diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
+index 821981f..77d485f 100644
+--- a/gtk/gtkscrolledwindow.c
++++ b/gtk/gtkscrolledwindow.c
+@@ -32,6 +32,7 @@
+ #include "gtkscrolledwindow.h"
+ #include "gtkwindow.h"
+ #include "gtkprivate.h"
++#include "gb-animation.h"
+ #include "gtkintl.h"
+ #include "gtkmain.h"
+ #include "gtkdnd.h"
+@@ -111,6 +112,17 @@ typedef struct {
+
+   gdouble                unclamped_hadj_value;
+   gdouble                unclamped_vadj_value;
++
++  GtkAdjustment *opacity;
++  GbAnimation   *opacity_anim;
++
++  gint           sb_min_height;
++  gint           sb_padding;
++  gint           sb_radius;
++  gint           sb_width;
++  gboolean       sb_fading_in;
++  gint           sb_fade_out_delay;
++  guint          sb_fade_out_id;
+ } GtkScrolledWindowPrivate;
+
+ #define GTK_SCROLLED_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_SCROLLED_WINDOW, GtkScrolledWindowPrivate))
+@@ -206,10 +218,21 @@ static gboolean _gtk_scrolled_window_set_adjustment_value      (GtkScrolledWindo
+                                                                 gboolean           allow_overshooting,
+                                                                 gboolean           snap_to_border);
+
++static void gtk_scrolled_window_cancel_animation         (GtkScrolledWindow *scrolled_window);
++static void gtk_scrolled_window_start_fade_in_animation  (GtkScrolledWindow *scrolled_window);
++static void gtk_scrolled_window_start_fade_out_animation (GtkScrolledWindow *scrolled_window);
++static gboolean gtk_scrolled_window_child_expose (GtkWidget         *widget,
++                                                  GdkEventExpose    *eevent,
++                                                  GtkScrolledWindow *scrolled_window);
++static void  gtk_scrolled_window_expose_scrollbars (GtkAdjustment     *adj,
++                                                    GtkScrolledWindow *scrolled_window);
++
+ static guint signals[LAST_SIGNAL] = {0};
+
+ G_DEFINE_TYPE (GtkScrolledWindow, gtk_scrolled_window, GTK_TYPE_BIN)
+
++static gboolean overlay_scrollbars = TRUE;
++
+ static void
+ add_scroll_binding (GtkBindingSet  *binding_set,
+                   guint           keyval,
+@@ -444,6 +467,8 @@ gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
+ static void
+ gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
+ {
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
+   gtk_widget_set_has_window (GTK_WIDGET (scrolled_window), FALSE);
+   gtk_widget_set_can_focus (GTK_WIDGET (scrolled_window), TRUE);
+
+@@ -462,6 +487,24 @@ gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
+       gtk_scrolled_window_set_kinetic_scrolling (scrolled_window, TRUE);
+       gtk_scrolled_window_set_capture_button_press (scrolled_window, TRUE);
+     }
++
++  if (overlay_scrollbars)
++    {
++      priv->opacity = g_object_new (GTK_TYPE_ADJUSTMENT,
++                                    "lower", 0.0,
++                                    "upper", 0.5,
++                                    "value", 0.0,
++                                    NULL);
++      priv->sb_min_height = 20;
++      priv->sb_padding = 2;
++      priv->sb_radius = 3;
++      priv->sb_width = 6;
++      priv->sb_fade_out_delay = 1000;
++
++      g_signal_connect (priv->opacity, "value-changed",
++                        G_CALLBACK (gtk_scrolled_window_expose_scrollbars),
++                        scrolled_window);
++    }
+ }
+
+ /**
+@@ -541,6 +584,17 @@ gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
+       g_signal_handlers_disconnect_by_func (old_adjustment,
+                                           gtk_scrolled_window_adjustment_changed,
+                                           scrolled_window);
++
++      if (overlay_scrollbars)
++        {
++          g_signal_handlers_disconnect_by_func (old_adjustment,
++                                                gtk_scrolled_window_adjustment_value_changed,
++                                                scrolled_window);
++          g_signal_handlers_disconnect_by_func (old_adjustment,
++                                                gtk_scrolled_window_expose_scrollbars,
++                                                scrolled_window);
++        }
++
+       gtk_range_set_adjustment (GTK_RANGE (scrolled_window->hscrollbar),
+                               hadjustment);
+     }
+@@ -556,10 +610,24 @@ gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
+   gtk_scrolled_window_adjustment_changed (hadjustment, scrolled_window);
+   gtk_scrolled_window_adjustment_value_changed (hadjustment, scrolled_window);
+
++  if (overlay_scrollbars)
++    {
++      g_signal_connect (hadjustment, "value-changed",
++                        G_CALLBACK (gtk_scrolled_window_adjustment_value_changed),
++                        scrolled_window);
++
++      g_signal_connect (hadjustment, "changed",
++                        G_CALLBACK (gtk_scrolled_window_expose_scrollbars),
++                        scrolled_window);
++      g_signal_connect (hadjustment, "value-changed",
++                        G_CALLBACK (gtk_scrolled_window_expose_scrollbars),
++                        scrolled_window);
++    }
++
+   if (bin->child)
+     gtk_widget_set_scroll_adjustments (bin->child,
+-                                     gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
+-                                     gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)));
++                                       gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
++                                       gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)));
+
+   g_object_notify (G_OBJECT (scrolled_window), "hadjustment");
+ }
+@@ -607,6 +675,17 @@ gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
+       g_signal_handlers_disconnect_by_func (old_adjustment,
+                                           gtk_scrolled_window_adjustment_changed,
+                                           scrolled_window);
++
++      if (overlay_scrollbars)
++        {
++          g_signal_handlers_disconnect_by_func (old_adjustment,
++                                                gtk_scrolled_window_adjustment_value_changed,
++                                                scrolled_window);
++          g_signal_handlers_disconnect_by_func (old_adjustment,
++                                                gtk_scrolled_window_expose_scrollbars,
++                                                scrolled_window);
++        }
++
+       gtk_range_set_adjustment (GTK_RANGE (scrolled_window->vscrollbar),
+                               vadjustment);
+     }
+@@ -622,10 +701,25 @@ gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
+   gtk_scrolled_window_adjustment_changed (vadjustment, scrolled_window);
+   gtk_scrolled_window_adjustment_value_changed (vadjustment, scrolled_window);
+
++  if (overlay_scrollbars)
++    {
++      g_signal_connect (vadjustment,
++                        "value-changed",
++                        G_CALLBACK (gtk_scrolled_window_adjustment_value_changed),
++                        scrolled_window);
++
++      g_signal_connect (vadjustment, "changed",
++                        G_CALLBACK (gtk_scrolled_window_expose_scrollbars),
++                        scrolled_window);
++      g_signal_connect (vadjustment, "value-changed",
++                        G_CALLBACK (gtk_scrolled_window_expose_scrollbars),
++                        scrolled_window);
++    }
++
+   if (bin->child)
+     gtk_widget_set_scroll_adjustments (bin->child,
+-                                     gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
+-                                     gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)));
++                                       gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
++                                       gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)));
+
+   g_object_notify (G_OBJECT (scrolled_window), "vadjustment");
+ }
+@@ -1073,11 +1167,24 @@ gtk_scrolled_window_destroy (GtkObject *object)
+   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object);
+   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+
++  gtk_scrolled_window_cancel_animation (scrolled_window);
++
+   if (scrolled_window->hscrollbar)
+     {
+       g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
+                                           gtk_scrolled_window_adjustment_changed,
+                                           scrolled_window);
++
++      if (overlay_scrollbars)
++        {
++          g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
++                                                gtk_scrolled_window_adjustment_value_changed,
++                                                scrolled_window);
++          g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
++                                                gtk_scrolled_window_expose_scrollbars,
++                                                scrolled_window);
++        }
++
+       gtk_widget_unparent (scrolled_window->hscrollbar);
+       gtk_widget_destroy (scrolled_window->hscrollbar);
+       g_object_unref (scrolled_window->hscrollbar);
+@@ -1088,6 +1195,17 @@ gtk_scrolled_window_destroy (GtkObject *object)
+       g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)),
+                                           gtk_scrolled_window_adjustment_changed,
+                                           scrolled_window);
++
++      if (overlay_scrollbars)
++        {
++          g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)),
++                                                gtk_scrolled_window_adjustment_value_changed,
++                                                scrolled_window);
++          g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)),
++                                                gtk_scrolled_window_expose_scrollbars,
++                                                scrolled_window);
++        }
++
+       gtk_widget_unparent (scrolled_window->vscrollbar);
+       gtk_widget_destroy (scrolled_window->vscrollbar);
+       g_object_unref (scrolled_window->vscrollbar);
+@@ -1515,7 +1633,7 @@ gtk_scrolled_window_size_request (GtkWidget      *widget,
+
+       if (scrolled_window->hscrollbar_policy == GTK_POLICY_NEVER)
+       requisition->width += child_requisition.width;
+-      else
++      else if (! overlay_scrollbars)
+       {
+         GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (bin->child, FALSE);
+
+@@ -1530,7 +1648,7 @@ gtk_scrolled_window_size_request (GtkWidget      *widget,
+
+       if (scrolled_window->vscrollbar_policy == GTK_POLICY_NEVER)
+       requisition->height += child_requisition.height;
+-      else
++      else if (! overlay_scrollbars)
+       {
+         GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (bin->child, FALSE);
+
+@@ -1544,20 +1662,23 @@ gtk_scrolled_window_size_request (GtkWidget      *widget,
+       }
+     }
+
+-  if (scrolled_window->hscrollbar_policy == GTK_POLICY_AUTOMATIC ||
+-      scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
++  if (! overlay_scrollbars)
+     {
+-      requisition->width = MAX (requisition->width, hscrollbar_requisition.width);
+-      if (!extra_height || scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
+-      extra_height = scrollbar_spacing + hscrollbar_requisition.height;
+-    }
++      if (scrolled_window->hscrollbar_policy == GTK_POLICY_AUTOMATIC ||
++          scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
++        {
++          requisition->width = MAX (requisition->width, hscrollbar_requisition.width);
++          if (!extra_height || scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
++            extra_height = scrollbar_spacing + hscrollbar_requisition.height;
++        }
+
+-  if (scrolled_window->vscrollbar_policy == GTK_POLICY_AUTOMATIC ||
+-      scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
+-    {
+-      requisition->height = MAX (requisition->height, vscrollbar_requisition.height);
+-      if (!extra_height || scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
+-      extra_width = scrollbar_spacing + vscrollbar_requisition.width;
++      if (scrolled_window->vscrollbar_policy == GTK_POLICY_AUTOMATIC ||
++          scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
++        {
++          requisition->height = MAX (requisition->height, vscrollbar_requisition.height);
++          if (!extra_height || scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
++            extra_width = scrollbar_spacing + vscrollbar_requisition.width;
++        }
+     }
+
+   requisition->width += GTK_CONTAINER (widget)->border_width * 2 + MAX (0, extra_width);
+@@ -1598,6 +1719,9 @@ gtk_scrolled_window_relative_allocation (GtkWidget     *widget,
+   allocation->width = MAX (1, (gint)widget->allocation.width - allocation->x * 2);
+   allocation->height = MAX (1, (gint)widget->allocation.height - allocation->y * 2);
+
++  if (overlay_scrollbars)
++    return;
++
+   if (scrolled_window->vscrollbar_visible)
+     {
+       GtkRequisition vscrollbar_requisition;
+@@ -1754,6 +1878,9 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
+   scrolled_window = GTK_SCROLLED_WINDOW (widget);
+   bin = GTK_BIN (scrolled_window);
+
++  if (overlay_scrollbars)
++    gtk_scrolled_window_expose_scrollbars (NULL, scrolled_window);
++
+   scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
+   gtk_widget_style_get (widget, "scrollbars-within-bevel", &scrollbars_within_bevel, NULL);
+
+@@ -1812,7 +1939,7 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
+       gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
+     }
+
+-  if (scrolled_window->hscrollbar_visible)
++  if (!overlay_scrollbars && scrolled_window->hscrollbar_visible)
+     {
+       GtkRequisition hscrollbar_requisition;
+       gtk_widget_get_child_requisition (scrolled_window->hscrollbar,
+@@ -1860,7 +1987,7 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
+   else if (gtk_widget_get_visible (scrolled_window->hscrollbar))
+     gtk_widget_hide (scrolled_window->hscrollbar);
+
+-  if (scrolled_window->vscrollbar_visible)
++  if (!overlay_scrollbars && scrolled_window->vscrollbar_visible)
+     {
+       GtkRequisition vscrollbar_requisition;
+       if (!gtk_widget_get_visible (scrolled_window->vscrollbar))
+@@ -1930,7 +2057,7 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+   if (gdk_event_get_scroll_deltas ((GdkEvent *) event, &delta_x, &delta_y))
+     {
+       if (delta_x != 0.0 && scrolled_window->hscrollbar &&
+-          gtk_widget_get_visible (scrolled_window->hscrollbar))
++          (overlay_scrollbars || gtk_widget_get_visible (scrolled_window->hscrollbar)))
+         {
+           GtkAdjustment *adj;
+           gdouble new_value;
+@@ -1948,7 +2075,7 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+         }
+
+       if (delta_y != 0.0 && scrolled_window->vscrollbar &&
+-          gtk_widget_get_visible (scrolled_window->vscrollbar))
++          (overlay_scrollbars || gtk_widget_get_visible (scrolled_window->vscrollbar)))
+         {
+           GtkAdjustment *adj;
+           gdouble new_value;
+@@ -1974,7 +2101,7 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+       else
+         range = scrolled_window->hscrollbar;
+
+-      if (range && gtk_widget_get_visible (range))
++      if (range && (overlay_scrollbars || gtk_widget_get_visible (range)))
+         {
+           GtkAdjustment *adj = GTK_RANGE (range)->adjustment;
+           gdouble delta, new_value;
+@@ -2614,6 +2741,9 @@ gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
+           gtk_widget_queue_resize (GTK_WIDGET (scrolled_win));
+       }
+     }
++
++  if (overlay_scrollbars)
++    gtk_scrolled_window_start_fade_in_animation (scrolled_win);
+ }
+
+ static void
+@@ -2634,6 +2764,9 @@ gtk_scrolled_window_adjustment_value_changed (GtkAdjustment *adjustment,
+   else if (scrolled_window->hscrollbar &&
+            adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)))
+     priv->unclamped_hadj_value = gtk_adjustment_get_value (adjustment);
++
++  if (overlay_scrollbars)
++    gtk_scrolled_window_start_fade_in_animation (scrolled_window);
+ }
+
+ static void
+@@ -2658,10 +2791,17 @@ gtk_scrolled_window_add (GtkContainer *container,
+
+   /* this is a temporary message */
+   if (!gtk_widget_set_scroll_adjustments (child,
+-                                        gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
+-                                        gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar))))
++                                          gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
++                                          gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar))))
+     g_warning ("gtk_scrolled_window_add(): cannot add non scrollable widget "
+              "use gtk_scrolled_window_add_with_viewport() instead");
++
++  if (overlay_scrollbars)
++    {
++      g_signal_connect_after (child, "expose-event",
++                              G_CALLBACK (gtk_scrolled_window_child_expose),
++                              container);
++    }
+ }
+
+ static void
+@@ -2671,7 +2811,14 @@ gtk_scrolled_window_remove (GtkContainer *container,
+   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
+   g_return_if_fail (child != NULL);
+   g_return_if_fail (GTK_BIN (container)->child == child);
+-
++
++  if (overlay_scrollbars)
++    {
++      g_signal_handlers_disconnect_by_func (child,
++                                            gtk_scrolled_window_child_expose,
++                                            container);
++    }
++
+   gtk_widget_set_scroll_adjustments (child, NULL, NULL);
+
+   /* chain parent class handler to remove child */
+@@ -2871,5 +3018,383 @@ gtk_scrolled_window_grab_notify (GtkWidget *widget,
+     }
+ }
+
++static void
++gtk_scrolled_window_rounded_rectangle (cairo_t *cr,
++                                       gint     x,
++                                       gint     y,
++                                       gint     width,
++                                       gint     height,
++                                       gint     x_radius,
++                                       gint     y_radius)
++{
++  gint x1, x2;
++  gint y1, y2;
++  gint xr1, xr2;
++  gint yr1, yr2;
++
++  x1 = x;
++  x2 = x1 + width;
++  y1 = y;
++  y2 = y1 + height;
++
++  x_radius = MIN (x_radius, width  / 2.0);
++  y_radius = MIN (y_radius, height / 2.0);
++
++  xr1 = x_radius;
++  xr2 = x_radius / 2.0;
++  yr1 = y_radius;
++  yr2 = y_radius / 2.0;
++
++  cairo_move_to    (cr, x1 + xr1, y1);
++  cairo_line_to    (cr, x2 - xr1, y1);
++  cairo_curve_to   (cr, x2 - xr2, y1, x2, y1 + yr2, x2, y1 + yr1);
++  cairo_line_to    (cr, x2, y2 - yr1);
++  cairo_curve_to   (cr, x2, y2 - yr2, x2 - xr2, y2, x2 - xr1, y2);
++  cairo_line_to    (cr, x1 + xr1, y2);
++  cairo_curve_to   (cr, x1 + xr2, y2, x1, y2 - yr2, x1, y2 - yr1);
++  cairo_line_to    (cr, x1, y1 + yr1);
++  cairo_curve_to   (cr, x1, y1 + yr2, x1 + xr2, y1, x1 + xr1, y1);
++  cairo_close_path (cr);
++}
++
++static void
++gtk_scrolled_window_get_child_scroll_areas (GtkScrolledWindow *scrolled_window,
++                                            GtkWidget         *child,
++                                            GdkWindow         *child_window,
++                                            GdkRectangle      *vbar_rect,
++                                            GdkRectangle      *vslider_rect,
++                                            GdkRectangle      *hbar_rect,
++                                            GdkRectangle      *hslider_rect)
++{
++   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++   GtkAdjustment *adj;
++   GtkAllocation allocation;
++   gdouble lower;
++   gdouble page_size;
++   gdouble upper;
++   gdouble value_h = 0.0;
++   gdouble value_v = 0.0;
++   gdouble ratio;
++   gdouble width;
++   gdouble height;
++   gdouble x;
++   gdouble y;
++   gint window_width;
++   gint window_height;
++   gint viewport_width;
++   gint viewport_height;
++
++   window_width = gdk_window_get_width (child_window);
++   window_height = gdk_window_get_height (child_window);
++
++   gtk_widget_get_allocation (child, &allocation);
++
++   viewport_width = MIN (window_width, allocation.width);
++   viewport_height = MIN (window_height, allocation.height);
++
++   if (scrolled_window->vscrollbar)
++     {
++       adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
++
++       value_v = gtk_adjustment_get_value (adj);
++     }
++
++   if (scrolled_window->hscrollbar)
++     {
++       adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
++
++       value_h = gtk_adjustment_get_value (adj);
++     }
++
++   if ((vbar_rect || vslider_rect) && scrolled_window->vscrollbar)
++     {
++       adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
++
++       g_object_get (adj,
++                     "lower", &lower,
++                     "upper", &upper,
++                     "page-size", &page_size,
++                     NULL);
++
++       ratio = page_size / (upper - lower);
++       if (ratio < 1.0)
++         {
++           height = ratio * (viewport_height - (2 * priv->sb_padding));
++           height = MAX (height, 20);
++           height = MIN (height, viewport_height - (2 * priv->sb_padding));
++
++           ratio = (value_v - lower) / (upper - page_size - lower);
++           y = ratio * (viewport_height - (2 * priv->sb_padding) - height) + priv->sb_padding;
++           x = viewport_width - priv->sb_width - priv->sb_padding;
++
++           if (window_width > allocation.width)
++             x += value_h;
++
++           if (window_height > allocation.height)
++             y += value_v;
++
++           if (vbar_rect)
++             {
++               vbar_rect->x = x - priv->sb_padding;
++               vbar_rect->y = 0;
++               vbar_rect->width = priv->sb_width + 2 * priv->sb_padding;
++               vbar_rect->height = viewport_height;
++             }
++
++           if (vslider_rect)
++             {
++               vslider_rect->x = x;
++               vslider_rect->y = y;
++               vslider_rect->width = priv->sb_width;
++               vslider_rect->height = height;
++             }
++         }
++       else
++         {
++           if (vbar_rect)
++             {
++               vbar_rect->x = 0;
++               vbar_rect->y = 0;
++               vbar_rect->width = 0;
++               vbar_rect->height = 0;
++             }
++
++           if (vslider_rect)
++             {
++               vslider_rect->x = 0;
++               vslider_rect->y = 0;
++               vslider_rect->width = 0;
++               vslider_rect->height = 0;
++             }
++         }
++     }
++
++   if ((hbar_rect || hslider_rect) && scrolled_window->hscrollbar)
++     {
++       adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
++
++       g_object_get (adj,
++                     "lower", &lower,
++                     "upper", &upper,
++                     "page-size", &page_size,
++                     NULL);
++
++       ratio = page_size / (upper - lower);
++       if (ratio < 1.0)
++         {
++           width = ratio * (viewport_width - (2 * priv->sb_padding));
++           width = MAX (width, 20);
++           width = MIN (width, viewport_width - (2 * priv->sb_padding));
++
++           ratio = (value_h - lower) / (upper - page_size - lower);
++           x = ratio * (viewport_width - (2 * priv->sb_padding) - width) + priv->sb_padding;
++           y = viewport_height - priv->sb_width - priv->sb_padding;
++
++           if (window_width > allocation.width)
++             x += value_h;
++
++           if (window_height > allocation.height)
++             y += value_v;
++
++           if (hbar_rect)
++             {
++               hbar_rect->x = 0;
++               hbar_rect->y = y - priv->sb_padding;
++               hbar_rect->width = viewport_width;
++               hbar_rect->height = priv->sb_width + 2 * priv->sb_padding;
++             }
++
++           if (hslider_rect)
++             {
++               hslider_rect->x = x;
++               hslider_rect->y = y;
++               hslider_rect->width = width;
++               hslider_rect->height = priv->sb_width;
++             }
++         }
++       else
++         {
++           if (hbar_rect)
++             {
++               hbar_rect->x = 0;
++               hbar_rect->y = 0;
++               hbar_rect->width = 0;
++               hbar_rect->height = 0;
++             }
++
++           if (hslider_rect)
++             {
++               hslider_rect->x = 0;
++               hslider_rect->y = 0;
++               hslider_rect->width = 0;
++               hslider_rect->height = 0;
++             }
++         }
++     }
++}
++
++static gboolean
++gtk_scrolled_window_child_expose (GtkWidget         *widget,
++                                  GdkEventExpose    *eevent,
++                                  GtkScrolledWindow *scrolled_window)
++{
++   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++   GdkRectangle vbar_rect;
++   GdkRectangle vslider_rect;
++   GdkRectangle hbar_rect;
++   GdkRectangle hslider_rect;
++   cairo_t   *cr;
++
++   cr = gdk_cairo_create (eevent->window);
++   gdk_cairo_region (cr, eevent->region);
++   cairo_clip (cr);
++
++   gtk_scrolled_window_get_child_scroll_areas (scrolled_window,
++                                               gtk_bin_get_child (GTK_BIN (scrolled_window)),
++                                               eevent->window,
++                                               &vbar_rect, &vslider_rect,
++                                               &hbar_rect, &hslider_rect);
++
++   if (TRUE)
++     {
++       if (scrolled_window->vscrollbar && vbar_rect.width > 0)
++         gdk_cairo_rectangle (cr, &vbar_rect);
++
++       if (scrolled_window->hscrollbar && hbar_rect.width > 0)
++         gdk_cairo_rectangle (cr, &hbar_rect);
++
++       cairo_set_source_rgba (cr, 0, 0, 0, 0.2);
++       cairo_fill (cr);
++     }
++
++   if (scrolled_window->vscrollbar && vslider_rect.width > 0)
++     gtk_scrolled_window_rounded_rectangle (cr,
++                                            vslider_rect.x,
++                                            vslider_rect.y,
++                                            vslider_rect.width,
++                                            vslider_rect.height,
++                                            priv->sb_radius,
++                                            priv->sb_radius);
++
++   if (scrolled_window->hscrollbar && hslider_rect.width > 0)
++     gtk_scrolled_window_rounded_rectangle (cr,
++                                            hslider_rect.x,
++                                            hslider_rect.y,
++                                            hslider_rect.width,
++                                            hslider_rect.height,
++                                            priv->sb_radius,
++                                            priv->sb_radius);
++
++   cairo_set_source_rgba (cr, 0, 0, 0, gtk_adjustment_get_value (priv->opacity));
++   cairo_fill (cr);
++
++   cairo_destroy (cr);
++
++   return FALSE;
++}
++
++static void
++gtk_scrolled_window_cancel_animation (GtkScrolledWindow *scrolled_window)
++{
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++  GbAnimation *anim = priv->opacity_anim;
++
++  if (anim)
++    {
++      priv->opacity_anim = NULL;
++      g_object_remove_weak_pointer (G_OBJECT (anim),
++                                    (gpointer *) &priv->opacity_anim);
++      _gb_animation_stop (anim);
++    }
++
++  if (priv->sb_fade_out_id)
++    {
++      g_source_remove (priv->sb_fade_out_id);
++      priv->sb_fade_out_id = 0;
++    }
++
++  priv->sb_fading_in = FALSE;
++}
++
++static gboolean
++gtk_scrolled_window_fade_out_timeout (GtkScrolledWindow *scrolled_window)
++{
++  gtk_scrolled_window_start_fade_out_animation (scrolled_window);
++
++  return FALSE;
++}
++
++static void
++gtk_scrolled_window_start_fade_in_animation (GtkScrolledWindow *scrolled_window)
++{
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++  gdouble upper;
++
++  if (priv->sb_fading_in)
++    return;
++
++  gtk_scrolled_window_cancel_animation (scrolled_window);
++
++  priv->sb_fading_in = TRUE;
++
++  upper = gtk_adjustment_get_upper (priv->opacity);
++  priv->opacity_anim = _gb_object_animate (priv->opacity,
++                                           GB_ANIMATION_EASE_OUT_QUAD,
++                                           100,
++                                           "value", upper,
++                                           NULL);
++  g_object_add_weak_pointer (G_OBJECT (priv->opacity_anim),
++                             (gpointer *) &priv->opacity_anim);
++
++  priv->sb_fade_out_id =
++    gdk_threads_add_timeout (priv->sb_fade_out_delay,
++                             (GSourceFunc) gtk_scrolled_window_fade_out_timeout,
++                             scrolled_window);
++}
++
++static void
++gtk_scrolled_window_start_fade_out_animation (GtkScrolledWindow *scrolled_window)
++{
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  gtk_scrolled_window_cancel_animation (scrolled_window);
++
++  priv->opacity_anim = _gb_object_animate (priv->opacity,
++                                           GB_ANIMATION_EASE_IN_QUAD,
++                                           300,
++                                           "value", 0.0,
++                                           NULL);
++  g_object_add_weak_pointer (G_OBJECT (priv->opacity_anim),
++                             (gpointer *) &priv->opacity_anim);
++}
++
++static void
++gtk_scrolled_window_expose_scrollbars (GtkAdjustment     *adj,
++                                       GtkScrolledWindow *scrolled_window)
++{
++  GtkWidget *child = gtk_bin_get_child (GTK_BIN (scrolled_window));
++
++  if (child && gtk_widget_get_visible (child))
++    {
++      GtkAllocation alloc;
++
++      gtk_widget_get_allocation (child, &alloc);
++
++      if (scrolled_window->vscrollbar)
++        gtk_widget_queue_draw_area (child,
++                                    alloc.width - 20,
++                                    0,
++                                    20,
++                                    alloc.height);
++
++      if (scrolled_window->hscrollbar)
++        gtk_widget_queue_draw_area (child,
++                                    0,
++                                    alloc.height - 20,
++                                    alloc.width,
++                                    20);
++    }
++}
++
+ #define __GTK_SCROLLED_WINDOW_C__
+ #include "gtkaliasdef.c"
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0014-gtk-add-event-handling-to-GtkScrolledWindow-s-overla.patch b/bockbuild/mac-sdk/patches/gtk/0014-gtk-add-event-handling-to-GtkScrolledWindow-s-overla.patch
new file mode 100644 (file)
index 0000000..62acd57
--- /dev/null
@@ -0,0 +1,613 @@
+From 713b51c19644653815b8ff1cd629d706f1074043 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Tue, 10 Jul 2012 14:33:45 +0200
+Subject: [PATCH 14/68] gtk: add event handling to GtkScrolledWindow's overlay
+ scrollbars
+
+---
+ gtk/gtkscrolledwindow.c |  438 +++++++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 403 insertions(+), 35 deletions(-)
+
+diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
+index 77d485f..70de6ec 100644
+--- a/gtk/gtkscrolledwindow.c
++++ b/gtk/gtkscrolledwindow.c
+@@ -84,6 +84,10 @@
+ #define OVERSHOOT_INVERSE_ACCELERATION 0.003
+ #define RELEASE_EVENT_TIMEOUT 1000
+
++/* Overlay scrollbars */
++#define SCROLL_INTERVAL_INITIAL 300
++#define SCROLL_INTERVAL_REPEAT 100
++
+ typedef struct {
+   gboolean window_placement_set;
+   GtkCornerType real_window_placement;
+@@ -123,6 +127,19 @@ typedef struct {
+   gboolean       sb_fading_in;
+   gint           sb_fade_out_delay;
+   guint          sb_fade_out_id;
++
++  gboolean       sb_hovering;
++  gboolean       sb_pointer_grabbed;
++  gboolean       sb_grab_vscroll;
++  gboolean       sb_grab_hscroll;
++  gboolean       sb_drag_slider;
++  gboolean       sb_visible;
++
++  gint           sb_grab_offset_x;
++  gint           sb_grab_offset_y;
++
++  gint           sb_scroll_direction;
++  guint          sb_scroll_timeout_id;
+ } GtkScrolledWindowPrivate;
+
+ #define GTK_SCROLLED_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_SCROLLED_WINDOW, GtkScrolledWindowPrivate))
+@@ -219,8 +236,24 @@ static gboolean _gtk_scrolled_window_set_adjustment_value      (GtkScrolledWindo
+                                                                 gboolean           snap_to_border);
+
+ static void gtk_scrolled_window_cancel_animation         (GtkScrolledWindow *scrolled_window);
++static void gtk_scrolled_window_start_fade_out_timeout (GtkScrolledWindow *scrolled_window);
++static void gtk_scrolled_window_stop_fade_out_timeout (GtkScrolledWindow *scrolled_window);
+ static void gtk_scrolled_window_start_fade_in_animation  (GtkScrolledWindow *scrolled_window);
+ static void gtk_scrolled_window_start_fade_out_animation (GtkScrolledWindow *scrolled_window);
++static gboolean
++           gtk_scrolled_window_over_child_scroll_areas (GtkScrolledWindow *scrolled_window,
++                                                        GdkEvent          *event,
++                                                        gint               x,
++                                                        gint               y,
++                                                        gboolean          *over_vscroll,
++                                                        gboolean          *over_hscroll);
++static void gtk_scrolled_window_get_child_scroll_areas (GtkScrolledWindow *scrolled_window,
++                                                        GtkWidget         *child,
++                                                        GdkWindow         *child_window,
++                                                        GdkRectangle      *vbar_rect,
++                                                        GdkRectangle      *vslider_rect,
++                                                        GdkRectangle      *hbar_rect,
++                                                        GdkRectangle      *hslider_rect);
+ static gboolean gtk_scrolled_window_child_expose (GtkWidget         *widget,
+                                                   GdkEventExpose    *eevent,
+                                                   GtkScrolledWindow *scrolled_window);
+@@ -2385,8 +2418,8 @@ gtk_scrolled_window_calculate_velocity (GtkScrolledWindow *scrolled_window,
+ }
+
+ static gboolean
+-gtk_scrolled_window_captured_button_release (GtkWidget *widget,
+-                                             GdkEvent  *event)
++gtk_scrolled_window_captured_button_release_kinetic (GtkWidget *widget,
++                                                     GdkEvent  *event)
+ {
+   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
+   GtkScrolledWindowPrivate *priv;
+@@ -2462,8 +2495,8 @@ gtk_scrolled_window_captured_button_release (GtkWidget *widget,
+ }
+
+ static gboolean
+-gtk_scrolled_window_captured_motion_notify (GtkWidget *widget,
+-                                            GdkEvent  *event)
++gtk_scrolled_window_captured_motion_notify_kinetic (GtkWidget *widget,
++                                                    GdkEvent  *event)
+ {
+   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
+   GtkScrolledWindowPrivate *priv;
+@@ -2554,8 +2587,8 @@ gtk_scrolled_window_captured_motion_notify (GtkWidget *widget,
+ }
+
+ static gboolean
+-gtk_scrolled_window_captured_button_press (GtkWidget *widget,
+-                                           GdkEvent  *event)
++gtk_scrolled_window_captured_button_press_kinetic (GtkWidget *widget,
++                                                   GdkEvent  *event)
+ {
+   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
+   GtkScrolledWindowPrivate *priv;
+@@ -2633,29 +2666,283 @@ gtk_scrolled_window_captured_button_press (GtkWidget *widget,
+     return FALSE;
+ }
+
++static void
++gtk_scrolled_window_scroll_step (GtkScrolledWindow *scrolled_window)
++{
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++  GtkAdjustment *adj;
++  gdouble value;
++
++  if (priv->sb_grab_vscroll)
++    {
++      adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
++    }
++  else if (priv->sb_grab_hscroll)
++    {
++      adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
++    }
++
++  value = adj->value + (priv->sb_scroll_direction * adj->page_size);
++  value = CLAMP (value, adj->lower, adj->upper - adj->page_size);
++
++  gtk_adjustment_set_value (adj, value);
++}
++
++static gboolean
++gtk_scrolled_window_scroll_step_timeout (gpointer data)
++{
++  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (data);
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  gtk_scrolled_window_scroll_step (scrolled_window);
++
++  g_source_remove (priv->sb_scroll_timeout_id);
++
++  priv->sb_scroll_timeout_id =
++    gdk_threads_add_timeout (SCROLL_INTERVAL_REPEAT,
++                             gtk_scrolled_window_scroll_step_timeout,
++                             scrolled_window);
++
++  return FALSE;
++}
++
++static gboolean
++gtk_scrolled_window_captured_button_press_scrollbar (GtkWidget *widget,
++                                                     GdkEvent  *event)
++{
++  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++  GdkEventButton *bevent = (GdkEventButton *) event;
++
++  if (bevent->button != 1)
++    return FALSE;
++
++  if (gtk_scrolled_window_over_child_scroll_areas (scrolled_window, event,
++                                                   bevent->x, bevent->y,
++                                                   &priv->sb_grab_vscroll,
++                                                   &priv->sb_grab_hscroll))
++    {
++      GdkRectangle vbar_rect;
++      GdkRectangle vslider_rect;
++      GdkRectangle hbar_rect;
++      GdkRectangle hslider_rect;
++
++      priv->sb_pointer_grabbed = TRUE;
++      gtk_grab_add (widget);
++
++      gtk_scrolled_window_get_child_scroll_areas (scrolled_window,
++                                                  gtk_bin_get_child (GTK_BIN (widget)),
++                                                  bevent->window,
++                                                  &vbar_rect, &vslider_rect,
++                                                  &hbar_rect, &hslider_rect);
++
++      if (priv->sb_grab_vscroll)
++        {
++          /* we consider the entire width of the scrollbar clickable */
++          vslider_rect.x = vbar_rect.x;
++          vslider_rect.width = vbar_rect.width;
++
++          if (bevent->x >= vslider_rect.x &&
++              bevent->x < (vslider_rect.x + vslider_rect.width) &&
++              bevent->y >= vslider_rect.y &&
++              bevent->y < (vslider_rect.y + vslider_rect.height))
++            {
++              priv->sb_drag_slider = TRUE;
++              priv->sb_grab_offset_y = bevent->y - vslider_rect.y;
++            }
++          else
++            {
++              priv->sb_drag_slider = FALSE;
++              priv->sb_grab_offset_y = bevent->y - vbar_rect.y;
++
++              if (bevent->y < vslider_rect.y)
++                priv->sb_scroll_direction = -1;
++              else
++                priv->sb_scroll_direction = 1;
++            }
++        }
++      else if (priv->sb_grab_hscroll)
++        {
++          /* we consider the entire height of the scrollbar clickable */
++          hslider_rect.y = hbar_rect.y;
++          hslider_rect.height = hbar_rect.height;
++
++          if (bevent->x >= hslider_rect.x &&
++              bevent->x < (hslider_rect.x + hslider_rect.width) &&
++              bevent->y >= hslider_rect.y &&
++              bevent->y < (hslider_rect.y + hslider_rect.height))
++            {
++              priv->sb_drag_slider = TRUE;
++              priv->sb_grab_offset_x = bevent->x - hslider_rect.x;
++            }
++          else
++            {
++              priv->sb_drag_slider = FALSE;
++              priv->sb_grab_offset_x = bevent->x - hbar_rect.x;
++
++              if (bevent->x < hslider_rect.x)
++                priv->sb_scroll_direction = -1;
++              else
++                priv->sb_scroll_direction = 1;
++            }
++        }
++
++      if ((priv->sb_grab_vscroll || priv->sb_grab_hscroll) &&
++          !priv->sb_drag_slider)
++        {
++          gtk_scrolled_window_scroll_step (scrolled_window);
++
++          priv->sb_scroll_timeout_id =
++            gdk_threads_add_timeout (SCROLL_INTERVAL_INITIAL,
++                                     gtk_scrolled_window_scroll_step_timeout,
++                                     scrolled_window);
++        }
++
++      return TRUE;
++    }
++
++  return FALSE;
++}
++
++static gboolean
++gtk_scrolled_window_captured_button_release_scrollbar (GtkWidget *widget,
++                                                       GdkEvent  *event)
++{
++  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++  GdkEventButton *bevent = (GdkEventButton *) event;
++
++  if (bevent->button != 1)
++    return FALSE;
++
++  gtk_grab_remove (widget);
++  priv->sb_pointer_grabbed = FALSE;
++
++  if (priv->sb_scroll_timeout_id)
++    {
++      g_source_remove (priv->sb_scroll_timeout_id);
++      priv->sb_scroll_timeout_id = 0;
++    }
++
++  return TRUE;
++}
++
++static gboolean
++gtk_scrolled_window_captured_motion_notify_scrollbar (GtkWidget *widget,
++                                                      GdkEvent  *event)
++{
++  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++  GdkEventMotion *mevent = (GdkEventMotion *) event;
++
++  if (priv->sb_pointer_grabbed)
++    {
++      if (priv->sb_drag_slider)
++        {
++          GdkRectangle vbar_rect;
++          GdkRectangle vslider_rect;
++          GdkRectangle hbar_rect;
++          GdkRectangle hslider_rect;
++          GtkAdjustment *adj;
++          gint pos;
++          gint visible_range;
++          gdouble value;
++
++          gtk_scrolled_window_get_child_scroll_areas (scrolled_window,
++                                                      gtk_bin_get_child (GTK_BIN (widget)),
++                                                      mevent->window,
++                                                      &vbar_rect, &vslider_rect,
++                                                      &hbar_rect, &hslider_rect);
++
++          if (priv->sb_grab_vscroll)
++            {
++              adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
++              pos = mevent->y - priv->sb_grab_offset_y - vbar_rect.y;
++              visible_range = vbar_rect.height - vslider_rect.height;
++            }
++          else if (priv->sb_grab_hscroll)
++            {
++              adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
++              pos = mevent->x - priv->sb_grab_offset_x - hbar_rect.x;
++              visible_range = hbar_rect.width - hslider_rect.width;
++            }
++
++          pos = CLAMP (pos, 0, visible_range);
++
++          value = (adj->upper - adj->page_size - adj->lower) * pos / visible_range;
++
++          gtk_adjustment_set_value (adj, value);
++        }
++
++      return TRUE;
++    }
++  else
++    {
++      if (gtk_scrolled_window_over_child_scroll_areas (scrolled_window, event,
++                                                       mevent->x, mevent->y,
++                                                       NULL, NULL))
++        {
++          priv->sb_hovering = TRUE;
++          priv->sb_visible = TRUE;
++
++          gtk_scrolled_window_start_fade_in_animation (scrolled_window);
++          gtk_scrolled_window_stop_fade_out_timeout (scrolled_window);
++
++          /* needed when entering the scrollbar */
++          gtk_scrolled_window_expose_scrollbars (NULL, scrolled_window);
++
++          return TRUE;
++        }
++
++      priv->sb_hovering = FALSE;
++
++      if (priv->sb_visible || gtk_adjustment_get_value (priv->opacity) > 0.0)
++        {
++          /* keep visible scrollbars visible while the mouse is moving */
++          gtk_scrolled_window_start_fade_in_animation (scrolled_window);
++          gtk_scrolled_window_stop_fade_out_timeout (scrolled_window);
++          gtk_scrolled_window_start_fade_out_timeout (scrolled_window);
++        }
++
++      return FALSE;
++    }
++}
++
+ static gboolean
+ gtk_scrolled_window_captured_event (GtkWidget *widget,
+                                     GdkEvent  *event)
+ {
+-  gboolean retval = FALSE;
++  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
+   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (widget);
++  gboolean retval = FALSE;
+
+   switch (event->type)
+     {
+     case GDK_BUTTON_PRESS:
+-      retval = gtk_scrolled_window_captured_button_press (widget, event);
++      retval = gtk_scrolled_window_captured_button_press_scrollbar (widget, event);
++      if (!retval)
++        retval = gtk_scrolled_window_captured_button_press_kinetic (widget, event);
+       break;
+     case GDK_BUTTON_RELEASE:
+-      if (priv->pointer_grabbed)
+-        retval = gtk_scrolled_window_captured_button_release (widget, event);
++      if (priv->sb_pointer_grabbed)
++        retval = gtk_scrolled_window_captured_button_release_scrollbar (widget, event);
++      else if (priv->pointer_grabbed)
++        retval = gtk_scrolled_window_captured_button_release_kinetic (widget, event);
+       else
+         priv->last_button_event_valid = FALSE;
+       break;
+     case GDK_MOTION_NOTIFY:
+-      if (priv->pointer_grabbed)
+-        retval = gtk_scrolled_window_captured_motion_notify (widget, event);
++      if (priv->sb_pointer_grabbed || !priv->pointer_grabbed)
++        retval = gtk_scrolled_window_captured_motion_notify_scrollbar (widget, event);
++      else if (priv->pointer_grabbed)
++        retval = gtk_scrolled_window_captured_motion_notify_kinetic (widget, event);
+       break;
+     case GDK_LEAVE_NOTIFY:
++      if (!priv->in_drag && !priv->sb_pointer_grabbed)
++        {
++          gtk_scrolled_window_start_fade_out_timeout (scrolled_window);
++          priv->sb_hovering = FALSE;
++        }
+     case GDK_ENTER_NOTIFY:
+       if (priv->in_drag &&
+           event->crossing.mode != GDK_CROSSING_GRAB)
+@@ -3016,6 +3303,17 @@ gtk_scrolled_window_grab_notify (GtkWidget *widget,
+
+       priv->last_button_event_valid = FALSE;
+     }
++
++  if (priv->sb_pointer_grabbed && !was_grabbed)
++    {
++      priv->sb_pointer_grabbed = FALSE;
++
++      if (priv->sb_scroll_timeout_id)
++        {
++          g_source_remove (priv->sb_scroll_timeout_id);
++          priv->sb_scroll_timeout_id = 0;
++        }
++    }
+ }
+
+ static void
+@@ -3057,6 +3355,56 @@ gtk_scrolled_window_rounded_rectangle (cairo_t *cr,
+   cairo_close_path (cr);
+ }
+
++static gboolean
++gtk_scrolled_window_over_child_scroll_areas (GtkScrolledWindow *scrolled_window,
++                                             GdkEvent          *event,
++                                             gint               x,
++                                             gint               y,
++                                             gboolean          *over_vscroll,
++                                             gboolean          *over_hscroll)
++{
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++  GtkWidget *child;
++  GdkRectangle vbar_rect;
++  GdkRectangle hbar_rect;
++  gboolean over_v = FALSE;
++  gboolean over_h = FALSE;
++
++  child = gtk_bin_get_child (GTK_BIN (scrolled_window));
++  if (!child)
++    return FALSE;
++
++  if (gtk_get_event_widget (event) != child)
++    return FALSE;
++
++  if (gtk_adjustment_get_value (priv->opacity) == 0.0)
++    return FALSE;
++
++  gtk_scrolled_window_get_child_scroll_areas (scrolled_window,
++                                              child,
++                                              ((GdkEventAny *) event)->window,
++                                              &vbar_rect, NULL,
++                                              &hbar_rect, NULL);
++
++  if (vbar_rect.width > 0 &&
++      x >= vbar_rect.x && x < (vbar_rect.x + vbar_rect.width) &&
++      y >= vbar_rect.y && y < (vbar_rect.y + vbar_rect.height))
++    {
++      over_v = TRUE;
++    }
++  else if (hbar_rect.width > 0 &&
++           x >= hbar_rect.x && x < (hbar_rect.x + hbar_rect.width) &&
++           y >= hbar_rect.y && y < (hbar_rect.y + hbar_rect.height))
++    {
++      over_h = TRUE;
++    }
++
++  if (over_vscroll) *over_vscroll = over_v;
++  if (over_hscroll) *over_hscroll = over_h;
++
++  return over_v || over_h;
++}
++
+ static void
+ gtk_scrolled_window_get_child_scroll_areas (GtkScrolledWindow *scrolled_window,
+                                             GtkWidget         *child,
+@@ -3083,6 +3431,8 @@ gtk_scrolled_window_get_child_scroll_areas (GtkScrolledWindow *scrolled_window,
+    gint window_height;
+    gint viewport_width;
+    gint viewport_height;
++   gint offset_x = 0;
++   gint offset_y = 0;
+
+    window_width = gdk_window_get_width (child_window);
+    window_height = gdk_window_get_height (child_window);
+@@ -3106,6 +3456,12 @@ gtk_scrolled_window_get_child_scroll_areas (GtkScrolledWindow *scrolled_window,
+        value_h = gtk_adjustment_get_value (adj);
+      }
+
++   if (window_width > allocation.width)
++     offset_x = value_h;
++
++   if (window_height > allocation.height)
++     offset_y = value_v;
++
+    if ((vbar_rect || vslider_rect) && scrolled_window->vscrollbar)
+      {
+        adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
+@@ -3127,16 +3483,13 @@ gtk_scrolled_window_get_child_scroll_areas (GtkScrolledWindow *scrolled_window,
+            y = ratio * (viewport_height - (2 * priv->sb_padding) - height) + priv->sb_padding;
+            x = viewport_width - priv->sb_width - priv->sb_padding;
+
+-           if (window_width > allocation.width)
+-             x += value_h;
+-
+-           if (window_height > allocation.height)
+-             y += value_v;
++           x += offset_x;
++           y += offset_y;
+
+            if (vbar_rect)
+              {
+                vbar_rect->x = x - priv->sb_padding;
+-               vbar_rect->y = 0;
++               vbar_rect->y = offset_y;
+                vbar_rect->width = priv->sb_width + 2 * priv->sb_padding;
+                vbar_rect->height = viewport_height;
+              }
+@@ -3190,15 +3543,12 @@ gtk_scrolled_window_get_child_scroll_areas (GtkScrolledWindow *scrolled_window,
+            x = ratio * (viewport_width - (2 * priv->sb_padding) - width) + priv->sb_padding;
+            y = viewport_height - priv->sb_width - priv->sb_padding;
+
+-           if (window_width > allocation.width)
+-             x += value_h;
+-
+-           if (window_height > allocation.height)
+-             y += value_v;
++           x += offset_x;
++           y += offset_y;
+
+            if (hbar_rect)
+              {
+-               hbar_rect->x = 0;
++               hbar_rect->x = offset_x;
+                hbar_rect->y = y - priv->sb_padding;
+                hbar_rect->width = viewport_width;
+                hbar_rect->height = priv->sb_width + 2 * priv->sb_padding;
+@@ -3255,7 +3605,7 @@ gtk_scrolled_window_child_expose (GtkWidget         *widget,
+                                                &vbar_rect, &vslider_rect,
+                                                &hbar_rect, &hslider_rect);
+
+-   if (TRUE)
++   if (priv->sb_visible)
+      {
+        if (scrolled_window->vscrollbar && vbar_rect.width > 0)
+          gdk_cairo_rectangle (cr, &vbar_rect);
+@@ -3263,7 +3613,7 @@ gtk_scrolled_window_child_expose (GtkWidget         *widget,
+        if (scrolled_window->hscrollbar && hbar_rect.width > 0)
+          gdk_cairo_rectangle (cr, &hbar_rect);
+
+-       cairo_set_source_rgba (cr, 0, 0, 0, 0.2);
++       cairo_set_source_rgba (cr, 0, 0, 0, gtk_adjustment_get_value (priv->opacity) / 2.0);
+        cairo_fill (cr);
+      }
+
+@@ -3307,11 +3657,7 @@ gtk_scrolled_window_cancel_animation (GtkScrolledWindow *scrolled_window)
+       _gb_animation_stop (anim);
+     }
+
+-  if (priv->sb_fade_out_id)
+-    {
+-      g_source_remove (priv->sb_fade_out_id);
+-      priv->sb_fade_out_id = 0;
+-    }
++  gtk_scrolled_window_stop_fade_out_timeout (scrolled_window);
+
+   priv->sb_fading_in = FALSE;
+ }
+@@ -3325,6 +3671,30 @@ gtk_scrolled_window_fade_out_timeout (GtkScrolledWindow *scrolled_window)
+ }
+
+ static void
++gtk_scrolled_window_start_fade_out_timeout (GtkScrolledWindow *scrolled_window)
++{
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  if (! priv->sb_fade_out_id)
++    priv->sb_fade_out_id =
++      gdk_threads_add_timeout (priv->sb_fade_out_delay,
++                               (GSourceFunc) gtk_scrolled_window_fade_out_timeout,
++                               scrolled_window);
++}
++
++static void
++gtk_scrolled_window_stop_fade_out_timeout (GtkScrolledWindow *scrolled_window)
++{
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  if (priv->sb_fade_out_id)
++    {
++      g_source_remove (priv->sb_fade_out_id);
++      priv->sb_fade_out_id = 0;
++    }
++}
++
++static void
+ gtk_scrolled_window_start_fade_in_animation (GtkScrolledWindow *scrolled_window)
+ {
+   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+@@ -3336,6 +3706,7 @@ gtk_scrolled_window_start_fade_in_animation (GtkScrolledWindow *scrolled_window)
+   gtk_scrolled_window_cancel_animation (scrolled_window);
+
+   priv->sb_fading_in = TRUE;
++  priv->sb_visible = priv->sb_hovering;
+
+   upper = gtk_adjustment_get_upper (priv->opacity);
+   priv->opacity_anim = _gb_object_animate (priv->opacity,
+@@ -3346,10 +3717,7 @@ gtk_scrolled_window_start_fade_in_animation (GtkScrolledWindow *scrolled_window)
+   g_object_add_weak_pointer (G_OBJECT (priv->opacity_anim),
+                              (gpointer *) &priv->opacity_anim);
+
+-  priv->sb_fade_out_id =
+-    gdk_threads_add_timeout (priv->sb_fade_out_delay,
+-                             (GSourceFunc) gtk_scrolled_window_fade_out_timeout,
+-                             scrolled_window);
++  gtk_scrolled_window_start_fade_out_timeout (scrolled_window);
+ }
+
+ static void
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0015-Use-gtk-enable-overlay-scrollbars-in-GtkScrolledWind.patch b/bockbuild/mac-sdk/patches/gtk/0015-Use-gtk-enable-overlay-scrollbars-in-GtkScrolledWind.patch
new file mode 100644 (file)
index 0000000..06a2fc7
--- /dev/null
@@ -0,0 +1,371 @@
+From eea6eef69858ff65ff8ccf46bb640bcc0580f592 Mon Sep 17 00:00:00 2001
+From: Kristian Rietveld <kris@lanedo.com>
+Date: Sun, 29 Jul 2012 16:14:09 +0200
+Subject: [PATCH 15/68] Use gtk-enable-overlay-scrollbars in GtkScrolledWindow
+
+And listen for changes to this setting.  Move overlay_scrollbars variable
+to GtkScrolledWindowPrivate, because we are going to have to monitor for
+each scrolled window whether it has transformed itself in response to the
+signal.
+---
+ gtk/gtkscrolledwindow.c |   97 +++++++++++++++++++++++++++++++++++------------
+ 1 file changed, 72 insertions(+), 25 deletions(-)
+
+diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
+index 70de6ec..3220e91 100644
+--- a/gtk/gtkscrolledwindow.c
++++ b/gtk/gtkscrolledwindow.c
+@@ -140,6 +140,8 @@ typedef struct {
+
+   gint           sb_scroll_direction;
+   guint          sb_scroll_timeout_id;
++
++  gboolean       overlay_scrollbars;
+ } GtkScrolledWindowPrivate;
+
+ #define GTK_SCROLLED_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_SCROLLED_WINDOW, GtkScrolledWindowPrivate))
+@@ -260,12 +262,14 @@ static gboolean gtk_scrolled_window_child_expose (GtkWidget         *widget,
+ static void  gtk_scrolled_window_expose_scrollbars (GtkAdjustment     *adj,
+                                                     GtkScrolledWindow *scrolled_window);
+
++static void gtk_scrolled_window_overlay_scrollbars_changed (GtkSettings *settings,
++                                                            GParamSpec  *arg,
++                                                            gpointer     user_data);
++
+ static guint signals[LAST_SIGNAL] = {0};
+
+ G_DEFINE_TYPE (GtkScrolledWindow, gtk_scrolled_window, GTK_TYPE_BIN)
+
+-static gboolean overlay_scrollbars = TRUE;
+-
+ static void
+ add_scroll_binding (GtkBindingSet  *binding_set,
+                   guint           keyval,
+@@ -501,6 +505,7 @@ static void
+ gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
+ {
+   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++  GtkSettings *settings;
+
+   gtk_widget_set_has_window (GTK_WIDGET (scrolled_window), FALSE);
+   gtk_widget_set_can_focus (GTK_WIDGET (scrolled_window), TRUE);
+@@ -515,13 +520,22 @@ gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
+   scrolled_window->window_placement = GTK_CORNER_TOP_LEFT;
+   gtk_scrolled_window_update_real_placement (scrolled_window);
+
++  settings = gtk_widget_get_settings (GTK_WIDGET (scrolled_window));
++  g_object_get (settings,
++                "gtk-enable-overlay-scrollbars",
++                &priv->overlay_scrollbars,
++                NULL);
++  g_signal_connect (settings, "notify::gtk-enable-overlay-scrollbars",
++                    G_CALLBACK (gtk_scrolled_window_overlay_scrollbars_changed),
++                    scrolled_window);
++
+   if (g_getenv ("GTK2_KINETIC_SCROLLING"))
+     {
+       gtk_scrolled_window_set_kinetic_scrolling (scrolled_window, TRUE);
+       gtk_scrolled_window_set_capture_button_press (scrolled_window, TRUE);
+     }
+
+-  if (overlay_scrollbars)
++  if (priv->overlay_scrollbars)
+     {
+       priv->opacity = g_object_new (GTK_TYPE_ADJUSTMENT,
+                                     "lower", 0.0,
+@@ -586,6 +600,7 @@ gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
+                                    GtkAdjustment     *hadjustment)
+ {
+   GtkBin *bin;
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+
+   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
+   if (hadjustment)
+@@ -618,7 +633,7 @@ gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
+                                           gtk_scrolled_window_adjustment_changed,
+                                           scrolled_window);
+
+-      if (overlay_scrollbars)
++      if (priv->overlay_scrollbars)
+         {
+           g_signal_handlers_disconnect_by_func (old_adjustment,
+                                                 gtk_scrolled_window_adjustment_value_changed,
+@@ -643,7 +658,7 @@ gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
+   gtk_scrolled_window_adjustment_changed (hadjustment, scrolled_window);
+   gtk_scrolled_window_adjustment_value_changed (hadjustment, scrolled_window);
+
+-  if (overlay_scrollbars)
++  if (priv->overlay_scrollbars)
+     {
+       g_signal_connect (hadjustment, "value-changed",
+                         G_CALLBACK (gtk_scrolled_window_adjustment_value_changed),
+@@ -677,6 +692,7 @@ gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
+                                    GtkAdjustment     *vadjustment)
+ {
+   GtkBin *bin;
++  GtkScrolledWindowPrivate *priv;
+
+   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
+   if (vadjustment)
+@@ -685,6 +701,7 @@ gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
+     vadjustment = (GtkAdjustment*) g_object_new (GTK_TYPE_ADJUSTMENT, NULL);
+
+   bin = GTK_BIN (scrolled_window);
++  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+
+   if (!scrolled_window->vscrollbar)
+     {
+@@ -709,7 +726,7 @@ gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
+                                           gtk_scrolled_window_adjustment_changed,
+                                           scrolled_window);
+
+-      if (overlay_scrollbars)
++      if (priv->overlay_scrollbars)
+         {
+           g_signal_handlers_disconnect_by_func (old_adjustment,
+                                                 gtk_scrolled_window_adjustment_value_changed,
+@@ -734,7 +751,7 @@ gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
+   gtk_scrolled_window_adjustment_changed (vadjustment, scrolled_window);
+   gtk_scrolled_window_adjustment_value_changed (vadjustment, scrolled_window);
+
+-  if (overlay_scrollbars)
++  if (priv->overlay_scrollbars)
+     {
+       g_signal_connect (vadjustment,
+                         "value-changed",
+@@ -1208,7 +1225,7 @@ gtk_scrolled_window_destroy (GtkObject *object)
+                                           gtk_scrolled_window_adjustment_changed,
+                                           scrolled_window);
+
+-      if (overlay_scrollbars)
++      if (priv->overlay_scrollbars)
+         {
+           g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
+                                                 gtk_scrolled_window_adjustment_value_changed,
+@@ -1229,7 +1246,7 @@ gtk_scrolled_window_destroy (GtkObject *object)
+                                           gtk_scrolled_window_adjustment_changed,
+                                           scrolled_window);
+
+-      if (overlay_scrollbars)
++      if (priv->overlay_scrollbars)
+         {
+           g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)),
+                                                 gtk_scrolled_window_adjustment_value_changed,
+@@ -1245,6 +1262,10 @@ gtk_scrolled_window_destroy (GtkObject *object)
+       scrolled_window->vscrollbar = NULL;
+     }
+
++  g_signal_handlers_disconnect_by_func (gtk_widget_get_settings (GTK_WIDGET (scrolled_window)),
++                                        G_CALLBACK (gtk_scrolled_window_overlay_scrollbars_changed),
++                                        scrolled_window);
++
+   if (priv->release_timeout_id)
+     {
+       g_source_remove (priv->release_timeout_id);
+@@ -1641,12 +1662,14 @@ gtk_scrolled_window_size_request (GtkWidget      *widget,
+   GtkRequisition hscrollbar_requisition;
+   GtkRequisition vscrollbar_requisition;
+   GtkRequisition child_requisition;
++  GtkScrolledWindowPrivate *priv;
+
+   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
+   g_return_if_fail (requisition != NULL);
+
+   scrolled_window = GTK_SCROLLED_WINDOW (widget);
+   bin = GTK_BIN (scrolled_window);
++  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+
+   scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
+
+@@ -1666,7 +1689,7 @@ gtk_scrolled_window_size_request (GtkWidget      *widget,
+
+       if (scrolled_window->hscrollbar_policy == GTK_POLICY_NEVER)
+       requisition->width += child_requisition.width;
+-      else if (! overlay_scrollbars)
++      else if (! priv->overlay_scrollbars)
+       {
+         GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (bin->child, FALSE);
+
+@@ -1681,7 +1704,7 @@ gtk_scrolled_window_size_request (GtkWidget      *widget,
+
+       if (scrolled_window->vscrollbar_policy == GTK_POLICY_NEVER)
+       requisition->height += child_requisition.height;
+-      else if (! overlay_scrollbars)
++      else if (! priv->overlay_scrollbars)
+       {
+         GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (bin->child, FALSE);
+
+@@ -1695,7 +1718,7 @@ gtk_scrolled_window_size_request (GtkWidget      *widget,
+       }
+     }
+
+-  if (! overlay_scrollbars)
++  if (! priv->overlay_scrollbars)
+     {
+       if (scrolled_window->hscrollbar_policy == GTK_POLICY_AUTOMATIC ||
+           scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
+@@ -1752,7 +1775,7 @@ gtk_scrolled_window_relative_allocation (GtkWidget     *widget,
+   allocation->width = MAX (1, (gint)widget->allocation.width - allocation->x * 2);
+   allocation->height = MAX (1, (gint)widget->allocation.height - allocation->y * 2);
+
+-  if (overlay_scrollbars)
++  if (priv->overlay_scrollbars)
+     return;
+
+   if (scrolled_window->vscrollbar_visible)
+@@ -1909,16 +1932,15 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
+   g_return_if_fail (allocation != NULL);
+
+   scrolled_window = GTK_SCROLLED_WINDOW (widget);
++  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+   bin = GTK_BIN (scrolled_window);
+
+-  if (overlay_scrollbars)
++  if (priv->overlay_scrollbars)
+     gtk_scrolled_window_expose_scrollbars (NULL, scrolled_window);
+
+   scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
+   gtk_widget_style_get (widget, "scrollbars-within-bevel", &scrollbars_within_bevel, NULL);
+
+-  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+-
+   widget->allocation = *allocation;
+
+   if (scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
+@@ -1972,7 +1994,7 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
+       gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
+     }
+
+-  if (!overlay_scrollbars && scrolled_window->hscrollbar_visible)
++  if (!priv->overlay_scrollbars && scrolled_window->hscrollbar_visible)
+     {
+       GtkRequisition hscrollbar_requisition;
+       gtk_widget_get_child_requisition (scrolled_window->hscrollbar,
+@@ -2020,7 +2042,7 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
+   else if (gtk_widget_get_visible (scrolled_window->hscrollbar))
+     gtk_widget_hide (scrolled_window->hscrollbar);
+
+-  if (!overlay_scrollbars && scrolled_window->vscrollbar_visible)
++  if (!priv->overlay_scrollbars && scrolled_window->vscrollbar_visible)
+     {
+       GtkRequisition vscrollbar_requisition;
+       if (!gtk_widget_get_visible (scrolled_window->vscrollbar))
+@@ -2080,6 +2102,7 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+                                 GdkEventScroll *event)
+ {
+   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+   gboolean handled = FALSE;
+   gdouble delta_x;
+   gdouble delta_y;
+@@ -2090,7 +2113,7 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+   if (gdk_event_get_scroll_deltas ((GdkEvent *) event, &delta_x, &delta_y))
+     {
+       if (delta_x != 0.0 && scrolled_window->hscrollbar &&
+-          (overlay_scrollbars || gtk_widget_get_visible (scrolled_window->hscrollbar)))
++          (priv->overlay_scrollbars || gtk_widget_get_visible (scrolled_window->hscrollbar)))
+         {
+           GtkAdjustment *adj;
+           gdouble new_value;
+@@ -2108,7 +2131,7 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+         }
+
+       if (delta_y != 0.0 && scrolled_window->vscrollbar &&
+-          (overlay_scrollbars || gtk_widget_get_visible (scrolled_window->vscrollbar)))
++          (priv->overlay_scrollbars || gtk_widget_get_visible (scrolled_window->vscrollbar)))
+         {
+           GtkAdjustment *adj;
+           gdouble new_value;
+@@ -2134,7 +2157,7 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+       else
+         range = scrolled_window->hscrollbar;
+
+-      if (range && (overlay_scrollbars || gtk_widget_get_visible (range)))
++      if (range && (priv->overlay_scrollbars || gtk_widget_get_visible (range)))
+         {
+           GtkAdjustment *adj = GTK_RANGE (range)->adjustment;
+           gdouble delta, new_value;
+@@ -2994,11 +3017,13 @@ gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
+                                       gpointer       data)
+ {
+   GtkScrolledWindow *scrolled_win;
++  GtkScrolledWindowPrivate *priv;
+
+   g_return_if_fail (adjustment != NULL);
+   g_return_if_fail (data != NULL);
+
+   scrolled_win = GTK_SCROLLED_WINDOW (data);
++  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (data);
+
+   if (scrolled_win->hscrollbar &&
+       adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_win->hscrollbar)))
+@@ -3029,7 +3054,7 @@ gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
+       }
+     }
+
+-  if (overlay_scrollbars)
++  if (priv->overlay_scrollbars)
+     gtk_scrolled_window_start_fade_in_animation (scrolled_win);
+ }
+
+@@ -3052,7 +3077,7 @@ gtk_scrolled_window_adjustment_value_changed (GtkAdjustment *adjustment,
+            adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)))
+     priv->unclamped_hadj_value = gtk_adjustment_get_value (adjustment);
+
+-  if (overlay_scrollbars)
++  if (priv->overlay_scrollbars)
+     gtk_scrolled_window_start_fade_in_animation (scrolled_window);
+ }
+
+@@ -3083,7 +3108,7 @@ gtk_scrolled_window_add (GtkContainer *container,
+     g_warning ("gtk_scrolled_window_add(): cannot add non scrollable widget "
+              "use gtk_scrolled_window_add_with_viewport() instead");
+
+-  if (overlay_scrollbars)
++  if (priv->overlay_scrollbars)
+     {
+       g_signal_connect_after (child, "expose-event",
+                               G_CALLBACK (gtk_scrolled_window_child_expose),
+@@ -3095,11 +3120,15 @@ static void
+ gtk_scrolled_window_remove (GtkContainer *container,
+                           GtkWidget    *child)
+ {
++  GtkScrolledWindowPrivate *priv;
++
+   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
+   g_return_if_fail (child != NULL);
+   g_return_if_fail (GTK_BIN (container)->child == child);
+
+-  if (overlay_scrollbars)
++  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (container);
++
++  if (priv->overlay_scrollbars)
+     {
+       g_signal_handlers_disconnect_by_func (child,
+                                             gtk_scrolled_window_child_expose,
+@@ -3764,5 +3793,23 @@ gtk_scrolled_window_expose_scrollbars (GtkAdjustment     *adj,
+     }
+ }
+
++static void
++gtk_scrolled_window_overlay_scrollbars_changed (GtkSettings *settings,
++                                                GParamSpec  *arg,
++                                                gpointer     user_data)
++{
++  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (user_data);
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (user_data);
++
++  /* FIXME: tear down/set up things to make the switch */
++
++  g_object_get (settings,
++                "gtk-enable-overlay-scrollbars",
++                &priv->overlay_scrollbars,
++                NULL);
++
++  g_print ("enable-overlay-scrollbar is now: %d\n", priv->overlay_scrollbars);
++}
++
+ #define __GTK_SCROLLED_WINDOW_C__
+ #include "gtkaliasdef.c"
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0016-gtk-correctly-handle-toggling-of-the-scrollbar-visib.patch b/bockbuild/mac-sdk/patches/gtk/0016-gtk-correctly-handle-toggling-of-the-scrollbar-visib.patch
new file mode 100644 (file)
index 0000000..d53385f
--- /dev/null
@@ -0,0 +1,386 @@
+From 8d10b09aff0bc03c54c2f1899900cc062f36ad4b Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Thu, 16 Aug 2012 09:35:53 +0200
+Subject: [PATCH 16/68] gtk: correctly handle toggling of the scrollbar
+ visibility setting
+
+By doing most things unconditionally, like connecting to signals
+and creating the opacity adjustment. Queue a resize when the
+setting changes so things get recalculated properly, and make
+sure the scrollbars get expose events if they are visible.
+Unrelated: don't leak the priv->opacity adjustment.
+---
+ gtk/gtkscrolledwindow.c |  244 +++++++++++++++++++++++------------------------
+ 1 file changed, 119 insertions(+), 125 deletions(-)
+
+diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
+index 3220e91..7680f5d 100644
+--- a/gtk/gtkscrolledwindow.c
++++ b/gtk/gtkscrolledwindow.c
+@@ -529,29 +529,25 @@ gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
+                     G_CALLBACK (gtk_scrolled_window_overlay_scrollbars_changed),
+                     scrolled_window);
+
+-  if (g_getenv ("GTK2_KINETIC_SCROLLING"))
+-    {
+-      gtk_scrolled_window_set_kinetic_scrolling (scrolled_window, TRUE);
+-      gtk_scrolled_window_set_capture_button_press (scrolled_window, TRUE);
+-    }
+-
+-  if (priv->overlay_scrollbars)
+-    {
+-      priv->opacity = g_object_new (GTK_TYPE_ADJUSTMENT,
+-                                    "lower", 0.0,
+-                                    "upper", 0.5,
+-                                    "value", 0.0,
+-                                    NULL);
+-      priv->sb_min_height = 20;
+-      priv->sb_padding = 2;
+-      priv->sb_radius = 3;
+-      priv->sb_width = 6;
+-      priv->sb_fade_out_delay = 1000;
+-
+-      g_signal_connect (priv->opacity, "value-changed",
+-                        G_CALLBACK (gtk_scrolled_window_expose_scrollbars),
+-                        scrolled_window);
+-    }
++  gtk_scrolled_window_set_kinetic_scrolling (scrolled_window, TRUE);
++  gtk_scrolled_window_set_capture_button_press (scrolled_window, TRUE);
++
++  priv->opacity = g_object_new (GTK_TYPE_ADJUSTMENT,
++                                "lower", 0.0,
++                                "upper", 0.5,
++                                "value", 0.0,
++                                NULL);
++  g_object_ref_sink (priv->opacity);
++
++  priv->sb_min_height = 20;
++  priv->sb_padding = 2;
++  priv->sb_radius = 3;
++  priv->sb_width = 6;
++  priv->sb_fade_out_delay = 1000;
++
++  g_signal_connect (priv->opacity, "value-changed",
++                    G_CALLBACK (gtk_scrolled_window_expose_scrollbars),
++                    scrolled_window);
+ }
+
+ /**
+@@ -632,16 +628,12 @@ gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
+       g_signal_handlers_disconnect_by_func (old_adjustment,
+                                           gtk_scrolled_window_adjustment_changed,
+                                           scrolled_window);
+-
+-      if (priv->overlay_scrollbars)
+-        {
+-          g_signal_handlers_disconnect_by_func (old_adjustment,
+-                                                gtk_scrolled_window_adjustment_value_changed,
+-                                                scrolled_window);
+-          g_signal_handlers_disconnect_by_func (old_adjustment,
+-                                                gtk_scrolled_window_expose_scrollbars,
+-                                                scrolled_window);
+-        }
++      g_signal_handlers_disconnect_by_func (old_adjustment,
++                                            gtk_scrolled_window_adjustment_value_changed,
++                                            scrolled_window);
++      g_signal_handlers_disconnect_by_func (old_adjustment,
++                                            gtk_scrolled_window_expose_scrollbars,
++                                            scrolled_window);
+
+       gtk_range_set_adjustment (GTK_RANGE (scrolled_window->hscrollbar),
+                               hadjustment);
+@@ -658,19 +650,18 @@ gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
+   gtk_scrolled_window_adjustment_changed (hadjustment, scrolled_window);
+   gtk_scrolled_window_adjustment_value_changed (hadjustment, scrolled_window);
+
+-  if (priv->overlay_scrollbars)
+-    {
+-      g_signal_connect (hadjustment, "value-changed",
+-                        G_CALLBACK (gtk_scrolled_window_adjustment_value_changed),
+-                        scrolled_window);
++#if 0
++  g_signal_connect (hadjustment, "value-changed",
++                    G_CALLBACK (gtk_scrolled_window_adjustment_value_changed),
++                    scrolled_window);
++#endif
+
+-      g_signal_connect (hadjustment, "changed",
+-                        G_CALLBACK (gtk_scrolled_window_expose_scrollbars),
+-                        scrolled_window);
+-      g_signal_connect (hadjustment, "value-changed",
+-                        G_CALLBACK (gtk_scrolled_window_expose_scrollbars),
+-                        scrolled_window);
+-    }
++  g_signal_connect (hadjustment, "changed",
++                    G_CALLBACK (gtk_scrolled_window_expose_scrollbars),
++                    scrolled_window);
++  g_signal_connect (hadjustment, "value-changed",
++                    G_CALLBACK (gtk_scrolled_window_expose_scrollbars),
++                    scrolled_window);
+
+   if (bin->child)
+     gtk_widget_set_scroll_adjustments (bin->child,
+@@ -725,16 +716,12 @@ gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
+       g_signal_handlers_disconnect_by_func (old_adjustment,
+                                           gtk_scrolled_window_adjustment_changed,
+                                           scrolled_window);
+-
+-      if (priv->overlay_scrollbars)
+-        {
+-          g_signal_handlers_disconnect_by_func (old_adjustment,
+-                                                gtk_scrolled_window_adjustment_value_changed,
+-                                                scrolled_window);
+-          g_signal_handlers_disconnect_by_func (old_adjustment,
+-                                                gtk_scrolled_window_expose_scrollbars,
+-                                                scrolled_window);
+-        }
++      g_signal_handlers_disconnect_by_func (old_adjustment,
++                                            gtk_scrolled_window_adjustment_value_changed,
++                                            scrolled_window);
++      g_signal_handlers_disconnect_by_func (old_adjustment,
++                                            gtk_scrolled_window_expose_scrollbars,
++                                            scrolled_window);
+
+       gtk_range_set_adjustment (GTK_RANGE (scrolled_window->vscrollbar),
+                               vadjustment);
+@@ -751,20 +738,19 @@ gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
+   gtk_scrolled_window_adjustment_changed (vadjustment, scrolled_window);
+   gtk_scrolled_window_adjustment_value_changed (vadjustment, scrolled_window);
+
+-  if (priv->overlay_scrollbars)
+-    {
+-      g_signal_connect (vadjustment,
+-                        "value-changed",
+-                        G_CALLBACK (gtk_scrolled_window_adjustment_value_changed),
+-                        scrolled_window);
++#if 0
++  g_signal_connect (vadjustment,
++                    "value-changed",
++                    G_CALLBACK (gtk_scrolled_window_adjustment_value_changed),
++                    scrolled_window);
++#endif
+
+-      g_signal_connect (vadjustment, "changed",
+-                        G_CALLBACK (gtk_scrolled_window_expose_scrollbars),
+-                        scrolled_window);
+-      g_signal_connect (vadjustment, "value-changed",
+-                        G_CALLBACK (gtk_scrolled_window_expose_scrollbars),
+-                        scrolled_window);
+-    }
++  g_signal_connect (vadjustment, "changed",
++                    G_CALLBACK (gtk_scrolled_window_expose_scrollbars),
++                    scrolled_window);
++  g_signal_connect (vadjustment, "value-changed",
++                    G_CALLBACK (gtk_scrolled_window_expose_scrollbars),
++                    scrolled_window);
+
+   if (bin->child)
+     gtk_widget_set_scroll_adjustments (bin->child,
+@@ -1224,16 +1210,12 @@ gtk_scrolled_window_destroy (GtkObject *object)
+       g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
+                                           gtk_scrolled_window_adjustment_changed,
+                                           scrolled_window);
+-
+-      if (priv->overlay_scrollbars)
+-        {
+-          g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
+-                                                gtk_scrolled_window_adjustment_value_changed,
+-                                                scrolled_window);
+-          g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
+-                                                gtk_scrolled_window_expose_scrollbars,
+-                                                scrolled_window);
+-        }
++      g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
++                                            gtk_scrolled_window_adjustment_value_changed,
++                                            scrolled_window);
++      g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
++                                            gtk_scrolled_window_expose_scrollbars,
++                                            scrolled_window);
+
+       gtk_widget_unparent (scrolled_window->hscrollbar);
+       gtk_widget_destroy (scrolled_window->hscrollbar);
+@@ -1245,16 +1227,12 @@ gtk_scrolled_window_destroy (GtkObject *object)
+       g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)),
+                                           gtk_scrolled_window_adjustment_changed,
+                                           scrolled_window);
+-
+-      if (priv->overlay_scrollbars)
+-        {
+-          g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)),
+-                                                gtk_scrolled_window_adjustment_value_changed,
+-                                                scrolled_window);
+-          g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)),
+-                                                gtk_scrolled_window_expose_scrollbars,
+-                                                scrolled_window);
+-        }
++      g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)),
++                                            gtk_scrolled_window_adjustment_value_changed,
++                                            scrolled_window);
++      g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)),
++                                            gtk_scrolled_window_expose_scrollbars,
++                                            scrolled_window);
+
+       gtk_widget_unparent (scrolled_window->vscrollbar);
+       gtk_widget_destroy (scrolled_window->vscrollbar);
+@@ -1283,6 +1261,12 @@ gtk_scrolled_window_destroy (GtkObject *object)
+       priv->button_press_event = NULL;
+     }
+
++  if (priv->opacity)
++    {
++      g_object_unref (priv->opacity);
++      priv->opacity = NULL;
++    }
++
+   GTK_OBJECT_CLASS (gtk_scrolled_window_parent_class)->destroy (object);
+ }
+
+@@ -1482,11 +1466,23 @@ static gboolean
+ gtk_scrolled_window_expose (GtkWidget      *widget,
+                           GdkEventExpose *event)
+ {
++  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
+   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (widget);
+
+   if (gtk_widget_is_drawable (widget))
+     {
+-      if (event->window == priv->overshoot_window)
++      GdkWindow *hscrollbar_window = NULL;
++      GdkWindow *vscrollbar_window = NULL;
++
++      if (scrolled_window->hscrollbar)
++        hscrollbar_window = gtk_widget_get_window (scrolled_window->hscrollbar);
++
++      if (scrolled_window->vscrollbar)
++        vscrollbar_window = gtk_widget_get_window (scrolled_window->vscrollbar);
++
++      if (event->window == priv->overshoot_window ||
++          event->window == hscrollbar_window ||
++          event->window == vscrollbar_window)
+         GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->expose_event (widget, event);
+       else
+         gtk_scrolled_window_paint (widget, &event->area);
+@@ -1935,8 +1931,7 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
+   priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+   bin = GTK_BIN (scrolled_window);
+
+-  if (priv->overlay_scrollbars)
+-    gtk_scrolled_window_expose_scrollbars (NULL, scrolled_window);
++  gtk_scrolled_window_expose_scrollbars (NULL, scrolled_window);
+
+   scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
+   gtk_widget_style_get (widget, "scrollbars-within-bevel", &scrollbars_within_bevel, NULL);
+@@ -3108,12 +3103,9 @@ gtk_scrolled_window_add (GtkContainer *container,
+     g_warning ("gtk_scrolled_window_add(): cannot add non scrollable widget "
+              "use gtk_scrolled_window_add_with_viewport() instead");
+
+-  if (priv->overlay_scrollbars)
+-    {
+-      g_signal_connect_after (child, "expose-event",
+-                              G_CALLBACK (gtk_scrolled_window_child_expose),
+-                              container);
+-    }
++  g_signal_connect_after (child, "expose-event",
++                          G_CALLBACK (gtk_scrolled_window_child_expose),
++                          container);
+ }
+
+ static void
+@@ -3128,12 +3120,9 @@ gtk_scrolled_window_remove (GtkContainer *container,
+
+   priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (container);
+
+-  if (priv->overlay_scrollbars)
+-    {
+-      g_signal_handlers_disconnect_by_func (child,
+-                                            gtk_scrolled_window_child_expose,
+-                                            container);
+-    }
++  g_signal_handlers_disconnect_by_func (child,
++                                        gtk_scrolled_window_child_expose,
++                                        container);
+
+   gtk_widget_set_scroll_adjustments (child, NULL, NULL);
+
+@@ -3624,6 +3613,9 @@ gtk_scrolled_window_child_expose (GtkWidget         *widget,
+    GdkRectangle hslider_rect;
+    cairo_t   *cr;
+
++   if (!priv->overlay_scrollbars)
++     return FALSE;
++
+    cr = gdk_cairo_create (eevent->window);
+    gdk_cairo_region (cr, eevent->region);
+    cairo_clip (cr);
+@@ -3769,27 +3761,32 @@ static void
+ gtk_scrolled_window_expose_scrollbars (GtkAdjustment     *adj,
+                                        GtkScrolledWindow *scrolled_window)
+ {
+-  GtkWidget *child = gtk_bin_get_child (GTK_BIN (scrolled_window));
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+
+-  if (child && gtk_widget_get_visible (child))
++  if (priv->overlay_scrollbars)
+     {
+-      GtkAllocation alloc;
+-
+-      gtk_widget_get_allocation (child, &alloc);
+-
+-      if (scrolled_window->vscrollbar)
+-        gtk_widget_queue_draw_area (child,
+-                                    alloc.width - 20,
+-                                    0,
+-                                    20,
+-                                    alloc.height);
++      GtkWidget *child = gtk_bin_get_child (GTK_BIN (scrolled_window));
+
+-      if (scrolled_window->hscrollbar)
+-        gtk_widget_queue_draw_area (child,
+-                                    0,
+-                                    alloc.height - 20,
+-                                    alloc.width,
+-                                    20);
++      if (child && gtk_widget_get_visible (child))
++        {
++          GtkAllocation alloc;
++
++          gtk_widget_get_allocation (child, &alloc);
++
++          if (scrolled_window->vscrollbar)
++            gtk_widget_queue_draw_area (child,
++                                        alloc.width - 20,
++                                        0,
++                                        20,
++                                        alloc.height);
++
++          if (scrolled_window->hscrollbar)
++            gtk_widget_queue_draw_area (child,
++                                        0,
++                                        alloc.height - 20,
++                                        alloc.width,
++                                        20);
++        }
+     }
+ }
+
+@@ -3798,17 +3795,14 @@ gtk_scrolled_window_overlay_scrollbars_changed (GtkSettings *settings,
+                                                 GParamSpec  *arg,
+                                                 gpointer     user_data)
+ {
+-  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (user_data);
+   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (user_data);
+
+-  /* FIXME: tear down/set up things to make the switch */
+-
+   g_object_get (settings,
+                 "gtk-enable-overlay-scrollbars",
+                 &priv->overlay_scrollbars,
+                 NULL);
+
+-  g_print ("enable-overlay-scrollbar is now: %d\n", priv->overlay_scrollbars);
++  gtk_widget_queue_resize (user_data);
+ }
+
+ #define __GTK_SCROLLED_WINDOW_C__
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0017-gtk-handle-gtk-primary-button-warps-slider-for-the-o.patch b/bockbuild/mac-sdk/patches/gtk/0017-gtk-handle-gtk-primary-button-warps-slider-for-the-o.patch
new file mode 100644 (file)
index 0000000..0844eed
--- /dev/null
@@ -0,0 +1,69 @@
+From f2c762968b02b73323a75a723ad664ff1645abde Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Fri, 31 Aug 2012 16:24:07 +0200
+Subject: [PATCH 17/68] gtk: handle gtk-primary-button-warps-slider for the
+ overlay scrollbars
+
+---
+ gtk/gtkscrolledwindow.c |   38 +++++++++++++++++++++++++++++++++-----
+ 1 file changed, 33 insertions(+), 5 deletions(-)
+
+diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
+index 7680f5d..02745b1 100644
+--- a/gtk/gtkscrolledwindow.c
++++ b/gtk/gtkscrolledwindow.c
+@@ -2725,6 +2725,10 @@ gtk_scrolled_window_scroll_step_timeout (gpointer data)
+ }
+
+ static gboolean
++gtk_scrolled_window_captured_motion_notify_scrollbar (GtkWidget *widget,
++                                                      GdkEvent  *event);
++
++static gboolean
+ gtk_scrolled_window_captured_button_press_scrollbar (GtkWidget *widget,
+                                                      GdkEvent  *event)
+ {
+@@ -2808,12 +2812,36 @@ gtk_scrolled_window_captured_button_press_scrollbar (GtkWidget *widget,
+       if ((priv->sb_grab_vscroll || priv->sb_grab_hscroll) &&
+           !priv->sb_drag_slider)
+         {
+-          gtk_scrolled_window_scroll_step (scrolled_window);
++          gboolean primary_warps;
++
++          g_object_get (gtk_widget_get_settings (widget),
++                        "gtk-primary-button-warps-slider", &primary_warps,
++                        NULL);
++
++          if (primary_warps)
++            {
++              GdkEventMotion mevent = { 0, };
++
++              priv->sb_drag_slider = TRUE;
++              priv->sb_grab_offset_x = hslider_rect.width / 2;
++              priv->sb_grab_offset_y = vslider_rect.height / 2;
++
++              mevent.window = bevent->window;
++              mevent.x = bevent->x;
++              mevent.y = bevent->y;
+
+-          priv->sb_scroll_timeout_id =
+-            gdk_threads_add_timeout (SCROLL_INTERVAL_INITIAL,
+-                                     gtk_scrolled_window_scroll_step_timeout,
+-                                     scrolled_window);
++              gtk_scrolled_window_captured_motion_notify_scrollbar (widget,
++                                                                    (GdkEvent *) &mevent);
++            }
++          else
++            {
++              gtk_scrolled_window_scroll_step (scrolled_window);
++
++              priv->sb_scroll_timeout_id =
++                gdk_threads_add_timeout (SCROLL_INTERVAL_INITIAL,
++                                         gtk_scrolled_window_scroll_step_timeout,
++                                         scrolled_window);
++            }
+         }
+
+       return TRUE;
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0018-Introduce-phase-field-in-GdkEventScroll.patch b/bockbuild/mac-sdk/patches/gtk/0018-Introduce-phase-field-in-GdkEventScroll.patch
new file mode 100644 (file)
index 0000000..40be941
--- /dev/null
@@ -0,0 +1,166 @@
+From 4ef417938760f98e530c152ee50071da2af31b06 Mon Sep 17 00:00:00 2001
+From: Kristian Rietveld <kris@lanedo.com>
+Date: Sun, 2 Sep 2012 14:16:45 +0200
+Subject: [PATCH 18/68] Introduce phase field in GdkEventScroll
+
+Using the phase field it is possible to distinguish between
+events generated while the user is performing a gesture and
+momentum events that are generated after the gesture has been
+finished.
+---
+ gdk/gdkevents.c               |    1 +
+ gdk/gdkevents.h               |    9 +++++++++
+ gdk/gdkwindow.c               |    1 +
+ gdk/quartz/gdkevents-quartz.c |   36 +++++++++++++++++++++++++++++++++---
+ 4 files changed, 44 insertions(+), 3 deletions(-)
+
+diff --git a/gdk/gdkevents.c b/gdk/gdkevents.c
+index 0f8bba2..d3d67db 100644
+--- a/gdk/gdkevents.c
++++ b/gdk/gdkevents.c
+@@ -394,6 +394,7 @@ gdk_event_new (GdkEventType type)
+       new_event->scroll.y_root = 0.;
+       new_event->scroll.delta_x = 0.;
+       new_event->scroll.delta_y = 0.;
++      new_event->scroll.phase = GDK_EVENT_SCROLL_PHASE_NONE;
+       break;
+     case GDK_ENTER_NOTIFY:
+     case GDK_LEAVE_NOTIFY:
+diff --git a/gdk/gdkevents.h b/gdk/gdkevents.h
+index f6b4e04..765b520 100644
+--- a/gdk/gdkevents.h
++++ b/gdk/gdkevents.h
+@@ -263,6 +263,14 @@ typedef enum
+   GDK_OWNER_CHANGE_CLOSE
+ } GdkOwnerChange;
+
++typedef enum
++{
++  GDK_EVENT_SCROLL_PHASE_NONE,
++  GDK_EVENT_SCROLL_PHASE_START,
++  GDK_EVENT_SCROLL_PHASE_ACTIVE,
++  GDK_EVENT_SCROLL_PHASE_END
++} GdkEventScrollPhase;
++
+ struct _GdkEventAny
+ {
+   GdkEventType type;
+@@ -340,6 +348,7 @@ struct _GdkEventScroll
+   gboolean has_deltas;
+   gdouble delta_x;
+   gdouble delta_y;
++  GdkEventScrollPhase phase;
+ };
+
+ struct _GdkEventKey
+diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
+index d48751e..1843873 100644
+--- a/gdk/gdkwindow.c
++++ b/gdk/gdkwindow.c
+@@ -10803,6 +10803,7 @@ proxy_button_event (GdkEvent *source_event,
+       event->scroll.has_deltas = source_event->scroll.has_deltas;
+       event->scroll.delta_x = source_event->scroll.delta_x;
+       event->scroll.delta_y = source_event->scroll.delta_y;
++      event->scroll.phase = source_event->scroll.phase;
+       return TRUE;
+
+     default:
+diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
+index e7d97dc..bb4da70 100644
+--- a/gdk/quartz/gdkevents-quartz.c
++++ b/gdk/quartz/gdkevents-quartz.c
+@@ -62,6 +62,7 @@ static GdkWindow *find_toplevel_under_pointer   (GdkDisplay *display,
+ - (BOOL) hasPreciseScrollingDeltas;
+ - (CGFloat) scrollingDeltaX;
+ - (CGFloat) scrollingDeltaY;
++- (int) phase;
+ @end
+
+
+@@ -990,6 +991,7 @@ fill_scroll_event (GdkWindow          *window,
+                    gboolean            has_deltas,
+                    gdouble             delta_x,
+                    gdouble             delta_y,
++                   GdkEventScrollPhase phase,
+                    GdkScrollDirection  direction)
+ {
+   GdkWindowObject *private;
+@@ -1012,6 +1014,7 @@ fill_scroll_event (GdkWindow          *window,
+   event->scroll.has_deltas = has_deltas;
+   event->scroll.delta_x = delta_x;
+   event->scroll.delta_y = delta_y;
++  event->scroll.phase = phase;
+ }
+
+ static void
+@@ -1300,6 +1303,28 @@ test_resize (NSEvent *event, GdkWindow *toplevel, gint x, gint y)
+   return FALSE;
+ }
+
++static GdkEventScrollPhase
++gdk_event_scroll_phase_from_ns_event_phase (NSUInteger phase)
++{
++  switch (phase)
++    {
++      case 0:
++        return GDK_EVENT_SCROLL_PHASE_NONE;
++
++      case 1 << 0:
++        return GDK_EVENT_SCROLL_PHASE_START;
++
++      case 1 << 1:
++      case 1 << 2:
++        return GDK_EVENT_SCROLL_PHASE_ACTIVE;
++
++      case 1 << 3:
++        return GDK_EVENT_SCROLL_PHASE_END;
++    }
++
++  return GDK_EVENT_SCROLL_PHASE_NONE;
++}
++
+ static gboolean
+ gdk_event_translate (GdkEvent *event,
+                      NSEvent  *nsevent)
+@@ -1491,6 +1516,7 @@ gdk_event_translate (GdkEvent *event,
+       if (gdk_quartz_osx_version() >= GDK_OSX_LION &&
+           [(id <PreciseDeltas>) nsevent hasPreciseScrollingDeltas])
+         {
++            GdkEventScrollPhase phase;
+           dx = [(id <PreciseDeltas>) nsevent scrollingDeltaX];
+           dy = [(id <PreciseDeltas>) nsevent scrollingDeltaY];
+
+@@ -1509,8 +1535,10 @@ gdk_event_translate (GdkEvent *event,
+                   direction = GDK_SCROLL_LEFT;
+               }
+
++            phase = gdk_event_scroll_phase_from_ns_event_phase ([(id <PreciseDeltas>) nsevent phase]);
++
+             fill_scroll_event (window, event, nsevent, x, y, x_root, y_root,
+-                               TRUE, -dx, -dy, direction);
++                               TRUE, -dx, -dy, phase, direction);
+         }
+       else
+         {
+@@ -1525,7 +1553,8 @@ gdk_event_translate (GdkEvent *event,
+                   direction = GDK_SCROLL_UP;
+
+                 fill_scroll_event (window, event, nsevent, x, y, x_root, y_root,
+-                                   FALSE, 0.0, fabs (dy), direction);
++                                   FALSE, 0.0, fabs (dy), GDK_EVENT_SCROLL_PHASE_NONE,
++                                   direction);
+               }
+             else if (dx != 0.0)
+               {
+@@ -1535,7 +1564,8 @@ gdk_event_translate (GdkEvent *event,
+                   direction = GDK_SCROLL_LEFT;
+
+                 fill_scroll_event (window, event, nsevent, x, y, x_root, y_root,
+-                                   FALSE, fabs (dx), 0.0, direction);
++                                   FALSE, fabs (dx), 0.0, GDK_EVENT_SCROLL_PHASE_NONE,
++                                   direction);
+               }
+           }
+       }
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0019-Add-hack-to-lock-flow-of-scroll-events-to-window-whe.patch b/bockbuild/mac-sdk/patches/gtk/0019-Add-hack-to-lock-flow-of-scroll-events-to-window-whe.patch
new file mode 100644 (file)
index 0000000..edf5b8d
--- /dev/null
@@ -0,0 +1,144 @@
+From 026f9bc1846eae8fa98a307975fedce1f61d9cd5 Mon Sep 17 00:00:00 2001
+From: Kristian Rietveld <kris@lanedo.com>
+Date: Fri, 28 Sep 2012 08:24:05 +0200
+Subject: [PATCH 19/68] Add hack to lock flow of scroll events to window where
+ scroll started
+
+A bit evil but there is probably no other way, because this is very
+different from GDK's usual behavior.
+
+There's one quirk left, if you start a scroll and move to another GTK+
+window in the same process and click, the click won't be processed until
+the folow of momentum events has ended.
+---
+ gdk/gdkwindow.c |   94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 94 insertions(+)
+
+diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
+index 1843873..1dac543 100644
+--- a/gdk/gdkwindow.c
++++ b/gdk/gdkwindow.c
+@@ -434,6 +434,10 @@ accumulate_get_window (GSignalInvocationHint *ihint,
+ }
+
+ static GQuark quark_pointer_window = 0;
++#ifdef GDK_WINDOWING_QUARTZ
++static GQuark quark_last_scroll_pointer_window = 0;
++static GQuark quark_last_scroll_event_window = 0;
++#endif /* GDK_WINDOWING_QUARTZ */
+
+ static void
+ gdk_window_class_init (GdkWindowObjectClass *klass)
+@@ -478,6 +482,12 @@ gdk_window_class_init (GdkWindowObjectClass *klass)
+   drawable_class->get_source_drawable = gdk_window_get_source_drawable;
+
+   quark_pointer_window = g_quark_from_static_string ("gtk-pointer-window");
++#ifdef GDK_WINDOWING_QUARTZ
++  quark_last_scroll_pointer_window =
++      g_quark_from_static_string ("gtk-last-scroll-pointer-window");
++  quark_last_scroll_event_window =
++      g_quark_from_static_string ("gtk-last-scroll-event-window");
++#endif /* GDK_WINDOWING_QUARTZ */
+
+
+   /* Properties */
+@@ -10702,6 +10712,64 @@ proxy_pointer_event (GdkDisplay                 *display,
+                            GDK_BUTTON4_MASK | \
+                            GDK_BUTTON5_MASK)
+
++#ifdef GDK_WINDOWING_QUARTZ
++static void
++last_scroll_event_weak_ref_notify (gpointer  data,
++                                   GObject  *where_the_object_was)
++{
++  /* If any of pointer_window or event_window is destroyed, we unset
++   * both values in the display's qdata.
++   */
++  GdkDisplay *display = data;
++
++  g_object_set_qdata (G_OBJECT (display), quark_last_scroll_pointer_window,
++                      NULL);
++  g_object_set_qdata (G_OBJECT (display), quark_last_scroll_event_window,
++                      NULL);
++}
++
++static void
++set_last_scroll_event_windows (GdkDisplay *display,
++                               GdkWindow  *pointer_window,
++                               GdkWindow  *event_window)
++{
++  GdkWindow *old_window;
++
++  /* Check whether the values are still set from a previous scroll,
++   * if so we need to release the weak references. (If they are no
++   * longer set, we assume the weak ref notify callback was called).
++   */
++  old_window = g_object_get_qdata (G_OBJECT (display),
++                                   quark_last_scroll_pointer_window);
++  if (old_window)
++    g_object_weak_unref (G_OBJECT (old_window),
++                         last_scroll_event_weak_ref_notify, display);
++
++  old_window = g_object_get_qdata (G_OBJECT (display),
++                                   quark_last_scroll_event_window);
++  if (old_window)
++    g_object_weak_unref (G_OBJECT (old_window),
++                         last_scroll_event_weak_ref_notify, display);
++
++  /* Set new values and setup weak references. Note that pointer_window
++   * and event_window can be NULL, in which case GDK won't proxy the
++   * event. In this case we store NULL into the qdata so that we won't
++   * store the scroll event.
++   */
++  g_object_set_qdata (G_OBJECT (display), quark_last_scroll_pointer_window,
++                      pointer_window);
++  if (pointer_window)
++    g_object_weak_ref (G_OBJECT (pointer_window),
++                       last_scroll_event_weak_ref_notify, display);
++
++  g_object_set_qdata (G_OBJECT (display), quark_last_scroll_event_window,
++                      event_window);
++  if (event_window)
++    g_object_weak_ref (G_OBJECT (event_window),
++                       last_scroll_event_weak_ref_notify, display);
++}
++#endif /* GDK_WINDOWING_QUARTZ */
++
+ static gboolean
+ proxy_button_event (GdkEvent *source_event,
+                   gulong serial)
+@@ -10769,6 +10837,32 @@ proxy_button_event (GdkEvent *source_event,
+                               type, state,
+                               NULL, serial);
+
++#ifdef GDK_WINDOWING_QUARTZ
++  /* A Quartz-specific hack we cannot handle from within the backend
++   * unfortunately. For scroll events with precise deltas (i.e. these
++   * generated by the Mac touchpad or Magic Mouse, we want to lock the
++   * flow of events belonging to a single gesture to the window the
++   * gesture was started on. The default behavior of GDK, which insists
++   * to send events to the window under the pointer or discard the
++   * events when there's no GDK window under the pointer, makes it
++   * impossible to implement this differently.
++   */
++  if (type == GDK_SCROLL && source_event->scroll.has_deltas)
++    {
++      if (source_event->scroll.phase == GDK_EVENT_SCROLL_PHASE_START)
++        {
++          set_last_scroll_event_windows (display, pointer_window, event_win);
++        }
++      else
++        {
++          pointer_window = g_object_get_qdata (G_OBJECT (display),
++                                               quark_last_scroll_pointer_window);
++          event_win = g_object_get_qdata (G_OBJECT (display),
++                                          quark_last_scroll_event_window);
++        }
++    }
++#endif /* GDK_WINDOWING_QUARTZ */
++
+   if (event_win == NULL || display->ignore_core_events)
+     return TRUE;
+
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0020-Introduce-a-background-window.patch b/bockbuild/mac-sdk/patches/gtk/0020-Introduce-a-background-window.patch
new file mode 100644 (file)
index 0000000..4a1f763
--- /dev/null
@@ -0,0 +1,189 @@
+From 69e85305f2d455c8943514edde215ce69791076a Mon Sep 17 00:00:00 2001
+From: Kristian Rietveld <kris@lanedo.com>
+Date: Sun, 2 Sep 2012 21:21:51 +0200
+Subject: [PATCH 20/68] Introduce a background window
+
+The background window covers the part left uncovered by the overshoot
+window. Two background windows are used to be able to cover an "L shape"
+that appears when is scrolled in the horizontal and vertical direction
+at the same time. These background windows are used to capture events,
+such as scroll events. In the future, it could also be used to draw a
+specific background pattern/gradient (if the window is configured as
+INPUT/OUTPUT window).
+---
+ gtk/gtkscrolledwindow.c |  104 +++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 104 insertions(+)
+
+diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
+index 02745b1..9d0d87a 100644
+--- a/gtk/gtkscrolledwindow.c
++++ b/gtk/gtkscrolledwindow.c
+@@ -95,6 +95,8 @@ typedef struct {
+   /* Kinetic scrolling */
+   GdkEvent              *button_press_event;
+   GdkWindow             *overshoot_window;
++  GdkWindow             *vbackground_window;
++  GdkWindow             *hbackground_window;
+   guint                  pointer_grabbed           : 1;
+   guint                  kinetic_scrolling         : 1;
+   guint                  capture_button_press      : 1;
+@@ -1481,6 +1483,8 @@ gtk_scrolled_window_expose (GtkWidget      *widget,
+         vscrollbar_window = gtk_widget_get_window (scrolled_window->vscrollbar);
+
+       if (event->window == priv->overshoot_window ||
++          event->window == priv->vbackground_window ||
++          event->window == priv->hbackground_window ||
+           event->window == hscrollbar_window ||
+           event->window == vscrollbar_window)
+         GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->expose_event (widget, event);
+@@ -1871,6 +1875,7 @@ _gtk_scrolled_window_allocate_overshoot_window (GtkScrolledWindow *scrolled_wind
+   _gtk_scrolled_window_get_overshoot (scrolled_window,
+                                       &overshoot_x, &overshoot_y);
+
++  /* Overshoot window */
+   window_allocation = relative_allocation;
+   window_allocation.x += allocation.x;
+   window_allocation.y += allocation.y;
+@@ -1887,6 +1892,46 @@ _gtk_scrolled_window_allocate_overshoot_window (GtkScrolledWindow *scrolled_wind
+   gdk_window_move_resize (priv->overshoot_window,
+                           window_allocation.x, window_allocation.y,
+                           window_allocation.width, window_allocation.height);
++
++  /* Vertical background window */
++  window_allocation = relative_allocation;
++  window_allocation.x += allocation.x;
++  window_allocation.y += allocation.y;
++
++  if (ABS (overshoot_x) > 0)
++    {
++      window_allocation.width = ABS (overshoot_x);
++      if (overshoot_x > 0)
++        window_allocation.x += relative_allocation.width - overshoot_x;
++
++      gdk_window_move_resize (priv->vbackground_window,
++                              window_allocation.x, window_allocation.y,
++                              window_allocation.width,
++                              window_allocation.height);
++      gdk_window_show (priv->vbackground_window);
++    }
++  else
++    gdk_window_hide (priv->vbackground_window);
++
++  /* Horizontal background window */
++  window_allocation = relative_allocation;
++  window_allocation.x += allocation.x;
++  window_allocation.y += allocation.y;
++
++  if (ABS (overshoot_y) > 0)
++    {
++      window_allocation.height = ABS (overshoot_y);
++      if (overshoot_y > 0)
++        window_allocation.y += relative_allocation.height - overshoot_y;
++
++      gdk_window_move_resize (priv->hbackground_window,
++                              window_allocation.x, window_allocation.y,
++                              window_allocation.width,
++                              window_allocation.height);
++      gdk_window_show (priv->hbackground_window);
++    }
++  else
++    gdk_window_hide (priv->hbackground_window);
+ }
+
+ static void
+@@ -3259,6 +3304,7 @@ gtk_scrolled_window_realize (GtkWidget *widget)
+   gtk_widget_get_allocation (widget, &allocation);
+   gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
+
++  /* Overshoot window */
+   attributes.window_type = GDK_WINDOW_CHILD;
+   attributes.x = allocation.x + relative_allocation.x;
+   attributes.y = allocation.y + relative_allocation.y;
+@@ -3277,6 +3323,45 @@ gtk_scrolled_window_realize (GtkWidget *widget)
+
+   gdk_window_set_user_data (priv->overshoot_window, widget);
+
++  /* Vertical background window */
++  attributes.window_type = GDK_WINDOW_CHILD;
++  attributes.x = allocation.x + relative_allocation.x;
++  attributes.y = allocation.y + relative_allocation.y;
++  attributes.width = 0;
++  attributes.height = 0;
++  attributes.wclass = GDK_INPUT_ONLY;
++  attributes.visual = gtk_widget_get_visual (widget);
++  attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK |
++    GDK_BUTTON_MOTION_MASK | GDK_SCROLL_MASK;
++
++  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
++
++  priv->vbackground_window =
++    gdk_window_new (gtk_widget_get_parent_window (widget),
++                    &attributes, attributes_mask);
++
++  gdk_window_set_user_data (priv->vbackground_window, widget);
++
++  /* Horizontal background window */
++  attributes.window_type = GDK_WINDOW_CHILD;
++  attributes.x = allocation.x + relative_allocation.x;
++  attributes.y = allocation.y + relative_allocation.y;
++  attributes.width = 0;
++  attributes.height = 0;
++  attributes.wclass = GDK_INPUT_ONLY;
++  attributes.visual = gtk_widget_get_visual (widget);
++  attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK |
++    GDK_BUTTON_MOTION_MASK | GDK_SCROLL_MASK;
++
++  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
++
++  priv->hbackground_window =
++    gdk_window_new (gtk_widget_get_parent_window (widget),
++                    &attributes, attributes_mask);
++
++  gdk_window_set_user_data (priv->hbackground_window, widget);
++
++
+   child_widget = gtk_bin_get_child (GTK_BIN (widget));
+
+   if (child_widget)
+@@ -3296,6 +3381,14 @@ gtk_scrolled_window_unrealize (GtkWidget *widget)
+   gdk_window_destroy (priv->overshoot_window);
+   priv->overshoot_window = NULL;
+
++  gdk_window_set_user_data (priv->vbackground_window, NULL);
++  gdk_window_destroy (priv->vbackground_window);
++  priv->vbackground_window = NULL;
++
++  gdk_window_set_user_data (priv->hbackground_window, NULL);
++  gdk_window_destroy (priv->hbackground_window);
++  priv->hbackground_window = NULL;
++
+   gtk_widget_set_realized (widget, FALSE);
+
+   GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->unrealize (widget);
+@@ -3308,6 +3401,15 @@ gtk_scrolled_window_map (GtkWidget *widget)
+   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+
+   gdk_window_show (priv->overshoot_window);
++  if (gdk_window_get_width (priv->vbackground_window) > 1)
++    gdk_window_show (priv->vbackground_window);
++  else
++    gdk_window_hide (priv->vbackground_window);
++
++  if (gdk_window_get_height (priv->hbackground_window) > 1)
++    gdk_window_show (priv->hbackground_window);
++  else
++    gdk_window_hide (priv->hbackground_window);
+
+   GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->map (widget);
+ }
+@@ -3319,6 +3421,8 @@ gtk_scrolled_window_unmap (GtkWidget *widget)
+   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+
+   gdk_window_hide (priv->overshoot_window);
++  gdk_window_hide (priv->vbackground_window);
++  gdk_window_hide (priv->hbackground_window);
+
+   GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->unmap (widget);
+ }
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0021-Make-scrolled-window-work-well-with-Mac-touchpad.patch b/bockbuild/mac-sdk/patches/gtk/0021-Make-scrolled-window-work-well-with-Mac-touchpad.patch
new file mode 100644 (file)
index 0000000..1bd84e6
--- /dev/null
@@ -0,0 +1,870 @@
+From 79c1e789097b4e46b9f3fdcbc96a2aae69e24144 Mon Sep 17 00:00:00 2001
+From: Kristian Rietveld <kris@lanedo.com>
+Date: Mon, 3 Sep 2012 10:45:13 +0200
+Subject: [PATCH 21/68] Make scrolled window work well with Mac touchpad
+
+Modify the scrolled window code to work with a Mac touchpad as you
+would expect. When precise deltas are received from the Mac touchpad,
+overshooting and snapping back will work. The existing kinetic scrolling
+code is only used for snapping back. The amount of pixels to overshoot
+is determined by the incoming scroll events from the touchpad. We use
+the deceleration mechanism that was already in place to snap back.
+
+Other changes made are:
+ - Increased the kinetic scrolling distance, this makes things feel
+ nicer IMHO.
+ - Removed everything related to handling kinetic scrolling by making
+ drag gestures. We don't need this code.
+---
+ gtk/gtkscrolledwindow.c |  680 +++++++++++------------------------------------
+ 1 file changed, 157 insertions(+), 523 deletions(-)
+
+diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
+index 9d0d87a..5341b50 100644
+--- a/gtk/gtkscrolledwindow.c
++++ b/gtk/gtkscrolledwindow.c
+@@ -79,7 +79,7 @@
+
+ /* Kinetic scrolling */
+ #define FRAME_INTERVAL (1000 / 60)
+-#define MAX_OVERSHOOT_DISTANCE 50
++#define MAX_OVERSHOOT_DISTANCE 100
+ #define FRICTION_DECELERATION 0.003
+ #define OVERSHOOT_INVERSE_ACCELERATION 0.003
+ #define RELEASE_EVENT_TIMEOUT 1000
+@@ -98,20 +98,11 @@ typedef struct {
+   GdkWindow             *vbackground_window;
+   GdkWindow             *hbackground_window;
+   guint                  pointer_grabbed           : 1;
+-  guint                  kinetic_scrolling         : 1;
+-  guint                  capture_button_press      : 1;
+   guint                  in_drag                   : 1;
+-  guint                  last_button_event_valid   : 1;
+
+-  guint                  release_timeout_id;
+   guint                  deceleration_id;
+
+-  gdouble                last_button_event_x_root;
+-  gdouble                last_button_event_y_root;
+-
+-  gdouble                last_motion_event_x_root;
+-  gdouble                last_motion_event_y_root;
+-  guint32                last_motion_event_time;
++  guint32                last_scroll_event_time;
+
+   gdouble                x_velocity;
+   gdouble                y_velocity;
+@@ -144,6 +135,7 @@ typedef struct {
+   guint          sb_scroll_timeout_id;
+
+   gboolean       overlay_scrollbars;
++  gboolean       is_snapping_back;
+ } GtkScrolledWindowPrivate;
+
+ #define GTK_SCROLLED_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_SCROLLED_WINDOW, GtkScrolledWindowPrivate))
+@@ -167,8 +159,7 @@ enum {
+   PROP_VSCROLLBAR_POLICY,
+   PROP_WINDOW_PLACEMENT,
+   PROP_WINDOW_PLACEMENT_SET,
+-  PROP_SHADOW_TYPE,
+-  PROP_KINETIC_SCROLLING
++  PROP_SHADOW_TYPE
+ };
+
+ /* Signals */
+@@ -268,6 +259,13 @@ static void gtk_scrolled_window_overlay_scrollbars_changed (GtkSettings *setting
+                                                             GParamSpec  *arg,
+                                                             gpointer     user_data);
+
++
++static void gtk_scrolled_window_start_deceleration      (GtkScrolledWindow *scrolled_window);
++static gboolean gtk_scrolled_window_calculate_velocity  (GtkScrolledWindow *scrolled_window,
++                                                         GdkEvent          *event);
++static void gtk_scrolled_window_init_overlay_scrollbars (GtkScrolledWindow *window);
++
++
+ static guint signals[LAST_SIGNAL] = {0};
+
+ G_DEFINE_TYPE (GtkScrolledWindow, gtk_scrolled_window, GTK_TYPE_BIN)
+@@ -432,22 +430,6 @@ gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
+                                                            GTK_PARAM_READABLE));
+
+   /**
+-   * GtkScrolledWindow:kinetic-scrolling:
+-   *
+-   * The kinetic scrolling behavior flags.
+-   *
+-   * Since: X.XX
+-   */
+-  g_object_class_install_property (gobject_class,
+-                                   PROP_KINETIC_SCROLLING,
+-                                   g_param_spec_boolean ("kinetic-scrolling",
+-                                                         P_("Kinetic Scrolling"),
+-                                                         P_("Kinetic scrolling mode."),
+-                                                         TRUE,
+-                                                         GTK_PARAM_READABLE |
+-                                                         GTK_PARAM_WRITABLE));
+-
+-  /**
+    * GtkScrolledWindow::scroll-child:
+    * @scrolled_window: a #GtkScrolledWindow
+    * @scroll: a #GtkScrollType describing how much to scroll
+@@ -531,8 +513,7 @@ gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
+                     G_CALLBACK (gtk_scrolled_window_overlay_scrollbars_changed),
+                     scrolled_window);
+
+-  gtk_scrolled_window_set_kinetic_scrolling (scrolled_window, TRUE);
+-  gtk_scrolled_window_set_capture_button_press (scrolled_window, TRUE);
++  gtk_scrolled_window_init_overlay_scrollbars (scrolled_window);
+
+   priv->opacity = g_object_new (GTK_TYPE_ADJUSTMENT,
+                                 "lower", 0.0,
+@@ -1075,130 +1056,6 @@ gtk_scrolled_window_get_shadow_type (GtkScrolledWindow *scrolled_window)
+   return scrolled_window->shadow_type;
+ }
+
+-/**
+- * gtk_scrolled_window_set_kinetic_scrolling:
+- * @scrolled_window: a #GtkScrolledWindow
+- * @kinetic_scrolling: %TRUE to enable kinetic scrolling
+- *
+- * Turns kinetic scrolling on or off.
+- * Kinetic scrolling only applies to devices with source
+- * %GDK_SOURCE_TOUCHSCREEN.
+- *
+- * Since: X.XX
+- **/
+-void
+-gtk_scrolled_window_set_kinetic_scrolling (GtkScrolledWindow *scrolled_window,
+-                                           gboolean           kinetic_scrolling)
+-{
+-  GtkScrolledWindowPrivate *priv;
+-
+-  g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
+-
+-  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+-
+-  if (priv->kinetic_scrolling == kinetic_scrolling)
+-    return;
+-
+-  priv->kinetic_scrolling = kinetic_scrolling;
+-  if (priv->kinetic_scrolling)
+-    {
+-      _gtk_widget_set_captured_event_handler (GTK_WIDGET (scrolled_window),
+-                                              gtk_scrolled_window_captured_event);
+-    }
+-  else
+-    {
+-      _gtk_widget_set_captured_event_handler (GTK_WIDGET (scrolled_window), NULL);
+-      if (priv->release_timeout_id)
+-        {
+-          g_source_remove (priv->release_timeout_id);
+-          priv->release_timeout_id = 0;
+-        }
+-      if (priv->deceleration_id)
+-        {
+-          g_source_remove (priv->deceleration_id);
+-          priv->deceleration_id = 0;
+-        }
+-    }
+-  g_object_notify (G_OBJECT (scrolled_window), "kinetic-scrolling");
+-}
+-
+-/**
+- * gtk_scrolled_window_get_kinetic_scrolling:
+- * @scrolled_window: a #GtkScrolledWindow
+- *
+- * Returns the specified kinetic scrolling behavior.
+- *
+- * Return value: the scrolling behavior flags.
+- *
+- * Since: X.XX
+- */
+-gboolean
+-gtk_scrolled_window_get_kinetic_scrolling (GtkScrolledWindow *scrolled_window)
+-{
+-  GtkScrolledWindowPrivate *priv;
+-
+-  g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), FALSE);
+-
+-  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+-
+-  return priv->kinetic_scrolling;
+-}
+-
+-/**
+- * gtk_scrolled_window_set_capture_button_press:
+- * @scrolled_window: a #GtkScrolledWindow
+- * @capture_button_press: %TRUE to capture button presses
+- *
+- * Changes the behaviour of @scrolled_window wrt. to the initial
+- * event that possibly starts kinetic scrolling. When @capture_button_press
+- * is set to %TRUE, the event is captured by the scrolled window, and
+- * then later replayed if it is meant to go to the child widget.
+- *
+- * This should be enabled if any child widgets perform non-reversible
+- * actions on #GtkWidget::button-press-event. If they don't, and handle
+- * additionally handle #GtkWidget::grab-broken-event, it might be better
+- * to set @capture_button_press to %FALSE.
+- *
+- * This setting only has an effect if kinetic scrolling is enabled.
+- *
+- * Since: X.XX
+- */
+-void
+-gtk_scrolled_window_set_capture_button_press (GtkScrolledWindow *scrolled_window,
+-                                              gboolean           capture_button_press)
+-{
+-  GtkScrolledWindowPrivate *priv;
+-
+-  g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
+-
+-  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+-  priv->capture_button_press = capture_button_press;
+-}
+-
+-/**
+- * gtk_scrolled_window_get_capture_button_press:
+- * @scrolled_window: a #GtkScrolledWindow
+- *
+- * Return whether button presses are captured during kinetic
+- * scrolling. See gtk_scrolled_window_set_capture_button_press().
+- *
+- * Returns: %TRUE if button presses are captured during kinetic scrolling
+- *
+- * Since: X.XX
+- */
+-gboolean
+-gtk_scrolled_window_get_capture_button_press (GtkScrolledWindow *scrolled_window)
+-{
+-  GtkScrolledWindowPrivate *priv;
+-
+-  g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), FALSE);
+-
+-  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+-
+-  return priv->capture_button_press;
+-}
+-
+-
+ static void
+ gtk_scrolled_window_destroy (GtkObject *object)
+ {
+@@ -1246,11 +1103,6 @@ gtk_scrolled_window_destroy (GtkObject *object)
+                                         G_CALLBACK (gtk_scrolled_window_overlay_scrollbars_changed),
+                                         scrolled_window);
+
+-  if (priv->release_timeout_id)
+-    {
+-      g_source_remove (priv->release_timeout_id);
+-      priv->release_timeout_id = 0;
+-    }
+   if (priv->deceleration_id)
+     {
+       g_source_remove (priv->deceleration_id);
+@@ -1313,10 +1165,6 @@ gtk_scrolled_window_set_property (GObject      *object,
+       gtk_scrolled_window_set_shadow_type (scrolled_window,
+                                          g_value_get_enum (value));
+       break;
+-    case PROP_KINETIC_SCROLLING:
+-      gtk_scrolled_window_set_kinetic_scrolling (scrolled_window,
+-                                                 g_value_get_boolean (value));
+-      break;
+     default:
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       break;
+@@ -1357,9 +1205,6 @@ gtk_scrolled_window_get_property (GObject    *object,
+     case PROP_SHADOW_TYPE:
+       g_value_set_enum (value, scrolled_window->shadow_type);
+       break;
+-    case PROP_KINETIC_SCROLLING:
+-      g_value_set_boolean (value, priv->kinetic_scrolling);
+-      break;
+     default:
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       break;
+@@ -2152,40 +1997,146 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+
+   if (gdk_event_get_scroll_deltas ((GdkEvent *) event, &delta_x, &delta_y))
+     {
+-      if (delta_x != 0.0 && scrolled_window->hscrollbar &&
+-          (priv->overlay_scrollbars || gtk_widget_get_visible (scrolled_window->hscrollbar)))
++      gint new_overshoot_x, new_overshoot_y;
++      gint old_overshoot_x, old_overshoot_y;
++      gboolean start_snap_back = FALSE;
++      gboolean is_overshot = FALSE;
++      gboolean is_momentum_event = event->phase == GDK_EVENT_SCROLL_PHASE_NONE;
++
++      _gtk_scrolled_window_get_overshoot (scrolled_window,
++                                          &old_overshoot_x, &old_overshoot_y);
++
++      /* Check if the view is currently overshot. */
++      if (old_overshoot_x != 0 || old_overshoot_y != 0)
++        is_overshot = TRUE;
++
++      /* In case the view is not overshot, no snap back is active
++       * and this event is not a momentum event, then a new scrolling
++       * gesture has started. In case we are still in snapping back
++       * state we can reset this (because the snapback has ended).
++       */
++      if (!is_overshot && priv->deceleration_id == 0 && !is_momentum_event)
++        priv->is_snapping_back = FALSE;
++
++      /* Scroll events are handled in two cases:
++       *  1) We are not overshot and not snapping back, so scroll as
++       *  usual and also handle momentum events.
++       *  2) If the view is currently overshot, then do not handle
++       *  momentum events but handle non-momentum events as usual.
++       *
++       * For both cases we only allow overshooting in a direction if
++       * that particular scrollbar is actually visible.
++       */
++      if ((!is_overshot && !priv->is_snapping_back) ||
++          (is_overshot && !is_momentum_event))
+         {
+-          GtkAdjustment *adj;
+-          gdouble new_value;
++          if (delta_x != 0.0 && scrolled_window->hscrollbar &&
++              (priv->overlay_scrollbars || gtk_widget_get_visible (scrolled_window->hscrollbar)))
++            {
++              GtkAdjustment *adj;
+
+-          adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
++              adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
+
+-          new_value = CLAMP (gtk_adjustment_get_value (adj) + delta_x,
+-                             gtk_adjustment_get_lower (adj),
+-                             gtk_adjustment_get_upper (adj) -
+-                             gtk_adjustment_get_page_size (adj));
++              if (scrolled_window->hscrollbar_visible)
++                {
++                  _gtk_scrolled_window_set_adjustment_value (scrolled_window,
++                                                             adj,
++                                                             priv->unclamped_hadj_value + delta_x,
++                                                             TRUE,
++                                                             FALSE);
++                }
++              else
++                {
++                  gdouble new_value;
+
+-          gtk_adjustment_set_value (adj, new_value);
++                  /* If the scrollbar is not visible, clamp the value and
++                   * don't trigger overshooting.
++                   */
++                  new_value = CLAMP (gtk_adjustment_get_value (adj) + delta_x,
++                                     gtk_adjustment_get_lower (adj),
++                                     gtk_adjustment_get_upper (adj) -
++                                     gtk_adjustment_get_page_size (adj));
+
+-          handled = TRUE;
++                  gtk_adjustment_set_value (adj, new_value);
++                }
++
++              handled = TRUE;
++            }
++
++          if (delta_y != 0.0 && scrolled_window->vscrollbar &&
++              (priv->overlay_scrollbars || gtk_widget_get_visible (scrolled_window->vscrollbar)))
++            {
++              GtkAdjustment *adj;
++
++              adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
++
++              if (scrolled_window->vscrollbar_visible)
++                {
++                  _gtk_scrolled_window_set_adjustment_value (scrolled_window,
++                                                             adj,
++                                                             priv->unclamped_vadj_value + delta_y,
++                                                             TRUE,
++                                                             FALSE);
++                }
++              else
++                {
++                  gdouble new_value;
++
++                  /* If the scrollbar is not visible, clamp the value and
++                   * don't trigger overshooting.
++                   */
++                  new_value = CLAMP (gtk_adjustment_get_value (adj) + delta_y,
++                                     gtk_adjustment_get_lower (adj),
++                                     gtk_adjustment_get_upper (adj) -
++                                     gtk_adjustment_get_page_size (adj));
++
++                  gtk_adjustment_set_value (adj, new_value);
++                }
++
++              handled = TRUE;
++            }
++
++
++          priv->last_scroll_event_time = gdk_event_get_time ((GdkEvent *)event);
++          gtk_scrolled_window_calculate_velocity (scrolled_window, (GdkEvent *)event);
+         }
+
+-      if (delta_y != 0.0 && scrolled_window->vscrollbar &&
+-          (priv->overlay_scrollbars || gtk_widget_get_visible (scrolled_window->vscrollbar)))
+-        {
+-          GtkAdjustment *adj;
+-          gdouble new_value;
++      _gtk_scrolled_window_get_overshoot (scrolled_window,
++                                          &new_overshoot_x, &new_overshoot_y);
+
+-          adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
++      if (old_overshoot_x != new_overshoot_x ||
++          old_overshoot_y != new_overshoot_y)
++        _gtk_scrolled_window_allocate_overshoot_window (scrolled_window);
+
+-          new_value = CLAMP (gtk_adjustment_get_value (adj) + delta_y,
+-                             gtk_adjustment_get_lower (adj),
+-                             gtk_adjustment_get_upper (adj) -
+-                             gtk_adjustment_get_page_size (adj));
++      /* In two cases we want to start snapping back:
++       *  1) The view is overshot and the gesture has ended (signalled
++       *  by an event with both deltas set to zero.
++       *  2) The view is overshot and we receive a momentum event, which
++       *  also signals that the user's gesture has ended.
++       */
++      if (is_overshot &&
++          ((delta_x == 0.0 && delta_y == 0.0) || is_momentum_event))
++        start_snap_back = TRUE;
+
+-          gtk_adjustment_set_value (adj, new_value);
++      /* If we should start a snap back and no current deceleration
++       * is active, start the snap back.
++       */
++      if (start_snap_back && priv->deceleration_id == 0)
++        {
++          /* Zero out vector components without a visible scrollbar */
++          if (!scrolled_window->hscrollbar_visible)
++            priv->x_velocity = 0;
++          if (!scrolled_window->vscrollbar_visible)
++            priv->y_velocity = 0;
+
+-          handled = TRUE;
++          priv->is_snapping_back = TRUE;
++
++          if (new_overshoot_x != 0 || new_overshoot_y != 0)
++            {
++              gtk_scrolled_window_start_deceleration (scrolled_window);
++              priv->x_velocity = 0.0;
++              priv->y_velocity = 0.0;
++            }
+         }
+     }
+   else
+@@ -2369,18 +2320,6 @@ scrolled_window_deceleration_cb (gpointer user_data)
+ }
+
+ static void
+-gtk_scrolled_window_cancel_deceleration (GtkScrolledWindow *scrolled_window)
+-{
+-  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+-
+-  if (priv->deceleration_id)
+-    {
+-      g_source_remove (priv->deceleration_id);
+-      priv->deceleration_id = 0;
+-    }
+-}
+-
+-static void
+ gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
+ {
+   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+@@ -2408,327 +2347,36 @@ gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
+ }
+
+ static gboolean
+-gtk_scrolled_window_release_captured_event (GtkScrolledWindow *scrolled_window)
+-{
+-  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+-
+-  /* Cancel the scrolling and send the button press
+-   * event to the child widget
+-   */
+-  if (!priv->button_press_event)
+-    return FALSE;
+-
+-  if (priv->pointer_grabbed)
+-    {
+-      gtk_grab_remove (GTK_WIDGET (scrolled_window));
+-      priv->pointer_grabbed = FALSE;
+-    }
+-
+-  if (priv->capture_button_press)
+-    {
+-      GtkWidget *event_widget;
+-
+-      event_widget = gtk_get_event_widget (priv->button_press_event);
+-
+-      if (!_gtk_propagate_captured_event (event_widget,
+-                                          priv->button_press_event,
+-                                          gtk_bin_get_child (GTK_BIN (scrolled_window))))
+-        gtk_propagate_event (event_widget, priv->button_press_event);
+-
+-      gdk_event_free (priv->button_press_event);
+-      priv->button_press_event = NULL;
+-    }
+-
+-  if (_gtk_scrolled_window_get_overshoot (scrolled_window, NULL, NULL))
+-    gtk_scrolled_window_start_deceleration (scrolled_window);
+-
+-  return FALSE;
+-}
+-
+-static gboolean
+ gtk_scrolled_window_calculate_velocity (GtkScrolledWindow *scrolled_window,
+                                       GdkEvent          *event)
+ {
+   GtkScrolledWindowPrivate *priv;
+-  gdouble x_root, y_root;
+   guint32 _time;
+
+-#define STILL_THRESHOLD 40
+-
+-  if (!gdk_event_get_root_coords (event, &x_root, &y_root))
+-    return FALSE;
+-
+   priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+   _time = gdk_event_get_time (event);
+
+-  if (priv->last_motion_event_x_root != x_root ||
+-      priv->last_motion_event_y_root != y_root ||
+-      ABS (_time - priv->last_motion_event_time) > STILL_THRESHOLD)
+-    {
+-      priv->x_velocity = (priv->last_motion_event_x_root - x_root) /
+-        (gdouble) (_time - priv->last_motion_event_time);
+-      priv->y_velocity = (priv->last_motion_event_y_root - y_root) /
+-        (gdouble) (_time - priv->last_motion_event_time);
+-    }
+-
+-  priv->last_motion_event_x_root = x_root;
+-  priv->last_motion_event_y_root = y_root;
+-  priv->last_motion_event_time = _time;
+-
+-#undef STILL_THRESHOLD
+-
+-  return TRUE;
+-}
+-
+-static gboolean
+-gtk_scrolled_window_captured_button_release_kinetic (GtkWidget *widget,
+-                                                     GdkEvent  *event)
+-{
+-  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
+-  GtkScrolledWindowPrivate *priv;
+-  GtkWidget *child;
+-  gboolean overshoot;
+-  gdouble x_root, y_root;
+-
+-  if (event->button.button != 1)
+-    return FALSE;
+-
+-  child = gtk_bin_get_child (GTK_BIN (widget));
+-  if (!child)
+-    return FALSE;
+-
+-  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+-  gtk_grab_remove (widget);
+-  priv->pointer_grabbed = FALSE;
+-
+-  if (priv->release_timeout_id)
+-    {
+-      g_source_remove (priv->release_timeout_id);
+-      priv->release_timeout_id = 0;
+-    }
+-
+-  overshoot = _gtk_scrolled_window_get_overshoot (scrolled_window, NULL, NULL);
+-
+-  if (priv->in_drag)
+-    gdk_pointer_ungrab (gdk_event_get_time (event));
+-  else
+-    {
+-      /* There hasn't been scrolling at all, so just let the
+-       * child widget handle the button press normally
+-       */
+-      gtk_scrolled_window_release_captured_event (scrolled_window);
+-
+-      if (!overshoot)
+-        return FALSE;
+-    }
+-  priv->in_drag = FALSE;
+-
+-  if (priv->button_press_event)
+-    {
+-      gdk_event_free (priv->button_press_event);
+-      priv->button_press_event = NULL;
+-    }
+-
+-  gtk_scrolled_window_calculate_velocity (scrolled_window, event);
+-
+-  /* Zero out vector components without a visible scrollbar */
+-  if (!scrolled_window->hscrollbar_visible)
+-    priv->x_velocity = 0;
+-  if (!scrolled_window->vscrollbar_visible)
+-    priv->y_velocity = 0;
++#define STILL_THRESHOLD 40
+
+-  if (priv->x_velocity != 0 || priv->y_velocity != 0 || overshoot)
++  if (event->type == GDK_SCROLL)
+     {
+-      gtk_scrolled_window_start_deceleration (scrolled_window);
+-      priv->x_velocity = priv->y_velocity = 0;
+-      priv->last_button_event_valid = FALSE;
+-    }
+-  else
+-    {
+-      gdk_event_get_root_coords (event, &x_root, &y_root);
+-      priv->last_button_event_x_root = x_root;
+-      priv->last_button_event_y_root = y_root;
+-      priv->last_button_event_valid = TRUE;
+-    }
+-
+-  if (priv->capture_button_press)
+-    return TRUE;
+-  else
+-    return FALSE;
+-}
++      gdouble delta_x, delta_y;
+
+-static gboolean
+-gtk_scrolled_window_captured_motion_notify_kinetic (GtkWidget *widget,
+-                                                    GdkEvent  *event)
+-{
+-  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
+-  GtkScrolledWindowPrivate *priv;
+-  gint old_overshoot_x, old_overshoot_y;
+-  gint new_overshoot_x, new_overshoot_y;
+-  GtkWidget *child;
+-  GtkAdjustment *hadjustment;
+-  GtkAdjustment *vadjustment;
+-  gdouble dx, dy;
+-  GdkModifierType state;
+-  gdouble x_root, y_root;
+-
+-  gdk_event_get_state (event, &state);
+-  if (!(state & GDK_BUTTON1_MASK))
+-    return FALSE;
+-
+-  child = gtk_bin_get_child (GTK_BIN (widget));
+-  if (!child)
+-    return FALSE;
+-
+-  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+-
+-  /* Check if we've passed the drag threshold */
+-  gdk_event_get_root_coords (event, &x_root, &y_root);
+-  if (!priv->in_drag)
+-    {
+-      if (gtk_drag_check_threshold (widget,
+-                                    priv->last_button_event_x_root,
+-                                    priv->last_button_event_y_root,
+-                                    x_root, y_root))
++      if (gdk_event_get_scroll_deltas (event, &delta_x, &delta_y) &&
++          ABS (_time - priv->last_scroll_event_time) > STILL_THRESHOLD)
+         {
+-          if (priv->release_timeout_id)
+-            {
+-              g_source_remove (priv->release_timeout_id);
+-              priv->release_timeout_id = 0;
+-            }
++          priv->x_velocity = delta_x / (gdouble) (_time - priv->last_scroll_event_time);
++          priv->y_velocity = delta_y / (gdouble) (_time - priv->last_scroll_event_time);
+
+-          priv->last_button_event_valid = FALSE;
+-          priv->in_drag = TRUE;
++          priv->last_scroll_event_time = _time;
+         }
+-      else
+-        return TRUE;
+-    }
+-
+-  gdk_pointer_grab (gtk_widget_get_window (widget),
+-                    TRUE,
+-                    GDK_BUTTON_RELEASE_MASK | GDK_BUTTON1_MOTION_MASK,
+-                    NULL, NULL,
+-                    gdk_event_get_time (event));
+-
+-  priv->last_button_event_valid = FALSE;
+-
+-  if (priv->button_press_event)
+-    {
+-      gdk_event_free (priv->button_press_event);
+-      priv->button_press_event = NULL;
+-    }
+-
+-  _gtk_scrolled_window_get_overshoot (scrolled_window,
+-                                      &old_overshoot_x, &old_overshoot_y);
+-
+-  hadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
+-  if (hadjustment && scrolled_window->hscrollbar_visible)
+-    {
+-      dx = (priv->last_motion_event_x_root - x_root) + priv->unclamped_hadj_value;
+-      _gtk_scrolled_window_set_adjustment_value (scrolled_window, hadjustment,
+-                                                 dx, TRUE, FALSE);
+-    }
+-
+-  vadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
+-  if (vadjustment && scrolled_window->vscrollbar_visible)
+-    {
+-      dy = (priv->last_motion_event_y_root - y_root) + priv->unclamped_vadj_value;
+-      _gtk_scrolled_window_set_adjustment_value (scrolled_window, vadjustment,
+-                                                 dy, TRUE, FALSE);
+     }
+
+-  _gtk_scrolled_window_get_overshoot (scrolled_window,
+-                                      &new_overshoot_x, &new_overshoot_y);
+-
+-  if (old_overshoot_x != new_overshoot_x ||
+-      old_overshoot_y != new_overshoot_y)
+-    _gtk_scrolled_window_allocate_overshoot_window (scrolled_window);
+-
+-  gtk_scrolled_window_calculate_velocity (scrolled_window, event);
++#undef STILL_THRESHOLD
+
+   return TRUE;
+ }
+
+-static gboolean
+-gtk_scrolled_window_captured_button_press_kinetic (GtkWidget *widget,
+-                                                   GdkEvent  *event)
+-{
+-  GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
+-  GtkScrolledWindowPrivate *priv;
+-  GtkWidget *child;
+-  GtkWidget *event_widget;
+-  gdouble x_root, y_root;
+-
+-  /* If scrollbars are not visible, we don't do kinetic scrolling */
+-  if (!scrolled_window->vscrollbar_visible &&
+-      !scrolled_window->hscrollbar_visible)
+-    return FALSE;
+-
+-  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+-
+-  event_widget = gtk_get_event_widget (event);
+-
+-  /* If there's another scrolled window between the widget
+-   * receiving the event and this capturing scrolled window,
+-   * let it handle the events.
+-   */
+-  if (widget != gtk_widget_get_ancestor (event_widget, GTK_TYPE_SCROLLED_WINDOW))
+-    return FALSE;
+-
+-  /* Check whether the button press is close to the previous one,
+-   * take that as a shortcut to get the child widget handle events
+-   */
+-  gdk_event_get_root_coords (event, &x_root, &y_root);
+-  if (priv->last_button_event_valid &&
+-      ABS (x_root - priv->last_button_event_x_root) < TOUCH_BYPASS_CAPTURED_THRESHOLD &&
+-      ABS (y_root - priv->last_button_event_y_root) < TOUCH_BYPASS_CAPTURED_THRESHOLD)
+-    {
+-      priv->last_button_event_valid = FALSE;
+-      return FALSE;
+-    }
+-
+-  priv->last_button_event_x_root = priv->last_motion_event_x_root = x_root;
+-  priv->last_button_event_y_root = priv->last_motion_event_y_root = y_root;
+-  priv->last_motion_event_time = gdk_event_get_time (event);
+-  priv->last_button_event_valid = TRUE;
+-
+-  if (event->button.button != 1)
+-    return FALSE;
+-
+-  child = gtk_bin_get_child (GTK_BIN (widget));
+-  if (!child)
+-    return FALSE;
+-
+-  if (scrolled_window->hscrollbar == event_widget ||
+-      scrolled_window->vscrollbar == event_widget)
+-    return FALSE;
+-
+-  priv->pointer_grabbed = TRUE;
+-  gtk_grab_add (widget);
+-
+-  gtk_scrolled_window_cancel_deceleration (scrolled_window);
+-
+-  /* Only set the timeout if we're going to store an event */
+-  if (priv->capture_button_press)
+-    priv->release_timeout_id =
+-      gdk_threads_add_timeout (RELEASE_EVENT_TIMEOUT,
+-                               (GSourceFunc) gtk_scrolled_window_release_captured_event,
+-                               scrolled_window);
+-
+-  priv->in_drag = FALSE;
+-
+-  if (priv->capture_button_press)
+-    {
+-      /* Store the button press event in
+-       * case we need to propagate it later
+-       */
+-      priv->button_press_event = gdk_event_copy (event);
+-      return TRUE;
+-    }
+-  else
+-    return FALSE;
+-}
+-
+ static void
+ gtk_scrolled_window_scroll_step (GtkScrolledWindow *scrolled_window)
+ {
+@@ -3011,22 +2659,14 @@ gtk_scrolled_window_captured_event (GtkWidget *widget,
+     {
+     case GDK_BUTTON_PRESS:
+       retval = gtk_scrolled_window_captured_button_press_scrollbar (widget, event);
+-      if (!retval)
+-        retval = gtk_scrolled_window_captured_button_press_kinetic (widget, event);
+       break;
+     case GDK_BUTTON_RELEASE:
+       if (priv->sb_pointer_grabbed)
+         retval = gtk_scrolled_window_captured_button_release_scrollbar (widget, event);
+-      else if (priv->pointer_grabbed)
+-        retval = gtk_scrolled_window_captured_button_release_kinetic (widget, event);
+-      else
+-        priv->last_button_event_valid = FALSE;
+       break;
+     case GDK_MOTION_NOTIFY:
+       if (priv->sb_pointer_grabbed || !priv->pointer_grabbed)
+         retval = gtk_scrolled_window_captured_motion_notify_scrollbar (widget, event);
+-      else if (priv->pointer_grabbed)
+-        retval = gtk_scrolled_window_captured_motion_notify_kinetic (widget, event);
+       break;
+     case GDK_LEAVE_NOTIFY:
+       if (!priv->in_drag && !priv->sb_pointer_grabbed)
+@@ -3439,19 +3079,6 @@ gtk_scrolled_window_grab_notify (GtkWidget *widget,
+       gdk_pointer_ungrab (gtk_get_current_event_time ());
+       priv->pointer_grabbed = FALSE;
+       priv->in_drag = FALSE;
+-
+-      if (priv->release_timeout_id)
+-        {
+-          g_source_remove (priv->release_timeout_id);
+-          priv->release_timeout_id = 0;
+-        }
+-
+-      if (_gtk_scrolled_window_get_overshoot (scrolled_window, NULL, NULL))
+-        gtk_scrolled_window_start_deceleration (scrolled_window);
+-      else
+-        gtk_scrolled_window_cancel_deceleration (scrolled_window);
+-
+-      priv->last_button_event_valid = FALSE;
+     }
+
+   if (priv->sb_pointer_grabbed && !was_grabbed)
+@@ -3923,6 +3550,13 @@ gtk_scrolled_window_expose_scrollbars (GtkAdjustment     *adj,
+ }
+
+ static void
++gtk_scrolled_window_init_overlay_scrollbars (GtkScrolledWindow *scrolled_window)
++{
++  _gtk_widget_set_captured_event_handler (GTK_WIDGET (scrolled_window),
++                                          gtk_scrolled_window_captured_event);
++}
++
++static void
+ gtk_scrolled_window_overlay_scrollbars_changed (GtkSettings *settings,
+                                                 GParamSpec  *arg,
+                                                 gpointer     user_data)
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0022-Use-start-end-phase-in-event-handling.patch b/bockbuild/mac-sdk/patches/gtk/0022-Use-start-end-phase-in-event-handling.patch
new file mode 100644 (file)
index 0000000..f09b1f0
--- /dev/null
@@ -0,0 +1,48 @@
+From a4e5fe549e5497a7e5ae7eecae4fc654330500f2 Mon Sep 17 00:00:00 2001
+From: Kristian Rietveld <kris@lanedo.com>
+Date: Fri, 28 Sep 2012 06:18:49 +0200
+Subject: [PATCH 22/68] Use start/end phase in event handling
+
+Should make things work better on Mountain Lion.
+---
+ gtk/gtkscrolledwindow.c |   13 +++++--------
+ 1 file changed, 5 insertions(+), 8 deletions(-)
+
+diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
+index 5341b50..92e75a0 100644
+--- a/gtk/gtkscrolledwindow.c
++++ b/gtk/gtkscrolledwindow.c
+@@ -2010,12 +2010,10 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+       if (old_overshoot_x != 0 || old_overshoot_y != 0)
+         is_overshot = TRUE;
+
+-      /* In case the view is not overshot, no snap back is active
+-       * and this event is not a momentum event, then a new scrolling
+-       * gesture has started. In case we are still in snapping back
+-       * state we can reset this (because the snapback has ended).
++      /* If a new gesture has started, reset snap back state.
++       * FIXME: check if overshoot has really ended.
+        */
+-      if (!is_overshot && priv->deceleration_id == 0 && !is_momentum_event)
++      if (event->phase == GDK_EVENT_SCROLL_PHASE_START)
+         priv->is_snapping_back = FALSE;
+
+       /* Scroll events are handled in two cases:
+@@ -2109,13 +2107,12 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+         _gtk_scrolled_window_allocate_overshoot_window (scrolled_window);
+
+       /* In two cases we want to start snapping back:
+-       *  1) The view is overshot and the gesture has ended (signalled
+-       *  by an event with both deltas set to zero.
++       *  1) The view is overshot and the gesture has ended.
+        *  2) The view is overshot and we receive a momentum event, which
+        *  also signals that the user's gesture has ended.
+        */
+       if (is_overshot &&
+-          ((delta_x == 0.0 && delta_y == 0.0) || is_momentum_event))
++          (event->phase == GDK_EVENT_SCROLL_PHASE_END || is_momentum_event))
+         start_snap_back = TRUE;
+
+       /* If we should start a snap back and no current deceleration
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0023-Improve-overshooting-behavior.patch b/bockbuild/mac-sdk/patches/gtk/0023-Improve-overshooting-behavior.patch
new file mode 100644 (file)
index 0000000..d04e295
--- /dev/null
@@ -0,0 +1,368 @@
+From ced3c2c63872021885cf91f134dde818096bae42 Mon Sep 17 00:00:00 2001
+From: Kristian Rietveld <kris@lanedo.com>
+Date: Wed, 19 Sep 2012 07:22:39 +0200
+Subject: [PATCH 23/68] Improve overshooting behavior
+
+This is done by taking the stiffness calculations as found in the WebKit
+source code. These calculations are now used to compute the overshooting
+distance as well as handling the snap back animation. Also, we only
+start overshooting after we have hit a border in the container (i.e. an
+adjustment has reached its upper/lower bound).
+
+Also rename the timeout functions from deceleration to snap back, since
+these are not handling kinetic deceleration in this code.
+---
+ gtk/gtkscrolledwindow.c |  179 ++++++++++++++++++++++++++---------------------
+ 1 file changed, 99 insertions(+), 80 deletions(-)
+
+diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
+index 92e75a0..f3be303 100644
+--- a/gtk/gtkscrolledwindow.c
++++ b/gtk/gtkscrolledwindow.c
+@@ -84,6 +84,10 @@
+ #define OVERSHOOT_INVERSE_ACCELERATION 0.003
+ #define RELEASE_EVENT_TIMEOUT 1000
+
++#define BAND_STIFFNESS 20.0f
++#define BAND_AMPLITUDE 0.31f
++#define BAND_PERIOD 1.6f
++
+ /* Overlay scrollbars */
+ #define SCROLL_INTERVAL_INITIAL 300
+ #define SCROLL_INTERVAL_REPEAT 100
+@@ -107,6 +111,9 @@ typedef struct {
+   gdouble                x_velocity;
+   gdouble                y_velocity;
+
++  gdouble                x_force;
++  gdouble                y_force;
++
+   gdouble                unclamped_hadj_value;
+   gdouble                unclamped_vadj_value;
+
+@@ -143,12 +150,13 @@ typedef struct {
+ typedef struct
+ {
+   GtkScrolledWindow     *scrolled_window;
+-  gint64                 last_deceleration_time;
++  gint64                 start_snap_back_time;
+
+   gdouble                x_velocity;
+   gdouble                y_velocity;
+-  gdouble                vel_cosine;
+-  gdouble                vel_sine;
++
++  gint                   x_overshoot;
++  gint                   y_overshoot;
+ } KineticScrollData;
+
+ enum {
+@@ -260,7 +268,7 @@ static void gtk_scrolled_window_overlay_scrollbars_changed (GtkSettings *setting
+                                                             gpointer     user_data);
+
+
+-static void gtk_scrolled_window_start_deceleration      (GtkScrolledWindow *scrolled_window);
++static void gtk_scrolled_window_start_snap_back         (GtkScrolledWindow *scrolled_window);
+ static gboolean gtk_scrolled_window_calculate_velocity  (GtkScrolledWindow *scrolled_window,
+                                                          GdkEvent          *event);
+ static void gtk_scrolled_window_init_overlay_scrollbars (GtkScrolledWindow *window);
+@@ -2016,6 +2024,9 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+       if (event->phase == GDK_EVENT_SCROLL_PHASE_START)
+         priv->is_snapping_back = FALSE;
+
++      if (is_momentum_event && !is_overshot)
++        gtk_scrolled_window_calculate_velocity (scrolled_window, (GdkEvent *)event);
++
+       /* Scroll events are handled in two cases:
+        *  1) We are not overshot and not snapping back, so scroll as
+        *  usual and also handle momentum events.
+@@ -2031,15 +2042,29 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+           if (delta_x != 0.0 && scrolled_window->hscrollbar &&
+               (priv->overlay_scrollbars || gtk_widget_get_visible (scrolled_window->hscrollbar)))
+             {
++              gboolean may_overshoot = FALSE;
+               GtkAdjustment *adj;
+
++              /* Overshooting is allowed once the adjustment has reached
++               * the left/right.
++               */
+               adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
++              gdouble max_adj = gtk_adjustment_get_upper (adj) - gtk_adjustment_get_page_size (adj);
++              if (gtk_adjustment_get_value (adj) < 1.0 ||
++                  gtk_adjustment_get_value (adj) > max_adj - 1.0)
++                may_overshoot = TRUE;
+
+-              if (scrolled_window->hscrollbar_visible)
++              if (scrolled_window->hscrollbar_visible && (is_overshot || may_overshoot))
+                 {
++                  gdouble damped_delta;
++
++                  priv->x_force += delta_x;
++                  damped_delta = ceil(priv->x_force / BAND_STIFFNESS);
++                  damped_delta = damped_delta - old_overshoot_x;
++
+                   _gtk_scrolled_window_set_adjustment_value (scrolled_window,
+                                                              adj,
+-                                                             priv->unclamped_hadj_value + delta_x,
++                                                             priv->unclamped_hadj_value + damped_delta,
+                                                              TRUE,
+                                                              FALSE);
+                 }
+@@ -2064,15 +2089,29 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+           if (delta_y != 0.0 && scrolled_window->vscrollbar &&
+               (priv->overlay_scrollbars || gtk_widget_get_visible (scrolled_window->vscrollbar)))
+             {
++              gboolean may_overshoot = FALSE;
+               GtkAdjustment *adj;
+
++              /* Overshooting is allowed once the adjustment has reached
++               * the top/bottom.
++               */
+               adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
++              gdouble max_adj = gtk_adjustment_get_upper (adj) - gtk_adjustment_get_page_size (adj);
++              if (gtk_adjustment_get_value (adj) < 1.0 ||
++                    gtk_adjustment_get_value (adj) > max_adj - 1.0)
++                may_overshoot = TRUE;
+
+-              if (scrolled_window->vscrollbar_visible)
++              if (scrolled_window->vscrollbar_visible && (is_overshot || may_overshoot))
+                 {
++                  gdouble damped_delta;
++
++                  priv->y_force += delta_y;
++                  damped_delta = ceil(priv->y_force / BAND_STIFFNESS);
++                  damped_delta = damped_delta - old_overshoot_y;
++
+                   _gtk_scrolled_window_set_adjustment_value (scrolled_window,
+                                                              adj,
+-                                                             priv->unclamped_vadj_value + delta_y,
++                                                             priv->unclamped_vadj_value + damped_delta,
+                                                              TRUE,
+                                                              FALSE);
+                 }
+@@ -2093,10 +2132,6 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+
+               handled = TRUE;
+             }
+-
+-
+-          priv->last_scroll_event_time = gdk_event_get_time ((GdkEvent *)event);
+-          gtk_scrolled_window_calculate_velocity (scrolled_window, (GdkEvent *)event);
+         }
+
+       _gtk_scrolled_window_get_overshoot (scrolled_window,
+@@ -2112,9 +2147,17 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+        *  also signals that the user's gesture has ended.
+        */
+       if (is_overshot &&
+-          (event->phase == GDK_EVENT_SCROLL_PHASE_END || is_momentum_event))
++          ((priv->last_scroll_event_time > 0 && is_momentum_event) ||
++           event->phase == GDK_EVENT_SCROLL_PHASE_END))
+         start_snap_back = TRUE;
+
++       /* Reset force if gesture has ended. */
++       if (event->phase == GDK_EVENT_SCROLL_PHASE_END)
++         {
++           priv->x_force = 0.0;
++           priv->y_force = 0.0;
++         }
++
+       /* If we should start a snap back and no current deceleration
+        * is active, start the snap back.
+        */
+@@ -2130,9 +2173,10 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+
+           if (new_overshoot_x != 0 || new_overshoot_y != 0)
+             {
+-              gtk_scrolled_window_start_deceleration (scrolled_window);
++              gtk_scrolled_window_start_snap_back (scrolled_window);
+               priv->x_velocity = 0.0;
+               priv->y_velocity = 0.0;
++              priv->last_scroll_event_time = 0;
+             }
+         }
+     }
+@@ -2207,16 +2251,16 @@ _gtk_scrolled_window_set_adjustment_value (GtkScrolledWindow *scrolled_window,
+ }
+
+ static gboolean
+-scrolled_window_deceleration_cb (gpointer user_data)
++scrolled_window_snap_back_cb (gpointer user_data)
+ {
+   KineticScrollData *data = user_data;
+   GtkScrolledWindow *scrolled_window = data->scrolled_window;
+   GtkScrolledWindowPrivate *priv;
+   GtkAdjustment *hadjustment, *vadjustment;
+   gint old_overshoot_x, old_overshoot_y, overshoot_x, overshoot_y;
+-  gdouble value;
+   gint64 current_time;
+-  guint elapsed;
++  gdouble elapsed;
++  gdouble damp_factor;
+
+   priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+   hadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
+@@ -2226,12 +2270,22 @@ scrolled_window_deceleration_cb (gpointer user_data)
+                                       &old_overshoot_x, &old_overshoot_y);
+
+   current_time = g_get_monotonic_time ();
+-  elapsed = (current_time - data->last_deceleration_time) / 1000;
+-  data->last_deceleration_time = current_time;
++  elapsed = (current_time - data->start_snap_back_time) / 1000000.0;
++  damp_factor = exp((((double)-elapsed) * BAND_STIFFNESS) / BAND_PERIOD);
+
+   if (hadjustment && scrolled_window->hscrollbar_visible)
+     {
+-      value = priv->unclamped_hadj_value + (data->x_velocity * elapsed);
++      gdouble delta_x, value;
++
++      delta_x = (data->x_overshoot + (data->x_velocity * elapsed * BAND_AMPLITUDE)) * damp_factor;
++
++      if (fabs (delta_x) >= 1.0)
++        value = priv->unclamped_hadj_value + (delta_x - old_overshoot_x);
++      else
++        value = CLAMP (priv->unclamped_hadj_value,
++                       gtk_adjustment_get_lower (hadjustment),
++                       gtk_adjustment_get_upper (hadjustment) -
++                       gtk_adjustment_get_page_size (hadjustment));
+
+       if (_gtk_scrolled_window_set_adjustment_value (scrolled_window,
+                                                      hadjustment,
+@@ -2243,7 +2297,17 @@ scrolled_window_deceleration_cb (gpointer user_data)
+
+   if (vadjustment && scrolled_window->vscrollbar_visible)
+     {
+-      value = priv->unclamped_vadj_value + (data->y_velocity * elapsed);
++      gdouble delta_y, value;
++
++      delta_y = (data->y_overshoot + (data->y_velocity * elapsed * BAND_AMPLITUDE)) * damp_factor;
++
++      if (fabs (delta_y) >= 1.0)
++        value = priv->unclamped_vadj_value + (delta_y - old_overshoot_y);
++      else
++        value = CLAMP (priv->unclamped_vadj_value,
++                       gtk_adjustment_get_lower (vadjustment),
++                       gtk_adjustment_get_upper (vadjustment) -
++                       gtk_adjustment_get_page_size (vadjustment));
+
+       if (_gtk_scrolled_window_set_adjustment_value (scrolled_window,
+                                                      vadjustment,
+@@ -2256,58 +2320,17 @@ scrolled_window_deceleration_cb (gpointer user_data)
+   _gtk_scrolled_window_get_overshoot (scrolled_window,
+                                       &overshoot_x, &overshoot_y);
+
+-  if (overshoot_x == 0)
+-    {
+-      if (old_overshoot_x != 0)
+-        {
+-          /* Overshooting finished snapping back */
+-          data->x_velocity = 0;
+-        }
+-      else if (data->x_velocity > 0)
+-        {
+-          data->x_velocity -= FRICTION_DECELERATION * elapsed * data->vel_sine;
+-          data->x_velocity = MAX (0, data->x_velocity);
+-        }
+-      else if (data->x_velocity < 0)
+-        {
+-          data->x_velocity += FRICTION_DECELERATION * elapsed * data->vel_sine;
+-          data->x_velocity = MIN (0, data->x_velocity);
+-        }
+-    }
+-  else if (overshoot_x < 0)
+-    data->x_velocity += OVERSHOOT_INVERSE_ACCELERATION * elapsed;
+-  else if (overshoot_x > 0)
+-    data->x_velocity -= OVERSHOOT_INVERSE_ACCELERATION * elapsed;
++  if (overshoot_x != 0)
++    priv->x_force = overshoot_x * BAND_STIFFNESS;
+
+-  if (overshoot_y == 0)
+-    {
+-      if (old_overshoot_y != 0)
+-        {
+-          /* Overshooting finished snapping back */
+-          data->y_velocity = 0;
+-        }
+-      else if (data->y_velocity > 0)
+-        {
+-          data->y_velocity -= FRICTION_DECELERATION * elapsed * data->vel_cosine;
+-          data->y_velocity = MAX (0, data->y_velocity);
+-        }
+-      else if (data->y_velocity < 0)
+-        {
+-          data->y_velocity += FRICTION_DECELERATION * elapsed * data->vel_cosine;
+-          data->y_velocity = MIN (0, data->y_velocity);
+-        }
+-    }
+-  else if (overshoot_y < 0)
+-    data->y_velocity += OVERSHOOT_INVERSE_ACCELERATION * elapsed;
+-  else if (overshoot_y > 0)
+-    data->y_velocity -= OVERSHOOT_INVERSE_ACCELERATION * elapsed;
++  if (overshoot_y != 0)
++    priv->y_force = overshoot_y * BAND_STIFFNESS;
+
+   if (old_overshoot_x != overshoot_x ||
+       old_overshoot_y != overshoot_y)
+     _gtk_scrolled_window_allocate_overshoot_window (scrolled_window);
+
+-  if (overshoot_x != 0 || overshoot_y != 0 ||
+-      data->x_velocity != 0 || data->y_velocity != 0)
++  if (overshoot_x != 0 || overshoot_y != 0)
+     return TRUE;
+   else
+     {
+@@ -2317,29 +2340,24 @@ scrolled_window_deceleration_cb (gpointer user_data)
+ }
+
+ static void
+-gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
++gtk_scrolled_window_start_snap_back (GtkScrolledWindow *scrolled_window)
+ {
+   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+   KineticScrollData *data;
+-  gdouble angle;
+
+   data = g_new0 (KineticScrollData, 1);
+   data->scrolled_window = scrolled_window;
+-  data->last_deceleration_time = g_get_monotonic_time ();
++  data->start_snap_back_time = g_get_monotonic_time ();
+   data->x_velocity = priv->x_velocity;
+   data->y_velocity = priv->y_velocity;
+-
+-  /* We use sine/cosine as a factor to deceleration x/y components
+-   * of the vector, so we care about the sign later.
+-   */
+-  angle = atan2 (ABS (data->x_velocity), ABS (data->y_velocity));
+-  data->vel_cosine = cos (angle);
+-  data->vel_sine = sin (angle);
++  _gtk_scrolled_window_get_overshoot (scrolled_window,
++                                      &data->x_overshoot,
++                                      &data->y_overshoot);
+
+   priv->deceleration_id =
+     gdk_threads_add_timeout_full (G_PRIORITY_DEFAULT,
+                                   FRAME_INTERVAL,
+-                                  scrolled_window_deceleration_cb,
++                                  scrolled_window_snap_back_cb,
+                                   data, (GDestroyNotify) g_free);
+ }
+
+@@ -2360,13 +2378,14 @@ gtk_scrolled_window_calculate_velocity (GtkScrolledWindow *scrolled_window,
+       gdouble delta_x, delta_y;
+
+       if (gdk_event_get_scroll_deltas (event, &delta_x, &delta_y) &&
++          priv->last_scroll_event_time > 0 &&
+           ABS (_time - priv->last_scroll_event_time) > STILL_THRESHOLD)
+         {
+           priv->x_velocity = delta_x / (gdouble) (_time - priv->last_scroll_event_time);
+           priv->y_velocity = delta_y / (gdouble) (_time - priv->last_scroll_event_time);
+-
+-          priv->last_scroll_event_time = _time;
+         }
++
++      priv->last_scroll_event_time = _time;
+     }
+
+ #undef STILL_THRESHOLD
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0024-Cancel-out-smaller-delta-component.patch b/bockbuild/mac-sdk/patches/gtk/0024-Cancel-out-smaller-delta-component.patch
new file mode 100644 (file)
index 0000000..c6f3494
--- /dev/null
@@ -0,0 +1,30 @@
+From 649890483c012837251571c0042b9149743be9e7 Mon Sep 17 00:00:00 2001
+From: Kristian Rietveld <kris@lanedo.com>
+Date: Wed, 19 Sep 2012 07:28:20 +0200
+Subject: [PATCH 24/68] Cancel out smaller delta component.
+
+---
+ gtk/gtkscrolledwindow.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
+index f3be303..ab3df16 100644
+--- a/gtk/gtkscrolledwindow.c
++++ b/gtk/gtkscrolledwindow.c
+@@ -2027,6 +2027,14 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+       if (is_momentum_event && !is_overshot)
+         gtk_scrolled_window_calculate_velocity (scrolled_window, (GdkEvent *)event);
+
++      /* Cancel out smaller component, makes it easier to scroll when the
++       * gestures are not fully straight.
++       */
++      if (fabs (delta_y) >= fabs (delta_x))
++        delta_x = 0.0;
++      else
++        delta_y = 0.0;
++
+       /* Scroll events are handled in two cases:
+        *  1) We are not overshot and not snapping back, so scroll as
+        *  usual and also handle momentum events.
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0025-quartz-Add-a-dummy-NSView-serving-as-layer-view.patch b/bockbuild/mac-sdk/patches/gtk/0025-quartz-Add-a-dummy-NSView-serving-as-layer-view.patch
new file mode 100644 (file)
index 0000000..04efc9d
--- /dev/null
@@ -0,0 +1,100 @@
+From 3c7e6438bb2420c8fd31ba164c400b66ae474f5d Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Fri, 5 Oct 2012 12:10:15 +0200
+Subject: [PATCH 25/68] quartz: Add a dummy NSView serving as layer view
+
+By doing this, the GdkQuartzView does not have to be marked as layer
+backed, such that the disadvantages that come with that (not being able
+to copy pixels and large redraw areas) no longer apply.
+---
+ gdk/quartz/GdkQuartzView.c    |    6 ++++++
+ gdk/quartz/gdkquartz.h        |    1 +
+ gdk/quartz/gdkwindow-quartz.c |   16 ++++++++++++++++
+ gdk/quartz/gdkwindow-quartz.h |    1 +
+ 4 files changed, 24 insertions(+)
+
+diff --git a/gdk/quartz/GdkQuartzView.c b/gdk/quartz/GdkQuartzView.c
+index 7f0ec40..c6ccf06 100644
+--- a/gdk/quartz/GdkQuartzView.c
++++ b/gdk/quartz/GdkQuartzView.c
+@@ -632,6 +632,8 @@
+       [[self window] invalidateShadow];
+       needsInvalidateShadow = NO;
+     }
++
++  [[self layer] removeAllAnimations];
+ }
+
+ -(void)setNeedsInvalidateShadow: (BOOL)invalidate
+@@ -690,7 +692,11 @@
+
+ -(void)setFrame: (NSRect)frame
+ {
++  GdkWindowObject *private = GDK_WINDOW_OBJECT (gdk_window);
++  GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
++
+   [super setFrame: frame];
++  [impl->layer_view setFrame: frame];
+
+   if ([self window])
+     [self updateTrackingRect];
+diff --git a/gdk/quartz/gdkquartz.h b/gdk/quartz/gdkquartz.h
+index 3c42983..8b0085c 100644
+--- a/gdk/quartz/gdkquartz.h
++++ b/gdk/quartz/gdkquartz.h
+@@ -54,6 +54,7 @@ typedef enum
+
+ NSWindow *gdk_quartz_window_get_nswindow                        (GdkWindow      *window);
+ NSView   *gdk_quartz_window_get_nsview                          (GdkWindow      *window);
++NSView   *gdk_quartz_window_get_layer_view                      (GdkWindow      *window);
+ NSImage  *gdk_quartz_pixbuf_to_ns_image_libgtk_only             (GdkPixbuf      *pixbuf);
+ id        gdk_quartz_drag_context_get_dragging_info_libgtk_only (GdkDragContext *context);
+ NSEvent  *gdk_quartz_event_get_nsevent                          (GdkEvent       *event);
+diff --git a/gdk/quartz/gdkwindow-quartz.c b/gdk/quartz/gdkwindow-quartz.c
+index 318a171..500776d 100644
+--- a/gdk/quartz/gdkwindow-quartz.c
++++ b/gdk/quartz/gdkwindow-quartz.c
+@@ -68,6 +68,17 @@ gdk_quartz_window_get_nsview (GdkWindow *window)
+   return ((GdkWindowImplQuartz *)private->impl)->view;
+ }
+
++NSView *
++gdk_quartz_window_get_layer_view (GdkWindow *window)
++{
++  GdkWindowObject *private = (GdkWindowObject *)window;
++
++  if (GDK_WINDOW_DESTROYED (window))
++    return NULL;
++
++  return ((GdkWindowImplQuartz *)private->impl)->layer_view;
++}
++
+ NSWindow *
+ gdk_quartz_window_get_nswindow (GdkWindow *window)
+ {
+@@ -1024,6 +1035,11 @@ _gdk_window_impl_new (GdkWindow     *window,
+       [impl->view setGdkWindow:window];
+       [impl->toplevel setContentView:impl->view];
+       [impl->view release];
++
++        impl->layer_view = [[NSView alloc] initWithFrame:content_rect];
++        [impl->view addSubview:impl->layer_view];
++        [impl->layer_view setWantsLayer:YES];
++        [impl->layer_view release];
+       }
+       break;
+
+diff --git a/gdk/quartz/gdkwindow-quartz.h b/gdk/quartz/gdkwindow-quartz.h
+index 4a0e27a..f35238b 100644
+--- a/gdk/quartz/gdkwindow-quartz.h
++++ b/gdk/quartz/gdkwindow-quartz.h
+@@ -47,6 +47,7 @@ struct _GdkWindowImplQuartz
+   NSWindow *toplevel;
+   NSTrackingRectTag tracking_rect;
+   GdkQuartzView *view;
++  NSView *layer_view;
+
+   GdkWindowTypeHint type_hint;
+
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0026-gtk-port-overlay-scrollbars-to-native-CALayers.patch b/bockbuild/mac-sdk/patches/gtk/0026-gtk-port-overlay-scrollbars-to-native-CALayers.patch
new file mode 100644 (file)
index 0000000..5a03745
--- /dev/null
@@ -0,0 +1,1099 @@
+From 756b650315bed2426bd7f1e0525a10b707c868e6 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Thu, 27 Sep 2012 17:03:47 +0200
+Subject: [PATCH 26/68] gtk: port overlay scrollbars to native CALayers
+
+---
+ gtk/gtkscrolledwindow.c |  679 ++++++++++++++++++++++++++---------------------
+ 1 file changed, 379 insertions(+), 300 deletions(-)
+
+diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
+index ab3df16..1fba87b 100644
+--- a/gtk/gtkscrolledwindow.c
++++ b/gtk/gtkscrolledwindow.c
+@@ -36,8 +36,12 @@
+ #include "gtkintl.h"
+ #include "gtkmain.h"
+ #include "gtkdnd.h"
++#include "gtktreeview.h"
+ #include "gtkalias.h"
+
++#include "gdk/quartz/gdkquartz.h"
++#include <Cocoa/Cocoa.h>
++
+
+ /* scrolled window policy and size requisition handling:
+  *
+@@ -117,6 +121,12 @@ typedef struct {
+   gdouble                unclamped_hadj_value;
+   gdouble                unclamped_vadj_value;
+
++  GtkAllocation  viewport_allocation;
++  CALayer       *vbar_layer;
++  CALayer       *hbar_layer;
++  CALayer       *vslider_layer;
++  CALayer       *hslider_layer;
++
+   GtkAdjustment *opacity;
+   GbAnimation   *opacity_anim;
+
+@@ -243,29 +253,23 @@ static void gtk_scrolled_window_start_fade_out_timeout (GtkScrolledWindow *scrol
+ static void gtk_scrolled_window_stop_fade_out_timeout (GtkScrolledWindow *scrolled_window);
+ static void gtk_scrolled_window_start_fade_in_animation  (GtkScrolledWindow *scrolled_window);
+ static void gtk_scrolled_window_start_fade_out_animation (GtkScrolledWindow *scrolled_window);
+-static gboolean
+-           gtk_scrolled_window_over_child_scroll_areas (GtkScrolledWindow *scrolled_window,
+-                                                        GdkEvent          *event,
++static gboolean  gtk_scrolled_window_over_scroll_areas (GtkScrolledWindow *scrolled_window,
+                                                         gint               x,
+                                                         gint               y,
+                                                         gboolean          *over_vscroll,
+                                                         gboolean          *over_hscroll);
+-static void gtk_scrolled_window_get_child_scroll_areas (GtkScrolledWindow *scrolled_window,
+-                                                        GtkWidget         *child,
+-                                                        GdkWindow         *child_window,
++static void      gtk_scrolled_window_get_scroll_areas  (GtkScrolledWindow *scrolled_window,
+                                                         GdkRectangle      *vbar_rect,
+                                                         GdkRectangle      *vslider_rect,
+                                                         GdkRectangle      *hbar_rect,
+                                                         GdkRectangle      *hslider_rect);
+-static gboolean gtk_scrolled_window_child_expose (GtkWidget         *widget,
+-                                                  GdkEventExpose    *eevent,
+-                                                  GtkScrolledWindow *scrolled_window);
+-static void  gtk_scrolled_window_expose_scrollbars (GtkAdjustment     *adj,
+-                                                    GtkScrolledWindow *scrolled_window);
++static void  gtk_scrolled_window_update_scrollbars (GtkScrolledWindow *scrolled_window);
+
+ static void gtk_scrolled_window_overlay_scrollbars_changed (GtkSettings *settings,
+                                                             GParamSpec  *arg,
+                                                             gpointer     user_data);
++static void gtk_scrolled_window_map_layers                 (GtkScrolledWindow *scrolled_window);
++static void gtk_scrolled_window_unmap_layers               (GtkScrolledWindow *scrolled_window);
+
+
+ static void gtk_scrolled_window_start_snap_back         (GtkScrolledWindow *scrolled_window);
+@@ -536,9 +540,9 @@ gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
+   priv->sb_width = 6;
+   priv->sb_fade_out_delay = 1000;
+
+-  g_signal_connect (priv->opacity, "value-changed",
+-                    G_CALLBACK (gtk_scrolled_window_expose_scrollbars),
+-                    scrolled_window);
++  g_signal_connect_swapped (priv->opacity, "value-changed",
++                            G_CALLBACK (gtk_scrolled_window_update_scrollbars),
++                            scrolled_window);
+ }
+
+ /**
+@@ -587,7 +591,6 @@ gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
+                                    GtkAdjustment     *hadjustment)
+ {
+   GtkBin *bin;
+-  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+
+   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
+   if (hadjustment)
+@@ -623,7 +626,7 @@ gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
+                                             gtk_scrolled_window_adjustment_value_changed,
+                                             scrolled_window);
+       g_signal_handlers_disconnect_by_func (old_adjustment,
+-                                            gtk_scrolled_window_expose_scrollbars,
++                                            gtk_scrolled_window_update_scrollbars,
+                                             scrolled_window);
+
+       gtk_range_set_adjustment (GTK_RANGE (scrolled_window->hscrollbar),
+@@ -641,18 +644,12 @@ gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
+   gtk_scrolled_window_adjustment_changed (hadjustment, scrolled_window);
+   gtk_scrolled_window_adjustment_value_changed (hadjustment, scrolled_window);
+
+-#if 0
+-  g_signal_connect (hadjustment, "value-changed",
+-                    G_CALLBACK (gtk_scrolled_window_adjustment_value_changed),
+-                    scrolled_window);
+-#endif
+-
+-  g_signal_connect (hadjustment, "changed",
+-                    G_CALLBACK (gtk_scrolled_window_expose_scrollbars),
+-                    scrolled_window);
+-  g_signal_connect (hadjustment, "value-changed",
+-                    G_CALLBACK (gtk_scrolled_window_expose_scrollbars),
+-                    scrolled_window);
++  g_signal_connect_swapped (hadjustment, "changed",
++                            G_CALLBACK (gtk_scrolled_window_update_scrollbars),
++                            scrolled_window);
++  g_signal_connect_swapped (hadjustment, "value-changed",
++                            G_CALLBACK (gtk_scrolled_window_update_scrollbars),
++                            scrolled_window);
+
+   if (bin->child)
+     gtk_widget_set_scroll_adjustments (bin->child,
+@@ -711,7 +708,7 @@ gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
+                                             gtk_scrolled_window_adjustment_value_changed,
+                                             scrolled_window);
+       g_signal_handlers_disconnect_by_func (old_adjustment,
+-                                            gtk_scrolled_window_expose_scrollbars,
++                                            gtk_scrolled_window_update_scrollbars,
+                                             scrolled_window);
+
+       gtk_range_set_adjustment (GTK_RANGE (scrolled_window->vscrollbar),
+@@ -729,19 +726,12 @@ gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
+   gtk_scrolled_window_adjustment_changed (vadjustment, scrolled_window);
+   gtk_scrolled_window_adjustment_value_changed (vadjustment, scrolled_window);
+
+-#if 0
+-  g_signal_connect (vadjustment,
+-                    "value-changed",
+-                    G_CALLBACK (gtk_scrolled_window_adjustment_value_changed),
+-                    scrolled_window);
+-#endif
+-
+-  g_signal_connect (vadjustment, "changed",
+-                    G_CALLBACK (gtk_scrolled_window_expose_scrollbars),
+-                    scrolled_window);
+-  g_signal_connect (vadjustment, "value-changed",
+-                    G_CALLBACK (gtk_scrolled_window_expose_scrollbars),
+-                    scrolled_window);
++  g_signal_connect_swapped (vadjustment, "changed",
++                            G_CALLBACK (gtk_scrolled_window_update_scrollbars),
++                            scrolled_window);
++  g_signal_connect_swapped (vadjustment, "value-changed",
++                            G_CALLBACK (gtk_scrolled_window_update_scrollbars),
++                            scrolled_window);
+
+   if (bin->child)
+     gtk_widget_set_scroll_adjustments (bin->child,
+@@ -1081,7 +1071,7 @@ gtk_scrolled_window_destroy (GtkObject *object)
+                                             gtk_scrolled_window_adjustment_value_changed,
+                                             scrolled_window);
+       g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
+-                                            gtk_scrolled_window_expose_scrollbars,
++                                            gtk_scrolled_window_update_scrollbars,
+                                             scrolled_window);
+
+       gtk_widget_unparent (scrolled_window->hscrollbar);
+@@ -1098,7 +1088,7 @@ gtk_scrolled_window_destroy (GtkObject *object)
+                                             gtk_scrolled_window_adjustment_value_changed,
+                                             scrolled_window);
+       g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)),
+-                                            gtk_scrolled_window_expose_scrollbars,
++                                            gtk_scrolled_window_update_scrollbars,
+                                             scrolled_window);
+
+       gtk_widget_unparent (scrolled_window->vscrollbar);
+@@ -1276,10 +1266,11 @@ gtk_scrolled_window_screen_changed (GtkWidget *widget,
+ }
+
+ static void
+-gtk_scrolled_window_paint (GtkWidget    *widget,
+-                         GdkRectangle *area)
++gtk_scrolled_window_paint (GtkWidget      *widget,
++                         GdkEventExpose *event)
+ {
+   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
++  GdkRectangle *area = &event->area;
+   GtkAllocation relative_allocation;
+
+   if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
+@@ -1317,6 +1308,116 @@ gtk_scrolled_window_paint (GtkWidget    *widget,
+     }
+ }
+
++static void
++gtk_scrolled_window_update_scrollbars (GtkScrolledWindow *scrolled_window)
++{
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++  GtkWidget *widget = GTK_WIDGET (scrolled_window);
++  GdkWindow *window;
++  gint window_height;
++  GdkRectangle vbar_rect;
++  GdkRectangle vslider_rect;
++  GdkRectangle hbar_rect;
++  GdkRectangle hslider_rect;
++  CGRect rect;
++
++  if (!priv->overlay_scrollbars || !gtk_widget_get_realized (widget))
++    return;
++
++  window = gtk_widget_get_window (gtk_widget_get_toplevel (widget));
++  window_height = gdk_window_get_height (window);
++
++  gtk_scrolled_window_get_scroll_areas (scrolled_window,
++                                        &vbar_rect, &vslider_rect,
++                                        &hbar_rect, &hslider_rect);
++
++  if (priv->sb_visible && scrolled_window->vscrollbar && vbar_rect.width > 0)
++    {
++      rect.origin.x = priv->viewport_allocation.x + vbar_rect.x;
++      rect.origin.y = priv->viewport_allocation.y + vbar_rect.y;
++      rect.size.width = vbar_rect.width;
++      rect.size.height = vbar_rect.height;
++
++      rect.origin.y = window_height - rect.origin.y - rect.size.height;
++
++      priv->vbar_layer.frame = rect;
++      priv->vbar_layer.opacity = gtk_adjustment_get_value (priv->opacity) / 2.0;
++    }
++  else
++    {
++      priv->vbar_layer.opacity = 0.0;
++    }
++
++  if (priv->sb_visible && scrolled_window->hscrollbar && hbar_rect.width > 0)
++    {
++      rect.origin.x = priv->viewport_allocation.x + hbar_rect.x;
++      rect.origin.y = priv->viewport_allocation.y + hbar_rect.y;
++      rect.size.width = hbar_rect.width;
++      rect.size.height = hbar_rect.height;
++
++      /* don't overlap in the corner */
++      if (scrolled_window->vscrollbar && vbar_rect.width > 0)
++        rect.size.width -= vbar_rect.width;
++
++      rect.origin.y = window_height - rect.origin.y - rect.size.height;
++
++      priv->hbar_layer.frame = rect;
++      priv->hbar_layer.opacity = gtk_adjustment_get_value (priv->opacity) / 2.0;
++    }
++  else
++    {
++      priv->hbar_layer.opacity = 0.0;
++    }
++
++  if (scrolled_window->vscrollbar && vslider_rect.width > 0)
++    {
++      rect.origin.x = priv->viewport_allocation.x + vslider_rect.x;
++      rect.origin.y = priv->viewport_allocation.y + vslider_rect.y;
++      rect.size.width = vslider_rect.width;
++      rect.size.height = vslider_rect.height;
++
++      rect.origin.y = window_height - rect.origin.y - rect.size.height;
++
++      priv->vslider_layer.frame = rect;
++      priv->vslider_layer.cornerRadius = priv->sb_radius;
++      priv->vslider_layer.opacity = gtk_adjustment_get_value (priv->opacity);
++    }
++  else
++    {
++      priv->vslider_layer.opacity = 0.0;
++    }
++
++  if (scrolled_window->hscrollbar && hslider_rect.width > 0)
++    {
++      rect.origin.x = priv->viewport_allocation.x + hslider_rect.x;
++      rect.origin.y = priv->viewport_allocation.y + hslider_rect.y;
++      rect.size.width = hslider_rect.width;
++      rect.size.height = hslider_rect.height;
++
++      rect.origin.y = window_height - rect.origin.y - rect.size.height;
++
++      priv->hslider_layer.frame = rect;
++      priv->hslider_layer.cornerRadius = priv->sb_radius;
++      priv->hslider_layer.opacity = gtk_adjustment_get_value (priv->opacity);
++    }
++  else
++    {
++      priv->hslider_layer.opacity = 0.0;
++    }
++
++  [priv->vbar_layer removeAllAnimations];
++  [priv->vbar_layer setNeedsDisplay];
++
++  [priv->vslider_layer removeAllAnimations];
++  [priv->vslider_layer setNeedsDisplay];
++
++  [priv->hbar_layer removeAllAnimations];
++  [priv->hbar_layer setNeedsDisplay];
++
++  [priv->hslider_layer removeAllAnimations];
++  [priv->hslider_layer setNeedsDisplay];
++}
++
+ static gboolean
+ gtk_scrolled_window_expose (GtkWidget      *widget,
+                           GdkEventExpose *event)
+@@ -1326,23 +1427,11 @@ gtk_scrolled_window_expose (GtkWidget      *widget,
+
+   if (gtk_widget_is_drawable (widget))
+     {
+-      GdkWindow *hscrollbar_window = NULL;
+-      GdkWindow *vscrollbar_window = NULL;
++      gtk_scrolled_window_paint (widget, event);
+
+-      if (scrolled_window->hscrollbar)
+-        hscrollbar_window = gtk_widget_get_window (scrolled_window->hscrollbar);
++      GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->expose_event (widget, event);
+
+-      if (scrolled_window->vscrollbar)
+-        vscrollbar_window = gtk_widget_get_window (scrolled_window->vscrollbar);
+-
+-      if (event->window == priv->overshoot_window ||
+-          event->window == priv->vbackground_window ||
+-          event->window == priv->hbackground_window ||
+-          event->window == hscrollbar_window ||
+-          event->window == vscrollbar_window)
+-        GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->expose_event (widget, event);
+-      else
+-        gtk_scrolled_window_paint (widget, &event->area);
++      gtk_scrolled_window_update_scrollbars (scrolled_window);
+     }
+
+   return FALSE;
+@@ -1554,6 +1643,8 @@ gtk_scrolled_window_size_request (GtkWidget      *widget,
+         else
+           requisition->width += vscrollbar_requisition.width;
+       }
++      else
++        requisition->width += priv->sb_width + 2 * priv->sb_padding;
+
+       if (scrolled_window->vscrollbar_policy == GTK_POLICY_NEVER)
+       requisition->height += child_requisition.height;
+@@ -1569,6 +1660,8 @@ gtk_scrolled_window_size_request (GtkWidget      *widget,
+         else
+           requisition->height += hscrollbar_requisition.height;
+       }
++      else
++        requisition->height += priv->sb_width + 2 * priv->sb_padding;
+     }
+
+   if (! priv->overlay_scrollbars)
+@@ -1785,6 +1878,12 @@ _gtk_scrolled_window_allocate_overshoot_window (GtkScrolledWindow *scrolled_wind
+     }
+   else
+     gdk_window_hide (priv->hbackground_window);
++
++  if (priv->overlay_scrollbars)
++    {
++      gtk_scrolled_window_start_fade_in_animation (scrolled_window);
++      gtk_scrolled_window_update_scrollbars (scrolled_window);
++    }
+ }
+
+ static void
+@@ -1811,6 +1910,35 @@ gtk_scrolled_window_allocate_child (GtkScrolledWindow *swindow,
+ }
+
+ static void
++gtk_scrolled_window_compute_viewport_allocation (GtkScrolledWindow *scrolled_window)
++{
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++  GtkWidget *widget = GTK_WIDGET (scrolled_window);
++  GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
++  gint toplevel_alloc_x, toplevel_alloc_y;
++
++  /* Translate the viewport_allocation coordinates to coordinates relative to
++   * the toplevel. Then set these coordinates as viewport_allocation, which
++   * will be used to draw the scrollbars to the CALayer.
++   */
++  gtk_scrolled_window_relative_allocation (widget, &priv->viewport_allocation);
++  if (gtk_widget_translate_coordinates (widget, toplevel,
++                                        priv->viewport_allocation.x,
++                                        priv->viewport_allocation.y,
++                                        &toplevel_alloc_x, &toplevel_alloc_y))
++    {
++      priv->viewport_allocation.x = toplevel_alloc_x;
++      priv->viewport_allocation.y = toplevel_alloc_y;
++    }
++  else
++    {
++      /* Fallback using only the widget's allocation. */
++      priv->viewport_allocation.x += widget->allocation.x;
++      priv->viewport_allocation.y += widget->allocation.y;
++    }
++}
++
++static void
+ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
+                                  GtkAllocation *allocation)
+ {
+@@ -1829,8 +1957,6 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
+   priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+   bin = GTK_BIN (scrolled_window);
+
+-  gtk_scrolled_window_expose_scrollbars (NULL, scrolled_window);
+-
+   scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
+   gtk_widget_style_get (widget, "scrollbars-within-bevel", &scrollbars_within_bevel, NULL);
+
+@@ -1879,6 +2005,9 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
+       }
+       while (previous_hvis != scrolled_window->hscrollbar_visible ||
+            previous_vvis != scrolled_window->vscrollbar_visible);
++
++      if (gtk_widget_get_realized (widget))
++        gtk_scrolled_window_compute_viewport_allocation (scrolled_window);
+     }
+   else
+     {
+@@ -2166,6 +2295,10 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+            priv->y_force = 0.0;
+          }
+
++       /* Stop fade out timeout while we're overshot */
++       if (new_overshoot_x != 0 || new_overshoot_y != 0)
++         gtk_scrolled_window_stop_fade_out_timeout (scrolled_window);
++
+       /* If we should start a snap back and no current deceleration
+        * is active, start the snap back.
+        */
+@@ -2343,6 +2476,10 @@ scrolled_window_snap_back_cb (gpointer user_data)
+   else
+     {
+       priv->deceleration_id = 0;
++
++      /* Snap back has finished, make sure the scrollbars will fade out */
++      gtk_scrolled_window_start_fade_out_timeout (scrolled_window);
++
+       return FALSE;
+     }
+ }
+@@ -2445,6 +2582,25 @@ static gboolean
+ gtk_scrolled_window_captured_motion_notify_scrollbar (GtkWidget *widget,
+                                                       GdkEvent  *event);
+
++static void
++gtk_scrolled_window_translate_coordinates (GtkWidget  *src_widget,
++                                           GtkWidget  *dest_widget,
++                                           gint        src_x,
++                                           gint        src_y,
++                                           gint       *dest_x,
++                                           gint       *dest_y)
++{
++  if (GTK_IS_TREE_VIEW (src_widget))
++    {
++      gtk_tree_view_convert_bin_window_to_widget_coords (GTK_TREE_VIEW (src_widget),
++                                                         src_x, src_y,
++                                                         &src_x, &src_y);
++    }
++
++  gtk_widget_translate_coordinates (src_widget, dest_widget,
++                                    src_x, src_y, dest_x, dest_y);
++}
++
+ static gboolean
+ gtk_scrolled_window_captured_button_press_scrollbar (GtkWidget *widget,
+                                                      GdkEvent  *event)
+@@ -2452,14 +2608,19 @@ gtk_scrolled_window_captured_button_press_scrollbar (GtkWidget *widget,
+   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
+   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+   GdkEventButton *bevent = (GdkEventButton *) event;
++  GtkWidget *event_widget = gtk_get_event_widget (event);
++  gint x, y;
+
+   if (bevent->button != 1)
+     return FALSE;
+
+-  if (gtk_scrolled_window_over_child_scroll_areas (scrolled_window, event,
+-                                                   bevent->x, bevent->y,
+-                                                   &priv->sb_grab_vscroll,
+-                                                   &priv->sb_grab_hscroll))
++  gtk_scrolled_window_translate_coordinates (event_widget, widget,
++                                             bevent->x, bevent->y, &x, &y);
++
++  if (gtk_scrolled_window_over_scroll_areas (scrolled_window,
++                                             x, y,
++                                             &priv->sb_grab_vscroll,
++                                             &priv->sb_grab_hscroll))
+     {
+       GdkRectangle vbar_rect;
+       GdkRectangle vslider_rect;
+@@ -2469,11 +2630,9 @@ gtk_scrolled_window_captured_button_press_scrollbar (GtkWidget *widget,
+       priv->sb_pointer_grabbed = TRUE;
+       gtk_grab_add (widget);
+
+-      gtk_scrolled_window_get_child_scroll_areas (scrolled_window,
+-                                                  gtk_bin_get_child (GTK_BIN (widget)),
+-                                                  bevent->window,
+-                                                  &vbar_rect, &vslider_rect,
+-                                                  &hbar_rect, &hslider_rect);
++      gtk_scrolled_window_get_scroll_areas (scrolled_window,
++                                            &vbar_rect, &vslider_rect,
++                                            &hbar_rect, &hslider_rect);
+
+       if (priv->sb_grab_vscroll)
+         {
+@@ -2481,20 +2640,20 @@ gtk_scrolled_window_captured_button_press_scrollbar (GtkWidget *widget,
+           vslider_rect.x = vbar_rect.x;
+           vslider_rect.width = vbar_rect.width;
+
+-          if (bevent->x >= vslider_rect.x &&
+-              bevent->x < (vslider_rect.x + vslider_rect.width) &&
+-              bevent->y >= vslider_rect.y &&
+-              bevent->y < (vslider_rect.y + vslider_rect.height))
++          if (x >= vslider_rect.x &&
++              x < (vslider_rect.x + vslider_rect.width) &&
++              y >= vslider_rect.y &&
++              y < (vslider_rect.y + vslider_rect.height))
+             {
+               priv->sb_drag_slider = TRUE;
+-              priv->sb_grab_offset_y = bevent->y - vslider_rect.y;
++              priv->sb_grab_offset_y = y - vslider_rect.y;
+             }
+           else
+             {
+               priv->sb_drag_slider = FALSE;
+-              priv->sb_grab_offset_y = bevent->y - vbar_rect.y;
++              priv->sb_grab_offset_y = y - vbar_rect.y;
+
+-              if (bevent->y < vslider_rect.y)
++              if (y < vslider_rect.y)
+                 priv->sb_scroll_direction = -1;
+               else
+                 priv->sb_scroll_direction = 1;
+@@ -2506,20 +2665,20 @@ gtk_scrolled_window_captured_button_press_scrollbar (GtkWidget *widget,
+           hslider_rect.y = hbar_rect.y;
+           hslider_rect.height = hbar_rect.height;
+
+-          if (bevent->x >= hslider_rect.x &&
+-              bevent->x < (hslider_rect.x + hslider_rect.width) &&
+-              bevent->y >= hslider_rect.y &&
+-              bevent->y < (hslider_rect.y + hslider_rect.height))
++          if (x >= hslider_rect.x &&
++              x < (hslider_rect.x + hslider_rect.width) &&
++              y >= hslider_rect.y &&
++              y < (hslider_rect.y + hslider_rect.height))
+             {
+               priv->sb_drag_slider = TRUE;
+-              priv->sb_grab_offset_x = bevent->x - hslider_rect.x;
++              priv->sb_grab_offset_x = x - hslider_rect.x;
+             }
+           else
+             {
+               priv->sb_drag_slider = FALSE;
+-              priv->sb_grab_offset_x = bevent->x - hbar_rect.x;
++              priv->sb_grab_offset_x = x - hbar_rect.x;
+
+-              if (bevent->x < hslider_rect.x)
++              if (x < hslider_rect.x)
+                 priv->sb_scroll_direction = -1;
+               else
+                 priv->sb_scroll_direction = 1;
+@@ -2597,6 +2756,11 @@ gtk_scrolled_window_captured_motion_notify_scrollbar (GtkWidget *widget,
+   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
+   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+   GdkEventMotion *mevent = (GdkEventMotion *) event;
++  GtkWidget *event_widget = gtk_get_event_widget (event);
++  gint x, y;
++
++  gtk_scrolled_window_translate_coordinates (event_widget, widget,
++                                             mevent->x, mevent->y, &x, &y);
+
+   if (priv->sb_pointer_grabbed)
+     {
+@@ -2611,22 +2775,20 @@ gtk_scrolled_window_captured_motion_notify_scrollbar (GtkWidget *widget,
+           gint visible_range;
+           gdouble value;
+
+-          gtk_scrolled_window_get_child_scroll_areas (scrolled_window,
+-                                                      gtk_bin_get_child (GTK_BIN (widget)),
+-                                                      mevent->window,
+-                                                      &vbar_rect, &vslider_rect,
+-                                                      &hbar_rect, &hslider_rect);
++          gtk_scrolled_window_get_scroll_areas (scrolled_window,
++                                                &vbar_rect, &vslider_rect,
++                                                &hbar_rect, &hslider_rect);
+
+           if (priv->sb_grab_vscroll)
+             {
+               adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
+-              pos = mevent->y - priv->sb_grab_offset_y - vbar_rect.y;
++              pos = y - priv->sb_grab_offset_y - vbar_rect.y;
+               visible_range = vbar_rect.height - vslider_rect.height;
+             }
+           else if (priv->sb_grab_hscroll)
+             {
+               adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
+-              pos = mevent->x - priv->sb_grab_offset_x - hbar_rect.x;
++              pos = x - priv->sb_grab_offset_x - hbar_rect.x;
+               visible_range = hbar_rect.width - hslider_rect.width;
+             }
+
+@@ -2641,9 +2803,9 @@ gtk_scrolled_window_captured_motion_notify_scrollbar (GtkWidget *widget,
+     }
+   else
+     {
+-      if (gtk_scrolled_window_over_child_scroll_areas (scrolled_window, event,
+-                                                       mevent->x, mevent->y,
+-                                                       NULL, NULL))
++      if (gtk_scrolled_window_over_scroll_areas (scrolled_window,
++                                                 x, y,
++                                                 NULL, NULL))
+         {
+           priv->sb_hovering = TRUE;
+           priv->sb_visible = TRUE;
+@@ -2652,7 +2814,7 @@ gtk_scrolled_window_captured_motion_notify_scrollbar (GtkWidget *widget,
+           gtk_scrolled_window_stop_fade_out_timeout (scrolled_window);
+
+           /* needed when entering the scrollbar */
+-          gtk_scrolled_window_expose_scrollbars (NULL, scrolled_window);
++          gtk_scrolled_window_update_scrollbars (scrolled_window);
+
+           return TRUE;
+         }
+@@ -2839,10 +3001,6 @@ gtk_scrolled_window_add (GtkContainer *container,
+                                           gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar))))
+     g_warning ("gtk_scrolled_window_add(): cannot add non scrollable widget "
+              "use gtk_scrolled_window_add_with_viewport() instead");
+-
+-  g_signal_connect_after (child, "expose-event",
+-                          G_CALLBACK (gtk_scrolled_window_child_expose),
+-                          container);
+ }
+
+ static void
+@@ -2857,10 +3015,6 @@ gtk_scrolled_window_remove (GtkContainer *container,
+
+   priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (container);
+
+-  g_signal_handlers_disconnect_by_func (child,
+-                                        gtk_scrolled_window_child_expose,
+-                                        container);
+-
+   gtk_widget_set_scroll_adjustments (child, NULL, NULL);
+
+   /* chain parent class handler to remove child */
+@@ -3033,6 +3187,37 @@ gtk_scrolled_window_realize (GtkWidget *widget)
+                                   priv->overshoot_window);
+
+   GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->realize (widget);
++
++  gtk_scrolled_window_compute_viewport_allocation (scrolled_window);
++
++  GdkWindow *parent_window = gtk_widget_get_window (gtk_widget_get_toplevel (widget));
++  NSView    *layer_view;
++  CALayer   *parent_layer;
++
++  layer_view = gdk_quartz_window_get_layer_view (parent_window);
++  parent_layer = [layer_view layer];
++
++  priv->vbar_layer = [[CALayer layer] retain];
++  priv->vbar_layer.backgroundColor = CGColorCreateGenericRGB (0.0, 0.0, 0.0, 0.5);
++  priv->vbar_layer.hidden = YES;
++
++  priv->vslider_layer = [[CALayer layer] retain];
++  priv->vslider_layer.backgroundColor = CGColorCreateGenericRGB (0.0, 0.0, 0.0, 1.0);
++  priv->vslider_layer.hidden = YES;
++
++  priv->hbar_layer = [[CALayer layer] retain];
++  priv->hbar_layer.backgroundColor = CGColorCreateGenericRGB (0.0, 0.0, 0.0, 0.5);
++  priv->hbar_layer.hidden = YES;
++
++  priv->hslider_layer = [[CALayer layer] retain];
++  priv->hslider_layer.backgroundColor = CGColorCreateGenericRGB (0.0, 0.0, 0.0, 1.0);
++  priv->hslider_layer.hidden = YES;
++
++  [parent_layer addSublayer:priv->vbar_layer];
++  [parent_layer addSublayer:priv->vslider_layer];
++
++  [parent_layer addSublayer:priv->hbar_layer];
++  [parent_layer addSublayer:priv->hslider_layer];
+ }
+
+ static void
+@@ -3053,6 +3238,22 @@ gtk_scrolled_window_unrealize (GtkWidget *widget)
+   gdk_window_destroy (priv->hbackground_window);
+   priv->hbackground_window = NULL;
+
++  [priv->vbar_layer removeFromSuperlayer];
++  [priv->vbar_layer release];
++  priv->vbar_layer = NULL;
++
++  [priv->vslider_layer removeFromSuperlayer];
++  [priv->vslider_layer release];
++  priv->vslider_layer = NULL;
++
++  [priv->hbar_layer removeFromSuperlayer];
++  [priv->hbar_layer release];
++  priv->hbar_layer = NULL;
++
++  [priv->hslider_layer removeFromSuperlayer];
++  [priv->hslider_layer release];
++  priv->hslider_layer = NULL;
++
+   gtk_widget_set_realized (widget, FALSE);
+
+   GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->unrealize (widget);
+@@ -3076,6 +3277,9 @@ gtk_scrolled_window_map (GtkWidget *widget)
+     gdk_window_hide (priv->hbackground_window);
+
+   GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->map (widget);
++
++  if (priv->overlay_scrollbars)
++    gtk_scrolled_window_map_layers (scrolled_window);
+ }
+
+ static void
+@@ -3088,6 +3292,9 @@ gtk_scrolled_window_unmap (GtkWidget *widget)
+   gdk_window_hide (priv->vbackground_window);
+   gdk_window_hide (priv->hbackground_window);
+
++  /* Always unmap the layers, regardless of overlay state */
++  gtk_scrolled_window_unmap_layers (scrolled_window);
++
+   GTK_WIDGET_CLASS (gtk_scrolled_window_parent_class)->unmap (widget);
+ }
+
+@@ -3117,75 +3324,25 @@ gtk_scrolled_window_grab_notify (GtkWidget *widget,
+     }
+ }
+
+-static void
+-gtk_scrolled_window_rounded_rectangle (cairo_t *cr,
+-                                       gint     x,
+-                                       gint     y,
+-                                       gint     width,
+-                                       gint     height,
+-                                       gint     x_radius,
+-                                       gint     y_radius)
+-{
+-  gint x1, x2;
+-  gint y1, y2;
+-  gint xr1, xr2;
+-  gint yr1, yr2;
+-
+-  x1 = x;
+-  x2 = x1 + width;
+-  y1 = y;
+-  y2 = y1 + height;
+-
+-  x_radius = MIN (x_radius, width  / 2.0);
+-  y_radius = MIN (y_radius, height / 2.0);
+-
+-  xr1 = x_radius;
+-  xr2 = x_radius / 2.0;
+-  yr1 = y_radius;
+-  yr2 = y_radius / 2.0;
+-
+-  cairo_move_to    (cr, x1 + xr1, y1);
+-  cairo_line_to    (cr, x2 - xr1, y1);
+-  cairo_curve_to   (cr, x2 - xr2, y1, x2, y1 + yr2, x2, y1 + yr1);
+-  cairo_line_to    (cr, x2, y2 - yr1);
+-  cairo_curve_to   (cr, x2, y2 - yr2, x2 - xr2, y2, x2 - xr1, y2);
+-  cairo_line_to    (cr, x1 + xr1, y2);
+-  cairo_curve_to   (cr, x1 + xr2, y2, x1, y2 - yr2, x1, y2 - yr1);
+-  cairo_line_to    (cr, x1, y1 + yr1);
+-  cairo_curve_to   (cr, x1, y1 + yr2, x1 + xr2, y1, x1 + xr1, y1);
+-  cairo_close_path (cr);
+-}
+-
+ static gboolean
+-gtk_scrolled_window_over_child_scroll_areas (GtkScrolledWindow *scrolled_window,
+-                                             GdkEvent          *event,
+-                                             gint               x,
+-                                             gint               y,
+-                                             gboolean          *over_vscroll,
+-                                             gboolean          *over_hscroll)
++gtk_scrolled_window_over_scroll_areas (GtkScrolledWindow *scrolled_window,
++                                       gint               x,
++                                       gint               y,
++                                       gboolean          *over_vscroll,
++                                       gboolean          *over_hscroll)
+ {
+   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+-  GtkWidget *child;
+   GdkRectangle vbar_rect;
+   GdkRectangle hbar_rect;
+   gboolean over_v = FALSE;
+   gboolean over_h = FALSE;
+
+-  child = gtk_bin_get_child (GTK_BIN (scrolled_window));
+-  if (!child)
+-    return FALSE;
+-
+-  if (gtk_get_event_widget (event) != child)
+-    return FALSE;
+-
+   if (gtk_adjustment_get_value (priv->opacity) == 0.0)
+     return FALSE;
+
+-  gtk_scrolled_window_get_child_scroll_areas (scrolled_window,
+-                                              child,
+-                                              ((GdkEventAny *) event)->window,
+-                                              &vbar_rect, NULL,
+-                                              &hbar_rect, NULL);
++  gtk_scrolled_window_get_scroll_areas (scrolled_window,
++                                        &vbar_rect, NULL,
++                                        &hbar_rect, NULL);
+
+   if (vbar_rect.width > 0 &&
+       x >= vbar_rect.x && x < (vbar_rect.x + vbar_rect.width) &&
+@@ -3207,72 +3364,48 @@ gtk_scrolled_window_over_child_scroll_areas (GtkScrolledWindow *scrolled_window,
+ }
+
+ static void
+-gtk_scrolled_window_get_child_scroll_areas (GtkScrolledWindow *scrolled_window,
+-                                            GtkWidget         *child,
+-                                            GdkWindow         *child_window,
+-                                            GdkRectangle      *vbar_rect,
+-                                            GdkRectangle      *vslider_rect,
+-                                            GdkRectangle      *hbar_rect,
+-                                            GdkRectangle      *hslider_rect)
++gtk_scrolled_window_get_scroll_areas (GtkScrolledWindow *scrolled_window,
++                                      GdkRectangle      *vbar_rect,
++                                      GdkRectangle      *vslider_rect,
++                                      GdkRectangle      *hbar_rect,
++                                      GdkRectangle      *hslider_rect)
+ {
+    GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+    GtkAdjustment *adj;
+-   GtkAllocation allocation;
++   gdouble value;
+    gdouble lower;
+    gdouble page_size;
+    gdouble upper;
+-   gdouble value_h = 0.0;
+-   gdouble value_v = 0.0;
+    gdouble ratio;
+    gdouble width;
+    gdouble height;
+    gdouble x;
+    gdouble y;
+-   gint window_width;
+-   gint window_height;
+    gint viewport_width;
+    gint viewport_height;
+    gint offset_x = 0;
+    gint offset_y = 0;
+
+-   window_width = gdk_window_get_width (child_window);
+-   window_height = gdk_window_get_height (child_window);
+-
+-   gtk_widget_get_allocation (child, &allocation);
+-
+-   viewport_width = MIN (window_width, allocation.width);
+-   viewport_height = MIN (window_height, allocation.height);
+-
+-   if (scrolled_window->vscrollbar)
+-     {
+-       adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
+-
+-       value_v = gtk_adjustment_get_value (adj);
+-     }
+-
+-   if (scrolled_window->hscrollbar)
+-     {
+-       adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
+-
+-       value_h = gtk_adjustment_get_value (adj);
+-     }
+-
+-   if (window_width > allocation.width)
+-     offset_x = value_h;
+-
+-   if (window_height > allocation.height)
+-     offset_y = value_v;
++   viewport_width = priv->viewport_allocation.width;
++   viewport_height = priv->viewport_allocation.height;
+
+    if ((vbar_rect || vslider_rect) && scrolled_window->vscrollbar)
+      {
+        adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
+
+        g_object_get (adj,
++                     "value", &value,
+                      "lower", &lower,
+                      "upper", &upper,
+                      "page-size", &page_size,
+                      NULL);
+
++       /* take overshooting into account */
++       if (priv->unclamped_vadj_value + page_size > upper)
++         page_size = upper - priv->unclamped_vadj_value;
++       else if (priv->unclamped_vadj_value < 0.0)
++         page_size += priv->unclamped_vadj_value;
++
+        ratio = page_size / (upper - lower);
+        if (ratio < 1.0)
+          {
+@@ -3280,7 +3413,7 @@ gtk_scrolled_window_get_child_scroll_areas (GtkScrolledWindow *scrolled_window,
+            height = MAX (height, 20);
+            height = MIN (height, viewport_height - (2 * priv->sb_padding));
+
+-           ratio = (value_v - lower) / (upper - page_size - lower);
++           ratio = (value - lower) / (upper - page_size - lower);
+            y = ratio * (viewport_height - (2 * priv->sb_padding) - height) + priv->sb_padding;
+            x = viewport_width - priv->sb_width - priv->sb_padding;
+
+@@ -3328,11 +3461,18 @@ gtk_scrolled_window_get_child_scroll_areas (GtkScrolledWindow *scrolled_window,
+        adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
+
+        g_object_get (adj,
++                     "value", &value,
+                      "lower", &lower,
+                      "upper", &upper,
+                      "page-size", &page_size,
+                      NULL);
+
++       /* take overshooting into account */
++       if (priv->unclamped_hadj_value + page_size > upper)
++         page_size = upper - priv->unclamped_hadj_value;
++       else if (priv->unclamped_hadj_value < 0.0)
++         page_size += priv->unclamped_hadj_value;
++
+        ratio = page_size / (upper - lower);
+        if (ratio < 1.0)
+          {
+@@ -3340,7 +3480,7 @@ gtk_scrolled_window_get_child_scroll_areas (GtkScrolledWindow *scrolled_window,
+            width = MAX (width, 20);
+            width = MIN (width, viewport_width - (2 * priv->sb_padding));
+
+-           ratio = (value_h - lower) / (upper - page_size - lower);
++           ratio = (value - lower) / (upper - page_size - lower);
+            x = ratio * (viewport_width - (2 * priv->sb_padding) - width) + priv->sb_padding;
+            y = viewport_height - priv->sb_width - priv->sb_padding;
+
+@@ -3384,69 +3524,6 @@ gtk_scrolled_window_get_child_scroll_areas (GtkScrolledWindow *scrolled_window,
+      }
+ }
+
+-static gboolean
+-gtk_scrolled_window_child_expose (GtkWidget         *widget,
+-                                  GdkEventExpose    *eevent,
+-                                  GtkScrolledWindow *scrolled_window)
+-{
+-   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+-   GdkRectangle vbar_rect;
+-   GdkRectangle vslider_rect;
+-   GdkRectangle hbar_rect;
+-   GdkRectangle hslider_rect;
+-   cairo_t   *cr;
+-
+-   if (!priv->overlay_scrollbars)
+-     return FALSE;
+-
+-   cr = gdk_cairo_create (eevent->window);
+-   gdk_cairo_region (cr, eevent->region);
+-   cairo_clip (cr);
+-
+-   gtk_scrolled_window_get_child_scroll_areas (scrolled_window,
+-                                               gtk_bin_get_child (GTK_BIN (scrolled_window)),
+-                                               eevent->window,
+-                                               &vbar_rect, &vslider_rect,
+-                                               &hbar_rect, &hslider_rect);
+-
+-   if (priv->sb_visible)
+-     {
+-       if (scrolled_window->vscrollbar && vbar_rect.width > 0)
+-         gdk_cairo_rectangle (cr, &vbar_rect);
+-
+-       if (scrolled_window->hscrollbar && hbar_rect.width > 0)
+-         gdk_cairo_rectangle (cr, &hbar_rect);
+-
+-       cairo_set_source_rgba (cr, 0, 0, 0, gtk_adjustment_get_value (priv->opacity) / 2.0);
+-       cairo_fill (cr);
+-     }
+-
+-   if (scrolled_window->vscrollbar && vslider_rect.width > 0)
+-     gtk_scrolled_window_rounded_rectangle (cr,
+-                                            vslider_rect.x,
+-                                            vslider_rect.y,
+-                                            vslider_rect.width,
+-                                            vslider_rect.height,
+-                                            priv->sb_radius,
+-                                            priv->sb_radius);
+-
+-   if (scrolled_window->hscrollbar && hslider_rect.width > 0)
+-     gtk_scrolled_window_rounded_rectangle (cr,
+-                                            hslider_rect.x,
+-                                            hslider_rect.y,
+-                                            hslider_rect.width,
+-                                            hslider_rect.height,
+-                                            priv->sb_radius,
+-                                            priv->sb_radius);
+-
+-   cairo_set_source_rgba (cr, 0, 0, 0, gtk_adjustment_get_value (priv->opacity));
+-   cairo_fill (cr);
+-
+-   cairo_destroy (cr);
+-
+-   return FALSE;
+-}
+-
+ static void
+ gtk_scrolled_window_cancel_animation (GtkScrolledWindow *scrolled_window)
+ {
+@@ -3541,39 +3618,6 @@ gtk_scrolled_window_start_fade_out_animation (GtkScrolledWindow *scrolled_window
+ }
+
+ static void
+-gtk_scrolled_window_expose_scrollbars (GtkAdjustment     *adj,
+-                                       GtkScrolledWindow *scrolled_window)
+-{
+-  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+-
+-  if (priv->overlay_scrollbars)
+-    {
+-      GtkWidget *child = gtk_bin_get_child (GTK_BIN (scrolled_window));
+-
+-      if (child && gtk_widget_get_visible (child))
+-        {
+-          GtkAllocation alloc;
+-
+-          gtk_widget_get_allocation (child, &alloc);
+-
+-          if (scrolled_window->vscrollbar)
+-            gtk_widget_queue_draw_area (child,
+-                                        alloc.width - 20,
+-                                        0,
+-                                        20,
+-                                        alloc.height);
+-
+-          if (scrolled_window->hscrollbar)
+-            gtk_widget_queue_draw_area (child,
+-                                        0,
+-                                        alloc.height - 20,
+-                                        alloc.width,
+-                                        20);
+-        }
+-    }
+-}
+-
+-static void
+ gtk_scrolled_window_init_overlay_scrollbars (GtkScrolledWindow *scrolled_window)
+ {
+   _gtk_widget_set_captured_event_handler (GTK_WIDGET (scrolled_window),
+@@ -3592,8 +3636,43 @@ gtk_scrolled_window_overlay_scrollbars_changed (GtkSettings *settings,
+                 &priv->overlay_scrollbars,
+                 NULL);
+
++  if (priv->overlay_scrollbars)
++    gtk_scrolled_window_map_layers (GTK_SCROLLED_WINDOW (user_data));
++  else
++    gtk_scrolled_window_unmap_layers (GTK_SCROLLED_WINDOW (user_data));
++
+   gtk_widget_queue_resize (user_data);
+ }
+
++static void
++gtk_scrolled_window_map_layers (GtkScrolledWindow *scrolled_window)
++{
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  priv->vbar_layer.hidden = NO;
++  priv->vslider_layer.hidden = NO;
++
++  priv->hbar_layer.hidden = NO;
++  priv->hslider_layer.hidden = NO;
++}
++
++static void
++gtk_scrolled_window_unmap_layers (GtkScrolledWindow *scrolled_window)
++{
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  priv->vbar_layer.hidden = YES;
++  [priv->vbar_layer setNeedsDisplay];
++
++  priv->vslider_layer.hidden = YES;
++  [priv->vslider_layer setNeedsDisplay];
++
++  priv->hbar_layer.hidden = YES;
++  [priv->hbar_layer setNeedsDisplay];
++
++  priv->hslider_layer.hidden = YES;
++  [priv->hslider_layer setNeedsDisplay];
++}
++
+ #define __GTK_SCROLLED_WINDOW_C__
+ #include "gtkaliasdef.c"
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0027-Refrain-from-starting-fading-out-while-a-gesture-is-.patch b/bockbuild/mac-sdk/patches/gtk/0027-Refrain-from-starting-fading-out-while-a-gesture-is-.patch
new file mode 100644 (file)
index 0000000..7aa5471
--- /dev/null
@@ -0,0 +1,69 @@
+From d35ff9d66c8d76d509819dabc7b97972b76d7438 Mon Sep 17 00:00:00 2001
+From: Kristian Rietveld <kris@lanedo.com>
+Date: Mon, 8 Oct 2012 11:48:38 +0200
+Subject: [PATCH 27/68] Refrain from starting fading out while a gesture is in
+ progress
+
+---
+ gtk/gtkscrolledwindow.c |   20 ++++++++++++++++----
+ 1 file changed, 16 insertions(+), 4 deletions(-)
+
+diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
+index 1fba87b..a04436b 100644
+--- a/gtk/gtkscrolledwindow.c
++++ b/gtk/gtkscrolledwindow.c
+@@ -153,6 +153,7 @@ typedef struct {
+
+   gboolean       overlay_scrollbars;
+   gboolean       is_snapping_back;
++  gboolean       gesture_in_progress;
+ } GtkScrolledWindowPrivate;
+
+ #define GTK_SCROLLED_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_SCROLLED_WINDOW, GtkScrolledWindowPrivate))
+@@ -2151,7 +2152,10 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+        * FIXME: check if overshoot has really ended.
+        */
+       if (event->phase == GDK_EVENT_SCROLL_PHASE_START)
+-        priv->is_snapping_back = FALSE;
++        {
++          priv->is_snapping_back = FALSE;
++          priv->gesture_in_progress = TRUE;
++        }
+
+       if (is_momentum_event && !is_overshot)
+         gtk_scrolled_window_calculate_velocity (scrolled_window, (GdkEvent *)event);
+@@ -2291,13 +2295,20 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+        /* Reset force if gesture has ended. */
+        if (event->phase == GDK_EVENT_SCROLL_PHASE_END)
+          {
++           priv->gesture_in_progress = FALSE;
++
+            priv->x_force = 0.0;
+            priv->y_force = 0.0;
+          }
+
+-       /* Stop fade out timeout while we're overshot */
+-       if (new_overshoot_x != 0 || new_overshoot_y != 0)
++       /* Stop fade out timeout while we're overshot or while
++        * a gesture is in progress.
++        */
++       if (new_overshoot_x != 0 || new_overshoot_y != 0 ||
++           priv->gesture_in_progress)
+          gtk_scrolled_window_stop_fade_out_timeout (scrolled_window);
++       else
++         gtk_scrolled_window_start_fade_out_timeout (scrolled_window);
+
+       /* If we should start a snap back and no current deceleration
+        * is active, start the snap back.
+@@ -3598,7 +3609,8 @@ gtk_scrolled_window_start_fade_in_animation (GtkScrolledWindow *scrolled_window)
+   g_object_add_weak_pointer (G_OBJECT (priv->opacity_anim),
+                              (gpointer *) &priv->opacity_anim);
+
+-  gtk_scrolled_window_start_fade_out_timeout (scrolled_window);
++  if (!priv->gesture_in_progress)
++    gtk_scrolled_window_start_fade_out_timeout (scrolled_window);
+ }
+
+ static void
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0028-gtk-don-t-show-the-olverlay-scrollbars-if-only-the-s.patch b/bockbuild/mac-sdk/patches/gtk/0028-gtk-don-t-show-the-olverlay-scrollbars-if-only-the-s.patch
new file mode 100644 (file)
index 0000000..26bd9e5
--- /dev/null
@@ -0,0 +1,179 @@
+From 133655d890a4513783e4cb13e25770a84d5c41d8 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Fri, 2 Nov 2012 16:02:32 +0100
+Subject: [PATCH 28/68] gtk: don't show the olverlay scrollbars if only the
+ size of the content changes
+
+This commit also optimizes away many signal connections and thus
+double and triple updates.
+---
+ gtk/gtkscrolledwindow.c |   57 ++++++++++++++++++++---------------------------
+ 1 file changed, 24 insertions(+), 33 deletions(-)
+
+diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
+index a04436b..7f56793 100644
+--- a/gtk/gtkscrolledwindow.c
++++ b/gtk/gtkscrolledwindow.c
+@@ -626,9 +626,6 @@ gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
+       g_signal_handlers_disconnect_by_func (old_adjustment,
+                                             gtk_scrolled_window_adjustment_value_changed,
+                                             scrolled_window);
+-      g_signal_handlers_disconnect_by_func (old_adjustment,
+-                                            gtk_scrolled_window_update_scrollbars,
+-                                            scrolled_window);
+
+       gtk_range_set_adjustment (GTK_RANGE (scrolled_window->hscrollbar),
+                               hadjustment);
+@@ -645,13 +642,6 @@ gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
+   gtk_scrolled_window_adjustment_changed (hadjustment, scrolled_window);
+   gtk_scrolled_window_adjustment_value_changed (hadjustment, scrolled_window);
+
+-  g_signal_connect_swapped (hadjustment, "changed",
+-                            G_CALLBACK (gtk_scrolled_window_update_scrollbars),
+-                            scrolled_window);
+-  g_signal_connect_swapped (hadjustment, "value-changed",
+-                            G_CALLBACK (gtk_scrolled_window_update_scrollbars),
+-                            scrolled_window);
+-
+   if (bin->child)
+     gtk_widget_set_scroll_adjustments (bin->child,
+                                        gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
+@@ -708,9 +698,6 @@ gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
+       g_signal_handlers_disconnect_by_func (old_adjustment,
+                                             gtk_scrolled_window_adjustment_value_changed,
+                                             scrolled_window);
+-      g_signal_handlers_disconnect_by_func (old_adjustment,
+-                                            gtk_scrolled_window_update_scrollbars,
+-                                            scrolled_window);
+
+       gtk_range_set_adjustment (GTK_RANGE (scrolled_window->vscrollbar),
+                               vadjustment);
+@@ -727,13 +714,6 @@ gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
+   gtk_scrolled_window_adjustment_changed (vadjustment, scrolled_window);
+   gtk_scrolled_window_adjustment_value_changed (vadjustment, scrolled_window);
+
+-  g_signal_connect_swapped (vadjustment, "changed",
+-                            G_CALLBACK (gtk_scrolled_window_update_scrollbars),
+-                            scrolled_window);
+-  g_signal_connect_swapped (vadjustment, "value-changed",
+-                            G_CALLBACK (gtk_scrolled_window_update_scrollbars),
+-                            scrolled_window);
+-
+   if (bin->child)
+     gtk_widget_set_scroll_adjustments (bin->child,
+                                        gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
+@@ -1071,9 +1051,6 @@ gtk_scrolled_window_destroy (GtkObject *object)
+       g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
+                                             gtk_scrolled_window_adjustment_value_changed,
+                                             scrolled_window);
+-      g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
+-                                            gtk_scrolled_window_update_scrollbars,
+-                                            scrolled_window);
+
+       gtk_widget_unparent (scrolled_window->hscrollbar);
+       gtk_widget_destroy (scrolled_window->hscrollbar);
+@@ -1088,9 +1065,6 @@ gtk_scrolled_window_destroy (GtkObject *object)
+       g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)),
+                                             gtk_scrolled_window_adjustment_value_changed,
+                                             scrolled_window);
+-      g_signal_handlers_disconnect_by_func (gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)),
+-                                            gtk_scrolled_window_update_scrollbars,
+-                                            scrolled_window);
+
+       gtk_widget_unparent (scrolled_window->vscrollbar);
+       gtk_widget_destroy (scrolled_window->vscrollbar);
+@@ -1805,7 +1779,8 @@ _gtk_scrolled_window_get_overshoot (GtkScrolledWindow *scrolled_window,
+ }
+
+ static void
+-_gtk_scrolled_window_allocate_overshoot_window (GtkScrolledWindow *scrolled_window)
++_gtk_scrolled_window_allocate_overshoot_window (GtkScrolledWindow *scrolled_window,
++                                                gboolean           update_scrollbars)
+ {
+   GtkAllocation window_allocation, relative_allocation, allocation;
+   GtkScrolledWindowPrivate *priv;
+@@ -1880,7 +1855,7 @@ _gtk_scrolled_window_allocate_overshoot_window (GtkScrolledWindow *scrolled_wind
+   else
+     gdk_window_hide (priv->hbackground_window);
+
+-  if (priv->overlay_scrollbars)
++  if (priv->overlay_scrollbars && update_scrollbars)
+     {
+       gtk_scrolled_window_start_fade_in_animation (scrolled_window);
+       gtk_scrolled_window_update_scrollbars (scrolled_window);
+@@ -1948,12 +1923,15 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
+   GtkBin *bin;
+   GtkAllocation relative_allocation;
+   GtkAllocation child_allocation;
++  GtkAllocation old_allocation;
+   gboolean scrollbars_within_bevel;
+   gint scrollbar_spacing;
+
+   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
+   g_return_if_fail (allocation != NULL);
+
++  old_allocation = widget->allocation;
++
+   scrolled_window = GTK_SCROLLED_WINDOW (widget);
+   priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+   bin = GTK_BIN (scrolled_window);
+@@ -2117,7 +2095,12 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
+   else if (gtk_widget_get_visible (scrolled_window->vscrollbar))
+     gtk_widget_hide (scrolled_window->vscrollbar);
+
+-  _gtk_scrolled_window_allocate_overshoot_window (scrolled_window);
++  /* need to update the overlay scrollbars only if the allocation has
++   * actually changed, not if only the content changed
++   */
++  _gtk_scrolled_window_allocate_overshoot_window (scrolled_window,
++                                                  allocation->x != old_allocation.x ||
++                                                  allocation->y != old_allocation.y);
+ }
+
+ static gboolean
+@@ -2280,7 +2263,7 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+
+       if (old_overshoot_x != new_overshoot_x ||
+           old_overshoot_y != new_overshoot_y)
+-        _gtk_scrolled_window_allocate_overshoot_window (scrolled_window);
++        _gtk_scrolled_window_allocate_overshoot_window (scrolled_window, TRUE);
+
+       /* In two cases we want to start snapping back:
+        *  1) The view is overshot and the gesture has ended.
+@@ -2480,7 +2463,7 @@ scrolled_window_snap_back_cb (gpointer user_data)
+
+   if (old_overshoot_x != overshoot_x ||
+       old_overshoot_y != overshoot_y)
+-    _gtk_scrolled_window_allocate_overshoot_window (scrolled_window);
++    _gtk_scrolled_window_allocate_overshoot_window (scrolled_window, TRUE);
+
+   if (overshoot_x != 0 || overshoot_y != 0)
+     return TRUE;
+@@ -2960,7 +2943,12 @@ gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
+     }
+
+   if (priv->overlay_scrollbars)
+-    gtk_scrolled_window_start_fade_in_animation (scrolled_win);
++    {
++      /* dont't fade in if the extent of the content changes, but update
++       * the scrollbar's dimensions anyway.
++       */
++      gtk_scrolled_window_update_scrollbars (scrolled_win);
++    }
+ }
+
+ static void
+@@ -2983,7 +2971,10 @@ gtk_scrolled_window_adjustment_value_changed (GtkAdjustment *adjustment,
+     priv->unclamped_hadj_value = gtk_adjustment_get_value (adjustment);
+
+   if (priv->overlay_scrollbars)
+-    gtk_scrolled_window_start_fade_in_animation (scrolled_window);
++    {
++      gtk_scrolled_window_start_fade_in_animation (scrolled_window);
++      gtk_scrolled_window_update_scrollbars (scrolled_window);
++    }
+ }
+
+ static void
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0029-Reclamp-unclamped-adjustments-after-resize.patch b/bockbuild/mac-sdk/patches/gtk/0029-Reclamp-unclamped-adjustments-after-resize.patch
new file mode 100644 (file)
index 0000000..4c2b61c
--- /dev/null
@@ -0,0 +1,64 @@
+From 5d691b32e0792cce518643f2e650909101c1095d Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Thu, 8 Nov 2012 15:54:13 +0100
+Subject: [PATCH 29/68] Reclamp unclamped adjustments after resize
+
+---
+ gtk/gtkscrolledwindow.c |   28 ++++++++++++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+
+diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
+index 7f56793..09f19d9 100644
+--- a/gtk/gtkscrolledwindow.c
++++ b/gtk/gtkscrolledwindow.c
+@@ -1926,6 +1926,7 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
+   GtkAllocation old_allocation;
+   gboolean scrollbars_within_bevel;
+   gint scrollbar_spacing;
++  gint overshoot_x, overshoot_y;
+
+   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
+   g_return_if_fail (allocation != NULL);
+@@ -1936,6 +1937,10 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
+   priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+   bin = GTK_BIN (scrolled_window);
+
++  /* Save overshoot state from before resizing the child. */
++  _gtk_scrolled_window_get_overshoot (scrolled_window,
++                                      &overshoot_x, &overshoot_y);
++
+   scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
+   gtk_widget_style_get (widget, "scrollbars-within-bevel", &scrollbars_within_bevel, NULL);
+
+@@ -2095,6 +2100,29 @@ gtk_scrolled_window_size_allocate (GtkWidget     *widget,
+   else if (gtk_widget_get_visible (scrolled_window->vscrollbar))
+     gtk_widget_hide (scrolled_window->vscrollbar);
+
++  /* We have to reclamp the unclamped adjustments, otherwise the content
++   * widget might be stuck in overshot state after resizing.
++   */
++  if (overshoot_x == 0.0)
++    {
++      GtkAdjustment *hadj;
++      hadj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
++      priv->unclamped_hadj_value = CLAMP (priv->unclamped_hadj_value,
++                                          gtk_adjustment_get_lower (hadj),
++                                          gtk_adjustment_get_upper (hadj) -
++                                          gtk_adjustment_get_page_size (hadj));
++    }
++
++  if (overshoot_y == 0.0)
++    {
++      GtkAdjustment *vadj;
++      vadj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
++      priv->unclamped_vadj_value = CLAMP (priv->unclamped_vadj_value,
++                                          gtk_adjustment_get_lower (vadj),
++                                          gtk_adjustment_get_upper (vadj) -
++                                          gtk_adjustment_get_page_size (vadj));
++    }
++
+   /* need to update the overlay scrollbars only if the allocation has
+    * actually changed, not if only the content changed
+    */
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0030-gtk-fix-size_request-of-scrolled-window.patch b/bockbuild/mac-sdk/patches/gtk/0030-gtk-fix-size_request-of-scrolled-window.patch
new file mode 100644 (file)
index 0000000..1c8f968
--- /dev/null
@@ -0,0 +1,97 @@
+From 438b85d3fe83286a5ecf9c83049e5db045097507 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Thu, 22 Nov 2012 19:49:20 +0100
+Subject: [PATCH 30/68] gtk: fix size_request() of scrolled window
+
+---
+ gtk/gtkscrolledwindow.c |   41 ++++++++++++++++-------------------------
+ 1 file changed, 16 insertions(+), 25 deletions(-)
+
+diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
+index 09f19d9..77bb5af 100644
+--- a/gtk/gtkscrolledwindow.c
++++ b/gtk/gtkscrolledwindow.c
+@@ -1579,14 +1579,12 @@ gtk_scrolled_window_size_request (GtkWidget      *widget,
+   GtkRequisition hscrollbar_requisition;
+   GtkRequisition vscrollbar_requisition;
+   GtkRequisition child_requisition;
+-  GtkScrolledWindowPrivate *priv;
+
+   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
+   g_return_if_fail (requisition != NULL);
+
+   scrolled_window = GTK_SCROLLED_WINDOW (widget);
+   bin = GTK_BIN (scrolled_window);
+-  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+
+   scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
+
+@@ -1606,7 +1604,7 @@ gtk_scrolled_window_size_request (GtkWidget      *widget,
+
+       if (scrolled_window->hscrollbar_policy == GTK_POLICY_NEVER)
+       requisition->width += child_requisition.width;
+-      else if (! priv->overlay_scrollbars)
++      else
+       {
+         GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (bin->child, FALSE);
+
+@@ -1617,13 +1615,11 @@ gtk_scrolled_window_size_request (GtkWidget      *widget,
+           }
+         else
+           requisition->width += vscrollbar_requisition.width;
+-      }
+-      else
+-        requisition->width += priv->sb_width + 2 * priv->sb_padding;
++        }
+
+       if (scrolled_window->vscrollbar_policy == GTK_POLICY_NEVER)
+       requisition->height += child_requisition.height;
+-      else if (! priv->overlay_scrollbars)
++      else
+       {
+         GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (bin->child, FALSE);
+
+@@ -1634,28 +1630,23 @@ gtk_scrolled_window_size_request (GtkWidget      *widget,
+           }
+         else
+           requisition->height += hscrollbar_requisition.height;
+-      }
+-      else
+-        requisition->height += priv->sb_width + 2 * priv->sb_padding;
++        }
+     }
+
+-  if (! priv->overlay_scrollbars)
++  if (scrolled_window->hscrollbar_policy == GTK_POLICY_AUTOMATIC ||
++      scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
+     {
+-      if (scrolled_window->hscrollbar_policy == GTK_POLICY_AUTOMATIC ||
+-          scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
+-        {
+-          requisition->width = MAX (requisition->width, hscrollbar_requisition.width);
+-          if (!extra_height || scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
+-            extra_height = scrollbar_spacing + hscrollbar_requisition.height;
+-        }
++      requisition->width = MAX (requisition->width, hscrollbar_requisition.width);
++      if (!extra_height || scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
++        extra_height = scrollbar_spacing + hscrollbar_requisition.height;
++    }
+
+-      if (scrolled_window->vscrollbar_policy == GTK_POLICY_AUTOMATIC ||
+-          scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
+-        {
+-          requisition->height = MAX (requisition->height, vscrollbar_requisition.height);
+-          if (!extra_height || scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
+-            extra_width = scrollbar_spacing + vscrollbar_requisition.width;
+-        }
++  if (scrolled_window->vscrollbar_policy == GTK_POLICY_AUTOMATIC ||
++      scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
++    {
++      requisition->height = MAX (requisition->height, vscrollbar_requisition.height);
++      if (!extra_height || scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
++        extra_width = scrollbar_spacing + vscrollbar_requisition.width;
+     }
+
+   requisition->width += GTK_CONTAINER (widget)->border_width * 2 + MAX (0, extra_width);
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0031-Hackish-fix-for-bug-8493-Min-size-of-GtkScrolledWind.patch b/bockbuild/mac-sdk/patches/gtk/0031-Hackish-fix-for-bug-8493-Min-size-of-GtkScrolledWind.patch
new file mode 100644 (file)
index 0000000..eeac133
--- /dev/null
@@ -0,0 +1,68 @@
+From fd8e0fe0f9c630a56d415604c3c80dce5cd24648 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Tue, 15 Jan 2013 14:56:29 +0100
+Subject: [PATCH 31/68] Hackish fix for bug 8493 - Min size of
+ GtkScrolledWindow is too small
+
+In gtk_scrollbar_size_allocate(), pretend the scrollbar
+always has scroll arrows so the parent impl makes it a bit
+larger.
+---
+ gtk/gtkscrollbar.c |   28 ++++++++++++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+
+diff --git a/gtk/gtkscrollbar.c b/gtk/gtkscrollbar.c
+index 634b337..bab062d 100644
+--- a/gtk/gtkscrollbar.c
++++ b/gtk/gtkscrollbar.c
+@@ -32,6 +32,8 @@
+ #include "gtkprivate.h"
+ #include "gtkalias.h"
+
++static void gtk_scrollbar_size_request (GtkWidget      *widget,
++                                        GtkRequisition *requisition);
+ static void gtk_scrollbar_style_set (GtkWidget *widget,
+                                      GtkStyle  *previous);
+
+@@ -42,6 +44,7 @@ gtk_scrollbar_class_init (GtkScrollbarClass *class)
+ {
+   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+
++  widget_class->size_request = gtk_scrollbar_size_request;
+   widget_class->style_set = gtk_scrollbar_style_set;
+
+   GTK_RANGE_CLASS (class)->stepper_detail = "Xscrollbar";
+@@ -97,6 +100,31 @@ gtk_scrollbar_init (GtkScrollbar *scrollbar)
+ }
+
+ static void
++gtk_scrollbar_size_request (GtkWidget      *widget,
++                            GtkRequisition *requisition)
++{
++  GtkRange *range = GTK_RANGE (widget);
++  gboolean saved_a, saved_b, saved_c, saved_d;
++
++  saved_a = range->has_stepper_a;
++  saved_b = range->has_stepper_b;
++  saved_c = range->has_stepper_c;
++  saved_d = range->has_stepper_d;
++
++  range->has_stepper_a = TRUE;
++  range->has_stepper_b = FALSE;
++  range->has_stepper_c = FALSE;
++  range->has_stepper_d = TRUE;
++
++  GTK_WIDGET_CLASS (gtk_scrollbar_parent_class)->size_request (widget, requisition);
++
++  range->has_stepper_a = saved_a;
++  range->has_stepper_b = saved_b;
++  range->has_stepper_c = saved_c;
++  range->has_stepper_d = saved_d;
++}
++
++static void
+ gtk_scrollbar_style_set (GtkWidget *widget,
+                          GtkStyle  *previous)
+ {
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0032-Add-momentum_phase-to-GdkEventScroll.patch b/bockbuild/mac-sdk/patches/gtk/0032-Add-momentum_phase-to-GdkEventScroll.patch
new file mode 100644 (file)
index 0000000..6fb818d
--- /dev/null
@@ -0,0 +1,110 @@
+From 7e06599edaf97a91943e992f412116e6513c0c7e Mon Sep 17 00:00:00 2001
+From: Kristian Rietveld <kris@lanedo.com>
+Date: Sat, 23 Feb 2013 00:52:43 +0100
+Subject: [PATCH 32/68] Add momentum_phase to GdkEventScroll
+
+We need this for the detection of legacy mice that do emit precise
+deltas.
+---
+ gdk/gdkevents.h               |    1 +
+ gdk/gdkwindow.c               |    1 +
+ gdk/quartz/gdkevents-quartz.c |   16 ++++++++++++----
+ 3 files changed, 14 insertions(+), 4 deletions(-)
+
+diff --git a/gdk/gdkevents.h b/gdk/gdkevents.h
+index 765b520..1cbfc58 100644
+--- a/gdk/gdkevents.h
++++ b/gdk/gdkevents.h
+@@ -349,6 +349,7 @@ struct _GdkEventScroll
+   gdouble delta_x;
+   gdouble delta_y;
+   GdkEventScrollPhase phase;
++  GdkEventScrollPhase momentum_phase;
+ };
+
+ struct _GdkEventKey
+diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
+index 1dac543..7a3732c 100644
+--- a/gdk/gdkwindow.c
++++ b/gdk/gdkwindow.c
+@@ -10898,6 +10898,7 @@ proxy_button_event (GdkEvent *source_event,
+       event->scroll.delta_x = source_event->scroll.delta_x;
+       event->scroll.delta_y = source_event->scroll.delta_y;
+       event->scroll.phase = source_event->scroll.phase;
++      event->scroll.momentum_phase = source_event->scroll.momentum_phase;
+       return TRUE;
+
+     default:
+diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
+index bb4da70..f3ba2c8 100644
+--- a/gdk/quartz/gdkevents-quartz.c
++++ b/gdk/quartz/gdkevents-quartz.c
+@@ -63,6 +63,7 @@ static GdkWindow *find_toplevel_under_pointer   (GdkDisplay *display,
+ - (CGFloat) scrollingDeltaX;
+ - (CGFloat) scrollingDeltaY;
+ - (int) phase;
++- (int) momentumPhase;
+ @end
+
+
+@@ -992,6 +993,7 @@ fill_scroll_event (GdkWindow          *window,
+                    gdouble             delta_x,
+                    gdouble             delta_y,
+                    GdkEventScrollPhase phase,
++                   GdkEventScrollPhase momentum_phase,
+                    GdkScrollDirection  direction)
+ {
+   GdkWindowObject *private;
+@@ -1015,6 +1017,7 @@ fill_scroll_event (GdkWindow          *window,
+   event->scroll.delta_x = delta_x;
+   event->scroll.delta_y = delta_y;
+   event->scroll.phase = phase;
++  event->scroll.momentum_phase = momentum_phase;
+ }
+
+ static void
+@@ -1516,7 +1519,7 @@ gdk_event_translate (GdkEvent *event,
+       if (gdk_quartz_osx_version() >= GDK_OSX_LION &&
+           [(id <PreciseDeltas>) nsevent hasPreciseScrollingDeltas])
+         {
+-            GdkEventScrollPhase phase;
++            GdkEventScrollPhase phase, momentum_phase;
+           dx = [(id <PreciseDeltas>) nsevent scrollingDeltaX];
+           dy = [(id <PreciseDeltas>) nsevent scrollingDeltaY];
+
+@@ -1536,9 +1539,10 @@ gdk_event_translate (GdkEvent *event,
+               }
+
+             phase = gdk_event_scroll_phase_from_ns_event_phase ([(id <PreciseDeltas>) nsevent phase]);
++            momentum_phase = gdk_event_scroll_phase_from_ns_event_phase ([(id <PreciseDeltas>) nsevent momentumPhase]);
+
+             fill_scroll_event (window, event, nsevent, x, y, x_root, y_root,
+-                               TRUE, -dx, -dy, phase, direction);
++                               TRUE, -dx, -dy, phase, momentum_phase, direction);
+         }
+       else
+         {
+@@ -1553,7 +1557,9 @@ gdk_event_translate (GdkEvent *event,
+                   direction = GDK_SCROLL_UP;
+
+                 fill_scroll_event (window, event, nsevent, x, y, x_root, y_root,
+-                                   FALSE, 0.0, fabs (dy), GDK_EVENT_SCROLL_PHASE_NONE,
++                                   FALSE, 0.0, fabs (dy),
++                                   GDK_EVENT_SCROLL_PHASE_NONE,
++                                   GDK_EVENT_SCROLL_PHASE_NONE,
+                                    direction);
+               }
+             else if (dx != 0.0)
+@@ -1564,7 +1570,9 @@ gdk_event_translate (GdkEvent *event,
+                   direction = GDK_SCROLL_LEFT;
+
+                 fill_scroll_event (window, event, nsevent, x, y, x_root, y_root,
+-                                   FALSE, fabs (dx), 0.0, GDK_EVENT_SCROLL_PHASE_NONE,
++                                   FALSE, fabs (dx), 0.0,
++                                   GDK_EVENT_SCROLL_PHASE_NONE,
++                                   GDK_EVENT_SCROLL_PHASE_NONE,
+                                    direction);
+               }
+           }
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0033-Never-intervene-in-the-event-stream-for-legacy-mice.patch b/bockbuild/mac-sdk/patches/gtk/0033-Never-intervene-in-the-event-stream-for-legacy-mice.patch
new file mode 100644 (file)
index 0000000..91378ba
--- /dev/null
@@ -0,0 +1,39 @@
+From 4eab270368617383e2e287c434f71e037e686047 Mon Sep 17 00:00:00 2001
+From: Kristian Rietveld <kris@lanedo.com>
+Date: Sun, 17 Feb 2013 13:06:59 +0100
+Subject: [PATCH 33/68] Never intervene in the event stream for legacy mice
+
+This is necessary for devices (e.g. Mighty Mouse) which do emit
+precise deltas but no phase.
+---
+ gdk/gdkwindow.c |   10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
+index 7a3732c..2db0c0b 100644
+--- a/gdk/gdkwindow.c
++++ b/gdk/gdkwindow.c
+@@ -10849,12 +10849,20 @@ proxy_button_event (GdkEvent *source_event,
+    */
+   if (type == GDK_SCROLL && source_event->scroll.has_deltas)
+     {
++      gboolean legacy_mouse =
++          source_event->scroll.phase == GDK_EVENT_SCROLL_PHASE_NONE &&
++          source_event->scroll.momentum_phase == GDK_EVENT_SCROLL_PHASE_NONE;
++
+       if (source_event->scroll.phase == GDK_EVENT_SCROLL_PHASE_START)
+         {
+           set_last_scroll_event_windows (display, pointer_window, event_win);
+         }
+-      else
++      else if (!legacy_mouse)
+         {
++          /* Never override pointer and event windows for legacy devices
++           * which are not capable of momentum scrolling. (The windows
++           * will be NULL, because they have never been set).
++           */
+           pointer_window = g_object_get_qdata (G_OBJECT (display),
+                                                quark_last_scroll_pointer_window);
+           event_win = g_object_get_qdata (G_OBJECT (display),
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0034-Do-not-start-overshooting-for-legacy-mouse-scroll-ev.patch b/bockbuild/mac-sdk/patches/gtk/0034-Do-not-start-overshooting-for-legacy-mouse-scroll-ev.patch
new file mode 100644 (file)
index 0000000..face229
--- /dev/null
@@ -0,0 +1,73 @@
+From 06fe34a85d02df941da86e34cd1d88ef9da52a18 Mon Sep 17 00:00:00 2001
+From: Kristian Rietveld <kris@lanedo.com>
+Date: Sun, 17 Feb 2013 13:08:14 +0100
+Subject: [PATCH 34/68] Do not start overshooting for legacy mouse scroll
+ events
+
+Doing overshooting properly relies on the detection of gestures.
+For legacy devices that do emit precise deltas but no (gesture) phase,
+simply disallow overshooting so that the state machine does not get
+stuck.
+---
+ gtk/gtkscrolledwindow.c |   23 ++++++++++++++++-------
+ 1 file changed, 16 insertions(+), 7 deletions(-)
+
+diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
+index 77bb5af..4159af8 100644
+--- a/gtk/gtkscrolledwindow.c
++++ b/gtk/gtkscrolledwindow.c
+@@ -2141,7 +2141,12 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+       gint old_overshoot_x, old_overshoot_y;
+       gboolean start_snap_back = FALSE;
+       gboolean is_overshot = FALSE;
+-      gboolean is_momentum_event = event->phase == GDK_EVENT_SCROLL_PHASE_NONE;
++      gboolean is_momentum_event = event->momentum_phase != GDK_EVENT_SCROLL_PHASE_NONE;
++      gboolean legacy_mouse = FALSE;
++
++      if (event->phase == GDK_EVENT_SCROLL_PHASE_NONE &&
++          event->momentum_phase == GDK_EVENT_SCROLL_PHASE_NONE)
++        legacy_mouse = TRUE;
+
+       _gtk_scrolled_window_get_overshoot (scrolled_window,
+                                           &old_overshoot_x, &old_overshoot_y);
+@@ -2150,10 +2155,12 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+       if (old_overshoot_x != 0 || old_overshoot_y != 0)
+         is_overshot = TRUE;
+
+-      /* If a new gesture has started, reset snap back state.
++      /* If a new gesture has started or we detect the end of a momentum
++       * phase, reset snap back state.
+        * FIXME: check if overshoot has really ended.
+        */
+-      if (event->phase == GDK_EVENT_SCROLL_PHASE_START)
++      if (event->momentum_phase == GDK_EVENT_SCROLL_PHASE_END ||
++          event->phase == GDK_EVENT_SCROLL_PHASE_START)
+         {
+           priv->is_snapping_back = FALSE;
+           priv->gesture_in_progress = TRUE;
+@@ -2193,8 +2200,9 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+                */
+               adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
+               gdouble max_adj = gtk_adjustment_get_upper (adj) - gtk_adjustment_get_page_size (adj);
+-              if (gtk_adjustment_get_value (adj) < 1.0 ||
+-                  gtk_adjustment_get_value (adj) > max_adj - 1.0)
++              if (!legacy_mouse &&
++                  (gtk_adjustment_get_value (adj) < 1.0 ||
++                   gtk_adjustment_get_value (adj) > max_adj - 1.0))
+                 may_overshoot = TRUE;
+
+               if (scrolled_window->hscrollbar_visible && (is_overshot || may_overshoot))
+@@ -2240,8 +2248,9 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+                */
+               adj = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
+               gdouble max_adj = gtk_adjustment_get_upper (adj) - gtk_adjustment_get_page_size (adj);
+-              if (gtk_adjustment_get_value (adj) < 1.0 ||
+-                    gtk_adjustment_get_value (adj) > max_adj - 1.0)
++              if (!legacy_mouse &&
++                  (gtk_adjustment_get_value (adj) < 1.0 ||
++                   gtk_adjustment_get_value (adj) > max_adj - 1.0))
+                 may_overshoot = TRUE;
+
+               if (scrolled_window->vscrollbar_visible && (is_overshot || may_overshoot))
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0035-gtk-remove-the-overlay-scrollbar-grab-on-unrealize.patch b/bockbuild/mac-sdk/patches/gtk/0035-gtk-remove-the-overlay-scrollbar-grab-on-unrealize.patch
new file mode 100644 (file)
index 0000000..e88a539
--- /dev/null
@@ -0,0 +1,28 @@
+From 388e70cee0897fb743531ec001c1e6f796e2c27f Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Fri, 1 Mar 2013 15:06:20 +0100
+Subject: [PATCH 35/68] gtk: remove the overlay scrollbar grab on unrealize()
+
+---
+ gtk/gtkscrolledwindow.c |    6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
+index 4159af8..7200462 100644
+--- a/gtk/gtkscrolledwindow.c
++++ b/gtk/gtkscrolledwindow.c
+@@ -3256,6 +3256,12 @@ gtk_scrolled_window_unrealize (GtkWidget *widget)
+   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
+   GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
+
++  if (priv->sb_pointer_grabbed)
++    {
++      gtk_grab_remove (widget);
++      priv->sb_pointer_grabbed = FALSE;
++    }
++
+   gdk_window_set_user_data (priv->overshoot_window, NULL);
+   gdk_window_destroy (priv->overshoot_window);
+   priv->overshoot_window = NULL;
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0036-gtk-add-GtkScrolledWindow-API-to-disable-overshoot-p.patch b/bockbuild/mac-sdk/patches/gtk/0036-gtk-add-GtkScrolledWindow-API-to-disable-overshoot-p.patch
new file mode 100644 (file)
index 0000000..8c03063
--- /dev/null
@@ -0,0 +1,100 @@
+From 2b8a48086aee90fe60753e5b6f0c415036469f48 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Fri, 5 Apr 2013 15:15:08 +0200
+Subject: [PATCH 36/68] gtk: add GtkScrolledWindow API to disable overshoot
+ per widget
+
+And remove some forgotten declarations in the header.
+---
+ gtk/gtkscrolledwindow.c |   33 +++++++++++++++++++++++++++++++--
+ gtk/gtkscrolledwindow.h |   10 +++-------
+ 2 files changed, 34 insertions(+), 9 deletions(-)
+
+diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
+index 7200462..9def3aa 100644
+--- a/gtk/gtkscrolledwindow.c
++++ b/gtk/gtkscrolledwindow.c
+@@ -154,6 +154,7 @@ typedef struct {
+   gboolean       overlay_scrollbars;
+   gboolean       is_snapping_back;
+   gboolean       gesture_in_progress;
++  gboolean       enable_overshoot;
+ } GtkScrolledWindowPrivate;
+
+ #define GTK_SCROLLED_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_SCROLLED_WINDOW, GtkScrolledWindowPrivate))
+@@ -541,6 +542,8 @@ gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
+   priv->sb_width = 6;
+   priv->sb_fade_out_delay = 1000;
+
++  priv->enable_overshoot = TRUE;
++
+   g_signal_connect_swapped (priv->opacity, "value-changed",
+                             G_CALLBACK (gtk_scrolled_window_update_scrollbars),
+                             scrolled_window);
+@@ -2144,8 +2147,9 @@ gtk_scrolled_window_scroll_event (GtkWidget      *widget,
+       gboolean is_momentum_event = event->momentum_phase != GDK_EVENT_SCROLL_PHASE_NONE;
+       gboolean legacy_mouse = FALSE;
+
+-      if (event->phase == GDK_EVENT_SCROLL_PHASE_NONE &&
+-          event->momentum_phase == GDK_EVENT_SCROLL_PHASE_NONE)
++      if (!priv->enable_overshoot ||
++          (event->phase == GDK_EVENT_SCROLL_PHASE_NONE &&
++           event->momentum_phase == GDK_EVENT_SCROLL_PHASE_NONE))
+         legacy_mouse = TRUE;
+
+       _gtk_scrolled_window_get_overshoot (scrolled_window,
+@@ -3106,6 +3110,31 @@ gtk_scrolled_window_add_with_viewport (GtkScrolledWindow *scrolled_window,
+   gtk_container_add (GTK_CONTAINER (viewport), child);
+ }
+
++void
++gtk_scrolled_window_set_enable_overshoot (GtkScrolledWindow *scrolled_window,
++                                          gboolean           enable_overshoot)
++{
++  GtkScrolledWindowPrivate *priv;
++
++  g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
++
++  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  priv->enable_overshoot = enable_overshoot ? TRUE : FALSE;
++}
++
++gboolean
++gtk_scrolled_window_get_enable_overshoot (GtkScrolledWindow *scrolled_window)
++{
++  GtkScrolledWindowPrivate *priv;
++
++  g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), FALSE);
++
++  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  return priv->enable_overshoot;
++}
++
+ /*
+  * _gtk_scrolled_window_get_spacing:
+  * @scrolled_window: a scrolled window
+diff --git a/gtk/gtkscrolledwindow.h b/gtk/gtkscrolledwindow.h
+index 1f555e0..f75596d 100644
+--- a/gtk/gtkscrolledwindow.h
++++ b/gtk/gtkscrolledwindow.h
+@@ -127,13 +127,9 @@ GtkShadowType  gtk_scrolled_window_get_shadow_type   (GtkScrolledWindow *scrolle
+ void         gtk_scrolled_window_add_with_viewport (GtkScrolledWindow *scrolled_window,
+                                                     GtkWidget         *child);
+
+-void           gtk_scrolled_window_set_kinetic_scrolling  (GtkScrolledWindow        *scrolled_window,
+-                                                           gboolean                  kinetic_scrolling);
+-gboolean       gtk_scrolled_window_get_kinetic_scrolling  (GtkScrolledWindow        *scrolled_window);
+-
+-void           gtk_scrolled_window_set_capture_button_press (GtkScrolledWindow      *scrolled_window,
+-                                                             gboolean                capture_button_press);
+-gboolean       gtk_scrolled_window_get_capture_button_press (GtkScrolledWindow      *scrolled_window);
++void           gtk_scrolled_window_set_enable_overshoot (GtkScrolledWindow *scrolled_window,
++                                                         gboolean           enable_overshoot);
++gboolean       gtk_scrolled_window_get_enable_overshoot (GtkScrolledWindow *scrolled_window);
+
+ gint _gtk_scrolled_window_get_scrollbar_spacing (GtkScrolledWindow *scrolled_window);
+
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0037-quartz-return-events-on-embedded-foreign-NSViews-bac.patch b/bockbuild/mac-sdk/patches/gtk/0037-quartz-return-events-on-embedded-foreign-NSViews-bac.patch
new file mode 100644 (file)
index 0000000..c475ca0
--- /dev/null
@@ -0,0 +1,92 @@
+From 6437422a8153939d06563d02fc938b90f36204d0 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Fri, 23 Mar 2012 12:22:31 +0100
+Subject: [PATCH 37/68] quartz: return events on embedded foreign NSViews back
+ to Cocoa
+
+---
+ gdk/gdkmarshalers.list        |    1 +
+ gdk/gdkwindow.c               |   14 ++++++++++++++
+ gdk/quartz/gdkevents-quartz.c |   20 ++++++++++++++++++++
+ 3 files changed, 35 insertions(+)
+
+diff --git a/gdk/gdkmarshalers.list b/gdk/gdkmarshalers.list
+index ea36bae..7b37163 100644
+--- a/gdk/gdkmarshalers.list
++++ b/gdk/gdkmarshalers.list
+@@ -4,3 +4,4 @@ VOID:POINTER,POINTER,POINTER
+ OBJECT:VOID
+ OBJECT:DOUBLE,DOUBLE
+ VOID:DOUBLE,DOUBLE,POINTER,POINTER
++VOID:POINTER,POINTER
+diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
+index 2db0c0b..a6b582c 100644
+--- a/gdk/gdkwindow.c
++++ b/gdk/gdkwindow.c
+@@ -126,6 +126,7 @@ enum {
+   PICK_EMBEDDED_CHILD, /* only called if children are embedded */
+   TO_EMBEDDER,
+   FROM_EMBEDDER,
++  NATIVE_CHILD_EVENT,
+   LAST_SIGNAL
+ };
+
+@@ -595,6 +596,19 @@ gdk_window_class_init (GdkWindowObjectClass *klass)
+                 G_TYPE_DOUBLE,
+                 G_TYPE_POINTER,
+                 G_TYPE_POINTER);
++
++  signals[NATIVE_CHILD_EVENT] =
++    g_signal_new (g_intern_static_string ("native-child-event"),
++                G_OBJECT_CLASS_TYPE (object_class),
++                G_SIGNAL_RUN_LAST,
++                0,
++                NULL, NULL,
++                _gdk_marshal_VOID__POINTER_POINTER,
++                G_TYPE_NONE,
++                2,
++                G_TYPE_POINTER,
++                G_TYPE_POINTER);
++
+ }
+
+ static void
+diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
+index f3ba2c8..f6742f0 100644
+--- a/gdk/quartz/gdkevents-quartz.c
++++ b/gdk/quartz/gdkevents-quartz.c
+@@ -841,12 +841,32 @@ find_window_for_ns_event (NSEvent *nsevent,
+               {
+                 GdkWindowObject *toplevel_private;
+                 GdkWindowImplQuartz *toplevel_impl;
++                guint n_subviews;
++                guint i;
+
+                 toplevel = toplevel_under_pointer;
+
+                 toplevel_private = (GdkWindowObject *)toplevel;
+                 toplevel_impl = (GdkWindowImplQuartz *)toplevel_private->impl;
+
++                n_subviews = [[toplevel_impl->view subviews] count];
++
++                for (i = 0; i < n_subviews; ++i)
++                  {
++                    NSView* sv = [[toplevel_impl->view subviews] objectAtIndex:i];
++                    NSRect r = [sv frame];
++
++                    if (r.origin.x <= *x && r.origin.x + r.size.width >= *x &&
++                        r.origin.y <= *y && r.origin.y + r.size.height >= *y)
++                      {
++                        g_signal_emit_by_name (toplevel, "native-child-event",
++                                               sv, nsevent);
++
++                        /* event is within subview, forward back to Cocoa */
++                        return NULL;
++                      }
++                  }
++
+                 *x = x_tmp;
+                 *y = y_tmp;
+               }
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0038-quartz-don-t-forward-events-to-the-toplevel-nswindow.patch b/bockbuild/mac-sdk/patches/gtk/0038-quartz-don-t-forward-events-to-the-toplevel-nswindow.patch
new file mode 100644 (file)
index 0000000..ed76786
--- /dev/null
@@ -0,0 +1,26 @@
+From 08000a6f3a45742baa6649271f41408047dcf61c Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Thu, 28 Feb 2013 11:08:13 +0100
+Subject: [PATCH 38/68] quartz: don't forward events to the toplevel
+ nswindow's layer_view
+
+---
+ gdk/quartz/gdkevents-quartz.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
+index f6742f0..6271085 100644
+--- a/gdk/quartz/gdkevents-quartz.c
++++ b/gdk/quartz/gdkevents-quartz.c
+@@ -856,6 +856,9 @@ find_window_for_ns_event (NSEvent *nsevent,
+                     NSView* sv = [[toplevel_impl->view subviews] objectAtIndex:i];
+                     NSRect r = [sv frame];
+
++                    if (sv == toplevel_impl->layer_view)
++                      continue;
++
+                     if (r.origin.x <= *x && r.origin.x + r.size.width >= *x &&
+                         r.origin.y <= *y && r.origin.y + r.size.height >= *y)
+                       {
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0039-gdk-add-a-move-native-children-signal-to-GdkWindow.patch b/bockbuild/mac-sdk/patches/gtk/0039-gdk-add-a-move-native-children-signal-to-GdkWindow.patch
new file mode 100644 (file)
index 0000000..986c4b9
--- /dev/null
@@ -0,0 +1,50 @@
+From a790bc42e0fdaf73fbc7561f7497e5b1fbdc1f81 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Fri, 22 Feb 2013 11:05:17 +0100
+Subject: [PATCH 39/68] gdk: add a "move-native-children" signal to GdkWindow
+
+and emit it from move_native_children(), so GtkNSView has
+a chance to do the right thing on scrolling.
+---
+ gdk/gdkwindow.c |   12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
+index a6b582c..3040321 100644
+--- a/gdk/gdkwindow.c
++++ b/gdk/gdkwindow.c
+@@ -127,6 +127,7 @@ enum {
+   TO_EMBEDDER,
+   FROM_EMBEDDER,
+   NATIVE_CHILD_EVENT,
++  MOVE_NATIVE_CHILDREN,
+   LAST_SIGNAL
+ };
+
+@@ -609,6 +610,15 @@ gdk_window_class_init (GdkWindowObjectClass *klass)
+                 G_TYPE_POINTER,
+                 G_TYPE_POINTER);
+
++  signals[MOVE_NATIVE_CHILDREN] =
++    g_signal_new (g_intern_static_string ("move-native-children"),
++                  G_OBJECT_CLASS_TYPE (object_class),
++                  G_SIGNAL_RUN_LAST,
++                  0,
++                  NULL, NULL,
++                  g_cclosure_marshal_VOID__VOID,
++                  G_TYPE_NONE,
++                  0);
+ }
+
+ static void
+@@ -7474,6 +7484,8 @@ move_native_children (GdkWindowObject *private)
+       else
+       move_native_children  (child);
+     }
++
++  g_signal_emit_by_name (private, "move-native-children");
+ }
+
+ static gboolean
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0040-gtk-add-new-widget-GtkNSView-which-alows-to-embed-an.patch b/bockbuild/mac-sdk/patches/gtk/0040-gtk-add-new-widget-GtkNSView-which-alows-to-embed-an.patch
new file mode 100644 (file)
index 0000000..3b8fb37
--- /dev/null
@@ -0,0 +1,844 @@
+From 99be0cbaccfc53b374055085f778a971a5758566 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@lanedo.com>
+Date: Tue, 29 Nov 2011 16:09:31 +0100
+Subject: [PATCH 40/68] gtk: add new widget GtkNSView which alows to embed an
+ NSView
+
+---
+ gtk/Makefile.am    |    2 +
+ gtk/gtk.h          |    4 +
+ gtk/gtknsview.c    |  470 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ gtk/gtknsview.h    |   62 +++++++
+ tests/Makefile.am  |   10 +-
+ tests/testnsview.c |  190 +++++++++++++++++++++
+ 6 files changed, 737 insertions(+), 1 deletion(-)
+ create mode 100644 gtk/gtknsview.c
+ create mode 100644 gtk/gtknsview.h
+ create mode 100644 tests/testnsview.c
+
+diff --git a/gtk/Makefile.am b/gtk/Makefile.am
+index 31dfd19..59a6742 100644
+--- a/gtk/Makefile.am
++++ b/gtk/Makefile.am
+@@ -737,6 +737,7 @@ gtk_use_win32_c_sources = \
+       gtkwin32embedwidget.c \
+       gtkmountoperation-stub.c
+ gtk_use_quartz_c_sources =    \
++      gtknsview.c             \
+       gtksearchenginequartz.c \
+       gtkplug-stub.c          \
+       gtksocket-stub.c        \
+@@ -757,6 +758,7 @@ else
+ if USE_QUARTZ
+ libgtk_quartz_2_0_la_CFLAGS = "-xobjective-c"
+ gtk_private_h_sources += gtksearchenginequartz.h
++gtk_public_h_sources += gtknsview.h
+ gtk_c_sources += $(gtk_use_quartz_c_sources)
+ else
+ gtk_c_sources += $(gtk_use_stub_c_sources)
+diff --git a/gtk/gtk.h b/gtk/gtk.h
+index 94e0b61..cc5834a 100644
+--- a/gtk/gtk.h
++++ b/gtk/gtk.h
+@@ -218,6 +218,10 @@
+ #include <gtk/gtkwidget.h>
+ #include <gtk/gtkwindow.h>
+
++#ifdef GDK_WINDOWING_QUARTZ
++#include <gtk/gtknsview.h>
++#endif
++
+ /* Broken */
+ #include <gtk/gtktext.h>
+ #include <gtk/gtktree.h>
+diff --git a/gtk/gtknsview.c b/gtk/gtknsview.c
+new file mode 100644
+index 0000000..40c6a9b
+--- /dev/null
++++ b/gtk/gtknsview.c
+@@ -0,0 +1,470 @@
++/* GTK - The GIMP Toolkit
++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * GtkNSView - Native NSView embedding widget
++ * Copyright (C) 2011 Michael Natterer <mitch@lanedo.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#include "config.h"
++
++#include <gdk/gdk.h>
++#include <gdk/gdkkeysyms.h>
++#include <gdk/quartz/gdkquartz.h>
++#include <objc/runtime.h>
++
++#include "gtknsview.h"
++#include "gtkprivate.h"
++#include "gtkintl.h"
++#include "gtkalias.h"
++
++
++/* #define DEBUG_FOCUS 1 */
++
++
++enum
++{
++  PROP_0,
++  PROP_VIEW
++};
++
++
++struct _GtkNSViewPrivate
++{
++  NSView *view;
++};
++
++#define GTK_NS_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
++                                      GTK_TYPE_NS_VIEW, GtkNSViewPrivate))
++
++
++static void       gtk_ns_view_finalize      (GObject        *object);
++static void       gtk_ns_view_set_property  (GObject        *object,
++                                             guint           prop_id,
++                                             const GValue   *value,
++                                             GParamSpec     *pspec);
++static void       gtk_ns_view_get_property  (GObject        *object,
++                                             guint           prop_id,
++                                             GValue         *value,
++                                             GParamSpec     *pspec);
++static void       gtk_ns_view_notify        (GObject        *object,
++                                             GParamSpec     *pspec);
++
++static void       gtk_ns_view_unrealize     (GtkWidget      *widget);
++static void       gtk_ns_view_map           (GtkWidget      *widget);
++static void       gtk_ns_view_unmap         (GtkWidget      *widget);
++static void       gtk_ns_view_size_request  (GtkWidget      *widget,
++                                             GtkRequisition *requisition);
++static void       gtk_ns_view_size_allocate (GtkWidget      *widget,
++                                             GtkAllocation  *allocation);
++static void       gtk_ns_view_grab_focus    (GtkWidget      *widget);
++static gboolean   gtk_ns_view_key_press     (GtkWidget      *widget,
++                                             GdkEventKey    *event);
++static gboolean   gtk_ns_view_key_release   (GtkWidget      *widget,
++                                             GdkEventKey    *event);
++
++static void       gtk_ns_view_native_child_event (GdkWindow     *window,
++                                                  NSView        *view,
++                                                  NSEvent       *event,
++                                                  GtkNSView     *ns_view);
++static gboolean   gtk_ns_view_forward_event      (GtkWidget     *widget,
++                                                  GdkEventKey   *event);
++
++
++G_DEFINE_TYPE (GtkNSView, gtk_ns_view, GTK_TYPE_WIDGET)
++
++
++static void
++gtk_ns_view_class_init (GtkNSViewClass *klass)
++{
++  GObjectClass *object_class = G_OBJECT_CLASS (klass);
++  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
++
++  g_type_class_add_private (klass, sizeof (GtkNSViewPrivate));
++
++  object_class->finalize = gtk_ns_view_finalize;
++  object_class->set_property = gtk_ns_view_set_property;
++  object_class->get_property = gtk_ns_view_get_property;
++  object_class->notify = gtk_ns_view_notify;
++
++  widget_class->unrealize = gtk_ns_view_unrealize;
++  widget_class->map = gtk_ns_view_map;
++  widget_class->unmap = gtk_ns_view_unmap;
++  widget_class->size_request = gtk_ns_view_size_request;
++  widget_class->size_allocate = gtk_ns_view_size_allocate;
++  widget_class->grab_focus = gtk_ns_view_grab_focus;
++  widget_class->key_press_event = gtk_ns_view_key_press;
++  widget_class->key_release_event = gtk_ns_view_key_release;
++
++  /**
++   * GtkNSView:view:
++   *
++   * The widget's NSView.
++   *
++   * Since: 2.24
++   */
++  g_object_class_install_property (object_class,
++                                 PROP_VIEW,
++                                 g_param_spec_pointer ("view",
++                                                         P_("View"),
++                                                         P_("The NSView"),
++                                                         GTK_PARAM_READWRITE |
++                                                         G_PARAM_CONSTRUCT_ONLY));
++}
++
++static void
++gtk_ns_view_init (GtkNSView *ns_view)
++{
++  ns_view->priv = GTK_NS_VIEW_GET_PRIVATE (ns_view);
++
++  gtk_widget_set_has_window (GTK_WIDGET (ns_view), FALSE);
++}
++
++static void
++gtk_ns_view_finalize (GObject *object)
++{
++  GtkNSView *ns_view = GTK_NS_VIEW (object);
++
++  if (ns_view->priv->view)
++    {
++      [ns_view->priv->view release];
++      ns_view->priv->view = NULL;
++    }
++
++  G_OBJECT_CLASS (gtk_ns_view_parent_class)->finalize (object);
++}
++
++static void
++gtk_ns_view_set_property (GObject      *object,
++                          guint         prop_id,
++                          const GValue *value,
++                          GParamSpec   *pspec)
++{
++  GtkNSView *ns_view = GTK_NS_VIEW (object);
++
++  switch (prop_id)
++    {
++    case PROP_VIEW:
++      ns_view->priv->view = g_value_get_pointer (value);
++      if (ns_view->priv->view)
++        {
++          [ns_view->priv->view retain];
++          gtk_widget_set_can_focus (GTK_WIDGET (ns_view),
++                                    [ns_view->priv->view acceptsFirstResponder]);
++
++#if DEBUG_FOCUS
++          g_printerr ("%s can focus: %d\n",
++                      class_getName ([ns_view->priv->view class]),
++                      gtk_widget_get_can_focus (GTK_WIDGET (ns_view)));
++#endif
++        }
++      break;
++
++    default:
++      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
++      break;
++    }
++}
++
++static void
++gtk_ns_view_get_property (GObject      *object,
++                          guint         prop_id,
++                          GValue       *value,
++                          GParamSpec   *pspec)
++{
++  GtkNSView *ns_view = GTK_NS_VIEW (object);
++
++  switch (prop_id)
++    {
++    case PROP_VIEW:
++      g_value_set_pointer (value, ns_view->priv->view);
++      break;
++
++    default:
++      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
++      break;
++    }
++}
++
++static void
++gtk_ns_view_notify (GObject    *object,
++                    GParamSpec *pspec)
++{
++  GtkNSView *ns_view = GTK_NS_VIEW (object);
++
++  if (G_OBJECT_CLASS (gtk_ns_view_parent_class)->notify)
++    G_OBJECT_CLASS (gtk_ns_view_parent_class)->notify (object, pspec);
++
++  if (!strcmp (pspec->name, "has-focus"))
++    {
++      NSWindow *ns_window = [ns_view->priv->view window];
++
++#if DEBUG_FOCUS
++      g_printerr ("%s has-focus: %d\n",
++                  class_getName ([ns_view->priv->view class]),
++                  gtk_widget_has_focus (GTK_WIDGET (object)));
++#endif
++
++      if (gtk_widget_has_focus (GTK_WIDGET (object)))
++        [ns_window makeFirstResponder:ns_view->priv->view];
++      else
++        [ns_window makeFirstResponder:nil];
++    }
++}
++
++static void
++gtk_ns_view_position_view (GtkNSView     *ns_view,
++                           GtkAllocation *allocation)
++{
++  GdkWindow *window = gtk_widget_get_window (GTK_WIDGET (ns_view));
++  GdkWindow *native;
++  gdouble x, y;
++  NSSize size;
++  NSPoint origin;
++
++  x = allocation->x;
++  y = allocation->y;
++
++  /* convert to the coordinate system of the innermost parent window
++   * that has an NSView
++   */
++  native = window;
++  while (! gdk_window_has_native (native))
++    {
++      gdk_window_coords_to_parent (native, x, y, &x, &y);
++      native = gdk_window_get_parent (native);
++    }
++
++  size.width = allocation->width;
++  size.height = allocation->height;
++  [ns_view->priv->view setFrameSize:size];
++
++  origin.x = x;
++  origin.y = y;
++  [ns_view->priv->view setFrameOrigin:origin];
++}
++
++static void
++gtk_ns_view_unrealize (GtkWidget *widget)
++{
++  if (gtk_widget_get_mapped (widget))
++    gtk_widget_unmap (widget);
++
++  GTK_WIDGET_CLASS (gtk_ns_view_parent_class)->unrealize (widget);
++}
++
++static void
++gtk_ns_view_map (GtkWidget *widget)
++{
++  GtkNSView *ns_view = GTK_NS_VIEW (widget);
++  GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
++  GtkAllocation allocation;
++  NSView *parent_view;
++
++  gtk_widget_get_allocation (widget, &allocation);
++  gtk_ns_view_position_view (ns_view, &allocation);
++
++  parent_view = gdk_quartz_window_get_nsview (gtk_widget_get_window (widget));
++  [parent_view addSubview:ns_view->priv->view];
++
++  [ns_view->priv->view setNextKeyView:nil];
++
++  g_signal_connect_object (gtk_widget_get_window (toplevel), "native-child-event",
++                           G_CALLBACK (gtk_ns_view_native_child_event),
++                           G_OBJECT (widget), 0);
++
++  GTK_WIDGET_CLASS (gtk_ns_view_parent_class)->map (widget);
++}
++
++static void
++gtk_ns_view_unmap (GtkWidget *widget)
++{
++  GtkNSView *ns_view = GTK_NS_VIEW (widget);
++  GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
++
++  g_signal_handlers_disconnect_by_func (gtk_widget_get_window (toplevel),
++                                        gtk_ns_view_native_child_event,
++                                        widget);
++
++  [ns_view->priv->view removeFromSuperview];
++
++  GTK_WIDGET_CLASS (gtk_ns_view_parent_class)->unmap (widget);
++}
++
++static void
++gtk_ns_view_size_request (GtkWidget      *widget,
++                          GtkRequisition *requisition)
++{
++  requisition->width = 1;
++  requisition->height = 1;
++}
++
++static void
++gtk_ns_view_size_allocate (GtkWidget     *widget,
++                           GtkAllocation *allocation)
++{
++  GtkNSView *ns_view = GTK_NS_VIEW (widget);
++
++  widget->allocation = *allocation;
++
++  if (gtk_widget_get_mapped (widget))
++    gtk_ns_view_position_view (ns_view, allocation);
++}
++
++static void
++gtk_ns_view_grab_focus (GtkWidget *widget)
++{
++  GtkNSView *ns_view = GTK_NS_VIEW (widget);
++  NSWindow *ns_window;
++
++  GTK_WIDGET_CLASS (gtk_ns_view_parent_class)->grab_focus (widget);
++
++  ns_window = [ns_view->priv->view window];
++  [ns_window makeFirstResponder:ns_view->priv->view];
++}
++
++static gboolean
++gtk_ns_view_key_press (GtkWidget   *widget,
++                       GdkEventKey *event)
++{
++  GtkNSView *ns_view = GTK_NS_VIEW (widget);
++  NSEvent *nsevent = gdk_quartz_event_get_nsevent ((GdkEvent *) event);
++  NSWindow *ns_window;
++
++  if (gtk_ns_view_forward_event (widget, event))
++    {
++      ns_window = [ns_view->priv->view window];
++      [ns_window sendEvent:nsevent];
++
++      return TRUE;
++    }
++
++  return GTK_WIDGET_CLASS (gtk_ns_view_parent_class)->key_press_event (widget, event);
++}
++
++static gboolean
++gtk_ns_view_key_release (GtkWidget   *widget,
++                         GdkEventKey *event)
++{
++  GtkNSView *ns_view = GTK_NS_VIEW (widget);
++  NSEvent *nsevent = gdk_quartz_event_get_nsevent ((GdkEvent *) event);
++  NSWindow *ns_window;
++
++  if (gtk_ns_view_forward_event (widget, event))
++    {
++      ns_window = [ns_view->priv->view window];
++      [ns_window sendEvent:nsevent];
++
++      return TRUE;
++    }
++
++  return GTK_WIDGET_CLASS (gtk_ns_view_parent_class)->key_release_event (widget, event);
++}
++
++static void
++gtk_ns_view_native_child_event (GdkWindow *window,
++                                NSView    *view,
++                                NSEvent   *event,
++                                GtkNSView *ns_view)
++{
++  if (view == ns_view->priv->view)
++    {
++#if 0
++      g_printerr ("native child event on %s\n",
++                  class_getName ([ns_view->priv->view class]));
++#endif
++
++      switch ([event type])
++        {
++        case NSLeftMouseDown:
++          if (! gtk_widget_has_focus (GTK_WIDGET (ns_view)) &&
++
++              /*  other code can set can-focus, so check for both  */
++              gtk_widget_get_can_focus (GTK_WIDGET (ns_view)) &&
++              [ns_view->priv->view acceptsFirstResponder])
++            {
++#if DEBUG_FOCUS
++              g_printerr ("grabbing focus on %s\n",
++                          class_getName ([ns_view->priv->view class]));
++#endif
++
++              gtk_widget_grab_focus (GTK_WIDGET (ns_view));
++            }
++          break;
++
++        default:
++          break;
++        }
++    }
++}
++
++static gboolean
++gtk_ns_view_forward_event (GtkWidget   *widget,
++                           GdkEventKey *event)
++{
++  GtkNSView *ns_view = GTK_NS_VIEW (widget);
++  NSWindow *ns_window;
++  NSResponder *first_responder;
++  NSView *next_key_view;
++
++  if (event->type != GDK_KEY_PRESS ||
++      (event->keyval != GDK_KEY_Tab &&
++       event->keyval != GDK_KEY_ISO_Left_Tab))
++    {
++      return TRUE;
++    }
++
++  ns_window = [ns_view->priv->view window];
++  first_responder = [ns_window firstResponder];
++
++#if DEBUG_FOCUS
++  g_printerr ("first reponder: %p  %s\n", first_responder,
++              class_getName ([first_responder class]));
++#endif
++
++  if (event->keyval == GDK_KEY_Tab)
++    next_key_view = [first_responder nextValidKeyView];
++  else
++    next_key_view = [first_responder previousValidKeyView];
++
++#if DEBUG_FOCUS
++  g_printerr ("next key view: %p  %s\n", next_key_view,
++              class_getName ([next_key_view class]));
++#endif
++
++  if (next_key_view &&
++      next_key_view != ns_view->priv->view &&
++      [next_key_view isDescendantOf:ns_view->priv->view])
++    {
++      return TRUE;
++    }
++
++  return FALSE;
++}
++
++GtkWidget *
++gtk_ns_view_new (gpointer nsview)
++{
++  g_return_val_if_fail (nsview != NULL, NULL);
++
++  return g_object_new (GTK_TYPE_NS_VIEW,
++                       "view", nsview,
++                       NULL);
++}
++
++#define __GTK_NS_VIEW_C__
++#include "gtkaliasdef.c"
+diff --git a/gtk/gtknsview.h b/gtk/gtknsview.h
+new file mode 100644
+index 0000000..2c0aab7
+--- /dev/null
++++ b/gtk/gtknsview.h
+@@ -0,0 +1,62 @@
++/* GTK - The GIMP Toolkit
++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * GtkNSView - Native NSView embedding widget
++ * Copyright (C) 2011 Michael Natterer <mitch@lanedo.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#ifndef __GTK_NS_VIEW_H__
++#define __GTK_NS_VIEW_H__
++
++#if defined(GTK_DISABLE_SINGLE_INCLUDES) && !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
++#error "Only <gtk/gtk.h> can be included directly."
++#endif
++
++#include <gtk/gtkwidget.h>
++
++G_BEGIN_DECLS
++
++#define GTK_TYPE_NS_VIEW            (gtk_ns_view_get_type ())
++#define GTK_NS_VIEW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_NS_VIEW, GtkNSView))
++#define GTK_NS_VIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_NS_VIEW, GtkNSViewClass))
++#define GTK_IS_NS_VIEW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_NS_VIEW))
++#define GTK_IS_NS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_NS_VIEW))
++#define GTK_NS_VIEW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_NS_VIEW, GtkNSViewClass))
++
++typedef struct _GtkNSView        GtkNSView;
++typedef struct _GtkNSViewClass   GtkNSViewClass;
++typedef struct _GtkNSViewPrivate GtkNSViewPrivate;
++
++struct _GtkNSView
++{
++  GtkWidget parent_instance;
++
++  GtkNSViewPrivate *priv;
++};
++
++struct _GtkNSViewClass
++{
++  GtkWidgetClass parent_class;
++};
++
++GType       gtk_ns_view_get_type (void) G_GNUC_CONST;
++GtkWidget * gtk_ns_view_new      (gpointer  nsview);
++
++G_END_DECLS
++
++#endif /* __GTK_NS_VIEW_H__ */
+diff --git a/tests/Makefile.am b/tests/Makefile.am
+index 3888826..af098f6 100644
+--- a/tests/Makefile.am
++++ b/tests/Makefile.am
+@@ -8,7 +8,8 @@ INCLUDES =                             \
+       -DGDK_DISABLE_DEPRECATED        \
+       -DGTK_DISABLE_DEPRECATED        \
+       $(GTK_DEBUG_FLAGS)              \
+-      $(GTK_DEP_CFLAGS)
++      $(GTK_DEP_CFLAGS)               \
++      -xobjective-c
+
+ DEPS =                                                                        \
+       $(top_builddir)/gdk/$(gdktargetlib)                             \
+@@ -57,6 +58,7 @@ noinst_PROGRAMS =  $(TEST_PROGS)     \
+       testmultiscreen                 \
+       testnotebookdnd                 \
+       testnouiprint                   \
++      testnsview                      \
+       testoffscreen                   \
+       testoffscreenwindow             \
+       testorientable                  \
+@@ -134,6 +136,7 @@ testmultidisplay_DEPENDENCIES = $(TEST_DEPS)
+ testmultiscreen_DEPENDENCIES = $(TEST_DEPS)
+ testnotebookdnd_DEPENDENCIES = $(TEST_DEPS)
+ testnouiprint_DEPENDENCIES = $(TEST_DEPS)
++testnsview_DEPENDENCIES = $(TEST_DEPS)
+ testoffscreen_DEPENDENCIES = $(TEST_DEPS)
+ testoffscreenwindow_DEPENDENCIES = $(TEST_DEPS)
+ testorientable_DEPENDENCIES = $(TEST_DEPS)
+@@ -166,6 +169,8 @@ testtooltips_DEPENDENCIES = $(TEST_DEPS)
+ testvolumebutton_DEPENDENCIES = $(TEST_DEPS)
+ testwindows_DEPENDENCIES = $(TEST_DEPS)
+
++testnsview_LDFLAGS = -framework WebKit
++
+ testentrycompletion_SOURCES =         \
+       prop-editor.c           \
+       testentrycompletion.c
+@@ -262,6 +267,9 @@ testrecentchoosermenu_SOURCES =    \
+ testvolumebutton_SOURCES =    \
+       testvolumebutton.c
+
++testnsview_SOURCES =          \
++      testnsview.c
++
+ testoffscreen_SOURCES =       \
+       gtkoffscreenbox.c       \
+       gtkoffscreenbox.h       \
+diff --git a/tests/testnsview.c b/tests/testnsview.c
+new file mode 100644
+index 0000000..7c9ccb7
+--- /dev/null
++++ b/tests/testnsview.c
+@@ -0,0 +1,190 @@
++/* testnsview.c
++ * Copyright (C) 2011 Michael Natterer <mitch@lanedo.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Library 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
++ * Library General Public License for more details.
++ *
++ * You should have received a copy of the GNU Library General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#include "config.h"
++
++#include <WebKit/WebKit.h>
++#include <gtk/gtk.h>
++
++
++static void
++back_clicked (GtkToolItem *item,
++              WebView     *webview)
++{
++  [webview goBack];
++}
++
++static void
++forward_clicked (GtkToolItem *item,
++                 WebView     *webview)
++{
++  [webview goForward];
++}
++
++gint
++main (gint   argc,
++      gchar *argv[])
++{
++  GtkWidget *window;
++  GtkWidget *vbox;
++  GtkWidget *toolbar;
++  GtkToolItem *item;
++  WebView *webview;
++  NSRect web_rect = { { 0.0, 0.0 }, { 100.0, 100.0 } };
++  NSURL *url;
++  NSURLRequest *request;
++  GtkWidget *ns_view;
++
++  gtk_init (&argc, &argv);
++
++  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
++  gtk_window_set_title (GTK_WINDOW (window), "GtkNSView featuring WebView");
++
++  g_signal_connect (window, "destroy",
++                    G_CALLBACK (gtk_main_quit),
++                    NULL);
++
++  vbox = gtk_vbox_new (FALSE, 0);
++  gtk_container_add (GTK_CONTAINER (window), vbox);
++  gtk_widget_show (vbox);
++
++  toolbar = gtk_toolbar_new ();
++  gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, FALSE, 0);
++  gtk_widget_show (toolbar);
++
++  webview = [WebView alloc];
++
++  item = gtk_tool_button_new_from_stock (GTK_STOCK_GO_BACK);
++  gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
++  gtk_widget_show (GTK_WIDGET (item));
++
++  g_signal_connect (item, "clicked",
++                    G_CALLBACK (back_clicked),
++                    webview);
++
++  item = gtk_tool_button_new_from_stock (GTK_STOCK_GO_FORWARD);
++  gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
++  gtk_widget_show (GTK_WIDGET (item));
++
++  g_signal_connect (item, "clicked",
++                    G_CALLBACK (forward_clicked),
++                    webview);
++
++  [webview initWithFrame:web_rect
++               frameName:@"foo"
++               groupName:@"bar"];
++
++  url = [NSURL URLWithString:@"http://www.gimp.org/"];
++  request = [NSURLRequest requestWithURL:url];
++
++  [[webview mainFrame] loadRequest:request];
++
++  ns_view = gtk_ns_view_new ((NSView *) webview);
++  gtk_widget_set_size_request (ns_view, 300, 200);
++  gtk_box_pack_end (GTK_BOX (vbox), ns_view, TRUE, TRUE, 0);
++  gtk_widget_show (ns_view);
++
++  [webview release];
++
++  {
++    GtkWidget *button;
++
++    button = gtk_button_new_with_label ("hide webview");
++    gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0);
++    gtk_widget_show (button);
++
++    g_signal_connect_swapped (button, "clicked",
++                              G_CALLBACK (gtk_widget_hide),
++                              ns_view);
++
++    button = gtk_button_new_with_label ("show webview");
++    gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0);
++    gtk_widget_show (button);
++
++    g_signal_connect_swapped (button, "clicked",
++                              G_CALLBACK (gtk_widget_show),
++                              ns_view);
++  }
++
++  /* add an entry in an event box to test living inside another gdkwindow */
++  {
++    GtkWidget *event_box;
++    GtkWidget *abox;
++    GtkWidget *hbox;
++    NSRect label_rect = { { 0.0, 0.0 }, { 100.0, 12.0 } };
++    NSRect text_rect = { { 0.0, 0.0 }, { 100.0, 12.0 } };
++    NSTextField *text_field;
++
++    event_box = gtk_event_box_new ();
++    gtk_widget_set_state (event_box, GTK_STATE_ACTIVE);
++    gtk_box_pack_start (GTK_BOX (vbox), event_box, FALSE, FALSE, 0);
++    gtk_widget_show (event_box);
++
++    abox = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
++    gtk_container_set_border_width (GTK_CONTAINER (abox), 10);
++    gtk_container_add (GTK_CONTAINER (event_box), abox);
++    gtk_widget_show (abox);
++
++    hbox = gtk_hbox_new (FALSE, 10);
++    gtk_container_add (GTK_CONTAINER (abox), hbox);
++    gtk_widget_show (hbox);
++
++    /* a non-editable text label */
++    text_field = [[NSTextField alloc] initWithFrame:label_rect];
++    [text_field setEditable:NO];
++    [text_field setDrawsBackground:NO];
++    [text_field setBordered:NO];
++    [text_field setStringValue:@"A Text Label"];
++
++    ns_view = gtk_ns_view_new ((NSView *) text_field);
++    gtk_widget_set_size_request (ns_view, 100, 20);
++    gtk_box_pack_start (GTK_BOX (hbox), ns_view, FALSE, FALSE, 0);
++    gtk_widget_show (ns_view);
++
++    [text_field release];
++
++    /* an editable text field */
++    text_field = [[NSTextField alloc] initWithFrame:text_rect];
++    [text_field setEditable:YES];
++    [text_field setStringValue:@"An editable text entry"];
++
++    ns_view = gtk_ns_view_new ((NSView *) text_field);
++    gtk_widget_set_size_request (ns_view, 100, 20);
++    gtk_box_pack_start (GTK_BOX (hbox), ns_view, TRUE, TRUE, 0);
++    gtk_widget_show (ns_view);
++
++    [text_field release];
++  }
++
++  /* and a normal GtkEntry to check focus */
++  {
++    GtkWidget *entry;
++
++    entry = gtk_entry_new ();
++    gtk_entry_set_text (GTK_ENTRY (entry), "Normal GTK+ entry");
++    gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
++    gtk_widget_show (entry);
++  }
++
++  gtk_widget_show (window);
++
++  gtk_main ();
++
++  return 0;
++}
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0041-tests-add-a-notebook-to-testnsview.c.patch b/bockbuild/mac-sdk/patches/gtk/0041-tests-add-a-notebook-to-testnsview.c.patch
new file mode 100644 (file)
index 0000000..e7f6fd7
--- /dev/null
@@ -0,0 +1,59 @@
+From 9e267bd60da4235a0facb6bab98fef5884bc0ff0 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Tue, 12 Feb 2013 13:22:39 +0100
+Subject: [PATCH 41/68] tests: add a notebook to testnsview.c
+
+---
+ tests/testnsview.c |   17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/tests/testnsview.c b/tests/testnsview.c
+index 7c9ccb7..45b1d60 100644
+--- a/tests/testnsview.c
++++ b/tests/testnsview.c
+@@ -45,6 +45,7 @@ main (gint   argc,
+   GtkWidget *vbox;
+   GtkWidget *toolbar;
+   GtkToolItem *item;
++  GtkWidget *notebook;
+   WebView *webview;
+   NSRect web_rect = { { 0.0, 0.0 }, { 100.0, 100.0 } };
+   NSURL *url;
+@@ -86,6 +87,10 @@ main (gint   argc,
+                     G_CALLBACK (forward_clicked),
+                     webview);
+
++  notebook = gtk_notebook_new ();
++  gtk_box_pack_end (GTK_BOX (vbox), notebook, TRUE, TRUE, 0);
++  gtk_widget_show (notebook);
++
+   [webview initWithFrame:web_rect
+                frameName:@"foo"
+                groupName:@"bar"];
+@@ -97,12 +102,24 @@ main (gint   argc,
+
+   ns_view = gtk_ns_view_new ((NSView *) webview);
+   gtk_widget_set_size_request (ns_view, 300, 200);
++#if 0
+   gtk_box_pack_end (GTK_BOX (vbox), ns_view, TRUE, TRUE, 0);
++#else
++  gtk_notebook_append_page (GTK_NOTEBOOK (notebook), ns_view,
++                            gtk_label_new ("WebView"));
++#endif
+   gtk_widget_show (ns_view);
+
+   [webview release];
+
+   {
++    GtkWidget *useless = gtk_label_new ("Useless Label");
++    gtk_notebook_append_page (GTK_NOTEBOOK (notebook), useless,
++                              gtk_label_new ("Useless"));
++    gtk_widget_show (useless);
++  }
++
++  {
+     GtkWidget *button;
+
+     button = gtk_button_new_with_label ("hide webview");
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0042-gtk-connect-GtkNSView-to-move-native-children-and-re.patch b/bockbuild/mac-sdk/patches/gtk/0042-gtk-connect-GtkNSView-to-move-native-children-and-re.patch
new file mode 100644 (file)
index 0000000..651e32a
--- /dev/null
@@ -0,0 +1,76 @@
+From 87d285a9e186e7745d4f3a2b2e6a489b1b803b94 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Fri, 22 Feb 2013 11:06:26 +0100
+Subject: [PATCH 42/68] gtk: connect GtkNSView to "move-native-children" and
+ reposition
+
+---
+ gtk/gtknsview.c |   32 ++++++++++++++++++++++++++------
+ 1 file changed, 26 insertions(+), 6 deletions(-)
+
+diff --git a/gtk/gtknsview.c b/gtk/gtknsview.c
+index 40c6a9b..a19a94e 100644
+--- a/gtk/gtknsview.c
++++ b/gtk/gtknsview.c
+@@ -77,12 +77,14 @@ static gboolean   gtk_ns_view_key_press     (GtkWidget      *widget,
+ static gboolean   gtk_ns_view_key_release   (GtkWidget      *widget,
+                                              GdkEventKey    *event);
+
+-static void       gtk_ns_view_native_child_event (GdkWindow     *window,
+-                                                  NSView        *view,
+-                                                  NSEvent       *event,
+-                                                  GtkNSView     *ns_view);
+-static gboolean   gtk_ns_view_forward_event      (GtkWidget     *widget,
+-                                                  GdkEventKey   *event);
++static void       gtk_ns_view_native_child_event   (GdkWindow     *window,
++                                                    NSView        *view,
++                                                    NSEvent       *event,
++                                                    GtkNSView     *ns_view);
++static void       gtk_ns_view_move_native_children (GdkWindow     *window,
++                                                    GtkNSView     *ns_view);
++static gboolean   gtk_ns_view_forward_event        (GtkWidget     *widget,
++                                                    GdkEventKey   *event);
+
+
+ G_DEFINE_TYPE (GtkNSView, gtk_ns_view, GTK_TYPE_WIDGET)
+@@ -287,6 +289,10 @@ gtk_ns_view_map (GtkWidget *widget)
+                            G_CALLBACK (gtk_ns_view_native_child_event),
+                            G_OBJECT (widget), 0);
+
++  g_signal_connect_object (gtk_widget_get_window (widget), "move-native-children",
++                           G_CALLBACK (gtk_ns_view_move_native_children),
++                           G_OBJECT (widget), 0);
++
+   GTK_WIDGET_CLASS (gtk_ns_view_parent_class)->map (widget);
+ }
+
+@@ -296,6 +302,10 @@ gtk_ns_view_unmap (GtkWidget *widget)
+   GtkNSView *ns_view = GTK_NS_VIEW (widget);
+   GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
+
++  g_signal_handlers_disconnect_by_func (gtk_widget_get_window (widget),
++                                        gtk_ns_view_move_native_children,
++                                        widget);
++
+   g_signal_handlers_disconnect_by_func (gtk_widget_get_window (toplevel),
+                                         gtk_ns_view_native_child_event,
+                                         widget);
+@@ -412,6 +422,16 @@ gtk_ns_view_native_child_event (GdkWindow *window,
+     }
+ }
+
++static void
++gtk_ns_view_move_native_children (GdkWindow *window,
++                                  GtkNSView *ns_view)
++{
++  GtkAllocation allocation;
++
++  gtk_widget_get_allocation (GTK_WIDGET (ns_view), &allocation);
++  gtk_ns_view_position_view (ns_view, &allocation);
++}
++
+ static gboolean
+ gtk_ns_view_forward_event (GtkWidget   *widget,
+                            GdkEventKey *event)
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0043-tests-add-a-scrolled-window-test-widget-to-testnsvie.patch b/bockbuild/mac-sdk/patches/gtk/0043-tests-add-a-scrolled-window-test-widget-to-testnsvie.patch
new file mode 100644 (file)
index 0000000..f43d40f
--- /dev/null
@@ -0,0 +1,74 @@
+From aa3e5322000437f02e04916abf278dbbc407a403 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Fri, 22 Feb 2013 11:06:58 +0100
+Subject: [PATCH 43/68] tests: add a scrolled window test widget to
+ testnsview.c
+
+---
+ tests/testnsview.c |   51 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 51 insertions(+)
+
+diff --git a/tests/testnsview.c b/tests/testnsview.c
+index 45b1d60..1a523e6 100644
+--- a/tests/testnsview.c
++++ b/tests/testnsview.c
+@@ -139,6 +139,57 @@ main (gint   argc,
+                               ns_view);
+   }
+
++  /* add an entry in a scrolled window to test scrolling / clipping */
++  {
++    GtkWidget *sw;
++    GtkWidget *abox;
++    GtkWidget *hbox;
++    NSRect label_rect = { { 0.0, 0.0 }, { 100.0, 12.0 } };
++    NSRect text_rect = { { 0.0, 0.0 }, { 100.0, 12.0 } };
++    NSTextField *text_field;
++
++    sw = gtk_scrolled_window_new (NULL, NULL);
++    gtk_widget_set_size_request (sw, -1, 100);
++    gtk_box_pack_start (GTK_BOX (vbox), sw, FALSE, FALSE, 0);
++    gtk_widget_show (sw);
++
++    abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
++    gtk_widget_set_size_request (abox, -1, 200);
++    gtk_container_set_border_width (GTK_CONTAINER (abox), 10);
++    gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw), abox);
++    gtk_widget_show (abox);
++
++    hbox = gtk_hbox_new (FALSE, 10);
++    gtk_container_add (GTK_CONTAINER (abox), hbox);
++    gtk_widget_show (hbox);
++
++    /* a non-editable text label */
++    text_field = [[NSTextField alloc] initWithFrame:label_rect];
++    [text_field setEditable:NO];
++    [text_field setDrawsBackground:NO];
++    [text_field setBordered:NO];
++    [text_field setStringValue:@"A Text Label"];
++
++    ns_view = gtk_ns_view_new ((NSView *) text_field);
++    gtk_widget_set_size_request (ns_view, 100, 20);
++    gtk_box_pack_start (GTK_BOX (hbox), ns_view, FALSE, FALSE, 0);
++    gtk_widget_show (ns_view);
++
++    [text_field release];
++
++    /* an editable text field */
++    text_field = [[NSTextField alloc] initWithFrame:text_rect];
++    [text_field setEditable:YES];
++    [text_field setStringValue:@"An editable text entry"];
++
++    ns_view = gtk_ns_view_new ((NSView *) text_field);
++    gtk_widget_set_size_request (ns_view, 100, 20);
++    gtk_box_pack_start (GTK_BOX (hbox), ns_view, TRUE, TRUE, 0);
++    gtk_widget_show (ns_view);
++
++    [text_field release];
++  }
++
+   /* add an entry in an event box to test living inside another gdkwindow */
+   {
+     GtkWidget *event_box;
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0044-gtknsview-clip-drawRect-to-a-parent-GtkViewport-s-wi.patch b/bockbuild/mac-sdk/patches/gtk/0044-gtknsview-clip-drawRect-to-a-parent-GtkViewport-s-wi.patch
new file mode 100644 (file)
index 0000000..0adb0e1
--- /dev/null
@@ -0,0 +1,180 @@
+From 08f7cca62c0a810d1bd5eaf52813b9ecb776478e Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Fri, 1 Mar 2013 12:39:41 +0100
+Subject: [PATCH 44/68] gtknsview: clip drawRect to a parent GtkViewport's
+ window
+
+not quite perfect yet, but getting there...
+---
+ gtk/gtknsview.c |  121 +++++++++++++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 109 insertions(+), 12 deletions(-)
+
+diff --git a/gtk/gtknsview.c b/gtk/gtknsview.c
+index a19a94e..84d758f 100644
+--- a/gtk/gtknsview.c
++++ b/gtk/gtknsview.c
+@@ -28,6 +28,7 @@
+ #include <objc/runtime.h>
+
+ #include "gtknsview.h"
++#include "gtkviewport.h"
+ #include "gtkprivate.h"
+ #include "gtkintl.h"
+ #include "gtkalias.h"
+@@ -52,6 +53,7 @@ struct _GtkNSViewPrivate
+                                       GTK_TYPE_NS_VIEW, GtkNSViewPrivate))
+
+
++static void       gtk_ns_view_constructed   (GObject        *object);
+ static void       gtk_ns_view_finalize      (GObject        *object);
+ static void       gtk_ns_view_set_property  (GObject        *object,
+                                              guint           prop_id,
+@@ -89,7 +91,6 @@ static gboolean   gtk_ns_view_forward_event        (GtkWidget     *widget,
+
+ G_DEFINE_TYPE (GtkNSView, gtk_ns_view, GTK_TYPE_WIDGET)
+
+-
+ static void
+ gtk_ns_view_class_init (GtkNSViewClass *klass)
+ {
+@@ -98,6 +99,7 @@ gtk_ns_view_class_init (GtkNSViewClass *klass)
+
+   g_type_class_add_private (klass, sizeof (GtkNSViewPrivate));
+
++  object_class->constructed = gtk_ns_view_constructed;
+   object_class->finalize = gtk_ns_view_finalize;
+   object_class->set_property = gtk_ns_view_set_property;
+   object_class->get_property = gtk_ns_view_get_property;
+@@ -136,6 +138,111 @@ gtk_ns_view_init (GtkNSView *ns_view)
+   gtk_widget_set_has_window (GTK_WIDGET (ns_view), FALSE);
+ }
+
++@implementation NSView (myDrawRect)
++- (void) myDrawRect: (NSRect) dirtyRect
++{
++  GtkNSView *ns_view;
++  GtkWidget *viewport;
++
++#if 0
++  g_printerr ("drawRect called\n");
++#endif
++
++  ns_view = (GtkNSView *) objc_getAssociatedObject (self, "gtknsview");
++
++  if (! ns_view)
++    {
++      [self myDrawRect: dirtyRect];
++      return;
++    }
++
++  viewport = gtk_widget_get_ancestor (GTK_WIDGET (ns_view), GTK_TYPE_VIEWPORT);
++
++  if (viewport)
++    {
++      CGContextRef cg_context = [[NSGraphicsContext currentContext] graphicsPort];
++      GtkAllocation viewport_allocation;
++      CGRect rect;
++
++#if 0
++      g_printerr ("drawRect called on gtknsview in gtkviewport\n");
++#endif
++
++      gtk_widget_get_allocation (viewport, &viewport_allocation);
++
++      if (gtk_viewport_get_shadow_type (GTK_VIEWPORT (viewport)) != GTK_SHADOW_NONE)
++        {
++          GtkStyle *style = gtk_widget_get_style (viewport);
++
++          viewport_allocation.x += style->xthickness;
++          viewport_allocation.y += style->ythickness;
++          viewport_allocation.width -= 2 * style->xthickness;
++          viewport_allocation.height -= 2 * style->ythickness;
++        }
++
++      gtk_widget_translate_coordinates (viewport, GTK_WIDGET (ns_view),
++                                        viewport_allocation.x,
++                                        viewport_allocation.y,
++                                        &viewport_allocation.x,
++                                        &viewport_allocation.y);
++
++      rect.origin.x = viewport_allocation.x;
++      rect.origin.y = viewport_allocation.y;
++      rect.size.width = viewport_allocation.width;
++      rect.size.height = viewport_allocation.height;
++
++      CGContextSaveGState (cg_context);
++      CGContextClipToRect (cg_context, rect);
++
++      [self myDrawRect: dirtyRect];
++
++      CGContextRestoreGState (cg_context);
++    }
++  else
++    {
++      [self myDrawRect: dirtyRect];
++    }
++}
++@end
++
++static void
++gtk_ns_view_constructed (GObject *object)
++{
++  GtkNSView *ns_view = GTK_NS_VIEW (object);
++  Method original_drawRect;
++  Method my_drawRect;
++
++  G_OBJECT_CLASS (gtk_ns_view_parent_class)->constructed (object);
++
++  gtk_widget_set_can_focus (GTK_WIDGET (ns_view),
++                            [ns_view->priv->view acceptsFirstResponder]);
++
++#if DEBUG_FOCUS
++  g_printerr ("%s can focus: %d\n",
++              class_getName ([ns_view->priv->view class]),
++              gtk_widget_get_can_focus (GTK_WIDGET (ns_view)));
++#endif
++
++  original_drawRect = class_getInstanceMethod ([ns_view->priv->view class],
++                                               @selector (drawRect:));
++  my_drawRect = class_getInstanceMethod ([ns_view->priv->view class],
++                                         @selector (myDrawRect:));
++
++  if (class_addMethod ([ns_view->priv->view class],
++                       @selector (myDrawRect:),
++                       method_getImplementation (original_drawRect),
++                       method_getTypeEncoding (original_drawRect)))
++    {
++      class_replaceMethod ([ns_view->priv->view class],
++                           @selector (drawRect:),
++                           method_getImplementation (my_drawRect),
++                           method_getTypeEncoding (my_drawRect));
++    }
++
++  objc_setAssociatedObject (ns_view->priv->view, "gtknsview", (id) ns_view,
++                            OBJC_ASSOCIATION_ASSIGN);
++}
++
+ static void
+ gtk_ns_view_finalize (GObject *object)
+ {
+@@ -163,17 +270,7 @@ gtk_ns_view_set_property (GObject      *object,
+     case PROP_VIEW:
+       ns_view->priv->view = g_value_get_pointer (value);
+       if (ns_view->priv->view)
+-        {
+-          [ns_view->priv->view retain];
+-          gtk_widget_set_can_focus (GTK_WIDGET (ns_view),
+-                                    [ns_view->priv->view acceptsFirstResponder]);
+-
+-#if DEBUG_FOCUS
+-          g_printerr ("%s can focus: %d\n",
+-                      class_getName ([ns_view->priv->view class]),
+-                      gtk_widget_get_can_focus (GTK_WIDGET (ns_view)));
+-#endif
+-        }
++        [ns_view->priv->view retain];
+       break;
+
+     default:
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0045-gtk-clip-NSViews-to-the-scrolled-window-s-overshoot_.patch b/bockbuild/mac-sdk/patches/gtk/0045-gtk-clip-NSViews-to-the-scrolled-window-s-overshoot_.patch
new file mode 100644 (file)
index 0000000..529d195
--- /dev/null
@@ -0,0 +1,78 @@
+From 24caf0db2af4d43a2d8bf1cd6dff7e54d5268502 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Thu, 14 Mar 2013 16:54:38 +0100
+Subject: [PATCH 45/68] gtk: clip NSViews to the scrolled window's
+ overshoot_window
+
+not to the viewport's allocation. This is ugly but by far the
+easiest way to get clipping right.
+---
+ gtk/gtknsview.c    |   31 +++++++++++++++++++++++++++++++
+ tests/testnsview.c |    3 ++-
+ 2 files changed, 33 insertions(+), 1 deletion(-)
+
+diff --git a/gtk/gtknsview.c b/gtk/gtknsview.c
+index 84d758f..db1da93 100644
+--- a/gtk/gtknsview.c
++++ b/gtk/gtknsview.c
+@@ -160,6 +160,7 @@ gtk_ns_view_init (GtkNSView *ns_view)
+
+   if (viewport)
+     {
++      GdkWindow *window;
+       CGContextRef cg_context = [[NSGraphicsContext currentContext] graphicsPort];
+       GtkAllocation viewport_allocation;
+       CGRect rect;
+@@ -170,6 +171,36 @@ gtk_ns_view_init (GtkNSView *ns_view)
+
+       gtk_widget_get_allocation (viewport, &viewport_allocation);
+
++#if 0
++      g_printerr ("viewport allocation: %d, %d (%d x %x)\n",
++                  viewport_allocation.x,
++                  viewport_allocation.y,
++                  viewport_allocation.width,
++                  viewport_allocation.height);
++#endif
++
++      /* evil: don't clip to the viewport's width/height but to that
++       * of its parent window, because we know we hacked an
++       * overshoot_window into GtkScrolledWindow and need to restrict
++       * rendering in its area
++       */
++      window = gtk_widget_get_parent_window (viewport);
++
++      viewport_allocation.width = gdk_window_get_width (window);
++      viewport_allocation.height = gdk_window_get_height (window);
++
++#if 0
++      {
++        gint x, y;
++
++        gdk_window_get_position (window, &x, &y);
++        g_printerr ("viewport parent window at %d, %d (%x x %x)\n",
++                    x, y,
++                    gdk_window_get_width (window),
++                    gdk_window_get_height (window));
++      }
++#endif
++
+       if (gtk_viewport_get_shadow_type (GTK_VIEWPORT (viewport)) != GTK_SHADOW_NONE)
+         {
+           GtkStyle *style = gtk_widget_get_style (viewport);
+diff --git a/tests/testnsview.c b/tests/testnsview.c
+index 1a523e6..24d1d41 100644
+--- a/tests/testnsview.c
++++ b/tests/testnsview.c
+@@ -149,7 +149,8 @@ main (gint   argc,
+     NSTextField *text_field;
+
+     sw = gtk_scrolled_window_new (NULL, NULL);
+-    gtk_widget_set_size_request (sw, -1, 100);
++    gtk_widget_set_size_request (sw, -1, 130);
++    gtk_container_set_border_width (GTK_CONTAINER (sw), 20);
+     gtk_box_pack_start (GTK_BOX (vbox), sw, FALSE, FALSE, 0);
+     gtk_widget_show (sw);
+
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0046-gtk-implement-clipping-to-multiple-parent-viewports-.patch b/bockbuild/mac-sdk/patches/gtk/0046-gtk-implement-clipping-to-multiple-parent-viewports-.patch
new file mode 100644 (file)
index 0000000..d7bfaaa
--- /dev/null
@@ -0,0 +1,108 @@
+From ab0bb7104783da5155361e6fbd89ee14f25e2544 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Thu, 14 Mar 2013 20:10:51 +0100
+Subject: [PATCH 46/68] gtk: implement clipping to multiple parent viewports
+ in GtkNSView
+
+---
+ gtk/gtknsview.c |   51 +++++++++++----------------------------------------
+ 1 file changed, 11 insertions(+), 40 deletions(-)
+
+diff --git a/gtk/gtknsview.c b/gtk/gtknsview.c
+index db1da93..1e0b7e6 100644
+--- a/gtk/gtknsview.c
++++ b/gtk/gtknsview.c
+@@ -143,10 +143,7 @@ gtk_ns_view_init (GtkNSView *ns_view)
+ {
+   GtkNSView *ns_view;
+   GtkWidget *viewport;
+-
+-#if 0
+-  g_printerr ("drawRect called\n");
+-#endif
++  CGContextRef cg_context;
+
+   ns_view = (GtkNSView *) objc_getAssociatedObject (self, "gtknsview");
+
+@@ -156,51 +153,30 @@ gtk_ns_view_init (GtkNSView *ns_view)
+       return;
+     }
+
+-  viewport = gtk_widget_get_ancestor (GTK_WIDGET (ns_view), GTK_TYPE_VIEWPORT);
++  cg_context = [[NSGraphicsContext currentContext] graphicsPort];
++  CGContextSaveGState (cg_context);
+
+-  if (viewport)
++  for (viewport = gtk_widget_get_ancestor (GTK_WIDGET (ns_view), GTK_TYPE_VIEWPORT);
++       viewport;
++       viewport = gtk_widget_get_ancestor (gtk_widget_get_parent (viewport),
++                                           GTK_TYPE_VIEWPORT))
+     {
+       GdkWindow *window;
+-      CGContextRef cg_context = [[NSGraphicsContext currentContext] graphicsPort];
+       GtkAllocation viewport_allocation;
+       CGRect rect;
+
+-#if 0
+-      g_printerr ("drawRect called on gtknsview in gtkviewport\n");
+-#endif
+-
+       gtk_widget_get_allocation (viewport, &viewport_allocation);
+
+-#if 0
+-      g_printerr ("viewport allocation: %d, %d (%d x %x)\n",
+-                  viewport_allocation.x,
+-                  viewport_allocation.y,
+-                  viewport_allocation.width,
+-                  viewport_allocation.height);
+-#endif
+-
+       /* evil: don't clip to the viewport's width/height but to that
+        * of its parent window, because we know we hacked an
+        * overshoot_window into GtkScrolledWindow and need to restrict
+-       * rendering in its area
++       * rendering to its area
+        */
+       window = gtk_widget_get_parent_window (viewport);
+
+       viewport_allocation.width = gdk_window_get_width (window);
+       viewport_allocation.height = gdk_window_get_height (window);
+
+-#if 0
+-      {
+-        gint x, y;
+-
+-        gdk_window_get_position (window, &x, &y);
+-        g_printerr ("viewport parent window at %d, %d (%x x %x)\n",
+-                    x, y,
+-                    gdk_window_get_width (window),
+-                    gdk_window_get_height (window));
+-      }
+-#endif
+-
+       if (gtk_viewport_get_shadow_type (GTK_VIEWPORT (viewport)) != GTK_SHADOW_NONE)
+         {
+           GtkStyle *style = gtk_widget_get_style (viewport);
+@@ -222,17 +198,12 @@ gtk_ns_view_init (GtkNSView *ns_view)
+       rect.size.width = viewport_allocation.width;
+       rect.size.height = viewport_allocation.height;
+
+-      CGContextSaveGState (cg_context);
+       CGContextClipToRect (cg_context, rect);
++    }
+
+-      [self myDrawRect: dirtyRect];
++  [self myDrawRect: dirtyRect];
+
+-      CGContextRestoreGState (cg_context);
+-    }
+-  else
+-    {
+-      [self myDrawRect: dirtyRect];
+-    }
++  CGContextRestoreGState (cg_context);
+ }
+ @end
+
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0047-gtk-first-attempt-to-also-clip-NSWindow-s-field-edit.patch b/bockbuild/mac-sdk/patches/gtk/0047-gtk-first-attempt-to-also-clip-NSWindow-s-field-edit.patch
new file mode 100644 (file)
index 0000000..de1ffb3
--- /dev/null
@@ -0,0 +1,142 @@
+From 56e863ef4b425c1ac79e53d35f9b8b9649cec7d3 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Fri, 15 Mar 2013 14:49:59 +0100
+Subject: [PATCH 47/68] gtk: first attempt to also clip NSWindow's field
+ editor
+
+Also, factor out the method swizzling to a utility function.
+---
+ gtk/gtknsview.c |   75 ++++++++++++++++++++++++++++++++++++++++++-------------
+ 1 file changed, 58 insertions(+), 17 deletions(-)
+
+diff --git a/gtk/gtknsview.c b/gtk/gtknsview.c
+index 1e0b7e6..b58a2c8 100644
+--- a/gtk/gtknsview.c
++++ b/gtk/gtknsview.c
+@@ -29,6 +29,7 @@
+
+ #include "gtknsview.h"
+ #include "gtkviewport.h"
++#include "gtkwindow.h"
+ #include "gtkprivate.h"
+ #include "gtkintl.h"
+ #include "gtkalias.h"
+@@ -147,6 +148,22 @@ gtk_ns_view_init (GtkNSView *ns_view)
+
+   ns_view = (GtkNSView *) objc_getAssociatedObject (self, "gtknsview");
+
++  if (! ns_view && ([self class] == [NSTextView class]))
++    {
++      /*  if it's not a GtkNSView, check if it's the NSWindow's cell
++       *  editor editing an NSTextField managed by a GtkNSView
++       */
++      GtkWindow *window = (GtkWindow *) objc_getAssociatedObject (self, "gtkwindow");
++
++      if (GTK_IS_WINDOW (window))
++        {
++          GtkWidget *focus = gtk_window_get_focus (window);
++
++          if (GTK_IS_NS_VIEW (focus))
++            ns_view = GTK_NS_VIEW (focus);
++        }
++    }
++
+   if (! ns_view)
+     {
+       [self myDrawRect: dirtyRect];
+@@ -208,38 +225,45 @@ gtk_ns_view_init (GtkNSView *ns_view)
+ @end
+
+ static void
+-gtk_ns_view_constructed (GObject *object)
++gtk_ns_view_swizzle_draw_rect (NSView *view)
+ {
+-  GtkNSView *ns_view = GTK_NS_VIEW (object);
+   Method original_drawRect;
+   Method my_drawRect;
+
+-  G_OBJECT_CLASS (gtk_ns_view_parent_class)->constructed (object);
+-
+-  gtk_widget_set_can_focus (GTK_WIDGET (ns_view),
+-                            [ns_view->priv->view acceptsFirstResponder]);
+-
+-#if DEBUG_FOCUS
+-  g_printerr ("%s can focus: %d\n",
+-              class_getName ([ns_view->priv->view class]),
+-              gtk_widget_get_can_focus (GTK_WIDGET (ns_view)));
+-#endif
+-
+-  original_drawRect = class_getInstanceMethod ([ns_view->priv->view class],
++  original_drawRect = class_getInstanceMethod ([view class],
+                                                @selector (drawRect:));
+-  my_drawRect = class_getInstanceMethod ([ns_view->priv->view class],
++  my_drawRect = class_getInstanceMethod ([view class],
+                                          @selector (myDrawRect:));
+
+-  if (class_addMethod ([ns_view->priv->view class],
++  if (class_addMethod ([view class],
+                        @selector (myDrawRect:),
+                        method_getImplementation (original_drawRect),
+                        method_getTypeEncoding (original_drawRect)))
+     {
+-      class_replaceMethod ([ns_view->priv->view class],
++      class_replaceMethod ([view class],
+                            @selector (drawRect:),
+                            method_getImplementation (my_drawRect),
+                            method_getTypeEncoding (my_drawRect));
+     }
++}
++
++static void
++gtk_ns_view_constructed (GObject *object)
++{
++  GtkNSView *ns_view = GTK_NS_VIEW (object);
++
++  G_OBJECT_CLASS (gtk_ns_view_parent_class)->constructed (object);
++
++  gtk_widget_set_can_focus (GTK_WIDGET (ns_view),
++                            [ns_view->priv->view acceptsFirstResponder]);
++
++#if DEBUG_FOCUS
++  g_printerr ("%s can focus: %d\n",
++              class_getName ([ns_view->priv->view class]),
++              gtk_widget_get_can_focus (GTK_WIDGET (ns_view)));
++#endif
++
++  gtk_ns_view_swizzle_draw_rect (ns_view->priv->view);
+
+   objc_setAssociatedObject (ns_view->priv->view, "gtknsview", (id) ns_view,
+                             OBJC_ASSOCIATION_ASSIGN);
+@@ -375,6 +399,7 @@ gtk_ns_view_map (GtkWidget *widget)
+   GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
+   GtkAllocation allocation;
+   NSView *parent_view;
++  NSWindow *window;
+
+   gtk_widget_get_allocation (widget, &allocation);
+   gtk_ns_view_position_view (ns_view, &allocation);
+@@ -393,6 +418,22 @@ gtk_ns_view_map (GtkWidget *widget)
+                            G_OBJECT (widget), 0);
+
+   GTK_WIDGET_CLASS (gtk_ns_view_parent_class)->map (widget);
++
++  window = [ns_view->priv->view window];
++
++  if (window)
++    {
++      NSText *text = [window fieldEditor: YES
++                               forObject: nil];
++
++      if (text)
++        {
++          gtk_ns_view_swizzle_draw_rect (text);
++
++          objc_setAssociatedObject (text, "gtkwindow", (id) toplevel,
++                                    OBJC_ASSOCIATION_ASSIGN);
++        }
++    }
+ }
+
+ static void
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0048-gtk-also-clip-the-NSView-s-subviews.patch b/bockbuild/mac-sdk/patches/gtk/0048-gtk-also-clip-the-NSView-s-subviews.patch
new file mode 100644 (file)
index 0000000..ce8f7a6
--- /dev/null
@@ -0,0 +1,75 @@
+From 20bf51d57fecdc6783aa3edee50a657243aa872a Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Fri, 15 Mar 2013 16:56:59 +0100
+Subject: [PATCH 48/68] gtk: also clip the NSView's subviews
+
+---
+ gtk/gtknsview.c |   29 ++++++++++++++++++++---------
+ 1 file changed, 20 insertions(+), 9 deletions(-)
+
+diff --git a/gtk/gtknsview.c b/gtk/gtknsview.c
+index b58a2c8..e2d8f96 100644
+--- a/gtk/gtknsview.c
++++ b/gtk/gtknsview.c
+@@ -225,10 +225,14 @@ gtk_ns_view_init (GtkNSView *ns_view)
+ @end
+
+ static void
+-gtk_ns_view_swizzle_draw_rect (NSView *view)
++gtk_ns_view_swizzle_draw_rect_recursive (NSView      *view,
++                                         const gchar *associated_key,
++                                         gpointer     associated_object)
+ {
+   Method original_drawRect;
+   Method my_drawRect;
++  NSArray *subviews;
++  gint i;
+
+   original_drawRect = class_getInstanceMethod ([view class],
+                                                @selector (drawRect:));
+@@ -245,6 +249,18 @@ gtk_ns_view_swizzle_draw_rect (NSView *view)
+                            method_getImplementation (my_drawRect),
+                            method_getTypeEncoding (my_drawRect));
+     }
++
++  objc_setAssociatedObject (view, associated_key, (id) associated_object,
++                            OBJC_ASSOCIATION_ASSIGN);
++
++  subviews = [view subviews];
++
++  for (i = 0; i < [subviews count]; i++)
++    {
++      gtk_ns_view_swizzle_draw_rect_recursive ([subviews objectAtIndex: i],
++                                               associated_key,
++                                               associated_object);
++    }
+ }
+
+ static void
+@@ -263,10 +279,8 @@ gtk_ns_view_constructed (GObject *object)
+               gtk_widget_get_can_focus (GTK_WIDGET (ns_view)));
+ #endif
+
+-  gtk_ns_view_swizzle_draw_rect (ns_view->priv->view);
+-
+-  objc_setAssociatedObject (ns_view->priv->view, "gtknsview", (id) ns_view,
+-                            OBJC_ASSOCIATION_ASSIGN);
++  gtk_ns_view_swizzle_draw_rect_recursive (ns_view->priv->view,
++                                           "gtknsview", ns_view);
+ }
+
+ static void
+@@ -428,10 +442,7 @@ gtk_ns_view_map (GtkWidget *widget)
+
+       if (text)
+         {
+-          gtk_ns_view_swizzle_draw_rect (text);
+-
+-          objc_setAssociatedObject (text, "gtkwindow", (id) toplevel,
+-                                    OBJC_ASSOCIATION_ASSIGN);
++          gtk_ns_view_swizzle_draw_rect_recursive (text, "gtkwindow", toplevel);
+         }
+     }
+ }
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0049-nsview-also-swizzle-DidAddSubview-and-clip-all-subvi.patch b/bockbuild/mac-sdk/patches/gtk/0049-nsview-also-swizzle-DidAddSubview-and-clip-all-subvi.patch
new file mode 100644 (file)
index 0000000..a378568
--- /dev/null
@@ -0,0 +1,119 @@
+From ef95f0fc2917e98ea48ea5a07031b6e4b4152634 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Thu, 25 Apr 2013 12:22:28 +0200
+Subject: [PATCH 49/68] nsview: also swizzle DidAddSubview and clip all
+ subviews that are added
+
+Finally makes textviews being clipped correctly. Original patch
+from Kris, I fixed a minor clipping off-by-something.
+---
+ gtk/gtknsview.c |   63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 62 insertions(+), 1 deletion(-)
+
+diff --git a/gtk/gtknsview.c b/gtk/gtknsview.c
+index e2d8f96..bc3cbfb 100644
+--- a/gtk/gtknsview.c
++++ b/gtk/gtknsview.c
+@@ -139,6 +139,25 @@ gtk_ns_view_init (GtkNSView *ns_view)
+   gtk_widget_set_has_window (GTK_WIDGET (ns_view), FALSE);
+ }
+
++
++static void   gtk_ns_view_swizzle_draw_rect_recursive (NSView      *view,
++                                                       const gchar *associated_key,
++                                                       gpointer     associated_object);
++
++@implementation NSView (myDidAddSubview)
++- (void) myDidAddSubview:(NSView *)aView
++{
++  void *associated_object;
++
++  associated_object = objc_getAssociatedObject (self, "gtknsview");
++
++  if (associated_object)
++    gtk_ns_view_swizzle_draw_rect_recursive (aView, "gtknsview", associated_object);
++
++  [self myDidAddSubview:aView];
++}
++@end
++
+ @implementation NSView (myDrawRect)
+ - (void) myDrawRect: (NSRect) dirtyRect
+ {
+@@ -164,7 +183,8 @@ gtk_ns_view_init (GtkNSView *ns_view)
+         }
+     }
+
+-  if (! ns_view)
++  if (! ns_view ||
++      ns_view->priv->view != [ns_view->priv->view ancestorSharedWithView: self])
+     {
+       [self myDrawRect: dirtyRect];
+       return;
+@@ -215,6 +235,18 @@ gtk_ns_view_init (GtkNSView *ns_view)
+       rect.size.width = viewport_allocation.width;
+       rect.size.height = viewport_allocation.height;
+
++      /*  need to translate rect if this is not the view itself but a subview  */
++      if (ns_view->priv->view != self)
++        {
++          NSRect offset = NSMakeRect (0, 0, 0, 0);
++
++          offset = [ns_view->priv->view convertRect: offset
++                                           fromView: self];
++
++          rect.origin.x -= offset.origin.x;
++          rect.origin.y -= offset.origin.y;
++        }
++
+       CGContextClipToRect (cg_context, rect);
+     }
+
+@@ -231,9 +263,20 @@ gtk_ns_view_swizzle_draw_rect_recursive (NSView      *view,
+ {
+   Method original_drawRect;
+   Method my_drawRect;
++  Method original_didAddSubview;
++  Method my_didAddSubview;
+   NSArray *subviews;
+   gint i;
+
++  /* This is a private method that disable automatic focus ring handling.
++   * It looks like automatic focus ring drawing is handled by a toplevel
++   * NSView, so it cannot be caught by our clipping. If we disable this
++   * automatic handling, the focus ring appears to be drawn locally and
++   * is affected by our clipping.
++   */
++  [view _setAutomaticFocusRingDisabled:YES];
++
++  /* Swizzle drawRect */
+   original_drawRect = class_getInstanceMethod ([view class],
+                                                @selector (drawRect:));
+   my_drawRect = class_getInstanceMethod ([view class],
+@@ -250,6 +293,24 @@ gtk_ns_view_swizzle_draw_rect_recursive (NSView      *view,
+                            method_getTypeEncoding (my_drawRect));
+     }
+
++  /* Swizzle didAddSubView */
++  original_didAddSubview = class_getInstanceMethod ([view class],
++                                                    @selector (didAddSubview:));
++  my_didAddSubview = class_getInstanceMethod ([view class],
++                                              @selector (myDidAddSubview:));
++
++  if (class_addMethod ([view class],
++                       @selector (myDidAddSubview:),
++                       method_getImplementation (original_didAddSubview),
++                       method_getTypeEncoding (original_didAddSubview)))
++    {
++      class_replaceMethod ([view class],
++                           @selector (didAddSubview:),
++                           method_getImplementation (my_didAddSubview),
++                           method_getTypeEncoding (my_didAddSubview));
++    }
++
++
+   objc_setAssociatedObject (view, associated_key, (id) associated_object,
+                             OBJC_ASSOCIATION_ASSIGN);
+
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0050-nsview-clip-text-field-cursor-drawing.patch b/bockbuild/mac-sdk/patches/gtk/0050-nsview-clip-text-field-cursor-drawing.patch
new file mode 100644 (file)
index 0000000..a28cba6
--- /dev/null
@@ -0,0 +1,221 @@
+From daf0f5ecb7b9a71d93d7e41b000369d977ea4816 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Thu, 25 Apr 2013 14:52:18 +0200
+Subject: [PATCH 50/68] nsview: clip text field cursor drawing
+
+by replacing (not "normal" swizzling) drawInsertionPointInRect. This
+fixes cursor clipping for the *blinking* cursor, but not if the
+cusor moves. Patch patially from Kris..
+---
+ gtk/gtknsview.c |  162 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 159 insertions(+), 3 deletions(-)
+
+diff --git a/gtk/gtknsview.c b/gtk/gtknsview.c
+index bc3cbfb..5e3aa59 100644
+--- a/gtk/gtknsview.c
++++ b/gtk/gtknsview.c
+@@ -145,14 +145,23 @@ static void   gtk_ns_view_swizzle_draw_rect_recursive (NSView      *view,
+                                                        gpointer     associated_object);
+
+ @implementation NSView (myDidAddSubview)
+-- (void) myDidAddSubview:(NSView *)aView
++- (void) myDidAddSubview: (NSView *) aView
+ {
+   void *associated_object;
+
+   associated_object = objc_getAssociatedObject (self, "gtknsview");
+
+   if (associated_object)
+-    gtk_ns_view_swizzle_draw_rect_recursive (aView, "gtknsview", associated_object);
++    {
++      gtk_ns_view_swizzle_draw_rect_recursive (aView, "gtknsview", associated_object);
++    }
++  else
++    {
++      associated_object = objc_getAssociatedObject (self, "gtkwindow");
++
++      if (associated_object)
++        gtk_ns_view_swizzle_draw_rect_recursive (aView, "gtkwindow", associated_object);
++    }
+
+   [self myDidAddSubview:aView];
+ }
+@@ -256,6 +265,110 @@ static void   gtk_ns_view_swizzle_draw_rect_recursive (NSView      *view,
+ }
+ @end
+
++@implementation NSTextView (myDrawInsertionPointInRect)
++- (void) myDrawInsertionPointInRect: (NSRect) aRect
++                              color: (NSColor *) aColor
++                           turnedOn: (BOOL) flag
++{
++  GtkNSView *ns_view;
++  GtkWidget *viewport;
++  CGContextRef cg_context;
++
++  ns_view = (GtkNSView *) objc_getAssociatedObject (self, "gtknsview");
++
++  if (! ns_view && ([self class] == [NSTextView class]))
++    {
++      /*  if it's not a GtkNSView, check if it's the NSWindow's cell
++       *  editor editing an NSTextField managed by a GtkNSView
++       */
++      GtkWindow *window = (GtkWindow *) objc_getAssociatedObject (self, "gtkwindow");
++
++      if (GTK_IS_WINDOW (window))
++        {
++          GtkWidget *focus = gtk_window_get_focus (window);
++
++          if (GTK_IS_NS_VIEW (focus))
++            ns_view = GTK_NS_VIEW (focus);
++        }
++    }
++
++  if (! ns_view ||
++      ns_view->priv->view != [ns_view->priv->view ancestorSharedWithView: self])
++    {
++      [self myDrawInsertionPointInRect: aRect
++                                 color: aColor
++                              turnedOn: flag];
++      return;
++    }
++
++  cg_context = [[NSGraphicsContext currentContext] graphicsPort];
++  CGContextSaveGState (cg_context);
++
++  for (viewport = gtk_widget_get_ancestor (GTK_WIDGET (ns_view), GTK_TYPE_VIEWPORT);
++       viewport;
++       viewport = gtk_widget_get_ancestor (gtk_widget_get_parent (viewport),
++                                           GTK_TYPE_VIEWPORT))
++    {
++      GdkWindow *window;
++      GtkAllocation viewport_allocation;
++      CGRect rect;
++
++      gtk_widget_get_allocation (viewport, &viewport_allocation);
++
++      /* evil: don't clip to the viewport's width/height but to that
++       * of its parent window, because we know we hacked an
++       * overshoot_window into GtkScrolledWindow and need to restrict
++       * rendering to its area
++       */
++      window = gtk_widget_get_parent_window (viewport);
++
++      viewport_allocation.width = gdk_window_get_width (window);
++      viewport_allocation.height = gdk_window_get_height (window);
++
++      if (gtk_viewport_get_shadow_type (GTK_VIEWPORT (viewport)) != GTK_SHADOW_NONE)
++        {
++          GtkStyle *style = gtk_widget_get_style (viewport);
++
++          viewport_allocation.x += style->xthickness;
++          viewport_allocation.y += style->ythickness;
++          viewport_allocation.width -= 2 * style->xthickness;
++          viewport_allocation.height -= 2 * style->ythickness;
++        }
++
++      gtk_widget_translate_coordinates (viewport, GTK_WIDGET (ns_view),
++                                        viewport_allocation.x,
++                                        viewport_allocation.y,
++                                        &viewport_allocation.x,
++                                        &viewport_allocation.y);
++
++      rect.origin.x = viewport_allocation.x;
++      rect.origin.y = viewport_allocation.y;
++      rect.size.width = viewport_allocation.width;
++      rect.size.height = viewport_allocation.height;
++
++      /*  need to translate rect if this is not the view itself but a subview  */
++      if (ns_view->priv->view != self)
++        {
++          NSRect offset = NSMakeRect (0, 0, 0, 0);
++
++          offset = [ns_view->priv->view convertRect: offset
++                                           fromView: self];
++
++          rect.origin.x -= offset.origin.x;
++          rect.origin.y -= offset.origin.y;
++        }
++
++      CGContextClipToRect (cg_context, rect);
++    }
++
++  [self myDrawInsertionPointInRect: aRect
++                             color: aColor
++                          turnedOn: flag];
++
++  CGContextRestoreGState (cg_context);
++}
++@end
++
+ static void
+ gtk_ns_view_swizzle_draw_rect_recursive (NSView      *view,
+                                          const gchar *associated_key,
+@@ -310,7 +423,6 @@ gtk_ns_view_swizzle_draw_rect_recursive (NSView      *view,
+                            method_getTypeEncoding (my_didAddSubview));
+     }
+
+-
+   objc_setAssociatedObject (view, associated_key, (id) associated_object,
+                             OBJC_ASSOCIATION_ASSIGN);
+
+@@ -325,6 +437,49 @@ gtk_ns_view_swizzle_draw_rect_recursive (NSView      *view,
+ }
+
+ static void
++gtk_ns_view_replace_draw_insertion_point (void)
++{
++  static volatile gsize draw_insertion_point_replaced = 0;
++
++  /* We replace the drawInsertPointInRect:color:turnedOn: method of the
++   * NSTextView class. This should only be done once per application
++   * instance.
++   */
++
++  if (g_once_init_enter (&draw_insertion_point_replaced))
++    {
++      Method original_drawInsertionPointInRect;
++      Method my_drawInsertionPointInRect;
++      IMP original_implementation;
++      Class text_view_class = [NSTextView class];
++
++      /* Get the original method and an explicit reference to the
++       * implementation behind this method. This because after the
++       * first replace method call, the method will point at a different
++       * implementation.
++       */
++      original_drawInsertionPointInRect = class_getInstanceMethod (text_view_class,
++                                                                   @selector (drawInsertionPointInRect:color:turnedOn:));
++      original_implementation = method_getImplementation (original_drawInsertionPointInRect);
++
++      my_drawInsertionPointInRect = class_getInstanceMethod (text_view_class,
++                                                             @selector (myDrawInsertionPointInRect:color:turnedOn:));
++
++      class_replaceMethod (text_view_class,
++                           @selector (drawInsertionPointInRect:color:turnedOn:),
++                           method_getImplementation (my_drawInsertionPointInRect),
++                           method_getTypeEncoding (my_drawInsertionPointInRect));
++
++      class_replaceMethod (text_view_class,
++                           @selector (myDrawInsertionPointInRect:color:turnedOn:),
++                           original_implementation,
++                           method_getTypeEncoding (original_drawInsertionPointInRect));
++
++      g_once_init_leave (&draw_insertion_point_replaced, TRUE);
++    }
++}
++
++static void
+ gtk_ns_view_constructed (GObject *object)
+ {
+   GtkNSView *ns_view = GTK_NS_VIEW (object);
+@@ -340,6 +495,7 @@ gtk_ns_view_constructed (GObject *object)
+               gtk_widget_get_can_focus (GTK_WIDGET (ns_view)));
+ #endif
+
++  gtk_ns_view_replace_draw_insertion_point ();
+   gtk_ns_view_swizzle_draw_rect_recursive (ns_view->priv->view,
+                                            "gtknsview", ns_view);
+ }
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0051-nsview-factor-out-almost-all-code-from-the-overridde.patch b/bockbuild/mac-sdk/patches/gtk/0051-nsview-factor-out-almost-all-code-from-the-overridde.patch
new file mode 100644 (file)
index 0000000..8b77e6b
--- /dev/null
@@ -0,0 +1,227 @@
+From 478d022cd553d33de59ec8ce22605b14a3837264 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Fri, 26 Apr 2013 15:50:14 +0200
+Subject: [PATCH 51/68] nsview: factor out almost all code from the overridden
+ draw functions
+
+---
+ gtk/gtknsview.c |  151 +++++++++++++++++--------------------------------------
+ 1 file changed, 47 insertions(+), 104 deletions(-)
+
+diff --git a/gtk/gtknsview.c b/gtk/gtknsview.c
+index 5e3aa59..b37b2fa 100644
+--- a/gtk/gtknsview.c
++++ b/gtk/gtknsview.c
+@@ -167,21 +167,19 @@ static void   gtk_ns_view_swizzle_draw_rect_recursive (NSView      *view,
+ }
+ @end
+
+-@implementation NSView (myDrawRect)
+-- (void) myDrawRect: (NSRect) dirtyRect
++static GtkNSView *
++get_associated_gtknsview (NSView *view)
+ {
+   GtkNSView *ns_view;
+-  GtkWidget *viewport;
+-  CGContextRef cg_context;
+
+-  ns_view = (GtkNSView *) objc_getAssociatedObject (self, "gtknsview");
++  ns_view = (GtkNSView *) objc_getAssociatedObject (view, "gtknsview");
+
+-  if (! ns_view && ([self class] == [NSTextView class]))
++  if (! ns_view && ([view class] == [NSTextView class]))
+     {
+       /*  if it's not a GtkNSView, check if it's the NSWindow's cell
+        *  editor editing an NSTextField managed by a GtkNSView
+        */
+-      GtkWindow *window = (GtkWindow *) objc_getAssociatedObject (self, "gtkwindow");
++      GtkWindow *window = (GtkWindow *) objc_getAssociatedObject (view, "gtkwindow");
+
+       if (GTK_IS_WINDOW (window))
+         {
+@@ -192,15 +190,21 @@ static void   gtk_ns_view_swizzle_draw_rect_recursive (NSView      *view,
+         }
+     }
+
+-  if (! ns_view ||
+-      ns_view->priv->view != [ns_view->priv->view ancestorSharedWithView: self])
++  if (ns_view &&
++      ns_view->priv->view != [ns_view->priv->view ancestorSharedWithView: view])
+     {
+-      [self myDrawRect: dirtyRect];
+-      return;
++      return NULL;
+     }
+
+-  cg_context = [[NSGraphicsContext currentContext] graphicsPort];
+-  CGContextSaveGState (cg_context);
++  return ns_view;
++}
++
++static CGContextRef
++clip_to_parent_viewports (GtkNSView *ns_view,
++                          NSView    *view)
++{
++  CGContextRef cg_context = nil;
++  GtkWidget *viewport;
+
+   for (viewport = gtk_widget_get_ancestor (GTK_WIDGET (ns_view), GTK_TYPE_VIEWPORT);
+        viewport;
+@@ -245,23 +249,44 @@ static void   gtk_ns_view_swizzle_draw_rect_recursive (NSView      *view,
+       rect.size.height = viewport_allocation.height;
+
+       /*  need to translate rect if this is not the view itself but a subview  */
+-      if (ns_view->priv->view != self)
++      if (ns_view->priv->view != view)
+         {
+           NSRect offset = NSMakeRect (0, 0, 0, 0);
+
+           offset = [ns_view->priv->view convertRect: offset
+-                                           fromView: self];
++                                           fromView: view];
+
+           rect.origin.x -= offset.origin.x;
+           rect.origin.y -= offset.origin.y;
+         }
+
++      if (! cg_context)
++        {
++          cg_context = [[NSGraphicsContext currentContext] graphicsPort];
++          CGContextSaveGState (cg_context);
++        }
++
+       CGContextClipToRect (cg_context, rect);
+     }
+
++  return cg_context;
++}
++
++@implementation NSView (myDrawRect)
++- (void) myDrawRect: (NSRect) dirtyRect
++{
++  GtkNSView *ns_view;
++  CGContextRef cg_context = nil;
++
++  ns_view = get_associated_gtknsview (self);
++
++  if (ns_view)
++    cg_context = clip_to_parent_viewports (ns_view, self);
++
+   [self myDrawRect: dirtyRect];
+
+-  CGContextRestoreGState (cg_context);
++  if (cg_context)
++    CGContextRestoreGState (cg_context);
+ }
+ @end
+
+@@ -271,101 +296,19 @@ static void   gtk_ns_view_swizzle_draw_rect_recursive (NSView      *view,
+                            turnedOn: (BOOL) flag
+ {
+   GtkNSView *ns_view;
+-  GtkWidget *viewport;
+-  CGContextRef cg_context;
+-
+-  ns_view = (GtkNSView *) objc_getAssociatedObject (self, "gtknsview");
+-
+-  if (! ns_view && ([self class] == [NSTextView class]))
+-    {
+-      /*  if it's not a GtkNSView, check if it's the NSWindow's cell
+-       *  editor editing an NSTextField managed by a GtkNSView
+-       */
+-      GtkWindow *window = (GtkWindow *) objc_getAssociatedObject (self, "gtkwindow");
+-
+-      if (GTK_IS_WINDOW (window))
+-        {
+-          GtkWidget *focus = gtk_window_get_focus (window);
+-
+-          if (GTK_IS_NS_VIEW (focus))
+-            ns_view = GTK_NS_VIEW (focus);
+-        }
+-    }
+-
+-  if (! ns_view ||
+-      ns_view->priv->view != [ns_view->priv->view ancestorSharedWithView: self])
+-    {
+-      [self myDrawInsertionPointInRect: aRect
+-                                 color: aColor
+-                              turnedOn: flag];
+-      return;
+-    }
+-
+-  cg_context = [[NSGraphicsContext currentContext] graphicsPort];
+-  CGContextSaveGState (cg_context);
+-
+-  for (viewport = gtk_widget_get_ancestor (GTK_WIDGET (ns_view), GTK_TYPE_VIEWPORT);
+-       viewport;
+-       viewport = gtk_widget_get_ancestor (gtk_widget_get_parent (viewport),
+-                                           GTK_TYPE_VIEWPORT))
+-    {
+-      GdkWindow *window;
+-      GtkAllocation viewport_allocation;
+-      CGRect rect;
+-
+-      gtk_widget_get_allocation (viewport, &viewport_allocation);
+-
+-      /* evil: don't clip to the viewport's width/height but to that
+-       * of its parent window, because we know we hacked an
+-       * overshoot_window into GtkScrolledWindow and need to restrict
+-       * rendering to its area
+-       */
+-      window = gtk_widget_get_parent_window (viewport);
+-
+-      viewport_allocation.width = gdk_window_get_width (window);
+-      viewport_allocation.height = gdk_window_get_height (window);
+-
+-      if (gtk_viewport_get_shadow_type (GTK_VIEWPORT (viewport)) != GTK_SHADOW_NONE)
+-        {
+-          GtkStyle *style = gtk_widget_get_style (viewport);
+-
+-          viewport_allocation.x += style->xthickness;
+-          viewport_allocation.y += style->ythickness;
+-          viewport_allocation.width -= 2 * style->xthickness;
+-          viewport_allocation.height -= 2 * style->ythickness;
+-        }
+-
+-      gtk_widget_translate_coordinates (viewport, GTK_WIDGET (ns_view),
+-                                        viewport_allocation.x,
+-                                        viewport_allocation.y,
+-                                        &viewport_allocation.x,
+-                                        &viewport_allocation.y);
++  CGContextRef cg_context = nil;;
+
+-      rect.origin.x = viewport_allocation.x;
+-      rect.origin.y = viewport_allocation.y;
+-      rect.size.width = viewport_allocation.width;
+-      rect.size.height = viewport_allocation.height;
++  ns_view = get_associated_gtknsview (self);
+
+-      /*  need to translate rect if this is not the view itself but a subview  */
+-      if (ns_view->priv->view != self)
+-        {
+-          NSRect offset = NSMakeRect (0, 0, 0, 0);
+-
+-          offset = [ns_view->priv->view convertRect: offset
+-                                           fromView: self];
+-
+-          rect.origin.x -= offset.origin.x;
+-          rect.origin.y -= offset.origin.y;
+-        }
+-
+-      CGContextClipToRect (cg_context, rect);
+-    }
++  if (ns_view)
++    cg_context = clip_to_parent_viewports (ns_view, self);
+
+   [self myDrawInsertionPointInRect: aRect
+                              color: aColor
+                           turnedOn: flag];
+
+-  CGContextRestoreGState (cg_context);
++  if (cg_context)
++    CGContextRestoreGState (cg_context);
+ }
+ @end
+
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0052-nsview-also-focus-the-GtkNSView-if-a-focussable-subv.patch b/bockbuild/mac-sdk/patches/gtk/0052-nsview-also-focus-the-GtkNSView-if-a-focussable-subv.patch
new file mode 100644 (file)
index 0000000..479fd04
--- /dev/null
@@ -0,0 +1,49 @@
+From 6bf17cdaffe648ce53dd39619c3ff9a65d272831 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Fri, 5 Jul 2013 11:49:22 +0200
+Subject: [PATCH 52/68] nsview: also focus the GtkNSView if a focussable
+ subview was clicked
+
+---
+ gtk/gtknsview.c |   22 +++++++++++++++-------
+ 1 file changed, 15 insertions(+), 7 deletions(-)
+
+diff --git a/gtk/gtknsview.c b/gtk/gtknsview.c
+index b37b2fa..3b30d3b 100644
+--- a/gtk/gtknsview.c
++++ b/gtk/gtknsview.c
+@@ -713,17 +713,25 @@ gtk_ns_view_native_child_event (GdkWindow *window,
+         {
+         case NSLeftMouseDown:
+           if (! gtk_widget_has_focus (GTK_WIDGET (ns_view)) &&
+-
+-              /*  other code can set can-focus, so check for both  */
+-              gtk_widget_get_can_focus (GTK_WIDGET (ns_view)) &&
+-              [ns_view->priv->view acceptsFirstResponder])
++              gtk_widget_get_can_focus (GTK_WIDGET (ns_view)))
+             {
++              NSPoint point = [[view superview ] convertPoint: [event locationInWindow]
++                                                     fromView: nil];
++              NSView *hit   = [view hitTest: point];
++
++              if (hit &&
++                  (hit == view ||
++                   [hit ancestorSharedWithView: view] == view) &&
++                  ([hit acceptsFirstResponder] ||
++                   [view acceptsFirstResponder]))
++                {
+ #if DEBUG_FOCUS
+-              g_printerr ("grabbing focus on %s\n",
+-                          class_getName ([ns_view->priv->view class]));
++                  g_printerr ("grabbing focus on %s\n",
++                              class_getName ([ns_view->priv->view class]));
+ #endif
+
+-              gtk_widget_grab_focus (GTK_WIDGET (ns_view));
++                  gtk_widget_grab_focus (GTK_WIDGET (ns_view));
++                }
+             }
+           break;
+
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0053-gtk-add-an-overlay-policy-API-to-GtkScrolledWindow.patch b/bockbuild/mac-sdk/patches/gtk/0053-gtk-add-an-overlay-policy-API-to-GtkScrolledWindow.patch
new file mode 100644 (file)
index 0000000..794a5c4
--- /dev/null
@@ -0,0 +1,159 @@
+From 3e4fba4264957d704d9c01496eef57e897b7d691 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Fri, 3 May 2013 11:55:51 +0200
+Subject: [PATCH 53/68] gtk: add an "overlay policy" API to GtkScrolledWindow
+
+which allows to turn off drawing of the overlay scrollbars,
+while keeping scrolling enabled.
+---
+ gtk/gtkscrolledwindow.c |   68 ++++++++++++++++++++++++++++++++++++++++++-----
+ gtk/gtkscrolledwindow.h |    6 +++++
+ 2 files changed, 68 insertions(+), 6 deletions(-)
+
+diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
+index 9def3aa..a643b7d 100644
+--- a/gtk/gtkscrolledwindow.c
++++ b/gtk/gtkscrolledwindow.c
+@@ -121,6 +121,9 @@ typedef struct {
+   gdouble                unclamped_hadj_value;
+   gdouble                unclamped_vadj_value;
+
++  GtkPolicyType  hoverlay_policy;
++  GtkPolicyType  voverlay_policy;
++
+   GtkAllocation  viewport_allocation;
+   CALayer       *vbar_layer;
+   CALayer       *hbar_layer;
+@@ -536,6 +539,9 @@ gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
+                                 NULL);
+   g_object_ref_sink (priv->opacity);
+
++  priv->hoverlay_policy = GTK_POLICY_AUTOMATIC;
++  priv->voverlay_policy = GTK_POLICY_AUTOMATIC;
++
+   priv->sb_min_height = 20;
+   priv->sb_padding = 2;
+   priv->sb_radius = 3;
+@@ -865,6 +871,42 @@ gtk_scrolled_window_get_policy (GtkScrolledWindow *scrolled_window,
+     *vscrollbar_policy = scrolled_window->vscrollbar_policy;
+ }
+
++void
++gtk_scrolled_window_set_overlay_policy (GtkScrolledWindow *scrolled_window,
++                                        GtkPolicyType      hoverlay_policy,
++                                        GtkPolicyType      voverlay_policy)
++{
++  GtkScrolledWindowPrivate *priv;
++
++  g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
++  g_return_if_fail (hoverlay_policy == GTK_POLICY_AUTOMATIC ||
++                    hoverlay_policy == GTK_POLICY_NEVER);
++  g_return_if_fail (voverlay_policy == GTK_POLICY_AUTOMATIC ||
++                    voverlay_policy == GTK_POLICY_NEVER);
++
++  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  priv->hoverlay_policy = hoverlay_policy;
++  priv->voverlay_policy = voverlay_policy;
++}
++
++void
++gtk_scrolled_window_get_overlay_policy (GtkScrolledWindow *scrolled_window,
++                                        GtkPolicyType     *hoverlay_policy,
++                                        GtkPolicyType     *voverlay_policy)
++{
++  GtkScrolledWindowPrivate *priv;
++
++  g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
++
++  priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (scrolled_window);
++
++  if (hoverlay_policy)
++    *hoverlay_policy = priv->hoverlay_policy;
++  if (voverlay_policy)
++    *voverlay_policy = priv->voverlay_policy;
++}
++
+ static void
+ gtk_scrolled_window_update_real_placement (GtkScrolledWindow *scrolled_window)
+ {
+@@ -1309,7 +1351,10 @@ gtk_scrolled_window_update_scrollbars (GtkScrolledWindow *scrolled_window)
+                                         &vbar_rect, &vslider_rect,
+                                         &hbar_rect, &hslider_rect);
+
+-  if (priv->sb_visible && scrolled_window->vscrollbar && vbar_rect.width > 0)
++  if (priv->sb_visible                              &&
++      scrolled_window->vscrollbar                   &&
++      priv->voverlay_policy == GTK_POLICY_AUTOMATIC &&
++      vbar_rect.width > 0)
+     {
+       rect.origin.x = priv->viewport_allocation.x + vbar_rect.x;
+       rect.origin.y = priv->viewport_allocation.y + vbar_rect.y;
+@@ -1326,7 +1371,10 @@ gtk_scrolled_window_update_scrollbars (GtkScrolledWindow *scrolled_window)
+       priv->vbar_layer.opacity = 0.0;
+     }
+
+-  if (priv->sb_visible && scrolled_window->hscrollbar && hbar_rect.width > 0)
++  if (priv->sb_visible                              &&
++      scrolled_window->hscrollbar                   &&
++      priv->hoverlay_policy == GTK_POLICY_AUTOMATIC &&
++      hbar_rect.width > 0)
+     {
+       rect.origin.x = priv->viewport_allocation.x + hbar_rect.x;
+       rect.origin.y = priv->viewport_allocation.y + hbar_rect.y;
+@@ -1334,8 +1382,12 @@ gtk_scrolled_window_update_scrollbars (GtkScrolledWindow *scrolled_window)
+       rect.size.height = hbar_rect.height;
+
+       /* don't overlap in the corner */
+-      if (scrolled_window->vscrollbar && vbar_rect.width > 0)
+-        rect.size.width -= vbar_rect.width;
++      if (scrolled_window->vscrollbar                   &&
++          priv->voverlay_policy == GTK_POLICY_AUTOMATIC &&
++          vbar_rect.width > 0)
++        {
++          rect.size.width -= vbar_rect.width;
++        }
+
+       rect.origin.y = window_height - rect.origin.y - rect.size.height;
+
+@@ -1347,7 +1399,9 @@ gtk_scrolled_window_update_scrollbars (GtkScrolledWindow *scrolled_window)
+       priv->hbar_layer.opacity = 0.0;
+     }
+
+-  if (scrolled_window->vscrollbar && vslider_rect.width > 0)
++  if (scrolled_window->vscrollbar                   &&
++      priv->voverlay_policy == GTK_POLICY_AUTOMATIC &&
++      vslider_rect.width > 0)
+     {
+       rect.origin.x = priv->viewport_allocation.x + vslider_rect.x;
+       rect.origin.y = priv->viewport_allocation.y + vslider_rect.y;
+@@ -1365,7 +1419,9 @@ gtk_scrolled_window_update_scrollbars (GtkScrolledWindow *scrolled_window)
+       priv->vslider_layer.opacity = 0.0;
+     }
+
+-  if (scrolled_window->hscrollbar && hslider_rect.width > 0)
++  if (scrolled_window->hscrollbar                   &&
++      priv->hoverlay_policy == GTK_POLICY_AUTOMATIC &&
++      hslider_rect.width > 0)
+     {
+       rect.origin.x = priv->viewport_allocation.x + hslider_rect.x;
+       rect.origin.y = priv->viewport_allocation.y + hslider_rect.y;
+diff --git a/gtk/gtkscrolledwindow.h b/gtk/gtkscrolledwindow.h
+index f75596d..69dcb43 100644
+--- a/gtk/gtkscrolledwindow.h
++++ b/gtk/gtkscrolledwindow.h
+@@ -116,6 +116,12 @@ void           gtk_scrolled_window_set_policy        (GtkScrolledWindow *scrolle
+ void           gtk_scrolled_window_get_policy        (GtkScrolledWindow *scrolled_window,
+                                                     GtkPolicyType     *hscrollbar_policy,
+                                                     GtkPolicyType     *vscrollbar_policy);
++void          gtk_scrolled_window_set_overlay_policy (GtkScrolledWindow *scrolled_window,
++                                                    GtkPolicyType      hoverlay_policy,
++                                                    GtkPolicyType      voverlay_policy);
++void          gtk_scrolled_window_get_overlay_policy (GtkScrolledWindow *scrolled_window,
++                                                    GtkPolicyType     *hoverlay_policy,
++                                                    GtkPolicyType     *voverlay_policy);
+ void           gtk_scrolled_window_set_placement     (GtkScrolledWindow *scrolled_window,
+                                                     GtkCornerType      window_placement);
+ void           gtk_scrolled_window_unset_placement   (GtkScrolledWindow *scrolled_window);
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0054-quartz-add-gdk_screen_-and-gdk_window_get_scale_fact.patch b/bockbuild/mac-sdk/patches/gtk/0054-quartz-add-gdk_screen_-and-gdk_window_get_scale_fact.patch
new file mode 100644 (file)
index 0000000..2829bb6
--- /dev/null
@@ -0,0 +1,193 @@
+From 13bba88188cc3880d4eba9a93f9109154308d51a Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Fri, 18 Jan 2013 15:47:29 +0100
+Subject: [PATCH 54/68] quartz: add gdk_screen_ and
+ gdk_window_get_scale_factor()
+
+which return 1.0 normally and 2.0 on retina displays.
+---
+ gdk/gdkscreen.h               |    2 ++
+ gdk/gdkwindow.c               |   24 ++++++++++++++++++++++++
+ gdk/gdkwindow.h               |    1 +
+ gdk/gdkwindowimpl.h           |    3 +++
+ gdk/quartz/gdkscreen-quartz.c |   33 +++++++++++++++++++++++++++++++++
+ gdk/quartz/gdkwindow-quartz.c |   22 ++++++++++++++++++++++
+ gdk/x11/gdkscreen-x11.c       |    7 +++++++
+ 7 files changed, 92 insertions(+)
+
+diff --git a/gdk/gdkscreen.h b/gdk/gdkscreen.h
+index d3d4fe9..0c1e895 100644
+--- a/gdk/gdkscreen.h
++++ b/gdk/gdkscreen.h
+@@ -109,6 +109,8 @@ gint          gdk_screen_get_monitor_height_mm (GdkScreen *screen,
+                                                 gint       monitor_num);
+ gchar *       gdk_screen_get_monitor_plug_name (GdkScreen *screen,
+                                                 gint       monitor_num);
++gdouble       gdk_screen_get_monitor_scale_factor (GdkScreen *screen,
++                                                   gint       monitor_num);
+
+ void          gdk_screen_broadcast_client_message  (GdkScreen       *screen,
+                                                   GdkEvent        *event);
+diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
+index 3040321..29b96e2 100644
+--- a/gdk/gdkwindow.c
++++ b/gdk/gdkwindow.c
+@@ -11475,6 +11475,30 @@ gdk_window_get_height (GdkWindow *window)
+   return height;
+ }
+
++gdouble
++gdk_window_get_scale_factor (GdkWindow *window)
++{
++  GdkWindowObject *private;
++  GdkWindowImplIface *impl_iface;
++
++  g_return_val_if_fail (GDK_IS_WINDOW (window), 1.0);
++
++  private = (GdkWindowObject *) window;
++  if (private->destroyed)
++    return 1.0;
++
++  window = gdk_window_get_toplevel (window);
++
++  if (gdk_window_has_impl (private))
++    {
++      impl_iface = GDK_WINDOW_IMPL_GET_IFACE (private->impl);
++
++      if (impl_iface->get_scale_factor)
++        return impl_iface->get_scale_factor (window);
++    }
++
++  return 1.0;
++}
+
+ #define __GDK_WINDOW_C__
+ #include "gdkaliasdef.c"
+diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h
+index 572797b..95a3665 100644
+--- a/gdk/gdkwindow.h
++++ b/gdk/gdkwindow.h
+@@ -341,6 +341,7 @@ GdkDisplay*   gdk_window_get_display           (GdkWindow     *window);
+ GdkVisual*    gdk_window_get_visual            (GdkWindow     *window);
+ int           gdk_window_get_width             (GdkWindow     *window);
+ int           gdk_window_get_height            (GdkWindow     *window);
++gdouble       gdk_window_get_scale_factor      (GdkWindow     *window);
+
+ GdkWindow*    gdk_window_at_pointer            (gint          *win_x,
+                                                 gint          *win_y);
+diff --git a/gdk/gdkwindowimpl.h b/gdk/gdkwindowimpl.h
+index 3a5029b..d6a0c89 100644
+--- a/gdk/gdkwindowimpl.h
++++ b/gdk/gdkwindowimpl.h
+@@ -146,6 +146,9 @@ struct _GdkWindowImplIface
+   void         (* input_window_destroy) (GdkWindow       *window);
+   void         (* input_window_crossing)(GdkWindow       *window,
+                                        gboolean         enter);
++
++  gdouble      (* get_scale_factor)     (GdkWindow       *window);
++
+   gboolean     supports_native_bg;
+ };
+
+diff --git a/gdk/quartz/gdkscreen-quartz.c b/gdk/quartz/gdkscreen-quartz.c
+index 4bb573b..e6f0c44 100644
+--- a/gdk/quartz/gdkscreen-quartz.c
++++ b/gdk/quartz/gdkscreen-quartz.c
+@@ -494,6 +494,39 @@ gdk_screen_get_monitor_workarea (GdkScreen    *screen,
+   GDK_QUARTZ_RELEASE_POOL;
+ }
+
++/* Protocol to build cleanly for OSX < 10.7 */
++@protocol ScaleFactor
++- (CGFloat) backingScaleFactor;
++@end
++
++gdouble
++gdk_screen_get_monitor_scale_factor (GdkScreen *screen,
++                                     gint       monitor_num)
++{
++  GdkScreenQuartz *quartz_screen;
++  NSArray *array;
++  NSScreen *nsscreen;
++  gdouble scale_factor = 1.0;
++
++  g_return_val_if_fail (GDK_IS_SCREEN (screen), 1.0);
++  g_return_val_if_fail (monitor_num < gdk_screen_get_n_monitors (screen), 1.0);
++  g_return_val_if_fail (monitor_num >= 0, 1.0);
++
++  quartz_screen = GDK_SCREEN_QUARTZ (screen);
++
++  GDK_QUARTZ_ALLOC_POOL;
++
++  array = [NSScreen screens];
++  nsscreen = [array objectAtIndex:monitor_num];
++
++  if (gdk_quartz_osx_version() >= GDK_OSX_LION)
++    scale_factor = [(id <ScaleFactor>) nsscreen backingScaleFactor];
++
++  GDK_QUARTZ_RELEASE_POOL;
++
++  return scale_factor;
++}
++
+ gchar *
+ gdk_screen_make_display_name (GdkScreen *screen)
+ {
+diff --git a/gdk/quartz/gdkwindow-quartz.c b/gdk/quartz/gdkwindow-quartz.c
+index 500776d..5b9ceef 100644
+--- a/gdk/quartz/gdkwindow-quartz.c
++++ b/gdk/quartz/gdkwindow-quartz.c
+@@ -3201,6 +3201,27 @@ _gdk_windowing_window_get_input_shape (GdkWindow *window)
+   return NULL;
+ }
+
++/* Protocol to build cleanly for OSX < 10.7 */
++@protocol ScaleFactor
++- (CGFloat) backingScaleFactor;
++@end
++
++static gdouble
++gdk_window_quartz_get_scale_factor (GdkWindow *window)
++{
++  GdkWindowImplQuartz *impl;
++
++  if (GDK_WINDOW_DESTROYED (window))
++    return 1.0;
++
++  impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (window)->impl);
++
++  if (gdk_quartz_osx_version() >= GDK_OSX_LION)
++    return [(id <ScaleFactor>) impl->toplevel backingScaleFactor];
++
++  return 1.0;
++}
++
+ static void
+ gdk_window_impl_iface_init (GdkWindowImplIface *iface)
+ {
+@@ -3229,4 +3250,5 @@ gdk_window_impl_iface_init (GdkWindowImplIface *iface)
+   iface->destroy = _gdk_quartz_window_destroy;
+   iface->input_window_destroy = _gdk_input_window_destroy;
+   iface->input_window_crossing = _gdk_input_window_crossing;
++  iface->get_scale_factor = gdk_window_quartz_get_scale_factor;
+ }
+diff --git a/gdk/x11/gdkscreen-x11.c b/gdk/x11/gdkscreen-x11.c
+index 66a0d96..d09d0b6 100644
+--- a/gdk/x11/gdkscreen-x11.c
++++ b/gdk/x11/gdkscreen-x11.c
+@@ -454,6 +454,13 @@ gdk_screen_get_monitor_plug_name (GdkScreen *screen,
+   return g_strdup (screen_x11->monitors[monitor_num].output_name);
+ }
+
++gdouble
++gdk_screen_get_monitor_scale_factor (GdkScreen *screen,
++                                     gint       monitor_num)
++{
++  return 1.0;
++}
++
+ /**
+  * gdk_x11_screen_get_monitor_output:
+  * @screen: a #GdkScreen
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0055-gtk-add-gtk_widget_get_scale_factor.patch b/bockbuild/mac-sdk/patches/gtk/0055-gtk-add-gtk_widget_get_scale_factor.patch
new file mode 100644 (file)
index 0000000..6ddd163
--- /dev/null
@@ -0,0 +1,55 @@
+From 82dbf415e822d1bb687db09b9dfa0d1e43528e99 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Fri, 15 Feb 2013 15:35:13 +0100
+Subject: [PATCH 55/68] gtk: add gtk_widget_get_scale_factor()
+
+---
+ gtk/gtkwidget.c |   20 ++++++++++++++++++++
+ gtk/gtkwidget.h |    1 +
+ 2 files changed, 21 insertions(+)
+
+diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
+index 8e38ee1..c812bb9 100644
+--- a/gtk/gtkwidget.c
++++ b/gtk/gtkwidget.c
+@@ -7713,6 +7713,26 @@ gtk_widget_has_screen (GtkWidget *widget)
+   return (gtk_widget_get_screen_unchecked (widget) != NULL);
+ }
+
++gdouble
++gtk_widget_get_scale_factor (GtkWidget *widget)
++{
++  GtkWidget *toplevel;
++
++  g_return_val_if_fail (GTK_IS_WIDGET (widget), 1.0);
++
++  toplevel = gtk_widget_get_toplevel (widget);
++  if (toplevel && toplevel != widget)
++    return gtk_widget_get_scale_factor (toplevel);
++
++  if (widget->window)
++    return gdk_window_get_scale_factor (widget->window);
++
++  /* else fall back to something that is more likely to be right than
++   * just returning 1.0:
++   */
++  return gdk_screen_get_monitor_scale_factor (gtk_widget_get_screen (widget), 0);
++}
++
+ /**
+  * gtk_widget_get_display:
+  * @widget: a #GtkWidget
+diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
+index 1fcf21a..cee16cd 100644
+--- a/gtk/gtkwidget.h
++++ b/gtk/gtkwidget.h
+@@ -1055,6 +1055,7 @@ GdkVisual*   gtk_widget_get_visual       (GtkWidget      *widget);
+
+ GdkScreen *   gtk_widget_get_screen      (GtkWidget *widget);
+ gboolean      gtk_widget_has_screen      (GtkWidget *widget);
++gdouble       gtk_widget_get_scale_factor (GtkWidget *widget);
+ GdkDisplay *  gtk_widget_get_display     (GtkWidget *widget);
+ GdkWindow *   gtk_widget_get_root_window (GtkWidget *widget);
+ GtkSettings*  gtk_widget_get_settings    (GtkWidget *widget);
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0056-iconfactory-Add-_scaled-variants.patch b/bockbuild/mac-sdk/patches/gtk/0056-iconfactory-Add-_scaled-variants.patch
new file mode 100644 (file)
index 0000000..4a5fa54
--- /dev/null
@@ -0,0 +1,328 @@
+From e9dfba023f756801f8931a08644c23809cb38412 Mon Sep 17 00:00:00 2001
+From: Carlos Garnacho <carlosg@gnome.org>
+Date: Tue, 12 Feb 2013 13:59:09 +0100
+Subject: [PATCH 56/68] iconfactory: Add _scaled() variants
+
+These functions can be used to deal with stock icons
+at sizes that are suitable for gdk_window_get_scale_factor()
+---
+ gtk/gtkiconfactory.c |  173 +++++++++++++++++++++++++++++++++++++++-----------
+ gtk/gtkiconfactory.h |   14 +++-
+ 2 files changed, 150 insertions(+), 37 deletions(-)
+
+diff --git a/gtk/gtkiconfactory.c b/gtk/gtkiconfactory.c
+index c4b6c9c..0dc31e6 100644
+--- a/gtk/gtkiconfactory.c
++++ b/gtk/gtkiconfactory.c
+@@ -801,6 +801,7 @@ icon_sizes_init_for_settings (GtkSettings *settings)
+ static gboolean
+ icon_size_lookup_intern (GtkSettings *settings,
+                        GtkIconSize  size,
++                         gdouble      scale,
+                        gint        *widthp,
+                        gint        *heightp)
+ {
+@@ -840,10 +841,16 @@ icon_size_lookup_intern (GtkSettings *settings,
+     }
+
+   if (widthp)
+-    *widthp = width_for_settings >= 0 ? width_for_settings : icon_sizes[size].width;
++    {
++      *widthp = width_for_settings >= 0 ? width_for_settings : icon_sizes[size].width;
++      (*widthp) *= scale;
++    }
+
+   if (heightp)
+-    *heightp = height_for_settings >= 0 ? height_for_settings : icon_sizes[size].height;
++    {
++      *heightp = height_for_settings >= 0 ? height_for_settings : icon_sizes[size].height;
++      (*heightp) *= scale;
++    }
+
+   return TRUE;
+ }
+@@ -879,7 +886,7 @@ gtk_icon_size_lookup_for_settings (GtkSettings *settings,
+ {
+   g_return_val_if_fail (GTK_IS_SETTINGS (settings), FALSE);
+
+-  return icon_size_lookup_intern (settings, size, width, height);
++  return icon_size_lookup_intern (settings, size, 1, width, height);
+ }
+
+ /**
+@@ -914,6 +921,18 @@ gtk_icon_size_lookup (GtkIconSize  size,
+                                           size, widthp, heightp);
+ }
+
++gboolean
++gtk_icon_size_lookup_scaled (GtkSettings *settings,
++                             GtkIconSize  size,
++                             gdouble      scale,
++                             gint        *width,
++                             gint        *height)
++{
++  g_return_val_if_fail (GTK_IS_SETTINGS (settings), FALSE);
++
++  return icon_size_lookup_intern (settings, size, scale, width, height);
++}
++
+ static GtkIconSize
+ icon_size_register_intern (const gchar *name,
+                          gint         width,
+@@ -1000,7 +1019,7 @@ gtk_icon_size_register_alias (const gchar *alias,
+
+   init_icon_sizes ();
+
+-  if (!icon_size_lookup_intern (NULL, target, NULL, NULL))
++  if (!icon_size_lookup_intern (NULL, target, 1, NULL, NULL))
+     g_warning ("gtk_icon_size_register_alias: Icon size %u does not exist", target);
+
+   ia = g_hash_table_lookup (icon_aliases, alias);
+@@ -1288,8 +1307,8 @@ sizes_equivalent (GtkIconSize lhs,
+
+   gint r_w, r_h, l_w, l_h;
+
+-  icon_size_lookup_intern (NULL, rhs, &r_w, &r_h);
+-  icon_size_lookup_intern (NULL, lhs, &l_w, &l_h);
++  icon_size_lookup_intern (NULL, rhs, 1, &r_w, &r_h);
++  icon_size_lookup_intern (NULL, lhs, 1, &l_w, &l_h);
+
+   return r_w == l_w && r_h == l_h;
+ #endif
+@@ -1372,7 +1391,8 @@ render_icon_name_pixbuf (GtkIconSource    *icon_source,
+                        GtkStateType      state,
+                        GtkIconSize       size,
+                        GtkWidget        *widget,
+-                       const char       *detail)
++                       const char       *detail,
++                         gboolean          scale_requested)
+ {
+   GdkPixbuf *pixbuf;
+   GdkPixbuf *tmp_pixbuf;
+@@ -1383,6 +1403,7 @@ render_icon_name_pixbuf (GtkIconSource    *icon_source,
+   gint width, height, pixel_size;
+   gint *sizes, *s, dist;
+   GError *error = NULL;
++  gdouble scale = 1;
+
+   if (widget && gtk_widget_has_screen (widget))
+     screen = gtk_widget_get_screen (widget);
+@@ -1398,6 +1419,14 @@ render_icon_name_pixbuf (GtkIconSource    *icon_source,
+   icon_theme = gtk_icon_theme_get_for_screen (screen);
+   settings = gtk_settings_get_for_screen (screen);
+
++  if (scale_requested && widget)
++    {
++      if (!widget->window)
++        gtk_widget_realize (widget);
++
++      scale = gdk_window_get_scale_factor (widget->window);
++    }
++
+   if (!gtk_icon_size_lookup_for_settings (settings, size, &width, &height))
+     {
+       if (size == (GtkIconSize)-1)
+@@ -1440,7 +1469,7 @@ render_icon_name_pixbuf (GtkIconSource    *icon_source,
+       }
+     }
+
+-  pixel_size = MIN (width, height);
++  pixel_size = MIN (width, height) * scale;
+
+   if (icon_source->direction != GTK_TEXT_DIR_NONE)
+     {
+@@ -1504,7 +1533,8 @@ find_and_render_icon_source (GtkIconSet       *icon_set,
+                            GtkStateType      state,
+                            GtkIconSize       size,
+                            GtkWidget         *widget,
+-                           const char        *detail)
++                           const char        *detail,
++                             gboolean           scale_requested)
+ {
+   GSList *failed = NULL;
+   GdkPixbuf *pixbuf = NULL;
+@@ -1546,7 +1576,7 @@ find_and_render_icon_source (GtkIconSet       *icon_set,
+       case GTK_ICON_SOURCE_STATIC_ICON_NAME:
+         pixbuf = render_icon_name_pixbuf (source, style,
+                                           direction, state, size,
+-                                          widget, detail);
++                                          widget, detail, scale_requested);
+         if (!pixbuf)
+           failed = g_slist_prepend (failed, source);
+         break;
+@@ -1598,6 +1628,84 @@ render_fallback_image (GtkStyle          *style,
+                                 detail);
+ }
+
++static gdouble
++_get_real_scale (GtkWidget   *widget,
++                 GtkStyle    *style,
++                 GtkIconSize  size,
++                 GdkPixbuf   *icon)
++{
++  GtkSettings *settings;
++  GdkScreen *screen;
++  gint icon_width;
++
++  if (widget && gtk_widget_has_screen (widget))
++    screen = gtk_widget_get_screen (widget);
++  else if (style && style->colormap)
++    screen = gdk_colormap_get_screen (style->colormap);
++  else
++    {
++      screen = gdk_screen_get_default ();
++      GTK_NOTE (MULTIHEAD,
++                g_warning ("Using the default screen for gtk_icon_set_render_icon()"));
++    }
++
++  settings = gtk_settings_get_for_screen (screen);
++  gtk_icon_size_lookup_for_settings (settings, size, &icon_width, NULL);
++
++  return (gdouble) gdk_pixbuf_get_width (icon) / icon_width;
++}
++
++GdkPixbuf*
++gtk_icon_set_render_icon_internal (GtkIconSet        *icon_set,
++                                   GtkStyle          *style,
++                                   GtkTextDirection   direction,
++                                   GtkStateType       state,
++                                   GtkIconSize        size,
++                                   GtkWidget         *widget,
++                                   const char        *detail,
++                                   gboolean           scale_requested,
++                                   gdouble           *real_scale)
++{
++  GdkPixbuf *icon;
++
++  if (real_scale)
++    *real_scale = 1;
++
++  if (icon_set->sources == NULL)
++    return render_fallback_image (style, direction, state, size, widget, detail);
++
++  if (detail == NULL)
++    {
++      icon = find_in_cache (icon_set, style, direction,
++                        state, size);
++
++      if (icon)
++      {
++        g_object_ref (icon);
++
++          if (scale_requested && real_scale)
++            *real_scale = _get_real_scale (widget, style, size, icon);
++
++        return icon;
++      }
++    }
++
++
++  icon = find_and_render_icon_source (icon_set, style, direction, state, size,
++                                    widget, detail, scale_requested);
++
++  if (icon == NULL)
++    icon = render_fallback_image (style, direction, state, size, widget, detail);
++
++  if (detail == NULL)
++    add_to_cache (icon_set, style, direction, state, size, icon);
++
++  if (scale_requested && real_scale)
++    *real_scale = _get_real_scale (widget, style, size, icon);
++
++  return icon;
++}
++
+ /**
+  * gtk_icon_set_render_icon:
+  * @icon_set: a #GtkIconSet
+@@ -1631,37 +1739,30 @@ gtk_icon_set_render_icon (GtkIconSet        *icon_set,
+                           GtkWidget         *widget,
+                           const char        *detail)
+ {
+-  GdkPixbuf *icon;
+-
+   g_return_val_if_fail (icon_set != NULL, NULL);
+   g_return_val_if_fail (style == NULL || GTK_IS_STYLE (style), NULL);
+
+-  if (icon_set->sources == NULL)
+-    return render_fallback_image (style, direction, state, size, widget, detail);
+-
+-  if (detail == NULL)
+-    {
+-      icon = find_in_cache (icon_set, style, direction,
+-                        state, size);
+-
+-      if (icon)
+-      {
+-        g_object_ref (icon);
+-        return icon;
+-      }
+-    }
+-
+-
+-  icon = find_and_render_icon_source (icon_set, style, direction, state, size,
+-                                    widget, detail);
+-
+-  if (icon == NULL)
+-    icon = render_fallback_image (style, direction, state, size, widget, detail);
++  return gtk_icon_set_render_icon_internal (icon_set, style, direction,
++                                            state, size, widget, detail,
++                                            FALSE, NULL);
++}
+
+-  if (detail == NULL)
+-    add_to_cache (icon_set, style, direction, state, size, icon);
++GdkPixbuf*
++gtk_icon_set_render_icon_scaled (GtkIconSet        *icon_set,
++                                 GtkStyle          *style,
++                                 GtkTextDirection   direction,
++                                 GtkStateType       state,
++                                 GtkIconSize        size,
++                                 GtkWidget         *widget,
++                                 const char        *detail,
++                                 gdouble           *real_scale)
++{
++  g_return_val_if_fail (icon_set != NULL, NULL);
++  g_return_val_if_fail (style == NULL || GTK_IS_STYLE (style), NULL);
+
+-  return icon;
++  return gtk_icon_set_render_icon_internal (icon_set, style, direction,
++                                            state, size, widget, detail,
++                                            TRUE, real_scale);
+ }
+
+ /* Order sources by their "wildness", so that "wilder" sources are
+diff --git a/gtk/gtkiconfactory.h b/gtk/gtkiconfactory.h
+index ea97123..e38f8e6 100644
+--- a/gtk/gtkiconfactory.h
++++ b/gtk/gtkiconfactory.h
+@@ -105,6 +105,11 @@ gboolean gtk_icon_size_lookup_for_settings (GtkSettings *settings,
+                                           GtkIconSize  size,
+                                           gint        *width,
+                                           gint        *height);
++gboolean gtk_icon_size_lookup_scaled       (GtkSettings *settings,
++                                            GtkIconSize  size,
++                                            gdouble      scale,
++                                            gint        *width,
++                                            gint        *height);
+
+ GtkIconSize           gtk_icon_size_register       (const gchar *name,
+                                                     gint         width,
+@@ -134,7 +139,14 @@ GdkPixbuf*  gtk_icon_set_render_icon     (GtkIconSet      *icon_set,
+                                           GtkIconSize      size,
+                                           GtkWidget       *widget,
+                                           const char      *detail);
+-
++GdkPixbuf* gtk_icon_set_render_icon_scaled (GtkIconSet        *icon_set,
++                                            GtkStyle          *style,
++                                            GtkTextDirection   direction,
++                                            GtkStateType       state,
++                                            GtkIconSize        size,
++                                            GtkWidget         *widget,
++                                            const char        *detail,
++                                            gdouble           *real_scale);
+
+ void           gtk_icon_set_add_source   (GtkIconSet          *icon_set,
+                                           const GtkIconSource *source);
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0057-widget-Add-_scaled-variants-for-icon-rendering.patch b/bockbuild/mac-sdk/patches/gtk/0057-widget-Add-_scaled-variants-for-icon-rendering.patch
new file mode 100644 (file)
index 0000000..e755cba
--- /dev/null
@@ -0,0 +1,69 @@
+From de10316fb1045f610072ef7c2addbe969e0fe617 Mon Sep 17 00:00:00 2001
+From: Carlos Garnacho <carlosg@gnome.org>
+Date: Tue, 12 Feb 2013 14:01:15 +0100
+Subject: [PATCH 57/68] widget: Add _scaled() variants for icon rendering
+
+Likewise to the iconfactory changes, this API allows to
+deal with stock icons at sizes that are suitable for
+gdk_window_get_scale_factor()
+---
+ gtk/gtkwidget.c |   27 +++++++++++++++++++++++++++
+ gtk/gtkwidget.h |    5 +++++
+ 2 files changed, 32 insertions(+)
+
+diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
+index c812bb9..f093c39 100644
+--- a/gtk/gtkwidget.c
++++ b/gtk/gtkwidget.c
+@@ -7502,6 +7502,33 @@ gtk_widget_render_icon (GtkWidget      *widget,
+   return retval;
+ }
+
++GdkPixbuf*
++gtk_widget_render_icon_scaled (GtkWidget      *widget,
++                             const gchar    *stock_id,
++                             GtkIconSize     size,
++                             const gchar    *detail,
++                             gdouble        *real_scale)
++{
++  GtkIconSet *icon_set;
++  GdkPixbuf *retval;
++
++  g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
++  g_return_val_if_fail (stock_id != NULL, NULL);
++  g_return_val_if_fail (size > GTK_ICON_SIZE_INVALID || size == -1, NULL);
++
++  gtk_widget_ensure_style (widget);
++
++  icon_set = gtk_style_lookup_icon_set (widget->style, stock_id);
++
++  if (icon_set == NULL)
++    return NULL;
++
++  return gtk_icon_set_render_icon_scaled (icon_set, widget->style,
++                                          gtk_widget_get_direction (widget),
++                                          gtk_widget_get_state (widget),
++                                          size, widget, detail, real_scale);
++}
++
+ /**
+  * gtk_widget_set_parent_window:
+  * @widget: a #GtkWidget.
+diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
+index cee16cd..f7ebf9b 100644
+--- a/gtk/gtkwidget.h
++++ b/gtk/gtkwidget.h
+@@ -1194,6 +1194,11 @@ GdkPixbuf    *gtk_widget_render_icon          (GtkWidget   *widget,
+                                                const gchar *stock_id,
+                                                GtkIconSize  size,
+                                                const gchar *detail);
++GdkPixbuf    *gtk_widget_render_icon_scaled   (GtkWidget      *widget,
++                                               const gchar    *stock_id,
++                                               GtkIconSize     size,
++                                               const gchar    *detail,
++                                               gdouble        *real_scale);
+
+ /* handle composite names for GTK_COMPOSITE_CHILD widgets,
+  * the returned name is newly allocated.
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0058-icontheme-Add-support-for-high-resolution-icons.patch b/bockbuild/mac-sdk/patches/gtk/0058-icontheme-Add-support-for-high-resolution-icons.patch
new file mode 100644 (file)
index 0000000..537ae8d
--- /dev/null
@@ -0,0 +1,399 @@
+From 75299b2806b1bed9e14081f2e108afb39e31896e Mon Sep 17 00:00:00 2001
+From: Carlos Garnacho <carlos@lanedo.com>
+Date: Fri, 10 May 2013 18:06:00 +0200
+Subject: [PATCH 58/68] icontheme: Add support for high resolution icons
+
+An optional OutputScale integer key has been added to index.theme
+subdirs description, so icon themes may provide icons that are
+more suitable to render at a (typically 2x) integer upscaled
+resolution. This way it is possible to make eg. a 16x16@2x icon has a
+real size of 32x32, but contains a similar level of detail to the
+16x16 icon so things don't look any more cluttered on high-dpi
+screens.
+
+The pixbuf lookup has changed so it prefers a minimal scale change
+that yields the minimal real size difference, so if looking up for
+a 16x16 icon at 2x, it would first prefer 16x16@2x, then 32x32, and
+then any other icon that's closest to match
+
+There is now *_for_scale() variants for all GtkIconTheme ways
+to directly or indirectly fetch a GdkPixbuf.
+---
+ gtk/gtkicontheme.c |  152 ++++++++++++++++++++++++++++++++++++++++------------
+ gtk/gtkicontheme.h |   17 +++++-
+ 2 files changed, 135 insertions(+), 34 deletions(-)
+
+diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c
+index bf81546..500f0ab 100644
+--- a/gtk/gtkicontheme.c
++++ b/gtk/gtkicontheme.c
+@@ -168,6 +168,7 @@ typedef struct
+   int min_size;
+   int max_size;
+   int threshold;
++  int scale;
+
+   char *dir;
+   char *subdir;
+@@ -206,6 +207,7 @@ static void         theme_destroy     (IconTheme        *theme);
+ static GtkIconInfo *theme_lookup_icon (IconTheme        *theme,
+                                      const char       *icon_name,
+                                      int               size,
++                                       gdouble           scale,
+                                      gboolean          allow_svg,
+                                      gboolean          use_default_icons);
+ static void         theme_list_icons  (IconTheme        *theme,
+@@ -1161,11 +1163,11 @@ _gtk_icon_theme_ensure_builtin_cache (void)
+   IconThemeDir *dir;
+   static IconThemeDir dirs[5] =
+     {
+-      { ICON_THEME_DIR_THRESHOLD, 0, 16, 16, 16, 2, NULL, "16", -1, NULL, NULL, NULL },
+-      { ICON_THEME_DIR_THRESHOLD, 0, 20, 20, 20, 2, NULL, "20", -1,  NULL, NULL, NULL },
+-      { ICON_THEME_DIR_THRESHOLD, 0, 24, 24, 24, 2, NULL, "24", -1, NULL, NULL, NULL },
+-      { ICON_THEME_DIR_THRESHOLD, 0, 32, 32, 32, 2, NULL, "32", -1, NULL, NULL, NULL },
+-      { ICON_THEME_DIR_THRESHOLD, 0, 48, 48, 48, 2, NULL, "48", -1, NULL, NULL, NULL }
++      { ICON_THEME_DIR_THRESHOLD, 0, 16, 16, 16, 2, 1, NULL, "16", -1, NULL, NULL, NULL },
++      { ICON_THEME_DIR_THRESHOLD, 0, 20, 20, 20, 2, 1, NULL, "20", -1,  NULL, NULL, NULL },
++      { ICON_THEME_DIR_THRESHOLD, 0, 24, 24, 24, 2, 1, NULL, "24", -1, NULL, NULL, NULL },
++      { ICON_THEME_DIR_THRESHOLD, 0, 32, 32, 32, 2, 1, NULL, "32", -1, NULL, NULL, NULL },
++      { ICON_THEME_DIR_THRESHOLD, 0, 48, 48, 48, 2, 1, NULL, "48", -1, NULL, NULL, NULL }
+     };
+   gint i;
+
+@@ -1242,6 +1244,7 @@ static GtkIconInfo *
+ choose_icon (GtkIconTheme       *icon_theme,
+            const gchar        *icon_names[],
+            gint                size,
++             gdouble             scale,
+            GtkIconLookupFlags  flags)
+ {
+   GtkIconThemePrivate *priv;
+@@ -1271,7 +1274,7 @@ choose_icon (GtkIconTheme       *icon_theme,
+
+       for (i = 0; icon_names[i]; i++)
+         {
+-          icon_info = theme_lookup_icon (theme, icon_names[i], size, allow_svg, use_builtin);
++          icon_info = theme_lookup_icon (theme, icon_names[i], size, scale, allow_svg, use_builtin);
+           if (icon_info)
+             goto out;
+         }
+@@ -1400,12 +1403,32 @@ gtk_icon_theme_lookup_icon (GtkIconTheme       *icon_theme,
+                           gint                size,
+                           GtkIconLookupFlags  flags)
+ {
++  g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL);
++  g_return_val_if_fail (icon_name != NULL, NULL);
++  g_return_val_if_fail ((flags & GTK_ICON_LOOKUP_NO_SVG) == 0 ||
++                      (flags & GTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL);
++
++  GTK_NOTE (ICONTHEME,
++          g_print ("gtk_icon_theme_lookup_icon %s\n", icon_name));
++
++  return gtk_icon_theme_lookup_icon_for_scale (icon_theme, icon_name,
++                                               size, 1, flags);
++}
++
++GtkIconInfo *
++gtk_icon_theme_lookup_icon_for_scale (GtkIconTheme       *icon_theme,
++                                      const gchar        *icon_name,
++                                      gint                size,
++                                      gdouble             scale,
++                                      GtkIconLookupFlags  flags)
++{
+   GtkIconInfo *info;
+
+   g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL);
+   g_return_val_if_fail (icon_name != NULL, NULL);
+   g_return_val_if_fail ((flags & GTK_ICON_LOOKUP_NO_SVG) == 0 ||
+                       (flags & GTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL);
++  g_return_val_if_fail (scale >= 1, NULL);
+
+   GTK_NOTE (ICONTHEME,
+           g_print ("gtk_icon_theme_lookup_icon %s\n", icon_name));
+@@ -1431,7 +1454,7 @@ gtk_icon_theme_lookup_icon (GtkIconTheme       *icon_theme,
+         }
+       names[dashes + 1] = NULL;
+
+-      info = choose_icon (icon_theme, (const gchar **) names, size, flags);
++      info = choose_icon (icon_theme, (const gchar **) names, size, scale, flags);
+
+       g_strfreev (names);
+     }
+@@ -1442,7 +1465,7 @@ gtk_icon_theme_lookup_icon (GtkIconTheme       *icon_theme,
+       names[0] = icon_name;
+       names[1] = NULL;
+
+-      info = choose_icon (icon_theme, names, size, flags);
++      info = choose_icon (icon_theme, names, size, scale, flags);
+     }
+
+   return info;
+@@ -1483,9 +1506,26 @@ gtk_icon_theme_choose_icon (GtkIconTheme       *icon_theme,
+   g_return_val_if_fail ((flags & GTK_ICON_LOOKUP_NO_SVG) == 0 ||
+                       (flags & GTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL);
+
+-  return choose_icon (icon_theme, icon_names, size, flags);
++  return choose_icon (icon_theme, icon_names, size, 1, flags);
++}
++
++GtkIconInfo *
++gtk_icon_theme_choose_icon_for_scale (GtkIconTheme       *icon_theme,
++                                      const gchar        *icon_names[],
++                                      gint                size,
++                                      gdouble             scale,
++                                      GtkIconLookupFlags  flags)
++{
++  g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL);
++  g_return_val_if_fail (icon_names != NULL, NULL);
++  g_return_val_if_fail ((flags & GTK_ICON_LOOKUP_NO_SVG) == 0 ||
++                      (flags & GTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL);
++  g_return_val_if_fail (scale >= 1, NULL);
++
++  return choose_icon (icon_theme, icon_names, size, scale, flags);
+ }
+
++
+ /* Error quark */
+ GQuark
+ gtk_icon_theme_error_quark (void)
+@@ -1529,6 +1569,24 @@ gtk_icon_theme_load_icon (GtkIconTheme         *icon_theme,
+                         GtkIconLookupFlags    flags,
+                         GError              **error)
+ {
++  g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL);
++  g_return_val_if_fail (icon_name != NULL, NULL);
++  g_return_val_if_fail ((flags & GTK_ICON_LOOKUP_NO_SVG) == 0 ||
++                      (flags & GTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL);
++  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
++
++  return gtk_icon_theme_load_icon_for_scale (icon_theme, icon_name,
++                                             size, 1, flags, error);
++}
++
++GdkPixbuf *
++gtk_icon_theme_load_icon_for_scale (GtkIconTheme        *icon_theme,
++                                    const gchar         *icon_name,
++                                    gint                 size,
++                                    gdouble              scale,
++                                    GtkIconLookupFlags   flags,
++                                    GError             **error)
++{
+   GtkIconInfo *icon_info;
+   GdkPixbuf *pixbuf = NULL;
+
+@@ -1537,9 +1595,10 @@ gtk_icon_theme_load_icon (GtkIconTheme         *icon_theme,
+   g_return_val_if_fail ((flags & GTK_ICON_LOOKUP_NO_SVG) == 0 ||
+                       (flags & GTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL);
+   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+-
+-  icon_info = gtk_icon_theme_lookup_icon (icon_theme, icon_name, size,
+-                                        flags | GTK_ICON_LOOKUP_USE_BUILTIN);
++  g_return_val_if_fail (scale >= 1, NULL);
++
++  icon_info = gtk_icon_theme_lookup_icon_for_scale (icon_theme, icon_name, size, scale,
++                                                    flags | GTK_ICON_LOOKUP_USE_BUILTIN);
+   if (!icon_info)
+     {
+       g_set_error (error, GTK_ICON_THEME_ERROR,  GTK_ICON_THEME_NOT_FOUND,
+@@ -1976,31 +2035,42 @@ theme_dir_destroy (IconThemeDir *dir)
+ }
+
+ static int
+-theme_dir_size_difference (IconThemeDir *dir, int size, gboolean *smaller)
++theme_dir_size_difference (IconThemeDir *dir,
++                           int           size,
++                           gdouble       scale,
++                           gboolean     *smaller,
++                           gint         *scale_diff)
+ {
++  int scaled_size, scaled_dir_size;
+   int min, max;
++
++  scaled_size = size * scale;
++  scaled_dir_size = dir->size * dir->scale;
++  *scale_diff = abs (scale - dir->scale);
++
+   switch (dir->type)
+     {
+     case ICON_THEME_DIR_FIXED:
+-      *smaller = size < dir->size;
+-      return abs (size - dir->size);
++      *smaller = scaled_size < scaled_dir_size;
++      return abs (scaled_size - scaled_dir_size);
+       break;
+     case ICON_THEME_DIR_SCALABLE:
+-      *smaller = size < dir->min_size;
+-      if (size < dir->min_size)
+-      return dir->min_size - size;
+-      if (size > dir->max_size)
+-      return size - dir->max_size;
++      *scale_diff = 0;
++      *smaller = scaled_size < (dir->min_size * dir->scale);
++      if (scaled_size < (dir->min_size * dir->scale))
++      return (dir->min_size * dir->scale) - scaled_size;
++      if (size > (dir->max_size * dir->scale))
++      return scaled_size - (dir->max_size * dir->scale);
+       return 0;
+       break;
+     case ICON_THEME_DIR_THRESHOLD:
+-      min = dir->size - dir->threshold;
+-      max = dir->size + dir->threshold;
+-      *smaller = size < min;
+-      if (size < min)
+-      return min - size;
+-      if (size > max)
+-      return size - max;
++      min = (dir->size - dir->threshold) * dir->scale;
++      max = (dir->size + dir->threshold) * dir->scale;
++      *smaller = scaled_size < min;
++      if (scaled_size < min)
++      return min - scaled_size;
++      if (scaled_size > max)
++      return scaled_size - max;
+       return 0;
+       break;
+     case ICON_THEME_DIR_UNTHEMED:
+@@ -2091,6 +2161,7 @@ static GtkIconInfo *
+ theme_lookup_icon (IconTheme          *theme,
+                  const char         *icon_name,
+                  int                 size,
++                   gdouble             scale,
+                  gboolean            allow_svg,
+                  gboolean            use_builtin)
+ {
+@@ -2098,11 +2169,13 @@ theme_lookup_icon (IconTheme          *theme,
+   IconThemeDir *dir, *min_dir;
+   char *file;
+   int min_difference, difference;
++  int min_scale_diff, scale_diff;
+   BuiltinIcon *closest_builtin = NULL;
+   gboolean smaller, has_larger, match;
+   IconSuffix suffix;
+
+   min_difference = G_MAXINT;
++  min_scale_diff = G_MAXINT;
+   min_dir = NULL;
+   has_larger = FALSE;
+   match = FALSE;
+@@ -2135,9 +2208,10 @@ theme_lookup_icon (IconTheme          *theme,
+       suffix = theme_dir_get_icon_suffix (dir, icon_name, NULL);
+       if (best_suffix (suffix, allow_svg) != ICON_SUFFIX_NONE)
+       {
+-        difference = theme_dir_size_difference (dir, size, &smaller);
++        difference = theme_dir_size_difference (dir, size, scale,
++                                                  &smaller, &scale_diff);
+
+-        if (difference == 0)
++        if (difference == 0 && scale_diff == 0)
+           {
+               if (dir->type == ICON_THEME_DIR_SCALABLE)
+                 {
+@@ -2156,13 +2230,15 @@ theme_lookup_icon (IconTheme          *theme,
+                    * going and look for a closer match
+                    */
+                   difference = abs (size - dir->size);
+-                  if (!match || difference < min_difference)
++                  if (!match ||
++                      (scale_diff <= min_scale_diff && difference < min_difference))
+                     {
+                       match = TRUE;
+                       min_difference = difference;
++                      min_scale_diff = scale_diff;
+                     min_dir = dir;
+                     }
+-                  if (difference == 0)
++                  if (difference == 0 && scale_diff == 0)
+                     break;
+                 }
+           }
+@@ -2171,18 +2247,20 @@ theme_lookup_icon (IconTheme          *theme,
+             {
+             if (!has_larger)
+               {
+-                if (difference < min_difference || smaller)
++                if ((scale_diff <= min_scale_diff && difference < min_difference) || (scale_diff == 0 && smaller))
+                   {
+                     min_difference = difference;
++                      min_scale_diff = scale_diff;
+                     min_dir = dir;
+                     has_larger = smaller;
+                   }
+               }
+             else
+               {
+-                if (difference < min_difference && smaller)
++                if ((scale_diff <= min_scale_diff && difference < min_difference) && (scale_diff == 0 && smaller))
+                   {
+                     min_difference = difference;
++                      min_scale_diff = scale_diff;
+                     min_dir = dir;
+                   }
+               }
+@@ -2484,6 +2562,7 @@ theme_subdir_load (GtkIconTheme *icon_theme,
+   char *full_dir;
+   GError *error = NULL;
+   IconThemeDirMtime *dir_mtime;
++  int scale;
+
+   size = g_key_file_get_integer (theme_file, subdir, "Size", &error);
+   if (error)
+@@ -2543,6 +2622,11 @@ theme_subdir_load (GtkIconTheme *icon_theme,
+       error = NULL;
+     }
+
++  if (g_key_file_has_key (theme_file, subdir, "OutputScale", NULL))
++    scale = g_key_file_get_integer (theme_file, subdir, "OutputScale", NULL);
++  else
++    scale = 1;
++
+   for (d = icon_theme->priv->dir_mtimes; d; d = d->next)
+     {
+       dir_mtime = (IconThemeDirMtime *)d->data;
+@@ -2571,6 +2655,8 @@ theme_subdir_load (GtkIconTheme *icon_theme,
+         dir->dir = full_dir;
+         dir->icon_data = NULL;
+         dir->subdir = g_strdup (subdir);
++          dir->scale = scale;
++
+         if (dir_mtime->cache != NULL)
+             {
+             dir->cache = _gtk_icon_cache_ref (dir_mtime->cache);
+diff --git a/gtk/gtkicontheme.h b/gtk/gtkicontheme.h
+index 3611c74..9b29f96 100644
+--- a/gtk/gtkicontheme.h
++++ b/gtk/gtkicontheme.h
+@@ -141,16 +141,31 @@ GtkIconInfo * gtk_icon_theme_lookup_icon           (GtkIconTheme
+                                                   const gchar                 *icon_name,
+                                                   gint                         size,
+                                                   GtkIconLookupFlags           flags);
++GtkIconInfo * gtk_icon_theme_lookup_icon_for_scale (GtkIconTheme                *icon_theme,
++                                                    const gchar                 *icon_name,
++                                                    gint                         size,
++                                                    gdouble                      scale,
++                                                    GtkIconLookupFlags           flags);
+ GtkIconInfo * gtk_icon_theme_choose_icon           (GtkIconTheme                *icon_theme,
+                                                   const gchar                 *icon_names[],
+                                                   gint                         size,
+                                                   GtkIconLookupFlags           flags);
++GtkIconInfo * gtk_icon_theme_choose_icon_for_scale (GtkIconTheme                *icon_theme,
++                                                  const gchar                 *icon_names[],
++                                                  gint                         size,
++                                                    gdouble                      scale,
++                                                  GtkIconLookupFlags           flags);
+ GdkPixbuf *   gtk_icon_theme_load_icon             (GtkIconTheme                *icon_theme,
+                                                   const gchar                 *icon_name,
+                                                   gint                         size,
+                                                   GtkIconLookupFlags           flags,
+                                                   GError                     **error);
+-
++GdkPixbuf *   gtk_icon_theme_load_icon_for_scale   (GtkIconTheme                *icon_theme,
++                                                    const gchar                 *icon_name,
++                                                    gint                         size,
++                                                    gdouble                      scale,
++                                                    GtkIconLookupFlags           flags,
++                                                    GError                     **error);
+ GtkIconInfo * gtk_icon_theme_lookup_by_gicon       (GtkIconTheme                *icon_theme,
+                                                     GIcon                       *icon,
+                                                     gint                         size,
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0059-iconfactory-Add-scale-info-to-GtkIconSource.patch b/bockbuild/mac-sdk/patches/gtk/0059-iconfactory-Add-scale-info-to-GtkIconSource.patch
new file mode 100644 (file)
index 0000000..d696b45
--- /dev/null
@@ -0,0 +1,480 @@
+From 431d1225b153c1a1389686920aed1d26ff3218b2 Mon Sep 17 00:00:00 2001
+From: Carlos Garnacho <carlos@lanedo.com>
+Date: Fri, 10 May 2013 18:24:26 +0200
+Subject: [PATCH 59/68] iconfactory: Add scale info to GtkIconSource
+
+GtkIconSource now has notions knows about scale, so it can correctly
+fetch the icon at the right scale for ICON_NAME source types.
+
+All default stock icons have been made to have a wildcarded scale,
+so it's up to the GtkIconTheme to do the scaling business.
+---
+ gtk/gtkiconfactory.c |  140 ++++++++++++++++++++++++++++++++------------------
+ gtk/gtkiconfactory.h |    7 ++-
+ 2 files changed, 97 insertions(+), 50 deletions(-)
+
+diff --git a/gtk/gtkiconfactory.c b/gtk/gtkiconfactory.c
+index 0dc31e6..41d1ee7 100644
+--- a/gtk/gtkiconfactory.c
++++ b/gtk/gtkiconfactory.c
+@@ -66,6 +66,7 @@ struct _GtkIconSource
+   GtkTextDirection direction;
+   GtkStateType state;
+   GtkIconSize size;
++  gdouble scale;
+
+   /* If TRUE, then the parameter is wildcarded, and the above
+    * fields should be ignored. If FALSE, the parameter is
+@@ -74,6 +75,7 @@ struct _GtkIconSource
+   guint any_direction : 1;
+   guint any_state : 1;
+   guint any_size : 1;
++  guint any_scale : 1;
+
+ #if defined (G_OS_WIN32) && !defined (_WIN64)
+   /* System codepage version of filename, for DLL ABI backward
+@@ -106,10 +108,10 @@ static GtkIconSize icon_size_register_intern (const gchar *name,
+                                             gint         width,
+                                             gint         height);
+
+-#define GTK_ICON_SOURCE_INIT(any_direction, any_state, any_size)      \
++#define GTK_ICON_SOURCE_INIT(any_direction, any_state, any_size, any_scale)   \
+   { GTK_ICON_SOURCE_EMPTY, { NULL }, NULL,                            \
+-   0, 0, 0,                                                           \
+-   any_direction, any_state, any_size }
++   0, 0, 0, 1,                                                                \
++   any_direction, any_state, any_size, any_scale }
+
+ G_DEFINE_TYPE_WITH_CODE (GtkIconFactory, gtk_icon_factory, G_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+@@ -349,7 +351,7 @@ register_stock_icon (GtkIconFactory *factory,
+                      const gchar    *icon_name)
+ {
+   GtkIconSet *set = gtk_icon_set_new ();
+-  GtkIconSource source = GTK_ICON_SOURCE_INIT (TRUE, TRUE, TRUE);
++  GtkIconSource source = GTK_ICON_SOURCE_INIT (TRUE, TRUE, TRUE, TRUE);
+
+   source.type = GTK_ICON_SOURCE_STATIC_ICON_NAME;
+   source.source.icon_name = (gchar *)icon_name;
+@@ -366,7 +368,7 @@ register_bidi_stock_icon (GtkIconFactory *factory,
+                           const gchar    *icon_name)
+ {
+   GtkIconSet *set = gtk_icon_set_new ();
+-  GtkIconSource source = GTK_ICON_SOURCE_INIT (FALSE, TRUE, TRUE);
++  GtkIconSource source = GTK_ICON_SOURCE_INIT (FALSE, TRUE, TRUE, TRUE);
+
+   source.type = GTK_ICON_SOURCE_STATIC_ICON_NAME;
+   source.source.icon_name = (gchar *)icon_name;
+@@ -1094,12 +1096,14 @@ static GdkPixbuf *find_in_cache     (GtkIconSet       *icon_set,
+                                      GtkStyle         *style,
+                                      GtkTextDirection  direction,
+                                      GtkStateType      state,
+-                                     GtkIconSize       size);
++                                     GtkIconSize       size,
++                                   gdouble           scale);
+ static void       add_to_cache      (GtkIconSet       *icon_set,
+                                      GtkStyle         *style,
+                                      GtkTextDirection  direction,
+                                      GtkStateType      state,
+                                      GtkIconSize       size,
++                                     gdouble           scale,
+                                      GdkPixbuf        *pixbuf);
+ /* Clear icon set contents, drop references to all contained
+  * GdkPixbuf objects and forget all GtkIconSources. Used to
+@@ -1179,7 +1183,7 @@ gtk_icon_set_new_from_pixbuf (GdkPixbuf *pixbuf)
+ {
+   GtkIconSet *set;
+
+-  GtkIconSource source = GTK_ICON_SOURCE_INIT (TRUE, TRUE, TRUE);
++  GtkIconSource source = GTK_ICON_SOURCE_INIT (TRUE, TRUE, TRUE, TRUE);
+
+   g_return_val_if_fail (pixbuf != NULL, NULL);
+
+@@ -1319,6 +1323,7 @@ find_best_matching_source (GtkIconSet       *icon_set,
+                          GtkTextDirection  direction,
+                          GtkStateType      state,
+                          GtkIconSize       size,
++                         gdouble           scale,
+                          GSList           *failed)
+ {
+   GtkIconSource *source;
+@@ -1340,7 +1345,8 @@ find_best_matching_source (GtkIconSet       *icon_set,
+
+       if ((s->any_direction || (s->direction == direction)) &&
+           (s->any_state || (s->state == state)) &&
+-          (s->any_size || size == (GtkIconSize)-1 || (sizes_equivalent (size, s->size))))
++          (s->any_size || size == (GtkIconSize)-1 || (sizes_equivalent (size, s->size))) &&
++          (s->any_scale || (s->scale == scale)))
+         {
+         if (!g_slist_find (failed, s))
+           {
+@@ -1392,7 +1398,7 @@ render_icon_name_pixbuf (GtkIconSource    *icon_source,
+                        GtkIconSize       size,
+                        GtkWidget        *widget,
+                        const char       *detail,
+-                         gboolean          scale_requested)
++                         gdouble           scale)
+ {
+   GdkPixbuf *pixbuf;
+   GdkPixbuf *tmp_pixbuf;
+@@ -1403,7 +1409,6 @@ render_icon_name_pixbuf (GtkIconSource    *icon_source,
+   gint width, height, pixel_size;
+   gint *sizes, *s, dist;
+   GError *error = NULL;
+-  gdouble scale = 1;
+
+   if (widget && gtk_widget_has_screen (widget))
+     screen = gtk_widget_get_screen (widget);
+@@ -1419,14 +1424,6 @@ render_icon_name_pixbuf (GtkIconSource    *icon_source,
+   icon_theme = gtk_icon_theme_get_for_screen (screen);
+   settings = gtk_settings_get_for_screen (screen);
+
+-  if (scale_requested && widget)
+-    {
+-      if (!widget->window)
+-        gtk_widget_realize (widget);
+-
+-      scale = gdk_window_get_scale_factor (widget->window);
+-    }
+-
+   if (!gtk_icon_size_lookup_for_settings (settings, size, &width, &height))
+     {
+       if (size == (GtkIconSize)-1)
+@@ -1469,7 +1466,7 @@ render_icon_name_pixbuf (GtkIconSource    *icon_source,
+       }
+     }
+
+-  pixel_size = MIN (width, height) * scale;
++  pixel_size = MIN (width, height);
+
+   if (icon_source->direction != GTK_TEXT_DIR_NONE)
+     {
+@@ -1483,9 +1480,10 @@ render_icon_name_pixbuf (GtkIconSource    *icon_source,
+       names[1] = icon_source->source.icon_name;
+       names[2] = NULL;
+
+-      info = gtk_icon_theme_choose_icon (icon_theme,
+-                                         names,
+-                                         pixel_size, GTK_ICON_LOOKUP_USE_BUILTIN);
++      info = gtk_icon_theme_choose_icon_for_scale (icon_theme,
++                                                   names,
++                                                   pixel_size, scale,
++                                                   GTK_ICON_LOOKUP_USE_BUILTIN);
+       g_free (name_with_dir);
+       if (info)
+         {
+@@ -1495,10 +1493,10 @@ render_icon_name_pixbuf (GtkIconSource    *icon_source,
+     }
+   else
+     {
+-      tmp_pixbuf = gtk_icon_theme_load_icon (icon_theme,
+-                                             icon_source->source.icon_name,
+-                                             pixel_size, 0,
+-                                             &error);
++      tmp_pixbuf = gtk_icon_theme_load_icon_for_scale (icon_theme,
++                                                       icon_source->source.icon_name,
++                                                       pixel_size, scale, 0,
++                                                       &error);
+     }
+
+   if (!tmp_pixbuf)
+@@ -1534,7 +1532,7 @@ find_and_render_icon_source (GtkIconSet       *icon_set,
+                            GtkIconSize       size,
+                            GtkWidget         *widget,
+                            const char        *detail,
+-                             gboolean           scale_requested)
++                           gdouble           scale)
+ {
+   GSList *failed = NULL;
+   GdkPixbuf *pixbuf = NULL;
+@@ -1551,7 +1549,7 @@ find_and_render_icon_source (GtkIconSet       *icon_set,
+    */
+   while (pixbuf == NULL)
+     {
+-      GtkIconSource *source = find_best_matching_source (icon_set, direction, state, size, failed);
++      GtkIconSource *source = find_best_matching_source (icon_set, direction, state, size, scale, failed);
+
+       if (source == NULL)
+       break;
+@@ -1576,7 +1574,7 @@ find_and_render_icon_source (GtkIconSet       *icon_set,
+       case GTK_ICON_SOURCE_STATIC_ICON_NAME:
+         pixbuf = render_icon_name_pixbuf (source, style,
+                                           direction, state, size,
+-                                          widget, detail, scale_requested);
++                                          widget, detail, scale);
+         if (!pixbuf)
+           failed = g_slist_prepend (failed, source);
+         break;
+@@ -1601,7 +1599,7 @@ render_fallback_image (GtkStyle          *style,
+                        const char        *detail)
+ {
+   /* This icon can be used for any direction/state/size */
+-  static GtkIconSource fallback_source = GTK_ICON_SOURCE_INIT (TRUE, TRUE, TRUE);
++  static GtkIconSource fallback_source = GTK_ICON_SOURCE_INIT (TRUE, TRUE, TRUE, TRUE);
+
+   if (fallback_source.type == GTK_ICON_SOURCE_EMPTY)
+     {
+@@ -1652,7 +1650,7 @@ _get_real_scale (GtkWidget   *widget,
+   settings = gtk_settings_get_for_screen (screen);
+   gtk_icon_size_lookup_for_settings (settings, size, &icon_width, NULL);
+
+-  return (gdouble) gdk_pixbuf_get_width (icon) / icon_width;
++  return round ((gdouble) gdk_pixbuf_get_width (icon) / icon_width);
+ }
+
+ GdkPixbuf*
+@@ -1663,28 +1661,23 @@ gtk_icon_set_render_icon_internal (GtkIconSet        *icon_set,
+                                    GtkIconSize        size,
+                                    GtkWidget         *widget,
+                                    const char        *detail,
+-                                   gboolean           scale_requested,
+-                                   gdouble           *real_scale)
++                                 gdouble           *scale)
+ {
+   GdkPixbuf *icon;
+
+-  if (real_scale)
+-    *real_scale = 1;
+-
+   if (icon_set->sources == NULL)
+     return render_fallback_image (style, direction, state, size, widget, detail);
+
+   if (detail == NULL)
+     {
+       icon = find_in_cache (icon_set, style, direction,
+-                        state, size);
++                          state, size, *scale);
+
+       if (icon)
+       {
+         g_object_ref (icon);
+
+-          if (scale_requested && real_scale)
+-            *real_scale = _get_real_scale (widget, style, size, icon);
++        *scale = _get_real_scale (widget, style, size, icon);
+
+         return icon;
+       }
+@@ -1692,16 +1685,15 @@ gtk_icon_set_render_icon_internal (GtkIconSet        *icon_set,
+
+
+   icon = find_and_render_icon_source (icon_set, style, direction, state, size,
+-                                    widget, detail, scale_requested);
++                                    widget, detail, *scale);
+
+   if (icon == NULL)
+     icon = render_fallback_image (style, direction, state, size, widget, detail);
+
+-  if (detail == NULL)
+-    add_to_cache (icon_set, style, direction, state, size, icon);
++  *scale = _get_real_scale (widget, style, size, icon);
+
+-  if (scale_requested && real_scale)
+-    *real_scale = _get_real_scale (widget, style, size, icon);
++  if (detail == NULL)
++    add_to_cache (icon_set, style, direction, state, size, *scale, icon);
+
+   return icon;
+ }
+@@ -1739,12 +1731,14 @@ gtk_icon_set_render_icon (GtkIconSet        *icon_set,
+                           GtkWidget         *widget,
+                           const char        *detail)
+ {
++  gdouble scale = 1;
++
+   g_return_val_if_fail (icon_set != NULL, NULL);
+   g_return_val_if_fail (style == NULL || GTK_IS_STYLE (style), NULL);
+
+   return gtk_icon_set_render_icon_internal (icon_set, style, direction,
+                                             state, size, widget, detail,
+-                                            FALSE, NULL);
++                                            &scale);
+ }
+
+ GdkPixbuf*
+@@ -1755,19 +1749,22 @@ gtk_icon_set_render_icon_scaled (GtkIconSet        *icon_set,
+                                  GtkIconSize        size,
+                                  GtkWidget         *widget,
+                                  const char        *detail,
+-                                 gdouble           *real_scale)
++                                 gdouble           *scale)
+ {
+   g_return_val_if_fail (icon_set != NULL, NULL);
+   g_return_val_if_fail (style == NULL || GTK_IS_STYLE (style), NULL);
++  g_return_val_if_fail (scale != NULL, NULL);
++
++  *scale = MAX (*scale, 1);
+
+   return gtk_icon_set_render_icon_internal (icon_set, style, direction,
+                                             state, size, widget, detail,
+-                                            TRUE, real_scale);
++                                            scale);
+ }
+
+ /* Order sources by their "wildness", so that "wilder" sources are
+  * greater than "specific" sources; for determining ordering,
+- * direction beats state beats size.
++ * direction beats state beats size beats scale.
+  */
+
+ static int
+@@ -1788,6 +1785,10 @@ icon_source_compare (gconstpointer ap, gconstpointer bp)
+     return -1;
+   else if (a->any_size && !b->any_size)
+     return 1;
++  else if (!a->any_scale && b->any_scale)
++    return -1;
++  else if (a->any_scale && !b->any_scale)
++    return 1;
+   else
+     return 0;
+ }
+@@ -1965,10 +1966,12 @@ gtk_icon_source_new (void)
+   src->direction = GTK_TEXT_DIR_NONE;
+   src->size = GTK_ICON_SIZE_INVALID;
+   src->state = GTK_STATE_NORMAL;
++  src->scale = 1;
+
+   src->any_direction = TRUE;
+   src->any_state = TRUE;
+   src->any_size = TRUE;
++  src->any_scale = TRUE;
+
+   return src;
+ }
+@@ -2319,6 +2322,15 @@ gtk_icon_source_set_size_wildcarded (GtkIconSource *source,
+   source->any_size = setting != FALSE;
+ }
+
++void
++gtk_icon_source_set_scale_wildcarded (GtkIconSource *source,
++                                      gboolean       setting)
++{
++  g_return_if_fail (source != NULL);
++
++  source->any_scale = setting != FALSE;
++}
++
+ /**
+  * gtk_icon_source_get_size_wildcarded:
+  * @source: a #GtkIconSource
+@@ -2367,6 +2379,14 @@ gtk_icon_source_get_direction_wildcarded (const GtkIconSource *source)
+   return source->any_direction;
+ }
+
++gboolean
++gtk_icon_source_get_scale_wildcarded (const GtkIconSource *source)
++{
++  g_return_val_if_fail (source != NULL, TRUE);
++
++  return source->any_scale;
++}
++
+ /**
+  * gtk_icon_source_set_direction:
+  * @source: a #GtkIconSource
+@@ -2433,6 +2453,15 @@ gtk_icon_source_set_size (GtkIconSource *source,
+   source->size = size;
+ }
+
++void
++gtk_icon_source_set_scale (GtkIconSource *source,
++                           gdouble        scale)
++{
++  g_return_if_fail (source != NULL);
++
++  source->scale = scale;
++}
++
+ /**
+  * gtk_icon_source_get_direction:
+  * @source: a #GtkIconSource
+@@ -2486,6 +2515,14 @@ gtk_icon_source_get_size (const GtkIconSource *source)
+   return source->size;
+ }
+
++gdouble
++gtk_icon_source_get_scale (const GtkIconSource *source)
++{
++  g_return_val_if_fail (source != NULL, 0);
++
++  return source->scale;
++}
++
+ #define NUM_CACHED_ICONS 8
+
+ typedef struct _CachedIcon CachedIcon;
+@@ -2499,6 +2536,7 @@ struct _CachedIcon
+   GtkTextDirection direction;
+   GtkStateType state;
+   GtkIconSize size;
++  gdouble scale;
+
+   GdkPixbuf *pixbuf;
+ };
+@@ -2529,7 +2567,8 @@ find_in_cache (GtkIconSet      *icon_set,
+                GtkStyle        *style,
+                GtkTextDirection direction,
+                GtkStateType     state,
+-               GtkIconSize      size)
++               GtkIconSize      size,
++               gdouble          scale)
+ {
+   GSList *tmp_list;
+   GSList *prev;
+@@ -2545,6 +2584,7 @@ find_in_cache (GtkIconSet      *icon_set,
+       if (icon->style == style &&
+           icon->direction == direction &&
+           icon->state == state &&
++          icon->scale == scale &&
+           (size == (GtkIconSize)-1 || icon->size == size))
+         {
+           if (prev)
+@@ -2571,6 +2611,7 @@ add_to_cache (GtkIconSet      *icon_set,
+               GtkTextDirection direction,
+               GtkStateType     state,
+               GtkIconSize      size,
++              gdouble          scale,
+               GdkPixbuf       *pixbuf)
+ {
+   CachedIcon *icon;
+@@ -2595,6 +2636,7 @@ add_to_cache (GtkIconSet      *icon_set,
+   icon->direction = direction;
+   icon->state = state;
+   icon->size = size;
++  icon->scale = scale;
+   icon->pixbuf = pixbuf;
+
+   if (icon->style)
+diff --git a/gtk/gtkiconfactory.h b/gtk/gtkiconfactory.h
+index e38f8e6..d646ed9 100644
+--- a/gtk/gtkiconfactory.h
++++ b/gtk/gtkiconfactory.h
+@@ -177,19 +177,24 @@ void             gtk_icon_source_set_state_wildcarded     (GtkIconSource       *
+                                                            gboolean             setting);
+ void             gtk_icon_source_set_size_wildcarded      (GtkIconSource       *source,
+                                                            gboolean             setting);
++void             gtk_icon_source_set_scale_wildcarded     (GtkIconSource       *source,
++                                                           gboolean             setting);
+ gboolean         gtk_icon_source_get_size_wildcarded      (const GtkIconSource *source);
+ gboolean         gtk_icon_source_get_state_wildcarded     (const GtkIconSource *source);
+ gboolean         gtk_icon_source_get_direction_wildcarded (const GtkIconSource *source);
++gboolean         gtk_icon_source_get_scale_wildcarded     (const GtkIconSource *source);
+ void             gtk_icon_source_set_direction            (GtkIconSource       *source,
+                                                            GtkTextDirection     direction);
+ void             gtk_icon_source_set_state                (GtkIconSource       *source,
+                                                            GtkStateType         state);
+ void             gtk_icon_source_set_size                 (GtkIconSource       *source,
+                                                            GtkIconSize          size);
++void             gtk_icon_source_set_scale                (GtkIconSource       *source,
++                                                           gdouble              scale);
+ GtkTextDirection gtk_icon_source_get_direction            (const GtkIconSource *source);
+ GtkStateType     gtk_icon_source_get_state                (const GtkIconSource *source);
+ GtkIconSize      gtk_icon_source_get_size                 (const GtkIconSource *source);
+-
++gdouble          gtk_icon_source_get_scale                (const GtkIconSource *source);
+
+ /* ignore this */
+ void _gtk_icon_set_invalidate_caches (void);
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0060-iconfactory-Add-gtk_cairo_set_source_icon_set.patch b/bockbuild/mac-sdk/patches/gtk/0060-iconfactory-Add-gtk_cairo_set_source_icon_set.patch
new file mode 100644 (file)
index 0000000..15b5bac
--- /dev/null
@@ -0,0 +1,77 @@
+From 2c894a76c7fb002ed276d1d82552fb4e91bb3a78 Mon Sep 17 00:00:00 2001
+From: Carlos Garnacho <carlos@lanedo.com>
+Date: Fri, 10 May 2013 18:29:05 +0200
+Subject: [PATCH 60/68] iconfactory: Add gtk_cairo_set_source_icon_set()
+
+As GtkIconSet remains a good candidate to delay pixbuf lookup until
+the moment of rendering, a cairo helper function has been added
+to easy enabling support for high resolution icons.
+---
+ gtk/gtkiconfactory.c |   32 ++++++++++++++++++++++++++++++++
+ gtk/gtkiconfactory.h |    9 +++++++++
+ 2 files changed, 41 insertions(+)
+
+diff --git a/gtk/gtkiconfactory.c b/gtk/gtkiconfactory.c
+index 41d1ee7..ab9a212 100644
+--- a/gtk/gtkiconfactory.c
++++ b/gtk/gtkiconfactory.c
+@@ -3127,5 +3127,37 @@ gtk_icon_source_get_filename (const GtkIconSource *source)
+
+ #endif
+
++void
++gtk_cairo_set_source_icon_set (cairo_t         *cr,
++                               GtkWidget       *widget,
++                               GtkIconSet      *icon_set,
++                               GtkIconSize      size,
++                               gdouble          scale,
++                               gdouble          icon_x,
++                               gdouble          icon_y)
++{
++  cairo_pattern_t *pattern;
++  cairo_matrix_t matrix;
++  GdkPixbuf *pixbuf;
++
++  g_return_if_fail (GTK_IS_WIDGET (widget));
++  g_return_if_fail (cr != NULL);
++  g_return_if_fail (icon_set != NULL);
++
++  pixbuf = gtk_icon_set_render_icon_scaled (icon_set,
++                                            gtk_widget_get_style (widget),
++                                            gtk_widget_get_direction (widget),
++                                            gtk_widget_get_state (widget),
++                                            size, widget, NULL, &scale);
++  gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
++
++  pattern = cairo_get_source (cr);
++  cairo_matrix_init_scale (&matrix, scale, scale);
++  cairo_matrix_translate (&matrix, -icon_x, -icon_y);
++  cairo_pattern_set_matrix (pattern, &matrix);
++
++  g_object_unref (pixbuf);
++}
++
+ #define __GTK_ICON_FACTORY_C__
+ #include "gtkaliasdef.c"
+diff --git a/gtk/gtkiconfactory.h b/gtk/gtkiconfactory.h
+index d646ed9..67e318a 100644
+--- a/gtk/gtkiconfactory.h
++++ b/gtk/gtkiconfactory.h
+@@ -196,6 +196,15 @@ GtkStateType     gtk_icon_source_get_state                (const GtkIconSource *
+ GtkIconSize      gtk_icon_source_get_size                 (const GtkIconSource *source);
+ gdouble          gtk_icon_source_get_scale                (const GtkIconSource *source);
+
++/* Cairo helper */
++void             gtk_cairo_set_source_icon_set            (cairo_t             *cr,
++                                                           GtkWidget           *widget,
++                                                           GtkIconSet          *icon_set,
++                                                           GtkIconSize          size,
++                                                           gdouble              scale,
++                                                           gdouble              icon_x,
++                                                           gdouble              icon_y);
++
+ /* ignore this */
+ void _gtk_icon_set_invalidate_caches (void);
+ GList* _gtk_icon_factory_list_ids (void);
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0061-image-Use-scaled-icons-on-windows-with-a-scaling-fac.patch b/bockbuild/mac-sdk/patches/gtk/0061-image-Use-scaled-icons-on-windows-with-a-scaling-fac.patch
new file mode 100644 (file)
index 0000000..eaff472
--- /dev/null
@@ -0,0 +1,202 @@
+From a7d250bd2126a146d0e5d77c1083a47285d5dfb7 Mon Sep 17 00:00:00 2001
+From: Carlos Garnacho <carlosg@gnome.org>
+Date: Tue, 12 Feb 2013 14:03:40 +0100
+Subject: [PATCH 61/68] image: Use scaled icons on windows with a scaling
+ factor
+
+---
+ gtk/gtkimage.c |  112 ++++++++++++++++++++++++++++++++++----------------------
+ 1 file changed, 68 insertions(+), 44 deletions(-)
+
+diff --git a/gtk/gtkimage.c b/gtk/gtkimage.c
+index c35d962..b492d73 100644
+--- a/gtk/gtkimage.c
++++ b/gtk/gtkimage.c
+@@ -1717,9 +1717,11 @@ ensure_pixbuf_for_icon_name (GtkImage *image)
+           }
+       }
+       image->data.name.pixbuf =
+-      gtk_icon_theme_load_icon (icon_theme,
+-                                image->data.name.icon_name,
+-                                MIN (width, height), flags, &error);
++      gtk_icon_theme_load_icon_for_scale (icon_theme,
++                                            image->data.name.icon_name,
++                                            MIN (width, height),
++                                            gtk_widget_get_scale_factor (GTK_WIDGET (image)),
++                                            flags, &error);
+       if (image->data.name.pixbuf == NULL)
+       {
+         g_error_free (error);
+@@ -1757,9 +1759,10 @@ ensure_pixbuf_for_gicon (GtkImage *image)
+         width = height = priv->pixel_size;
+           flags |= GTK_ICON_LOOKUP_FORCE_SIZE;
+       }
+-      else if (!gtk_icon_size_lookup_for_settings (settings,
+-                                                 image->icon_size,
+-                                                 &width, &height))
++      else if (!gtk_icon_size_lookup_scaled (settings,
++                                             image->icon_size,
++                                             gtk_widget_get_scale_factor (GTK_WIDGET (image)),
++                                             &width, &height))
+       {
+         if (image->icon_size == -1)
+           width = height = 48;
+@@ -1848,11 +1851,11 @@ gtk_image_expose (GtkWidget      *widget,
+       GdkBitmap *mask;
+       GdkPixbuf *pixbuf;
+       gboolean needs_state_transform;
++      gdouble render_scale = 1.0;
+
+       image = GTK_IMAGE (widget);
+       misc = GTK_MISC (widget);
+       priv = GTK_IMAGE_GET_PRIVATE (image);
+-
+       area = event->area;
+
+       /* For stock items and icon sets, we lazily calculate
+@@ -1954,12 +1957,13 @@ gtk_image_expose (GtkWidget      *widget,
+           break;
+
+         case GTK_IMAGE_STOCK:
+-          pixbuf = gtk_widget_render_icon (widget,
+-                                           image->data.stock.stock_id,
+-                                           image->icon_size,
+-                                           NULL);
++          render_scale = gtk_widget_get_scale_factor (widget);
++          pixbuf = gtk_widget_render_icon_scaled (widget,
++                                                  image->data.stock.stock_id,
++                                                  image->icon_size,
++                                                  NULL, &render_scale);
+           if (pixbuf)
+-            {
++            {
+               image_bound.width = gdk_pixbuf_get_width (pixbuf);
+               image_bound.height = gdk_pixbuf_get_height (pixbuf);
+             }
+@@ -1969,14 +1973,15 @@ gtk_image_expose (GtkWidget      *widget,
+           break;
+
+         case GTK_IMAGE_ICON_SET:
++          render_scale = gtk_widget_get_scale_factor (widget);
+           pixbuf =
+-            gtk_icon_set_render_icon (image->data.icon_set.icon_set,
+-                                      widget->style,
+-                                      gtk_widget_get_direction (widget),
+-                                      gtk_widget_get_state (widget),
+-                                      image->icon_size,
+-                                      widget,
+-                                      NULL);
++            gtk_icon_set_render_icon_scaled (image->data.icon_set.icon_set,
++                                             widget->style,
++                                             gtk_widget_get_direction (widget),
++                                             gtk_widget_get_state (widget),
++                                             image->icon_size,
++                                             widget,
++                                             NULL, &render_scale);
+
+           if (pixbuf)
+             {
+@@ -2082,17 +2087,35 @@ gtk_image_expose (GtkWidget      *widget,
+
+               if (pixbuf)
+                 {
+-                  gdk_draw_pixbuf (widget->window,
+-                                 widget->style->black_gc,
+-                                 pixbuf,
+-                                 image_bound.x - x,
+-                                 image_bound.y - y,
+-                                 image_bound.x,
+-                                 image_bound.y,
+-                                 image_bound.width,
+-                                 image_bound.height,
+-                                 GDK_RGB_DITHER_NORMAL,
+-                                 0, 0);
++                  if (render_scale == 1)
++                    {
++                      gdk_draw_pixbuf (widget->window,
++                                       widget->style->black_gc,
++                                       pixbuf,
++                                       image_bound.x - x,
++                                       image_bound.y - y,
++                                       image_bound.x,
++                                       image_bound.y,
++                                       image_bound.width,
++                                       image_bound.height,
++                                       GDK_RGB_DITHER_NORMAL,
++                                       0, 0);
++                    }
++                  else
++                    {
++                      cairo_t *cr = gdk_cairo_create (widget->window);
++
++                      gdk_cairo_region (cr, event->region);
++                      cairo_clip (cr);
++
++                      cairo_scale (cr, 1.0 / render_scale, 1.0 / render_scale);
++                      gdk_cairo_set_source_pixbuf (cr, pixbuf,
++                                                   image_bound.x * render_scale,
++                                                   image_bound.y * render_scale);
++
++                      cairo_paint (cr);
++                      cairo_destroy (cr);
++                    }
+                 }
+             }
+           else
+@@ -2298,8 +2321,10 @@ gtk_image_calc_size (GtkImage *image)
+   GtkWidget *widget = GTK_WIDGET (image);
+   GdkPixbuf *pixbuf = NULL;
+   GtkImagePrivate *priv;
++  gdouble render_scale;
+
+   priv = GTK_IMAGE_GET_PRIVATE (image);
++  render_scale = gtk_widget_get_scale_factor (widget);
+
+   priv->need_calc_size = 0;
+
+@@ -2311,20 +2336,20 @@ gtk_image_calc_size (GtkImage *image)
+   switch (image->storage_type)
+     {
+     case GTK_IMAGE_STOCK:
+-      pixbuf = gtk_widget_render_icon (widget,
+-                                     image->data.stock.stock_id,
+-                                       image->icon_size,
+-                                       NULL);
++      pixbuf = gtk_widget_render_icon_scaled (widget,
++                                              image->data.stock.stock_id,
++                                              image->icon_size,
++                                              NULL, &render_scale);
+       break;
+
+     case GTK_IMAGE_ICON_SET:
+-      pixbuf = gtk_icon_set_render_icon (image->data.icon_set.icon_set,
+-                                         widget->style,
+-                                         gtk_widget_get_direction (widget),
+-                                         gtk_widget_get_state (widget),
+-                                         image->icon_size,
+-                                         widget,
+-                                         NULL);
++      pixbuf = gtk_icon_set_render_icon_scaled (image->data.icon_set.icon_set,
++                                                widget->style,
++                                                gtk_widget_get_direction (widget),
++                                                gtk_widget_get_state (widget),
++                                                image->icon_size,
++                                                widget,
++                                                NULL, &render_scale);
+       break;
+     case GTK_IMAGE_ICON_NAME:
+       ensure_pixbuf_for_icon_name (image);
+@@ -2343,9 +2368,8 @@ gtk_image_calc_size (GtkImage *image)
+
+   if (pixbuf)
+     {
+-      widget->requisition.width = gdk_pixbuf_get_width (pixbuf) + GTK_MISC (image)->xpad * 2;
+-      widget->requisition.height = gdk_pixbuf_get_height (pixbuf) + GTK_MISC (image)->ypad * 2;
+-
++      widget->requisition.width = (gdk_pixbuf_get_width (pixbuf) / render_scale) + GTK_MISC (image)->xpad * 2;
++      widget->requisition.height = (gdk_pixbuf_get_height (pixbuf) / render_scale) + GTK_MISC (image)->ypad * 2;
+       g_object_unref (pixbuf);
+     }
+ }
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0062-cellrendererpixbuf-Use-scaled-icons-on-windows-with-.patch b/bockbuild/mac-sdk/patches/gtk/0062-cellrendererpixbuf-Use-scaled-icons-on-windows-with-.patch
new file mode 100644 (file)
index 0000000..eda1435
--- /dev/null
@@ -0,0 +1,227 @@
+From 52cba71be7d226b628731ea92c2064bf41f08b54 Mon Sep 17 00:00:00 2001
+From: Carlos Garnacho <carlosg@gnome.org>
+Date: Tue, 12 Feb 2013 14:04:09 +0100
+Subject: [PATCH 62/68] cellrendererpixbuf: Use scaled icons on windows with a
+ scale factor
+
+---
+ gtk/gtkcellrendererpixbuf.c |  115 ++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 102 insertions(+), 13 deletions(-)
+
+diff --git a/gtk/gtkcellrendererpixbuf.c b/gtk/gtkcellrendererpixbuf.c
+index f689784..7c767b6 100644
+--- a/gtk/gtkcellrendererpixbuf.c
++++ b/gtk/gtkcellrendererpixbuf.c
+@@ -63,7 +63,8 @@ enum {
+   PROP_STOCK_DETAIL,
+   PROP_FOLLOW_STATE,
+   PROP_ICON_NAME,
+-  PROP_GICON
++  PROP_GICON,
++  PROP_ICON_SET
+ };
+
+
+@@ -78,6 +79,8 @@ struct _GtkCellRendererPixbufPrivate
+   gboolean follow_state;
+   gchar *icon_name;
+   GIcon *gicon;
++  GtkIconSet *icon_set;
++  gdouble render_scale;
+ };
+
+ G_DEFINE_TYPE (GtkCellRendererPixbuf, gtk_cell_renderer_pixbuf, GTK_TYPE_CELL_RENDERER)
+@@ -173,6 +176,14 @@ gtk_cell_renderer_pixbuf_class_init (GtkCellRendererPixbufClass *class)
+                                                       NULL,
+                                                       GTK_PARAM_READWRITE));
+
++  g_object_class_install_property (object_class,
++                                   PROP_ICON_SET,
++                                   g_param_spec_boxed ("icon-set",
++                                                       P_("Icon set"),
++                                                       P_("Icon set to render the image from"),
++                                                       GTK_TYPE_ICON_SET,
++                                                       GTK_PARAM_READWRITE));
++
+   /**
+    * GtkCellRendererPixbuf:follow-state:
+    *
+@@ -277,6 +288,9 @@ gtk_cell_renderer_pixbuf_get_property (GObject        *object,
+     case PROP_GICON:
+       g_value_set_object (value, priv->gicon);
+       break;
++    case PROP_ICON_SET:
++      g_value_set_boxed (value, priv->icon_set);
++      break;
+     default:
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+       break;
+@@ -300,6 +314,7 @@ gtk_cell_renderer_pixbuf_set_property (GObject      *object,
+       if (cellpixbuf->pixbuf)
+       g_object_unref (cellpixbuf->pixbuf);
+       cellpixbuf->pixbuf = (GdkPixbuf*) g_value_dup_object (value);
++      priv->render_scale = 1;
+       if (cellpixbuf->pixbuf)
+         {
+           if (priv->stock_id)
+@@ -422,6 +437,7 @@ gtk_cell_renderer_pixbuf_set_property (GObject      *object,
+         g_object_unref (priv->gicon);
+       }
+       priv->gicon = (GIcon *) g_value_dup_object (value);
++      priv->render_scale = 1;
+       if (priv->gicon)
+         {
+         if (cellpixbuf->pixbuf)
+@@ -444,6 +460,49 @@ gtk_cell_renderer_pixbuf_set_property (GObject      *object,
+             }
+         }
+       break;
++    case PROP_ICON_SET:
++      if (priv->icon_set)
++      {
++        if (cellpixbuf->pixbuf)
++          {
++            g_object_unref (cellpixbuf->pixbuf);
++            cellpixbuf->pixbuf = NULL;
++              g_object_notify (object, "pixbuf");
++          }
++
++          gtk_icon_set_unref (priv->icon_set);
++      }
++
++      priv->icon_set = g_value_dup_boxed (value);
++
++      if (priv->icon_set)
++        {
++        if (cellpixbuf->pixbuf)
++          {
++              g_object_unref (cellpixbuf->pixbuf);
++              cellpixbuf->pixbuf = NULL;
++              g_object_notify (object, "pixbuf");
++          }
++          if (priv->stock_id)
++            {
++              g_free (priv->stock_id);
++              priv->stock_id = NULL;
++              g_object_notify (object, "stock-id");
++            }
++          if (priv->icon_name)
++            {
++              g_free (priv->icon_name);
++              priv->icon_name = NULL;
++              g_object_notify (object, "icon-name");
++            }
++          if (priv->gicon)
++            {
++              g_object_unref (priv->gicon);
++              priv->gicon = NULL;
++              g_object_notify (object, "gicon");
++            }
++        }
++      break;
+     default:
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+       break;
+@@ -474,16 +533,19 @@ gtk_cell_renderer_pixbuf_create_stock_pixbuf (GtkCellRendererPixbuf *cellpixbuf,
+                                               GtkWidget             *widget)
+ {
+   GtkCellRendererPixbufPrivate *priv;
++  GtkIconSet *icon_set;
+
+   priv = GTK_CELL_RENDERER_PIXBUF_GET_PRIVATE (cellpixbuf);
+
+   if (cellpixbuf->pixbuf)
+     g_object_unref (cellpixbuf->pixbuf);
+
+-  cellpixbuf->pixbuf = gtk_widget_render_icon (widget,
+-                                               priv->stock_id,
+-                                               priv->stock_size,
+-                                               priv->stock_detail);
++  priv->render_scale = gtk_widget_get_scale_factor (widget);
++  cellpixbuf->pixbuf = gtk_widget_render_icon_scaled (widget,
++                                                      priv->stock_id,
++                                                      priv->stock_size,
++                                                      priv->stock_detail,
++                                                      &priv->render_scale);
+
+   g_object_notify (G_OBJECT (cellpixbuf), "pixbuf");
+ }
+@@ -510,15 +572,24 @@ gtk_cell_renderer_pixbuf_create_themed_pixbuf (GtkCellRendererPixbuf *cellpixbuf
+   icon_theme = gtk_icon_theme_get_for_screen (screen);
+   settings = gtk_settings_get_for_screen (screen);
+
+-  if (!gtk_icon_size_lookup_for_settings (settings,
+-                                        priv->stock_size,
+-                                        &width, &height))
++  if (!gtk_icon_size_lookup_scaled (settings,
++                                    priv->stock_size,
++                                    gdk_window_get_scale_factor (GTK_WIDGET (widget)->window),
++                                    &width, &height))
+     {
+       g_warning ("Invalid icon size %u\n", priv->stock_size);
+       width = height = 24;
+     }
+
+-  if (priv->icon_name)
++  if (priv->icon_set)
++    cellpixbuf->pixbuf =
++      gtk_icon_set_render_icon_scaled (priv->icon_set,
++                                       widget->style,
++                                       gtk_widget_get_direction (widget),
++                                       gtk_widget_get_state (widget),
++                                       priv->stock_size, widget,
++                                       NULL, &priv->render_scale);
++  else if (priv->icon_name)
+     cellpixbuf->pixbuf = gtk_icon_theme_load_icon (icon_theme,
+                                                  priv->icon_name,
+                                                  MIN (width, height),
+@@ -611,14 +682,28 @@ gtk_cell_renderer_pixbuf_get_size (GtkCellRenderer *cell,
+     {
+       if (priv->stock_id)
+       gtk_cell_renderer_pixbuf_create_stock_pixbuf (cellpixbuf, widget);
++      else if (priv->icon_set)
++        {
++          gdouble scale;
++
++          scale = gtk_widget_get_scale_factor (widget);
++          cellpixbuf->pixbuf =
++            gtk_icon_set_render_icon_scaled (priv->icon_set,
++                                             widget->style,
++                                             gtk_widget_get_direction (widget),
++                                             gtk_widget_get_state (widget),
++                                             priv->stock_size,
++                                             widget, priv->stock_detail,
++                                             &scale);
++        }
+       else if (priv->icon_name || priv->gicon)
+       gtk_cell_renderer_pixbuf_create_themed_pixbuf (cellpixbuf, widget);
+     }
+
+   if (cellpixbuf->pixbuf)
+     {
+-      pixbuf_width  = gdk_pixbuf_get_width (cellpixbuf->pixbuf);
+-      pixbuf_height = gdk_pixbuf_get_height (cellpixbuf->pixbuf);
++      pixbuf_width  = gdk_pixbuf_get_width (cellpixbuf->pixbuf) / priv->render_scale;
++      pixbuf_height = gdk_pixbuf_get_height (cellpixbuf->pixbuf) / priv->render_scale;
+     }
+   if (cellpixbuf->pixbuf_expander_open)
+     {
+@@ -761,10 +846,14 @@ gtk_cell_renderer_pixbuf_render (GtkCellRenderer      *cell,
+       pixbuf = colorized;
+     }
+
++  draw_rect.x -= pix_rect.x;
++  draw_rect.y -= pix_rect.y;
++
+   cr = gdk_cairo_create (window);
+-
+-  gdk_cairo_set_source_pixbuf (cr, pixbuf, pix_rect.x, pix_rect.y);
++  cairo_translate (cr, pix_rect.x, pix_rect.y);
+   gdk_cairo_rectangle (cr, &draw_rect);
++  cairo_scale (cr, 1 / priv->render_scale, 1 / priv->render_scale);
++  gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
+   cairo_fill (cr);
+
+   cairo_destroy (cr);
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0063-entry-Use-scaled-icons-on-windows-with-a-scale-facto.patch b/bockbuild/mac-sdk/patches/gtk/0063-entry-Use-scaled-icons-on-windows-with-a-scale-facto.patch
new file mode 100644 (file)
index 0000000..81c969d
--- /dev/null
@@ -0,0 +1,351 @@
+From aba260146c099864e69379e31bd3decbf3681817 Mon Sep 17 00:00:00 2001
+From: Carlos Garnacho <carlosg@gnome.org>
+Date: Tue, 12 Feb 2013 14:04:37 +0100
+Subject: [PATCH 63/68] entry: Use scaled icons on windows with a scale factor
+
+---
+ gtk/gtkentry.c |  184 ++++++++++++++++++++++++++++++++++++++++++++++++++------
+ gtk/gtkentry.h |    7 +++
+ 2 files changed, 171 insertions(+), 20 deletions(-)
+
+diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c
+index 0d16d71..313804e 100644
+--- a/gtk/gtkentry.c
++++ b/gtk/gtkentry.c
+@@ -105,9 +105,11 @@ typedef struct
+   gchar        *stock_id;
+   gchar        *icon_name;
+   GIcon        *gicon;
++  GtkIconSet   *icon_set;
+
+   GtkTargetList *target_list;
+   GdkDragAction actions;
++  gdouble render_scale;
+ } EntryIconInfo;
+
+ struct _GtkEntryPrivate
+@@ -207,6 +209,8 @@ enum {
+   PROP_ICON_NAME_SECONDARY,
+   PROP_GICON_PRIMARY,
+   PROP_GICON_SECONDARY,
++  PROP_ICON_SET_PRIMARY,
++  PROP_ICON_SET_SECONDARY,
+   PROP_STORAGE_TYPE_PRIMARY,
+   PROP_STORAGE_TYPE_SECONDARY,
+   PROP_ACTIVATABLE_PRIMARY,
+@@ -1009,7 +1013,21 @@ gtk_entry_class_init (GtkEntryClass *class)
+                                                         P_("GIcon for secondary icon"),
+                                                         G_TYPE_ICON,
+                                                         GTK_PARAM_READWRITE));
+-
++  g_object_class_install_property (gobject_class,
++                                   PROP_ICON_SET_PRIMARY,
++                                   g_param_spec_boxed ("primary-icon-set",
++                                                       P_("Primary icon set"),
++                                                       P_("GtkIconSet for the primary icon"),
++                                                       GTK_TYPE_ICON_SET,
++                                                       GTK_PARAM_READWRITE));
++  g_object_class_install_property (gobject_class,
++                                   PROP_ICON_SET_SECONDARY,
++                                   g_param_spec_boxed ("secondary-icon-set",
++                                                       P_("Secondary icon set"),
++                                                       P_("GtkIconSet for the secondary icon"),
++                                                       GTK_TYPE_ICON_SET,
++                                                       GTK_PARAM_READWRITE));
++
+   /**
+    * GtkEntry:primary-icon-storage-type:
+    *
+@@ -1940,6 +1958,18 @@ gtk_entry_set_property (GObject         *object,
+                                      g_value_get_object (value));
+       break;
+
++    case PROP_ICON_SET_PRIMARY:
++      gtk_entry_set_icon_from_icon_set (entry,
++                                        GTK_ENTRY_ICON_PRIMARY,
++                                        g_value_get_boxed (value));
++      break;
++
++    case PROP_ICON_SET_SECONDARY:
++      gtk_entry_set_icon_from_icon_set (entry,
++                                        GTK_ENTRY_ICON_SECONDARY,
++                                        g_value_get_boxed (value));
++      break;
++
+     case PROP_ACTIVATABLE_PRIMARY:
+       gtk_entry_set_icon_activatable (entry,
+                                       GTK_ENTRY_ICON_PRIMARY,
+@@ -2158,6 +2188,18 @@ gtk_entry_get_property (GObject         *object,
+                                                     GTK_ENTRY_ICON_SECONDARY));
+       break;
+
++    case PROP_ICON_SET_PRIMARY:
++      g_value_set_boxed (value,
++                         gtk_entry_get_icon_set (entry,
++                                                 GTK_ENTRY_ICON_PRIMARY));
++      break;
++
++    case PROP_ICON_SET_SECONDARY:
++      g_value_set_boxed (value,
++                         gtk_entry_get_icon_set (entry,
++                                                 GTK_ENTRY_ICON_SECONDARY));
++      break;
++
+     case PROP_STORAGE_TYPE_PRIMARY:
+       g_value_set_enum (value,
+                         gtk_entry_get_icon_storage_type (entry,
+@@ -2334,7 +2376,9 @@ get_icon_width (GtkEntry             *entry,
+   gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU,
+                                      &menu_icon_width, NULL);
+
+-  return MAX (gdk_pixbuf_get_width (icon_info->pixbuf), menu_icon_width);
++  return MAX (gdk_pixbuf_get_width (icon_info->pixbuf) /
++              gtk_widget_get_scale_factor (GTK_WIDGET (entry)),
++              menu_icon_width);
+ }
+
+ static void
+@@ -3188,6 +3232,7 @@ draw_icon (GtkWidget            *widget,
+   EntryIconInfo *icon_info = priv->icons[icon_pos];
+   GdkPixbuf *pixbuf;
+   gint x, y, width, height;
++  gdouble window_scale;
+   cairo_t *cr;
+
+   if (!icon_info)
+@@ -3198,8 +3243,9 @@ draw_icon (GtkWidget            *widget,
+   if (icon_info->pixbuf == NULL)
+     return;
+
+-  width = gdk_window_get_width (icon_info->window);
+-  height = gdk_window_get_height (icon_info->window);
++  window_scale = gdk_window_get_scale_factor (widget->window);
++  width = gdk_window_get_width (icon_info->window) / window_scale;
++  height = gdk_window_get_height (icon_info->window) / window_scale;
+
+   /* size_allocate hasn't been called yet. These are the default values.
+    */
+@@ -3209,20 +3255,20 @@ draw_icon (GtkWidget            *widget,
+   pixbuf = icon_info->pixbuf;
+   g_object_ref (pixbuf);
+
+-  if (gdk_pixbuf_get_height (pixbuf) > height)
++  if (gdk_pixbuf_get_height (pixbuf) > (height * window_scale))
+     {
+       GdkPixbuf *temp_pixbuf;
+       gint scale;
+
+-      scale = height - 2 * priv->icon_margin;
++      scale = (height - 2 * priv->icon_margin) * window_scale;
+       temp_pixbuf = gdk_pixbuf_scale_simple (pixbuf, scale, scale,
+                                              GDK_INTERP_BILINEAR);
+       g_object_unref (pixbuf);
+       pixbuf = temp_pixbuf;
+     }
+
+-  x = (width  - gdk_pixbuf_get_width (pixbuf)) / 2;
+-  y = (height - gdk_pixbuf_get_height (pixbuf)) / 2;
++  x = (width  - (gdk_pixbuf_get_width (pixbuf) / window_scale)) / 2;
++  y = (height - (gdk_pixbuf_get_height (pixbuf) / window_scale)) / 2;
+
+   if (!gtk_widget_is_sensitive (widget) ||
+       icon_info->insensitive)
+@@ -6455,6 +6501,17 @@ gtk_entry_clear (GtkEntry             *entry,
+                        icon_pos == GTK_ENTRY_ICON_PRIMARY ? "primary-icon-gicon" : "secondary-icon-gicon");
+       break;
+
++    case GTK_IMAGE_ICON_SET:
++      if (icon_info->icon_set)
++        {
++          gtk_icon_set_unref (icon_info->icon_set);
++          icon_info->icon_set = NULL;
++        }
++
++      g_object_notify (G_OBJECT (entry),
++                       icon_pos == GTK_ENTRY_ICON_PRIMARY ? "primary-icon-set" : "secondary-icon-set");
++      break;
++
+     default:
+       g_assert_not_reached ();
+       break;
+@@ -6494,15 +6551,18 @@ gtk_entry_ensure_pixbuf (GtkEntry             *entry,
+     case GTK_IMAGE_STOCK:
+       state = gtk_widget_get_state (widget);
+       gtk_widget_set_state (widget, GTK_STATE_NORMAL);
+-      icon_info->pixbuf = gtk_widget_render_icon (widget,
+-                                                  icon_info->stock_id,
+-                                                  GTK_ICON_SIZE_MENU,
+-                                                  NULL);
++      icon_info->render_scale = gtk_widget_get_scale_factor (widget);
++      icon_info->pixbuf = gtk_widget_render_icon_scaled (widget,
++                                                         icon_info->stock_id,
++                                                         GTK_ICON_SIZE_MENU,
++                                                         NULL,
++                                                         &icon_info->render_scale);
+       if (!icon_info->pixbuf)
+-        icon_info->pixbuf = gtk_widget_render_icon (widget,
+-                                                    GTK_STOCK_MISSING_IMAGE,
+-                                                    GTK_ICON_SIZE_MENU,
+-                                                    NULL);
++        icon_info->pixbuf = gtk_widget_render_icon_scaled (widget,
++                                                           GTK_STOCK_MISSING_IMAGE,
++                                                           GTK_ICON_SIZE_MENU,
++                                                           NULL,
++                                                           &icon_info->render_scale);
+       gtk_widget_set_state (widget, state);
+       break;
+
+@@ -6514,8 +6574,9 @@ gtk_entry_ensure_pixbuf (GtkEntry             *entry,
+           settings = gtk_settings_get_for_screen (screen);
+
+           gtk_icon_size_lookup_for_settings (settings,
+-                                             GTK_ICON_SIZE_MENU,
+-                                             &width, &height);
++                                       GTK_ICON_SIZE_MENU,
++                                //                                       gdk_window_get_scale_factor (widget->window),
++                                       &width, &height);
+
+           icon_info->pixbuf = gtk_icon_theme_load_icon (icon_theme,
+                                                         icon_info->icon_name,
+@@ -6543,8 +6604,9 @@ gtk_entry_ensure_pixbuf (GtkEntry             *entry,
+           settings = gtk_settings_get_for_screen (screen);
+
+           gtk_icon_size_lookup_for_settings (settings,
+-                                             GTK_ICON_SIZE_MENU,
+-                                             &width, &height);
++                                       GTK_ICON_SIZE_MENU,
++                                             //gdk_window_get_scale_factor (widget->window),
++                                       &width, &height);
+
+           info = gtk_icon_theme_lookup_by_gicon (icon_theme,
+                                                  icon_info->gicon,
+@@ -6569,6 +6631,17 @@ gtk_entry_ensure_pixbuf (GtkEntry             *entry,
+         }
+       break;
+
++    case GTK_IMAGE_ICON_SET:
++      icon_info->render_scale = gtk_widget_get_scale_factor (widget);
++      icon_info->pixbuf =
++        gtk_icon_set_render_icon_scaled (icon_info->icon_set,
++                                         widget->style,
++                                         gtk_widget_get_direction (widget),
++                                         gtk_widget_get_state (widget),
++                                         GTK_ICON_SIZE_MENU, widget,
++                                         NULL, &icon_info->render_scale);
++      break;
++
+     default:
+       g_assert_not_reached ();
+       break;
+@@ -7847,6 +7920,58 @@ gtk_entry_set_icon_from_gicon (GtkEntry             *entry,
+   g_object_thaw_notify (G_OBJECT (entry));
+ }
+
++void
++gtk_entry_set_icon_from_icon_set (GtkEntry             *entry,
++                                  GtkEntryIconPosition  icon_pos,
++                                  GtkIconSet           *icon_set)
++{
++  GtkEntryPrivate *priv;
++  EntryIconInfo *icon_info;
++
++  g_return_if_fail (GTK_IS_ENTRY (entry));
++  g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
++
++  priv = GTK_ENTRY_GET_PRIVATE (entry);
++
++  if ((icon_info = priv->icons[icon_pos]) == NULL)
++    icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos);
++
++  g_object_freeze_notify (G_OBJECT (entry));
++
++  /* need to ref before clearing */
++  if (icon_set)
++    gtk_icon_set_ref (icon_set);
++
++  gtk_entry_clear (entry, icon_pos);
++
++  if (icon_set)
++    {
++      icon_info->storage_type = GTK_IMAGE_ICON_SET;
++      icon_info->icon_set = icon_set;
++
++      if (icon_pos == GTK_ENTRY_ICON_PRIMARY)
++        {
++          g_object_notify (G_OBJECT (entry), "primary-icon-set");
++          g_object_notify (G_OBJECT (entry), "primary-icon-storage-type");
++        }
++      else
++        {
++          g_object_notify (G_OBJECT (entry), "secondary-icon-set");
++          g_object_notify (G_OBJECT (entry), "secondary-icon-storage-type");
++        }
++
++      if (gtk_widget_get_mapped (GTK_WIDGET (entry)))
++          gdk_window_show_unraised (icon_info->window);
++    }
++
++  gtk_entry_ensure_pixbuf (entry, icon_pos);
++
++  if (gtk_widget_get_visible (GTK_WIDGET (entry)))
++    gtk_widget_queue_resize (GTK_WIDGET (entry));
++
++  g_object_thaw_notify (G_OBJECT (entry));
++}
++
+ /**
+  * gtk_entry_set_icon_activatable:
+  * @entry: A #GtkEntry
+@@ -8050,6 +8175,25 @@ gtk_entry_get_icon_name (GtkEntry             *entry,
+   return icon_info->storage_type == GTK_IMAGE_ICON_NAME ? icon_info->icon_name : NULL;
+ }
+
++const GtkIconSet *
++gtk_entry_get_icon_set (GtkEntry             *entry,
++                        GtkEntryIconPosition  icon_pos)
++{
++  GtkEntryPrivate *priv;
++  EntryIconInfo *icon_info;
++
++  g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
++  g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), NULL);
++
++  priv = GTK_ENTRY_GET_PRIVATE (entry);
++  icon_info = priv->icons[icon_pos];
++
++  if (!icon_info)
++    return NULL;
++
++  return icon_info->storage_type == GTK_IMAGE_ICON_SET ? icon_info->icon_set : NULL;
++}
++
+ /**
+  * gtk_entry_set_icon_sensitive:
+  * @entry: A #GtkEntry
+diff --git a/gtk/gtkentry.h b/gtk/gtkentry.h
+index f771e17..0153f49 100644
+--- a/gtk/gtkentry.h
++++ b/gtk/gtkentry.h
+@@ -264,6 +264,9 @@ void           gtk_entry_set_icon_from_icon_name         (GtkEntry             *
+ void           gtk_entry_set_icon_from_gicon             (GtkEntry             *entry,
+                                                         GtkEntryIconPosition  icon_pos,
+                                                         GIcon                *icon);
++void           gtk_entry_set_icon_from_icon_set          (GtkEntry             *entry,
++                                                        GtkEntryIconPosition  icon_pos,
++                                                        GtkIconSet           *icon_set);
+ GtkImageType gtk_entry_get_icon_storage_type             (GtkEntry             *entry,
+                                                         GtkEntryIconPosition  icon_pos);
+ GdkPixbuf*   gtk_entry_get_icon_pixbuf                   (GtkEntry             *entry,
+@@ -274,6 +277,10 @@ const gchar* gtk_entry_get_icon_name                     (GtkEntry             *
+                                                         GtkEntryIconPosition  icon_pos);
+ GIcon*       gtk_entry_get_icon_gicon                    (GtkEntry             *entry,
+                                                         GtkEntryIconPosition  icon_pos);
++const GtkIconSet *
++             gtk_entry_get_icon_set                      (GtkEntry             *entry,
++                                                          GtkEntryIconPosition  icon_pos);
++
+ void         gtk_entry_set_icon_activatable              (GtkEntry             *entry,
+                                                         GtkEntryIconPosition  icon_pos,
+                                                         gboolean              activatable);
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0064-gdk-Lookup-double-scaled-variants-on-pixbufs.patch b/bockbuild/mac-sdk/patches/gtk/0064-gdk-Lookup-double-scaled-variants-on-pixbufs.patch
new file mode 100644 (file)
index 0000000..2aeac73
--- /dev/null
@@ -0,0 +1,119 @@
+From 67197e562dbdfdbd518d1e8ffb4746af41c3f731 Mon Sep 17 00:00:00 2001
+From: Carlos Garnacho <carlosg@gnome.org>
+Date: Fri, 17 May 2013 15:58:15 +0200
+Subject: [PATCH 64/68] gdk: Lookup double scaled variants on pixbufs
+
+if the pixbuf contains its @2x variant as gobject data and
+the display has a doubled scale factor, use such pixbuf
+for rendering
+---
+ gdk/gdkcairo.c |   36 ++++++++++++++++++++++++++++++++++--
+ gdk/gdkdraw.c  |   18 ++++++++++++++++++
+ 2 files changed, 52 insertions(+), 2 deletions(-)
+
+diff --git a/gdk/gdkcairo.c b/gdk/gdkcairo.c
+index c423871..9aab5e1 100644
+--- a/gdk/gdkcairo.c
++++ b/gdk/gdkcairo.c
+@@ -23,6 +23,8 @@
+ #include "gdkregion-generic.h"
+ #include "gdkalias.h"
+
++static const cairo_user_data_key_t gdk_cairo_drawable_pointer;
++
+ static void
+ gdk_ensure_surface_flush (gpointer surface)
+ {
+@@ -58,6 +60,7 @@ gdk_cairo_create (GdkDrawable *drawable)
+
+   surface = _gdk_drawable_ref_cairo_surface (drawable);
+   cr = cairo_create (surface);
++  cairo_set_user_data (cr, &gdk_cairo_drawable_pointer, drawable, NULL);
+
+   if (GDK_DRAWABLE_GET_CLASS (drawable)->set_cairo_clip)
+     GDK_DRAWABLE_GET_CLASS (drawable)->set_cairo_clip (drawable, cr);
+@@ -202,7 +205,32 @@ gdk_cairo_set_source_pixbuf (cairo_t         *cr,
+   cairo_format_t format;
+   cairo_surface_t *surface;
+   static const cairo_user_data_key_t key;
+-  int j;
++  GdkWindow *window;
++  cairo_pattern_t *pattern;
++  cairo_matrix_t matrix;
++  int j, scale = 1;
++
++  window = cairo_get_user_data (cr, &gdk_cairo_drawable_pointer);
++
++  if (window &&
++      (int) gdk_window_get_scale_factor (window) == 2)
++    {
++      GdkPixbuf *scaled_pixbuf;
++
++      scaled_pixbuf = g_object_get_data (G_OBJECT (pixbuf),
++                                         "gdk-pixbuf-2x-variant");
++      if (scaled_pixbuf)
++        {
++          scale = 2;
++          pixbuf = scaled_pixbuf;
++        }
++    }
++
++  width = gdk_pixbuf_get_width (pixbuf);
++  height = gdk_pixbuf_get_height (pixbuf);
++  gdk_pixels = gdk_pixbuf_get_pixels (pixbuf);
++  gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
++  n_channels = gdk_pixbuf_get_n_channels (pixbuf);
+
+   if (n_channels == 3)
+     format = CAIRO_FORMAT_RGB24;
+@@ -274,7 +302,11 @@ gdk_cairo_set_source_pixbuf (cairo_t         *cr,
+       cairo_pixels += cairo_stride;
+     }
+
+-  cairo_set_source_surface (cr, surface, pixbuf_x, pixbuf_y);
++  cairo_set_source_surface (cr, surface, 0, 0);
++  pattern = cairo_get_source (cr);
++  cairo_matrix_init_scale (&matrix, scale, scale);
++  cairo_matrix_translate (&matrix, -pixbuf_x, -pixbuf_y);
++  cairo_pattern_set_matrix (pattern, &matrix);
+   cairo_surface_destroy (surface);
+ }
+
+diff --git a/gdk/gdkdraw.c b/gdk/gdkdraw.c
+index 932de97..6ebd8c7 100644
+--- a/gdk/gdkdraw.c
++++ b/gdk/gdkdraw.c
+@@ -819,6 +819,8 @@ gdk_draw_pixbuf (GdkDrawable     *drawable,
+                  gint             x_dither,
+                  gint             y_dither)
+ {
++  GdkPixbuf *scaled_pixbuf;
++
+   g_return_if_fail (GDK_IS_DRAWABLE (drawable));
+   g_return_if_fail (gc == NULL || GDK_IS_GC (gc));
+   g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
+@@ -826,6 +828,22 @@ gdk_draw_pixbuf (GdkDrawable     *drawable,
+   if (width == 0 || height == 0)
+     return;
+
++  scaled_pixbuf = g_object_get_data (G_OBJECT (pixbuf),
++                                     "gdk-pixbuf-2x-variant");
++
++  if (scaled_pixbuf && GDK_IS_WINDOW (drawable) &&
++      (int) gdk_window_get_scale_factor (GDK_WINDOW (drawable)) == 2)
++    {
++      cairo_t *cr;
++
++      cr = gdk_cairo_create (GDK_WINDOW (drawable));
++      gdk_cairo_set_source_pixbuf (cr, pixbuf, dest_x, dest_y);
++      cairo_paint (cr);
++
++      cairo_destroy (cr);
++      return;
++    }
++
+   if (width == -1)
+     width = gdk_pixbuf_get_width (pixbuf);
+   if (height == -1)
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0065-Make-usual-calls-to-get-a-GdkPixbuf-attach-a-2x-vari.patch b/bockbuild/mac-sdk/patches/gtk/0065-Make-usual-calls-to-get-a-GdkPixbuf-attach-a-2x-vari.patch
new file mode 100644 (file)
index 0000000..665c950
--- /dev/null
@@ -0,0 +1,197 @@
+From 318b7822a8a737a826aab50e1a829a6b59c9704f Mon Sep 17 00:00:00 2001
+From: Carlos Garnacho <carlosg@gnome.org>
+Date: Fri, 14 Jun 2013 15:47:44 +0200
+Subject: [PATCH 65/68] Make usual calls to get a GdkPixbuf attach a 2x
+ variant if available
+
+---
+ gtk/gtkiconfactory.c |   24 ++++++++++++++++++---
+ gtk/gtkicontheme.c   |   57 +++++++++++++++++++++++++++++++++++++++++++++-----
+ gtk/gtkwidget.c      |   20 ++++++++++++++----
+ 3 files changed, 89 insertions(+), 12 deletions(-)
+
+diff --git a/gtk/gtkiconfactory.c b/gtk/gtkiconfactory.c
+index ab9a212..291c05e 100644
+--- a/gtk/gtkiconfactory.c
++++ b/gtk/gtkiconfactory.c
+@@ -1731,14 +1731,32 @@ gtk_icon_set_render_icon (GtkIconSet        *icon_set,
+                           GtkWidget         *widget,
+                           const char        *detail)
+ {
++  GdkPixbuf *pixbuf, *variant;
+   gdouble scale = 1;
+
+   g_return_val_if_fail (icon_set != NULL, NULL);
+   g_return_val_if_fail (style == NULL || GTK_IS_STYLE (style), NULL);
+
+-  return gtk_icon_set_render_icon_internal (icon_set, style, direction,
+-                                            state, size, widget, detail,
+-                                            &scale);
++  pixbuf = gtk_icon_set_render_icon_internal (icon_set, style, direction,
++                                              state, size, widget, detail,
++                                              &scale);
++  if (pixbuf && scale == 1)
++    {
++      scale = 2;
++      variant = gtk_icon_set_render_icon_internal (icon_set, style, direction,
++                                                   state, size, widget, detail,
++                                                   &scale);
++      if (variant &&
++        gdk_pixbuf_get_width (variant) > gdk_pixbuf_get_width (pixbuf))
++        g_object_set_data_full (G_OBJECT (pixbuf),
++                                "gdk-pixbuf-2x-variant",
++                                variant,
++                                (GDestroyNotify) g_object_unref);
++      else if (variant)
++        g_object_unref (variant);
++    }
++
++  return pixbuf;
+ }
+
+ GdkPixbuf*
+diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c
+index 500f0ab..0e42adc 100644
+--- a/gtk/gtkicontheme.c
++++ b/gtk/gtkicontheme.c
+@@ -1403,6 +1403,8 @@ gtk_icon_theme_lookup_icon (GtkIconTheme       *icon_theme,
+                           gint                size,
+                           GtkIconLookupFlags  flags)
+ {
++  GtkIconInfo *retval, *variant;
++
+   g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL);
+   g_return_val_if_fail (icon_name != NULL, NULL);
+   g_return_val_if_fail ((flags & GTK_ICON_LOOKUP_NO_SVG) == 0 ||
+@@ -1411,8 +1413,22 @@ gtk_icon_theme_lookup_icon (GtkIconTheme       *icon_theme,
+   GTK_NOTE (ICONTHEME,
+           g_print ("gtk_icon_theme_lookup_icon %s\n", icon_name));
+
+-  return gtk_icon_theme_lookup_icon_for_scale (icon_theme, icon_name,
+-                                               size, 1, flags);
++  retval = gtk_icon_theme_lookup_icon_for_scale (icon_theme, icon_name,
++                                                 size, 1, flags);
++
++  variant = gtk_icon_theme_lookup_icon_for_scale (icon_theme, icon_name,
++                                                  size, 2, flags);
++  if (retval && variant &&
++      retval->pixbuf && variant->pixbuf &&
++      gdk_pixbuf_get_width (variant->pixbuf) > gdk_pixbuf_get_width (retval->pixbuf))
++    g_object_set_data_full (G_OBJECT (retval->pixbuf),
++                            "gdk-pixbuf-2x-variant",
++                            g_object_ref (variant->pixbuf),
++                            (GDestroyNotify) g_object_unref);
++  if (variant)
++    gtk_icon_info_free (variant);
++
++  return retval;
+ }
+
+ GtkIconInfo *
+@@ -1501,12 +1517,27 @@ gtk_icon_theme_choose_icon (GtkIconTheme       *icon_theme,
+                           gint                size,
+                           GtkIconLookupFlags  flags)
+ {
++  GtkIconInfo *retval, *variant;
++
+   g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL);
+   g_return_val_if_fail (icon_names != NULL, NULL);
+   g_return_val_if_fail ((flags & GTK_ICON_LOOKUP_NO_SVG) == 0 ||
+                       (flags & GTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL);
+
+-  return choose_icon (icon_theme, icon_names, size, 1, flags);
++  retval = choose_icon (icon_theme, icon_names, size, 1, flags);
++  variant = choose_icon (icon_theme, icon_names, size, 2, flags);
++
++  if (retval && variant &&
++      retval->pixbuf && variant->pixbuf &&
++      gdk_pixbuf_get_width (variant->pixbuf) > gdk_pixbuf_get_width (retval->pixbuf))
++    g_object_set_data_full (G_OBJECT (retval->pixbuf),
++                            "gdk-pixbuf-2x-variant",
++                            g_object_ref (variant->pixbuf),
++                            (GDestroyNotify) g_object_unref);
++  if (variant)
++    gtk_icon_info_free (variant);
++
++  return retval;
+ }
+
+ GtkIconInfo *
+@@ -1569,14 +1600,30 @@ gtk_icon_theme_load_icon (GtkIconTheme         *icon_theme,
+                         GtkIconLookupFlags    flags,
+                         GError              **error)
+ {
++  GdkPixbuf *pixbuf, *variant;
++
+   g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL);
+   g_return_val_if_fail (icon_name != NULL, NULL);
+   g_return_val_if_fail ((flags & GTK_ICON_LOOKUP_NO_SVG) == 0 ||
+                       (flags & GTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL);
+   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+-  return gtk_icon_theme_load_icon_for_scale (icon_theme, icon_name,
+-                                             size, 1, flags, error);
++  pixbuf = gtk_icon_theme_load_icon_for_scale (icon_theme, icon_name,
++                                               size, 1, flags, error);
++
++  variant = gtk_icon_theme_load_icon_for_scale (icon_theme, icon_name,
++                                               size, 2, flags, NULL);
++
++  if (pixbuf && variant &&
++      gdk_pixbuf_get_width (variant) > gdk_pixbuf_get_width (pixbuf))
++    g_object_set_data_full (G_OBJECT (pixbuf),
++                            "gdk-pixbuf-2x-variant",
++                            g_object_ref (variant),
++                            (GDestroyNotify) g_object_unref);
++  if (variant)
++    g_object_unref (variant);
++
++  return pixbuf;
+ }
+
+ GdkPixbuf *
+diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
+index f093c39..464cb59 100644
+--- a/gtk/gtkwidget.c
++++ b/gtk/gtkwidget.c
+@@ -7477,15 +7477,16 @@ gtk_widget_render_icon (GtkWidget      *widget,
+                         GtkIconSize     size,
+                         const gchar    *detail)
+ {
++  GdkPixbuf *retval, *variant;
+   GtkIconSet *icon_set;
+-  GdkPixbuf *retval;
+-
++  gdouble scale = 2;
++
+   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+   g_return_val_if_fail (stock_id != NULL, NULL);
+   g_return_val_if_fail (size > GTK_ICON_SIZE_INVALID || size == -1, NULL);
+-
++
+   gtk_widget_ensure_style (widget);
+-
++
+   icon_set = gtk_style_lookup_icon_set (widget->style, stock_id);
+
+   if (icon_set == NULL)
+@@ -7499,6 +7500,17 @@ gtk_widget_render_icon (GtkWidget      *widget,
+                                      widget,
+                                      detail);
+
++  variant = gtk_icon_set_render_icon_scaled (icon_set, widget->style,
++                                             gtk_widget_get_direction (widget),
++                                             gtk_widget_get_state (widget),
++                                             size, widget, detail, &scale);
++
++  if (variant)
++    g_object_set_data_full (G_OBJECT (retval),
++                            "gdk-pixbuf-2x-variant",
++                            variant,
++                            (GDestroyNotify) g_object_unref);
++
+   return retval;
+ }
+
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0066-cellrendererpixbuf-let-2x-variants-go-through-pixel-.patch b/bockbuild/mac-sdk/patches/gtk/0066-cellrendererpixbuf-let-2x-variants-go-through-pixel-.patch
new file mode 100644 (file)
index 0000000..1d41e20
--- /dev/null
@@ -0,0 +1,56 @@
+From 0f14c053a91185715f276dffe286698e0c3b43ba Mon Sep 17 00:00:00 2001
+From: Carlos Garnacho <carlosg@gnome.org>
+Date: Fri, 28 Jun 2013 19:35:02 +0200
+Subject: [PATCH 66/68] cellrendererpixbuf: let 2x variants go through
+ pixel-mangling code
+
+---
+ gtk/gtkcellrendererpixbuf.c |   26 ++++++++++++++++++++++++--
+ 1 file changed, 24 insertions(+), 2 deletions(-)
+
+diff --git a/gtk/gtkcellrendererpixbuf.c b/gtk/gtkcellrendererpixbuf.c
+index 7c767b6..5969792 100644
+--- a/gtk/gtkcellrendererpixbuf.c
++++ b/gtk/gtkcellrendererpixbuf.c
+@@ -614,8 +614,8 @@ gtk_cell_renderer_pixbuf_create_themed_pixbuf (GtkCellRendererPixbuf *cellpixbuf
+ }
+
+ static GdkPixbuf *
+-create_colorized_pixbuf (GdkPixbuf *src,
+-                       GdkColor  *new_color)
++create_colorized_pixbuf_single (GdkPixbuf *src,
++                              GdkColor  *new_color)
+ {
+   gint i, j;
+   gint width, height, has_alpha, src_row_stride, dst_row_stride;
+@@ -659,6 +659,28 @@ create_colorized_pixbuf (GdkPixbuf *src,
+   return dest;
+ }
+
++static GdkPixbuf *
++create_colorized_pixbuf (GdkPixbuf *src,
++                       GdkColor  *new_color)
++{
++  GdkPixbuf *colorized, *variant, *colorized_variant;
++
++  colorized = create_colorized_pixbuf_single (src, new_color);
++
++  variant = g_object_get_data (G_OBJECT (src),
++                               "gdk-pixbuf-2x-variant");
++
++  if (colorized && variant)
++    {
++      colorized_variant = create_colorized_pixbuf_single (variant, new_color);
++      g_object_set_data_full (G_OBJECT (colorized),
++                              "gdk-pixbuf-2x-variant",
++                              colorized_variant,
++                              (GDestroyNotify) g_object_unref);
++    }
++
++  return colorized;
++}
+
+ static void
+ gtk_cell_renderer_pixbuf_get_size (GtkCellRenderer *cell,
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0067-quartz-Make-event-loop-deal-with-recursive-poll-invo.patch b/bockbuild/mac-sdk/patches/gtk/0067-quartz-Make-event-loop-deal-with-recursive-poll-invo.patch
new file mode 100644 (file)
index 0000000..a7ae3f2
--- /dev/null
@@ -0,0 +1,127 @@
+From 5d0dfb203a4945eff28ad1696647b19dd0ef10e5 Mon Sep 17 00:00:00 2001
+From: Kristian Rietveld <kris@lanedo.com>
+Date: Mon, 8 Jul 2013 12:04:04 +0200
+Subject: [PATCH 67/68] quartz: Make event loop deal with recursive poll
+ invocations
+
+This patch addresses a number of problems with the recursion in
+poll_func() that happens on OS X. Firstly, autorelease pool refreshes
+are done from prepare and only if we are at the base level of *both*
+main loops and not recursing in poll. This first part incorporates
+suggestions from Daniel Sabo and John Ralls.
+
+Secondly, a mechanism is implemented to detect if poll has been
+called recursively. This is used to discard file descriptor state
+at the base level, retrieved before possibly recursing (through the
+NSApp get next event).
+---
+ gdk/quartz/gdkeventloop-quartz.c |  106 ++++++++++++++++++++++++++++----------
+ 1 file changed, 78 insertions(+), 28 deletions(-)
+
+diff --git a/gdk/quartz/gdkeventloop-quartz.c b/gdk/quartz/gdkeventloop-quartz.c
+index 224d84c..36c716a 100644
+--- a/gdk/quartz/gdkeventloop-quartz.c
++++ b/gdk/quartz/gdkeventloop-quartz.c
+@@ -168,6 +168,12 @@ static pthread_cond_t select_thread_cond = PTHREAD_COND_INITIALIZER;
+ static GPollFD *current_pollfds;
+ static guint current_n_pollfds;
+
++/* We maintain serial numbers for calls to the start function. Because we
++ * only test for equality of this number (and not smaller/greater than)
++ * no special handling is needed for wrap around.
++ */
++static guint select_thread_start_serial = 0;
++
+ /* These are the file descriptors that the select thread should pick
+  * up and start polling when it has a chance.
+  */
+@@ -399,6 +405,8 @@ select_thread_start_poll (GPollFD *ufds,
+   gint poll_fd_index = -1;
+   gint i;
+
++  select_thread_start_serial++;
++
+   for (i = 0; i < nfds; i++)
+     if (ufds[i].fd == -1)
+       {
+@@ -703,15 +721,33 @@ poll_func (GPollFD *ufds,
+   NSEvent *event;
+   NSDate *limit_date;
+   gint n_ready;
++  guint current_select_thread_serial;
+
+-  static GPollFD *last_ufds;
++  /* Maintain current poll parameters as static parameters. On recursive
++   * calls to poll, we update the values. This way, if the poll array
++   * is updated in an recursive call, we can still access the new array
++   * when the recursion is wound down.
++   *
++   * The ufds value that is pushed in is allocated in g_main_context_iterate()
++   * and is only reallocated for enlargement of this array. The array thus
++   * never shrinks.
++   */
++  static GPollFD *current_ufds = NULL;
++  static int current_nfds = 0;
+
+-  last_ufds = ufds;
++  current_ufds = ufds;
++  current_nfds = nfds;
+
+   n_ready = select_thread_start_poll (ufds, nfds, timeout_);
+   if (n_ready > 0)
+     timeout_ = 0;
+
++  /* Using this serial number, we can check below whether the select
++   * thread was started/collected in a recursive invocation of this
++   * function.
++   */
++  current_select_thread_serial = select_thread_start_serial;
++
+   if (timeout_ == -1)
+     limit_date = [NSDate distantFuture];
+   else if (timeout_ == 0)
+@@ -726,17 +762,31 @@ poll_func (GPollFD *ufds,
+                                dequeue: YES];
+   getting_events--;
+
+-  /* We check if last_ufds did not change since the time this function was
+-   * called. It is possible that a recursive main loop (and thus recursive
+-   * invocation of this poll function) is triggered while in
+-   * nextEventMatchingMask:. If during that time new fds are added,
+-   * the cached fds array might be replaced in g_main_context_iterate().
+-   * So, we should avoid accessing the old fd array (still pointed at by
+-   * ufds) here in that case, since it might have been freed. We avoid this
+-   * by not calling the collect stage.
+-   */
+-  if (last_ufds == ufds && n_ready < 0)
+-    n_ready = select_thread_collect_poll (ufds, nfds);
++  /* Note that, from this point onwards, ufds might point to freed memory! */
++
++  if (current_select_thread_serial == select_thread_start_serial)
++    {
++      if (n_ready < 0)
++        n_ready = select_thread_collect_poll (current_ufds, nfds);
++
++      /* Nothing should be done in case no poll func recursion occurred
++       * and n_ready > 0.
++       */
++    }
++  else
++    {
++      /* In this case, a recursive invocation of the poll function has
++       * collected results from the select thread. We clear the ufds
++       * values so that stale poll results are not returned. In case
++       * we did not receive results from start poll above, we also
++       * set n_ready to zero.
++       */
++      int i;
++
++      n_ready = 0;
++      for (i = 0; i < nfds; i++)
++        current_ufds[i].revents = 0;
++    }
+
+   if (event &&
+       [event type] == NSApplicationDefined &&
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0068-nsview-implement-a-few-text-view-command-accelerator.patch b/bockbuild/mac-sdk/patches/gtk/0068-nsview-implement-a-few-text-view-command-accelerator.patch
new file mode 100644 (file)
index 0000000..4f61fa1
--- /dev/null
@@ -0,0 +1,88 @@
+From da200e6664615a5ef9e89d0a295aa435f60522c9 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch@gimp.org>
+Date: Fri, 26 Jul 2013 14:48:57 +0200
+Subject: [PATCH 68/68] nsview: implement a few text view command accelerators
+ manually
+
+so cut, copy, paste and select all work.
+---
+ gtk/gtknsview.c |   50 ++++++++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 44 insertions(+), 6 deletions(-)
+
+diff --git a/gtk/gtknsview.c b/gtk/gtknsview.c
+index 3b30d3b..d5eb307 100644
+--- a/gtk/gtknsview.c
++++ b/gtk/gtknsview.c
+@@ -664,14 +664,52 @@ gtk_ns_view_key_press (GtkWidget   *widget,
+ {
+   GtkNSView *ns_view = GTK_NS_VIEW (widget);
+   NSEvent *nsevent = gdk_quartz_event_get_nsevent ((GdkEvent *) event);
+-  NSWindow *ns_window;
+
+   if (gtk_ns_view_forward_event (widget, event))
+     {
+-      ns_window = [ns_view->priv->view window];
+-      [ns_window sendEvent:nsevent];
++      NSWindow *ns_window = [ns_view->priv->view window];
++      NSResponder *responder = [ns_window firstResponder];
+
+-      return TRUE;
++      if ([responder isKindOfClass: [NSTextView class]] &&
++          (event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK |
++                           GDK_MOD1_MASK | GDK_MOD2_MASK)) == GDK_MOD2_MASK)
++        {
++          NSTextView *text_view = (NSTextView *) responder;
++          NSRange range = [text_view selectedRange];
++          gboolean has_selection = range.length > 0;
++
++          switch (event->keyval)
++            {
++            case GDK_KEY_c: /* copy */
++              if (has_selection)
++                [text_view copy: text_view];
++              return TRUE;
++
++            case GDK_KEY_x: /* cut */
++              if (has_selection)
++                [text_view cut: text_view];
++              return TRUE;
++
++            case GDK_KEY_v: /* paste */
++              [text_view paste: text_view];
++              return TRUE;
++
++            case GDK_KEY_a: /* all */
++              range.location = 0;
++              range.length = [[text_view string] length];
++              [text_view setSelectedRange: range];
++              return TRUE;
++
++            default:
++              break;
++            }
++        }
++      else
++        {
++          [ns_window sendEvent:nsevent];
++
++          return TRUE;
++        }
+     }
+
+   return GTK_WIDGET_CLASS (gtk_ns_view_parent_class)->key_press_event (widget, event);
+@@ -683,11 +721,11 @@ gtk_ns_view_key_release (GtkWidget   *widget,
+ {
+   GtkNSView *ns_view = GTK_NS_VIEW (widget);
+   NSEvent *nsevent = gdk_quartz_event_get_nsevent ((GdkEvent *) event);
+-  NSWindow *ns_window;
+
+   if (gtk_ns_view_forward_event (widget, event))
+     {
+-      ns_window = [ns_view->priv->view window];
++      NSWindow *ns_window = [ns_view->priv->view window];
++
+       [ns_window sendEvent:nsevent];
+
+       return TRUE;
+--
+1.7.10.2 (Apple Git-33)
diff --git a/bockbuild/mac-sdk/patches/gtk/0069-menu-scrolling.patch b/bockbuild/mac-sdk/patches/gtk/0069-menu-scrolling.patch
new file mode 100644 (file)
index 0000000..0d01982
--- /dev/null
@@ -0,0 +1,47 @@
+diff --git a/gtk/gtkmenu.c b/gtk/gtkmenu.c
+index fc25098..de9a4b0 100644
+--- a/gtk/gtkmenu.c
++++ b/gtk/gtkmenu.c
+@@ -55,6 +55,7 @@
+ #define MENU_SCROLL_FAST_ZONE  8
+ #define MENU_SCROLL_TIMEOUT1  50
+ #define MENU_SCROLL_TIMEOUT2  20
++#define GTK_SCROLL_STEP_SMOOTH 2
+
+ #define ATTACH_INFO_KEY "gtk-menu-child-attach-info-key"
+ #define ATTACHED_MENUS "gtk-attached-menus"
+@@ -3504,17 +3505,25 @@ gtk_menu_scroll (GtkWidget     *widget,
+                GdkEventScroll *event)
+ {
+   GtkMenu *menu = GTK_MENU (widget);
++  gdouble dx, dy;
+
+-  switch (event->direction)
++  if (gdk_event_get_scroll_deltas ((GdkEvent *) event, &dx, &dy))
+     {
+-    case GDK_SCROLL_RIGHT:
+-    case GDK_SCROLL_DOWN:
+-      gtk_menu_scroll_by (menu, MENU_SCROLL_STEP2);
+-      break;
+-    case GDK_SCROLL_LEFT:
+-    case GDK_SCROLL_UP:
+-      gtk_menu_scroll_by (menu, - MENU_SCROLL_STEP2);
+-      break;
++      gtk_menu_scroll_by (menu, GTK_SCROLL_STEP_SMOOTH * dy);
++    }
++  else
++    {
++      switch (event->direction)
++        {
++        case GDK_SCROLL_RIGHT:
++        case GDK_SCROLL_DOWN:
++          gtk_menu_scroll_by (menu, MENU_SCROLL_STEP2);
++          break;
++        case GDK_SCROLL_LEFT:
++        case GDK_SCROLL_UP:
++          gtk_menu_scroll_by (menu, - MENU_SCROLL_STEP2);
++          break;
++        }
+     }
+
+   return TRUE;
diff --git a/bockbuild/mac-sdk/patches/gtk/0070-tooltips-focus.patch b/bockbuild/mac-sdk/patches/gtk/0070-tooltips-focus.patch
new file mode 100644 (file)
index 0000000..0e661c4
--- /dev/null
@@ -0,0 +1,69 @@
+diff --git a/gtk/gtktooltip.c b/gtk/gtktooltip.c
+index 9918165..0efe4ff 100644
+--- a/gtk/gtktooltip.c
++++ b/gtk/gtktooltip.c
+@@ -98,6 +98,9 @@ static void       gtk_tooltip_display_closed       (GdkDisplay      *display,
+ static void       gtk_tooltip_set_last_window      (GtkTooltip      *tooltip,
+                                                   GdkWindow       *window);
+ static void       update_shape                     (GtkTooltip      *tooltip);
++static void       toplevel_focus_out               (GtkWidget       *widget,
++                                                    GdkEventFocus   *event,
++                                                    GtkTooltip      *tooltip);
+
+
+ G_DEFINE_TYPE (GtkTooltip, gtk_tooltip, G_TYPE_OBJECT);
+@@ -1169,6 +1172,7 @@ gtk_tooltip_show_tooltip (GdkDisplay *display)
+   GdkScreen *screen;
+
+   GdkWindow *window;
++  GtkWidget *toplevel;
+   GtkWidget *tooltip_widget;
+   GtkWidget *pointer_widget;
+   GtkTooltip *tooltip;
+@@ -1220,6 +1224,11 @@ gtk_tooltip_show_tooltip (GdkDisplay *display)
+       tooltip->current_window = GTK_WINDOW (GTK_TOOLTIP (tooltip)->window);
+     }
+
++  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tooltip_widget));
++  g_signal_connect (toplevel, "focus-out-event",
++                    G_CALLBACK (toplevel_focus_out),
++                    tooltip);
++
+   screen = gtk_widget_get_screen (tooltip_widget);
+
+   /* FIXME: should use tooltip->current_window iso tooltip->window */
+@@ -1251,6 +1260,8 @@ gtk_tooltip_show_tooltip (GdkDisplay *display)
+ static void
+ gtk_tooltip_hide_tooltip (GtkTooltip *tooltip)
+ {
++  GtkWidget *toplevel;
++
+   if (!tooltip)
+     return;
+
+@@ -1263,6 +1274,10 @@ gtk_tooltip_hide_tooltip (GtkTooltip *tooltip)
+   if (!GTK_TOOLTIP_VISIBLE (tooltip))
+     return;
+
++  toplevel = gtk_widget_get_toplevel (tooltip->tooltip_widget);
++  if (toplevel)
++    g_signal_handlers_disconnect_by_func (toplevel, G_CALLBACK (toplevel_focus_out), tooltip);
++
+   tooltip->tooltip_widget = NULL;
+
+   if (!tooltip->keyboard_mode_enabled)
+@@ -1302,6 +1317,14 @@ gtk_tooltip_hide_tooltip (GtkTooltip *tooltip)
+     }
+ }
+
++static void
++toplevel_focus_out (GtkWidget    *widget,
++                    GdkEventFocus *event,
++                    GtkTooltip    *tooltip)
++{
++  gtk_tooltip_hide_tooltip (tooltip);
++}
++
+ static gint
+ tooltip_popup_timeout (gpointer data)
+ {
diff --git a/bockbuild/mac-sdk/patches/gtk/0071-light-and-dark-overlay-scrollbars.patch b/bockbuild/mac-sdk/patches/gtk/0071-light-and-dark-overlay-scrollbars.patch
new file mode 100644 (file)
index 0000000..9c4f7de
--- /dev/null
@@ -0,0 +1,114 @@
+diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
+index a643b7d..02920ce 100644
+--- a/gtk/gtkscrolledwindow.c
++++ b/gtk/gtkscrolledwindow.c
+@@ -282,6 +282,10 @@ static gboolean gtk_scrolled_window_calculate_velocity  (GtkScrolledWindow *scro
+                                                          GdkEvent          *event);
+ static void gtk_scrolled_window_init_overlay_scrollbars (GtkScrolledWindow *window);
+
++static void gtk_scrolled_window_style_changed (GtkWidget  *widget,
++                                             GParamSpec *property,
++                                             gpointer    user_data);
++static void update_overlay_scrollbar_color (GtkWidget *widget);
+
+ static guint signals[LAST_SIGNAL] = {0};
+
+@@ -1149,7 +1153,7 @@ gtk_scrolled_window_set_property (GObject      *object,
+                                 GParamSpec   *pspec)
+ {
+   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object);
+-
++
+   switch (prop_id)
+     {
+     case PROP_HADJUSTMENT:
+@@ -1457,7 +1461,6 @@ gtk_scrolled_window_expose (GtkWidget      *widget,
+                           GdkEventExpose *event)
+ {
+   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
+-  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (widget);
+
+   if (gtk_widget_is_drawable (widget))
+     {
+@@ -3085,6 +3088,11 @@ gtk_scrolled_window_add (GtkContainer *container,
+   bin->child = child;
+   gtk_widget_set_parent (child, GTK_WIDGET (bin));
+
++  g_signal_connect (scrolled_window,
++                  "notify::style",
++                  G_CALLBACK (gtk_scrolled_window_style_changed),
++                  NULL);
++
+   /* this is a temporary message */
+   if (!gtk_widget_set_scroll_adjustments (child,
+                                           gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
+@@ -3224,6 +3232,43 @@ _gtk_scrolled_window_get_scrollbar_spacing (GtkScrolledWindow *scrolled_window)
+ }
+
+ static void
++gtk_scrolled_window_style_changed (GtkWidget  *widget,
++                                 GParamSpec *property,
++                                 gpointer    user_data)
++{
++  update_overlay_scrollbar_color (widget);
++}
++
++static void
++update_overlay_scrollbar_color (GtkWidget *widget)
++{
++  GtkScrolledWindowPrivate *priv = GTK_SCROLLED_WINDOW_GET_PRIVATE (widget);
++  GtkStyle *style;
++  GdkColor c;
++  gdouble r, g, b;
++  gfloat cc;
++  gint brightness;
++
++  style = gtk_widget_get_style (widget);
++  c = style->bg[GTK_STATE_NORMAL];
++
++  r = (gdouble)c.red;
++  g = (gdouble)c.green;
++  b = (gdouble)c.blue;
++
++  brightness = (int)(sqrt (r * r * 0.241 +
++                         g * g * 0.691 +
++                         b * b * 0.068) / 256.0);
++
++  cc = brightness < 130 ? 1.0 : 0.0;
++
++  [priv->vbar_layer setBackgroundColor: CGColorCreateGenericRGB (cc, cc, cc, 0.5)];
++  [priv->vslider_layer setBackgroundColor: CGColorCreateGenericRGB (cc, cc, cc, 1.0)];
++  [priv->hbar_layer setBackgroundColor: CGColorCreateGenericRGB (cc, cc, cc, 0.5)];
++  [priv->hslider_layer setBackgroundColor: CGColorCreateGenericRGB (cc, cc, cc, 1.0)];
++}
++
++static void
+ gtk_scrolled_window_realize (GtkWidget *widget)
+ {
+   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
+@@ -3313,21 +3358,22 @@ gtk_scrolled_window_realize (GtkWidget *widget)
+   parent_layer = [layer_view layer];
+
+   priv->vbar_layer = [[CALayer layer] retain];
+-  priv->vbar_layer.backgroundColor = CGColorCreateGenericRGB (0.0, 0.0, 0.0, 0.5);
+   priv->vbar_layer.hidden = YES;
+
+   priv->vslider_layer = [[CALayer layer] retain];
+-  priv->vslider_layer.backgroundColor = CGColorCreateGenericRGB (0.0, 0.0, 0.0, 1.0);
+   priv->vslider_layer.hidden = YES;
+
+   priv->hbar_layer = [[CALayer layer] retain];
+-  priv->hbar_layer.backgroundColor = CGColorCreateGenericRGB (0.0, 0.0, 0.0, 0.5);
+   priv->hbar_layer.hidden = YES;
+
+   priv->hslider_layer = [[CALayer layer] retain];
+-  priv->hslider_layer.backgroundColor = CGColorCreateGenericRGB (0.0, 0.0, 0.0, 1.0);
+   priv->hslider_layer.hidden = YES;
+
++  priv->vbar_layer.backgroundColor = CGColorCreateGenericRGB (0, 0, 0, 0.5);
++  priv->vslider_layer.backgroundColor = CGColorCreateGenericRGB (0, 0, 0, 1.0);
++  priv->hbar_layer.backgroundColor = CGColorCreateGenericRGB (0, 0, 0, 0.5);
++  priv->hslider_layer.backgroundColor = CGColorCreateGenericRGB (0, 0, 0, 1.0);
++
+   [parent_layer addSublayer:priv->vbar_layer];
+   [parent_layer addSublayer:priv->vslider_layer];
diff --git a/bockbuild/mac-sdk/patches/gtk/0072-let-global-keyboard-shortcuts-pass-through.patch b/bockbuild/mac-sdk/patches/gtk/0072-let-global-keyboard-shortcuts-pass-through.patch
new file mode 100644 (file)
index 0000000..7ddb135
--- /dev/null
@@ -0,0 +1,58 @@
+diff --git a/gdk/quartz/gdkkeys-quartz.c b/gdk/quartz/gdkkeys-quartz.c
+index a034bbd..e81ea4d 100644
+--- a/gdk/quartz/gdkkeys-quartz.c
++++ b/gdk/quartz/gdkkeys-quartz.c
+@@ -812,9 +812,41 @@ gdk_keymap_map_virtual_modifiers (GdkKeymap       *keymap,
+ GdkEventType
+ _gdk_quartz_keys_event_type (NSEvent *event)
+ {
+-  unsigned short keycode;
+-  unsigned int flags;
++  unsigned short keycode = [event keyCode];
++  unsigned int flags = [event modifierFlags];
++  CFArrayRef global_keys = NULL;
++  unsigned int eventmods = (flags & NSCommandKeyMask ? cmdKey : 0) |
++                           (flags & NSAlternateKeyMask ? optionKey : 0) |
++                           (flags & NSControlKeyMask ? controlKey : 0) |
++                           (flags & NSShiftKeyMask ? shiftKey : 0);
+   int i;
++
++  if (CopySymbolicHotKeys (&global_keys) == noErr && global_keys != NULL)
++    {
++      CFIndex length = CFArrayGetCount (global_keys);
++
++      for (i = 0; i < length; i++)
++      {
++        CFDictionaryRef key_info = CFArrayGetValueAtIndex (global_keys, i);
++
++        CFNumberRef code = CFDictionaryGetValue (key_info, kHISymbolicHotKeyCode);
++        CFNumberRef mods = CFDictionaryGetValue (key_info, kHISymbolicHotKeyModifiers);
++        CFBooleanRef enabled = CFDictionaryGetValue (key_info, kHISymbolicHotKeyEnabled);
++
++        gint32 mod_value;
++        gushort tmp_keycode;
++
++        CFNumberGetValue (mods, kCFNumberSInt32Type, &mod_value);
++        CFNumberGetValue (code, kCFNumberShortType, &tmp_keycode);
++
++        if (CFBooleanGetValue (enabled) && keycode == tmp_keycode && mod_value == eventmods)
++          {
++            return GDK_NOTHING;
++          }
++      }
++    }
++
++    CFRelease (global_keys);
+
+   switch ([event type])
+     {
+@@ -830,9 +862,6 @@ _gdk_quartz_keys_event_type (NSEvent *event)
+
+   /* For flags-changed events, we have to find the special key that caused the
+    * event, and see if it's in the modifier mask. */
+-  keycode = [event keyCode];
+-  flags = [event modifierFlags];
+-
+   for (i = 0; i < G_N_ELEMENTS (modifier_keys); i++)
+     {
+       if (modifier_keys[i].keycode == keycode)
diff --git a/bockbuild/mac-sdk/patches/gtk/0073-disable-combobox-scrolling.patch b/bockbuild/mac-sdk/patches/gtk/0073-disable-combobox-scrolling.patch
new file mode 100644 (file)
index 0000000..b975004
--- /dev/null
@@ -0,0 +1,53 @@
+diff --git a/gtk/gtkcombobox.c b/gtk/gtkcombobox.c
+index 39514fd..bd83a1e 100644
+--- a/gtk/gtkcombobox.c
++++ b/gtk/gtkcombobox.c
+@@ -330,8 +330,6 @@ static void     gtk_combo_box_forall               (GtkContainer     *container,
+                                                     gpointer          callback_data);
+ static gboolean gtk_combo_box_expose_event         (GtkWidget        *widget,
+                                                     GdkEventExpose   *event);
+-static gboolean gtk_combo_box_scroll_event         (GtkWidget        *widget,
+-                                                    GdkEventScroll   *event);
+ static void     gtk_combo_box_set_active_internal  (GtkComboBox      *combo_box,
+                                                   GtkTreePath      *path);
+
+@@ -551,7 +549,6 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass)
+   widget_class->size_allocate = gtk_combo_box_size_allocate;
+   widget_class->size_request = gtk_combo_box_size_request;
+   widget_class->expose_event = gtk_combo_box_expose_event;
+-  widget_class->scroll_event = gtk_combo_box_scroll_event;
+   widget_class->mnemonic_activate = gtk_combo_box_mnemonic_activate;
+   widget_class->grab_focus = gtk_combo_box_grab_focus;
+   widget_class->style_set = gtk_combo_box_style_set;
+@@ -2963,31 +2960,6 @@ tree_first (GtkComboBox  *combo,
+   return search_data.set;
+ }
+
+-static gboolean
+-gtk_combo_box_scroll_event (GtkWidget          *widget,
+-                            GdkEventScroll     *event)
+-{
+-  GtkComboBox *combo_box = GTK_COMBO_BOX (widget);
+-  gboolean found;
+-  GtkTreeIter iter;
+-  GtkTreeIter new_iter;
+-
+-  if (!gtk_combo_box_get_active_iter (combo_box, &iter))
+-    return TRUE;
+-
+-  if (event->direction == GDK_SCROLL_UP)
+-    found = tree_prev (combo_box, combo_box->priv->model,
+-                     &iter, &new_iter, FALSE);
+-  else
+-    found = tree_next (combo_box, combo_box->priv->model,
+-                     &iter, &new_iter, FALSE);
+-
+-  if (found)
+-    gtk_combo_box_set_active_iter (combo_box, &new_iter);
+-
+-  return TRUE;
+-}
+-
+ /*
+  * menu style
+  */
diff --git a/bockbuild/mac-sdk/patches/gtk/0074-fix-NULL-pointer-in-clipboard.patch b/bockbuild/mac-sdk/patches/gtk/0074-fix-NULL-pointer-in-clipboard.patch
new file mode 100644 (file)
index 0000000..b52c8a3
--- /dev/null
@@ -0,0 +1,23 @@
+commit 124e814f478936e017e58359240c540ad6678f3b
+Author: John Ralls <jralls@ceridwen.us>
+Date:   Sat Sep 28 10:55:22 2013 -0700
+
+    Bug 651224 - Potential NULL display ptr from quartz gtk_clipboard_wait_for_contents
+
+diff --git a/gtk/gtkclipboard-quartz.c b/gtk/gtkclipboard-quartz.c
+index ab7732b..a68d1cf 100644
+--- a/gtk/gtkclipboard-quartz.c
++++ b/gtk/gtkclipboard-quartz.c
+@@ -701,10 +701,12 @@ gtk_clipboard_wait_for_contents (GtkClipboard *clipboard,
+       GdkAtom *atoms;
+
+       length = [types count] * sizeof (GdkAtom);
+-
++
+       selection_data = g_slice_new0 (GtkSelectionData);
+       selection_data->selection = clipboard->selection;
+       selection_data->target = target;
++      if (!selection_data->display)
++      selection_data->display = gdk_display_get_default ();
+
+       atoms = g_malloc (length);
diff --git a/bockbuild/mac-sdk/patches/gtk/0075-filechooserwidget-location-entry-activation.patch b/bockbuild/mac-sdk/patches/gtk/0075-filechooserwidget-location-entry-activation.patch
new file mode 100644 (file)
index 0000000..5058a74
--- /dev/null
@@ -0,0 +1,121 @@
+diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c
+index f94f4d6..eeb501b 100644
+--- a/gtk/gtkfilechooserdefault.c
++++ b/gtk/gtkfilechooserdefault.c
+@@ -4409,17 +4409,26 @@ file_pane_create (GtkFileChooserDefault *impl,
+ }
+
+ static void
++on_folder_loaded (GtkFileChooserEntry *entry, GtkFileChooserDefault *chooser)
++{
++  gtk_file_chooser_default_should_respond (GTK_FILE_CHOOSER_EMBED (chooser));
++  g_signal_emit_by_name (chooser, "response-requested");
++}
++
++static void
+ location_entry_create (GtkFileChooserDefault *impl)
+ {
+   if (!impl->location_entry)
+-    impl->location_entry = _gtk_file_chooser_entry_new (TRUE);
++    {
++      impl->location_entry = _gtk_file_chooser_entry_new (TRUE);
++      g_signal_connect (impl->location_entry, "xam-load-folder", G_CALLBACK (on_folder_loaded), impl);
++    }
+
+   _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
+                                          impl->file_system);
+   _gtk_file_chooser_entry_set_local_only (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->local_only);
+   _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->action);
+   gtk_entry_set_width_chars (GTK_ENTRY (impl->location_entry), 45);
+-  gtk_entry_set_activates_default (GTK_ENTRY (impl->location_entry), TRUE);
+ }
+
+ /* Creates the widgets specific to Save mode */
+diff --git a/gtk/gtkfilechooserdialog.c b/gtk/gtkfilechooserdialog.c
+index c06fe3f..a0548a6 100644
+--- a/gtk/gtkfilechooserdialog.c
++++ b/gtk/gtkfilechooserdialog.c
+@@ -254,7 +254,7 @@ file_chooser_widget_response_requested (GtkWidget            *widget,
+
+   g_list_free (children);
+ }
+-
++
+ static GObject*
+ gtk_file_chooser_dialog_constructor (GType                  type,
+                                    guint                  n_construct_properties,
+diff --git a/gtk/gtkfilechooserentry.c b/gtk/gtkfilechooserentry.c
+index 3caa7b8..44cf665 100644
+--- a/gtk/gtkfilechooserentry.c
++++ b/gtk/gtkfilechooserentry.c
+@@ -28,6 +28,7 @@
+ #include "gtkfilechooserentry.h"
+ #include "gtklabel.h"
+ #include "gtkmain.h"
++#include "gtkmarshalers.h"
+ #include "gtkwindow.h"
+ #include "gtkintl.h"
+ #include "gtkalias.h"
+@@ -45,6 +46,11 @@ struct _GtkFileChooserEntryClass
+   GtkEntryClass parent_class;
+ };
+
++enum {
++  XAM_LOAD_FOLDER,
++  LAST_SIGNAL
++};
++
+ /* Action to take when the current folder finishes loading (for explicit or automatic completion) */
+ typedef enum {
+   LOAD_COMPLETE_NOTHING,
+@@ -168,6 +174,8 @@ static void pop_up_completion_feedback (GtkFileChooserEntry *chooser_entry,
+
+ static GtkEditableClass *parent_editable_iface;
+
++static guint signals[LAST_SIGNAL] = { 0 };
++
+ G_DEFINE_TYPE_WITH_CODE (GtkFileChooserEntry, _gtk_file_chooser_entry, GTK_TYPE_ENTRY,
+                        G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE,
+                                               gtk_file_chooser_entry_iface_init))
+@@ -188,6 +196,14 @@ _gtk_file_chooser_entry_class_init (GtkFileChooserEntryClass *class)
+   widget_class->focus_out_event = gtk_file_chooser_entry_focus_out_event;
+
+   entry_class->activate = gtk_file_chooser_entry_activate;
++
++  signals[XAM_LOAD_FOLDER] = g_signal_new (I_("xam-load-folder"),
++                                           G_OBJECT_CLASS_TYPE (gobject_class),
++                                           G_SIGNAL_RUN_LAST,
++                                           NULL,
++                                           NULL, NULL,
++                                           _gtk_marshal_VOID__VOID,
++                                           G_TYPE_NONE, 0);
+ }
+
+ static void
+@@ -1301,6 +1317,7 @@ gtk_file_chooser_entry_activate (GtkEntry *entry)
+   GtkFileChooserEntry *chooser_entry = GTK_FILE_CHOOSER_ENTRY (entry);
+
+   commit_completion_and_refresh (chooser_entry);
++  g_signal_emit (chooser_entry, signals[XAM_LOAD_FOLDER], 0);
+   GTK_ENTRY_CLASS (_gtk_file_chooser_entry_parent_class)->activate (entry);
+ }
+
+diff --git a/gtk/gtkfilechooserwidget.c b/gtk/gtkfilechooserwidget.c
+index d69d854..3ad8a19 100644
+--- a/gtk/gtkfilechooserwidget.c
++++ b/gtk/gtkfilechooserwidget.c
+@@ -24,6 +24,7 @@
+ #include "gtkfilechooserwidget.h"
+ #include "gtkfilechooserdefault.h"
+ #include "gtkfilechooserutils.h"
++#include "gtkmarshalers.h"
+ #include "gtktypebuiltins.h"
+ #include "gtkfilechooserembed.h"
+ #include "gtkintl.h"
+@@ -101,7 +102,6 @@ gtk_file_chooser_widget_constructor (GType                  type,
+   gtk_widget_push_composite_child ();
+
+   priv->impl = _gtk_file_chooser_default_new ();
+-
+   gtk_box_pack_start (GTK_BOX (object), priv->impl, TRUE, TRUE, 0);
+   gtk_widget_show (priv->impl);
diff --git a/bockbuild/mac-sdk/patches/gtk/0076-iconfactory-treat-gt-1-0-icons-as-2-0.patch b/bockbuild/mac-sdk/patches/gtk/0076-iconfactory-treat-gt-1-0-icons-as-2-0.patch
new file mode 100644 (file)
index 0000000..8c84743
--- /dev/null
@@ -0,0 +1,38 @@
+commit 072cd971ff3c9f48bd43b1e6f1e771dcb46f822a
+Author: Cody Russell <cody@jhu.edu>
+Date:   Thu Apr 24 16:37:14 2014 -0500
+
+    When finding matching icon sources or cached icons, any scale greater than
+    1.0 should be treated as 2.0. This is important on Windows where scales can
+    be things like 1.25 or 1.5.
+
+diff --git a/gtk/gtkiconfactory.c b/gtk/gtkiconfactory.c
+index 291c05e..5e356b7 100644
+--- a/gtk/gtkiconfactory.c
++++ b/gtk/gtkiconfactory.c
+@@ -1323,11 +1323,12 @@ find_best_matching_source (GtkIconSet       *icon_set,
+                          GtkTextDirection  direction,
+                          GtkStateType      state,
+                          GtkIconSize       size,
+-                         gdouble           scale,
++                         gdouble           _scale,
+                          GSList           *failed)
+ {
+   GtkIconSource *source;
+   GSList *tmp_list;
++  gdouble scale = (_scale > 1.0 ? 2.0 : 1.0);
+
+   /* We need to find the best icon source.  Direction matters more
+    * than state, state matters more than size. icon_set->sources
+@@ -2586,10 +2587,11 @@ find_in_cache (GtkIconSet      *icon_set,
+                GtkTextDirection direction,
+                GtkStateType     state,
+                GtkIconSize      size,
+-               gdouble          scale)
++               gdouble          _scale)
+ {
+   GSList *tmp_list;
+   GSList *prev;
++  gdouble scale = (_scale > 1.0 ? 2.0 : 1.0);
+
+   ensure_cache_up_to_date (icon_set);
diff --git a/bockbuild/mac-sdk/patches/gtk/bgo702841-fix-kana-eisu-keys.patch b/bockbuild/mac-sdk/patches/gtk/bgo702841-fix-kana-eisu-keys.patch
new file mode 100644 (file)
index 0000000..178a48b
--- /dev/null
@@ -0,0 +1,64 @@
+From b93535cc5d60149edc3a45d5b7f31f62a80234bf Mon Sep 17 00:00:00 2001
+From: Takuro Ashie <ashie@clear-code.com>
+Date: Fri, 21 Jun 2013 21:29:14 +0900
+Subject: [PATCH] Quartz: translate JIS Hiragana & Eisu keys.
+
+Since UCKeyTranslate() converts these keys to Space key unexpectedly,
+applications can't distinguish these keys by keysyms.
+To solve it, this fix translates these keys by same way with function
+keys & keypad keys.
+---
+ gdk/quartz/gdkkeys-quartz.c | 31 +++++++++++++++++++++++++++++++
+ 1 file changed, 31 insertions(+)
+
+diff --git a/gdk/quartz/gdkkeys-quartz.c b/gdk/quartz/gdkkeys-quartz.c
+index a4df2cf..fb11c33 100644
+--- a/gdk/quartz/gdkkeys-quartz.c
++++ b/gdk/quartz/gdkkeys-quartz.c
+@@ -191,6 +191,29 @@ const static struct {
+   { 92, GDK_KEY_9, GDK_KEY_KP_9 }
+ };
+
++/* Keys only in JIS layout.
++ * The rationale of these key codes is <HIToolbox/Events.h> in Carbon.
++ */
++const static struct {
++  guint keycode;
++  guint keyval;
++} jis_keys[] = {
++#if 0
++  /* Although These keys are also defined in <HIToolbox/Events.h>, they can be
++   * translated by UCKeyTranslate correctly.
++   */
++  { 0x5D, GDK_KEY_yen },
++  { 0x5E, GDK_KEY_underscore },
++  { 0x5F, GDK_KEY_comma },
++#endif
++  /* These keys are unexpectedly translated to Space key by UCKeyTranslate,
++   * and there is no suitable ucs value for them to add to special_ucs_table.
++   * So we should translate them particularly.
++   */
++  { 0x66 /* 102 */, GDK_KEY_Eisu_toggle },
++  { 0x68 /* 104 */, GDK_KEY_Hiragana }
++};
++
+ /* These values aren't covered by gdk_unicode_to_keyval */
+ const static struct {
+   gunichar ucs_value;
+@@ -498,6 +521,14 @@ maybe_update_keymap (void)
+         if (p[0] == known_numeric_keys[i].normal_keyval)
+             p[0] = known_numeric_keys[i].keypad_keyval;
+       }
++
++      for (i = 0; i < G_N_ELEMENTS (jis_keys); i++)
++      {
++        p = keyval_array + jis_keys[i].keycode * KEYVALS_PER_KEYCODE;
++
++          p[0] = jis_keys[i].keyval;
++          p[1] = p[2] = p[3] = 0;
++      }
+
+       if (current_layout)
+       g_signal_emit_by_name (default_keymap, "keys_changed");
+--
+1.7.12.4 (Apple Git-37)
diff --git a/bockbuild/mac-sdk/patches/gtk/bxc-41657.patch b/bockbuild/mac-sdk/patches/gtk/bxc-41657.patch
new file mode 100644 (file)
index 0000000..ba9fbea
--- /dev/null
@@ -0,0 +1,27 @@
+From ccd93c714859737d9b40b547e433a690ad6a9e55 Mon Sep 17 00:00:00 2001
+From: iain holmes <iain@xamarin.com>
+Date: Thu, 30 Jun 2016 12:34:56 +0100
+Subject: [PATCH] [Gdk] Don't crash when turning screen off
+
+Check the length of characters in the NSFlagsChanged event before accessing
+the individual characters because cmd+alt+power key doesn't have any characters
+so an ObjC will throw an exception.
+
+Fixes BXC #41657
+---
+ gdk/quartz/gdkevents-quartz.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
+index 8cb05c0..0fa63be 100644
+--- a/gdk/quartz/gdkevents-quartz.c
++++ b/gdk/quartz/gdkevents-quartz.c
+@@ -1847,7 +1847,7 @@ gdk_event_translate (GdkEvent *event,
+         NSView *tmp_view = [nswindow firstResponder];
+         gboolean gtk_child = FALSE;
+
+-        if (event_type == NSKeyDown && ([nsevent modifierFlags] & NSCommandKeyMask) != 0 && [[nsevent characters] characterAtIndex:0] == 'z')
++        if (event_type == NSKeyDown && ([nsevent modifierFlags] & NSCommandKeyMask) != 0 && [[nsevent characters] length] > 0 && [[nsevent characters] characterAtIndex:0] == 'z')
+           {
+             if ([tmp_view respondsToSelector:@selector(undoManager)])
+               {
diff --git a/bockbuild/mac-sdk/patches/gtk/bxc2158_workaround_crash_triggering_context_menu.patch b/bockbuild/mac-sdk/patches/gtk/bxc2158_workaround_crash_triggering_context_menu.patch
new file mode 100644 (file)
index 0000000..f82905f
--- /dev/null
@@ -0,0 +1,34 @@
+diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
+index a8800f7..a7d3f75 100644
+--- a/gdk/quartz/gdkevents-quartz.c
++++ b/gdk/quartz/gdkevents-quartz.c
+@@ -682,11 +682,25 @@ find_window_for_ns_event (NSEvent *nsevent,
+             else
+               {
+                 /* Finally check the grab window. */
+-              GdkWindow *grab_toplevel;
++              GdkWindow *grab_toplevel = NULL;
+
+-              grab_toplevel = gdk_window_get_effective_toplevel (grab->window);
+-                get_window_point_from_screen_point (grab_toplevel,
+-                                                    screen_point, x, y);
++                if (grab->window == NULL)
++                  {
++                    g_warning ("grab->window == NULL");
++                  }
++                else
++                  {
++                    grab_toplevel = gdk_window_get_effective_toplevel (grab->window);
++                    if (grab_toplevel == NULL)
++                      {
++                        g_warning ("grab_toplevel == NULL");
++                      }
++                    else
++                      {
++                        get_window_point_from_screen_point (grab_toplevel,
++                                                            screen_point, x, y);
++                      }
++                  }
+
+               return grab_toplevel;
+             }
diff --git a/bockbuild/mac-sdk/patches/gtk/bxc3457_more_standard_keyboard_shortcuts.patch b/bockbuild/mac-sdk/patches/gtk/bxc3457_more_standard_keyboard_shortcuts.patch
new file mode 100644 (file)
index 0000000..68256cc
--- /dev/null
@@ -0,0 +1,22 @@
+diff --git a/gtk/gtkrc.key.mac b/gtk/gtkrc.key.mac
+index 980f3e4..91033a6 100644
+--- a/gtk/gtkrc.key.mac
++++ b/gtk/gtkrc.key.mac
+@@ -10,6 +10,8 @@ binding "gtk-mac-alt-arrows"
+   bind "<shift><alt>KP_Right" { "move-cursor" (words, 1, 1) }
+   bind "<shift><alt>Left"     { "move-cursor" (words, -1, 1) }
+   bind "<shift><alt>KP_Left"  { "move-cursor" (words, -1, 1) }
++  bind "<ctrl>p"              { "move-cursor" (display-lines, -1, 0) }
++  bind "<ctrl>n"              { "move-cursor" (display-lines, 1, 0) }
+ }
+
+ class "GtkTextView" binding "gtk-mac-alt-arrows"
+@@ -19,6 +21,8 @@ class "GtkEntry" binding "gtk-mac-alt-arrows"
+
+ binding "gtk-mac-alt-delete"
+ {
++  bind "<ctrl>d" { "delete-from-cursor" (chars, 1) }
++  bind "<ctrl>k" { "delete-from-cursor" (paragraph-ends, 1) }
+   bind "<alt>Delete" { "delete-from-cursor" (word-ends, 1) }
+   bind "<alt>KP_Delete" { "delete-from-cursor" (word-ends, 1) }
+   bind "<alt>BackSpace" { "delete-from-cursor" (word-ends, -1) }
diff --git a/bockbuild/mac-sdk/patches/gtk/bxc_10256_window_tools_get_confused.diff b/bockbuild/mac-sdk/patches/gtk/bxc_10256_window_tools_get_confused.diff
new file mode 100644 (file)
index 0000000..5346958
--- /dev/null
@@ -0,0 +1,50 @@
+From c7143a37ec4d802710442380bc4cfd0d521350bd Mon Sep 17 00:00:00 2001
+From: Kristian Rietveld <kris@lanedo.com>
+Date: Sat, 23 Feb 2013 13:51:18 +0100
+Subject: [PATCH] Call NSApp finishLaunching before polling the first event
+ from Cocoa
+
+---
+ gdk/quartz/gdkeventloop-quartz.c |   20 ++++++++++++++++++++
+ 1 files changed, 20 insertions(+), 0 deletions(-)
+
+diff --git a/gdk/quartz/gdkeventloop-quartz.c b/gdk/quartz/gdkeventloop-quartz.c
+index 224d84c..80ef87f 100644
+--- a/gdk/quartz/gdkeventloop-quartz.c
++++ b/gdk/quartz/gdkeventloop-quartz.c
+@@ -695,6 +695,23 @@ static GSourceFuncs event_funcs = {
+  *********             Our Poll Function            *********
+  ************************************************************/
+
++static inline void
++ensure_finish_launching_called (void)
++{
++  static volatile gsize finish_launched_called = 0;
++
++  if (g_once_init_enter (&finish_launched_called))
++    {
++      /* This call finished application start up and enables for example
++       * accessibility support. This function is called from poll_func
++       * and an autorelease pool is set up at that point.
++       */
++      [NSApp finishLaunching];
++
++      g_once_init_leave (&finish_launched_called, TRUE);
++    }
++}
++
+ static gint
+ poll_func (GPollFD *ufds,
+          guint    nfds,
+@@ -706,6 +723,9 @@ poll_func (GPollFD *ufds,
+   static GPollFD *current_ufds = NULL;
+   static int current_nfds = 0;
+
++  /* This is performed *once* before we poll Cocoa for the first event. */
++  ensure_finish_launching_called ();
++
+   current_ufds = ufds;
+   current_nfds = nfds;
+
+--
+1.7.4.4
diff --git a/bockbuild/mac-sdk/patches/gtk/combobox-crossing-events.patch b/bockbuild/mac-sdk/patches/gtk/combobox-crossing-events.patch
new file mode 100644 (file)
index 0000000..fad3581
--- /dev/null
@@ -0,0 +1,44 @@
+diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
+index 9e57edd..e8c28ad 100644
+--- a/gdk/quartz/gdkevents-quartz.c
++++ b/gdk/quartz/gdkevents-quartz.c
+@@ -46,6 +46,8 @@
+ /* This is the window corresponding to the key window */
+ static GdkWindow   *current_keyboard_window;
+
++static GdkWindow   *crossing_current_window = NULL;
++
+ /* This is the event mask from the last event */
+ static GdkEventMask current_event_mask;
+
+@@ -1129,12 +1131,18 @@ synthesize_crossing_event (GdkWindow *window,
+       if (!(private->event_mask & GDK_ENTER_NOTIFY_MASK))
+         return FALSE;
+
++      if (crossing_current_window == window)
++        return FALSE;
++
+       fill_crossing_event (window, event, nsevent,
+                            x, y,
+                            x_root, y_root,
+                            GDK_ENTER_NOTIFY,
+                            GDK_CROSSING_NORMAL,
+                            GDK_NOTIFY_NONLINEAR);
++
++      crossing_current_window = window;
++
+       return TRUE;
+
+     case NSMouseExited:
+@@ -1142,6 +1150,11 @@ synthesize_crossing_event (GdkWindow *window,
+       if (!(private->event_mask & GDK_LEAVE_NOTIFY_MASK))
+         return FALSE;
+
++      if (crossing_current_window != NULL && crossing_current_window != window)
++        return FALSE;
++
++      crossing_current_window = NULL;
++
+       fill_crossing_event (window, event, nsevent,
+                            x, y,
+                            x_root, y_root,
diff --git a/bockbuild/mac-sdk/patches/gtk/create-accessibility-object.patch b/bockbuild/mac-sdk/patches/gtk/create-accessibility-object.patch
new file mode 100644 (file)
index 0000000..987c5ed
--- /dev/null
@@ -0,0 +1,42 @@
+commit 6ed9fd7a27d85b5abecc0f727282586bc616b79d
+Author: iain holmes <iain@xamarin.com>
+Date:   Mon Jul 25 17:00:40 2016 +0100
+
+    [GtkWidget] Always create an accessibilityy object for every widget
+
+    Create an accessibility once the widget has been fully constructed.
+
+diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
+index facc0db..55d1fbc 100644
+--- a/gtk/gtkwidget.c
++++ b/gtk/gtkwidget.c
+@@ -255,6 +255,7 @@ static void        gtk_widget_get_property          (GObject           *object,
+ static void   gtk_widget_dispose               (GObject           *object);
+ static void   gtk_widget_real_destroy          (GtkObject         *object);
+ static void   gtk_widget_finalize              (GObject           *object);
++static void gtk_widget_constructed (GObject     *object);
+ static void   gtk_widget_real_show             (GtkWidget         *widget);
+ static void   gtk_widget_real_hide             (GtkWidget         *widget);
+ static void   gtk_widget_real_map              (GtkWidget         *widget);
+@@ -481,6 +482,7 @@ gtk_widget_class_init (GtkWidgetClass *klass)
+
+   gobject_class->dispose = gtk_widget_dispose;
+   gobject_class->finalize = gtk_widget_finalize;
++  gobject_class->constructed = gtk_widget_constructed;
+   gobject_class->set_property = gtk_widget_set_property;
+   gobject_class->get_property = gtk_widget_get_property;
+
+@@ -2961,6 +2963,13 @@ gtk_widget_init (GtkWidget *widget)
+   g_object_ref (widget->style);
+ }
+
++static void
++gtk_widget_constructed (GObject *object)
++{
++  // Always create an accessible for widgets
++  gtk_widget_get_accessible (GTK_WIDGET (object));
++  G_OBJECT_CLASS (gtk_widget_parent_class)->constructed (object);
++}
+
+ static void
+ gtk_widget_dispatch_child_properties_changed (GtkWidget   *widget,
diff --git a/bockbuild/mac-sdk/patches/gtk/disable-eye-dropper.patch b/bockbuild/mac-sdk/patches/gtk/disable-eye-dropper.patch
new file mode 100644 (file)
index 0000000..a5ce90a
--- /dev/null
@@ -0,0 +1,20 @@
+diff --git a/gtk/gtkcolorsel.c b/gtk/gtkcolorsel.c
+index 78a483d..06b9d0e 100644
+--- a/gtk/gtkcolorsel.c
++++ b/gtk/gtkcolorsel.c
+@@ -367,6 +367,7 @@ gtk_color_selection_init (GtkColorSelection *colorsel)
+   gtk_container_add (GTK_CONTAINER (frame), priv->sample_area);
+   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
+
++  /*
+   button = gtk_button_new ();
+
+   gtk_widget_set_events (button, GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
+@@ -380,6 +381,7 @@ gtk_color_selection_init (GtkColorSelection *colorsel)
+
+   gtk_widget_set_tooltip_text (button,
+                         _("Click the eyedropper, then click a color anywhere on your screen to select that color."));
++                        */
+
+   top_right_vbox = gtk_vbox_new (FALSE, 6);
+   gtk_box_pack_start (GTK_BOX (top_hbox), top_right_vbox, FALSE, FALSE, 0);
diff --git a/bockbuild/mac-sdk/patches/gtk/dont-call-CopySymbolicHotKeys-so-much.patch b/bockbuild/mac-sdk/patches/gtk/dont-call-CopySymbolicHotKeys-so-much.patch
new file mode 100644 (file)
index 0000000..2bca866
--- /dev/null
@@ -0,0 +1,117 @@
+diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
+index f4ae401..d601ee3 100644
+--- a/gdk/quartz/gdkevents-quartz.c
++++ b/gdk/quartz/gdkevents-quartz.c
+@@ -680,6 +680,8 @@ _gdk_quartz_events_update_focus_window (GdkWindow *window,
+        * everything in the window is set to correct state.
+        */
+       generate_motion_event (window);
++
++      _gdk_quartz_update_symbolic_hotkeys ();
+     }
+ }
+
+diff --git a/gdk/quartz/gdkinput.c b/gdk/quartz/gdkinput.c
+index 6f5f8ea..8d5698f 100644
+--- a/gdk/quartz/gdkinput.c
++++ b/gdk/quartz/gdkinput.c
+@@ -568,6 +568,8 @@ _gdk_input_exit (void)
+       g_free (tmp_list->data);
+     }
+   g_list_free (_gdk_input_windows);
++
++  _gdk_quartz_release_symbolic_hotkeys ();
+ }
+
+ gboolean
+diff --git a/gdk/quartz/gdkkeys-quartz.c b/gdk/quartz/gdkkeys-quartz.c
+index e81ea4d..746881b 100644
+--- a/gdk/quartz/gdkkeys-quartz.c
++++ b/gdk/quartz/gdkkeys-quartz.c
+@@ -55,6 +55,7 @@
+ #include <AppKit/NSEvent.h>
+ #include "gdk.h"
+ #include "gdkkeysyms.h"
++#include "gdkprivate-quartz.h"
+
+ #define NUM_KEYCODES 128
+ #define KEYVALS_PER_KEYCODE 4
+@@ -65,6 +66,7 @@ static GdkKeymap *default_keymap = NULL;
+  * TThere is 1 keyval per modifier (Nothing, Shift, Alt, Shift+Alt);
+  */
+ static guint *keyval_array = NULL;
++static CFArrayRef global_hotkeys = NULL;
+
+ static inline UniChar
+ macroman2ucs (unsigned char c)
+@@ -806,6 +808,24 @@ gdk_keymap_map_virtual_modifiers (GdkKeymap       *keymap,
+   return TRUE;
+ }
+
++void
++_gdk_quartz_update_symbolic_hotkeys ()
++{
++  _gdk_quartz_release_symbolic_hotkeys ();
++
++  CopySymbolicHotKeys (&global_hotkeys);
++}
++
++void
++_gdk_quartz_release_symbolic_hotkeys ()
++{
++  if (global_hotkeys != NULL)
++    {
++      CFRelease (global_hotkeys);
++      global_hotkeys = NULL;
++    }
++}
++
+ /* What sort of key event is this? Returns one of
+  * GDK_KEY_PRESS, GDK_KEY_RELEASE, GDK_NOTHING (should be ignored)
+  */
+@@ -814,20 +834,19 @@ _gdk_quartz_keys_event_type (NSEvent *event)
+ {
+   unsigned short keycode = [event keyCode];
+   unsigned int flags = [event modifierFlags];
+-  CFArrayRef global_keys = NULL;
+   unsigned int eventmods = (flags & NSCommandKeyMask ? cmdKey : 0) |
+                            (flags & NSAlternateKeyMask ? optionKey : 0) |
+                            (flags & NSControlKeyMask ? controlKey : 0) |
+                            (flags & NSShiftKeyMask ? shiftKey : 0);
+   int i;
+
+-  if (CopySymbolicHotKeys (&global_keys) == noErr && global_keys != NULL)
++  if (global_hotkeys != NULL)
+     {
+-      CFIndex length = CFArrayGetCount (global_keys);
++      CFIndex length = CFArrayGetCount (global_hotkeys);
+
+       for (i = 0; i < length; i++)
+       {
+-        CFDictionaryRef key_info = CFArrayGetValueAtIndex (global_keys, i);
++        CFDictionaryRef key_info = CFArrayGetValueAtIndex (global_hotkeys, i);
+
+         CFNumberRef code = CFDictionaryGetValue (key_info, kHISymbolicHotKeyCode);
+         CFNumberRef mods = CFDictionaryGetValue (key_info, kHISymbolicHotKeyModifiers);
+@@ -846,8 +865,6 @@ _gdk_quartz_keys_event_type (NSEvent *event)
+       }
+     }
+
+-    CFRelease (global_keys);
+-
+   switch ([event type])
+     {
+     case NSKeyDown:
+diff --git a/gdk/quartz/gdkprivate-quartz.h b/gdk/quartz/gdkprivate-quartz.h
+index f8b382d..0b0f66b 100644
+--- a/gdk/quartz/gdkprivate-quartz.h
++++ b/gdk/quartz/gdkprivate-quartz.h
+@@ -200,6 +200,8 @@ GdkImage *_gdk_quartz_image_copy_to_image (GdkDrawable *drawable,
+                                           gint         height);
+
+ /* Keys */
++void         _gdk_quartz_update_symbolic_hotkeys  ();
++void         _gdk_quartz_release_symbolic_hotkeys ();
+ GdkEventType _gdk_quartz_keys_event_type  (NSEvent   *event);
+ gboolean     _gdk_quartz_keys_is_modifier (guint      keycode);
+ void         _gdk_quartz_synthesize_null_key_event (GdkWindow *window);
diff --git a/bockbuild/mac-sdk/patches/gtk/embedded-nstextview-has-focus.patch b/bockbuild/mac-sdk/patches/gtk/embedded-nstextview-has-focus.patch
new file mode 100644 (file)
index 0000000..a24649d
--- /dev/null
@@ -0,0 +1,74 @@
+diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h
+index e9428d0..8bd02d7 100644
+--- a/gdk/gdkwindow.h
++++ b/gdk/gdkwindow.h
+@@ -724,6 +724,8 @@ void       gdk_window_remove_redirection     (GdkWindow     *window);
+
+ /* NSView embedding */
+ gboolean   gdk_window_supports_nsview_embedding ();
++gboolean   gdk_window_has_embedded_nsview_focus (GdkWindow *window);
++void       gdk_window_set_has_embedded_nsview_focus (GdkWindow *window, gboolean value);
+
+ #ifndef GDK_DISABLE_DEPRECATED
+ #ifndef GDK_MULTIHEAD_SAFE
+diff --git a/gdk/quartz/GdkQuartzWindow.c b/gdk/quartz/GdkQuartzWindow.c
+index b6b794e..124427e 100644
+--- a/gdk/quartz/GdkQuartzWindow.c
++++ b/gdk/quartz/GdkQuartzWindow.c
+@@ -247,6 +247,15 @@
+         }
+     }
+
++  if (responder != NULL && [responder isKindOfClass: [NSTextView class]])
++    {
++      gdk_window_set_has_embedded_nsview_focus (window, TRUE);
++    }
++  else
++    {
++      gdk_window_set_has_embedded_nsview_focus (window, FALSE);
++    }
++
+   return [super makeFirstResponder:responder];
+ }
+
+diff --git a/gdk/quartz/gdkwindow-quartz.c b/gdk/quartz/gdkwindow-quartz.c
+index 050139a..cd5cc26 100644
+--- a/gdk/quartz/gdkwindow-quartz.c
++++ b/gdk/quartz/gdkwindow-quartz.c
+@@ -895,6 +895,24 @@ gdk_window_supports_nsview_embedding ()
+   return TRUE;
+ }
+
++gboolean
++gdk_window_has_embedded_nsview_focus (GdkWindow *window)
++{
++  GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
++  GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
++
++  return impl->has_nsview_focus;
++}
++
++void
++gdk_window_set_has_embedded_nsview_focus (GdkWindow *window, gboolean value)
++{
++  GdkWindowObject *private = GDK_WINDOW_OBJECT (window);
++  GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
++
++  impl->has_nsview_focus = value;
++}
++
+ void
+ _gdk_window_impl_new (GdkWindow     *window,
+                     GdkWindow     *real_parent,
+diff --git a/gdk/quartz/gdkwindow-quartz.h b/gdk/quartz/gdkwindow-quartz.h
+index f35238b..b619914 100644
+--- a/gdk/quartz/gdkwindow-quartz.h
++++ b/gdk/quartz/gdkwindow-quartz.h
+@@ -61,6 +61,7 @@ struct _GdkWindowImplQuartz
+   GList *sorted_children;
+
+   GdkRegion *needs_display_region;
++  gboolean has_nsview_focus;
+ };
+
+ struct _GdkWindowImplQuartzClass
diff --git a/bockbuild/mac-sdk/patches/gtk/emit-container-add.patch b/bockbuild/mac-sdk/patches/gtk/emit-container-add.patch
new file mode 100644 (file)
index 0000000..153cf53
--- /dev/null
@@ -0,0 +1,39 @@
+From 74a81cbb03a4b6a27b0e9c58099d54bc1537865d Mon Sep 17 00:00:00 2001
+From: iain holmes <iain@xamarin.com>
+Date: Fri, 22 Jul 2016 14:39:28 +0100
+Subject: [PATCH] [GtkBox] Emit GtkContainer's add signal
+
+Even though GtkBox is a subclass of GtkContainer, it won't emit
+GtkContainer::add when a widget is added via gtk_box_pack functions.
+
+We emit that signal, and guard against cycles caused by the signal triggering
+another gtk_box_add call.
+---
+ gtk/gtkbox.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/gtk/gtkbox.c b/gtk/gtkbox.c
+index 1ebcbcf..26c66cf 100644
+--- a/gtk/gtkbox.c
++++ b/gtk/gtkbox.c
+@@ -760,6 +760,8 @@ gtk_box_pack (GtkBox      *box,
+   gtk_widget_child_notify (child, "pack-type");
+   gtk_widget_child_notify (child, "position");
+   gtk_widget_thaw_child_notify (child);
++
++  g_signal_emit_by_name (G_OBJECT (box), "add", child);
+ }
+
+ /**
+@@ -1188,6 +1190,11 @@ gtk_box_add (GtkContainer *container,
+ {
+   GtkBoxPrivate *private = GTK_BOX_GET_PRIVATE (container);
+
++  if (widget->parent == container) {
++    // Break the add signal cycle
++    return;
++  }
++
+   gtk_box_pack_start (GTK_BOX (container), widget,
+                       private->default_expand,
+                       private->default_expand,
diff --git a/bockbuild/mac-sdk/patches/gtk/enable-swizzle-property.patch b/bockbuild/mac-sdk/patches/gtk/enable-swizzle-property.patch
new file mode 100644 (file)
index 0000000..137c82a
--- /dev/null
@@ -0,0 +1,101 @@
+diff --git a/gtk/gtknsview.c b/gtk/gtknsview.c
+index ad003d9..483f105 100644
+--- a/gtk/gtknsview.c
++++ b/gtk/gtknsview.c
+@@ -41,7 +41,8 @@
+ enum
+ {
+   PROP_0,
+-  PROP_VIEW
++  PROP_VIEW,
++  PROP_ENABLE_SWIZZLE
+ };
+
+
+@@ -49,6 +50,7 @@ struct _GtkNSViewPrivate
+ {
+   NSView *view;
+   guint   map_timeout;
++  gboolean enable_swizzle;
+ };
+
+ #define GTK_NS_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
+@@ -130,6 +132,14 @@ gtk_ns_view_class_init (GtkNSViewClass *klass)
+                                                          P_("The NSView"),
+                                                          GTK_PARAM_READWRITE |
+                                                          G_PARAM_CONSTRUCT_ONLY));
++
++  g_object_class_install_property (object_class,
++                                 PROP_ENABLE_SWIZZLE,
++                                 g_param_spec_boolean ("enable-swizzle",
++                                                       P_("Enable swizzle"),
++                                                       P_("Enable swizzle"),
++                                                       FALSE,
++                                                       GTK_PARAM_READWRITE));
+ }
+
+ static void
+@@ -149,12 +159,18 @@ static void   gtk_ns_view_swizzle_draw_rect_recursive (NSView      *view,
+ - (void) myDidAddSubview: (NSView *) aView
+ {
+   void *associated_object;
++  GtkNSView *gtknsview;
+
+   associated_object = objc_getAssociatedObject (self, "gtknsview");
+
+   if (associated_object)
+     {
+-      gtk_ns_view_swizzle_draw_rect_recursive (aView, "gtknsview", associated_object);
++      gtknsview = (GtkNSView *)associated_object;
++
++      if (gtknsview->priv->enable_swizzle)
++      {
++        gtk_ns_view_swizzle_draw_rect_recursive (aView, "gtknsview", associated_object);
++      }
+     }
+   else
+     {
+@@ -443,8 +459,11 @@ gtk_ns_view_constructed (GObject *object)
+ #endif
+
+   gtk_ns_view_replace_draw_insertion_point ();
+-  gtk_ns_view_swizzle_draw_rect_recursive (ns_view->priv->view,
+-                                           "gtknsview", ns_view);
++  if (ns_view->priv->enable_swizzle)
++    {
++      gtk_ns_view_swizzle_draw_rect_recursive (ns_view->priv->view,
++                                             "gtknsview", ns_view);
++    }
+ }
+
+ static void
+@@ -477,6 +496,10 @@ gtk_ns_view_set_property (GObject      *object,
+         [ns_view->priv->view retain];
+       break;
+
++    case PROP_ENABLE_SWIZZLE:
++      ns_view->priv->enable_swizzle = g_value_get_boolean (value);
++      break;
++
+     default:
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       break;
+@@ -497,6 +520,9 @@ gtk_ns_view_get_property (GObject      *object,
+       g_value_set_pointer (value, ns_view->priv->view);
+       break;
+
++    case PROP_ENABLE_SWIZZLE:
++      g_value_set_boolean (value, ns_view->priv->enable_swizzle);
++
+     default:
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       break;
+@@ -617,7 +643,7 @@ really_map (GtkWidget *widget) {
+       NSText *text = [window fieldEditor: YES
+                                forObject: nil];
+
+-      if (text)
++      if (text && ns_view->priv->enable_swizzle)
+         {
+           gtk_ns_view_swizzle_draw_rect_recursive (text, "gtkwindow", toplevel);
+         }
diff --git a/bockbuild/mac-sdk/patches/gtk/fix-imquartz-crasher.patch b/bockbuild/mac-sdk/patches/gtk/fix-imquartz-crasher.patch
new file mode 100644 (file)
index 0000000..6e8c27d
--- /dev/null
@@ -0,0 +1,49 @@
+From 4ba1fbfdb15fdf31643b7c88ca457b0eb71a0c00 Mon Sep 17 00:00:00 2001
+From: David Lechner <david@lechnology.com>
+Date: Fri, 2 Oct 2015 13:45:00 +0000
+Subject: [PATCH] Bug 753992 - im-quartz discard_preedit segmentation fault
+
+Replace checking if the NSView is really a GdkWindow, which will crash
+in the likely event it's not a GObject, with ensuring that the parent
+GdkWindow is really a GdkWindowQuartz.
+---
+ modules/input/imquartz.c | 12 +-----------
+ 1 file changed, 1 insertion(+), 11 deletions(-)
+
+diff --git a/modules/input/imquartz.c b/modules/input/imquartz.c
+index 67c7d6c..f6d8f0f 100644
+--- a/modules/input/imquartz.c
++++ b/modules/input/imquartz.c
+@@ -195,11 +195,7 @@ quartz_filter_keypress (GtkIMContext *context,
+     return FALSE;
+
+   nsview = gdk_quartz_window_get_nsview (qc->client_window);
+-  if (GDK_IS_WINDOW (nsview))
+-       /* it gets GDK_WINDOW in some cases */
+-    return gtk_im_context_filter_keypress (qc->slave, event);
+-  else
+-    win = (GdkWindow *)[ (GdkQuartzView *)nsview gdkWindow];
++  win = (GdkWindow *)[ (GdkQuartzView *)nsview gdkWindow];
+   GTK_NOTE (MISC, g_print ("client_window: %p, win: %p, nsview: %p\n",
+                          qc->client_window, win, nsview));
+
+@@ -251,9 +247,6 @@ discard_preedit (GtkIMContext *context)
+   if (!nsview)
+     return;
+
+-  if (GDK_IS_WINDOW (nsview))
+-    return;
+-
+   /* reset any partial input for this NSView */
+   [(GdkQuartzView *)nsview unmarkText];
+   NSInputManager *currentInputManager = [NSInputManager currentInputManager];
+@@ -334,9 +327,6 @@ quartz_set_cursor_location (GtkIMContext *context, GdkRectangle *area)
+   qc->cursor_rect->y = area->y + y;
+
+   nsview = gdk_quartz_window_get_nsview (qc->client_window);
+-  if (GDK_IS_WINDOW (nsview))
+-    /* it returns GDK_WINDOW in some cases */
+-    return;
+
+   win = (GdkWindow *)[ (GdkQuartzView*)nsview gdkWindow];
+   g_object_set_data (G_OBJECT (win), GIC_CURSOR_RECT, qc->cursor_rect);
diff --git a/bockbuild/mac-sdk/patches/gtk/flip-command-mask-between-mod1-and-mod2.patch b/bockbuild/mac-sdk/patches/gtk/flip-command-mask-between-mod1-and-mod2.patch
new file mode 100644 (file)
index 0000000..1ad1efd
--- /dev/null
@@ -0,0 +1,23 @@
+commit d15d466cc479630ac27925b0edaa769c5ab0bead
+Author: Cody Russell <cody@jhu.edu>
+Date:   Tue Jan 13 16:44:46 2015 -0600
+
+    [GtkNSView] Flip command mask between MOD1 and MOD2 depending on gdk_quartz_get_fix_modifiers
+
+diff --git a/gtk/gtknsview.c b/gtk/gtknsview.c
+index ad003d9..d5f8c76 100644
+--- a/gtk/gtknsview.c
++++ b/gtk/gtknsview.c
+@@ -700,9 +700,11 @@ gtk_ns_view_key_press (GtkWidget   *widget,
+       NSWindow *ns_window = [ns_view->priv->view window];
+       NSResponder *responder = [ns_window firstResponder];
+
++      gint command_mask = gdk_quartz_get_fix_modifiers () ? GDK_MOD2_MASK : GDK_MOD1_MASK;
++
+       if ([responder isKindOfClass: [NSTextView class]] &&
+           (event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK |
+-                           GDK_MOD1_MASK | GDK_MOD2_MASK)) == GDK_MOD2_MASK)
++                           GDK_MOD1_MASK | GDK_MOD2_MASK)) == command_mask)
+         {
+           NSTextView *text_view = (NSTextView *) responder;
+           NSRange range = [text_view selectedRange];
diff --git a/bockbuild/mac-sdk/patches/gtk/gtk-check-grab_toplevel-is-destroyed.patch b/bockbuild/mac-sdk/patches/gtk/gtk-check-grab_toplevel-is-destroyed.patch
new file mode 100644 (file)
index 0000000..ce227dd
--- /dev/null
@@ -0,0 +1,13 @@
+diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
+index 23e879c..b7b2665 100644
+--- a/gdk/quartz/gdkevents-quartz.c
++++ b/gdk/quartz/gdkevents-quartz.c
+@@ -831,7 +831,7 @@ find_window_for_ns_event (NSEvent *nsevent,
+                       {
+                         g_warning ("grab_toplevel == NULL");
+                       }
+-                    else
++                    else if (!gdk_window_is_destroyed (grab_toplevel))
+                       {
+                         get_window_point_from_screen_point (grab_toplevel,
+                                                             screen_point, x, y);
diff --git a/bockbuild/mac-sdk/patches/gtk/gtk-imquartz-defer-signals-in-output_result.patch b/bockbuild/mac-sdk/patches/gtk/gtk-imquartz-defer-signals-in-output_result.patch
new file mode 100644 (file)
index 0000000..ac863d1
--- /dev/null
@@ -0,0 +1,65 @@
+diff --git a/modules/input/imquartz.c b/modules/input/imquartz.c
+index 67c7d6c..a8ebd02 100644
+--- a/modules/input/imquartz.c
++++ b/modules/input/imquartz.c
+@@ -132,6 +132,8 @@ output_result (GtkIMContext *context,
+   GtkIMContextQuartz *qc = GTK_IM_CONTEXT_QUARTZ (context);
+   gboolean retval = FALSE;
+   gchar *fixed_str, *marked_str;
++  gboolean needs_commit = FALSE;
++  gboolean needs_preedit_change = FALSE;
+
+   fixed_str = g_object_get_data (G_OBJECT (win), TIC_INSERT_TEXT);
+   marked_str = g_object_get_data (G_OBJECT (win), TIC_MARKED_TEXT);
+@@ -141,8 +143,8 @@ output_result (GtkIMContext *context,
+       g_free (qc->preedit_str);
+       qc->preedit_str = NULL;
+       g_object_set_data (G_OBJECT (win), TIC_INSERT_TEXT, NULL);
+-      g_signal_emit_by_name (context, "commit", fixed_str);
+-      g_signal_emit_by_name (context, "preedit_changed");
++      needs_commit = TRUE;
++      needs_preedit_change = TRUE;
+
+       unsigned int filtered =
+          GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (win),
+@@ -162,10 +164,11 @@ output_result (GtkIMContext *context,
+       qc->selected_len =
+          GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (win),
+                                               TIC_SELECTED_LEN));
+-      g_free (qc->preedit_str);
++      if (qc->preedit_str)
++        g_free (qc->preedit_str);
+       qc->preedit_str = g_strdup (marked_str);
+       g_object_set_data (G_OBJECT (win), TIC_MARKED_TEXT, NULL);
+-      g_signal_emit_by_name (context, "preedit_changed");
++      needs_preedit_change = TRUE;
+       retval = TRUE;
+     }
+   if (!fixed_str && !marked_str)
+@@ -174,8 +177,15 @@ output_result (GtkIMContext *context,
+         retval = TRUE;
+     }
+
+-  g_free (fixed_str);
+-  g_free (marked_str);
++  if (needs_commit)
++    g_signal_emit_by_name (context, "commit", fixed_str);
++  if (needs_preedit_change)
++    g_signal_emit_by_name (context, "preedit-changed");
++
++  if (fixed_str)
++    g_free (fixed_str);
++  if (marked_str)
++    g_free (marked_str);
+
+   return retval;
+ }
+@@ -261,8 +271,6 @@ discard_preedit (GtkIMContext *context)
+
+   if (qc->preedit_str && strlen (qc->preedit_str) > 0)
+     {
+-      g_signal_emit_by_name (context, "commit", qc->preedit_str);
+-
+       g_free (qc->preedit_str);
+       qc->preedit_str = NULL;
+       g_signal_emit_by_name (context, "preedit_changed");
diff --git a/bockbuild/mac-sdk/patches/gtk/gtknsview-defer-map-and-lock-in-clipping.patch b/bockbuild/mac-sdk/patches/gtk/gtknsview-defer-map-and-lock-in-clipping.patch
new file mode 100644 (file)
index 0000000..a5d3bfd
--- /dev/null
@@ -0,0 +1,75 @@
+commit 33da74a9ab13bba4f46b2455cc858c7ae02bd923
+Author: Cody Russell <cody@jhu.edu>
+Date:   Mon Mar 31 08:51:25 2014 -0500
+
+    This is an attempt to solve an issue in GtkNSView that occurs in
+    Xamarin Studio when we try to use an animating NSProgressIndicator.
+    The error only occurred if the indicator was in animating mode,
+    and it seems likely to be a threading race condition somewhere.
+
+    This patch does two things. I've found the issue to be reproducible
+    if we do one of these things but not the other, but I have not been
+    able to reproduce it with both of these.
+
+    First, we slightly defer the mapping of the widget.
+    Second, we lock the view during clip_to_parent_viewports().
+
+    https://bugzilla.xamarin.com/show_bug.cgi?id=17401
+
+diff --git a/gtk/gtknsview.c b/gtk/gtknsview.c
+index d5eb307..31c4970 100644
+--- a/gtk/gtknsview.c
++++ b/gtk/gtknsview.c
+@@ -280,6 +280,7 @@ clip_to_parent_viewports (GtkNSView *ns_view,
+
+   ns_view = get_associated_gtknsview (self);
+
++  [self lockFocusIfCanDraw];
+   if (ns_view)
+     cg_context = clip_to_parent_viewports (ns_view, self);
+
+@@ -287,6 +288,8 @@ clip_to_parent_viewports (GtkNSView *ns_view,
+
+   if (cg_context)
+     CGContextRestoreGState (cg_context);
++
++  [self unlockFocus];
+ }
+ @end
+
+@@ -566,15 +569,17 @@ gtk_ns_view_unrealize (GtkWidget *widget)
+   GTK_WIDGET_CLASS (gtk_ns_view_parent_class)->unrealize (widget);
+ }
+
+-static void
+-gtk_ns_view_map (GtkWidget *widget)
+-{
++static gboolean
++really_map (GtkWidget *widget) {
+   GtkNSView *ns_view = GTK_NS_VIEW (widget);
+   GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
+   GtkAllocation allocation;
+   NSView *parent_view;
+   NSWindow *window;
+
++  if (gtk_widget_get_mapped (widget))
++    return FALSE;
++
+   gtk_widget_get_allocation (widget, &allocation);
+   gtk_ns_view_position_view (ns_view, &allocation);
+
+@@ -605,6 +610,14 @@ gtk_ns_view_map (GtkWidget *widget)
+           gtk_ns_view_swizzle_draw_rect_recursive (text, "gtkwindow", toplevel);
+         }
+     }
++
++  return FALSE;
++}
++
++static void
++gtk_ns_view_map (GtkWidget *widget)
++{
++   g_timeout_add (50, (GSourceFunc)really_map, widget);
+ }
+
+ static void
diff --git a/bockbuild/mac-sdk/patches/gtk/gtknsview-fix-invalid-casts.patch b/bockbuild/mac-sdk/patches/gtk/gtknsview-fix-invalid-casts.patch
new file mode 100644 (file)
index 0000000..0e79a71
--- /dev/null
@@ -0,0 +1,22 @@
+diff --git a/gtk/gtknsview.c b/gtk/gtknsview.c
+index bb9ae06..6820113 100644
+--- a/gtk/gtknsview.c
++++ b/gtk/gtknsview.c
+@@ -534,7 +534,7 @@ gtk_ns_view_notify (GObject    *object,
+                     GParamSpec *pspec)
+ {
+   GtkNSView *ns_view = GTK_NS_VIEW (object);
+-  GtkWindow *window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (object)));
++  GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (object));
+
+   if (G_OBJECT_CLASS (gtk_ns_view_parent_class)->notify)
+     G_OBJECT_CLASS (gtk_ns_view_parent_class)->notify (object, pspec);
+@@ -551,7 +551,7 @@ gtk_ns_view_notify (GObject    *object,
+
+       if (gtk_widget_has_focus (GTK_WIDGET (object)))
+         [ns_window makeFirstResponder:ns_view->priv->view];
+-      else if ([ns_window firstResponder] == ns_view->priv->view || !gtk_window_is_active (window))
++      else if ([ns_window firstResponder] == ns_view->priv->view || (GTK_IS_WINDOW (toplevel) && !gtk_window_is_active (GTK_WINDOW (toplevel))))
+         [ns_window makeFirstResponder:nil];
+     }
+ }
diff --git a/bockbuild/mac-sdk/patches/gtk/gtknsview-forward-cmdz-to-textview-undo-manager.patch b/bockbuild/mac-sdk/patches/gtk/gtknsview-forward-cmdz-to-textview-undo-manager.patch
new file mode 100644 (file)
index 0000000..7649b61
--- /dev/null
@@ -0,0 +1,22 @@
+commit ea748772ee7fd99d70a1ce119bc377c3e2083954
+Author: Cody Russell <cody@jhu.edu>
+Date:   Tue Jan 13 16:46:03 2015 -0600
+
+    [GtkNSView] Add support for forwarding Cmd-Z to an NSTextView's undo manager
+
+diff --git a/gtk/gtknsview.c b/gtk/gtknsview.c
+index d5f8c76..9ba080d 100644
+--- a/gtk/gtknsview.c
++++ b/gtk/gtknsview.c
+@@ -712,6 +712,11 @@ gtk_ns_view_key_press (GtkWidget   *widget,
+
+           switch (event->keyval)
+             {
++            case GDK_KEY_z: /* undo */
++              if ([[text_view undoManager] canUndo])
++                [[text_view undoManager] undo];
++              return TRUE;
++
+             case GDK_KEY_c: /* copy */
+               if (has_selection)
+                 [text_view copy: text_view];
diff --git a/bockbuild/mac-sdk/patches/gtk/gtknsview-getter.patch b/bockbuild/mac-sdk/patches/gtk/gtknsview-getter.patch
new file mode 100644 (file)
index 0000000..e860b73
--- /dev/null
@@ -0,0 +1,29 @@
+diff --git a/gtk/gtknsview.c b/gtk/gtknsview.c
+index 2540a81..e5c48c3 100644
+--- a/gtk/gtknsview.c
++++ b/gtk/gtknsview.c
+@@ -914,5 +914,13 @@ gtk_ns_view_new (gpointer nsview)
+                        NULL);
+ }
+
++gpointer
++gtk_ns_view_get_nsview (GtkNSView *gtknsview)
++{
++  g_return_val_if_fail (GTK_IS_NS_VIEW (gtknsview), NULL);
++
++  return gtknsview->priv->view;
++}
++
+ #define __GTK_NS_VIEW_C__
+ #include "gtkaliasdef.c"
+diff --git a/gtk/gtknsview.h b/gtk/gtknsview.h
+index 2c0aab7..a923827 100644
+--- a/gtk/gtknsview.h
++++ b/gtk/gtknsview.h
+@@ -56,6 +56,7 @@ struct _GtkNSViewClass
+
+ GType       gtk_ns_view_get_type (void) G_GNUC_CONST;
+ GtkWidget * gtk_ns_view_new      (gpointer  nsview);
++gpointer    gtk_ns_view_get_nsview (GtkNSView *gtknsview);
+
+ G_END_DECLS
diff --git a/bockbuild/mac-sdk/patches/gtk/gtknsview-only-unset-first-responder-if-it-is-our-view.patch b/bockbuild/mac-sdk/patches/gtk/gtknsview-only-unset-first-responder-if-it-is-our-view.patch
new file mode 100644 (file)
index 0000000..1a5504d
--- /dev/null
@@ -0,0 +1,28 @@
+commit f35387716481b79c353f098cb80ded665bd7d399
+Author: Cody Russell <cody@jhu.edu>
+Date:   Sat Feb 28 11:27:07 2015 -0600
+
+    GtkNSView should only unset the first responder if either it is
+    our embedded view or if our toplevel window is no longer focused.
+
+diff --git a/gtk/gtknsview.c b/gtk/gtknsview.c
+index b325bda..645231d 100644
+--- a/gtk/gtknsview.c
++++ b/gtk/gtknsview.c
+@@ -534,6 +534,7 @@ gtk_ns_view_notify (GObject    *object,
+                     GParamSpec *pspec)
+ {
+   GtkNSView *ns_view = GTK_NS_VIEW (object);
++  GtkWindow *window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (object)));
+
+   if (G_OBJECT_CLASS (gtk_ns_view_parent_class)->notify)
+     G_OBJECT_CLASS (gtk_ns_view_parent_class)->notify (object, pspec);
+@@ -550,7 +551,7 @@ gtk_ns_view_notify (GObject    *object,
+
+       if (gtk_widget_has_focus (GTK_WIDGET (object)))
+         [ns_window makeFirstResponder:ns_view->priv->view];
+-      else
++      else if ([ns_window firstResponder] == ns_view->priv->view || !gtk_window_is_active (window))
+         [ns_window makeFirstResponder:nil];
+     }
+ }
diff --git a/bockbuild/mac-sdk/patches/gtk/gtknsview-timeout-fix.patch b/bockbuild/mac-sdk/patches/gtk/gtknsview-timeout-fix.patch
new file mode 100644 (file)
index 0000000..a8e99f8
--- /dev/null
@@ -0,0 +1,57 @@
+diff --git a/gtk/gtknsview.c b/gtk/gtknsview.c
+index 31c4970..ad003d9 100644
+--- a/gtk/gtknsview.c
++++ b/gtk/gtknsview.c
+@@ -48,6 +48,7 @@ enum
+ struct _GtkNSViewPrivate
+ {
+   NSView *view;
++  guint   map_timeout;
+ };
+
+ #define GTK_NS_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
+@@ -563,6 +564,15 @@ gtk_ns_view_position_view (GtkNSView     *ns_view,
+ static void
+ gtk_ns_view_unrealize (GtkWidget *widget)
+ {
++  GtkNSView *ns_view = GTK_NS_VIEW (widget);
++
++  if (ns_view->priv->map_timeout != 0)
++    {
++      g_source_remove (ns_view->priv->map_timeout);
++      ns_view->priv->map_timeout = 0;
++      g_object_unref (widget);
++    }
++
+   if (gtk_widget_get_mapped (widget))
+     gtk_widget_unmap (widget);
+
+@@ -577,6 +587,8 @@ really_map (GtkWidget *widget) {
+   NSView *parent_view;
+   NSWindow *window;
+
++  g_object_unref (widget);
++
+   if (gtk_widget_get_mapped (widget))
+     return FALSE;
+
+@@ -611,13 +623,18 @@ really_map (GtkWidget *widget) {
+         }
+     }
+
++  ns_view->priv->map_timeout = 0;
++
+   return FALSE;
+ }
+
+ static void
+ gtk_ns_view_map (GtkWidget *widget)
+ {
+-   g_timeout_add (50, (GSourceFunc)really_map, widget);
++  GtkNSView *ns_view = GTK_NS_VIEW (widget);
++
++  g_object_ref (widget);
++  ns_view->priv->map_timeout = g_timeout_add (50, (GSourceFunc)really_map, widget);
+ }
+
+ static void
diff --git a/bockbuild/mac-sdk/patches/gtk/make-gtkpaned-emit-signals.patch b/bockbuild/mac-sdk/patches/gtk/make-gtkpaned-emit-signals.patch
new file mode 100644 (file)
index 0000000..a26a068
--- /dev/null
@@ -0,0 +1,48 @@
+From 1646b8a78f00cbddc00f6138d80fbc42dec82dac Mon Sep 17 00:00:00 2001
+From: iain holmes <iain@xamarin.com>
+Date: Tue, 13 Sep 2016 16:06:39 +0100
+Subject: [PATCH] [a11y] Make the GtkPaned widget emit GtkContainer::add
+ signals
+
+---
+ gtk/gtkpaned.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/gtk/gtkpaned.c b/gtk/gtkpaned.c
+index f6225f0..0e3afd6 100644
+--- a/gtk/gtkpaned.c
++++ b/gtk/gtkpaned.c
+@@ -1375,6 +1375,10 @@ gtk_paned_pack1 (GtkPaned  *paned,
+       paned->child1_shrink = shrink;
+
+       gtk_widget_set_parent (child, GTK_WIDGET (paned));
++
++      /* We need to emit this signal so that the accessibility system knows
++         that a widget has been added to the pane */
++      g_signal_emit_by_name (G_OBJECT (paned), "add", child);
+     }
+ }
+
+@@ -1394,6 +1398,10 @@ gtk_paned_pack2 (GtkPaned  *paned,
+       paned->child2_shrink = shrink;
+
+       gtk_widget_set_parent (child, GTK_WIDGET (paned));
++
++      /* We need to emit this signal so that the accessibility system knows
++         that a widget has been added to the pane */
++      g_signal_emit_by_name (G_OBJECT (paned), "add", child);
+     }
+ }
+
+@@ -1406,6 +1414,11 @@ gtk_paned_add (GtkContainer *container,
+
+   g_return_if_fail (GTK_IS_PANED (container));
+
++  /* Break the add signal cycle */
++  if (widget->parent == container) {
++    return;
++  }
++
+   paned = GTK_PANED (container);
+
+   if (!paned->child1)
diff --git a/bockbuild/mac-sdk/patches/gtk/nsview-check-for-superview.patch b/bockbuild/mac-sdk/patches/gtk/nsview-check-for-superview.patch
new file mode 100644 (file)
index 0000000..ff7a195
--- /dev/null
@@ -0,0 +1,16 @@
+diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
+index 183537f..ee7dc96 100644
+--- a/gdk/quartz/gdkevents-quartz.c
++++ b/gdk/quartz/gdkevents-quartz.c
+@@ -1831,7 +1831,10 @@ gdk_event_translate (GdkEvent *event,
+             if (tmp_view && [tmp_view respondsToSelector:@selector(isGtkView)])
+               gtk_child = TRUE;
+
+-            tmp_view = [tmp_view superview];
++            if ([tmp_view respondsToSelector:@selector(superview)])
++              tmp_view = [tmp_view superview];
++            else
++              tmp_view = NULL;
+           }
+
+         if (!gtk_child && ![[nswindow firstResponder] respondsToSelector:@selector(isGtkView)])
diff --git a/bockbuild/mac-sdk/patches/gtk/nsview-embedding-fix-keyboard-routing.patch b/bockbuild/mac-sdk/patches/gtk/nsview-embedding-fix-keyboard-routing.patch
new file mode 100644 (file)
index 0000000..e1403df
--- /dev/null
@@ -0,0 +1,32 @@
+commit 291c4626867885c74aa3a544eb9f74cd974895a0
+Author: Cody Russell <cody@jhu.edu>
+Date:   Wed Jan 14 14:56:34 2015 -0600
+
+    When determining if the event is destined for an NSView outside our
+    view hierarchy, we can't just check if it's not a gtkview, we need to
+    also ensure that none of its superviews are gtkviews.
+
+diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
+index 31c5d33..183537f 100644
+--- a/gdk/quartz/gdkevents-quartz.c
++++ b/gdk/quartz/gdkevents-quartz.c
+@@ -1823,7 +1823,18 @@ gdk_event_translate (GdkEvent *event,
+         GdkQuartzWindow *nswindow = ((GdkWindowImplQuartz *)private->impl)->toplevel;
+         GdkQuartzView *nsview = ((GdkWindowImplQuartz *)private->impl)->view;
+
+-        if (![[nswindow firstResponder] respondsToSelector:@selector(isGtkView)])
++        NSView *tmp_view = [nswindow firstResponder];
++        gboolean gtk_child = FALSE;
++
++        while (tmp_view != NULL)
++          {
++            if (tmp_view && [tmp_view respondsToSelector:@selector(isGtkView)])
++              gtk_child = TRUE;
++
++            tmp_view = [tmp_view superview];
++          }
++
++        if (!gtk_child && ![[nswindow firstResponder] respondsToSelector:@selector(isGtkView)])
+           {
+             return_val = FALSE;
+             break;
diff --git a/bockbuild/mac-sdk/patches/gtk/nsview-embedding.patch b/bockbuild/mac-sdk/patches/gtk/nsview-embedding.patch
new file mode 100644 (file)
index 0000000..1c74b71
--- /dev/null
@@ -0,0 +1,229 @@
+diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
+index 6d4abc0..cf8b626 100644
+--- a/gdk/gdkwindow.c
++++ b/gdk/gdkwindow.c
+@@ -1468,6 +1468,8 @@ gdk_window_new (GdkWindow     *parent,
+     private->parent->children = g_list_prepend (private->parent->children, window);
+
+   native = _gdk_native_windows; /* Default */
++  if (attributes->type_hint == 100)
++      native = TRUE;
+   if (private->parent->window_type == GDK_WINDOW_ROOT)
+     native = TRUE; /* Always use native windows for toplevels */
+   else if (!private->input_only &&
+diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h
+index 95a3665..e9428d0 100644
+--- a/gdk/gdkwindow.h
++++ b/gdk/gdkwindow.h
+@@ -722,6 +722,9 @@ void       gdk_window_redirect_to_drawable   (GdkWindow     *window,
+                                               gint           height);
+ void       gdk_window_remove_redirection     (GdkWindow     *window);
+
++/* NSView embedding */
++gboolean   gdk_window_supports_nsview_embedding ();
++
+ #ifndef GDK_DISABLE_DEPRECATED
+ #ifndef GDK_MULTIHEAD_SAFE
+ GdkPointerHooks *gdk_set_pointer_hooks (const GdkPointerHooks *new_hooks);
+diff --git a/gdk/quartz/GdkQuartzView.c b/gdk/quartz/GdkQuartzView.c
+index 1c92714..3c7ba37 100644
+--- a/gdk/quartz/GdkQuartzView.c
++++ b/gdk/quartz/GdkQuartzView.c
+@@ -122,6 +122,11 @@
+   return selectedRange;
+ }
+
++-(BOOL)isGtkView
++{
++  return YES;
++}
++
+ -(void)unmarkText
+ {
+   GDK_NOTE (EVENTS, g_print ("unmarkText\n"));
+diff --git a/gdk/quartz/GdkQuartzView.h b/gdk/quartz/GdkQuartzView.h
+index 2f86de7..04acb62 100644
+--- a/gdk/quartz/GdkQuartzView.h
++++ b/gdk/quartz/GdkQuartzView.h
+@@ -47,5 +47,6 @@
+ - (GdkWindow *)gdkWindow;
+ - (NSTrackingRectTag)trackingRect;
+ - (void)setNeedsInvalidateShadow: (BOOL)invalidate;
++- (void)mouseDown:(NSEvent *)theEvent;
+
+ @end
+diff --git a/gdk/quartz/GdkQuartzWindow.c b/gdk/quartz/GdkQuartzWindow.c
+index 8face0c..b6b794e 100644
+--- a/gdk/quartz/GdkQuartzWindow.c
++++ b/gdk/quartz/GdkQuartzWindow.c
+@@ -228,6 +228,28 @@
+   [self checkSendEnterNotify];
+ }
+
++-(BOOL)makeFirstResponder:(NSResponder *)responder
++{
++  GdkWindow *window = [[self contentView] gdkWindow];
++  GdkWindowObject *private = (GdkWindowObject *)window;
++  GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
++
++  if (impl->type_hint == GDK_WINDOW_TYPE_HINT_TOOLBAR)
++    {
++      if ([responder respondsToSelector:@selector(isGtkView)] ||
++          [responder isKindOfClass:[GdkQuartzView class]])
++        {
++          _gdk_quartz_events_update_focus_window (window, TRUE);
++        }
++      else
++        {
++          _gdk_quartz_events_update_focus_window (window, FALSE);
++        }
++    }
++
++  return [super makeFirstResponder:responder];
++}
++
+ -(id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask backing:(NSBackingStoreType)backingType defer:(BOOL)flag screen:(NSScreen *)screen
+ {
+   self = [super initWithContentRect:contentRect
+diff --git a/gdk/quartz/GdkQuartzWindow.h b/gdk/quartz/GdkQuartzWindow.h
+index 9cdee6b..928f961 100644
+--- a/gdk/quartz/GdkQuartzWindow.h
++++ b/gdk/quartz/GdkQuartzWindow.h
+@@ -44,6 +44,7 @@
+ -(BOOL)trackManualResize;
+ -(void)showAndMakeKey:(BOOL)makeKey;
+ -(void)hide;
++-(BOOL)makeFirstResponder:(NSResponder *)responder;
+
+ @end
+
+diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
+index b7b2665..f5bf65a 100644
+--- a/gdk/quartz/gdkevents-quartz.c
++++ b/gdk/quartz/gdkevents-quartz.c
+@@ -703,6 +703,37 @@ _gdk_quartz_events_send_map_event (GdkWindow *window)
+     }
+ }
+
++static NSView *
++find_nsview_at_pos (GdkWindowImplQuartz *impl, gint x, gint y)
++{
++  NSView *view = impl->view;
++  guint n_subviews;
++  guint i;
++
++  n_subviews = [[view subviews] count];
++
++  for (i = 0; i < n_subviews; ++i)
++    {
++      NSView* sv = [[view subviews] objectAtIndex:i];
++      NSRect r = [sv frame];
++
++      if (sv == impl->layer_view)
++        continue;
++
++      if (r.origin.x <= x && r.origin.x + r.size.width >= x &&
++          r.origin.y <= y && r.origin.y + r.size.height >= y)
++        {
++          NSView* child = find_nsview_at_pos (impl, x - r.origin.x, y - r.origin.y);
++          if (child != NULL)
++            return child;
++          else
++            return sv;
++        }
++    }
++
++  return NULL;
++}
++
+ static GdkWindow *
+ find_toplevel_under_pointer (GdkDisplay *display,
+                              NSPoint     screen_point,
+@@ -869,34 +900,21 @@ find_window_for_ns_event (NSEvent *nsevent,
+               {
+                 GdkWindowObject *toplevel_private;
+                 GdkWindowImplQuartz *toplevel_impl;
+-                guint n_subviews;
+-                guint i;
++                NSView *subview;
+
+                 toplevel = toplevel_under_pointer;
+
+                 toplevel_private = (GdkWindowObject *)toplevel;
+                 toplevel_impl = (GdkWindowImplQuartz *)toplevel_private->impl;
+
+-                n_subviews = [[toplevel_impl->view subviews] count];
+-
+-                for (i = 0; i < n_subviews; ++i)
+-                  {
+-                    NSView* sv = [[toplevel_impl->view subviews] objectAtIndex:i];
+-                    NSRect r = [sv frame];
+-
+-                    if (sv == toplevel_impl->layer_view)
+-                      continue;
+-
+-                    if (r.origin.x <= *x && r.origin.x + r.size.width >= *x &&
+-                        r.origin.y <= *y && r.origin.y + r.size.height >= *y)
+-                      {
+-                        g_signal_emit_by_name (toplevel, "native-child-event",
+-                                               sv, nsevent);
++                subview = find_nsview_at_pos (toplevel_impl, *x, *y);
++                if (subview != NULL && ![subview isKindOfClass:[GdkQuartzView class]]) {
++                  g_signal_emit_by_name (toplevel, "native-child-event",
++                                         subview, nsevent);
+
+-                        /* event is within subview, forward back to Cocoa */
+-                        return NULL;
+-                      }
+-                  }
++                  /* event is within subview, forward back to Cocoa */
++                  return NULL;
++                }
+
+                 *x = x_tmp;
+                 *y = y_tmp;
+@@ -1665,6 +1683,11 @@ gdk_event_translate (GdkEvent *event,
+       GdkWindowObject *private = (GdkWindowObject *)window;
+       GdkWindowImplQuartz *impl = GDK_WINDOW_IMPL_QUARTZ (private->impl);
+
++      GdkQuartzWindow *nswindow = ((GdkWindowImplQuartz *)private->impl)->toplevel;
++      GdkQuartzView *nsview = ((GdkWindowImplQuartz *)private->impl)->view;
++
++      [nswindow makeFirstResponder:nsview];
++
+       if (![NSApp isActive])
+         {
+           [NSApp activateIgnoringOtherApps:YES];
+@@ -1796,6 +1819,15 @@ gdk_event_translate (GdkEvent *event,
+     case NSFlagsChanged:
+       {
+         GdkEventType type;
++        GdkWindowObject *private = (GdkWindowObject *)window;
++        GdkQuartzWindow *nswindow = ((GdkWindowImplQuartz *)private->impl)->toplevel;
++        GdkQuartzView *nsview = ((GdkWindowImplQuartz *)private->impl)->view;
++
++        if (![[nswindow firstResponder] respondsToSelector:@selector(isGtkView)])
++          {
++            return_val = FALSE;
++            break;
++          }
+
+         type = _gdk_quartz_keys_event_type (nsevent);
+         if (type == GDK_NOTHING)
+diff --git a/gdk/quartz/gdkwindow-quartz.c b/gdk/quartz/gdkwindow-quartz.c
+index 5b9ceef..050139a 100644
+--- a/gdk/quartz/gdkwindow-quartz.c
++++ b/gdk/quartz/gdkwindow-quartz.c
+@@ -889,6 +889,12 @@ get_nsscreen_for_point (gint x, gint y)
+   return screen;
+ }
+
++gboolean
++gdk_window_supports_nsview_embedding ()
++{
++  return TRUE;
++}
++
+ void
+ _gdk_window_impl_new (GdkWindow     *window,
+                     GdkWindow     *real_parent,
diff --git a/bockbuild/mac-sdk/patches/gtk/quartz-call-undo-redo-on-cmdz.patch b/bockbuild/mac-sdk/patches/gtk/quartz-call-undo-redo-on-cmdz.patch
new file mode 100644 (file)
index 0000000..98db2ef
--- /dev/null
@@ -0,0 +1,54 @@
+diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
+index ee7dc96..f4ae401 100644
+--- a/gdk/quartz/gdkevents-quartz.c
++++ b/gdk/quartz/gdkevents-quartz.c
+@@ -1826,6 +1826,33 @@ gdk_event_translate (GdkEvent *event,
+         NSView *tmp_view = [nswindow firstResponder];
+         gboolean gtk_child = FALSE;
+
++        if (event_type == NSKeyDown && ([nsevent modifierFlags] & NSCommandKeyMask) != 0 && [[nsevent characters] characterAtIndex:0] == 'z')
++          {
++            if ([tmp_view respondsToSelector:@selector(undoManager)])
++              {
++                NSUndoManager *undo_manager = [tmp_view undoManager];
++
++                if (([nsevent modifierFlags] & NSShiftKeyMask) != 0)
++                  {
++                    if ([undo_manager canRedo])
++                      {
++                        [undo_manager redo];
++                        return_val = FALSE;
++                        break;
++                      }
++                  }
++                else
++                  {
++                    if ([undo_manager canUndo])
++                      {
++                        [undo_manager undo];
++                        return_val = FALSE;
++                        break;
++                      }
++                  }
++              }
++          }
++
+         while (tmp_view != NULL)
+           {
+             if (tmp_view && [tmp_view respondsToSelector:@selector(isGtkView)])
+diff --git a/gtk/gtknsview.c b/gtk/gtknsview.c
+index 71fd917..182c82d 100644
+--- a/gtk/gtknsview.c
++++ b/gtk/gtknsview.c
+@@ -742,11 +742,6 @@ gtk_ns_view_key_press (GtkWidget   *widget,
+
+           switch (event->keyval)
+             {
+-            case GDK_KEY_z: /* undo */
+-              if ([[text_view undoManager] canUndo])
+-                [[text_view undoManager] undo];
+-              return TRUE;
+-
+             case GDK_KEY_c: /* copy */
+               if (has_selection)
+                 [text_view copy: text_view];
diff --git a/bockbuild/mac-sdk/patches/gtk/remove-demos-from-build.patch b/bockbuild/mac-sdk/patches/gtk/remove-demos-from-build.patch
new file mode 100644 (file)
index 0000000..082970a
--- /dev/null
@@ -0,0 +1,19 @@
+commit d91f9583f6a3b0d40912ba35a71534255500b371
+Author: Alexis Christoforides <alexis@thenull.net>
+Date:   Fri Mar 6 15:30:34 2015 -0500
+
+    Remove demos from build, they fail when using a gdk-pixbuf that is staged.
+
+diff --git a/Makefile.am b/Makefile.am
+index 8e3a2f1..7288db2 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -1,7 +1,7 @@
+ ## Makefile.am for GTK+
+ include $(top_srcdir)/Makefile.decl
+
+-SRC_SUBDIRS = gdk gtk modules demos tests perf
++SRC_SUBDIRS = gdk gtk modules tests perf
+ SUBDIRS = po po-properties $(SRC_SUBDIRS) docs m4macros build
+
+ # require automake 1.4
diff --git a/bockbuild/mac-sdk/patches/gtk/remove-mouse-scrolling-from-GtkNotebook-tabs.patch b/bockbuild/mac-sdk/patches/gtk/remove-mouse-scrolling-from-GtkNotebook-tabs.patch
new file mode 100644 (file)
index 0000000..5fb4ce7
--- /dev/null
@@ -0,0 +1,95 @@
+commit ad48f4d52bbac6139dd829fcc421ad16441f34d2
+Author: Cody Russell <bratsche@gnome.org>
+Date:   Tue Sep 21 16:18:22 2010 -0500
+
+    Remove mouse scrolling from GtkNotebook tabs.  Bug #630226.
+
+diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c
+index 0770de6..9931b4c 100644
+--- a/gtk/gtknotebook.c
++++ b/gtk/gtknotebook.c
+@@ -257,8 +257,6 @@ static void gtk_notebook_size_allocate       (GtkWidget        *widget,
+                                             GtkAllocation    *allocation);
+ static gint gtk_notebook_expose              (GtkWidget        *widget,
+                                             GdkEventExpose   *event);
+-static gboolean gtk_notebook_scroll          (GtkWidget        *widget,
+-                                              GdkEventScroll   *event);
+ static gint gtk_notebook_button_press        (GtkWidget        *widget,
+                                             GdkEventButton   *event);
+ static gint gtk_notebook_button_release      (GtkWidget        *widget,
+@@ -542,7 +540,6 @@ gtk_notebook_class_init (GtkNotebookClass *class)
+   widget_class->size_request = gtk_notebook_size_request;
+   widget_class->size_allocate = gtk_notebook_size_allocate;
+   widget_class->expose_event = gtk_notebook_expose;
+-  widget_class->scroll_event = gtk_notebook_scroll;
+   widget_class->button_press_event = gtk_notebook_button_press;
+   widget_class->button_release_event = gtk_notebook_button_release;
+   widget_class->popup_menu = gtk_notebook_popup_menu;
+@@ -1658,7 +1655,6 @@ gtk_notebook_get_property (GObject         *object,
+  * gtk_notebook_size_request
+  * gtk_notebook_size_allocate
+  * gtk_notebook_expose
+- * gtk_notebook_scroll
+  * gtk_notebook_button_press
+  * gtk_notebook_button_release
+  * gtk_notebook_popup_menu
+@@ -1852,8 +1848,7 @@ gtk_notebook_realize (GtkWidget *widget)
+   attributes.event_mask = gtk_widget_get_events (widget);
+   attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
+                           GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
+-                          GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
+-                          GDK_SCROLL_MASK);
++                          GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK);
+   attributes_mask = GDK_WA_X | GDK_WA_Y;
+
+   notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
+@@ -2604,49 +2599,6 @@ get_widget_coordinates (GtkWidget *widget,
+     return FALSE;
+ }
+
+-static gboolean
+-gtk_notebook_scroll (GtkWidget      *widget,
+-                     GdkEventScroll *event)
+-{
+-  GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
+-  GtkNotebook *notebook = GTK_NOTEBOOK (widget);
+-  GtkWidget *child, *event_widget;
+-  gint i;
+-
+-  if (!notebook->cur_page)
+-    return FALSE;
+-
+-  child = notebook->cur_page->child;
+-  event_widget = gtk_get_event_widget ((GdkEvent *)event);
+-
+-  /* ignore scroll events from the content of the page */
+-  if (!event_widget || gtk_widget_is_ancestor (event_widget, child) || event_widget == child)
+-    return FALSE;
+-
+-  /* nor from the action area */
+-  for (i = 0; i < 2; i++)
+-    {
+-      if (event_widget == priv->action_widget[i] ||
+-          (priv->action_widget[i] &&
+-           gtk_widget_is_ancestor (event_widget, priv->action_widget[i])))
+-        return FALSE;
+-    }
+-
+-  switch (event->direction)
+-    {
+-    case GDK_SCROLL_RIGHT:
+-    case GDK_SCROLL_DOWN:
+-      gtk_notebook_next_page (notebook);
+-      break;
+-    case GDK_SCROLL_LEFT:
+-    case GDK_SCROLL_UP:
+-      gtk_notebook_prev_page (notebook);
+-      break;
+-    }
+-
+-  return TRUE;
+-}
+-
+ static GList*
+ get_tab_at_pos (GtkNotebook *notebook, gint x, gint y)
+ {
diff --git a/bockbuild/mac-sdk/patches/gtk/scrolled-window-draw-child-bg.patch b/bockbuild/mac-sdk/patches/gtk/scrolled-window-draw-child-bg.patch
new file mode 100644 (file)
index 0000000..1edc25c
--- /dev/null
@@ -0,0 +1,84 @@
+diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
+index 02920ce..3999d7d 100644
+--- a/gtk/gtkscrolledwindow.c
++++ b/gtk/gtkscrolledwindow.c
+@@ -442,6 +442,13 @@ gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
+                                                                GTK_PARAM_READABLE));
+
+   gtk_widget_class_install_style_property (widget_class,
++             g_param_spec_boolean ("draw-child-bg",
++                       P_("Draw Child Background"),
++                       P_("Fill window with child background color"),
++                       FALSE,
++                       GTK_PARAM_READABLE));
++
++  gtk_widget_class_install_style_property (widget_class,
+                                          g_param_spec_int ("scrollbar-spacing",
+                                                            P_("Scrollbar spacing"),
+                                                            P_("Number of pixels between the scrollbars and the scrolled window"),
+@@ -1296,8 +1303,10 @@ gtk_scrolled_window_paint (GtkWidget      *widget,
+   GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
+   GdkRectangle *area = &event->area;
+   GtkAllocation relative_allocation;
++  gboolean draw_child_bg;
++  gtk_widget_style_get (widget, "draw-child-bg", &draw_child_bg, NULL);
+
+-  if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
++  if (draw_child_bg || scrolled_window->shadow_type != GTK_SHADOW_NONE)
+     {
+       gboolean scrollbars_within_bevel;
+
+@@ -1322,13 +1331,47 @@ gtk_scrolled_window_paint (GtkWidget      *widget,
+           relative_allocation.height = widget->allocation.height - 2 * container->border_width;
+         }
+
+-      gtk_paint_shadow (widget->style, widget->window,
+-                      GTK_STATE_NORMAL, scrolled_window->shadow_type,
+-                      area, widget, "scrolled_window",
+-                      widget->allocation.x + relative_allocation.x,
+-                      widget->allocation.y + relative_allocation.y,
+-                      relative_allocation.width,
+-                      relative_allocation.height);
++      if (draw_child_bg)
++        {
++          GtkWidget *child  = gtk_bin_get_child (GTK_BIN (widget));
++          if (child != NULL)
++            {
++              GdkColor *bgcolor = NULL;
++              if (GTK_IS_TREE_VIEW (child))
++                {
++                  gtk_widget_style_get (child, "even-row-color", &bgcolor, NULL);
++                  if (!bgcolor)
++                    bgcolor = &child->style->base[child->state];
++                } else
++                  bgcolor = &child->style->bg[child->state];
++
++              if (bgcolor)
++                {
++                  cairo_t *cr = gdk_cairo_create (widget->window);
++                  cairo_rectangle (cr,
++                                  widget->allocation.x + relative_allocation.x,
++                                  widget->allocation.y + relative_allocation.y,
++                                  relative_allocation.width,
++                                  relative_allocation.height);
++                  cairo_clip_preserve (cr);
++                  gdk_cairo_set_source_color (cr, bgcolor);
++                  cairo_fill (cr);
++                  cairo_destroy (cr);
++                }
++            }
++        }
++
++      if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
++        {
++
++          gtk_paint_shadow (widget->style, widget->window,
++                           GTK_STATE_NORMAL, scrolled_window->shadow_type,
++                           area, widget, "scrolled_window",
++                           widget->allocation.x + relative_allocation.x,
++                           widget->allocation.y + relative_allocation.y,
++                           relative_allocation.width,
++                           relative_allocation.height);
++        }
+     }
+ }
diff --git a/bockbuild/mac-sdk/patches/mcs-pkgconfig.patch b/bockbuild/mac-sdk/patches/mcs-pkgconfig.patch
new file mode 100644 (file)
index 0000000..eeefebc
--- /dev/null
@@ -0,0 +1,23 @@
+diff --git a/scripts/Makefile.am b/scripts/Makefile.am
+index 73b9cea..98b8cfb 100644
+--- a/scripts/Makefile.am
++++ b/scripts/Makefile.am
+@@ -179,7 +179,8 @@ REWRITE_COMMON = sed \
+       -e 's,@''bindir@,$(bindir),g'                           \
+       -e 's,@''plat_bindir@,$(plat_bindir),g'                 \
+       -e 's,@''mono_instdir@,$(mono_instdir),g'               \
+-      -e 's,@''gtkdir@,$(gtkdir),g'
++      -e 's,@''gtkdir@,$(gtkdir),g'                           \
++      -e 's,@''mono_version@,$(VERSION),g'
+
+ REWRITE = $(REWRITE_COMMON) -e 's,@''mono_interp@,$(mono_interp),g'
+ REWRITE_DEBUG = $(REWRITE_COMMON) -e 's,@''mono_interp@,$(mono_interp) --debug,g'
+diff --git a/scripts/mcs.in b/scripts/mcs.in
+index 32498fa..c15087e 100644
+--- a/scripts/mcs.in
++++ b/scripts/mcs.in
+@@ -1,2 +1,4 @@
+ #!/bin/sh
++export PATH=$PATH:/Library/Frameworks/Mono.framework/Versions/@mono_version@/bin
++export PKG_CONFIG_PATH=/Library/Frameworks/Mono.framework/External/pkgconfig:/Library/Frameworks/Mono.framework/Versions/@mono_version@/lib/pkgconfig:/Library/Frameworks/Mono.framework/Versions/@mono_version@/share/pkgconfig:$PKG_CONFIG_PATH
+ exec @bindir@/mono $MONO_OPTIONS @mono_instdir@/2.0/mcs.exe -lib:@mono_instdir@/2.0 -lib:@mono_instdir@/3.5 "$@"
diff --git a/bockbuild/mac-sdk/patches/murrine-osx.patch b/bockbuild/mac-sdk/patches/murrine-osx.patch
new file mode 100644 (file)
index 0000000..ae5b1f2
--- /dev/null
@@ -0,0 +1,42 @@
+diff --git a/src/murrine_draw.c b/src/murrine_draw.c
+index 4cab20f..06ed9b1 100644
+--- a/src/murrine_draw.c
++++ b/src/murrine_draw.c
+@@ -1625,10 +1625,6 @@ murrine_draw_scrollbar_slider (cairo_t *cr,
+       }
+
+       cairo_restore (cr);
+-
+-      murrine_set_color_rgb (cr, &border);
+-      murrine_rounded_rectangle (cr, 0.5, 0.5, width-1, height-1, widget->roundness, widget->corners);
+-      cairo_stroke (cr);
+ }
+
+ static void
+@@ -1791,21 +1787,15 @@ murrine_draw_normal_arrow (cairo_t *cr,
+ {
+       double arrow_width;
+       double arrow_height;
+-      double line_width_2;
+
+-      cairo_save (cr);
+-
+-      arrow_width = MIN (height*2.0 + MAX (1.0, ceil (height*2.0/6.0*2.0)/2.0)/2.0, width);
+-      line_width_2 = MAX (1.0, ceil (arrow_width/6.0*2.0)/2.0)/2.0;
+-      arrow_height = arrow_width/2.0+line_width_2;
++      arrow_width = CLAMP (width, 3, 8);
++      arrow_height = CLAMP (height, 3, 8);
+
+-      cairo_translate (cr, x, y-arrow_height/2.0);
++      cairo_save (cr);
+
+-      cairo_move_to (cr, -arrow_width/2.0, line_width_2);
+-      cairo_line_to (cr, -arrow_width/2.0 + line_width_2, 0);
+-      cairo_arc_negative (cr, 0, arrow_height-2*line_width_2-2*line_width_2*sqrt(2), 2*line_width_2, M_PI_2+M_PI_4, M_PI_4);
+-      cairo_line_to (cr, arrow_width/2.0-line_width_2, 0);
+-      cairo_line_to (cr, arrow_width/2.0, line_width_2);
++      cairo_translate (cr, x, y - arrow_height / 2.0);
++      cairo_move_to (cr, -arrow_width / 2.0, 0);
++      cairo_line_to (cr, arrow_width / 2.0, 0);
+       cairo_line_to (cr, 0, arrow_height);
+       cairo_close_path (cr);
diff --git a/bockbuild/mac-sdk/patches/pango-coretext-astral-plane-1.patch b/bockbuild/mac-sdk/patches/pango-coretext-astral-plane-1.patch
new file mode 100644 (file)
index 0000000..70be347
--- /dev/null
@@ -0,0 +1,26 @@
+From 3cab26a0468bab855ed2eb13e4f334176e109483 Mon Sep 17 00:00:00 2001
+From: Kristian Rietveld <kris@lanedo.com>
+Date: Tue, 19 Mar 2013 11:23:09 +0100
+Subject: [PATCH 1/2] Simply process entire bitmap obtained from the core text
+ font
+
+---
+ pango/pangocoretext.c |    3 +--
+ 1 files changed, 1 insertions(+), 2 deletions(-)
+
+diff --git a/pango/pangocoretext.c b/pango/pangocoretext.c
+index 36bcd82..1d46271 100644
+--- a/pango/pangocoretext.c
++++ b/pango/pangocoretext.c
+@@ -89,8 +89,7 @@ ct_font_descriptor_get_coverage (CTFontDescriptorRef desc)
+   bitmap = CFCharacterSetCreateBitmapRepresentation (kCFAllocatorDefault,
+                                                      charset);
+
+-  /* We only handle the BMP plane */
+-  length = MIN (CFDataGetLength (bitmap), 8192);
++  length = CFDataGetLength (bitmap);
+   ptr = CFDataGetBytePtr (bitmap);
+
+   /* FIXME: can and should this be done more efficiently? */
+--
+1.7.4.4
diff --git a/bockbuild/mac-sdk/patches/pango-coretext-astral-plane-2.patch b/bockbuild/mac-sdk/patches/pango-coretext-astral-plane-2.patch
new file mode 100644 (file)
index 0000000..92dc8d1
--- /dev/null
@@ -0,0 +1,109 @@
+661f8c0b920f5da Mon Sep 17 00:00:00 2001
+From: Kristian Rietveld <kris@lanedo.com>
+Date: Tue, 19 Mar 2013 11:23:49 +0100
+Subject: [PATCH 2/2] Detect and handle characters encoded in two UTF16 code
+ points
+
+Another important change: gi->index should point at the current
+character, not the current into the string. Before this change,
+the current character equaled the current index into the string.
+---
+ modules/basic/basic-coretext.c |   55 ++++++++++++++++++++++++++++-----------
+ 1 files changed, 39 insertions(+), 16 deletions(-)
+
+diff --git a/modules/basic/basic-coretext.c b/modules/basic/basic-coretext.c
+index 33ce479..06b648e 100644
+--- a/modules/basic/basic-coretext.c
++++ b/modules/basic/basic-coretext.c
+@@ -166,7 +166,42 @@ run_iterator_run_is_non_monotonic (struct RunIterator *iter)
+ static gunichar
+ run_iterator_get_character (struct RunIterator *iter)
+ {
+-  return CFStringGetCharacterAtIndex (iter->cstr, iter->current_indices[iter->ct_i]);
++  int lower, upper;
++
++  lower = iter->current_indices[iter->ct_i];
++  if (iter->ct_i + 1 < CTRunGetGlyphCount (iter->current_run))
++    upper = iter->current_indices[iter->ct_i + 1];
++  else
++    {
++      CFRange range = CTRunGetStringRange (iter->current_run);
++      upper = range.location + range.length;
++    }
++
++  if (upper - lower == 1)
++    return CFStringGetCharacterAtIndex (iter->cstr, lower);
++  if (upper - lower == 2)
++    {
++      /* Character is encoded in two UTF16 code points. */
++      gunichar *ch;
++      gunichar retval;
++      gunichar2 orig[2];
++
++      orig[0] = CFStringGetCharacterAtIndex (iter->cstr, lower);
++      orig[1] = CFStringGetCharacterAtIndex (iter->cstr, lower + 1);
++
++      ch = g_utf16_to_ucs4 (orig, 2, NULL, NULL, NULL);
++      retval = *ch;
++      g_free (ch);
++
++      return retval;
++    }
++
++  /* This should not be reached, because other cases cannot occur. Instead
++   * of crashing, return the first character which will likely be displayed
++   * as unknown glyph.
++   */
++
++  return CFStringGetCharacterAtIndex (iter->cstr, lower);
+ }
+
+ static CGGlyph
+@@ -175,12 +210,6 @@ run_iterator_get_cgglyph (struct RunIterator *iter)
+   return iter->current_cgglyphs[iter->ct_i];
+ }
+
+-static CFIndex
+-run_iterator_get_index (struct RunIterator *iter)
+-{
+-  return iter->current_indices[iter->ct_i];
+-}
+-
+ static gboolean
+ run_iterator_create (struct RunIterator *iter,
+                      const char         *text,
+@@ -336,7 +365,7 @@ create_core_text_glyph_list (const char *text,
+       struct GlyphInfo *gi;
+
+       gi = g_slice_new (struct GlyphInfo);
+-      gi->index = run_iterator_get_index (&riter);
++      gi->index = riter.total_ct_i;
+       gi->cgglyph = run_iterator_get_cgglyph (&riter);
+       gi->wc = run_iterator_get_character (&riter);
+
+@@ -376,9 +405,8 @@ basic_engine_shape (PangoEngineShape    *engine,
+    * glyph sequence generated by the CoreText typesetter:
+    *   # E.g. zero-width spaces do not end up in the CoreText glyph sequence. We have
+    *     to manually account for the gap in the character indices.
+-   *   # Sometimes, CoreText generates two glyph for the same character index. We
+-   *     currently handle this "properly" as in we do not crash or corrupt memory,
+-   *     but that's about it.
++   *   # Sometimes, CoreText generates two glyph for the same character index. These
++   *     are properly composed into a single 32-bit gunichar.
+    *   # Due to mismatches in size, the CoreText glyph sequence can either be longer or
+    *     shorter than the PangoGlyphString. Note that the size of the PangoGlyphString
+    *     should match the number of characters in "text".
+@@ -390,11 +418,6 @@ basic_engine_shape (PangoEngineShape    *engine,
+    * increasing/decreasing.
+    *
+    * FIXME items for future fixing:
+-   *   # CoreText strings are UTF16, and the indices *often* refer to characters,
+-   *     but not *always*. Notable exception is when a character is encoded using
+-   *     two UTF16 code points. This are two characters in a CFString. At this point
+-   *     advancing a single character in the CFString and advancing a single character
+-   *     using g_utf8_next_char in the const char string goes out of sync.
+    *   # We currently don't bother about LTR, Pango core appears to fix this up for us.
+    *     (Even when we cared warnings were generated that strings were in the wrong
+    *     order, this should be investigated).
+--
+1.7.4.4
diff --git a/bockbuild/mac-sdk/patches/pango-coretext-condensed-trait.patch b/bockbuild/mac-sdk/patches/pango-coretext-condensed-trait.patch
new file mode 100644 (file)
index 0000000..7b68888
--- /dev/null
@@ -0,0 +1,14 @@
+diff --git a/pango/pangocoretext-fontmap.c b/pango/pangocoretext-fontmap.c
+index 53b2676..2b30a07 100644
+--- a/pango/pangocoretext-fontmap.c
++++ b/pango/pangocoretext-fontmap.c
+@@ -411,6 +411,9 @@ _pango_core_text_font_description_from_ct_font_descriptor (CTFontDescriptorRef d
+   else
+     pango_font_description_set_style (font_desc, PANGO_STYLE_NORMAL);
+
++  if ((font_traits & kCTFontCondensedTrait) == kCTFontCondensedTrait)
++    pango_font_description_set_stretch (font_desc, PANGO_STRETCH_CONDENSED);
++
+   if (ct_font_descriptor_is_small_caps (desc))
+     pango_font_description_set_variant (font_desc, PANGO_VARIANT_SMALL_CAPS);
+   else
diff --git a/bockbuild/mac-sdk/patches/pango-coretext-fix-yosemite-crasher.patch b/bockbuild/mac-sdk/patches/pango-coretext-fix-yosemite-crasher.patch
new file mode 100644 (file)
index 0000000..16c8d36
--- /dev/null
@@ -0,0 +1,187 @@
+diff --git a/modules/basic/.libs/basic-coretext.o b/modules/basic/.libs/basic-coretext.o
+index 13cce67..80c3268 100644
+Binary files a/modules/basic/.libs/basic-coretext.o and b/modules/basic/.libs/basic-coretext.o differ
+diff --git a/modules/basic/.libs/pango-basic-coretext.so b/modules/basic/.libs/pango-basic-coretext.so
+index 70bb117..d0940c4 100755
+Binary files a/modules/basic/.libs/pango-basic-coretext.so and b/modules/basic/.libs/pango-basic-coretext.so differ
+diff --git a/modules/basic/basic-coretext.c b/modules/basic/basic-coretext.c
+index c34460a..46d83ff 100644
+--- a/modules/basic/basic-coretext.c
++++ b/modules/basic/basic-coretext.c
+@@ -92,6 +92,7 @@ struct RunIterator
+   CTRunRef current_run;
+   CFIndex *current_indices;
+   const CGGlyph *current_cgglyphs;
++  CGGlyph *current_cgglyphs_buffer;
+   CTRunStatus current_run_status;
+ };
+
+@@ -101,6 +102,9 @@ run_iterator_free_current_run (struct RunIterator *iter)
+   iter->current_run_number = -1;
+   iter->current_run = NULL;
+   iter->current_cgglyphs = NULL;
++  if (iter->current_cgglyphs_buffer)
++    free (iter->current_cgglyphs_buffer);
++  iter->current_cgglyphs_buffer = NULL;
+   if (iter->current_indices)
+     free (iter->current_indices);
+   iter->current_indices = NULL;
+@@ -116,10 +120,18 @@ run_iterator_set_current_run (struct RunIterator *iter,
+
+   iter->current_run_number = run_number;
+   iter->current_run = CFArrayGetValueAtIndex (iter->runs, run_number);
++  ct_glyph_count = CTRunGetGlyphCount (iter->current_run);
++
+   iter->current_run_status = CTRunGetStatus (iter->current_run);
+   iter->current_cgglyphs = CTRunGetGlyphsPtr (iter->current_run);
++  if (!iter->current_cgglyphs)
++    {
++      iter->current_cgglyphs_buffer = (CGGlyph *)malloc (sizeof (CGGlyph) * ct_glyph_count);
++      CTRunGetGlyphs (iter->current_run, CFRangeMake (0, ct_glyph_count),
++                      iter->current_cgglyphs_buffer);
++      iter->current_cgglyphs = iter->current_cgglyphs_buffer;
++    }
+
+-  ct_glyph_count = CTRunGetGlyphCount (iter->current_run);
+   iter->current_indices = malloc (sizeof (CFIndex *) * ct_glyph_count);
+   CTRunGetStringIndices (iter->current_run, CFRangeMake (0, ct_glyph_count),
+                          iter->current_indices);
+@@ -237,6 +249,7 @@ run_iterator_create (struct RunIterator *iter,
+   iter->current_run = NULL;
+   iter->current_indices = NULL;
+   iter->current_cgglyphs = NULL;
++  iter->current_cgglyphs_buffer = NULL;
+
+   /* Create CTLine */
+   attributes = CFDictionaryCreate (kCFAllocatorDefault,
+diff --git a/modules/basic/basic-coretext.c.orig b/modules/basic/basic-coretext.c.orig
+index 0a2c27f..c34460a 100644
+--- a/modules/basic/basic-coretext.c.orig
++++ b/modules/basic/basic-coretext.c.orig
+@@ -166,7 +166,42 @@ run_iterator_run_is_non_monotonic (struct RunIterator *iter)
+ static gunichar
+ run_iterator_get_character (struct RunIterator *iter)
+ {
+-  return CFStringGetCharacterAtIndex (iter->cstr, iter->current_indices[iter->ct_i]);
++  int lower, upper;
++
++  lower = iter->current_indices[iter->ct_i];
++  if (iter->ct_i + 1 < CTRunGetGlyphCount (iter->current_run))
++    upper = iter->current_indices[iter->ct_i + 1];
++  else
++    {
++      CFRange range = CTRunGetStringRange (iter->current_run);
++      upper = range.location + range.length;
++    }
++
++  if (upper - lower == 1)
++    return CFStringGetCharacterAtIndex (iter->cstr, lower);
++  if (upper - lower == 2)
++    {
++      /* Character is encoded in two UTF16 code points. */
++      gunichar *ch;
++      gunichar retval;
++      gunichar2 orig[2];
++
++      orig[0] = CFStringGetCharacterAtIndex (iter->cstr, lower);
++      orig[1] = CFStringGetCharacterAtIndex (iter->cstr, lower + 1);
++
++      ch = g_utf16_to_ucs4 (orig, 2, NULL, NULL, NULL);
++      retval = *ch;
++      g_free (ch);
++
++      return retval;
++    }
++
++  /* This should not be reached, because other cases cannot occur. Instead
++   * of crashing, return the first character which will likely be displayed
++   * as unknown glyph.
++   */
++
++  return CFStringGetCharacterAtIndex (iter->cstr, lower);
+ }
+
+ static CGGlyph
+@@ -175,12 +210,6 @@ run_iterator_get_cgglyph (struct RunIterator *iter)
+   return iter->current_cgglyphs[iter->ct_i];
+ }
+
+-static CFIndex
+-run_iterator_get_index (struct RunIterator *iter)
+-{
+-  return iter->current_indices[iter->ct_i];
+-}
+-
+ static gboolean
+ run_iterator_create (struct RunIterator *iter,
+                      const char         *text,
+@@ -190,13 +219,17 @@ run_iterator_create (struct RunIterator *iter,
+   char *copy;
+   CFDictionaryRef attributes;
+   CFAttributedStringRef attstr;
++  int val = 0;
++  CFNumberRef number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &val);
+
+   CFTypeRef keys[] = {
+-      (CFTypeRef) kCTFontAttributeName
++      (CFTypeRef) kCTFontAttributeName,
++      kCTLigatureAttributeName
+   };
+
+   CFTypeRef values[] = {
+-      ctfont
++      ctfont,
++      number
+   };
+
+   /* Initialize RunIterator structure */
+@@ -209,7 +242,7 @@ run_iterator_create (struct RunIterator *iter,
+   attributes = CFDictionaryCreate (kCFAllocatorDefault,
+                                    (const void **)keys,
+                                    (const void **)values,
+-                                   1,
++                                   sizeof (keys) / sizeof (keys[0]),
+                                    &kCFCopyStringDictionaryKeyCallBacks,
+                                    &kCFTypeDictionaryValueCallBacks);
+
+@@ -233,6 +266,7 @@ run_iterator_create (struct RunIterator *iter,
+   iter->line = CTLineCreateWithAttributedString (attstr);
+   iter->runs = CTLineGetGlyphRuns (iter->line);
+
++  CFRelease (number);
+   CFRelease (attstr);
+   CFRelease (attributes);
+
+@@ -336,7 +370,7 @@ create_core_text_glyph_list (const char *text,
+       struct GlyphInfo *gi;
+
+       gi = g_slice_new (struct GlyphInfo);
+-      gi->index = run_iterator_get_index (&riter);
++      gi->index = riter.total_ct_i;
+       gi->cgglyph = run_iterator_get_cgglyph (&riter);
+       gi->wc = run_iterator_get_character (&riter);
+
+@@ -378,9 +412,8 @@ basic_engine_shape (PangoEngineShape    *engine,
+    * glyph sequence generated by the CoreText typesetter:
+    *   # E.g. zero-width spaces do not end up in the CoreText glyph sequence. We have
+    *     to manually account for the gap in the character indices.
+-   *   # Sometimes, CoreText generates two glyph for the same character index. We
+-   *     currently handle this "properly" as in we do not crash or corrupt memory,
+-   *     but that's about it.
++   *   # Sometimes, CoreText generates two glyph for the same character index. These
++   *     are properly composed into a single 32-bit gunichar.
+    *   # Due to mismatches in size, the CoreText glyph sequence can either be longer or
+    *     shorter than the PangoGlyphString. Note that the size of the PangoGlyphString
+    *     should match the number of characters in "text".
+@@ -392,11 +425,6 @@ basic_engine_shape (PangoEngineShape    *engine,
+    * increasing/decreasing.
+    *
+    * FIXME items for future fixing:
+-   *   # CoreText strings are UTF16, and the indices *often* refer to characters,
+-   *     but not *always*. Notable exception is when a character is encoded using
+-   *     two UTF16 code points. This are two characters in a CFString. At this point
+-   *     advancing a single character in the CFString and advancing a single character
+-   *     using g_utf8_next_char in the const char string goes out of sync.
+    *   # We currently don't bother about LTR, Pango core appears to fix this up for us.
+    *     (Even when we cared warnings were generated that strings were in the wrong
+    *     order, this should be investigated).
diff --git a/bockbuild/mac-sdk/patches/pango-disable-ligatures.patch b/bockbuild/mac-sdk/patches/pango-disable-ligatures.patch
new file mode 100644 (file)
index 0000000..ca9140d
--- /dev/null
@@ -0,0 +1,46 @@
+diff --git a/modules/basic/.libs/basic-coretext.o b/modules/basic/.libs/basic-coretext.o
+index f013cbc..270a4f4 100644
+Binary files a/modules/basic/.libs/basic-coretext.o and b/modules/basic/.libs/basic-coretext.o differ
+diff --git a/modules/basic/.libs/pango-basic-coretext.so b/modules/basic/.libs/pango-basic-coretext.so
+index 2cbf3ef..fec3e0f 100755
+Binary files a/modules/basic/.libs/pango-basic-coretext.so and b/modules/basic/.libs/pango-basic-coretext.so differ
+diff --git a/modules/basic/basic-coretext.c b/modules/basic/basic-coretext.c
+index 82c2b48..c34460a 100644
+--- a/modules/basic/basic-coretext.c
++++ b/modules/basic/basic-coretext.c
+@@ -219,13 +219,17 @@ run_iterator_create (struct RunIterator *iter,
+   char *copy;
+   CFDictionaryRef attributes;
+   CFAttributedStringRef attstr;
++  int val = 0;
++  CFNumberRef number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &val);
+
+   CFTypeRef keys[] = {
+-      (CFTypeRef) kCTFontAttributeName
++      (CFTypeRef) kCTFontAttributeName,
++      kCTLigatureAttributeName
+   };
+
+   CFTypeRef values[] = {
+-      ctfont
++      ctfont,
++      number
+   };
+
+   /* Initialize RunIterator structure */
+@@ -238,7 +242,7 @@ run_iterator_create (struct RunIterator *iter,
+   attributes = CFDictionaryCreate (kCFAllocatorDefault,
+                                    (const void **)keys,
+                                    (const void **)values,
+-                                   1,
++                                   sizeof (keys) / sizeof (keys[0]),
+                                    &kCFCopyStringDictionaryKeyCallBacks,
+                                    &kCFTypeDictionaryValueCallBacks);
+
+@@ -262,6 +266,7 @@ run_iterator_create (struct RunIterator *iter,
+   iter->line = CTLineCreateWithAttributedString (attstr);
+   iter->runs = CTLineGetGlyphRuns (iter->line);
+
++  CFRelease (number);
+   CFRelease (attstr);
+   CFRelease (attributes);
diff --git a/bockbuild/mac-sdk/patches/pango-fix-ct_font_descriptor_get_weight-crasher.patch b/bockbuild/mac-sdk/patches/pango-fix-ct_font_descriptor_get_weight-crasher.patch
new file mode 100644 (file)
index 0000000..124692b
--- /dev/null
@@ -0,0 +1,13 @@
+diff --git a/pango/pangocoretext-fontmap.c b/pango/pangocoretext-fontmap.c
+index bcbb173..53b2676 100644
+--- a/pango/pangocoretext-fontmap.c
++++ b/pango/pangocoretext-fontmap.c
+@@ -297,7 +297,7 @@ ct_font_descriptor_get_weight (CTFontDescriptorRef desc)
+   cf_number = (CFNumberRef)CFDictionaryGetValue (dict,
+                                                  kCTFontWeightTrait);
+
+-  if (CFNumberGetValue (cf_number, kCFNumberCGFloatType, &value))
++  if (cf_number != NULL && CFNumberGetValue (cf_number, kCFNumberCGFloatType, &value))
+     {
+       if (value < ct_weight_min || value > ct_weight_max)
+       {
diff --git a/bockbuild/mac-sdk/patches/pango-relative-config-file.patch b/bockbuild/mac-sdk/patches/pango-relative-config-file.patch
new file mode 100644 (file)
index 0000000..ec7a4c1
--- /dev/null
@@ -0,0 +1,25 @@
+Index: pango/pango-utils.c
+===================================================================
+--- a/pango/pango-utils.c      (revision 2425)
++++ b/pango/pango-utils.c      (working copy)
+@@ -567,6 +567,20 @@ read_config_file (const char *filename,
+             gchar *value =  g_key_file_get_value(key_file, group, key, &key_error);
+             if (value != NULL)
+               {
++                  if (!g_path_is_absolute (value))
++                    {
++                      gchar *dirname;
++                      gchar *absolute_path;
++
++                      dirname = g_path_get_dirname (filename);
++                      absolute_path = g_build_filename (dirname, value, NULL);
++
++                      g_free (dirname);
++                      g_free (value);
++
++                      value = absolute_path;
++                    }
++
+                 g_hash_table_insert (ht,
+                                      g_strdup_printf ("%s/%s", group, key),
+                                      value);
diff --git a/bockbuild/mac-sdk/patches/pango-system-font-check-version.patch b/bockbuild/mac-sdk/patches/pango-system-font-check-version.patch
new file mode 100644 (file)
index 0000000..3188dcd
--- /dev/null
@@ -0,0 +1,70 @@
+diff --git a/pango/pangocairo-coretextfontmap.c b/pango/pangocairo-coretextfontmap.c
+index 6cb3809..c75737c 100644
+--- a/pango/pangocairo-coretextfontmap.c
++++ b/pango/pangocairo-coretextfontmap.c
+@@ -185,9 +185,13 @@ pango_cairo_core_text_font_map_load_font (PangoCoreTextFontMap       *fontmap,
+                                           PangoContext               *context,
+                                           const PangoFontDescription *description)
+ {
+-  char *descname = pango_font_description_get_family (description);
++  const char *descname = pango_font_description_get_family (description);
++  SInt32 major, minor;
+
+-  if (strcmp (descname, "-apple-system-font") == 0)
++  Gestalt (gestaltSystemVersionMajor, &major);
++  Gestalt (gestaltSystemVersionMinor, &minor);
++
++  if (major == 10 && minor>= 11 && strcmp (descname, "-apple-system-font") == 0)
+     {
+       PangoCoreTextFont *cfont;
+       NSFont *sysfont;
+@@ -195,7 +199,6 @@ pango_cairo_core_text_font_map_load_font (PangoCoreTextFontMap       *fontmap,
+       cairo_matrix_t font_matrix;
+       PangoCoreTextFontsetKey fontset_key;
+       PangoCoreTextFontKey key;
+-      PangoLanguage *language;
+       PangoFontDescription *tmp_desc;
+       gboolean synthetic_italic = FALSE;
+       double abs_size = get_scaled_size (fontmap, context, description);
+@@ -207,7 +210,7 @@ pango_cairo_core_text_font_map_load_font (PangoCoreTextFontMap       *fontmap,
+       PangoCairoCoreTextFont *cafont = g_object_new (PANGO_TYPE_CAIRO_CORE_TEXT_FONT, NULL);
+       cfont = PANGO_CORE_TEXT_FONT (cafont);
+       cafont->abs_size = abs_size;
+-      _pango_core_text_font_set_ctfont (cfont, CFRetain (sysfont));
++      _pango_core_text_font_set_ctfont (cfont, (CTFontRef)CFRetain (sysfont));
+
+       tmp_desc = pango_font_description_copy_static (description);
+
+@@ -261,7 +264,7 @@ pango_cairo_core_text_font_map_load_font (PangoCoreTextFontMap       *fontmap,
+         }
+     }
+
+-  return PANGO_FONT_MAP_CLASS (pango_cairo_core_text_font_map_parent_class)->load_font (fontmap, context, description);
++  return (PangoCoreTextFont*) PANGO_FONT_MAP_CLASS (pango_cairo_core_text_font_map_parent_class)->load_font (PANGO_FONT_MAP (fontmap), context, description);
+ }
+
+ static void
+diff --git a/pango/pangocoretext-fontmap.c b/pango/pangocoretext-fontmap.c
+index 4234bf1..c395c91 100644
+--- a/pango/pangocoretext-fontmap.c
++++ b/pango/pangocoretext-fontmap.c
+@@ -1367,6 +1367,7 @@ pango_core_text_font_map_init (PangoCoreTextFontMap *ctfontmap)
+   CTFontCollectionRef collection;
+   CFArrayRef ctfaces;
+   CFIndex i, count;
++  SInt32 major, minor;
+
+   ctfontmap->serial = 1;
+   ctfontmap->families = g_hash_table_new_full (g_str_hash, g_str_equal,
+@@ -1430,7 +1431,10 @@ pango_core_text_font_map_init (PangoCoreTextFontMap *ctfontmap)
+       CFRelease (dict);
+     }
+
+-  if (true)
++  Gestalt (gestaltSystemVersionMajor, &major);
++  Gestalt (gestaltSystemVersionMinor, &minor);
++
++  if (major == 10 && minor >= 11)
+     {
+       NSFont *sysfont = [NSFont systemFontOfSize: 0.0];
+       NSString *name = [[NSFont fontWithName: [[sysfont fontDescriptor] postscriptName] size: 0.0] familyName];
diff --git a/bockbuild/mac-sdk/patches/pango-system-font-single.patch b/bockbuild/mac-sdk/patches/pango-system-font-single.patch
new file mode 100644 (file)
index 0000000..c208222
--- /dev/null
@@ -0,0 +1,543 @@
+diff --git a/configure.ac b/configure.ac
+index 42c04ef..1260b8a 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -185,7 +185,7 @@ changequote(,)dnl
+ if test "x$GCC" = "xyes"; then
+   case " $CFLAGS " in
+   *[\ \       ]-Wall[\ \      ]*) ;;
+-  *) CFLAGS="$CFLAGS -Wall" ;;
++  *) CFLAGS="$CFLAGS -Wall -ObjC" ;;
+   esac
+ fi
+ changequote([,])dnl
+diff --git a/pango/pangocairo-coretext.h b/pango/pangocairo-coretext.h
+index 31faf9b..f562587 100644
+--- a/pango/pangocairo-coretext.h
++++ b/pango/pangocairo-coretext.h
+@@ -43,6 +43,19 @@ struct _PangoCairoCoreTextFontMap
+   gdouble dpi;
+ };
+
++struct _PangoCairoCoreTextFont
++{
++  PangoCoreTextFont font;
++  PangoCairoFontPrivate cf_priv;
++
++  int abs_size;
++};
++
++struct _PangoCairoCoreTextFontClass
++{
++  PangoCoreTextFontClass parent_class;
++};
++
+ GType pango_cairo_core_text_font_map_get_type (void) G_GNUC_CONST;
+
+ PangoCoreTextFont *
+diff --git a/pango/pangocairo-coretextfont.c b/pango/pangocairo-coretextfont.c
+index 0f2a9ef..463b6e2 100644
+--- a/pango/pangocairo-coretextfont.c
++++ b/pango/pangocairo-coretextfont.c
+@@ -23,6 +23,7 @@
+
+ #include "config.h"
+
++#import <AppKit/AppKit.h>
+ #include <Carbon/Carbon.h>
+
+ #include "pango-impl-utils.h"
+@@ -32,21 +33,6 @@
+ #include "pangocairo-coretext.h"
+ #include "pangocairo-coretextfont.h"
+
+-struct _PangoCairoCoreTextFont
+-{
+-  PangoCoreTextFont font;
+-  PangoCairoFontPrivate cf_priv;
+-
+-  int abs_size;
+-};
+-
+-struct _PangoCairoCoreTextFontClass
+-{
+-  PangoCoreTextFontClass parent_class;
+-};
+-
+-
+-
+ static cairo_font_face_t *pango_cairo_core_text_font_create_font_face           (PangoCairoFont *font);
+ static PangoFontMetrics  *pango_cairo_core_text_font_create_base_metrics_for_context (PangoCairoFont *font,
+                                                                                       PangoContext    *context);
+@@ -204,6 +190,75 @@ pango_cairo_core_text_font_init (PangoCairoCoreTextFont *cafont G_GNUC_UNUSED)
+ {
+ }
+
++static gchar *
++gchar_from_cf_string (CFStringRef str)
++{
++  CFIndex len;
++  gchar *buffer;
++
++  /* GetLength returns the number of UTF-16 pairs, so this number
++   * times 2 should definitely give us enough space for UTF8.
++   * We add one for the terminating zero.
++   */
++  len = CFStringGetLength (str) * 2 + 1;
++  buffer = g_new0 (char, len);
++  CFStringGetCString (str, buffer, len, kCFStringEncodingUTF8);
++
++  return buffer;
++}
++
++static gchar *
++ct_font_descriptor_get_family_name (CTFontDescriptorRef desc,
++                                    gboolean            may_fail)
++{
++  CFStringRef cf_str;
++  char *buffer;
++
++  cf_str = CTFontDescriptorCopyAttribute (desc, kCTFontFamilyNameAttribute);
++  if (!cf_str)
++    {
++      int i;
++
++      /* No font family name is set, try to retrieve font name and deduce
++       * the family name from that instead.
++       */
++      cf_str = CTFontDescriptorCopyAttribute (desc, kCTFontNameAttribute);
++      if (!cf_str)
++        {
++          if (may_fail)
++            return NULL;
++
++          /* This font is likely broken, return a default family name ... */
++          return g_strdup ("Sans");
++        }
++
++      buffer = gchar_from_cf_string (cf_str);
++      CFRelease (cf_str);
++
++      for (i = 0; i < strlen (buffer); i++)
++        if (buffer[i] == '-')
++          break;
++
++      if (i < strlen (buffer))
++        {
++          char *ret;
++
++          ret = g_strndup (buffer, i);
++          g_free (buffer);
++
++          return ret;
++        }
++      else
++        return buffer;
++    }
++  /* else */
++
++  buffer = gchar_from_cf_string (cf_str);
++  CFRelease (cf_str);
++
++  return buffer;
++}
++
+ PangoCoreTextFont *
+ _pango_cairo_core_text_font_new (PangoCairoCoreTextFontMap  *cafontmap,
+                                  PangoCoreTextFontKey       *key)
+diff --git a/pango/pangocairo-coretextfontmap.c b/pango/pangocairo-coretextfontmap.c
+index ba5dcec..6cb3809 100644
+--- a/pango/pangocairo-coretextfontmap.c
++++ b/pango/pangocairo-coretextfontmap.c
+@@ -26,6 +26,9 @@
+ #include "pangocairo.h"
+ #include "pangocairo-private.h"
+ #include "pangocairo-coretext.h"
++#include "pangocairo-coretextfont.h"
++
++#import <AppKit/Appkit.h>
+
+ typedef struct _PangoCairoCoreTextFontMapClass PangoCairoCoreTextFontMapClass;
+
+@@ -161,6 +164,106 @@ pango_cairo_core_text_font_map_context_key_equal (PangoCoreTextFontMap *fontmap
+   return cairo_font_options_equal (key_a, key_b);
+ }
+
++static int
++get_scaled_size (PangoCoreTextFontMap       *fontmap,
++                 PangoContext               *context,
++                 const PangoFontDescription *desc)
++{
++  double size = pango_font_description_get_size (desc);
++
++  if (!pango_font_description_get_size_is_absolute (desc))
++    {
++      double dpi = pango_cairo_core_text_font_map_get_resolution_core_text (fontmap, context);
++      size = size * dpi / 72.;
++    }
++
++  return .5 + pango_matrix_get_font_scale_factor (pango_context_get_matrix (context)) * size;
++}
++
++static PangoCoreTextFont *
++pango_cairo_core_text_font_map_load_font (PangoCoreTextFontMap       *fontmap,
++                                          PangoContext               *context,
++                                          const PangoFontDescription *description)
++{
++  char *descname = pango_font_description_get_family (description);
++
++  if (strcmp (descname, "-apple-system-font") == 0)
++    {
++      PangoCoreTextFont *cfont;
++      NSFont *sysfont;
++      CTFontDescriptorRef ctfontdescriptor;
++      cairo_matrix_t font_matrix;
++      PangoCoreTextFontsetKey fontset_key;
++      PangoCoreTextFontKey key;
++      PangoLanguage *language;
++      PangoFontDescription *tmp_desc;
++      gboolean synthetic_italic = FALSE;
++      double abs_size = get_scaled_size (fontmap, context, description);
++      double size = pango_units_to_double (abs_size) / pango_matrix_get_font_scale_factor (pango_context_get_matrix (context));
++
++      sysfont = [NSFont systemFontOfSize: size];
++      ctfontdescriptor = (CTFontDescriptorRef)[sysfont fontDescriptor];
++
++      PangoCairoCoreTextFont *cafont = g_object_new (PANGO_TYPE_CAIRO_CORE_TEXT_FONT, NULL);
++      cfont = PANGO_CORE_TEXT_FONT (cafont);
++      cafont->abs_size = abs_size;
++      _pango_core_text_font_set_ctfont (cfont, CFRetain (sysfont));
++
++      tmp_desc = pango_font_description_copy_static (description);
++
++      _pango_core_text_fontset_key_init (&fontset_key,
++                                         fontmap,
++                                         context,
++                                         tmp_desc,
++                                         pango_context_get_language (context));
++      _pango_core_text_font_key_init (&key,
++                                      fontmap,
++                                      &fontset_key,
++                                      ctfontdescriptor,
++                                      synthetic_italic);
++
++      if (pango_core_text_font_key_get_synthetic_italic (&key))
++        synthetic_italic = TRUE;
++
++      if (synthetic_italic)
++        {
++          cairo_matrix_init (&font_matrix,
++                             1, 0,
++                             -0.25, 1,
++                             0, 0);
++        }
++      else
++        {
++          cairo_matrix_init_identity (&font_matrix);
++        }
++
++      cairo_matrix_scale (&font_matrix, size, size);
++
++      _pango_cairo_font_private_initialize (&cafont->cf_priv,
++                                            (PangoCairoFont *)cafont,
++                                            pango_core_text_font_key_get_gravity (&key),
++                                            pango_core_text_font_key_get_context_key (&key),
++                                            pango_core_text_font_key_get_matrix (&key),
++                                            &font_matrix);
++
++      PangoCoreTextFont *tmp_font = _pango_core_text_font_map_lookup_font (fontmap, &key);
++      if (tmp_font)
++        {
++          g_object_ref (tmp_font);
++          return tmp_font;
++        }
++      else
++        {
++          g_object_ref (cfont);
++          _pango_core_text_font_map_add (PANGO_CORE_TEXT_FONT_MAP (fontmap), &key, cfont);
++
++          return cfont;
++        }
++    }
++
++  return PANGO_FONT_MAP_CLASS (pango_cairo_core_text_font_map_parent_class)->load_font (fontmap, context, description);
++}
++
+ static void
+ pango_cairo_core_text_font_map_class_init (PangoCairoCoreTextFontMapClass *class)
+ {
+@@ -170,6 +273,7 @@ pango_cairo_core_text_font_map_class_init (PangoCairoCoreTextFontMapClass *class
+
+   object_class->finalize = pango_cairo_core_text_font_map_finalize;
+
++  fontmap_class->load_font = pango_cairo_core_text_font_map_load_font;
+   fontmap_class->get_serial = pango_cairo_core_text_font_map_get_serial;
+   fontmap_class->changed = pango_cairo_core_text_font_map_changed;
+
+diff --git a/pango/pangocoretext-fontmap.c b/pango/pangocoretext-fontmap.c
+index bcbb173..4234bf1 100644
+--- a/pango/pangocoretext-fontmap.c
++++ b/pango/pangocoretext-fontmap.c
+@@ -28,6 +28,7 @@
+ #include "pango-impl-utils.h"
+ #include "modules.h"
+
++#import <AppKit/Appkit.h>
+ #include <Carbon/Carbon.h>
+
+ typedef struct _FontHashKey      FontHashKey;
+@@ -826,28 +827,12 @@ get_scaled_size (PangoCoreTextFontMap       *fontmap,
+   return .5 + pango_matrix_get_font_scale_factor (pango_context_get_matrix (context)) * size;
+ }
+
+-
+-/*
+- * PangoCoreTextFontsetKey
+- */
+-struct _PangoCoreTextFontsetKey
+-{
+-  PangoCoreTextFontMap *fontmap;
+-  PangoLanguage *language;
+-  PangoFontDescription *desc;
+-  PangoMatrix matrix;
+-  int pixelsize;
+-  double resolution;
+-  PangoGravity gravity;
+-  gpointer context_key;
+-};
+-
+-static void
+-pango_core_text_fontset_key_init (PangoCoreTextFontsetKey    *key,
+-                                  PangoCoreTextFontMap       *fontmap,
+-                                  PangoContext               *context,
+-                                  const PangoFontDescription *desc,
+-                                  PangoLanguage              *language)
++void
++_pango_core_text_fontset_key_init (PangoCoreTextFontsetKey    *key,
++                                   PangoCoreTextFontMap       *fontmap,
++                                   PangoContext               *context,
++                                   const PangoFontDescription *desc,
++                                   PangoLanguage              *language)
+ {
+   if (!language && context)
+     language = pango_context_get_language (context);
+@@ -960,27 +945,12 @@ pango_core_text_fontset_key_get_context_key (const PangoCoreTextFontsetKey *key)
+   return key->context_key;
+ }
+
+-/*
+- * PangoCoreTextFontKey
+- */
+-struct _PangoCoreTextFontKey
+-{
+-  PangoCoreTextFontMap *fontmap;
+-  CTFontDescriptorRef ctfontdescriptor;
+-  PangoMatrix matrix;
+-  PangoGravity gravity;
+-  int pixelsize;
+-  double resolution;
+-  gboolean synthetic_italic;
+-  gpointer context_key;
+-};
+-
+-static void
+-pango_core_text_font_key_init (PangoCoreTextFontKey    *key,
+-                               PangoCoreTextFontMap    *ctfontmap,
+-                               PangoCoreTextFontsetKey *fontset_key,
+-                               CTFontDescriptorRef      ctdescriptor,
+-                               gboolean                 synthetic_italic)
++void
++_pango_core_text_font_key_init (PangoCoreTextFontKey    *key,
++                                PangoCoreTextFontMap    *ctfontmap,
++                                PangoCoreTextFontsetKey *fontset_key,
++                                CTFontDescriptorRef      ctdescriptor,
++                                gboolean                 synthetic_italic)
+ {
+   key->fontmap = ctfontmap;
+   key->ctfontdescriptor = ctdescriptor;
+@@ -1104,14 +1074,24 @@ pango_core_text_font_key_get_ctfontdescriptor (const PangoCoreTextFontKey *key)
+   return key->ctfontdescriptor;
+ }
+
++PangoCoreTextFont *
++_pango_core_text_font_map_lookup_font (PangoCoreTextFontMap *fontmap,
++                                       PangoCoreTextFontKey *key)
++{
++  return g_hash_table_lookup (fontmap->font_hash, key);
++}
+
+-
+-static void
+-pango_core_text_font_map_add (PangoCoreTextFontMap *ctfontmap,
+-                              PangoCoreTextFontKey *key,
+-                              PangoCoreTextFont    *ctfont)
++void
++_pango_core_text_font_map_add (PangoCoreTextFontMap *ctfontmap,
++                               PangoCoreTextFontKey *key,
++                               PangoCoreTextFont    *ctfont)
+ {
+   PangoCoreTextFontKey *key_copy;
++  PangoCoreTextFont *tmp;
++
++  tmp = g_hash_table_lookup (ctfontmap->font_hash, key);
++  if (tmp)
++    return;
+
+   _pango_core_text_font_set_font_map (ctfont, ctfontmap);
+
+@@ -1130,8 +1110,8 @@ pango_core_text_font_map_new_font (PangoCoreTextFontMap    *fontmap,
+   PangoCoreTextFont *font;
+   PangoCoreTextFontKey key;
+
+-  pango_core_text_font_key_init (&key, fontmap, fontset_key, ctfontdescriptor,
+-                                 synthetic_italic);
++  _pango_core_text_font_key_init (&key, fontmap, fontset_key, ctfontdescriptor,
++                                  synthetic_italic);
+
+   font = g_hash_table_lookup (fontmap->font_hash, &key);
+   if (font)
+@@ -1144,7 +1124,7 @@ pango_core_text_font_map_new_font (PangoCoreTextFontMap    *fontmap,
+   if (!font)
+     return NULL;
+
+-  pango_core_text_font_map_add (fontmap, &key, font);
++  _pango_core_text_font_map_add (fontmap, &key, font);
+
+   return font;
+ }
+@@ -1295,8 +1275,8 @@ pango_core_text_font_map_load_fontset (PangoFontMap               *fontmap,
+   PangoCoreTextFontMap *ctfontmap = PANGO_CORE_TEXT_FONT_MAP (fontmap);
+   static gboolean warned_full_fallback = FALSE; /* MT-safe */
+
+-  pango_core_text_fontset_key_init (&key, ctfontmap,
+-                                    context, desc, language);
++  _pango_core_text_fontset_key_init (&key, ctfontmap,
++                                     context, desc, language);
+
+   fontset = g_hash_table_lookup (ctfontmap->fontset_hash, &key);
+
+@@ -1320,8 +1300,8 @@ pango_core_text_font_map_load_fontset (PangoFontMap               *fontmap,
+           tmp_desc = pango_font_description_copy_static (desc);
+           pango_font_description_set_family_static (tmp_desc, "Sans");
+
+-          pango_core_text_fontset_key_init (&key, ctfontmap, context, tmp_desc,
+-                                            language);
++          _pango_core_text_fontset_key_init (&key, ctfontmap, context, tmp_desc,
++                                             language);
+
+           fontset = g_hash_table_lookup (ctfontmap->fontset_hash, &key);
+           if (G_LIKELY (fontset))
+@@ -1450,6 +1430,53 @@ pango_core_text_font_map_init (PangoCoreTextFontMap *ctfontmap)
+       CFRelease (dict);
+     }
+
++  if (true)
++    {
++      NSFont *sysfont = [NSFont systemFontOfSize: 0.0];
++      NSString *name = [[NSFont fontWithName: [[sysfont fontDescriptor] postscriptName] size: 0.0] familyName];
++
++      NSArray *fontfaces = [[NSFontManager sharedFontManager] availableMembersOfFontFamily: name];
++      int num_faces = [fontfaces count];
++      CFRelease (name);
++
++      for (int faceindex = 0; faceindex < num_faces; faceindex++)
++        {
++          SInt64 font_traits;
++          char *buffer;
++          char *family_name;
++          CFNumberRef number;
++          CFDictionaryRef dict;
++          CTFontDescriptorRef desc = [sysfont fontDescriptor];
++
++          buffer = ct_font_descriptor_get_family_name (desc, TRUE);
++          if (!buffer)
++            continue;
++
++          family_name = g_utf8_casefold (buffer, -1);
++          family = g_hash_table_lookup (ctfontmap->families, family_name);
++          if (!family)
++            {
++              family = g_object_new (PANGO_TYPE_CORE_TEXT_FAMILY, NULL);
++              g_hash_table_insert (ctfontmap->families, g_strdup ("-apple-system-font"), family);
++              family->family_name = g_strdup (buffer);
++            }
++
++          g_free (buffer);
++          g_free (family_name);
++
++          dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
++          number = (CFNumberRef)CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
++
++          if (CFNumberGetValue (number, kCFNumberSInt64Type, &font_traits))
++            {
++              if ((font_traits & kCTFontMonoSpaceTrait) == kCTFontMonoSpaceTrait)
++                family->is_monospace = TRUE;
++            }
++
++          CFRelease (dict);
++        }
++    }
++
+   /* Insert aliases */
+   family = g_object_new (PANGO_TYPE_CORE_TEXT_FAMILY, NULL);
+   family->family_name = g_strdup ("Sans");
+diff --git a/pango/pangocoretext-private.h b/pango/pangocoretext-private.h
+index 8076eae..5c6ce41 100644
+--- a/pango/pangocoretext-private.h
++++ b/pango/pangocoretext-private.h
+@@ -81,6 +81,30 @@ struct _PangoCoreTextFontMapClass
+                                           PangoContext              *context);
+ };
+
++struct _PangoCoreTextFontKey
++{
++  PangoCoreTextFontMap *fontmap;
++  CTFontDescriptorRef ctfontdescriptor;
++  PangoMatrix matrix;
++  PangoGravity gravity;
++  int pixelsize;
++  double resolution;
++  gboolean synthetic_italic;
++  gpointer context_key;
++};
++
++struct _PangoCoreTextFontsetKey
++{
++  PangoCoreTextFontMap *fontmap;
++  PangoLanguage *language;
++  PangoFontDescription *desc;
++  PangoMatrix matrix;
++  int pixelsize;
++  double resolution;
++  PangoGravity gravity;
++  gpointer context_key;
++};
++
+
+ GType                 pango_core_text_font_map_get_type          (void) G_GNUC_CONST;
+
+@@ -97,6 +121,24 @@ void                  _pango_core_text_font_set_font_key         (PangoCoreTextF
+ void                  _pango_core_text_font_set_ctfont           (PangoCoreTextFont    *font,
+                                                                   CTFontRef         font_ref);
+
++void                  _pango_core_text_fontset_key_init          (PangoCoreTextFontsetKey    *key,
++                                                                  PangoCoreTextFontMap       *fontmap,
++                                                                  PangoContext               *context,
++                                                                  const PangoFontDescription *desc,
++                                                                  PangoLanguage              *language);
++void                  _pango_core_text_font_key_init             (PangoCoreTextFontKey       *key,
++                                                                  PangoCoreTextFontMap       *ctfontmap,
++                                                                  PangoCoreTextFontsetKey    *fontset_key,
++                                                                  CTFontDescriptorRef         ctdescriptor,
++                                                                  gboolean                    synthetic_italic);
++
++void                  _pango_core_text_font_map_add              (PangoCoreTextFontMap       *ctfontmap,
++                                                                  PangoCoreTextFontKey       *key,
++                                                                  PangoCoreTextFont          *ctfont);
++
++PangoCoreTextFont    *_pango_core_text_font_map_lookup_font      (PangoCoreTextFontMap       *fontmap,
++                                                                  PangoCoreTextFontKey       *key);
++
+ PangoFontDescription *_pango_core_text_font_description_from_ct_font_descriptor (CTFontDescriptorRef desc);
+
+ int                   pango_core_text_font_key_get_absolute_size    (const PangoCoreTextFontKey *key);
diff --git a/bockbuild/mac-sdk/patches/tiff-4.0.2-macosx-2.patch b/bockbuild/mac-sdk/patches/tiff-4.0.2-macosx-2.patch
new file mode 100644 (file)
index 0000000..a5f74df
--- /dev/null
@@ -0,0 +1,22 @@
+diff --git a/libs/tiff-4.0.2/tools/tiffgt.c b/libs/tiff-4.0.2/tools/tiffgt.c
+index de42039..4c8e509 100644
+--- a/tools/tiffgt.c
++++ b/tools/tiffgt.c
+@@ -31,11 +31,16 @@
+ #include <string.h>
+ #include <unistd.h>
+
+-#if HAVE_APPLE_OPENGL_FRAMEWORK
++#if HAVE_OPENGL_GL_H
+ # include <OpenGL/gl.h>
++#endif
++#if HAVE_GLUT_GLUT_H
+ # include <GLUT/glut.h>
+-#else
++#endif
++#if HAVE_GL_GL_H
+ # include <GL/gl.h>
++#endif
++#if HAVE_GL_GLUT_H
+ # include <GL/glut.h>
+ #endif
diff --git a/bockbuild/mac-sdk/pcl-reference-assemblies.py b/bockbuild/mac-sdk/pcl-reference-assemblies.py
new file mode 100644 (file)
index 0000000..2953a0a
--- /dev/null
@@ -0,0 +1,57 @@
+import glob
+import os
+import shutil
+
+
+class PCLReferenceAssembliesPackage(Package):
+
+    def __init__(self):
+        Package.__init__(self,
+                         name='PortableReferenceAssemblies',
+                         version='2014-04-14',
+                         sources=['http://storage.bos.xamarin.com/bot-provisioning/PortableReferenceAssemblies-2014-04-14.zip'])
+
+    def build(self):
+        pass
+
+    # A bunch of shell script written inside python literals ;(
+    def install(self):
+        dest = os.path.join(
+            self.staged_prefix,
+            "lib",
+            "mono",
+            "xbuild-frameworks",
+            ".NETPortable")
+        if not os.path.exists(dest):
+            os.makedirs(dest)
+
+        shutil.rmtree(dest, ignore_errors=True)
+
+        self.sh("rsync -abv -q %s/* %s" % (self.workspace, dest))
+
+        for f in glob.glob("%s/*/Profile/*/SupportedFrameworks" % dest):
+            self.write_xml(f)
+
+    def write_xml(self, directory):
+        # print "Writing iOS/Android/Mac listings for " + directory
+        data = {
+            os.path.join(directory, "MonoTouch.xml"):
+            """<Framework Identifier="MonoTouch" MinimumVersion="1.0" Profile="*" DisplayName="Xamarin.iOS Classic"/>""",
+            os.path.join(directory, "Xamarin.iOS.xml"):
+            """<Framework Identifier="Xamarin.iOS" MinimumVersion="1.0" Profile="*" DisplayName="Xamarin.iOS Unified"/>""",
+            os.path.join(directory, "Xamarin.Android.xml"):
+            """<Framework Identifier="MonoAndroid" MinimumVersion="1.0" Profile="*" DisplayName="Xamarin.Android"/>""",
+            os.path.join(directory, "Xamarin.Mac.xml"):
+            """<Framework Identifier="Xamarin.Mac" MinimumVersion="2.0" Profile="*" DisplayName="Xamarin.Mac Unified"/>""",
+            os.path.join(directory, "Xamarin.TVOS.xml"):
+            """<Framework Identifier="Xamarin.TVOS" MinimumVersion="1.0" Profile="*" DisplayName="Xamarin.TVOS"/>""",
+            os.path.join(directory, "Xamarin.WatchOS.xml"):
+            """<Framework Identifier="Xamarin.WatchOS" MinimumVersion="1.0" Profile="*" DisplayName="Xamarin.WatchOS"/>""",
+        }
+        for filename, content in data.iteritems():
+            f = open(filename, "w")
+            f.write(content + "\n")
+            f.close()
+
+
+PCLReferenceAssembliesPackage()
diff --git a/bockbuild/mac-sdk/pixman.py b/bockbuild/mac-sdk/pixman.py
new file mode 100644 (file)
index 0000000..c0394a9
--- /dev/null
@@ -0,0 +1,6 @@
+class PixmanPackage (CairoGraphicsPackage):
+
+    def __init__(self):
+        CairoGraphicsPackage.__init__(self, 'pixman', '0.30.0')
+
+PixmanPackage()
diff --git a/bockbuild/mac-sdk/pkg-config.py b/bockbuild/mac-sdk/pkg-config.py
new file mode 100644 (file)
index 0000000..6c62cbe
--- /dev/null
@@ -0,0 +1,4 @@
+package = FreeDesktopPackage('%{name}', 'pkg-config', '0.27',
+                             configure_flags=["--with-internal-glib"])
+
+package.needs_lipo = True
diff --git a/bockbuild/mac-sdk/profile.py b/bockbuild/mac-sdk/profile.py
new file mode 100755 (executable)
index 0000000..33d309b
--- /dev/null
@@ -0,0 +1,398 @@
+import itertools
+import os
+import re
+import shutil
+import string
+import sys
+import tempfile
+import subprocess
+import stat
+
+from bockbuild.darwinprofile import DarwinProfile
+from bockbuild.util.util import *
+from glob import glob
+
+class MonoReleaseProfile(DarwinProfile):
+
+    packages = [
+        'autoconf',
+        'automake',
+        'gettext',
+        'pkg-config',
+
+        # Base Libraries
+        'libpng',
+        'libjpeg',
+        'libtiff',
+        'libgif',
+        'libxml2',
+        'freetype',
+        'fontconfig',
+        'pixman',
+        'cairo',
+        'libffi',
+        'glib',
+        'pango',
+        'atk',
+        'intltool',
+        'gdk-pixbuf',
+        'gtk+',
+        'libglade',
+        'sqlite',
+        'expat',
+        'ige-mac-integration',
+
+        # Theme
+        'libcroco',
+        'librsvg',
+        'hicolor-icon-theme',
+        'gtk-engines',
+        'murrine',
+        'xamarin-gtk-theme',
+        'gtk-quartz-engine',
+
+        # Mono
+        'mono-llvm',
+        'mono',
+        'msbuild',
+        'pcl-reference-assemblies',
+        'libgdiplus',
+        'xsp',
+        'gtk-sharp',
+        'ironlangs',
+        'fsharp',
+        'mono-basic',
+        'nuget'
+    ]
+
+    def attach (self, bockbuild):
+        self.min_version = 7
+        DarwinProfile.attach (self, bockbuild)
+
+        # quick disk space check (http://stackoverflow.com/questions/787776/)
+        s = os.statvfs(bockbuild.root)
+        free_space = (s.f_bavail * s.f_frsize) / (1024 * 1024 * 1024)  # in GB
+
+        if free_space < 10:
+            error('Low disk space (less than 10GB), aborting')
+
+        # check for XQuartz installation (needed for libgdiplus)
+        if not os.path.exists('/opt/X11/include/X11/Xlib.h'):
+            error(
+                'XQuartz is required to be installed (download from http://xquartz.macosforge.org/) ')
+
+        self.MONO_ROOT = "/Library/Frameworks/Mono.framework"
+        self.BUILD_NUMBER = "0"
+        self.MDK_GUID = "964ebddd-1ffe-47e7-8128-5ce17ffffb05"
+
+        self.self_dir = os.path.realpath(os.path.dirname(sys.argv[0]))
+        self.packaging_dir = os.path.join(self.self_dir, "packaging")
+
+        system_mono_dir = '/Library/Frameworks/Mono.framework/Versions/Current'
+        self.env.set('system_mono', os.path.join(
+            system_mono_dir, 'bin', 'mono'))
+        self.env.set('system_mcs', os.path.join(system_mono_dir, 'bin', 'mcs'))
+
+        self.env.set('system_mono_version', backtick(
+            '%s --version' % self.env.system_mono)[0])
+
+        # config overrides for some programs to be functional while staged
+
+        self.env.set('GDK_PIXBUF_MODULE_FILE',
+                     '%{staged_prefix}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache')
+        self.env.set('GDK_PIXBUF_MODULEDIR',
+                     '%{staged_prefix}/lib/gdk-pixbuf-2.0/2.10.0/loaders')
+        self.env.set('PANGO_SYSCONFDIR', '%{staged_prefix}/etc')
+        self.env.set('PANGO_LIBDIR', '%{staged_prefix}/lib')
+        # self.env.set ('MONO_PATH', '%{staged_prefix}/lib/mono/4.0')
+        self.debug_info = ['gtk+', 'cairo',
+                           'pango', 'mono', 'llvm', 'libgdiplus']
+        self.cache_host = None
+
+    def setup_release(self):
+        self.mono_package = self.release_packages['mono']
+        self.mono_package.fetch()
+
+        verbose('Mono version: %s' % self.mono_package.version)
+        self.RELEASE_VERSION = self.mono_package.version
+        self.prefix = os.path.join(
+            self.MONO_ROOT, "Versions", self.RELEASE_VERSION)
+
+        if os.path.exists(self.prefix):
+            error('Prefix %s exists, and may interfere with the staged build. Please remove and try again.' % self.prefix)
+
+        self.calculate_updateid()
+        trace(self.package_info('MDK'))
+
+        self.dont_optimize = ['pixman']
+
+        for p in self.release_packages.values():
+            if p.name in self.dont_optimize:
+                continue
+            self.gcc_flags.extend(['-O2'])
+
+    # THIS IS THE MAIN METHOD FOR MAKING A PACKAGE
+    def package(self):
+        self.fix_gtksharp_configs()
+        self.verify_binaries()
+
+        working = self.setup_working_dir()
+        uninstall_script = os.path.join(working, "uninstallMono.sh")
+
+        # make the MDK
+        self.apply_blacklist(working, 'mdk_blacklist.sh')
+        self.make_updateinfo(working, self.MDK_GUID)
+        mdk_pkg = self.run_pkgbuild(working, "MDK")
+        title(mdk_pkg)
+        # self.make_dmg(mdk_dmg, title, mdk_pkg, uninstall_script)
+
+        shutil.rmtree(working)
+
+    def calculate_updateid(self):
+        # Create the updateid
+        pwd = os.getcwd()
+        git_bin = self.bockbuild.git_bin
+        trace("cur path is %s and git is %s" % (pwd, git_bin))
+        blame_rev_str = 'cd %s; %s blame configure.ac HEAD | grep AC_INIT | sed \'s/ .*//\' ' % (
+            self.mono_package.workspace, git_bin)
+        blame_rev = backtick(blame_rev_str)[0]
+        trace("Last commit to the version string %s" % (blame_rev))
+        version_number_str = 'cd %s; %s log %s..HEAD --oneline | wc -l | sed \'s/ //g\'' % (
+            self.mono_package.workspace, git_bin, blame_rev)
+        self.BUILD_NUMBER = backtick(version_number_str)[0]
+        trace("Calculating commit distance, %s" % (self.BUILD_NUMBER))
+        self.FULL_VERSION = self.RELEASE_VERSION + "." + self.BUILD_NUMBER
+        os.chdir(pwd)
+
+        parts = self.RELEASE_VERSION.split(".")
+        version_list = (parts + ["0"] * (3 - len(parts)))[:4]
+        for i in range(1, 3):
+            version_list[i] = version_list[i].zfill(2)
+            self.updateid = "".join(version_list)
+            self.updateid += self.BUILD_NUMBER.replace(
+                ".", "").zfill(9 - len(self.updateid))
+        trace(self.updateid)
+
+    # creates and returns the path to a working directory containing:
+    #   PKGROOT/ - this root will be bundled into the .pkg and extracted at /
+    #   uninstallMono.sh - copied onto the DMG
+    #   Info{_sdk}.plist - used by packagemaker to make the installer
+    #   resources/ - other resources used by packagemaker for the installer
+    def setup_working_dir(self):
+        def make_package_symlinks(root):
+            os.symlink(self.prefix, os.path.join(root, "Versions", "Current"))
+            currentlink = os.path.join(self.MONO_ROOT, "Versions", "Current")
+            links = [
+                ("bin", "Commands"),
+                ("include", "Headers"),
+                ("lib", "Libraries"),
+                ("", "Home"),
+                (os.path.join("lib", "libmono-2.0.dylib"), "Mono")
+            ]
+            for srcname, destname in links:
+                src = os.path.join(currentlink, srcname)
+                dest = os.path.join(root, destname)
+                # If the symlink exists, we remove it so we can create a fresh
+                # one
+                if os.path.exists(dest):
+                    os.unlink(dest)
+                os.symlink(src, dest)
+
+        tmpdir = tempfile.mkdtemp()
+        monoroot = os.path.join(tmpdir, "PKGROOT", self.MONO_ROOT[1:])
+        versions = os.path.join(monoroot, "Versions")
+        os.makedirs(versions)
+
+        print "Setting up temporary package directory:", tmpdir
+
+        # setup metadata
+        run_shell('rsync -aPq %s/* %s' % (self.packaging_dir, tmpdir), False)
+
+        packages_list = string.join(
+            [pkg.desc for pkg in self.release_packages.values()], "\\\n")
+        deps_list = 'bockbuild (rev. %s)\\\n' % self.bockbuild_rev + string.join(
+            [pkg.desc for pkg in self.toolchain_packages.values()], "\\\n")
+
+        parameter_map = {
+            '@@MONO_VERSION@@': self.RELEASE_VERSION,
+            '@@MONO_RELEASE@@': self.BUILD_NUMBER,
+            '@@MONO_VERSION_RELEASE@@': self.RELEASE_VERSION + '_' + self.BUILD_NUMBER,
+            '@@MONO_CSDK_GUID@@': self.MDK_GUID,
+            '@@MONO_VERSION_RELEASE_INT@@': self.updateid,
+            '@@PACKAGES@@': packages_list,
+            '@@DEP_PACKAGES@@': deps_list
+        }
+        for dirpath, d, files in os.walk(tmpdir):
+            for name in files:
+                if not name.startswith('.'):
+                    replace_in_file(os.path.join(dirpath, name), parameter_map)
+
+        make_package_symlinks(monoroot)
+
+        # copy to package root
+        run_shell('rsync -aPq "%s"/* "%s/%s"' %
+                  (self.package_root, versions, self.RELEASE_VERSION), False)
+
+        return tmpdir
+
+    def apply_blacklist(self, working_dir, blacklist_name):
+        print "Applying blacklist script:", blacklist_name
+        blacklist = os.path.join(self.packaging_dir, blacklist_name)
+        root = os.path.join(working_dir, "PKGROOT", self.prefix[1:])
+        run_shell('%s "%s" > /dev/null' % (blacklist, root), print_cmd=False)
+
+    def run_pkgbuild(self, working_dir, package_type):
+        print 'Running pkgbuild & productbuild...',
+        info = self.package_info(package_type)
+        output = os.path.join(self.self_dir, info["filename"])
+        identifier = "com.xamarin.mono-" + info["type"] + ".pkg"
+        resources_dir = os.path.join(working_dir, "resources")
+        distribution_xml = os.path.join(resources_dir, "distribution.xml")
+
+        old_cwd = os.getcwd()
+        os.chdir(working_dir)
+        pkgbuild = "/usr/bin/pkgbuild"
+        pkgbuild_cmd = ' '.join([pkgbuild,
+                                 "--identifier " + identifier,
+                                 "--root '%s/PKGROOT'" % working_dir,
+                                 "--version '%s'" % self.RELEASE_VERSION,
+                                 "--install-location '/'",
+                                 "--scripts '%s'" % resources_dir,
+                                 "--quiet",
+                                 os.path.join(working_dir, "mono.pkg")])
+
+        run_shell(pkgbuild_cmd)
+
+        productbuild = "/usr/bin/productbuild"
+        productbuild_cmd = ' '.join([productbuild,
+                                     "--resources %s" % resources_dir,
+                                     "--distribution %s" % distribution_xml,
+                                     "--package-path %s" % working_dir,
+                                     "--quiet",
+                                     output])
+
+        run_shell(productbuild_cmd)
+
+        assert_exists(output)
+        os.chdir(old_cwd)
+        print output
+        return output
+
+    def make_updateinfo(self, working_dir, guid):
+        updateinfo = os.path.join(
+            working_dir, "PKGROOT", self.prefix[1:], "updateinfo")
+        with open(updateinfo, "w") as updateinfo:
+            updateinfo.write(guid + ' ' + self.updateid + "\n")
+
+    def package_info(self, pkg_type):
+        arch = self.bockbuild.cmd_options.arch
+        arch_str = None
+        if  arch == "darwin-32":
+            arch_str = "x86"
+        elif arch == "darwin-64":
+            arch_str = "x64"
+        elif arch == "darwin-universal":
+            arch_str = "universal"
+        else:
+            error ("Unknown architecture")
+
+        if self.bockbuild.cmd_options.release_build:
+            info = (pkg_type, self.FULL_VERSION, arch_str)
+        else:
+            info = (pkg_type, '%s-%s' % (git_shortid(self.bockbuild,
+                                                     self.mono_package.workspace), self.FULL_VERSION), arch_str)
+
+        filename = "MonoFramework-%s-%s.macos10.xamarin.%s.pkg" % info
+        return {
+            "type": pkg_type,
+            "filename": filename
+        }
+
+    def fix_line(self, line, matcher):
+        def insert_install_root(matches):
+            root = self.prefix
+            captures = matches.groupdict()
+            return 'target="%s"' % os.path.join(root, "lib", captures["lib"])
+
+        if matcher(line):
+            pattern = r'target="(?P<lib>.+\.dylib)"'
+            result = re.sub(pattern, insert_install_root, line)
+            return result
+        else:
+            return line
+
+    def fix_dllmap(self, config, matcher):
+        handle, temp = tempfile.mkstemp()
+        with open(config) as c:
+            with open(temp, "w") as output:
+                for line in c:
+                    output.write(self.fix_line(line, matcher))
+        os.rename(temp, config)
+        os.system('chmod a+r %s' % config)
+
+    def fix_gtksharp_configs(self):
+        print 'Fixing GTK# configuration files...',
+        count = 0
+        libs = [
+            'atk-sharp',
+            'gdk-sharp',
+            'glade-sharp',
+            'glib-sharp',
+            'gtk-dotnet',
+            'gtk-sharp',
+            'pango-sharp'
+        ]
+        gac = os.path.join(self.package_root, "lib", "mono", "gac")
+        confs = [glob(os.path.join(gac, x, "*", "*.dll.config")) for x in libs]
+        for c in itertools.chain(*confs):
+            count = count + 1
+            self.fix_dllmap(c, lambda line: "dllmap" in line)
+        print count
+
+    def verify(self, f):
+        result = " ".join(backtick("otool -L " + f))
+        regex = os.path.join(self.MONO_ROOT, "Versions", r"(\d+\.\d+\.\d+)")
+
+        match = re.search(regex, result)
+        if match is None:
+            return
+        token = match.group(1)
+        trace(token)
+        if self.RELEASE_VERSION not in token:
+            raise Exception("%s references Mono %s\n%s" % (f, token, text))
+
+    def verify_binaries(self):
+        bindir = os.path.join(self.package_root, "bin")
+        for path, dirs, files in os.walk(bindir):
+            for name in files:
+                f = os.path.join(path, name)
+                file_type = backtick('file "%s"' % f)
+                if "Mach-O executable" in "".join(file_type):
+                    self.verify(f)
+
+    def shell(self):
+        envscript = '''#!/bin/sh
+        PROFNAME="%s"
+        INSTALLDIR="%s"
+        ROOT="%s"
+        export DYLD_FALLBACK_LIBRARY_PATH="$INSTALLDIR/lib:/lib:/usr/lib"
+        export ACLOCAL_PATH="$INSTALLDIR/share/aclocal"
+        export CONFIG_SITE="$INSTALLDIR/$PROFNAME-config.site"
+        export MONO_GAC_PREFIX="$INSTALLDIR"
+        export MONO_ADDINS_REGISTRY="$ROOT/addinreg"
+        export MONO_INSTALL_PREFIX="$INSTALLDIR"
+
+        export PS1="\[\e[1;3m\][$PROFNAME] \w @ "
+        bash -i
+        ''' % (self.profile_name, self.staged_prefix, self.root)
+
+        path = os.path.join(self.root, self.profile_name + '.sh')
+
+        with open(path, 'w') as f:
+            f.write(envscript)
+
+        os.chmod(path, os.stat(path).st_mode | stat.S_IEXEC)
+
+        subprocess.call(['bash', '-c', path])
+
+MonoReleaseProfile()
\ No newline at end of file
diff --git a/bockbuild/mac-sdk/sqlite.py b/bockbuild/mac-sdk/sqlite.py
new file mode 100644 (file)
index 0000000..f0f5082
--- /dev/null
@@ -0,0 +1,3 @@
+Package('sqlite-autoconf', '3090200', sources=[
+    'http://www.sqlite.org/2015/%{name}-%{version}.tar.gz'
+])
diff --git a/bockbuild/mac-sdk/xamarin-gtk-theme.py b/bockbuild/mac-sdk/xamarin-gtk-theme.py
new file mode 100644 (file)
index 0000000..34d3ae0
--- /dev/null
@@ -0,0 +1,20 @@
+class XamarinGtkThemePackage (Package):
+
+    def __init__(self):
+        Package.__init__(self, 'xamarin-gtk-theme',
+                         sources=[
+                             'git://github.com/mono/xamarin-gtk-theme.git'],
+                         revision='cc3fb66e56d494e968be3a529a0737a60e31c1f3')
+
+    def build(self):
+        try:
+            self.sh('./autogen.sh --prefix=%{staged_prefix}')
+        except:
+            pass
+        finally:
+            #self.sh ('intltoolize --force --copy --debug')
+            #self.sh ('./configure --prefix="%{package_prefix}"')
+            Package.build(self)
+
+
+XamarinGtkThemePackage()
diff --git a/bockbuild/mac-sdk/xsp.py b/bockbuild/mac-sdk/xsp.py
new file mode 100644 (file)
index 0000000..8180001
--- /dev/null
@@ -0,0 +1,23 @@
+class XspPackage (GitHubTarballPackage):
+
+    def __init__(self):
+        GitHubTarballPackage.__init__(self, 'mono', 'xsp', '4.4',
+                                      'c98e068f5647fb06ff2fbef7cd5f1b35417362b1',
+                                      configure='./autogen.sh --prefix="%{package_prefix}"')
+
+    def install(self):
+        # scoop up some mislocated files
+        misdir = '%s%s' % (self.stage_root, self.staged_profile)
+        unprotect_dir(self.stage_root)
+        Package.install(self)
+        if not os.path.exists(misdir):
+            for path in iterate_dir(self.stage_root):
+                print path
+            error('Could not find mislocated files')
+
+        self.sh('rsync -a --ignore-existing %s/* %s' %
+                (misdir, self.profile.staged_prefix))
+        self.sh('rm -rf %s/*' % misdir)
+
+
+XspPackage()
index c558be34ceb5f2a5c318018df69c516230ff2942..0aadc7379b354dcd01b97d8568ff4643a7668577 160000 (submodule)
@@ -1 +1 @@
-Subproject commit c558be34ceb5f2a5c318018df69c516230ff2942
+Subproject commit 0aadc7379b354dcd01b97d8568ff4643a7668577