[gtk-osx] Replace Gtk patches with new ones for 2.24.6.



commit 6c455cb011c29784c82335031deea78cf7aec52b
Author: John Ralls <jralls ceridwen us>
Date:   Mon Sep 26 12:22:34 2011 -0700

    Replace Gtk patches with new ones for 2.24.6.
    
    
    Note that most of these are already applied in Git, but the time immediately around gtk-2.24.6's release was very busy for the quartz maintainers and a bunch of important changes got committed afterwards; we want those changes in applications, so here are the patches, some of which supersede the older patches which are removed.

 ...f1345-Fix-refresh-of-static-autorelease_p.patch |   42 +
 ...Gtk-build-fails-because-of-objective-c-el.patch |   56 +
 ...mplement-relocatable-paths-for-quartz-si.patch} |   67 +-
 ...82-GtkSelection-implementation-for-quartz.patch |  923 ++++++
 ...Write-to-released-memory-in-gtkdnd-quartz.patch |   52 +
 ...722-Drag-and-Drop-sometimes-stops-working.patch |  274 ++
 ...767-Drag-and-Drop-NSEvent-capture-is-racy.patch |   78 +
 ...GtkDragSourceOwner-pasteboardChangedOwner.patch |   39 +
 ...009-Implement-recent-items-in-Filechooser.patch |  880 ++++++
 ...ead-accents-keys-don-t-work-in-GTK-appli.patch} |   37 +-
 ...filechooser-Deal-with-corrupted-.gtk-book.patch |   57 +
 ...Option-MOD1-and-Command-SUPER-modifiers-a.patch |  835 ++++++
 ...406-Abstract-what-triggers-a-context-menu.patch |  329 +++
 ...gdk_quartz_draw_opaque_stippled_pattern-c.patch |   25 +
 ...gtkfilechooser-crashes-when-adding-favori.patch |   59 +
 patches/gdk-quartz-cursor.patch                    |   48 -
 patches/gdk-quartz-input-window.patch              |   35 -
 patches/gdk-quartz-norects.patch                   |  227 --
 patches/gdk-quartz-version.patch                   |   58 -
 patches/gdkeventloop.patch                         |   22 -
 patches/gtk-borderless.patch                       |   62 -
 patches/gtk-introspection.patch                    | 2967 --------------------
 patches/gtk-keyhash.patch                          |   41 -
 patches/gtk2-lion-resize.patch                     |  117 -
 patches/gtkcups.patch                              |   45 -
 patches/gtkdndmemory.patch                         |   90 -
 patches/gtkselection.patch                         | 1177 --------
 patches/gtkselection_deref.patch                   |   22 -
 28 files changed, 3714 insertions(+), 4950 deletions(-)
---
diff --git a/patches/0001-Backport-acf1345-Fix-refresh-of-static-autorelease_p.patch b/patches/0001-Backport-acf1345-Fix-refresh-of-static-autorelease_p.patch
new file mode 100644
index 0000000..2fd1d04
--- /dev/null
+++ b/patches/0001-Backport-acf1345-Fix-refresh-of-static-autorelease_p.patch
@@ -0,0 +1,42 @@
+From e1b9400f6ebadd7e4d137ec7b416e762f44148da Mon Sep 17 00:00:00 2001
+From: John Ralls <jralls ceridwen us>
+Date: Mon, 3 Jan 2011 11:56:20 -0800
+Subject: [PATCH 01/15] (Backport acf1345) Fix refresh of static
+ autorelease_pool so that it doesn't happen in
+ gtk-nested loops.
+
+---
+ gdk/quartz/gdkeventloop-quartz.c |   17 ++++++++---------
+ 1 files changed, 8 insertions(+), 9 deletions(-)
+
+diff --git a/gdk/quartz/gdkeventloop-quartz.c b/gdk/quartz/gdkeventloop-quartz.c
+index f11d4d8..568d4c8 100644
+--- a/gdk/quartz/gdkeventloop-quartz.c
++++ b/gdk/quartz/gdkeventloop-quartz.c
+@@ -632,15 +632,14 @@ gdk_event_check (GSource *source)
+ 
+   GDK_THREADS_ENTER ();
+ 
+-  /* XXX: This check isn't right it won't handle a recursive GLib main
+-   * loop run within an outer CFRunLoop run. Such loops will pile up
+-   * memory. Fixing this requires setting a flag *only* when we call
+-   * g_main_context_check() from within the run loop iteraton code,
+-   * and also maintaining our own stack of run loops... allocating and
+-   * releasing NSAutoReleasePools not properly nested with CFRunLoop
+-   * runs seems to cause problems.
+-   */
+-  if (current_loop_level == 0)
++/* Refresh the autorelease pool if we're at the base CFRunLoop level
++  * (indicated by current_loop_level) and the base g_main_loop level
++  * (indicated by g_main_depth()). Messing with the autorelease pool at
++  * any level of nesting can cause access to deallocated memory because
++  * autorelease_pool is static and releasing a pool will cause all pools
++  * allocated inside of it to be released as well.
++  */
++    if (current_loop_level == 0 && g_main_depth() == 0)
+     {
+       if (autorelease_pool)
+ 	[autorelease_pool release];
+-- 
+1.7.6.3.dirty
+
diff --git a/patches/0002-Bug-628396-Gtk-build-fails-because-of-objective-c-el.patch b/patches/0002-Bug-628396-Gtk-build-fails-because-of-objective-c-el.patch
new file mode 100644
index 0000000..940f49e
--- /dev/null
+++ b/patches/0002-Bug-628396-Gtk-build-fails-because-of-objective-c-el.patch
@@ -0,0 +1,56 @@
+From c595a1c92bf29f34f835fcd365ba7cf54a990700 Mon Sep 17 00:00:00 2001
+From: John Ralls <jralls ceridwen us>
+Date: Sun, 26 Dec 2010 15:02:36 -0800
+Subject: [PATCH 02/15] Bug 628396: Gtk build fails because of objective-c
+ elements
+
+---
+ gtk/Makefile.am |    7 ++-----
+ 1 files changed, 2 insertions(+), 5 deletions(-)
+
+diff --git a/gtk/Makefile.am b/gtk/Makefile.am
+index 6050c76..78f4684 100644
+--- a/gtk/Makefile.am
++++ b/gtk/Makefile.am
+@@ -53,7 +53,6 @@ INCLUDES =						\
+ 	-DGTK_PRINT_BACKEND_ENABLE_UNSUPPORTED		\
+ 	$(GTK_DEBUG_FLAGS)				\
+ 	$(GTK_DEP_CFLAGS)				\
+-	$(gtk_clipboard_dnd_c_sources_CFLAGS)		\
+ 	$(INCLUDED_IMMODULE_DEFINE)
+ 
+ gtarget=$(gdktarget)
+@@ -740,7 +739,7 @@ gtk_use_stub_c_sources = \
+ 	gtkplug-stub.c   \
+ 	gtksocket-stub.c \
+ 	gtkmountoperation-stub.c
+-gtk_all_c_sources += $(gtk_use_x11_c_sources) $(gtk_use_win32_c_sources) $(gtk_use_quartz_c_sources) $(gtk_use_stub_c_sources)
++gtk_all_c_sources += $(gtk_use_x11_c_sources) $(gtk_use_win32_c_source) $(gtk_use_stub_c_sources)
+ if USE_X11
+ gtk_private_h_sources += gtkxembed.h gtktrayicon.h xembed.h
+ gtk_c_sources += $(gtk_use_x11_c_sources)
+@@ -750,9 +749,9 @@ gtk_private_h_sources += gtkwin32embed.h gtkwin32embedwidget.h
+ gtk_c_sources += $(gtk_use_win32_c_sources)
+ else
+ if USE_QUARTZ
++libgtk_quartz_2_0_la_CFLAGS = "-xobjective-c"
+ gtk_private_h_sources += gtksearchenginequartz.h
+ gtk_c_sources += $(gtk_use_quartz_c_sources)
+-gtk_use_quartz_c_sources_CFLAGS = "-xobjective-c"
+ else
+ gtk_c_sources += $(gtk_use_stub_c_sources)
+ endif
+@@ -762,10 +761,8 @@ endif
+ if USE_QUARTZ
+ gtk_clipboard_dnd_c_sources = gtkclipboard-quartz.c gtkdnd-quartz.c gtkquartz.c
+ gtk_clipboard_dnd_h_sources = gtkquartz.h
+-gtk_clipboard_dnd_c_sources_CFLAGS = "-xobjective-c"
+ else
+ gtk_clipboard_dnd_c_sources = gtkclipboard.c gtkdnd.c
+-gtk_clipboard_dnd_c_sources_CFLAGS =
+ endif
+ EXTRA_DIST += gtkquartz.h
+ 
+-- 
+1.7.6.3.dirty
+
diff --git a/patches/gtk-relocation.patch b/patches/0003-Bug-658772-Implement-relocatable-paths-for-quartz-si.patch
similarity index 59%
rename from patches/gtk-relocation.patch
rename to patches/0003-Bug-658772-Implement-relocatable-paths-for-quartz-si.patch
index 50f4ac2..08c718c 100644
--- a/patches/gtk-relocation.patch
+++ b/patches/0003-Bug-658772-Implement-relocatable-paths-for-quartz-si.patch
@@ -1,37 +1,39 @@
+From 7e0d64a32bc9d0afa855e717d5b1eacc305b3458 Mon Sep 17 00:00:00 2001
+From: John Ralls <jralls ceridwen us>
+Date: Mon, 13 Dec 2010 15:01:02 -0800
+Subject: [PATCH 03/15] Bug 658772: Implement relocatable paths for quartz,
+ similar to those in Win32.
+
+The motivation was a complaint in the Gtk OSX forum that GTK didn't seem to be able to find its translations when bundled.
+---
+ gtk/gtkprivate.h |    4 +-
+ gtk/gtkquartz.c  |   68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 70 insertions(+), 2 deletions(-)
+
 diff --git a/gtk/gtkprivate.h b/gtk/gtkprivate.h
-index 7ba5a5d..b3fcf40 100644
+index 7ba5a5d..3933dc5 100644
 --- a/gtk/gtkprivate.h
 +++ b/gtk/gtkprivate.h
-@@ -95,6 +95,27 @@ const gchar *_gtk_get_data_prefix ();
+@@ -74,7 +74,7 @@ typedef enum
+ #define GTK_PRIVATE_SET_FLAG(wid,flag)    G_STMT_START{ (GTK_PRIVATE_FLAGS (wid) |= (PRIVATE_ ## flag)); }G_STMT_END
+ #define GTK_PRIVATE_UNSET_FLAG(wid,flag)  G_STMT_START{ (GTK_PRIVATE_FLAGS (wid) &= ~(PRIVATE_ ## flag)); }G_STMT_END
  
- #endif /* G_OS_WIN32 */
+-#ifdef G_OS_WIN32
++#if defined G_OS_WIN32 || defined GDK_WINDOWING_QUARTZ
+ 
+ const gchar *_gtk_get_datadir ();
+ const gchar *_gtk_get_libdir ();
+@@ -93,7 +93,7 @@ const gchar *_gtk_get_data_prefix ();
+ #undef GTK_DATA_PREFIX
+ #define GTK_DATA_PREFIX _gtk_get_data_prefix ()
+ 
+-#endif /* G_OS_WIN32 */
++#endif /* G_OS_WIN32 || GDK_WINDOWING_QUARTZ */
  
-+/* Likewise for quartz */
-+#ifdef  GDK_WINDOWING_QUARTZ
-+
-+const gchar *_gtk_quartz_get_datadir ();
-+const gchar *_gtk_quartz_get_libdir ();
-+const gchar *_gtk_quartz_get_sysconfdir ();
-+const gchar *_gtk_quartz_get_localedir ();
-+const gchar *_gtk_quartz_get_data_prefix ();
-+
-+#undef GTK_DATADIR
-+#define GTK_DATADIR _gtk_quartz_get_datadir ()
-+#undef GTK_LIBDIR
-+#define GTK_LIBDIR _gtk_quartz_get_libdir ()
-+#undef GTK_LOCALEDIR
-+#define GTK_LOCALEDIR _gtk_quartz_get_localedir ()
-+#undef GTK_SYSCONFDIR
-+#define GTK_SYSCONFDIR _gtk_quartz_get_sysconfdir ()
-+#undef GTK_DATA_PREFIX
-+#define GTK_DATA_PREFIX _gtk_quartz_get_data_prefix ()
-+
-+#endif /*  GDK_WINDOWING_QUARTZ */
  gboolean _gtk_fnmatch (const char *pattern,
  		       const char *string,
- 		       gboolean    no_leading_period);
 diff --git a/gtk/gtkquartz.c b/gtk/gtkquartz.c
-index 265d9ff..80b9e87 100644
+index 265d9ff..5b54104 100644
 --- a/gtk/gtkquartz.c
 +++ b/gtk/gtkquartz.c
 @@ -322,3 +322,71 @@ _gtk_quartz_set_selection_data_for_pasteboard (NSPasteboard     *pasteboard,
@@ -64,7 +66,7 @@ index 265d9ff..80b9e87 100644
 +}
 +
 +const gchar *
-+_gtk_quartz_get_datadir (void)
++_gtk_get_datadir (void)
 +{
 +  gchar *resource_dir = get_bundle_path();
 +  gchar *retval = g_build_filename(resource_dir, "share", NULL);
@@ -73,7 +75,7 @@ index 265d9ff..80b9e87 100644
 +}
 +
 +const gchar *
-+_gtk_quartz_get_libdir (void)
++_gtk_get_libdir (void)
 +{
 +  gchar *resource_dir = get_bundle_path();
 +  gchar *retval = g_build_filename(resource_dir, "lib", NULL);
@@ -82,7 +84,7 @@ index 265d9ff..80b9e87 100644
 +}
 +
 +const gchar *
-+_gtk_quartz_get_localedir (void)
++_gtk_get_localedir (void)
 +{
 +
 +  gchar *resource_dir = get_bundle_path();
@@ -92,7 +94,7 @@ index 265d9ff..80b9e87 100644
 +}
 +
 +const gchar *
-+_gtk_quartz_get_sysconfdir (void)
++_gtk_get_sysconfdir (void)
 +{
 +  gchar *resource_dir = get_bundle_path();
 +  gchar *retval = g_build_filename(resource_dir, "etc", NULL);
@@ -101,8 +103,11 @@ index 265d9ff..80b9e87 100644
 +}
 +
 +const gchar *
-+_gtk_quartz_get_data_prefix (void)
++_gtk_get_data_prefix (void)
 +{
 +  return get_bundle_path();
 +}
 +
+-- 
+1.7.6.3.dirty
+
diff --git a/patches/0004-Bug-571582-GtkSelection-implementation-for-quartz.patch b/patches/0004-Bug-571582-GtkSelection-implementation-for-quartz.patch
new file mode 100644
index 0000000..0d8dbe9
--- /dev/null
+++ b/patches/0004-Bug-571582-GtkSelection-implementation-for-quartz.patch
@@ -0,0 +1,923 @@
+From 6118cdb88497c5531e64886d51a96fd24a895c61 Mon Sep 17 00:00:00 2001
+From: John Ralls <jralls ceridwen us>
+Date: Sun, 26 Dec 2010 13:48:47 -0800
+Subject: [PATCH 04/15] Bug 571582: GtkSelection implementation for quartz.
+
+---
+ gdk/quartz/gdkselection-quartz.c |   36 ++-
+ gtk/Makefile.am                  |   10 +-
+ gtk/gtkquartz.c                  |    1 +
+ gtk/gtkselection-quartz.c        |  670 ++++++++++++++++++++++++++++++++++++++
+ gtk/gtkselection.c               |   14 +-
+ 5 files changed, 711 insertions(+), 20 deletions(-)
+ create mode 100644 gtk/gtkselection-quartz.c
+
+diff --git a/gdk/quartz/gdkselection-quartz.c b/gdk/quartz/gdkselection-quartz.c
+index c327eb9..a51f567 100644
+--- a/gdk/quartz/gdkselection-quartz.c
++++ b/gdk/quartz/gdkselection-quartz.c
+@@ -32,7 +32,8 @@ gdk_selection_owner_set_for_display (GdkDisplay *display,
+ 				     guint32     time,
+ 				     gint        send_event)
+ {
+-  /* FIXME: Implement */
++  g_print ("Not a valid interface on Quartz. Use GtkSelection.\n");
++  g_return_val_if_reached(TRUE);
+   return TRUE;
+ }
+ 
+@@ -40,7 +41,7 @@ GdkWindow*
+ gdk_selection_owner_get_for_display (GdkDisplay *display,
+ 				     GdkAtom     selection)
+ {
+-  /* FIXME: Implement */
++ /* Quartz doesn't have an X-selection, so it doesn't have a gdk_selection. */
+   return NULL;
+ }
+ 
+@@ -50,7 +51,9 @@ gdk_selection_convert (GdkWindow *requestor,
+ 		       GdkAtom    target,
+ 		       guint32    time)
+ {
+-  /* FIXME: Implement */
++  g_print ("Not a valid interface on Quartz. Use GtkSelection.\n");
++  g_return_if_reached();
++
+ }
+ 
+ gint
+@@ -59,7 +62,8 @@ gdk_selection_property_get (GdkWindow  *requestor,
+ 			    GdkAtom    *ret_type,
+ 			    gint       *ret_format)
+ {
+-  /* FIXME: Implement */
++  g_print ("Quartz windows do not support properties.\n");
++  g_return_val_if_reached(-1);
+   return 0;
+ }
+ 
+@@ -71,7 +75,8 @@ gdk_selection_send_notify_for_display (GdkDisplay *display,
+ 				       GdkAtom     property,
+ 				       guint32     time)
+ {
+-  /* FIXME: Implement */
++  g_print ("Not a valid interface on Quartz. Use GtkSelection.\n");
++  g_return_if_reached();
+ }
+ 
+ gint
+@@ -82,8 +87,9 @@ gdk_text_property_to_text_list_for_display (GdkDisplay   *display,
+ 					    gint          length,
+ 					    gchar      ***list)
+ {
+-  /* FIXME: Implement */
+-  return 0;
++  /* text and utf8 are equivalent on OSX */
++  return gdk_text_property_to_utf8_list_for_display (display, encoding, format,
++						     text, length, list);
+ }
+ 
+ gint
+@@ -94,20 +100,21 @@ gdk_string_to_compound_text_for_display (GdkDisplay  *display,
+ 					 guchar     **ctext,
+ 					 gint        *length)
+ {
+-  /* FIXME: Implement */
++  *ctext = (guchar*)g_strdup (str);
++  *length = strlen (str);
+   return 0;
+ }
+ 
+ void gdk_free_compound_text (guchar *ctext)
+ {
+-  /* FIXME: Implement */
++  g_free (ctext);
+ }
+ 
+ gchar *
+ gdk_utf8_to_string_target (const gchar *str)
+ {
+-  /* FIXME: Implement */
+-  return NULL;
++  /* UTF8 is the standard string on OSX */
++  return g_strdup (str);
+ }
+ 
+ gboolean
+@@ -118,8 +125,11 @@ gdk_utf8_to_compound_text_for_display (GdkDisplay  *display,
+ 				       guchar     **ctext,
+ 				       gint        *length)
+ {
+-  /* FIXME: Implement */
+-  return 0;
++  /* We don't use compound text on OSX, just stuff a copy of the string*/
++
++  *ctext = (guchar*)g_strdup (str);
++  *length = strlen (str);
++  return TRUE;
+ }
+ 
+ void
+diff --git a/gtk/Makefile.am b/gtk/Makefile.am
+index 78f4684..4794835 100644
+--- a/gtk/Makefile.am
++++ b/gtk/Makefile.am
+@@ -560,7 +560,6 @@ gtk_base_c_sources =            \
+ 	gtkscalebutton.c	\
+ 	gtkscrollbar.c		\
+ 	gtkscrolledwindow.c	\
+-	gtkselection.c		\
+ 	gtkseparator.c		\
+ 	gtkseparatormenuitem.c	\
+ 	gtkseparatortoolitem.c	\
+@@ -759,10 +758,15 @@ endif
+ endif
+ 
+ if USE_QUARTZ
+-gtk_clipboard_dnd_c_sources = gtkclipboard-quartz.c gtkdnd-quartz.c gtkquartz.c
++gtk_clipboard_dnd_c_sources = \
++	gtkselection.c \
++	gtkselection-quartz.c \
++	gtkclipboard-quartz.c \
++	gtkdnd-quartz.c \
++	gtkquartz.c
+ gtk_clipboard_dnd_h_sources = gtkquartz.h
+ else
+-gtk_clipboard_dnd_c_sources = gtkclipboard.c gtkdnd.c
++gtk_clipboard_dnd_c_sources = gtkselection.c gtkclipboard.c gtkdnd.c
+ endif
+ EXTRA_DIST += gtkquartz.h
+ 
+diff --git a/gtk/gtkquartz.c b/gtk/gtkquartz.c
+index 5b54104..8ffeb0b 100644
+--- a/gtk/gtkquartz.c
++++ b/gtk/gtkquartz.c
+@@ -271,6 +271,7 @@ _gtk_quartz_set_selection_data_for_pasteboard (NSPasteboard     *pasteboard,
+ 
+   type = target_to_pasteboard_type (target);
+   g_free (target);
++  g_return_if_fail (data != NULL);
+ 
+   if ([type isEqualTo:NSStringPboardType]) 
+     [pasteboard setString:[NSString stringWithUTF8String:(const char *)data]
+diff --git a/gtk/gtkselection-quartz.c b/gtk/gtkselection-quartz.c
+new file mode 100644
+index 0000000..1ce7d55
+--- /dev/null
++++ b/gtk/gtkselection-quartz.c
+@@ -0,0 +1,670 @@
++/* GTK - The GIMP Toolkit
++ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++/* This file implements most of the work of the ICCCM selection protocol.
++ * The code was written after an intensive study of the equivalent part
++ * of John Ousterhout's Tk toolkit, and does many things in much the 
++ * same way.
++ *
++ * The one thing in the ICCCM that isn't fully supported here (or in Tk)
++ * is side effects targets. For these to be handled properly, MULTIPLE
++ * targets need to be done in the order specified. This cannot be
++ * guaranteed with the way we do things, since if we are doing INCR
++ * transfers, the order will depend on the timing of the requestor.
++ *
++ * By Owen Taylor <owt1 cornell edu>	      8/16/97
++ */
++
++/* Terminology note: when not otherwise specified, the term "incr" below
++ * refers to the _sending_ part of the INCR protocol. The receiving
++ * portion is referred to just as "retrieval". (Terminology borrowed
++ * from Tk, because there is no good opposite to "retrieval" in English.
++ * "send" can't be made into a noun gracefully and we're already using
++ * "emission" for something else ....)
++ */
++
++/* The MOTIF entry widget seems to ask for the TARGETS target, then
++   (regardless of the reply) ask for the TEXT target. It's slightly
++   possible though that it somehow thinks we are responding negatively
++   to the TARGETS request, though I don't really think so ... */
++
++/*
++ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
++ * file for a list of people on the GTK+ Team.  See the ChangeLog
++ * files for a list of changes.  These files are distributed with
++ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
++ */
++
++#include "config.h"
++#include <stdarg.h>
++#include <string.h>
++#include "gdk.h"
++
++#include "gtkmain.h"
++#include "gtkselection.h"
++#include "gtktextbufferrichtext.h"
++#include "gtkintl.h"
++#include "gdk-pixbuf/gdk-pixbuf.h"
++#include "gtkclipboard.h"
++
++#import <Cocoa/Cocoa.h>
++#include "gtkalias.h"
++
++#undef DEBUG_SELECTION
++/*
++ * DON'T USE THIS INTERFACE: USE GTKCLIPBOARD INSTEAD!
++ *
++ * This is the Quartz version of gtkselection. Unlike the other
++ * versions, it was written in 2010, after most code was rewritten to
++ * use GtkClipboard. Quartz, unlike X11, is not a remote-capable
++ * display system, so most of ICCCM is pointless. This implementation
++ * can therefore be much simpler than the X11 implementation. Text is
++ * a lot simpler, too. It's UTF8. No compound text, no legacy
++ * charsets.  There's also only one display, so instead of passing it
++ * around, we'll generally just use gdk_display_get_default() when we
++ * need it.
++ *
++ * There are two constraints: The existing code in various GtkWidgets
++ * which uses GDK_SELECTION_CLIPBOARD (which gtkclipboard-quartz sets
++ * to generalPasteboard) for <ctrl>c copies and GDK_SELECTION_PRIMARY
++ * (for which gtkclipboard-quartz creates a separate pasteboard) for
++ * X-style selection transfers, and Apple's X11 Quartz implementation
++ * which by default puts both on the generalPasteboard. We need to
++ * operate with both.
++ *
++ * IMPORTANT: There is no X11 magic in quartz. If you insist on using
++ * this interface (and you really shouldn't), your MUST connect to
++ * selection-get, selection-received, and selection-clear-event for
++ * your widget.
++ */
++
++/* Maximum size of a sent chunk, in bytes. Also the default size of
++   our buffers */
++
++
++#define IDLE_ABORT_TIME 30
++
++enum {
++  INCR,
++  MULTIPLE,
++  TARGETS,
++  TIMESTAMP,
++  SAVE_TARGETS,
++  LAST_ATOM
++};
++
++typedef struct _GtkSelectionInfo GtkSelectionInfo;
++
++struct _GtkSelectionInfo
++{
++  GdkAtom	 selection;
++  GtkWidget	*owner;	/* widget that owns selection */
++  guint32	 time;		/* time used to acquire selection */
++};
++
++
++/* Local Functions */
++static void gtk_selection_get_cb            (GtkClipboard     *clipboard,
++					     GtkSelectionData *data,
++					     guint             info,
++					     gpointer          widget);
++static void gtk_selection_clear_cb          (GtkClipboard     *clipboard,
++					     gpointer 	       widget);
++static void gtk_selection_default_handler   (GtkWidget        *widget,
++					     GtkSelectionData *data);
++static int  gtk_selection_bytes_per_item    (gint              format);
++static GtkSelectionInfo *gtk_selection_info_get (GdkAtom selection);
++static void gtk_selection_info_remove		(GdkAtom selection,
++						 GtkWidget *owner);
++static void gtk_selection_info_append 		(GdkAtom selection, 
++						 GtkWidget *owner, 
++						 guint32 time);
++static void gtk_selection_info_clear		(GtkWidget *owner);
++static GtkTargetList *gtk_selection_target_list_get (GtkWidget    *widget,
++						     GdkAtom       selection);
++static void gtk_selection_target_list_remove 	    (GtkWidget *widget);
++
++/* Local Data */
++static gint initialize = TRUE;
++static GList *current_selections = NULL;
++
++static GdkAtom gtk_selection_atoms[LAST_ATOM];
++static const char gtk_selection_handler_key[] = "gtk-selection-handlers";
++
++static GtkTargetEntry default_target = {"UTF8_STRING", 0, 1};
++
++/**
++ * gtk_selection_owner_set_for_display:
++ * @display: the #Gdkdisplay where the selection is set
++ * @widget: (allow-none): new selection owner (a #GdkWidget), or %NULL.
++ * @selection: an interned atom representing the selection to claim.
++ * @time_: timestamp with which to claim the selection
++ *
++ * Claim ownership of a given selection for a particular widget, or,
++ * if @widget is %NULL, release ownership of the selection.
++ *
++ * Return value: TRUE if the operation succeeded 
++ * 
++ * Since: 2.2
++ */
++gboolean
++gtk_selection_owner_set_for_display (GdkDisplay   *display,
++				     GtkWidget    *widget,
++				     GdkAtom       selection,
++				     guint32       time)
++{
++  GObject *old_owner;
++  GtkClipboard *clip = gtk_clipboard_get (selection);
++  GtkTargetEntry *targets = &default_target;
++  gint num_targets = 1;
++  GtkTargetList *tlist;
++
++  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
++  g_return_val_if_fail (selection != GDK_NONE, FALSE);
++
++  old_owner = gtk_clipboard_get_owner (clip);
++  if (old_owner)
++    gtk_selection_info_remove (selection, GTK_WIDGET(old_owner));
++
++  if (widget == NULL) 
++    return TRUE;
++
++  g_return_val_if_fail (gtk_widget_get_display (widget) == display, FALSE);
++  
++  if ((tlist = gtk_selection_target_list_get (widget, selection)) != NULL) 
++      targets = gtk_target_table_new_from_list (tlist, &num_targets);
++
++  if (gtk_clipboard_set_with_owner (clip, targets, num_targets,
++				    gtk_selection_get_cb, 
++				    gtk_selection_clear_cb, 
++				    G_OBJECT (widget)))
++    {
++      gtk_selection_info_append (selection, widget, GDK_CURRENT_TIME);
++      return TRUE;
++    }
++  return FALSE;
++}
++
++
++typedef struct _GtkSelectionTargetList GtkSelectionTargetList;
++
++struct _GtkSelectionTargetList {
++  GdkAtom selection;
++  GtkTargetList *list;
++};
++
++/**
++ * gtk_selection_remove_all:
++ * @widget: a #GtkWidget 
++ * 
++ * Removes all handlers and unsets ownership of all 
++ * selections for a widget. Called when widget is being
++ * destroyed. This function will not generally be
++ * called by applications.
++ **/
++void
++gtk_selection_remove_all (GtkWidget *widget)
++{
++  g_return_if_fail(widget == NULL || GTK_IS_WIDGET(widget));
++  gtk_selection_info_clear (widget);
++  /* Remove all selection lists */
++  gtk_selection_target_list_remove (widget);
++}
++
++
++/**
++ * gtk_selection_convert:
++ * @widget: The widget which acts as requestor
++ * @selection: Which selection to get
++ * @target: Form of information desired (e.g., STRING)
++ * @time_: Time of request (usually of triggering event)
++       In emergency, you could use #GDK_CURRENT_TIME
++ * 
++ * Requests the contents of a selection. When received, 
++ * a "selection-received" signal will be generated.
++ * 
++ * Return value: %TRUE if requested succeeded. %FALSE if we could not process
++ *          request. (e.g., there was already a request in process for
++ *          this widget).
++ **/
++gboolean
++gtk_selection_convert (GtkWidget *widget, 
++		       GdkAtom	  selection, 
++		       GdkAtom	  target,
++		       guint32	  time_)
++{
++  GtkClipboard *clip = gtk_clipboard_get (selection);
++  GtkSelectionData *data;
++  
++  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
++  g_return_val_if_fail (selection != GDK_NONE, FALSE);
++  
++  data = gtk_clipboard_wait_for_contents (clip, target);
++  if (data == NULL)
++    return FALSE;
++
++  g_signal_emit_by_name (widget, "selection-received", data, time);
++	  
++  return TRUE;
++}
++
++
++/**
++ * gtk_selection_clear:
++ * @widget: a #GtkWidget
++ * @event: the event
++ * 
++ * The default handler for the #GtkWidget::selection-clear-event
++ * signal. 
++ * 
++ * Return value: %TRUE if the event was handled, otherwise false
++ **/
++gboolean
++gtk_selection_clear (GtkWidget         *widget,
++		     GdkEventSelection *event)
++{
++  gtk_selection_clear_targets (widget, event->selection);
++  return FALSE;
++}
++
++
++/*************************************************************
++ * _gtk_selection_request:
++ *     Handler for "selection_request_event" 
++ *   arguments:
++ *     widget:
++ *     event:
++ *   results:
++ *************************************************************/
++
++gboolean
++_gtk_selection_request (GtkWidget *widget,
++			GdkEventSelection *event)
++{
++  g_print ("Selection Request Events should not occur in quartz\n");  
++  return TRUE;
++}
++
++/*************************************************************
++ * _gtk_selection_incr_event:
++ *     Called whenever an PropertyNotify event occurs for an 
++ *     GdkWindow with user_data == NULL. These will be notifications
++ *     that a window we are sending the selection to via the
++ *     INCR protocol has deleted a property and is ready for
++ *     more data.
++ *
++ *   arguments:
++ *     window:	the requestor window
++ *     event:	the property event structure
++ *
++ *   results:
++ *************************************************************/
++
++gboolean
++_gtk_selection_incr_event (GdkWindow	   *window,
++			   GdkEventProperty *event)
++{
++  g_print ("Selection_INCR_Events should not occur in quartz\n");  
++  return TRUE;
++}
++
++/*************************************************************
++ * _gtk_selection_notify:
++ *     Handler for "selection-notify-event" signals on windows
++ *     where a retrieval is currently in process. The selection
++ *     owner has responded to our conversion request.
++ *   arguments:
++ *     widget:		Widget getting signal
++ *     event:		Selection event structure
++ *     info:		Information about this retrieval
++ *   results:
++ *     was event handled?
++ *************************************************************/
++
++gboolean
++_gtk_selection_notify (GtkWidget	       *widget,
++		       GdkEventSelection *event)
++{
++  g_print ("Selection_Notifications should not occur in quartz\n");  
++  
++  return TRUE;
++}
++
++/*************************************************************
++ * _gtk_selection_property_notify:
++ *     Handler for "property-notify-event" signals on windows
++ *     where a retrieval is currently in process. The selection
++ *     owner has added more data.
++ *   arguments:
++ *     widget:		Widget getting signal
++ *     event:		Property event structure
++ *     info:		Information about this retrieval
++ *   results:
++ *     was event handled?
++ *************************************************************/
++
++gboolean
++_gtk_selection_property_notify (GtkWidget	*widget,
++				GdkEventProperty *event)
++{
++  g_print ("Selection_Property_Notifications should not occur in quartz\n");  
++  return TRUE;
++}
++
++
++/*************************************************************
++ * gtk_selection_get_cb()
++ * @clipboard: The clipboard requesting the data
++ * @data: Pass to selection-get signal; handlers should put requested
++ * data in the structure pointed to.
++ * @info: DND uses this on Windows and X11. It can be ignored for
++ * normal selection use.
++ * @owner: The window to which the information request is sent; it's
++ * the owner set with gtk_selection_owner_set_for_display.
++ *
++ * Emits a signal to the owner window to fill in the provided data structure.
++ *************************************************************/
++/* GtkClipboardGetFunc */
++static void
++gtk_selection_get_cb (GtkClipboard* clipboard,
++		      GtkSelectionData *data,
++		      guint info,
++		      gpointer owner)
++{
++  GtkTargetList *target_list;
++  GtkWidget *widget = GTK_WIDGET (owner);
++  
++
++  g_return_if_fail (widget != NULL);
++
++  target_list = gtk_selection_target_list_get (widget, data->selection);
++
++  if ( data->target == gtk_selection_atoms[TIMESTAMP] ||
++       data->target == gtk_selection_atoms[TARGETS] ||
++       data->target == gtk_selection_atoms[SAVE_TARGETS])
++    {
++      gtk_selection_default_handler (widget, data);
++      return;
++    }
++  if (target_list &&
++      gtk_target_list_find (target_list, data->target, &info))
++    {
++      g_signal_emit_by_name (widget,
++			     "selection-get",
++			     data,
++			     info, time);
++    }
++}
++
++static void
++gtk_selection_clear_cb (GtkClipboard* clipboard,
++			gpointer owner)
++{
++  GtkWidget *widget = GTK_WIDGET (owner);
++  GdkEventSelection event;
++  event.type = GDK_SELECTION_CLEAR;
++  event.selection = GDK_SELECTION_PRIMARY;
++  event.window = gtk_widget_get_window(widget);
++  g_signal_emit_by_name (widget,
++			 "selection-clear-event",
++			 &event,
++			 NULL);
++}
++
++/*************************************************************
++ * gtk_selection_default_handler:
++ *     Handles some default targets that exist for any widget
++ *     If it can't fit results into buffer, returns -1. This
++ *     won't happen in any conceivable case, since it would
++ *     require 1000 selection targets!
++ *
++ *   arguments:
++ *     widget:	    selection owner
++ *     data:	    selection data [INOUT]
++ *
++ *************************************************************/
++
++static void
++gtk_selection_default_handler (GtkWidget	*widget,
++			       GtkSelectionData *data)
++{
++  if (data->target == gtk_selection_atoms[TIMESTAMP])
++    {
++      /* Time which was used to obtain selection */
++      GList *tmp_list;
++      GtkSelectionInfo *selection_info;
++      
++      tmp_list = current_selections;
++      while (tmp_list)
++	{
++	  selection_info = (GtkSelectionInfo *)tmp_list->data;
++	  if ((selection_info->owner == widget) &&
++	      (selection_info->selection == data->selection))
++	    {
++	      gulong time = selection_info->time;
++
++	      gtk_selection_data_set (data,
++				      GDK_SELECTION_TYPE_INTEGER,
++				      32,
++				      (guchar *)&time,
++				      sizeof (time));
++	      return;
++	    }
++	  
++	  tmp_list = tmp_list->next;
++	}
++      
++      data->length = -1;
++    }
++  else if (data->target == gtk_selection_atoms[TARGETS])
++    {
++      /* List of all targets supported for this widget/selection pair */
++      GdkAtom *p;
++      guint count;
++      GList *tmp_list;
++      GtkTargetList *target_list;
++      GtkTargetPair *pair;
++      
++      target_list = gtk_selection_target_list_get (widget,
++						   data->selection);
++      count = g_list_length (target_list->list) + 3;
++      
++      data->type = GDK_SELECTION_TYPE_ATOM;
++      data->format = 32;
++      data->length = count * sizeof (GdkAtom);
++
++      /* selection data is always terminated by a trailing \0
++       */
++      p = g_malloc (data->length + 1);
++      data->data = (guchar *)p;
++      data->data[data->length] = '\0';
++      
++      *p++ = gtk_selection_atoms[TIMESTAMP];
++      *p++ = gtk_selection_atoms[TARGETS];
++      *p++ = gtk_selection_atoms[MULTIPLE];
++      
++      tmp_list = target_list->list;
++      while (tmp_list)
++	{
++	  pair = (GtkTargetPair *)tmp_list->data;
++	  *p++ = pair->target;
++	  
++	  tmp_list = tmp_list->next;
++	}
++    }
++  else if (data->target == gtk_selection_atoms[SAVE_TARGETS])
++    {
++      gtk_selection_data_set (data,
++			      gdk_atom_intern_static_string ("NULL"),
++			      32, NULL, 0);
++    }
++  else
++    {
++      data->length = -1;
++    }
++}
++
++static GtkSelectionInfo *
++gtk_selection_info_get (GdkAtom selection) 
++{
++  GList *tmp_list;
++  GList *next;
++  GtkSelectionInfo *selection_info;
++
++  tmp_list = current_selections;
++  while (tmp_list)
++    {
++      next = tmp_list->next;
++      selection_info = (GtkSelectionInfo *)tmp_list->data;
++      
++      if (selection_info->selection == selection)
++	{	
++	  return selection_info;
++	}
++      
++      tmp_list = next;
++    }
++  return NULL;
++}
++
++static void
++gtk_selection_info_remove (GdkAtom selection, GtkWidget *owner)
++{
++  GList *tmp_list;
++  GList *next;
++  GtkSelectionInfo *selection_info;
++
++  g_return_if_fail (GTK_IS_WIDGET (owner));
++
++  tmp_list = current_selections;
++  while (tmp_list)
++    {
++      next = tmp_list->next;
++      selection_info = (GtkSelectionInfo *)tmp_list->data;
++      
++      if (selection_info->selection == selection &&
++	  selection_info->owner == owner)
++	{
++	  GtkClipboard *clip = gtk_clipboard_get(selection_info->selection);
++	  gtk_clipboard_clear(clip);
++	  current_selections = g_list_remove_link (current_selections,
++						   tmp_list);
++	  g_list_free (tmp_list);
++	  g_slice_free (GtkSelectionInfo, selection_info);
++	  return;
++	}
++      
++      tmp_list = next;
++    }
++}
++static void 
++gtk_selection_info_append (GdkAtom selection, GtkWidget *owner, guint32 time)
++{
++  GtkSelectionInfo *selection_info;
++
++  g_return_if_fail (GTK_IS_WIDGET (owner));
++
++  selection_info = g_slice_new (GtkSelectionInfo);
++  selection_info->selection = selection;
++  selection_info->owner = owner;
++  selection_info->time = time;
++  current_selections = g_list_prepend (current_selections,
++				       selection_info);
++}
++
++static void
++gtk_selection_info_clear (GtkWidget *owner)
++{
++  GList *tmp_list;
++  GList *next;
++  GtkSelectionInfo *selection_info;
++
++  g_return_if_fail (GTK_IS_WIDGET (owner));
++
++  tmp_list = current_selections;
++  while (tmp_list)
++    {
++      next = tmp_list->next;
++      selection_info = (GtkSelectionInfo *)tmp_list->data;
++      
++      if (selection_info->owner == owner)
++	{	
++	  current_selections = g_list_remove_link (current_selections,
++						   tmp_list);
++	  g_list_free (tmp_list);
++	  g_slice_free (GtkSelectionInfo, selection_info);
++	}
++      
++      tmp_list = next;
++    }
++}
++
++static GtkTargetList *
++gtk_selection_target_list_get (GtkWidget    *widget,
++			       GdkAtom       selection)
++{
++  GtkSelectionTargetList *sellist;
++  GList *tmp_list;
++  GList *lists;
++
++  lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
++  
++  tmp_list = lists;
++  while (tmp_list)
++    {
++      sellist = tmp_list->data;
++      if (sellist->selection == selection)
++	return sellist->list;
++      tmp_list = tmp_list->next;
++    }
++
++  sellist = g_slice_new (GtkSelectionTargetList);
++  sellist->selection = selection;
++  sellist->list = gtk_target_list_new (NULL, 0);
++
++  lists = g_list_prepend (lists, sellist);
++  g_object_set_data (G_OBJECT (widget), I_(gtk_selection_handler_key), lists);
++
++  return sellist->list;
++}
++
++static void
++gtk_selection_target_list_remove (GtkWidget *widget)
++{
++  GtkSelectionTargetList *sellist;
++  GList *tmp_list;
++  GList *lists;
++
++  lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
++  
++  tmp_list = lists;
++  while (tmp_list)
++    {
++      sellist = tmp_list->data;
++
++      gtk_target_list_unref (sellist->list);
++
++      g_slice_free (GtkSelectionTargetList, sellist);
++      tmp_list = tmp_list->next;
++    }
++
++  g_list_free (lists);
++  g_object_set_data (G_OBJECT (widget), I_(gtk_selection_handler_key), NULL);
++}
++
+diff --git a/gtk/gtkselection.c b/gtk/gtkselection.c
+index c2c9d97..01774dc 100644
+--- a/gtk/gtkselection.c
++++ b/gtk/gtkselection.c
+@@ -633,6 +633,7 @@ gtk_target_table_free (GtkTargetEntry *targets,
+   g_free (targets);
+ }
+ 
++#ifndef GDK_WINDOWING_QUARTZ /* Quartz handled by gtkselection-quartz.c */
+ /**
+  * gtk_selection_owner_set_for_display:
+  * @display: the #Gdkdisplay where the selection is set
+@@ -735,7 +736,7 @@ gtk_selection_owner_set_for_display (GdkDisplay   *display,
+   else
+     return FALSE;
+ }
+-
++#endif /* GDK_WINDOWING_QUARTZ */
+ /**
+  * gtk_selection_owner_set:
+  * @widget: (allow-none):  a #GtkWidget, or %NULL.
+@@ -937,7 +938,7 @@ gtk_selection_add_targets (GtkWidget            *widget,
+ #endif
+ }
+ 
+-
++#ifndef GDK_WINDOWING_QUARTZ /* Quartz is handled in gtkselection-quartz.c */
+ /**
+  * gtk_selection_remove_all:
+  * @widget: a #GtkWidget 
+@@ -998,8 +999,9 @@ gtk_selection_remove_all (GtkWidget *widget)
+   /* Remove all selection lists */
+   gtk_selection_target_list_remove (widget);
+ }
++#endif /* GDK_WINDOWING_QUARTZ */
+ 
+-
++#ifndef GDK_WINDOWING_QUARTZ /* Quartz is handled in gtkselection-quartz.c */
+ /**
+  * gtk_selection_convert:
+  * @widget: The widget which acts as requestor
+@@ -1111,7 +1113,7 @@ gtk_selection_convert (GtkWidget *widget,
+   
+   return TRUE;
+ }
+-
++#endif /* GDK_WINDOWING_QUARTZ */
+ /**
+  * gtk_selection_data_get_selection:
+  * @selection_data: a pointer to a #GtkSelectionData structure.
+@@ -2184,6 +2186,7 @@ gtk_selection_init (void)
+   initialize = FALSE;
+ }
+ 
++#ifndef GDK_WINDOWING_QUARTZ /* Quartz handled by gtkselection-quartz.c */
+ /**
+  * gtk_selection_clear:
+  * @widget: a #GtkWidget
+@@ -2622,6 +2625,7 @@ _gtk_selection_incr_event (GdkWindow	   *window,
+   
+   return TRUE;
+ }
++#endif /* GDK_WINDOWING_QUARTZ */
+ 
+ /*************************************************************
+  * gtk_selection_incr_timeout:
+@@ -2676,6 +2680,7 @@ gtk_selection_incr_timeout (GtkIncrInfo *info)
+   return retval;
+ }
+ 
++#ifndef GDK_WINDOWING_QUARTZ /* Quartz handled by gtkselection-quartz.c */
+ /*************************************************************
+  * _gtk_selection_notify:
+  *     Handler for "selection-notify-event" signals on windows
+@@ -2869,6 +2874,7 @@ _gtk_selection_property_notify (GtkWidget	*widget,
+   
+   return TRUE;
+ }
++#endif /* GDK_WINDOWING_QUARTZ */
+ 
+ /*************************************************************
+  * gtk_selection_retrieval_timeout:
+-- 
+1.7.6.3.dirty
+
diff --git a/patches/0005-Bug-657770-Write-to-released-memory-in-gtkdnd-quartz.patch b/patches/0005-Bug-657770-Write-to-released-memory-in-gtkdnd-quartz.patch
new file mode 100644
index 0000000..a221675
--- /dev/null
+++ b/patches/0005-Bug-657770-Write-to-released-memory-in-gtkdnd-quartz.patch
@@ -0,0 +1,52 @@
+From 1280340f539644de8e8766d76bcbd65b253bb346 Mon Sep 17 00:00:00 2001
+From: Kristian Rietveld <kris gtk org>
+Date: Sat, 24 Sep 2011 17:32:21 -0700
+Subject: [PATCH 05/15] Bug 657770 - Write to released memory in
+ gtkdnd-quartz.c
+
+Clear the Drag paste board just before the info->context is released.
+This way the GtkDragSourceOwner is released just before the drag context
+is and thus can pasteboard:provideDataForType: not accidentally access
+an already released drag context
+---
+ gtk/gtkdnd-quartz.c |   14 ++++++++++++++
+ 1 files changed, 14 insertions(+), 0 deletions(-)
+
+diff --git a/gtk/gtkdnd-quartz.c b/gtk/gtkdnd-quartz.c
+index 8dd47b9..5688568 100644
+--- a/gtk/gtkdnd-quartz.c
++++ b/gtk/gtkdnd-quartz.c
+@@ -1835,6 +1835,9 @@ gtk_drag_set_default_icon (GdkColormap   *colormap,
+ static void
+ gtk_drag_source_info_destroy (GtkDragSourceInfo *info)
+ {
++  NSPasteboard *pasteboard;
++  NSAutoreleasePool *pool;
++
+   if (info->icon_pixbuf)
+     g_object_unref (info->icon_pixbuf);
+ 
+@@ -1849,10 +1852,21 @@ gtk_drag_source_info_destroy (GtkDragSourceInfo *info)
+ 
+   gtk_target_list_unref (info->target_list);
+ 
++  pool = [[NSAutoreleasePool alloc] init];
++
++  /* Empty the pasteboard, so that it will not accidentally access
++   * info->context after it has been destroyed.
++   */
++  pasteboard = [NSPasteboard pasteboardWithName: NSDragPboard];
++  [pasteboard declareTypes: nil owner: nil];
++
++  [pool release];
++
+   gtk_drag_clear_source_info (info->context);
+   g_object_unref (info->context);
+ 
+   g_free (info);
++  info = NULL;
+ }
+ 
+ static gboolean
+
+
diff --git a/patches/0006-Bug-658722-Drag-and-Drop-sometimes-stops-working.patch b/patches/0006-Bug-658722-Drag-and-Drop-sometimes-stops-working.patch
new file mode 100644
index 0000000..b0a1ef5
--- /dev/null
+++ b/patches/0006-Bug-658722-Drag-and-Drop-sometimes-stops-working.patch
@@ -0,0 +1,274 @@
+From dcd9ab00c64a1df63fd5fa58c2ca25efd9b3e09e Mon Sep 17 00:00:00 2001
+From: John Ralls <jralls ceridwen us>
+Date: Sat, 24 Sep 2011 18:14:09 -0700
+Subject: [PATCH 06/15] Bug 658722 - Drag and Drop sometimes stops working
+
+First, rather than assuming that there's already an event queued up if
+_gdk_quartz_drag_source_context isn't NULL, assume that it just didn't get
+cleaned up the last time it ran and abort it.
+
+This naturally requires implementing gdk_quartz_drag_abort(), so remove the
+code from [GdkQuartzNSWindow draggedImage:endedAt:operation:] and move it to
+gdkdnd_quartz.c as static void gdk_quartz_drag_end(). Implement both
+gdk_quartz_drag_drop() and gdk_quartz_drag_abort() by calling
+gdk_quartz_drag_end().
+
+Next, try to get rid of the memory cycle between gtk_drag_source_info.context
+and _gdk_quartz_drag_source_context (which carries the GtkQuartzDragSourceInfo
+struct as qdata). Replace gtk_drag_source_clear_info() by using a
+g_object_set_qdata_full() for context in gtk_drag_get_source_context, calling
+gtk_drag_source_info_destroy() as the destructor. This eliminates the need to
+queue a cleanup idle event. I use g_object_run_dispose() on
+_gtk_quartz_drag_source_context to force the deletion of the info stored as
+qdata, which in turn unrefs the info->context pointer. Ordinarily this gets
+fired off from draggedImage:endedAt:operation:, meaning that the special
+dragging CFRunLoop is complete and NSEvents are again flowing, so queuing a
+cleanup event isn't necessary. The advantage is that it can also be run from
+gdk_drag_abort, so if Gdk thinks there's a drag but CF doesn't all of the
+memory still gets cleaned up.
+---
+ gdk/quartz/GdkQuartzWindow.c |   16 +-------
+ gdk/quartz/gdkdnd-quartz.c   |   35 +++++++++++++--
+ gtk/gtkdnd-quartz.c          |   96 ++++++++++++++++-------------------------
+ 3 files changed, 69 insertions(+), 78 deletions(-)
+
+diff --git a/gdk/quartz/GdkQuartzWindow.c b/gdk/quartz/GdkQuartzWindow.c
+index dcd7250..20ed80e 100644
+--- a/gdk/quartz/GdkQuartzWindow.c
++++ b/gdk/quartz/GdkQuartzWindow.c
+@@ -560,21 +560,7 @@ update_context_from_dragging_info (id <NSDraggingInfo> sender)
+ 
+ - (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation
+ {
+-  GdkEvent event;
+-
+-  g_assert (_gdk_quartz_drag_source_context != NULL);
+-
+-  event.dnd.type = GDK_DROP_FINISHED;
+-  event.dnd.window = g_object_ref ([[self contentView] gdkWindow]);
+-  event.dnd.send_event = FALSE;
+-  event.dnd.context = _gdk_quartz_drag_source_context;
+-
+-  (*_gdk_event_func) (&event, _gdk_event_data);
+-
+-  g_object_unref (event.dnd.window);
+-
+-  g_object_unref (_gdk_quartz_drag_source_context);
+-  _gdk_quartz_drag_source_context = NULL;
++  gdk_drag_drop (_gdk_quartz_drag_source_context, (guint32)g_get_real_time());
+ }
+ 
+ @end
+diff --git a/gdk/quartz/gdkdnd-quartz.c b/gdk/quartz/gdkdnd-quartz.c
+index bb70b71..143a8ed 100644
+--- a/gdk/quartz/gdkdnd-quartz.c
++++ b/gdk/quartz/gdkdnd-quartz.c
+@@ -111,11 +111,20 @@ GdkDragContext *
+ gdk_drag_begin (GdkWindow     *window,
+ 		GList         *targets)
+ {
+-  g_assert (_gdk_quartz_drag_source_context == NULL);
++  if (_gdk_quartz_drag_source_context != NULL)
++    {
++      /* Something is amiss with the existing drag, so log a message
++	 and abort it */
++      g_warning ("Drag begun with existing context; aborting the preexisting drag");
++      gdk_drag_abort (_gdk_quartz_drag_source_context,
++		      (guint32)g_get_real_time ());
++    }
++
+   
+   /* Create fake context */
+   _gdk_quartz_drag_source_context = gdk_drag_context_new ();
+   _gdk_quartz_drag_source_context->is_source = TRUE;
++  _gdk_quartz_drag_source_context->source_window = window;
+   
+   return _gdk_quartz_drag_source_context;
+ }
+@@ -155,20 +164,36 @@ gdk_drag_find_window_for_screen (GdkDragContext  *context,
+   /* FIXME: Implement */
+ }
+ 
++static void
++gdk_quartz_drag_end (GdkDragContext *context)
++{
++  GdkEvent event;
++
++  g_assert (context != NULL);
++  event.dnd.type = GDK_DROP_FINISHED;
++  event.dnd.window = g_object_ref (context->source_window);
++  event.dnd.send_event = FALSE;
++  event.dnd.context = context;
++
++  (*_gdk_event_func) (&event, _gdk_event_data);
++
++  g_object_run_dispose (_gdk_quartz_drag_source_context);
++  _gdk_quartz_drag_source_context = NULL;
++}
++
+ void
+ gdk_drag_drop (GdkDragContext *context,
+ 	       guint32         time)
+ {
+-  /* FIXME: Implement */
++  gdk_quartz_drag_end (context);
+ }
+ 
+ void
+ gdk_drag_abort (GdkDragContext *context,
+ 		guint32         time)
+ {
+-  g_return_if_fail (context != NULL);
+-  
+-  /* FIXME: Implement */
++  g_warning ("Gdk-quartz-drag-drop, aborting\n");
++  gdk_quartz_drag_end (context);
+ }
+ 
+ void             
+diff --git a/gtk/gtkdnd-quartz.c b/gtk/gtkdnd-quartz.c
+index 5688568..be92a22 100644
+--- a/gtk/gtkdnd-quartz.c
++++ b/gtk/gtkdnd-quartz.c
+@@ -269,6 +269,39 @@ gtk_drag_dest_info_destroy (gpointer data)
+   g_free (info);
+ }
+ 
++static void
++gtk_drag_source_info_destroy (GtkDragSourceInfo *info)
++{
++  NSPasteboard *pasteboard;
++  NSAutoreleasePool *pool;
++
++  if (info->icon_pixbuf)
++    g_object_unref (info->icon_pixbuf);
++
++  g_signal_emit_by_name (info->widget, "drag-end", 
++			 info->context);
++
++  if (info->source_widget)
++    g_object_unref (info->source_widget);
++
++  if (info->widget)
++    g_object_unref (info->widget);
++
++  gtk_target_list_unref (info->target_list);
++
++  pool = [[NSAutoreleasePool alloc] init];
++
++  /* Empty the pasteboard, so that it will not accidentally access
++   * info->context after it has been destroyed.
++   */
++  pasteboard = [NSPasteboard pasteboardWithName: NSDragPboard];
++  [pasteboard declareTypes: nil owner: nil];
++
++  [pool release];
++
++  g_free (info);
++}
++
+ static GtkDragDestInfo *
+ gtk_drag_get_dest_info (GdkDragContext *context,
+ 			gboolean        create)
+@@ -308,18 +341,14 @@ gtk_drag_get_source_info (GdkDragContext *context,
+     {
+       info = g_new0 (GtkDragSourceInfo, 1);
+       info->context = context;
+-      g_object_set_qdata (G_OBJECT (context), dest_info_quark, info);
++      g_object_ref (info->context);
++      g_object_set_qdata_full (G_OBJECT (context), dest_info_quark,
++			       info, gtk_drag_source_info_destroy);
+     }
+ 
+   return info;
+ }
+ 
+-static void
+-gtk_drag_clear_source_info (GdkDragContext *context)
+-{
+-  g_object_set_qdata (G_OBJECT (context), dest_info_quark, NULL);
+-}
+-
+ GtkWidget *
+ gtk_drag_get_source_widget (GdkDragContext *context)
+ {
+@@ -1089,7 +1118,8 @@ gtk_drag_begin_idle (gpointer arg)
+   [owner release];
+   [types release];
+ 
+-  if ((nswindow = get_toplevel_nswindow (info->source_widget)) == NULL)
++  if (info->source_widget == NULL
++      || (nswindow = get_toplevel_nswindow (info->source_widget)) == NULL)
+      return FALSE;
+   
+   /* Ref the context. It's unreffed when the drag has been aborted */
+@@ -1108,7 +1138,6 @@ gtk_drag_begin_idle (gpointer arg)
+                source:nswindow
+             slideBack:YES];
+ 
+-  [info->nsevent release];
+   [drag_image release];
+ 
+   [pool release];
+@@ -1833,61 +1862,12 @@ gtk_drag_set_default_icon (GdkColormap   *colormap,
+ }
+ 
+ static void
+-gtk_drag_source_info_destroy (GtkDragSourceInfo *info)
+-{
+-  NSPasteboard *pasteboard;
+-  NSAutoreleasePool *pool;
+-
+-  if (info->icon_pixbuf)
+-    g_object_unref (info->icon_pixbuf);
+-
+-  g_signal_emit_by_name (info->widget, "drag-end", 
+-			 info->context);
+-
+-  if (info->source_widget)
+-    g_object_unref (info->source_widget);
+-
+-  if (info->widget)
+-    g_object_unref (info->widget);
+-
+-  gtk_target_list_unref (info->target_list);
+-
+-  pool = [[NSAutoreleasePool alloc] init];
+-
+-  /* Empty the pasteboard, so that it will not accidentally access
+-   * info->context after it has been destroyed.
+-   */
+-  pasteboard = [NSPasteboard pasteboardWithName: NSDragPboard];
+-  [pasteboard declareTypes: nil owner: nil];
+-
+-  [pool release];
+-
+-  gtk_drag_clear_source_info (info->context);
+-  g_object_unref (info->context);
+-
+-  g_free (info);
+-  info = NULL;
+-}
+-
+-static gboolean
+-drag_drop_finished_idle_cb (gpointer data)
+-{
+-  gtk_drag_source_info_destroy (data);
+-  return FALSE;
+-}
+-
+-static void
+ gtk_drag_drop_finished (GtkDragSourceInfo *info)
+ {
+   if (info->success && info->delete)
+     g_signal_emit_by_name (info->source_widget, "drag-data-delete",
+                            info->context);
+ 
+-  /* Workaround for the fact that the NS API blocks until the drag is
+-   * over. This way the context is still valid when returning from
+-   * drag_begin, even if it will still be quite useless. See bug #501588.
+-  */
+-  g_idle_add (drag_drop_finished_idle_cb, info);
+ }
+ 
+ /*************************************************************
diff --git a/patches/0007-Bug-658767-Drag-and-Drop-NSEvent-capture-is-racy.patch b/patches/0007-Bug-658767-Drag-and-Drop-NSEvent-capture-is-racy.patch
new file mode 100644
index 0000000..2bbc098
--- /dev/null
+++ b/patches/0007-Bug-658767-Drag-and-Drop-NSEvent-capture-is-racy.patch
@@ -0,0 +1,78 @@
+From 592a11566aa832e8ad80a389fcb19aa7e634f6e5 Mon Sep 17 00:00:00 2001
+From: John Ralls <jralls ceridwen us>
+Date: Sat, 24 Sep 2011 18:19:56 -0700
+Subject: [PATCH 07/15] Bug 658767 - Drag and Drop NSEvent capture is racy
+
+Create a synthetic NSMouseLeftDown to store in the GtkQuartzDragSourceInfo
+rather than relying on the NSWindow's latest event being the right one (or the
+right kind).
+---
+ gtk/gtkdnd-quartz.c |   43 +++++++++++++++++++++++++++++++++++--------
+ 1 files changed, 35 insertions(+), 8 deletions(-)
+
+diff --git a/gtk/gtkdnd-quartz.c b/gtk/gtkdnd-quartz.c
+index be92a22..084aada 100644
+--- a/gtk/gtkdnd-quartz.c
++++ b/gtk/gtkdnd-quartz.c
+@@ -1155,13 +1155,44 @@ gtk_drag_begin_internal (GtkWidget         *widget,
+ {
+   GtkDragSourceInfo *info;
+   GdkDragContext *context;
+-  NSWindow *nswindow;
+-
+-  context = gdk_drag_begin (NULL, NULL);
++  NSWindow *nswindow = get_toplevel_nswindow (widget);
++  NSPoint point = {0, 0};
++  gdouble x, y;
++  double time = (double)g_get_real_time ();
++  NSEvent *nsevent;
++  NSTimeInterval nstime;
++
++  if (event)
++    {
++      if (gdk_event_get_coords (event, &x, &y))
++        {
++          point.x = x;
++          point.y = y;
++        }
++      time = (double)gdk_event_get_time (event);
++    }
++  nstime = [[NSDate dateWithTimeIntervalSince1970: time / 1000] timeIntervalSinceReferenceDate];
++  nsevent = [NSEvent mouseEventWithType: NSLeftMouseDown
++        	      location: point
++		      modifierFlags: 0
++	              timestamp: nstime
++		      windowNumber: [nswindow windowNumber]
++		      context: [nswindow graphicsContext]
++		      eventNumber: 0
++		      clickCount: 1
++	              pressure: 0.0 ];
++
++  GdkWindow *window = [[nswindow contentView] gdkWindow];
++  g_return_val_if_fail(nsevent != NULL, NULL);
++
++  context = gdk_drag_begin (window, NULL);
++  g_return_val_if_fail( context != NULL, NULL);
+   context->is_source = TRUE;
+ 
+   info = gtk_drag_get_source_info (context, TRUE);
+-  
++  info->nsevent = nsevent;
++  [info->nsevent retain];
++
+   info->source_widget = g_object_ref (widget);
+   info->widget = g_object_ref (widget);
+   info->target_list = target_list;
+@@ -1228,10 +1259,6 @@ gtk_drag_begin_internal (GtkWidget         *widget,
+ 	  }
+     }
+ 
+-  nswindow = get_toplevel_nswindow (widget);
+-  info->nsevent = [nswindow currentEvent];
+-  [info->nsevent retain];
+-
+   /* drag will begin in an idle handler to avoid nested run loops */
+ 
+   g_idle_add_full (G_PRIORITY_HIGH_IDLE, gtk_drag_begin_idle, context, NULL);
+
+
diff --git a/patches/0008-Implement-GtkDragSourceOwner-pasteboardChangedOwner.patch b/patches/0008-Implement-GtkDragSourceOwner-pasteboardChangedOwner.patch
new file mode 100644
index 0000000..5b9153c
--- /dev/null
+++ b/patches/0008-Implement-GtkDragSourceOwner-pasteboardChangedOwner.patch
@@ -0,0 +1,39 @@
+From 259563958047ccbf6f61578f2d724fc731218304 Mon Sep 17 00:00:00 2001
+From: John Ralls <jralls ceridwen us>
+Date: Sun, 25 Sep 2011 12:03:54 -0700
+Subject: [PATCH 08/15] Implement GtkDragSourceOwner pasteboardChangedOwner:
+
+---
+ gtk/gtkdnd-quartz.c |   11 +++++++++++
+ 1 files changed, 11 insertions(+), 0 deletions(-)
+
+diff --git a/gtk/gtkdnd-quartz.c b/gtk/gtkdnd-quartz.c
+index 084aada..21ce11a 100644
+--- a/gtk/gtkdnd-quartz.c
++++ b/gtk/gtkdnd-quartz.c
+@@ -149,6 +149,8 @@ struct _GtkDragFindData
+   guint target_info;
+   GtkSelectionData selection_data;
+ 
++  g_return_if_fail(info->source_widget != NULL);
++  g_return_if_fail(info->target_list != NULL);
+   selection_data.selection = GDK_NONE;
+   selection_data.data = NULL;
+   selection_data.length = -1;
+@@ -171,6 +173,15 @@ struct _GtkDragFindData
+     }
+ }
+ 
++- (void)pasteboardChangedOwner: (NSPasteboard*)sender
++{
++  if (!info) return;
++
++  info->target_list = NULL;
++  info->widget = NULL;
++  info->source_widget = NULL;
++}
++
+ - (id)initWithInfo:(GtkDragSourceInfo *)anInfo
+ {
+   self = [super init];
+
diff --git a/patches/0009-Implement-recent-items-in-Filechooser.patch b/patches/0009-Implement-recent-items-in-Filechooser.patch
new file mode 100644
index 0000000..34b4a1c
--- /dev/null
+++ b/patches/0009-Implement-recent-items-in-Filechooser.patch
@@ -0,0 +1,880 @@
+From 7ec6fc1e4161f798de9a5e6f82855ad16c60b5d4 Mon Sep 17 00:00:00 2001
+From: Federico Mena Quintero <federico gnome org>
+Date: Tue, 26 Jul 2011 16:00:35 -0500
+Subject: [PATCH 09/15] Implement recent items in Filechooser
+
+---
+ gtk/gtkfilechooserdefault.c |  563 ++++++++++++++++---------------------------
+ gtk/gtkfilechooserprivate.h |    1 +
+ 2 files changed, 208 insertions(+), 356 deletions(-)
+
+diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c
+index 2ee7903..9e636c2 100644
+--- a/gtk/gtkfilechooserdefault.c
++++ b/gtk/gtkfilechooserdefault.c
+@@ -401,22 +401,23 @@ static void location_switch_to_path_bar (GtkFileChooserDefault *impl);
+ 
+ static void stop_loading_and_clear_list_model (GtkFileChooserDefault *impl,
+                                                gboolean remove_from_treeview);
++
++static void     search_setup_widgets         (GtkFileChooserDefault *impl);
+ static void     search_stop_searching        (GtkFileChooserDefault *impl,
+                                               gboolean               remove_query);
+ static void     search_clear_model           (GtkFileChooserDefault *impl, 
+ 					      gboolean               remove_from_treeview);
+ static gboolean search_should_respond        (GtkFileChooserDefault *impl);
+-static void     search_switch_to_browse_mode (GtkFileChooserDefault *impl);
+ static GSList  *search_get_selected_files    (GtkFileChooserDefault *impl);
+ static void     search_entry_activate_cb     (GtkEntry              *entry, 
+ 					      gpointer               data);
+ static void     settings_load                (GtkFileChooserDefault *impl);
+ 
++static void     recent_start_loading         (GtkFileChooserDefault *impl);
+ static void     recent_stop_loading          (GtkFileChooserDefault *impl);
+ static void     recent_clear_model           (GtkFileChooserDefault *impl,
+                                               gboolean               remove_from_treeview);
+ static gboolean recent_should_respond        (GtkFileChooserDefault *impl);
+-static void     recent_switch_to_browse_mode (GtkFileChooserDefault *impl);
+ static GSList * recent_get_selected_files    (GtkFileChooserDefault *impl);
+ static void     set_file_system_backend      (GtkFileChooserDefault *impl);
+ static void     unset_file_system_backend    (GtkFileChooserDefault *impl);
+@@ -2322,23 +2323,9 @@ renderer_editing_canceled_cb (GtkCellRendererText   *cell_renderer_text,
+ static GtkWidget *
+ filter_create (GtkFileChooserDefault *impl)
+ {
+-  GtkCellRenderer *cell;
+-  GList           *cells;
+-
+   impl->filter_combo = gtk_combo_box_text_new ();
+   gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (impl->filter_combo), FALSE);
+ 
+-  /* Get the combo's text renderer and set ellipsize parameters */
+-  cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (impl->filter_combo));
+-  g_assert (cells);
+-  cell = cells->data;
+-
+-  g_object_set (G_OBJECT (cell),
+-		"ellipsize", PANGO_ELLIPSIZE_END,
+-		NULL);
+-
+-  g_list_free (cells);
+-
+   g_signal_connect (impl->filter_combo, "changed",
+ 		    G_CALLBACK (filter_combo_changed), impl);
+ 
+@@ -3692,7 +3679,7 @@ key_is_left_or_right (GdkEventKey *event)
+ 
+ /* Handles key press events on the file list, so that we can trap Enter to
+  * activate the default button on our own.  Also, checks to see if '/' has been
+- * pressed.  See comment by tree_view_keybinding_cb() for more details.
++ * pressed.
+  */
+ static gboolean
+ browse_files_key_press_event_cb (GtkWidget   *widget,
+@@ -4130,7 +4117,9 @@ typedef struct {
+   gint model_column;
+ } ColumnMap;
+ 
+-/* Sets the sort column IDs for the file list based on the operation mode */
++/* Sets the sort column IDs for the file list; needs to be done whenever we
++ * change the model on the treeview.
++ */
+ static void
+ file_list_set_sort_column_ids (GtkFileChooserDefault *impl)
+ {
+@@ -4368,6 +4357,20 @@ file_pane_create (GtkFileChooserDefault *impl,
+   return vbox;
+ }
+ 
++static void
++location_entry_create (GtkFileChooserDefault *impl)
++{
++  if (!impl->location_entry)
++    impl->location_entry = _gtk_file_chooser_entry_new (TRUE);
++
++  _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 */
+ static void
+ save_widgets_create (GtkFileChooserDefault *impl)
+@@ -4400,12 +4403,7 @@ save_widgets_create (GtkFileChooserDefault *impl)
+ 
+   /* Location entry */
+ 
+-  impl->location_entry = _gtk_file_chooser_entry_new (TRUE);
+-  _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_entry_set_width_chars (GTK_ENTRY (impl->location_entry), 45);
+-  gtk_entry_set_activates_default (GTK_ENTRY (impl->location_entry), TRUE);
++  location_entry_create (impl);
+   gtk_table_attach (GTK_TABLE (impl->save_widgets_table), impl->location_entry,
+ 		    1, 2, 0, 1,
+ 		    GTK_EXPAND | GTK_FILL, 0,
+@@ -4457,53 +4455,6 @@ location_switch_to_path_bar (GtkFileChooserDefault *impl)
+   gtk_widget_hide (impl->location_entry_box);
+ }
+ 
+-/* Sets the full path of the current folder as the text in the location entry. */
+-static void
+-location_entry_set_initial_text (GtkFileChooserDefault *impl)
+-{
+-  gchar *text, *filename;
+-
+-  if (!impl->current_folder)
+-    return;
+-
+-  filename = g_file_get_path (impl->current_folder);
+-
+-  if (filename)
+-    {
+-      text = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
+-      g_free (filename);
+-    }
+-  else
+-    text = g_file_get_uri (impl->current_folder);
+-
+-  if (text)
+-    {
+-      gboolean need_slash;
+-      int len;
+-
+-      len = strlen (text);
+-      need_slash = (text[len - 1] != G_DIR_SEPARATOR);
+-
+-      if (need_slash)
+-	{
+-	  char *slash_text;
+-
+-	  slash_text = g_new (char, len + 2);
+-	  strcpy (slash_text, text);
+-	  slash_text[len] = G_DIR_SEPARATOR;
+-	  slash_text[len + 1] = 0;
+-
+-	  g_free (text);
+-	  text = slash_text;
+-	}
+-
+-      _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), text);
+-      g_free (text);
+-    }
+-
+-  g_free (filename);
+-}
+-
+ /* Turns on the location entry.  Can be called even if we are already in that
+  * mode.
+  */
+@@ -4519,7 +4470,10 @@ location_switch_to_filename_entry (GtkFileChooserDefault *impl)
+     return;
+ 
+   if (impl->location_entry)
+-    gtk_widget_destroy (impl->location_entry);
++    {
++      gtk_widget_destroy (impl->location_entry);
++      impl->location_entry = NULL;
++    }
+ 
+   /* Box */
+ 
+@@ -4527,19 +4481,13 @@ location_switch_to_filename_entry (GtkFileChooserDefault *impl)
+ 
+   /* Entry */
+ 
+-  impl->location_entry = _gtk_file_chooser_entry_new (TRUE);
+-  _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
+-					   impl->file_system);
+-  gtk_entry_set_activates_default (GTK_ENTRY (impl->location_entry), TRUE);
+-  _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->action);
+-
++  location_entry_create (impl);
+   gtk_box_pack_start (GTK_BOX (impl->location_entry_box), impl->location_entry, TRUE, TRUE, 0);
+   gtk_label_set_mnemonic_widget (GTK_LABEL (impl->location_label), impl->location_entry);
+ 
+   /* Configure the entry */
+ 
+   _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->current_folder);
+-  _gtk_file_chooser_entry_set_local_only (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->local_only);
+ 
+   /* Done */
+ 
+@@ -4892,9 +4840,13 @@ browse_widgets_create (GtkFileChooserDefault *impl)
+   GtkWidget *widget;
+   GtkSizeGroup *size_group;
+ 
+-  /* size group is used by the scrolled windows of the panes */
+-  size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
+   impl->browse_widgets_box = gtk_vbox_new (FALSE, 12);
++  gtk_box_pack_start (GTK_BOX (impl), impl->browse_widgets_box, TRUE, TRUE, 0);
++  gtk_widget_show (impl->browse_widgets_box);
++
++  impl->browse_header_box = gtk_vbox_new (FALSE, 12);
++  gtk_box_pack_start (GTK_BOX (impl->browse_widgets_box), impl->browse_header_box, FALSE, FALSE, 0);
++  gtk_widget_show (impl->browse_header_box);
+ 
+   /* Path bar, info bar, and their respective machinery - the browse_path_bar_hbox will get packed elsewhere */
+   path_bar_widgets_create (impl);
+@@ -4902,12 +4854,15 @@ browse_widgets_create (GtkFileChooserDefault *impl)
+   /* Box for the location label and entry */
+ 
+   impl->location_entry_box = gtk_hbox_new (FALSE, 12);
+-  gtk_box_pack_start (GTK_BOX (impl->browse_widgets_box), impl->location_entry_box, FALSE, FALSE, 0);
++  gtk_box_pack_start (GTK_BOX (impl->browse_header_box), impl->location_entry_box, FALSE, FALSE, 0);
+ 
+   impl->location_label = gtk_label_new_with_mnemonic (_("_Location:"));
+   gtk_widget_show (impl->location_label);
+   gtk_box_pack_start (GTK_BOX (impl->location_entry_box), impl->location_label, FALSE, FALSE, 0);
+ 
++  /* size group is used by the scrolled windows of the panes */
++  size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
++
+   /* Paned widget */
+   hpaned = gtk_hpaned_new ();
+   gtk_widget_show (hpaned);
+@@ -4945,7 +4900,6 @@ gtk_file_chooser_default_constructor (GType                  type,
+ 
+   /* The browse widgets */
+   browse_widgets_create (impl);
+-  gtk_box_pack_start (GTK_BOX (impl), impl->browse_widgets_box, TRUE, TRUE, 0);
+ 
+   /* Alignment to hold extra widget */
+   impl->extra_align = gtk_alignment_new (0.0, 0.5, 1.0, 1.0);
+@@ -5116,8 +5070,8 @@ restore_path_bar (GtkFileChooserDefault *impl)
+   if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
+       || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+     {
+-      gtk_box_pack_start (GTK_BOX (impl->browse_widgets_box), impl->browse_path_bar_hbox, FALSE, FALSE, 0);
+-      gtk_box_reorder_child (GTK_BOX (impl->browse_widgets_box), impl->browse_path_bar_hbox, 0);
++      gtk_box_pack_start (GTK_BOX (impl->browse_header_box), impl->browse_path_bar_hbox, FALSE, FALSE, 0);
++      gtk_box_reorder_child (GTK_BOX (impl->browse_header_box), impl->browse_path_bar_hbox, 0);
+     }
+   else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
+ 	   || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+@@ -5199,6 +5153,140 @@ path_bar_update (GtkFileChooserDefault *impl)
+   path_bar_set_mode (impl, mode);
+ }
+ 
++static void
++operation_mode_discard_search_widgets (GtkFileChooserDefault *impl)
++{
++  if (impl->search_hbox)
++    {
++      gtk_widget_destroy (impl->search_hbox);
++
++      impl->search_hbox = NULL;
++      impl->search_entry = NULL;
++    }
++}
++
++/* Stops running operations like populating the browse model, searches, and the recent-files model */
++static void
++operation_mode_stop (GtkFileChooserDefault *impl, OperationMode mode)
++{
++  switch (mode)
++    {
++    case OPERATION_MODE_BROWSE:
++      stop_loading_and_clear_list_model (impl, TRUE);
++      break;
++
++    case OPERATION_MODE_SEARCH:
++      search_stop_searching (impl, FALSE);
++      search_clear_model (impl, TRUE);
++
++      operation_mode_discard_search_widgets (impl);
++      break;
++
++    case OPERATION_MODE_RECENT:
++      recent_stop_loading (impl);
++      recent_clear_model (impl, TRUE);
++      break;
++
++    default:
++      g_assert_not_reached ();
++    }
++}
++
++static void
++operation_mode_set_browse (GtkFileChooserDefault *impl)
++{
++  path_bar_update (impl);
++
++  if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
++      impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
++    {
++      gtk_widget_show (impl->location_button);
++      location_mode_set (impl, impl->location_mode, TRUE);
++
++      if (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY)
++	gtk_widget_show (impl->location_entry_box);
++    }
++}
++
++static void
++operation_mode_set_search (GtkFileChooserDefault *impl)
++{
++  g_assert (impl->search_hbox == NULL);
++  g_assert (impl->search_entry == NULL);
++  g_assert (impl->search_model == NULL);
++
++  search_setup_widgets (impl);
++}
++
++static void
++operation_mode_set_recent (GtkFileChooserDefault *impl)
++{
++  path_bar_update (impl);
++
++  /* Hide the location widgets temporarily */
++  if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
++      impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
++    {
++      gtk_widget_hide (impl->location_button);
++      gtk_widget_hide (impl->location_entry_box);
++    }
++
++  recent_start_loading (impl);
++}
++
++/* Sometimes we need to frob the selection in the shortcuts list manually */
++static void
++shortcuts_select_item_without_activating (GtkFileChooserDefault *impl, int pos)
++{
++  GtkTreeSelection *selection;
++  GtkTreePath *path;
++
++  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view));
++
++  g_signal_handlers_block_by_func (selection, G_CALLBACK (shortcuts_selection_changed_cb), impl);
++
++  path = gtk_tree_path_new_from_indices (pos, -1);
++  gtk_tree_selection_select_path (selection, path);
++  gtk_tree_path_free (path);
++
++  g_signal_handlers_unblock_by_func (selection, G_CALLBACK (shortcuts_selection_changed_cb), impl);
++}
++
++static void
++operation_mode_set (GtkFileChooserDefault *impl, OperationMode mode)
++{
++  ShortcutsIndex shortcut_to_select;
++
++  operation_mode_stop (impl, impl->operation_mode);
++
++  impl->operation_mode = mode;
++
++  switch (impl->operation_mode)
++    {
++    case OPERATION_MODE_BROWSE:
++      operation_mode_set_browse (impl);
++      shortcut_to_select = SHORTCUTS_CURRENT_FOLDER;
++      break;
++
++    case OPERATION_MODE_SEARCH:
++      operation_mode_set_search (impl);
++      shortcut_to_select = SHORTCUTS_SEARCH;
++      break;
++
++    case OPERATION_MODE_RECENT:
++      operation_mode_set_recent (impl);
++      shortcut_to_select = SHORTCUTS_RECENT;
++      break;
++
++    default:
++      g_assert_not_reached ();
++      return;
++    }
++
++  if (shortcut_to_select != SHORTCUTS_CURRENT_FOLDER)
++    shortcuts_select_item_without_activating (impl, shortcuts_get_index (impl, shortcut_to_select));
++}
++
+ /* This function is basically a do_all function.
+  *
+  * It sets the visibility on all the widgets based on the current state, and
+@@ -5236,7 +5324,6 @@ update_appearance (GtkFileChooserDefault *impl)
+     {
+       gtk_widget_show (impl->location_button);
+       save_widgets_destroy (impl);
+-      gtk_widget_show (impl->browse_widgets_box);
+       location_mode_set (impl, impl->location_mode, TRUE);
+     }
+ 
+@@ -6070,6 +6157,7 @@ load_set_model (GtkFileChooserDefault *impl)
+   gtk_tree_view_columns_autosize (GTK_TREE_VIEW (impl->browse_files_tree_view));
+   gtk_tree_view_set_search_column (GTK_TREE_VIEW (impl->browse_files_tree_view),
+ 				   MODEL_COL_NAME);
++  file_list_set_sort_column_ids (impl);
+   set_sort_column (impl);
+   profile_msg ("    gtk_tree_view_set_model end", NULL);
+   impl->list_sort_ascending = TRUE;
+@@ -7095,17 +7183,7 @@ gtk_file_chooser_default_update_current_folder (GtkFileChooser    *chooser,
+ 
+   g_object_ref (file);
+ 
+-  switch (impl->operation_mode)
+-    {
+-    case OPERATION_MODE_SEARCH:
+-      search_switch_to_browse_mode (impl);
+-      break;
+-    case OPERATION_MODE_RECENT:
+-      recent_switch_to_browse_mode (impl);
+-      break;
+-    case OPERATION_MODE_BROWSE:
+-      break;
+-    }
++  operation_mode_set (impl, OPERATION_MODE_BROWSE);
+ 
+   if (impl->local_only && !g_file_is_native (file))
+     {
+@@ -8747,7 +8825,8 @@ gtk_file_chooser_default_initial_focus (GtkFileChooserEmbed *chooser_embed)
+   if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+       impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+     {
+-      if (impl->location_mode == LOCATION_MODE_PATH_BAR)
++      if (impl->location_mode == LOCATION_MODE_PATH_BAR
++	  || impl->operation_mode == OPERATION_MODE_RECENT)
+ 	widget = impl->browse_files_tree_view;
+       else
+ 	widget = impl->location_entry;
+@@ -8865,6 +8944,7 @@ search_engine_finished_cb (GtkSearchEngine *engine,
+    */
+   gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
+                            GTK_TREE_MODEL (impl->search_model));
++  file_list_set_sort_column_ids (impl);
+ #endif
+ 
+   /* FMQ: if search was empty, say that we got no hits */
+@@ -8934,34 +9014,6 @@ search_stop_searching (GtkFileChooserDefault *impl,
+     }
+ }
+ 
+-/* Stops any pending searches, clears the file list, and switches back to OPERATION_MODE_BROWSE */
+-static void
+-search_switch_to_browse_mode (GtkFileChooserDefault *impl)
+-{
+-  g_assert (impl->operation_mode != OPERATION_MODE_BROWSE);
+-
+-  search_stop_searching (impl, FALSE);
+-  search_clear_model (impl, TRUE);
+-
+-  gtk_widget_destroy (impl->search_hbox);
+-  impl->search_hbox = NULL;
+-  impl->search_entry = NULL;
+-
+-  impl->operation_mode = OPERATION_MODE_BROWSE;
+-  path_bar_update (impl);
+-
+-  if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+-      impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+-    {
+-      gtk_widget_show (impl->location_button);
+-
+-      if (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY)
+-	gtk_widget_show (impl->location_entry_box);
+-    }
+-
+-  file_list_set_sort_column_ids (impl);
+-}
+-
+ /* Creates the search_model and puts it in the tree view */
+ static void
+ search_setup_model (GtkFileChooserDefault *impl)
+@@ -8992,6 +9044,7 @@ search_setup_model (GtkFileChooserDefault *impl)
+    */
+   gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
+                            GTK_TREE_MODEL (impl->search_model));
++  file_list_set_sort_column_ids (impl);
+ }
+ 
+ /* Creates a new query with the specified text and launches it */
+@@ -9141,79 +9194,6 @@ search_setup_widgets (GtkFileChooserDefault *impl)
+   /* FMQ: hide the filter combo? */
+ }
+ 
+-/* Stops running operations like populating the browse model, searches, and the recent-files model */
+-static void
+-stop_operation (GtkFileChooserDefault *impl, OperationMode mode)
+-{
+-  switch (mode)
+-    {
+-    case OPERATION_MODE_BROWSE:
+-      stop_loading_and_clear_list_model (impl, TRUE);
+-      break;
+-
+-    case OPERATION_MODE_SEARCH:
+-      search_stop_searching (impl, FALSE);
+-      search_clear_model (impl, TRUE);
+-
+-      gtk_widget_destroy (impl->search_hbox);
+-      impl->search_hbox = NULL;
+-      impl->search_entry = NULL;
+-      break;
+-
+-    case OPERATION_MODE_RECENT:
+-      recent_stop_loading (impl);
+-      recent_clear_model (impl, TRUE);
+-      break;
+-    }
+-}
+-
+-/* Sometimes we need to frob the selection in the shortcuts list manually */
+-static void
+-shortcuts_select_item_without_activating (GtkFileChooserDefault *impl, int pos)
+-{
+-  GtkTreeSelection *selection;
+-  GtkTreePath *path;
+-
+-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view));
+-
+-  g_signal_handlers_block_by_func (selection, G_CALLBACK (shortcuts_selection_changed_cb), impl);
+-
+-  path = gtk_tree_path_new_from_indices (pos, -1);
+-  gtk_tree_selection_select_path (selection, path);
+-  gtk_tree_path_free (path);
+-
+-  g_signal_handlers_unblock_by_func (selection, G_CALLBACK (shortcuts_selection_changed_cb), impl);
+-}
+-
+-/* Main entry point to the searching functions; this gets called when the user
+- * activates the Search shortcut.
+- */
+-static void
+-search_activate (GtkFileChooserDefault *impl)
+-{
+-  OperationMode previous_mode;
+-  
+-  if (impl->operation_mode == OPERATION_MODE_SEARCH)
+-    {
+-      focus_search_entry_in_idle (impl);
+-      return;
+-    }
+-
+-  previous_mode = impl->operation_mode;
+-  impl->operation_mode = OPERATION_MODE_SEARCH;
+-
+-  shortcuts_select_item_without_activating (impl, shortcuts_get_index (impl, SHORTCUTS_SEARCH));
+-
+-  stop_operation (impl, previous_mode);
+-
+-  g_assert (impl->search_hbox == NULL);
+-  g_assert (impl->search_entry == NULL);
+-  g_assert (impl->search_model == NULL);
+-
+-  search_setup_widgets (impl);
+-  file_list_set_sort_column_ids (impl);
+-}
+-
+ /*
+  * Recent files support
+  */
+@@ -9246,34 +9226,6 @@ recent_stop_loading (GtkFileChooserDefault *impl)
+     }
+ }
+ 
+-/* Stops any pending load, clears the file list, and switches
+- * back to OPERATION_MODE_BROWSE
+- */
+-static void
+-recent_switch_to_browse_mode (GtkFileChooserDefault *impl)
+-{
+-  g_assert (impl->operation_mode != OPERATION_MODE_BROWSE);
+-
+-  recent_stop_loading (impl);
+-  recent_clear_model (impl, TRUE);
+-
+-  impl->operation_mode = OPERATION_MODE_BROWSE;
+-  path_bar_update (impl);
+-
+-  if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+-      impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+-    {
+-      gtk_widget_show (impl->location_button);
+-
+-      if (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY)
+-	gtk_widget_show (impl->location_entry_box);
+-    }
+-
+-  gtk_tree_view_column_set_visible (impl->list_size_column, impl->show_size_column);
+-
+-  file_list_set_sort_column_ids (impl);
+-}
+-
+ static void
+ recent_setup_model (GtkFileChooserDefault *impl)
+ {
+@@ -9304,7 +9256,6 @@ typedef struct
+ {
+   GtkFileChooserDefault *impl;
+   GList *items;
+-  guint needs_sorting : 1;
+ } RecentLoadData;
+ 
+ static void
+@@ -9315,6 +9266,8 @@ recent_idle_cleanup (gpointer data)
+ 
+   gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
+                            GTK_TREE_MODEL (impl->recent_model));
++  file_list_set_sort_column_ids (impl);
++  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (impl->recent_model), MODEL_COL_MTIME, GTK_SORT_DESCENDING);
+ 
+   set_busy_cursor (impl, FALSE);
+   
+@@ -9324,16 +9277,6 @@ recent_idle_cleanup (gpointer data)
+ }
+ 
+ static gint
+-recent_sort_mru (gconstpointer a,
+-                 gconstpointer b)
+-{
+-  GtkRecentInfo *info_a = (GtkRecentInfo *) a;
+-  GtkRecentInfo *info_b = (GtkRecentInfo *) b;
+-
+-  return (gtk_recent_info_get_modified (info_b) - gtk_recent_info_get_modified (info_a));
+-}
+-
+-static gint
+ get_recent_files_limit (GtkWidget *widget)
+ {
+   GtkSettings *settings;
+@@ -9408,32 +9351,18 @@ recent_idle_load (gpointer data)
+   if (!impl->recent_manager)
+     return FALSE;
+ 
+-  /* first iteration: load all the items */
++  load_data->items = gtk_recent_manager_get_items (impl->recent_manager);
+   if (!load_data->items)
+-    {
+-      load_data->items = gtk_recent_manager_get_items (impl->recent_manager);
+-      if (!load_data->items)
+-        return FALSE;
+-
+-      load_data->needs_sorting = TRUE;
+-
+-      return TRUE;
+-    }
+-  
+-  /* second iteration: MRU sorting and clamping, and populating the model */
+-  if (load_data->needs_sorting)
+-    {
+-      load_data->items = g_list_sort (load_data->items, recent_sort_mru);
++    return FALSE;
+ 
+-      if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
+-	populate_model_with_recent_items (impl, load_data->items);
+-      else
+-	populate_model_with_folders (impl, load_data->items);
++  if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
++    populate_model_with_recent_items (impl, load_data->items);
++  else
++    populate_model_with_folders (impl, load_data->items);
+ 
+-      g_list_foreach (load_data->items, (GFunc) gtk_recent_info_unref, NULL);
+-      g_list_free (load_data->items);
+-      load_data->items = NULL;
+-    }
++  g_list_foreach (load_data->items, (GFunc) gtk_recent_info_unref, NULL);
++  g_list_free (load_data->items);
++  load_data->items = NULL;
+ 
+   return FALSE;
+ }
+@@ -9453,7 +9382,6 @@ recent_start_loading (GtkFileChooserDefault *impl)
+   load_data = g_new (RecentLoadData, 1);
+   load_data->impl = impl;
+   load_data->items = NULL;
+-  load_data->needs_sorting = TRUE;
+ 
+   /* begin lazy loading the recent files into the model */
+   impl->load_recent_id = gdk_threads_add_idle_full (G_PRIORITY_HIGH_IDLE + 30,
+@@ -9507,45 +9435,6 @@ recent_should_respond (GtkFileChooserDefault *impl)
+   return (gtk_tree_selection_count_selected_rows (selection) != 0);
+ }
+ 
+-/* Hide the location widgets temporarily */
+-static void
+-recent_hide_entry (GtkFileChooserDefault *impl)
+-{
+-  path_bar_update (impl);
+-
+-  /* Hide the location widgets temporarily */
+-  if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+-      impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+-    {
+-      gtk_widget_hide (impl->location_button);
+-      gtk_widget_hide (impl->location_entry_box);
+-    }
+-}
+-
+-/* Main entry point to the recent files functions; this gets called when
+- * the user activates the Recently Used shortcut.
+- */
+-static void
+-recent_activate (GtkFileChooserDefault *impl)
+-{
+-  OperationMode previous_mode;
+-
+-  if (impl->operation_mode == OPERATION_MODE_RECENT)
+-    return;
+-
+-  previous_mode = impl->operation_mode;
+-  impl->operation_mode = OPERATION_MODE_RECENT;
+-
+-  shortcuts_select_item_without_activating (impl, shortcuts_get_index (impl, SHORTCUTS_RECENT));
+-
+-  stop_operation (impl, previous_mode);
+-
+-  recent_hide_entry (impl);
+-
+-  file_list_set_sort_column_ids (impl);
+-  recent_start_loading (impl);
+-}
+-
+ static void
+ set_current_filter (GtkFileChooserDefault *impl,
+ 		    GtkFileFilter         *filter)
+@@ -9719,17 +9608,7 @@ shortcuts_activate_volume (GtkFileChooserDefault *impl,
+ {
+   GFile *file;
+ 
+-  switch (impl->operation_mode)
+-    {
+-    case OPERATION_MODE_BROWSE:
+-      break;
+-    case OPERATION_MODE_SEARCH:
+-      search_switch_to_browse_mode (impl);
+-      break;
+-    case OPERATION_MODE_RECENT:
+-      recent_switch_to_browse_mode (impl);
+-      break;
+-    }
++  operation_mode_set (impl, OPERATION_MODE_BROWSE);
+ 
+   /* We ref the file chooser since volume_mount() may run a main loop, and the
+    * user could close the file chooser window in the meantime.
+@@ -9836,7 +9715,10 @@ shortcuts_activate_iter (GtkFileChooserDefault *impl,
+   gpointer col_data;
+   ShortcutType shortcut_type;
+ 
+-  if (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY
++  /* In the Save modes, we want to preserve what the uesr typed in the filename
++   * entry, so that he may choose another folder without erasing his typed name.
++   */
++  if (impl->location_entry
+       && !(impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
+ 	   || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER))
+     _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), "");
+@@ -9860,6 +9742,8 @@ shortcuts_activate_iter (GtkFileChooserDefault *impl,
+ 
+       volume = col_data;
+ 
++      operation_mode_set (impl, OPERATION_MODE_BROWSE);
++
+       shortcuts_activate_volume (impl, volume);
+     }
+   else if (shortcut_type == SHORTCUT_TYPE_FILE)
+@@ -9867,6 +9751,8 @@ shortcuts_activate_iter (GtkFileChooserDefault *impl,
+       struct ShortcutsActivateData *data;
+       GtkFileSystemVolume *volume;
+ 
++      operation_mode_set (impl, OPERATION_MODE_BROWSE);
++
+       volume = _gtk_file_system_get_volume_for_file (impl->file_system, col_data);
+ 
+       data = g_new0 (struct ShortcutsActivateData, 1);
+@@ -9898,11 +9784,11 @@ shortcuts_activate_iter (GtkFileChooserDefault *impl,
+     }
+   else if (shortcut_type == SHORTCUT_TYPE_SEARCH)
+     {
+-      search_activate (impl);
++      operation_mode_set (impl, OPERATION_MODE_SEARCH);
+     }
+   else if (shortcut_type == SHORTCUT_TYPE_RECENT)
+     {
+-      recent_activate (impl);
++      operation_mode_set (impl, OPERATION_MODE_RECENT);
+     }
+ }
+ 
+@@ -10163,21 +10049,9 @@ location_popup_handler (GtkFileChooserDefault *impl,
+   if (impl->operation_mode != OPERATION_MODE_BROWSE)
+     {
+       GtkWidget *widget_to_focus;
+-      
+-      /* This will give us the location widgets back */
+-      switch (impl->operation_mode)
+-        {
+-        case OPERATION_MODE_SEARCH:
+-          search_switch_to_browse_mode (impl);
+-          break;
+-        case OPERATION_MODE_RECENT:
+-          recent_switch_to_browse_mode (impl);
+-          break;
+-        case OPERATION_MODE_BROWSE:
+-          g_assert_not_reached ();
+-          break;
+-        }
+ 
++      operation_mode_set (impl, OPERATION_MODE_BROWSE);
++      
+       if (impl->current_folder)
+         change_folder_and_display_error (impl, impl->current_folder, FALSE);
+ 
+@@ -10193,34 +10067,11 @@ location_popup_handler (GtkFileChooserDefault *impl,
+   if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+       impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+     {
+-      LocationMode new_mode;
+-
+-      if (path != NULL)
+-	{
+-	  /* since the user typed something, we unconditionally want to turn on the entry */
+-	  new_mode = LOCATION_MODE_FILENAME_ENTRY;
+-	}
+-      else if (impl->location_mode == LOCATION_MODE_PATH_BAR)
+-	new_mode = LOCATION_MODE_FILENAME_ENTRY;
+-      else if (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY)
+-	new_mode = LOCATION_MODE_PATH_BAR;
+-      else
+-	{
+-	  g_assert_not_reached ();
+-	  return;
+-	}
++      if (!path)
++	return;
+ 
+-      location_mode_set (impl, new_mode, TRUE);
+-      if (new_mode == LOCATION_MODE_FILENAME_ENTRY)
+-	{
+-	  if (path != NULL)
+-	    location_set_user_text (impl, path);
+-	  else
+-	    {
+-	      location_entry_set_initial_text (impl);
+-	      gtk_editable_select_region (GTK_EDITABLE (impl->location_entry), 0, -1);
+-	    }
+-	}
++      location_mode_set (impl, LOCATION_MODE_FILENAME_ENTRY, TRUE);
++      location_set_user_text (impl, path);
+     }
+   else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
+ 	   impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+diff --git a/gtk/gtkfilechooserprivate.h b/gtk/gtkfilechooserprivate.h
+index f5159d1..53f2745 100644
+--- a/gtk/gtkfilechooserprivate.h
++++ b/gtk/gtkfilechooserprivate.h
+@@ -168,6 +168,7 @@ struct _GtkFileChooserDefault
+ 
+   /* The file browsing widgets */
+   GtkWidget *browse_widgets_box;
++  GtkWidget *browse_header_box;
+   GtkWidget *browse_shortcuts_tree_view;
+   GtkWidget *browse_shortcuts_add_button;
+   GtkWidget *browse_shortcuts_remove_button;
+
+
diff --git a/patches/gdk-deadkeys.patch b/patches/0010-Bug-617583-Dead-accents-keys-don-t-work-in-GTK-appli.patch
similarity index 74%
rename from patches/gdk-deadkeys.patch
rename to patches/0010-Bug-617583-Dead-accents-keys-don-t-work-in-GTK-appli.patch
index ff4b953..797f3e9 100644
--- a/patches/gdk-deadkeys.patch
+++ b/patches/0010-Bug-617583-Dead-accents-keys-don-t-work-in-GTK-appli.patch
@@ -1,11 +1,28 @@
---- a/gdk/quartz/gdkkeys-quartz.c	2010-11-27 18:04:40.b/b000000000 -0800
-+++ b/gdk/quartz/gdkkeys-quartz.c	2010-11-28 15:46:42.000000000 -0800
-@@ -182,7 +182,58 @@
+From a601126aa92db1da327298d2bcc94764a356ea52 Mon Sep 17 00:00:00 2001
+From: John Ralls <jralls ceridwen us>
+Date: Fri, 9 Sep 2011 10:12:40 +0200
+Subject: [PATCH 10/15] Bug 617583 - Dead accents keys don't work in GTK+
+ applications on OSX
+
+Handle dead keys in special_ucs_table and have them converted by
+UCKeyTranslate(), so all dead key combinations can be entered.
+Later, this should be handled in the input method, just as it's
+done for X11/Win32.
+---
+ gdk/quartz/gdkkeys-quartz.c |   77 ++++++++++++++++++++++++++++++++++++++++---
+ 1 files changed, 72 insertions(+), 5 deletions(-)
+
+diff --git a/gdk/quartz/gdkkeys-quartz.c b/gdk/quartz/gdkkeys-quartz.c
+index 52b0867..8c7e6f1 100644
+--- a/gdk/quartz/gdkkeys-quartz.c
++++ b/gdk/quartz/gdkkeys-quartz.c
+@@ -182,7 +182,60 @@ const static struct {
    { 0x001d, GDK_Right },
    { 0x001e, GDK_Up },
    { 0x001f, GDK_Down },
 -  { 0x007f, GDK_Delete }
 +  { 0x007f, GDK_Delete },
++  { 0xf027, GDK_dead_acute },
 +  { 0xf060, GDK_dead_grave },
 +  { 0xf300, GDK_dead_grave },
 +  { 0xf0b4, GDK_dead_acute },
@@ -27,6 +44,7 @@
 +  { 0xf308, GDK_dead_diaeresis },
 +  { 0xf2da, GDK_dead_abovering },
 +  { 0xf30A, GDK_dead_abovering },
++  { 0xf022, GDK_dead_doubleacute },
 +  { 0xf2dd, GDK_dead_doubleacute },
 +  { 0xf30B, GDK_dead_doubleacute },
 +  { 0xf2c7, GDK_dead_caron },
@@ -60,7 +78,7 @@
  };
  
  static void
-@@ -330,10 +381,10 @@
+@@ -330,10 +383,10 @@ maybe_update_keymap (void)
  		  UniChar uc;
  		  
  		  key_code = modifiers[j] | i;
@@ -73,17 +91,19 @@
  		                        &state, 4, &nChars, chars);
  
  
-@@ -346,7 +397,21 @@
+@@ -345,8 +398,22 @@ maybe_update_keymap (void)
+ 		    {
  		      int k;
  		      gboolean found = FALSE;
- 		      
+-		      
 -		      uc = chars[0];
++
 +		      /* A few <Shift><Option>keys return two
 +		       * characters, the first of which is U+00a0,
 +		       * which isn't interesting; so we return the
 +		       * second. More sophisticated handling is the
 +		       * job of a GtkIMContext.
-+		       
++		       *
 +		       * If state isn't zero, it means that it's a
 +		       * dead key of some sort. Some of those are
 +		       * enumerated in the special_ucs_table with the
@@ -91,8 +111,9 @@
 +		       * private use range. Here we do the same.
 +		       */
 +		      if (state != 0)
-+			  chars[nChars - 1] |= 0xf000;
++			chars[nChars - 1] |= 0xf000;
 +		      uc = chars[nChars - 1];
  
  		      for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++) 
  			{
+
diff --git a/patches/0011-bgo-514843-filechooser-Deal-with-corrupted-.gtk-book.patch b/patches/0011-bgo-514843-filechooser-Deal-with-corrupted-.gtk-book.patch
new file mode 100644
index 0000000..a323019
--- /dev/null
+++ b/patches/0011-bgo-514843-filechooser-Deal-with-corrupted-.gtk-book.patch
@@ -0,0 +1,57 @@
+From 996c6b0cb4cfbc9cf98bafd32cbb4080452d4ffa Mon Sep 17 00:00:00 2001
+From: John Ralls <jralls ceridwen us>
+Date: Mon, 12 Sep 2011 14:25:45 -0500
+Subject: [PATCH 11/15] bgo#514843 - [filechooser] Deal with corrupted
+ .gtk-bookmarks gracefully
+
+We weren't checking for the lines in that file being valid UTF-8 strings.
+---
+ gtk/gtkfilesystem.c |   13 +++++++++----
+ 1 files changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/gtk/gtkfilesystem.c b/gtk/gtkfilesystem.c
+index 6e7be3c..f2897d2 100644
+--- a/gtk/gtkfilesystem.c
++++ b/gtk/gtkfilesystem.c
+@@ -272,6 +272,9 @@ read_bookmarks (GFile *file)
+       if (!*lines[i])
+ 	continue;
+ 
++      if (!g_utf8_validate (lines[i], -1, NULL))
++	continue;
++
+       bookmark = g_slice_new0 (GtkFileSystemBookmark);
+ 
+       if ((space = strchr (lines[i], ' ')) != NULL)
+@@ -297,23 +300,25 @@ save_bookmarks (GFile  *bookmarks_file,
+ {
+   GError *error = NULL;
+   GString *contents;
++  GSList *l;
+ 
+   contents = g_string_new ("");
+ 
+-  while (bookmarks)
++  for (l = bookmarks; l; l = l->next)
+     {
+-      GtkFileSystemBookmark *bookmark;
++      GtkFileSystemBookmark *bookmark = l->data;
+       gchar *uri;
+ 
+-      bookmark = bookmarks->data;
+       uri = g_file_get_uri (bookmark->file);
++      if (!uri)
++	continue;
++
+       g_string_append (contents, uri);
+ 
+       if (bookmark->label)
+ 	g_string_append_printf (contents, " %s", bookmark->label);
+ 
+       g_string_append_c (contents, '\n');
+-      bookmarks = bookmarks->next;
+       g_free (uri);
+     }
+ 
+
+
diff --git a/patches/0012-Bug-605799-Option-MOD1-and-Command-SUPER-modifiers-a.patch b/patches/0012-Bug-605799-Option-MOD1-and-Command-SUPER-modifiers-a.patch
new file mode 100644
index 0000000..63f21f9
--- /dev/null
+++ b/patches/0012-Bug-605799-Option-MOD1-and-Command-SUPER-modifiers-a.patch
@@ -0,0 +1,835 @@
+From 2123991148d68ca1d0ea451b8bbc58306d0378c9 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch lanedo com>
+Date: Fri, 16 Sep 2011 15:39:23 +0200
+Subject: [PATCH 12/15] Bug 605799 - Option (MOD1) and Command (SUPER)
+ modifiers are switched
+
+- maps Alt/Option to MOD1 as on all other platforms
+- maps Command to MOD2
+- maps MOD2 to the virtual META
+- fixes (?) group handling in gdkkeys-quartz.c
+- fixes text input by adding GTK_NO_TEXT_INPUT_MOD_MASK instead
+  of hardcoding something that doesn't match a Mac
+- disables mnemonics
+- sets the default accel modifier to META on quartz
+- adds <Primary> as possible modifier to GtkAccelGroup which
+  automatically maps to Control or Meta, depending on the platform
+- fixes GtkCellRendererAccel to recognize virtual modifiers
+- changes default stock items to GTK_NO_TEXT_INPUT_MOD_MASK instead
+  of hardcoding GDK_CONTROL_MASK
+---
+ gdk/quartz/gdkevents-quartz.c |    8 +++--
+ gdk/quartz/gdkkeys-quartz.c   |   18 +++++++---
+ gtk/gtkaccelgroup.c           |   36 ++++++++++++++++++++
+ gtk/gtkcellrendereraccel.c    |    5 ++-
+ gtk/gtkentry.c                |    2 +-
+ gtk/gtkfilechooserdefault.c   |    7 +---
+ gtk/gtkiconview.c             |   46 +++++++++++++-------------
+ gtk/gtkimcontextsimple.c      |    2 +-
+ gtk/gtkimmulticontext.c       |    2 +-
+ gtk/gtkprivate.h              |   18 ++++++++++
+ gtk/gtkrc.key.mac             |    2 +
+ gtk/gtkstock.c                |   23 +++++++------
+ gtk/gtktextview.c             |    4 +-
+ gtk/gtktreeprivate.h          |    8 ++--
+ gtk/gtktreeview.c             |   74 ++++++++++++++++++++--------------------
+ 15 files changed, 161 insertions(+), 94 deletions(-)
+
+diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
+index 9e27329..4625070 100644
+--- a/gdk/quartz/gdkevents-quartz.c
++++ b/gdk/quartz/gdkevents-quartz.c
+@@ -271,8 +271,10 @@ get_keyboard_modifiers_from_ns_event (NSEvent *nsevent)
+     modifiers |= GDK_SHIFT_MASK;
+   if (nsflags & NSControlKeyMask)
+     modifiers |= GDK_CONTROL_MASK;
+-  if (nsflags & NSCommandKeyMask)
++  if (nsflags & NSAlternateKeyMask)
+     modifiers |= GDK_MOD1_MASK;
++  if (nsflags & NSCommandKeyMask)
++    modifiers |= GDK_MOD2_MASK;
+ 
+   return modifiers;
+ }
+@@ -908,7 +910,7 @@ fill_key_event (GdkWindow    *window,
+         {
+         case GDK_Meta_R:
+         case GDK_Meta_L:
+-          mask = GDK_MOD1_MASK;
++          mask = GDK_MOD2_MASK;
+           break;
+         case GDK_Shift_R:
+         case GDK_Shift_L:
+@@ -919,7 +921,7 @@ fill_key_event (GdkWindow    *window,
+           break;
+         case GDK_Alt_R:
+         case GDK_Alt_L:
+-          mask = GDK_MOD5_MASK;
++          mask = GDK_MOD1_MASK;
+           break;
+         case GDK_Control_R:
+         case GDK_Control_L:
+diff --git a/gdk/quartz/gdkkeys-quartz.c b/gdk/quartz/gdkkeys-quartz.c
+index 8c7e6f1..9fffc70 100644
+--- a/gdk/quartz/gdkkeys-quartz.c
++++ b/gdk/quartz/gdkkeys-quartz.c
+@@ -547,8 +547,8 @@ gdk_keymap_get_entries_for_keyval (GdkKeymap     *keymap,
+       (*n_keys)++;
+ 
+       key.keycode = i / KEYVALS_PER_KEYCODE;
+-      key.group = 0;
+-      key.level = i % KEYVALS_PER_KEYCODE;
++      key.group = (i % KEYVALS_PER_KEYCODE) >= 2;
++      key.level = i % 2;
+ 
+       g_array_append_val (keys_array, key);
+     }
+@@ -606,7 +606,7 @@ gdk_keymap_get_entries_for_keycode (GdkKeymap     *keymap,
+ 	  GdkKeymapKey key;
+ 
+ 	  key.keycode = hardware_keycode;
+-	  key.group = i / 2;
++	  key.group = i >= 2;
+ 	  key.level = i % 2;
+ 
+ 	  g_array_append_val (keys_array, key);
+@@ -666,6 +666,11 @@ translate_keysym (guint           hardware_keycode,
+         tmp_keyval = upper;
+     }
+ 
++  if (effective_group)
++    *effective_group = group;
++  if (effective_level)
++    *effective_level = level;
++
+   return tmp_keyval;
+ }
+ 
+@@ -723,14 +728,17 @@ void
+ gdk_keymap_add_virtual_modifiers (GdkKeymap       *keymap,
+                                   GdkModifierType *state)
+ {
+-  /* FIXME: For now, we've mimiced the Windows backend. */
++  if (*state & GDK_MOD2_MASK)
++    *state |= GDK_META_MASK;
+ }
+ 
+ gboolean
+ gdk_keymap_map_virtual_modifiers (GdkKeymap       *keymap,
+                                   GdkModifierType *state)
+ {
+-  /* FIXME: For now, we've mimiced the Windows backend. */
++  if (*state & GDK_META_MASK)
++    *state |= GDK_MOD2_MASK;
++
+   return TRUE;
+ }
+ 
+diff --git a/gtk/gtkaccelgroup.c b/gtk/gtkaccelgroup.c
+index 4c21943..eb2a937 100644
+--- a/gtk/gtkaccelgroup.c
++++ b/gtk/gtkaccelgroup.c
+@@ -35,6 +35,7 @@
+ #include "gtkmain.h"		/* For _gtk_boolean_handled_accumulator */
+ #include "gdk/gdkkeysyms.h"
+ #include "gtkmarshalers.h"
++#include "gtkprivate.h"
+ #include "gtkalias.h"
+ 
+ /**
+@@ -1121,6 +1122,20 @@ is_hyper (const gchar *string)
+ 	  (string[6] == '>'));
+ }
+ 
++static inline gboolean
++is_primary (const gchar *string)
++{
++  return ((string[0] == '<') &&
++	  (string[1] == 'p' || string[1] == 'P') &&
++	  (string[2] == 'r' || string[2] == 'R') &&
++	  (string[3] == 'i' || string[3] == 'I') &&
++	  (string[4] == 'm' || string[4] == 'M') &&
++	  (string[5] == 'a' || string[5] == 'A') &&
++	  (string[6] == 'r' || string[6] == 'R') &&
++	  (string[7] == 'y' || string[7] == 'Y') &&
++	  (string[8] == '>'));
++}
++
+ /**
+  * gtk_accelerator_parse:
+  * @accelerator:      string representing an accelerator
+@@ -1167,6 +1182,12 @@ gtk_accelerator_parse (const gchar     *accelerator,
+ 	      len -= 9;
+ 	      mods |= GDK_RELEASE_MASK;
+ 	    }
++	  else if (len >= 9 && is_primary (accelerator))
++	    {
++	      accelerator += 9;
++	      len -= 9;
++	      mods |= GTK_DEFAULT_ACCEL_MOD_MASK;
++	    }
+ 	  else if (len >= 9 && is_control (accelerator))
+ 	    {
+ 	      accelerator += 9;
+@@ -1280,6 +1301,7 @@ gtk_accelerator_name (guint           accelerator_key,
+ 		      GdkModifierType accelerator_mods)
+ {
+   static const gchar text_release[] = "<Release>";
++  static const gchar text_primary[] = "<Primary>";
+   static const gchar text_shift[] = "<Shift>";
+   static const gchar text_control[] = "<Control>";
+   static const gchar text_mod1[] = "<Alt>";
+@@ -1290,6 +1312,7 @@ gtk_accelerator_name (guint           accelerator_key,
+   static const gchar text_meta[] = "<Meta>";
+   static const gchar text_super[] = "<Super>";
+   static const gchar text_hyper[] = "<Hyper>";
++  GdkModifierType saved_mods;
+   guint l;
+   gchar *keyval_name;
+   gchar *accelerator;
+@@ -1300,9 +1323,15 @@ gtk_accelerator_name (guint           accelerator_key,
+   if (!keyval_name)
+     keyval_name = "";
+ 
++  saved_mods = accelerator_mods;
+   l = 0;
+   if (accelerator_mods & GDK_RELEASE_MASK)
+     l += sizeof (text_release) - 1;
++  if (accelerator_mods & GTK_DEFAULT_ACCEL_MOD_MASK)
++    {
++      l += sizeof (text_primary) - 1;
++      accelerator_mods &= ~GTK_DEFAULT_ACCEL_MOD_MASK; /* consume the default accel */
++    }
+   if (accelerator_mods & GDK_SHIFT_MASK)
+     l += sizeof (text_shift) - 1;
+   if (accelerator_mods & GDK_CONTROL_MASK)
+@@ -1327,6 +1356,7 @@ gtk_accelerator_name (guint           accelerator_key,
+ 
+   accelerator = g_new (gchar, l + 1);
+ 
++  accelerator_mods = saved_mods;
+   l = 0;
+   accelerator[l] = 0;
+   if (accelerator_mods & GDK_RELEASE_MASK)
+@@ -1334,6 +1364,12 @@ gtk_accelerator_name (guint           accelerator_key,
+       strcpy (accelerator + l, text_release);
+       l += sizeof (text_release) - 1;
+     }
++  if (accelerator_mods & GTK_DEFAULT_ACCEL_MOD_MASK)
++    {
++      strcpy (accelerator + l, text_primary);
++      l += sizeof (text_primary) - 1;
++      accelerator_mods &= ~GTK_DEFAULT_ACCEL_MOD_MASK; /* consume the default accel */
++    }
+   if (accelerator_mods & GDK_SHIFT_MASK)
+     {
+       strcpy (accelerator + l, text_shift);
+diff --git a/gtk/gtkcellrendereraccel.c b/gtk/gtkcellrendereraccel.c
+index dedbfda..846b1ec 100644
+--- a/gtk/gtkcellrendereraccel.c
++++ b/gtk/gtkcellrendereraccel.c
+@@ -427,11 +427,14 @@ grab_key_callback (GtkWidget            *widget,
+                                        event->group,
+ 				       NULL, NULL, NULL, &consumed_modifiers);
+ 
++  accel_mods = event->state;
++  gdk_keymap_add_virtual_modifiers (gdk_keymap_get_for_display (display), &accel_mods);
++
+   accel_key = gdk_keyval_to_lower (event->keyval);
+   if (accel_key == GDK_ISO_Left_Tab) 
+     accel_key = GDK_Tab;
+ 
+-  accel_mods = event->state & gtk_accelerator_get_default_mod_mask ();
++  accel_mods &= gtk_accelerator_get_default_mod_mask ();
+ 
+   /* Filter consumed modifiers 
+    */
+diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c
+index 0a833cf..8e2c2b2 100644
+--- a/gtk/gtkentry.c
++++ b/gtk/gtkentry.c
+@@ -3696,7 +3696,7 @@ gtk_entry_button_press (GtkWidget      *widget,
+       entry->select_words = FALSE;
+       entry->select_lines = FALSE;
+ 
+-      if (event->state & GDK_SHIFT_MASK)
++      if (event->state & GTK_EXTEND_SELECTION_MOD_MASK)
+ 	{
+ 	  _gtk_entry_reset_im_context (entry);
+ 	  
+diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c
+index 9e636c2..44c2d17 100644
+--- a/gtk/gtkfilechooserdefault.c
++++ b/gtk/gtkfilechooserdefault.c
+@@ -3687,18 +3687,15 @@ browse_files_key_press_event_cb (GtkWidget   *widget,
+ 				 gpointer     data)
+ {
+   GtkFileChooserDefault *impl;
+-  int modifiers;
+ 
+   impl = (GtkFileChooserDefault *) data;
+ 
+-  modifiers = gtk_accelerator_get_default_mod_mask ();
+-
+   if ((event->keyval == GDK_KEY_slash
+        || event->keyval == GDK_KEY_KP_Divide
+ #ifdef G_OS_UNIX
+        || event->keyval == GDK_KEY_asciitilde
+ #endif
+-       ) && ! (event->state & (~GDK_SHIFT_MASK & modifiers)))
++       ) && !(event->state & GTK_NO_TEXT_INPUT_MOD_MASK))
+     {
+       location_popup_handler (impl, event->string);
+       return TRUE;
+@@ -3715,7 +3712,7 @@ browse_files_key_press_event_cb (GtkWidget   *widget,
+        || event->keyval == GDK_KEY_KP_Enter
+        || event->keyval == GDK_KEY_space
+        || event->keyval == GDK_KEY_KP_Space)
+-      && ((event->state & modifiers) == 0)
++      && !(event->state & gtk_accelerator_get_default_mod_mask ())
+       && !(impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
+ 	   impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER))
+     {
+diff --git a/gtk/gtkiconview.c b/gtk/gtkiconview.c
+index 8ce402f..54b3f3b 100644
+--- a/gtk/gtkiconview.c
++++ b/gtk/gtkiconview.c
+@@ -183,8 +183,8 @@ struct _GtkIconViewPrivate
+   guint reorderable : 1;
+   guint empty_view_drop :1;
+ 
+-  guint ctrl_pressed : 1;
+-  guint shift_pressed : 1;
++  guint modify_selection_pressed : 1;
++  guint extend_selection_pressed : 1;
+ 
+   guint draw_focus : 1;
+ };
+@@ -2177,7 +2177,7 @@ gtk_icon_view_button_press (GtkWidget      *widget,
+ 	      gtk_icon_view_set_cursor_item (icon_view, item, cursor_cell);
+ 	    }
+ 	  else if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE &&
+-		   (event->state & GDK_SHIFT_MASK))
++		   (event->state & GTK_EXTEND_SELECTION_MOD_MASK))
+ 	    {
+ 	      gtk_icon_view_unselect_all_internal (icon_view);
+ 
+@@ -2194,7 +2194,7 @@ gtk_icon_view_button_press (GtkWidget      *widget,
+ 	    {
+ 	      if ((icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE ||
+ 		  ((icon_view->priv->selection_mode == GTK_SELECTION_SINGLE) && item->selected)) &&
+-		  (event->state & GDK_CONTROL_MASK))
++		  (event->state & GTK_MODIFY_SELECTION_MOD_MASK))
+ 		{
+ 		  item->selected = !item->selected;
+ 		  gtk_icon_view_queue_draw_item (icon_view, item);
+@@ -2239,7 +2239,7 @@ gtk_icon_view_button_press (GtkWidget      *widget,
+       else
+ 	{
+ 	  if (icon_view->priv->selection_mode != GTK_SELECTION_BROWSE &&
+-	      !(event->state & GDK_CONTROL_MASK))
++	      !(event->state & GTK_MODIFY_SELECTION_MOD_MASK))
+ 	    {
+ 	      dirty = gtk_icon_view_unselect_all_internal (icon_view);
+ 	    }
+@@ -3856,10 +3856,10 @@ gtk_icon_view_real_move_cursor (GtkIconView     *icon_view,
+ 
+   if (gtk_get_current_event_state (&state))
+     {
+-      if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
+-        icon_view->priv->ctrl_pressed = TRUE;
+-      if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
+-        icon_view->priv->shift_pressed = TRUE;
++      if ((state & GTK_MODIFY_SELECTION_MOD_MASK) == GTK_MODIFY_SELECTION_MOD_MASK)
++        icon_view->priv->modify_selection_pressed = TRUE;
++      if ((state & GTK_EXTEND_SELECTION_MOD_MASK) == GTK_EXTEND_SELECTION_MOD_MASK)
++        icon_view->priv->extend_selection_pressed = TRUE;
+     }
+   /* else we assume not pressed */
+ 
+@@ -3882,8 +3882,8 @@ gtk_icon_view_real_move_cursor (GtkIconView     *icon_view,
+       g_assert_not_reached ();
+     }
+ 
+-  icon_view->priv->ctrl_pressed = FALSE;
+-  icon_view->priv->shift_pressed = FALSE;
++  icon_view->priv->modify_selection_pressed = FALSE;
++  icon_view->priv->extend_selection_pressed = FALSE;
+ 
+   icon_view->priv->draw_focus = TRUE;
+ 
+@@ -4154,15 +4154,15 @@ gtk_icon_view_move_cursor_up_down (GtkIconView *icon_view,
+       return;
+     }
+ 
+-  if (icon_view->priv->ctrl_pressed ||
+-      !icon_view->priv->shift_pressed ||
++  if (icon_view->priv->modify_selection_pressed ||
++      !icon_view->priv->extend_selection_pressed ||
+       !icon_view->priv->anchor_item ||
+       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
+     icon_view->priv->anchor_item = item;
+ 
+   gtk_icon_view_set_cursor_item (icon_view, item, cell);
+ 
+-  if (!icon_view->priv->ctrl_pressed &&
++  if (!icon_view->priv->modify_selection_pressed &&
+       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
+     {
+       dirty = gtk_icon_view_unselect_all_internal (icon_view);
+@@ -4209,15 +4209,15 @@ gtk_icon_view_move_cursor_page_up_down (GtkIconView *icon_view,
+   if (!item)
+     return;
+ 
+-  if (icon_view->priv->ctrl_pressed ||
+-      !icon_view->priv->shift_pressed ||
++  if (icon_view->priv->modify_selection_pressed ||
++      !icon_view->priv->extend_selection_pressed ||
+       !icon_view->priv->anchor_item ||
+       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
+     icon_view->priv->anchor_item = item;
+ 
+   gtk_icon_view_set_cursor_item (icon_view, item, -1);
+ 
+-  if (!icon_view->priv->ctrl_pressed &&
++  if (!icon_view->priv->modify_selection_pressed &&
+       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
+     {
+       dirty = gtk_icon_view_unselect_all_internal (icon_view);
+@@ -4291,15 +4291,15 @@ gtk_icon_view_move_cursor_left_right (GtkIconView *icon_view,
+       return;
+     }
+ 
+-  if (icon_view->priv->ctrl_pressed ||
+-      !icon_view->priv->shift_pressed ||
++  if (icon_view->priv->modify_selection_pressed ||
++      !icon_view->priv->extend_selection_pressed ||
+       !icon_view->priv->anchor_item ||
+       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
+     icon_view->priv->anchor_item = item;
+ 
+   gtk_icon_view_set_cursor_item (icon_view, item, cell);
+ 
+-  if (!icon_view->priv->ctrl_pressed &&
++  if (!icon_view->priv->modify_selection_pressed &&
+       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
+     {
+       dirty = gtk_icon_view_unselect_all_internal (icon_view);
+@@ -4338,15 +4338,15 @@ gtk_icon_view_move_cursor_start_end (GtkIconView *icon_view,
+   if (!item)
+     return;
+ 
+-  if (icon_view->priv->ctrl_pressed ||
+-      !icon_view->priv->shift_pressed ||
++  if (icon_view->priv->modify_selection_pressed ||
++      !icon_view->priv->extend_selection_pressed ||
+       !icon_view->priv->anchor_item ||
+       icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
+     icon_view->priv->anchor_item = item;
+ 
+   gtk_icon_view_set_cursor_item (icon_view, item, -1);
+ 
+-  if (!icon_view->priv->ctrl_pressed &&
++  if (!icon_view->priv->modify_selection_pressed &&
+       icon_view->priv->selection_mode != GTK_SELECTION_NONE)
+     {
+       dirty = gtk_icon_view_unselect_all_internal (icon_view);
+diff --git a/gtk/gtkimcontextsimple.c b/gtk/gtkimcontextsimple.c
+index 9ef18a9..d496166 100644
+--- a/gtk/gtkimcontextsimple.c
++++ b/gtk/gtkimcontextsimple.c
+@@ -871,7 +871,7 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context,
+       (context_simple->in_hex_sequence && !hex_keyval && 
+        !is_hex_start && !is_hex_end && !is_escape && !is_backspace))
+     {
+-      if (event->state & (GDK_MOD1_MASK | GDK_CONTROL_MASK) ||
++      if (event->state & GTK_NO_TEXT_INPUT_MOD_MASK ||
+ 	  (context_simple->in_hex_sequence && context_simple->modifiers_dropped &&
+ 	   (event->keyval == GDK_Return || 
+ 	    event->keyval == GDK_ISO_Enter ||
+diff --git a/gtk/gtkimmulticontext.c b/gtk/gtkimmulticontext.c
+index 6185667..34f34b6 100644
+--- a/gtk/gtkimmulticontext.c
++++ b/gtk/gtkimmulticontext.c
+@@ -330,7 +330,7 @@ gtk_im_multicontext_filter_keypress (GtkIMContext *context,
+   if (slave)
+     return gtk_im_context_filter_keypress (slave, event);
+   else if (event->type == GDK_KEY_PRESS &&
+-           (event->state & (GDK_MOD1_MASK | GDK_CONTROL_MASK)) == 0)
++           (event->state & GTK_NO_TEXT_INPUT_MOD_MASK) == 0)
+     {
+       gunichar ch;
+ 
+diff --git a/gtk/gtkprivate.h b/gtk/gtkprivate.h
+index 3933dc5..00440cb 100644
+--- a/gtk/gtkprivate.h
++++ b/gtk/gtkprivate.h
+@@ -112,6 +112,24 @@ gboolean _gtk_fnmatch (const char *pattern,
+ #define GTK_DEFAULT_ACCEL_MOD_MASK GDK_META_MASK
+ #endif
+ 
++/* When any of these modifiers are active, a key
++ * event cannot produce a symbol, so should be
++ * skipped when handling text input
++ */
++#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)
++#endif
++
++#ifndef GDK_WINDOWING_QUARTZ
++#define GTK_EXTEND_SELECTION_MOD_MASK GDK_SHIFT_MASK
++#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
++#endif
++
+ G_END_DECLS
+ 
+ #endif /* __GTK_PRIVATE_H__ */
+diff --git a/gtk/gtkrc.key.mac b/gtk/gtkrc.key.mac
+index 7b6e8d1..5389ffe 100644
+--- a/gtk/gtkrc.key.mac
++++ b/gtk/gtkrc.key.mac
+@@ -1,3 +1,5 @@
++gtk-enable-mnemonics = 0
++
+ binding "gtk-mac-alt-arrows"
+ {
+   bind "<alt>Right"           { "move-cursor" (words, 1, 0) }
+diff --git a/gtk/gtkstock.c b/gtk/gtkstock.c
+index 66b0ed5..5cb64ec 100644
+--- a/gtk/gtkstock.c
++++ b/gtk/gtkstock.c
+@@ -32,6 +32,7 @@
+ #include "gtkiconfactory.h"
+ #include "gtkintl.h"
+ #include <gdk/gdkkeysyms.h>
++#include "gtkprivate.h"
+ #include "gtkalias.h"
+ 
+ /**
+@@ -326,18 +327,18 @@ static const GtkStockItem builtin_items [] =
+   { GTK_STOCK_CANCEL, NC_("Stock label", "_Cancel"), 0, 0, GETTEXT_PACKAGE },
+   { GTK_STOCK_CDROM, NC_("Stock label", "_CD-Rom"), 0, 0, GETTEXT_PACKAGE },
+   { GTK_STOCK_CLEAR, NC_("Stock label", "_Clear"), 0, 0, GETTEXT_PACKAGE },
+-  { GTK_STOCK_CLOSE, NC_("Stock label", "_Close"), GDK_CONTROL_MASK, 'w', GETTEXT_PACKAGE },
++  { GTK_STOCK_CLOSE, NC_("Stock label", "_Close"), GTK_DEFAULT_ACCEL_MOD_MASK, 'w', GETTEXT_PACKAGE },
+   { GTK_STOCK_CONNECT, NC_("Stock label", "C_onnect"), 0, 0, GETTEXT_PACKAGE },
+   { GTK_STOCK_CONVERT, NC_("Stock label", "_Convert"), 0, 0, GETTEXT_PACKAGE },
+-   { GTK_STOCK_COPY, NC_("Stock label", "_Copy"), GDK_CONTROL_MASK, 'c', GETTEXT_PACKAGE },
+-  { GTK_STOCK_CUT, NC_("Stock label", "Cu_t"), GDK_CONTROL_MASK, 'x', GETTEXT_PACKAGE },
++   { GTK_STOCK_COPY, NC_("Stock label", "_Copy"), GTK_DEFAULT_ACCEL_MOD_MASK, 'c', GETTEXT_PACKAGE },
++  { GTK_STOCK_CUT, NC_("Stock label", "Cu_t"), GTK_DEFAULT_ACCEL_MOD_MASK, 'x', GETTEXT_PACKAGE },
+   { GTK_STOCK_DELETE, NC_("Stock label", "_Delete"), 0, 0, GETTEXT_PACKAGE },
+   { GTK_STOCK_DISCARD, NC_("Stock label", "_Discard"), 0, 0, GETTEXT_PACKAGE },
+   { GTK_STOCK_DISCONNECT, NC_("Stock label", "_Disconnect"), 0, 0, GETTEXT_PACKAGE },
+   { GTK_STOCK_EXECUTE, NC_("Stock label", "_Execute"), 0, 0, GETTEXT_PACKAGE },
+   { GTK_STOCK_EDIT, NC_("Stock label", "_Edit"), 0, 0, GETTEXT_PACKAGE },
+-  { GTK_STOCK_FIND, NC_("Stock label", "_Find"), GDK_CONTROL_MASK, 'f', GETTEXT_PACKAGE },
+-  { GTK_STOCK_FIND_AND_REPLACE, NC_("Stock label", "Find and _Replace"), GDK_CONTROL_MASK, 'r', GETTEXT_PACKAGE },
++  { GTK_STOCK_FIND, NC_("Stock label", "_Find"), GTK_DEFAULT_ACCEL_MOD_MASK, 'f', GETTEXT_PACKAGE },
++  { GTK_STOCK_FIND_AND_REPLACE, NC_("Stock label", "Find and _Replace"), GTK_DEFAULT_ACCEL_MOD_MASK, 'r', GETTEXT_PACKAGE },
+   { GTK_STOCK_FLOPPY, NC_("Stock label", "_Floppy"), 0, 0, GETTEXT_PACKAGE },
+   { GTK_STOCK_FULLSCREEN, NC_("Stock label", "_Fullscreen"), 0, 0, GETTEXT_PACKAGE },
+   { GTK_STOCK_LEAVE_FULLSCREEN, NC_("Stock label", "_Leave Fullscreen"), 0, 0, GETTEXT_PACKAGE },
+@@ -358,7 +359,7 @@ static const GtkStockItem builtin_items [] =
+   /* This is a navigation label as in "go up" */
+   { GTK_STOCK_GO_UP, NC_("Stock label, navigation", "_Up"), 0, 0, GETTEXT_PACKAGE "-navigation" },
+   { GTK_STOCK_HARDDISK, NC_("Stock label", "_Harddisk"), 0, 0, GETTEXT_PACKAGE },
+-  { GTK_STOCK_HELP, NC_("Stock label", "_Help"), GDK_CONTROL_MASK, 'h', GETTEXT_PACKAGE },
++  { GTK_STOCK_HELP, NC_("Stock label", "_Help"), GTK_DEFAULT_ACCEL_MOD_MASK, 'h', GETTEXT_PACKAGE },
+   { GTK_STOCK_HOME, NC_("Stock label", "_Home"), 0, 0, GETTEXT_PACKAGE },
+   { GTK_STOCK_INDENT, NC_("Stock label", "Increase Indent"), 0, 0, GETTEXT_PACKAGE },
+   { GTK_STOCK_UNINDENT, NC_("Stock label", "Decrease Indent"), 0, 0, GETTEXT_PACKAGE },
+@@ -392,10 +393,10 @@ static const GtkStockItem builtin_items [] =
+   /* Media label */
+   { GTK_STOCK_MEDIA_STOP, NC_("Stock label, media", "_Stop"), 0, 0, GETTEXT_PACKAGE "-media" },
+   { GTK_STOCK_NETWORK, NC_("Stock label", "_Network"), 0, 0, GETTEXT_PACKAGE },
+-  { GTK_STOCK_NEW, NC_("Stock label", "_New"), GDK_CONTROL_MASK, 'n', GETTEXT_PACKAGE },
++  { GTK_STOCK_NEW, NC_("Stock label", "_New"), GTK_DEFAULT_ACCEL_MOD_MASK, 'n', GETTEXT_PACKAGE },
+   { GTK_STOCK_NO, NC_("Stock label", "_No"), 0, 0, GETTEXT_PACKAGE },
+   { GTK_STOCK_OK, NC_("Stock label", "_OK"), 0, 0, GETTEXT_PACKAGE },
+-  { GTK_STOCK_OPEN, NC_("Stock label", "_Open"), GDK_CONTROL_MASK, 'o', GETTEXT_PACKAGE },
++  { GTK_STOCK_OPEN, NC_("Stock label", "_Open"), GTK_DEFAULT_ACCEL_MOD_MASK, 'o', GETTEXT_PACKAGE },
+   /* Page orientation */
+   { GTK_STOCK_ORIENTATION_LANDSCAPE, NC_("Stock label", "Landscape"), 0, 0, GETTEXT_PACKAGE },
+   /* Page orientation */
+@@ -405,17 +406,17 @@ static const GtkStockItem builtin_items [] =
+   /* Page orientation */
+   { GTK_STOCK_ORIENTATION_REVERSE_PORTRAIT, NC_("Stock label", "Reverse portrait"), 0, 0, GETTEXT_PACKAGE },
+   { GTK_STOCK_PAGE_SETUP, NC_("Stock label", "Page Set_up"), 0, 0, GETTEXT_PACKAGE },
+-  { GTK_STOCK_PASTE, NC_("Stock label", "_Paste"), GDK_CONTROL_MASK, 'v', GETTEXT_PACKAGE },
++  { GTK_STOCK_PASTE, NC_("Stock label", "_Paste"), GTK_DEFAULT_ACCEL_MOD_MASK, 'v', GETTEXT_PACKAGE },
+   { GTK_STOCK_PREFERENCES, NC_("Stock label", "_Preferences"), 0, 0, GETTEXT_PACKAGE },
+   { GTK_STOCK_PRINT, NC_("Stock label", "_Print"), 0, 0, GETTEXT_PACKAGE },
+   { GTK_STOCK_PRINT_PREVIEW, NC_("Stock label", "Print Pre_view"), 0, 0, GETTEXT_PACKAGE },
+   { GTK_STOCK_PROPERTIES, NC_("Stock label", "_Properties"), 0, 0, GETTEXT_PACKAGE },
+-  { GTK_STOCK_QUIT, NC_("Stock label", "_Quit"), GDK_CONTROL_MASK, 'q', GETTEXT_PACKAGE },
++  { GTK_STOCK_QUIT, NC_("Stock label", "_Quit"), GTK_DEFAULT_ACCEL_MOD_MASK, 'q', GETTEXT_PACKAGE },
+   { GTK_STOCK_REDO, NC_("Stock label", "_Redo"), 0, 0, GETTEXT_PACKAGE },
+   { GTK_STOCK_REFRESH, NC_("Stock label", "_Refresh"), 0, 0, GETTEXT_PACKAGE },
+   { GTK_STOCK_REMOVE, NC_("Stock label", "_Remove"), 0, 0, GETTEXT_PACKAGE },
+   { GTK_STOCK_REVERT_TO_SAVED, NC_("Stock label", "_Revert"), 0, 0, GETTEXT_PACKAGE },
+-  { GTK_STOCK_SAVE, NC_("Stock label", "_Save"), GDK_CONTROL_MASK, 's', GETTEXT_PACKAGE },
++  { GTK_STOCK_SAVE, NC_("Stock label", "_Save"), GTK_DEFAULT_ACCEL_MOD_MASK, 's', GETTEXT_PACKAGE },
+   { GTK_STOCK_SAVE_AS, NC_("Stock label", "Save _As"), 0, 0, GETTEXT_PACKAGE },
+   { GTK_STOCK_SELECT_ALL, NC_("Stock label", "Select _All"), 0, 0, GETTEXT_PACKAGE },
+   { GTK_STOCK_SELECT_COLOR, NC_("Stock label", "_Color"), 0, 0, GETTEXT_PACKAGE },
+diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c
+index 57316f6..2061b5b 100644
+--- a/gtk/gtktextview.c
++++ b/gtk/gtktextview.c
+@@ -4368,7 +4368,7 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
+           if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
+                                                     &start, &end) &&
+               gtk_text_iter_in_range (&iter, &start, &end) &&
+-              !(event->state & GDK_SHIFT_MASK))
++              !(event->state & GTK_EXTEND_SELECTION_MOD_MASK))
+             {
+               text_view->drag_start_x = event->x;
+               text_view->drag_start_y = event->y;
+@@ -6295,7 +6295,7 @@ gtk_text_view_start_selection_drag (GtkTextView       *text_view,
+   orig_start = ins;
+   orig_end = bound;
+ 
+-  if (button->state & GDK_SHIFT_MASK)
++  if (button->state & GTK_EXTEND_SELECTION_MOD_MASK)
+     {
+       /* Extend selection */
+       GtkTextIter old_ins, old_bound;
+diff --git a/gtk/gtktreeprivate.h b/gtk/gtktreeprivate.h
+index acd6d69..82c52da 100644
+--- a/gtk/gtktreeprivate.h
++++ b/gtk/gtktreeprivate.h
+@@ -211,8 +211,8 @@ struct _GtkTreeViewPrivate
+   gint rubber_band_status;
+   gint rubber_band_x;
+   gint rubber_band_y;
+-  gint rubber_band_shift;
+-  gint rubber_band_ctrl;
++  gint rubber_band_extend;
++  gint rubber_band_modify;
+ 
+   GtkRBNode *rubber_band_start_node;
+   GtkRBTree *rubber_band_start_tree;
+@@ -276,8 +276,8 @@ struct _GtkTreeViewPrivate
+   /* for DnD */
+   guint empty_view_drop : 1;
+ 
+-  guint ctrl_pressed : 1;
+-  guint shift_pressed : 1;
++  guint modify_selection_pressed : 1;
++  guint extend_selection_pressed : 1;
+ 
+   guint init_hadjust_value : 1;
+ 
+diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c
+index 47d0282..33dd907 100644
+--- a/gtk/gtktreeview.c
++++ b/gtk/gtktreeview.c
+@@ -2773,21 +2773,21 @@ gtk_tree_view_button_press (GtkWidget      *widget,
+        */
+       if (event->type == GDK_BUTTON_PRESS)
+         {
+-          if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
+-            tree_view->priv->ctrl_pressed = TRUE;
+-          if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
+-            tree_view->priv->shift_pressed = TRUE;
++          if ((event->state & GTK_MODIFY_SELECTION_MOD_MASK) == GTK_MODIFY_SELECTION_MOD_MASK)
++            tree_view->priv->modify_selection_pressed = TRUE;
++          if ((event->state & GTK_EXTEND_SELECTION_MOD_MASK) == GTK_EXTEND_SELECTION_MOD_MASK)
++            tree_view->priv->extend_selection_pressed = TRUE;
+ 
+           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column, event->x - background_area.x);
+           if (focus_cell)
+             gtk_tree_view_column_focus_cell (column, focus_cell);
+ 
+-          if (event->state & GDK_CONTROL_MASK)
++          if (event->state & GTK_MODIFY_SELECTION_MOD_MASK)
+             {
+               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
+               gtk_tree_view_real_toggle_cursor_row (tree_view);
+             }
+-          else if (event->state & GDK_SHIFT_MASK)
++          else if (event->state & GTK_EXTEND_SELECTION_MOD_MASK)
+             {
+               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
+               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
+@@ -2797,8 +2797,8 @@ gtk_tree_view_button_press (GtkWidget      *widget,
+               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
+             }
+ 
+-          tree_view->priv->ctrl_pressed = FALSE;
+-          tree_view->priv->shift_pressed = FALSE;
++          tree_view->priv->modify_selection_pressed = FALSE;
++          tree_view->priv->extend_selection_pressed = FALSE;
+         }
+ 
+       /* the treeview may have been scrolled because of _set_cursor,
+@@ -2830,10 +2830,10 @@ gtk_tree_view_button_press (GtkWidget      *widget,
+ 	      tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
+ 	      tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
+ 
+-	      if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
+-		tree_view->priv->rubber_band_ctrl = TRUE;
+-	      if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
+-		tree_view->priv->rubber_band_shift = TRUE;
++	      if ((event->state & GTK_MODIFY_SELECTION_MOD_MASK) == GTK_MODIFY_SELECTION_MOD_MASK)
++		tree_view->priv->rubber_band_modify = TRUE;
++	      if ((event->state & GTK_EXTEND_SELECTION_MOD_MASK) == GTK_EXTEND_SELECTION_MOD_MASK)
++		tree_view->priv->rubber_band_extend = TRUE;
+ 	    }
+         }
+ 
+@@ -3791,8 +3791,8 @@ gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
+ 
+   /* Clear status variables */
+   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
+-  tree_view->priv->rubber_band_shift = 0;
+-  tree_view->priv->rubber_band_ctrl = 0;
++  tree_view->priv->rubber_band_extend = FALSE;
++  tree_view->priv->rubber_band_modify = FALSE;
+ 
+   tree_view->priv->rubber_band_start_node = NULL;
+   tree_view->priv->rubber_band_start_tree = NULL;
+@@ -3837,9 +3837,9 @@ gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
+ 
+       if (select)
+         {
+-	  if (tree_view->priv->rubber_band_shift)
+-	    GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
+-	  else if (tree_view->priv->rubber_band_ctrl)
++	  if (tree_view->priv->rubber_band_extend)
++            GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
++	  else if (tree_view->priv->rubber_band_modify)
+ 	    {
+ 	      /* Toggle the selection state */
+ 	      if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
+@@ -3853,9 +3853,9 @@ gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
+       else
+         {
+ 	  /* Mirror the above */
+-	  if (tree_view->priv->rubber_band_shift)
++	  if (tree_view->priv->rubber_band_extend)
+ 	    GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
+-	  else if (tree_view->priv->rubber_band_ctrl)
++	  else if (tree_view->priv->rubber_band_modify)
+ 	    {
+ 	      /* Toggle the selection state */
+ 	      if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
+@@ -8203,10 +8203,10 @@ gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
+ 
+   if (gtk_get_current_event_state (&state))
+     {
+-      if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
+-        tree_view->priv->ctrl_pressed = TRUE;
+-      if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
+-        tree_view->priv->shift_pressed = TRUE;
++      if ((state & GTK_MODIFY_SELECTION_MOD_MASK) == GTK_MODIFY_SELECTION_MOD_MASK)
++        tree_view->priv->modify_selection_pressed = TRUE;
++      if ((state & GTK_EXTEND_SELECTION_MOD_MASK) == GTK_EXTEND_SELECTION_MOD_MASK)
++        tree_view->priv->extend_selection_pressed = TRUE;
+     }
+   /* else we assume not pressed */
+ 
+@@ -8230,8 +8230,8 @@ gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
+       g_assert_not_reached ();
+     }
+ 
+-  tree_view->priv->ctrl_pressed = FALSE;
+-  tree_view->priv->shift_pressed = FALSE;
++  tree_view->priv->modify_selection_pressed = FALSE;
++  tree_view->priv->extend_selection_pressed = FALSE;
+ 
+   return TRUE;
+ }
+@@ -9690,7 +9690,7 @@ gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
+ 
+   if (selection_count == 0
+       && tree_view->priv->selection->type != GTK_SELECTION_NONE
+-      && !tree_view->priv->ctrl_pressed
++      && !tree_view->priv->modify_selection_pressed
+       && selectable)
+     {
+       /* Don't move the cursor, but just select the current node */
+@@ -9759,7 +9759,7 @@ gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
+     {
+       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
+ 
+-      if (!tree_view->priv->shift_pressed)
++      if (!tree_view->priv->extend_selection_pressed)
+         {
+           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
+                                           count < 0 ?
+@@ -10111,7 +10111,7 @@ gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
+       return FALSE;
+     }
+ 
+-  if (!tree_view->priv->shift_pressed && start_editing &&
++  if (!tree_view->priv->extend_selection_pressed && start_editing &&
+       tree_view->priv->focus_column)
+     {
+       if (gtk_tree_view_start_editing (tree_view, cursor_path))
+@@ -10121,9 +10121,9 @@ gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
+ 	}
+     }
+ 
+-  if (tree_view->priv->ctrl_pressed)
++  if (tree_view->priv->modify_selection_pressed)
+     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
+-  if (tree_view->priv->shift_pressed)
++  if (tree_view->priv->extend_selection_pressed)
+     mode |= GTK_TREE_SELECT_MODE_EXTEND;
+ 
+   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
+@@ -10147,7 +10147,7 @@ gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
+   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
+   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
+ 
+-  if (!tree_view->priv->shift_pressed)
++  if (!tree_view->priv->extend_selection_pressed)
+     gtk_tree_view_row_activated (tree_view, cursor_path,
+                                  tree_view->priv->focus_column);
+     
+@@ -10285,8 +10285,8 @@ gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
+ 
+       if (gtk_get_current_event_state (&state))
+ 	{
+-	  if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
+-	    tree_view->priv->ctrl_pressed = TRUE;
++	  if ((state & GTK_MODIFY_SELECTION_MOD_MASK) == GTK_MODIFY_SELECTION_MOD_MASK)
++	    tree_view->priv->modify_selection_pressed = TRUE;
+ 	}
+ 
+       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
+@@ -10296,7 +10296,7 @@ gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
+       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
+       gtk_tree_path_free (cursor_path);
+ 
+-      tree_view->priv->ctrl_pressed = FALSE;
++      tree_view->priv->modify_selection_pressed = FALSE;
+ 
+       return TRUE;
+     }
+@@ -12579,13 +12579,13 @@ gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
+       GtkRBTree *new_tree = NULL;
+       GtkRBNode *new_node = NULL;
+ 
+-      if (clear_and_select && !tree_view->priv->ctrl_pressed)
++      if (clear_and_select && !tree_view->priv->modify_selection_pressed)
+         {
+           GtkTreeSelectMode mode = 0;
+ 
+-          if (tree_view->priv->ctrl_pressed)
++          if (tree_view->priv->modify_selection_pressed)
+             mode |= GTK_TREE_SELECT_MODE_TOGGLE;
+-          if (tree_view->priv->shift_pressed)
++          if (tree_view->priv->extend_selection_pressed)
+             mode |= GTK_TREE_SELECT_MODE_EXTEND;
+ 
+           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
+
+
diff --git a/patches/0013-Bug-659406-Abstract-what-triggers-a-context-menu.patch b/patches/0013-Bug-659406-Abstract-what-triggers-a-context-menu.patch
new file mode 100644
index 0000000..1ae7095
--- /dev/null
+++ b/patches/0013-Bug-659406-Abstract-what-triggers-a-context-menu.patch
@@ -0,0 +1,329 @@
+From f2a96fb87408010775730a5b89c26ea5120cf2f2 Mon Sep 17 00:00:00 2001
+From: Michael Natterer <mitch lanedo com>
+Date: Mon, 19 Sep 2011 00:32:52 +0200
+Subject: [PATCH 13/15] Bug 659406 - Abstract what triggers a context menu
+
+Add _gtk_button_event_triggers_context_menu() and use it instead
+of checking for event->button == 3, so context menus are invoked
+correctly on the Mac.
+---
+ gtk/gtkcolorsel.c             |    5 ++---
+ gtk/gtkentry.c                |   18 +++++++++---------
+ gtk/gtkfilechooserdefault.c   |    4 ++--
+ gtk/gtklabel.c                |   23 ++++++++++++-----------
+ gtk/gtklinkbutton.c           |    4 ++--
+ gtk/gtkmain.c                 |   21 +++++++++++++++++++++
+ gtk/gtkmountoperation.c       |    3 +--
+ gtk/gtknotebook.c             |    2 +-
+ gtk/gtkprivate.h              |    2 ++
+ gtk/gtkrecentchooserdefault.c |    4 ++--
+ gtk/gtkstatusicon.c           |    8 ++++----
+ gtk/gtktextview.c             |   12 ++++++------
+ gtk/gtktoolbar.c              |    2 +-
+ 13 files changed, 65 insertions(+), 43 deletions(-)
+
+diff --git a/gtk/gtkcolorsel.c b/gtk/gtkcolorsel.c
+index 6c65d9e..4981e74 100644
+--- a/gtk/gtkcolorsel.c
++++ b/gtk/gtkcolorsel.c
+@@ -1436,9 +1436,8 @@ palette_press (GtkWidget      *drawing_area,
+   GtkColorSelection *colorsel = GTK_COLOR_SELECTION (data);
+ 
+   gtk_widget_grab_focus (drawing_area);
+-  
+-  if (event->button == 3 &&
+-      event->type == GDK_BUTTON_PRESS)
++
++  if (_gtk_button_event_triggers_context_menu (event))
+     {
+       do_popup (colorsel, drawing_area, event->time);
+       return TRUE;
+diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c
+index 8e2c2b2..2c9c5a4 100644
+--- a/gtk/gtkentry.c
++++ b/gtk/gtkentry.c
+@@ -3688,8 +3688,15 @@ gtk_entry_button_press (GtkWidget      *widget,
+     }
+   
+   tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
+-    
+-  if (event->button == 1)
++
++  if (_gtk_button_event_triggers_context_menu (event))
++    {
++      gtk_entry_do_popup (entry, event);
++      entry->button = 0;	/* Don't wait for release, since the menu will gtk_grab_add */
++
++      return TRUE;
++    }
++  else if (event->button == 1)
+     {
+       gboolean have_selection = gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end);
+       
+@@ -3810,13 +3817,6 @@ gtk_entry_button_press (GtkWidget      *widget,
+           gtk_widget_error_bell (widget);
+         }
+     }
+-  else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
+-    {
+-      gtk_entry_do_popup (entry, event);
+-      entry->button = 0;	/* Don't wait for release, since the menu will gtk_grab_add */
+-
+-      return TRUE;
+-    }
+ 
+   return FALSE;
+ }
+diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c
+index 44c2d17..256cc20 100644
+--- a/gtk/gtkfilechooserdefault.c
++++ b/gtk/gtkfilechooserdefault.c
+@@ -3419,7 +3419,7 @@ shortcuts_button_press_event_cb (GtkWidget             *widget,
+   if (in_press)
+     return FALSE;
+ 
+-  if (event->button != 3)
++  if (!_gtk_button_event_triggers_context_menu (event))
+     return FALSE;
+ 
+   in_press = TRUE;
+@@ -4097,7 +4097,7 @@ list_button_press_event_cb (GtkWidget             *widget,
+   if (in_press)
+     return FALSE;
+ 
+-  if (event->button != 3)
++  if (!_gtk_button_event_triggers_context_menu (event))
+     return FALSE;
+ 
+   in_press = TRUE;
+diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c
+index 01225b1..c539537 100644
+--- a/gtk/gtklabel.c
++++ b/gtk/gtklabel.c
+@@ -4189,16 +4189,16 @@ gtk_label_button_press (GtkWidget      *widget,
+ 
+   if (info->active_link)
+     {
+-      if (event->button == 1)
++      if (_gtk_button_event_triggers_context_menu (event))
+         {
+           info->link_clicked = 1;
+-          gtk_widget_queue_draw (widget);
++          gtk_label_do_popup (label, event);
++          return TRUE;
+         }
+-      else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
++      else if (event->button == 1)
+         {
+           info->link_clicked = 1;
+-          gtk_label_do_popup (label, event);
+-          return TRUE;
++          gtk_widget_queue_draw (widget);
+         }
+     }
+ 
+@@ -4208,7 +4208,13 @@ gtk_label_button_press (GtkWidget      *widget,
+   info->in_drag = FALSE;
+   info->select_words = FALSE;
+ 
+-  if (event->button == 1)
++  if (_gtk_button_event_triggers_context_menu (event))
++    {
++      gtk_label_do_popup (label, event);
++
++      return TRUE;
++    }
++  else if (event->button == 1)
+     {
+       if (!gtk_widget_has_focus (widget))
+ 	{
+@@ -4271,12 +4277,7 @@ gtk_label_button_press (GtkWidget      *widget,
+ 
+       return TRUE;
+     }
+-  else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
+-    {
+-      gtk_label_do_popup (label, event);
+ 
+-      return TRUE;
+-    }
+   return FALSE;
+ }
+ 
+diff --git a/gtk/gtklinkbutton.c b/gtk/gtklinkbutton.c
+index a3f246f..bae8ec3 100644
+--- a/gtk/gtklinkbutton.c
++++ b/gtk/gtklinkbutton.c
+@@ -36,8 +36,8 @@
+ #include "gtkstock.h"
+ #include "gtkshow.h"
+ #include "gtktooltip.h"
+-
+ #include "gtklinkbutton.h"
++#include "gtkprivate.h"
+ 
+ #include "gtkintl.h"
+ #include "gtkalias.h"
+@@ -455,7 +455,7 @@ gtk_link_button_button_press (GtkWidget      *widget,
+   if (!gtk_widget_has_focus (widget))
+     gtk_widget_grab_focus (widget);
+ 
+-  if ((event->button == 3) && (event->type == GDK_BUTTON_PRESS))
++  if (_gtk_button_event_triggers_context_menu (event))
+     {
+       gtk_link_button_do_popup (GTK_LINK_BUTTON (widget), event);
+       
+diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
+index d081f70..bc19aed 100644
+--- a/gtk/gtkmain.c
++++ b/gtk/gtkmain.c
+@@ -2632,5 +2632,26 @@ _gtk_boolean_handled_accumulator (GSignalInvocationHint *ihint,
+   return continue_emission;
+ }
+ 
++gboolean
++_gtk_button_event_triggers_context_menu (GdkEventButton *event)
++{
++  if (event->type == GDK_BUTTON_PRESS)
++    {
++      if (event->button == 3 &&
++          ! (event->state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK)))
++        return TRUE;
++
++#ifdef GDK_WINDOWING_QUARTZ
++      if (event->button == 1 &&
++          ! (event->state & (GDK_BUTTON2_MASK | GDK_BUTTON3_MASK)) &&
++          (event->state & GDK_CONTROL_MASK))
++        return TRUE;
++#endif
++    }
++
++  return FALSE;
++}
++
++
+ #define __GTK_MAIN_C__
+ #include "gtkaliasdef.c"
+diff --git a/gtk/gtkmountoperation.c b/gtk/gtkmountoperation.c
+index 0747ed5..6ddaabf 100644
+--- a/gtk/gtkmountoperation.c
++++ b/gtk/gtkmountoperation.c
+@@ -1171,8 +1171,7 @@ on_button_press_event_for_process_tree_view (GtkWidget      *widget,
+ 
+   ret = FALSE;
+ 
+-  /* Ignore double-clicks and triple-clicks */
+-  if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
++  if (_gtk_button_event_triggers_context_menu (event))
+     {
+       ret = do_popup_menu_for_process_tree_view (widget, event, op);
+     }
+diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c
+index 254f6b8..a8c8057 100644
+--- a/gtk/gtknotebook.c
++++ b/gtk/gtknotebook.c
+@@ -2681,7 +2681,7 @@ gtk_notebook_button_press (GtkWidget      *widget,
+   if (arrow)
+     return gtk_notebook_arrow_button_press (notebook, arrow, event->button);
+ 
+-  if (event->button == 3 && notebook->menu)
++  if (notebook->menu && _gtk_button_event_triggers_context_menu (event))
+     {
+       gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL, 
+ 		      NULL, NULL, 3, event->time);
+diff --git a/gtk/gtkprivate.h b/gtk/gtkprivate.h
+index 00440cb..27aaf1f 100644
+--- a/gtk/gtkprivate.h
++++ b/gtk/gtkprivate.h
+@@ -130,6 +130,8 @@ gboolean _gtk_fnmatch (const char *pattern,
+ #define GTK_MODIFY_SELECTION_MOD_MASK GDK_MOD2_MASK
+ #endif
+ 
++gboolean _gtk_button_event_triggers_context_menu (GdkEventButton *event);
++
+ G_END_DECLS
+ 
+ #endif /* __GTK_PRIVATE_H__ */
+diff --git a/gtk/gtkrecentchooserdefault.c b/gtk/gtkrecentchooserdefault.c
+index 676d599..1ab48e2 100644
+--- a/gtk/gtkrecentchooserdefault.c
++++ b/gtk/gtkrecentchooserdefault.c
+@@ -1893,8 +1893,8 @@ recent_view_button_press_cb (GtkWidget      *widget,
+ 			     gpointer        user_data)
+ {
+   GtkRecentChooserDefault *impl = GTK_RECENT_CHOOSER_DEFAULT (user_data);
+-  
+-  if (event->button == 3)
++
++  if (_gtk_button_event_triggers_context_menu (event))
+     {
+       GtkTreePath *path;
+       gboolean res;
+diff --git a/gtk/gtkstatusicon.c b/gtk/gtkstatusicon.c
+index bd43da1..ab8fe79 100644
+--- a/gtk/gtkstatusicon.c
++++ b/gtk/gtkstatusicon.c
+@@ -1750,14 +1750,14 @@ gtk_status_icon_button_press (GtkStatusIcon  *status_icon,
+   if (handled)
+     return TRUE;
+ 
+-  if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
++  if (_gtk_button_event_triggers_context_menu (event))
+     {
+-      emit_activate_signal (status_icon);
++      emit_popup_menu_signal (status_icon, event->button, event->time);
+       return TRUE;
+     }
+-  else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
++  else if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
+     {
+-      emit_popup_menu_signal (status_icon, event->button, event->time);
++      emit_activate_signal (status_icon);
+       return TRUE;
+     }
+ 
+diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c
+index 2061b5b..9ddddec 100644
+--- a/gtk/gtktextview.c
++++ b/gtk/gtktextview.c
+@@ -4352,7 +4352,12 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
+     {
+       gtk_text_view_reset_im_context (text_view);
+ 
+-      if (event->button == 1)
++      if (_gtk_button_event_triggers_context_menu (event))
++        {
++	  gtk_text_view_do_popup (text_view, event);
++	  return TRUE;
++        }
++      else if (event->button == 1)
+         {
+           /* If we're in the selection, start a drag copy/move of the
+            * selection; otherwise, start creating a new selection.
+@@ -4402,11 +4407,6 @@ gtk_text_view_button_press_event (GtkWidget *widget, GdkEventButton *event)
+ 					   text_view->editable);
+           return TRUE;
+         }
+-      else if (event->button == 3)
+-        {
+-	  gtk_text_view_do_popup (text_view, event);
+-	  return TRUE;
+-        }
+     }
+   else if ((event->type == GDK_2BUTTON_PRESS ||
+ 	    event->type == GDK_3BUTTON_PRESS) &&
+diff --git a/gtk/gtktoolbar.c b/gtk/gtktoolbar.c
+index 17e2f8f..1388a65 100644
+--- a/gtk/gtktoolbar.c
++++ b/gtk/gtktoolbar.c
+@@ -2699,7 +2699,7 @@ static gboolean
+ gtk_toolbar_button_press (GtkWidget      *toolbar,
+     			  GdkEventButton *event)
+ {
+-  if (event->button == 3)
++  if (_gtk_button_event_triggers_context_menu (event))
+     {
+       gboolean return_value;
+       
+
+
diff --git a/patches/0014-Bug-659907-gdk_quartz_draw_opaque_stippled_pattern-c.patch b/patches/0014-Bug-659907-gdk_quartz_draw_opaque_stippled_pattern-c.patch
new file mode 100644
index 0000000..2cb9373
--- /dev/null
+++ b/patches/0014-Bug-659907-gdk_quartz_draw_opaque_stippled_pattern-c.patch
@@ -0,0 +1,25 @@
+From 86bdbe35b30cd1f10624628800db66e5d8e6673e Mon Sep 17 00:00:00 2001
+From: Steffen Gutmann <muibase yahoo com>
+Date: Fri, 23 Sep 2011 09:01:44 +0200
+Subject: [PATCH 14/15] Bug 659907 - gdk_quartz_draw_opaque_stippled_pattern
+ crashes
+
+---
+ gdk/quartz/gdkgc-quartz.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/gdk/quartz/gdkgc-quartz.c b/gdk/quartz/gdkgc-quartz.c
+index d922154..cfdde77 100644
+--- a/gdk/quartz/gdkgc-quartz.c
++++ b/gdk/quartz/gdkgc-quartz.c
+@@ -426,7 +426,7 @@ gdk_quartz_draw_opaque_stippled_pattern (void         *info,
+   CGContextFillRect (context, rect);
+ 
+   CGContextClipToMask (context, rect, pattern_image);
+-  color = _gdk_quartz_colormap_get_cgcolor_from_pixel (info,
++  color = _gdk_quartz_colormap_get_cgcolor_from_pixel (pinfo->drawable,
+                                                        _gdk_gc_get_fg_pixel (gc));
+   CGContextSetFillColorWithColor (context, color);
+   CGColorRelease (color);
+
+
diff --git a/patches/0015-Bug-653450-gtkfilechooser-crashes-when-adding-favori.patch b/patches/0015-Bug-653450-gtkfilechooser-crashes-when-adding-favori.patch
new file mode 100644
index 0000000..b070249
--- /dev/null
+++ b/patches/0015-Bug-653450-gtkfilechooser-crashes-when-adding-favori.patch
@@ -0,0 +1,59 @@
+From c797c34e600f21b37ddbf4d2cd6e7a0f9312ced4 Mon Sep 17 00:00:00 2001
+From: John Ralls <jralls ceridwen us>
+Date: Sun, 3 Jul 2011 16:40:03 -0700
+Subject: [PATCH 15/15] Bug 653450 - gtkfilechooser crashes when adding
+ favorite
+
+Ensure that display is set during drag-and-drop, and that string lists'
+memory is zeroed after allocation to prevent g_strfreev() from
+over-running.
+---
+ gdk/quartz/gdkselection-quartz.c |    4 +---
+ gtk/gtkdnd-quartz.c              |    1 +
+ gtk/gtkquartz.c                  |    3 ++-
+ 3 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/gdk/quartz/gdkselection-quartz.c b/gdk/quartz/gdkselection-quartz.c
+index a51f567..b216871 100644
+--- a/gdk/quartz/gdkselection-quartz.c
++++ b/gdk/quartz/gdkselection-quartz.c
+@@ -189,10 +189,8 @@ make_list (const gchar  *text,
+     }
+ 
+   if (list)
+-    *list = g_new (gchar *, n_strings + 1);
++    *list = g_new0 (gchar *, n_strings + 1);
+ 
+-  (*list)[n_strings] = NULL;
+-  
+   i = n_strings;
+   tmp_list = strings;
+   while (tmp_list)
+diff --git a/gtk/gtkdnd-quartz.c b/gtk/gtkdnd-quartz.c
+index 21ce11a..670b185 100644
+--- a/gtk/gtkdnd-quartz.c
++++ b/gtk/gtkdnd-quartz.c
+@@ -155,6 +155,7 @@ struct _GtkDragFindData
+   selection_data.data = NULL;
+   selection_data.length = -1;
+   selection_data.target = _gtk_quartz_pasteboard_type_to_atom (type);
++  selection_data.display = gdk_display_get_default ();
+ 
+   if (gtk_target_list_find (info->target_list, 
+ 			    selection_data.target, 
+diff --git a/gtk/gtkquartz.c b/gtk/gtkquartz.c
+index 8ffeb0b..a675d8a 100644
+--- a/gtk/gtkquartz.c
++++ b/gtk/gtkquartz.c
+@@ -160,7 +160,8 @@ _gtk_quartz_get_selection_data_from_pasteboard (NSPasteboard *pasteboard,
+   selection_data = g_slice_new0 (GtkSelectionData);
+   selection_data->selection = selection;
+   selection_data->target = target;
+-
++  if (!selection_data->display)
++    selection_data->display = gdk_display_get_default ();
+   if (target == gdk_atom_intern_static_string ("UTF8_STRING"))
+     {
+       NSString *s = [pasteboard stringForType:NSStringPboardType];
+
+



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]