summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorPellegrino Prevete2021-08-11 00:16:51 +0200
committerPellegrino Prevete2021-08-11 00:16:51 +0200
commitcc35f686f58ba61522c193cc5eca74e4bce5124b (patch)
tree25cba63a595897806aac10a60edd7fbc3c816456
downloadaur-cc35f686f58ba61522c193cc5eca74e4bce5124b.tar.gz
aur/gtk2-maemo: new package
-rw-r--r--.SRCINFO66
-rw-r--r--PKGBUILD114
-rw-r--r--gtk-query-immodules-2.0.hook11
-rw-r--r--gtk2.install3
-rw-r--r--gtkrc3
-rw-r--r--hildonize-gdk-window.patch45
-rw-r--r--hildonize-gtk-container.patch276
-rw-r--r--hildonize-gtk-dialog.patch642
-rw-r--r--hildonize-gtk-entry.patch958
-rw-r--r--hildonize-gtk-enums.patch92
-rw-r--r--hildonize-gtk-iconview.patch1311
-rw-r--r--hildonize-gtk-imcontext.patch486
-rw-r--r--hildonize-gtk-menu.patch755
-rw-r--r--hildonize-gtk-rbtree.patch77
-rw-r--r--hildonize-gtk-textview.patch811
-rw-r--r--hildonize-gtk-widget.patch932
-rw-r--r--hildonize-gtk-window.patch278
-rw-r--r--xid-collision-debug.patch20
18 files changed, 6880 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO
new file mode 100644
index 000000000000..9e1b56de8b45
--- /dev/null
+++ b/.SRCINFO
@@ -0,0 +1,66 @@
+pkgbase = gtk2-maemo
+ pkgdesc = GObject-based multi-platform GUI toolkit (legacy)
+ pkgver = 2.24.33
+ pkgrel = 2
+ url = https://www.gtk.org/
+ install = gtk2.install
+ arch = x86_64
+ license = LGPL
+ makedepends = gobject-introspection
+ makedepends = git
+ makedepends = gtk-doc
+ makedepends = hicolor-icon-theme
+ depends = atk
+ depends = pango
+ depends = libxcursor
+ depends = libxinerama
+ depends = libxrandr
+ depends = libxi
+ depends = libxcomposite
+ depends = libxdamage
+ depends = shared-mime-info
+ depends = cairo
+ depends = libcups
+ depends = gtk-update-icon-cache
+ depends = librsvg
+ depends = desktop-file-utils
+ optdepends = gnome-themes-standard: Default widget theme
+ optdepends = adwaita-icon-theme: Default icon theme
+ optdepends = python: gtk-builder-convert
+ provides = libgailutil.so
+ provides = libgdk-x11-2.0.so
+ provides = libgtk-x11-2.0.so
+ source = gtk2::git+https://gitlab.gnome.org/GNOME/gtk.git#commit=68631945733158f164427db84f01301d7e875763
+ source = hildonize-gdk-window.patch::https://raw.githubusercontent.com/maemo-leste/gtk/2.24.25/debian/patches/hildonize-gdk-window.diff
+ source = hildonize-gtk-container.patch::https://raw.githubusercontent.com/maemo-leste/gtk/2.24.25/debian/patches/hildonize-gtk-container.diff
+ source = hildonize-gtk-dialog.patch::https://raw.githubusercontent.com/maemo-leste/gtk/2.24.25/debian/patches/hildonize-gtk-dialog.diff
+ source = hildonize-gtk-entry.patch::https://raw.githubusercontent.com/maemo-leste/gtk/2.24.25/debian/patches/hildonize-gtk-entry.diff
+ source = hildonize-gtk-enums.patch::https://raw.githubusercontent.com/maemo-leste/gtk/2.24.25/debian/patches/hildonize-gtk-enums.diff
+ source = hildonize-gtk-iconview.patch::https://raw.githubusercontent.com/maemo-leste/gtk/2.24.25/debian/patches/hildonize-gtk-iconview.diff
+ source = hildonize-gtk-imcontext.patch::https://raw.githubusercontent.com/maemo-leste/gtk/2.24.25/debian/patches/hildonize-gtk-imcontext.diff
+ source = hildonize-gtk-menu.patch::https://raw.githubusercontent.com/maemo-leste/gtk/2.24.25/debian/patches/hildonize-gtk-menu.diff
+ source = hildonize-gtk-rbtree.patch::https://raw.githubusercontent.com/maemo-leste/gtk/2.24.25/debian/patches/hildonize-gtk-rbtree.diff
+ source = hildonize-gtk-textview.patch::https://raw.githubusercontent.com/maemo-leste/gtk/2.24.25/debian/patches/hildonize-gtk-textview.diff
+ source = hildonize-gtk-widget.patch::https://raw.githubusercontent.com/maemo-leste/gtk/2.24.25/debian/patches/hildonize-gtk-widget.diff
+ source = hildonize-gtk-window.patch::https://raw.githubusercontent.com/maemo-leste/gtk/2.24.25/debian/patches/hildonize-gtk-window.diff
+ source = gtkrc
+ source = gtk-query-immodules-2.0.hook
+ source = xid-collision-debug.patch
+ sha512sums = SKIP
+ sha512sums = f838b74958b4f5f1f37fb2831c07dfb7ea051fd62c74f17d8848736e1bbd5671b9a8a66e5a34ce131669a05b2e99312fa43a91ef1d456a914f2d308c09412681
+ sha512sums = 809135f8921bf42c0684be6183eb626ec21db87ead3cb3efbfb59d1b6c57f6d2bc61f23cdf54ed6521de1a74c606ed69cb9991332edb938b076baecd805154b2
+ sha512sums = 77c37f91e989b9e6326b9b2c1bf32f5feaa7b81ec5742f5fb1c5b6db07de4efcc9753beadb9517fe8e04983e11d122b5dfd94897bc8bdb2d68cf7dfffdb1b46e
+ sha512sums = 29ea967378c84e907f7a102bcf6cd893c12c25586c95b2a2994e92dd1f1e82996bfb1416cef47a17ff6b8a225a222cd545b2080d45d190d9061a0f1ecf2baf37
+ sha512sums = a65dc9a3f5e2967d382d8f13781bf446441bea23d84740eaf43e4ce7ee14b3592b7f105f4b89b7246c42f5be9a9e1e9ae93ac23bc6b62ae9c09b45a0eb6a273d
+ sha512sums = 44ba4adcd50c589990af195d3b25baed8098ef8f7f191d841b9ce86bf7e65a48c4e8222a755eca1373eaabe6a79db9c3721f0fa690cca5e5e31fd9b4c3fc69bb
+ sha512sums = ece16de21b19ccb7b08bad78880fa83765bb562973cf73249a9b2b617e0918e231d54bf64ee82648901c7f6c4af4220b06547dc9a17bbb77fab9e83c08cdcfe7
+ sha512sums = 44cd0f71316f38da52ad0e9db3681bf4fbf83c9175b98bb9241d0bedf3f66ed6923c8aa6c9c26264ee4d7b5f8abb15f2ab7cd9f1eaf037273bf94ec50ff4ea41
+ sha512sums = d664555b7e7a98a567548d403e3df0d0534312ba6947d422a0d68dddbaa786806a842a25dcb5f4a0e1235a2f64d6920f67bf93b4574540d4af2337e1d5b68f2c
+ sha512sums = f4c1978b1cbd00cc28779f1cda99434f2f5aec53fd6564282d7d2c5ac5d4869207d38a31ad971bfa09eefe5a78030b3c4c169cbdbd7f5e3b2f7c42bed7f58e56
+ sha512sums = aa3100404b4fe4509ec52c79384e5e59585d482947e394ad26f9c83ad11c9a19f2b0f66112ba9c74feb7a0c7d1b5ec54c64fac34ec0c03666b3ecb62160db8b6
+ sha512sums = 7622b5ff6cd1c0705eee7ad5789c675055a79a4b0aaf2f25fdab4a6fdf883e6fbdef22145d2f2ce4ada3015bd7a8424f61a325a8d00c80e26bf1b507c7949318
+ sha512sums = b124433dd4b20d1d62f073df87e253ca23b3b51625cce55f29a220a4369eda5108c0de07fdc686f570232322c3ff04f7758383f2be5aeace40f843907aa3696d
+ sha512sums = 5e99c5558bf48dc251134869c6310bd9e4bce3775a93547f62028fe32b415c18079da89fe46c85d80b54c4810732acbd6b88ec9946962d02fafc46ed7f672cf2
+ sha512sums = c473ac89fab47cc79e912695aa7408c22c4bcd998e00f9b00d46374d4a961d41ffaa1f885bf2f9d9b68a401e16f64c617f0dfb058a98469dbe16beb37229b9bc
+
+pkgname = gtk2-maemo
diff --git a/PKGBUILD b/PKGBUILD
new file mode 100644
index 000000000000..dd5884074cc2
--- /dev/null
+++ b/PKGBUILD
@@ -0,0 +1,114 @@
+# Maintainer: Pellegrino Prevete <pellegrinoprevete@gmail.com>
+# Contributor: Jan Alexander Steffens (heftig) <heftig@archlinux.org>
+# Contributor: Jan de Groot <jgc@archlinux.org>
+
+_pkgname=gtk2
+pkgname=$_pkgname-maemo
+pkgver=2.24.33
+_tag=2.24.25
+pkgrel=2
+pkgdesc="GObject-based multi-platform GUI toolkit (legacy)"
+arch=(x86_64)
+url="https://www.gtk.org/"
+depends=(atk pango libxcursor libxinerama libxrandr libxi libxcomposite libxdamage
+ shared-mime-info cairo libcups gtk-update-icon-cache librsvg desktop-file-utils)
+makedepends=(gobject-introspection git gtk-doc hicolor-icon-theme)
+optdepends=('gnome-themes-standard: Default widget theme'
+ 'adwaita-icon-theme: Default icon theme'
+ 'python: gtk-builder-convert')
+provides=(libgailutil.so libg{d,t}k-x11-2.0.so)
+license=(LGPL)
+install=gtk2.install
+_commit=68631945733158f164427db84f01301d7e875763 # tags/2.24.33^0
+_raw_url="https://raw.githubusercontent.com/maemo-leste/gtk"
+source=("$_pkgname::git+https://gitlab.gnome.org/GNOME/gtk.git#commit=$_commit"
+ hildonize-gdk-window.patch::$_raw_url/$_tag/debian/patches/hildonize-gdk-window.diff
+ hildonize-gtk-container.patch::$_raw_url/$_tag/debian/patches/hildonize-gtk-container.diff
+ hildonize-gtk-dialog.patch::$_raw_url/$_tag/debian/patches/hildonize-gtk-dialog.diff
+ hildonize-gtk-entry.patch::$_raw_url/$_tag/debian/patches/hildonize-gtk-entry.diff
+ hildonize-gtk-enums.patch::$_raw_url/$_tag/debian/patches/hildonize-gtk-enums.diff
+ hildonize-gtk-iconview.patch::$_raw_url/$_tag/debian/patches/hildonize-gtk-iconview.diff
+ hildonize-gtk-imcontext.patch::$_raw_url/$_tag/debian/patches/hildonize-gtk-imcontext.diff
+ hildonize-gtk-menu.patch::$_raw_url/$_tag/debian/patches/hildonize-gtk-menu.diff
+ hildonize-gtk-rbtree.patch::$_raw_url/$_tag/debian/patches/hildonize-gtk-rbtree.diff
+ hildonize-gtk-textview.patch::$_raw_url/$_tag/debian/patches/hildonize-gtk-textview.diff
+ hildonize-gtk-widget.patch::$_raw_url/$_tag/debian/patches/hildonize-gtk-widget.diff
+ hildonize-gtk-window.patch::$_raw_url/$_tag/debian/patches/hildonize-gtk-window.diff
+ gtkrc
+ gtk-query-immodules-2.0.hook
+ xid-collision-debug.patch)
+sha512sums=('SKIP'
+ 'f838b74958b4f5f1f37fb2831c07dfb7ea051fd62c74f17d8848736e1bbd5671b9a8a66e5a34ce131669a05b2e99312fa43a91ef1d456a914f2d308c09412681'
+ '809135f8921bf42c0684be6183eb626ec21db87ead3cb3efbfb59d1b6c57f6d2bc61f23cdf54ed6521de1a74c606ed69cb9991332edb938b076baecd805154b2'
+ '77c37f91e989b9e6326b9b2c1bf32f5feaa7b81ec5742f5fb1c5b6db07de4efcc9753beadb9517fe8e04983e11d122b5dfd94897bc8bdb2d68cf7dfffdb1b46e'
+ '29ea967378c84e907f7a102bcf6cd893c12c25586c95b2a2994e92dd1f1e82996bfb1416cef47a17ff6b8a225a222cd545b2080d45d190d9061a0f1ecf2baf37'
+ 'a65dc9a3f5e2967d382d8f13781bf446441bea23d84740eaf43e4ce7ee14b3592b7f105f4b89b7246c42f5be9a9e1e9ae93ac23bc6b62ae9c09b45a0eb6a273d'
+ '44ba4adcd50c589990af195d3b25baed8098ef8f7f191d841b9ce86bf7e65a48c4e8222a755eca1373eaabe6a79db9c3721f0fa690cca5e5e31fd9b4c3fc69bb'
+ 'ece16de21b19ccb7b08bad78880fa83765bb562973cf73249a9b2b617e0918e231d54bf64ee82648901c7f6c4af4220b06547dc9a17bbb77fab9e83c08cdcfe7'
+ '44cd0f71316f38da52ad0e9db3681bf4fbf83c9175b98bb9241d0bedf3f66ed6923c8aa6c9c26264ee4d7b5f8abb15f2ab7cd9f1eaf037273bf94ec50ff4ea41'
+ 'd664555b7e7a98a567548d403e3df0d0534312ba6947d422a0d68dddbaa786806a842a25dcb5f4a0e1235a2f64d6920f67bf93b4574540d4af2337e1d5b68f2c'
+ 'f4c1978b1cbd00cc28779f1cda99434f2f5aec53fd6564282d7d2c5ac5d4869207d38a31ad971bfa09eefe5a78030b3c4c169cbdbd7f5e3b2f7c42bed7f58e56'
+ 'aa3100404b4fe4509ec52c79384e5e59585d482947e394ad26f9c83ad11c9a19f2b0f66112ba9c74feb7a0c7d1b5ec54c64fac34ec0c03666b3ecb62160db8b6'
+ '7622b5ff6cd1c0705eee7ad5789c675055a79a4b0aaf2f25fdab4a6fdf883e6fbdef22145d2f2ce4ada3015bd7a8424f61a325a8d00c80e26bf1b507c7949318'
+ 'b124433dd4b20d1d62f073df87e253ca23b3b51625cce55f29a220a4369eda5108c0de07fdc686f570232322c3ff04f7758383f2be5aeace40f843907aa3696d'
+ '5e99c5558bf48dc251134869c6310bd9e4bce3775a93547f62028fe32b415c18079da89fe46c85d80b54c4810732acbd6b88ec9946962d02fafc46ed7f672cf2'
+ 'c473ac89fab47cc79e912695aa7408c22c4bcd998e00f9b00d46374d4a961d41ffaa1f885bf2f9d9b68a401e16f64c617f0dfb058a98469dbe16beb37229b9bc')
+
+pkgver() {
+ cd $_pkgname
+ git describe --tags | sed 's/-/+/g'
+}
+
+prepare() {
+ cd $_pkgname
+ git apply -3 ../xid-collision-debug.patch
+ patch -p1 < ../hildonize-gdk-window.patch
+ patch -p1 < ../hildonize-gtk-container.patch
+ patch -p1 < ../hildonize-gtk-dialog.patch
+ patch -p1 < ../hildonize-gtk-entry.patch
+ patch -p1 < ../hildonize-gtk-enums.patch
+ patch -p1 < ../hildonize-gtk-iconview.patch
+ patch -p1 < ../hildonize-gtk-imcontext.patch
+ patch -p1 < ../hildonize-gtk-menu.patch
+ patch -p1 < ../hildonize-gtk-rbtree.patch
+ patch -p1 < ../hildonize-gtk-textview.patch
+ patch -p1 < ../hildonize-gtk-widget.patch
+ patch -p1 < ../hildonize-gtk-window.patch
+ libtoolize --force
+ aclocal -I m4
+ autoconf
+ automake --add-missing
+ NOCONFIGURE=1 ./autogen.sh
+}
+
+build() {
+ cd $_pkgname
+
+ ./configure \
+ --build=$CBUILD \
+ --host=$CHOST \
+ --prefix=/usr \
+ --sysconfdir=/etc \
+ --localstatedir=/var \
+ --with-xinput=yes \
+ --without-libjasper \ # try without
+ --with-included-loaders=png
+ --disable-gtk-doc
+
+ # https://bugzilla.gnome.org/show_bug.cgi?id=655517
+ sed -i -e 's/ -shared / -Wl,-O1,--as-needed\0/g' libtool
+
+ make
+}
+
+package() {
+ cd _pkgname
+ make DESTDIR="$pkgdir" install
+
+ install -Dt "$pkgdir/usr/share/gtk-2.0" -m644 ../gtkrc
+ install -Dt "$pkgdir/usr/share/libalpm/hooks" -m644 ../gtk-query-immodules-2.0.hook
+
+ rm "$pkgdir/usr/bin/gtk-update-icon-cache"
+}
+
+# vim:set et sw=2:
diff --git a/gtk-query-immodules-2.0.hook b/gtk-query-immodules-2.0.hook
new file mode 100644
index 000000000000..51986eb2856e
--- /dev/null
+++ b/gtk-query-immodules-2.0.hook
@@ -0,0 +1,11 @@
+[Trigger]
+Type = Path
+Operation = Install
+Operation = Upgrade
+Operation = Remove
+Target = usr/lib/gtk-2.0/2.10.0/immodules/*.so
+
+[Action]
+Description = Probing GTK2 input method modules...
+When = PostTransaction
+Exec = /usr/bin/gtk-query-immodules-2.0 --update-cache
diff --git a/gtk2.install b/gtk2.install
new file mode 100644
index 000000000000..1fb17159a6c2
--- /dev/null
+++ b/gtk2.install
@@ -0,0 +1,3 @@
+pre_remove() {
+ rm -f /usr/lib/gtk-2.0/2.10.0/immodules.cache
+}
diff --git a/gtkrc b/gtkrc
new file mode 100644
index 000000000000..1ee9497d946f
--- /dev/null
+++ b/gtkrc
@@ -0,0 +1,3 @@
+gtk-icon-theme-name = "Adwaita"
+gtk-theme-name = "Adwaita"
+gtk-font-name = "Cantarell 11"
diff --git a/hildonize-gdk-window.patch b/hildonize-gdk-window.patch
new file mode 100644
index 000000000000..7dbce537d54a
--- /dev/null
+++ b/hildonize-gdk-window.patch
@@ -0,0 +1,45 @@
+--- a/gdk/gdkwindow.c
++++ b/gdk/gdkwindow.c
+@@ -6372,6 +6372,32 @@
+ }
+
+ /**
++ * gdk_window_reset_toplevel_updates_libgtk_only:
++ * @window: a #GdkWindow
++ *
++ * Thaws all pending freezes (if any) made with
++ * gdk_window_freeze_toplevel_updates_libgtk_only()
++ *
++ * This function is not part of the GDK public API and is only
++ * for use by GTK+.
++ **/
++void
++gdk_window_reset_toplevel_updates_libgtk_only (GdkWindow *window)
++{
++ GdkWindowObject *private = (GdkWindowObject *)window;
++
++ g_return_if_fail (GDK_IS_WINDOW (window));
++ g_return_if_fail (private->window_type != GDK_WINDOW_CHILD);
++
++ if (private->update_and_descendants_freeze_count > 0)
++ {
++ private->update_and_descendants_freeze_count = 0;
++
++ gdk_window_schedule_update (window);
++ }
++}
++
++/**
+ * gdk_window_set_debug_updates:
+ * @setting: %TRUE to turn on update debugging
+ *
+--- a/gdk/gdkwindow.h
++++ b/gdk/gdkwindow.h
+@@ -679,6 +679,7 @@
+
+ void gdk_window_freeze_toplevel_updates_libgtk_only (GdkWindow *window);
+ void gdk_window_thaw_toplevel_updates_libgtk_only (GdkWindow *window);
++void gdk_window_reset_toplevel_updates_libgtk_only (GdkWindow *window);
+
+ void gdk_window_process_all_updates (void);
+ void gdk_window_process_updates (GdkWindow *window,
diff --git a/hildonize-gtk-container.patch b/hildonize-gtk-container.patch
new file mode 100644
index 000000000000..e634b7904d2d
--- /dev/null
+++ b/hildonize-gtk-container.patch
@@ -0,0 +1,276 @@
+--- a/gtk/gtkcontainer.c
++++ b/gtk/gtkcontainer.c
+@@ -41,7 +41,7 @@
+ #include <gobject/gobjectnotifyqueue.c>
+ #include <gobject/gvaluecollector.h>
+ #include "gtkalias.h"
+-
++#include "gtkmenu.h"
+
+ enum {
+ ADD,
+@@ -58,6 +58,13 @@
+ PROP_CHILD
+ };
+
++typedef struct
++{
++ GtkWidget *menu;
++ void *func;
++ GtkWidgetTapAndHoldFlags flags;
++} GtkContainerTAH;
++
+ #define PARAM_SPEC_PARAM_ID(pspec) ((pspec)->param_id)
+ #define PARAM_SPEC_SET_PARAM_ID(pspec, id) ((pspec)->param_id = (id))
+
+@@ -100,6 +107,12 @@
+
+ static gchar* gtk_container_child_default_composite_name (GtkContainer *container,
+ GtkWidget *child);
++static void gtk_container_tap_and_hold_setup (GtkWidget *widget,
++ GtkWidget *menu,
++ GtkCallback func,
++ GtkWidgetTapAndHoldFlags flags);
++static void gtk_container_tap_and_hold_setup_forall (GtkWidget *widget,
++ GtkContainerTAH *tah);
+
+ /* GtkBuildable */
+ static void gtk_container_buildable_init (GtkBuildableIface *iface);
+@@ -224,6 +237,12 @@
+ widget_class->unmap = gtk_container_unmap;
+ widget_class->focus = gtk_container_focus;
+
++ g_signal_override_class_closure (
++ g_signal_lookup ("tap-and-hold-setup", GTK_TYPE_WIDGET),
++ GTK_TYPE_CONTAINER,
++ g_cclosure_new (G_CALLBACK (gtk_container_tap_and_hold_setup),
++ NULL, NULL));
++
+ class->add = gtk_container_add_unimplemented;
+ class->remove = gtk_container_remove_unimplemented;
+ class->check_resize = gtk_container_real_check_resize;
+@@ -1050,6 +1069,9 @@
+ container->reallocate_redraws = FALSE;
+ }
+
++static GSList *size_allocated_containers = NULL;
++static guint collect_size_allocated_containers = 0;
++
+ static void
+ gtk_container_destroy (GtkObject *object)
+ {
+@@ -1064,6 +1086,9 @@
+ container->focus_child = NULL;
+ }
+
++ size_allocated_containers =
++ g_slist_remove_all (size_allocated_containers, container);
++
+ /* do this before walking child widgets, to avoid
+ * removing children from focus chain one by one.
+ */
+@@ -1334,6 +1359,17 @@
+ return GTK_IS_RESIZE_CONTAINER (widget) ? (GtkContainer*) widget : NULL;
+ }
+
++void
++_gtk_container_post_size_allocate (GtkContainer *container)
++{
++ size_allocated_containers =
++ g_slist_prepend (size_allocated_containers, container);
++}
++
++static void
++container_scroll_focus_adjustments (GtkContainer *container,
++ gboolean resize_update);
++
+ static gboolean
+ gtk_container_idle_sizer (gpointer data)
+ {
+@@ -1354,7 +1390,49 @@
+ g_slist_free_1 (slist);
+
+ GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_PENDING);
++ collect_size_allocated_containers++;
+ gtk_container_check_resize (GTK_CONTAINER (widget));
++ collect_size_allocated_containers--;
++ }
++
++ /* adjust scroll position in all windows that recently resized a container */
++ if (collect_size_allocated_containers == 0)
++ {
++ GtkWidget *last = NULL;
++ GSList *current;
++
++ /* sort toplevels to allow deduping */
++ size_allocated_containers =
++ g_slist_sort (size_allocated_containers, g_direct_equal);
++ /* adjust focus position on toplevels */
++ for (current = size_allocated_containers; current;
++ current = current->next)
++ {
++ if (last != current->data) /* dedup toplevels */
++ {
++ last = current->data;
++
++ if (GTK_IS_WINDOW (current->data))
++ {
++ GtkWidget *focus = GTK_WINDOW (current->data)->focus_widget;
++
++ if (focus && !GTK_IS_CONTAINER (focus))
++ focus = focus->parent;
++
++ while (focus)
++ {
++ /* adjust all focus widget parents that could possibly
++ * scroll
++ */
++ container_scroll_focus_adjustments (GTK_CONTAINER (focus),
++ TRUE);
++ focus = focus->parent;
++ }
++ }
++ }
++ }
++ g_slist_free (size_allocated_containers);
++ size_allocated_containers = NULL;
+ }
+
+ gdk_window_process_all_updates ();
+@@ -1753,7 +1831,12 @@
+ g_object_ref (container->focus_child);
+ }
+
++ container_scroll_focus_adjustments (container, FALSE);
++}
+
++static void
++container_scroll_focus_adjustments (GtkContainer *container, gboolean resize_update)
++{
+ /* check for h/v adjustments
+ */
+ if (container->focus_child)
+@@ -1767,6 +1850,7 @@
+ vadj = g_object_get_qdata (G_OBJECT (container), vadjustment_key_id);
+ if (hadj || vadj)
+ {
++ gboolean valid_coordinates = FALSE;
+
+ focus_child = container->focus_child;
+ while (GTK_IS_CONTAINER (focus_child) &&
+@@ -1775,17 +1859,39 @@
+ focus_child = GTK_CONTAINER (focus_child)->focus_child;
+ }
+
+- gtk_widget_translate_coordinates (focus_child, container->focus_child,
+- 0, 0, &x, &y);
++ valid_coordinates =
++ gtk_widget_translate_coordinates (focus_child,
++ container->focus_child,
++ 0, 0, &x, &y);
+
+ x += container->focus_child->allocation.x;
+ y += container->focus_child->allocation.y;
+
+ if (vadj)
+- gtk_adjustment_clamp_page (vadj, y, y + focus_child->allocation.height);
++ {
++ /* When updating the adjustments as a result of container resize
++ * (resize_update=TRUE) force the focused widget visible only if
++ * it is smaller than the viewport. Otherwise the updates starts
++ * to oscillate between two values (possibly HildonScrollArea is
++ * causing that.) That should be enough for vkb resized dialogs.
++ */
++ if (valid_coordinates && !resize_update ||
++ focus_child->allocation.height < vadj->page_size)
++ {
++ gtk_adjustment_clamp_page (
++ vadj, y, y + focus_child->allocation.height);
++ }
++ }
+
+ if (hadj)
+- gtk_adjustment_clamp_page (hadj, x, x + focus_child->allocation.width);
++ {
++ if (valid_coordinates && !resize_update ||
++ focus_child->allocation.width < hadj->page_size)
++ {
++ gtk_adjustment_clamp_page (
++ hadj, x, x + focus_child->allocation.width);
++ }
++ }
+ }
+ }
+ }
+@@ -2760,5 +2866,61 @@
+ }
+ }
+
++static void
++gtk_container_tap_and_hold_setup_forall (GtkWidget *widget,
++ GtkContainerTAH *tah)
++{
++ gtk_widget_tap_and_hold_setup (widget, tah->menu, tah->func, tah->flags);
++}
++
++static void
++gtk_container_tap_and_hold_setup (GtkWidget *widget,
++ GtkWidget *menu,
++ GtkCallback func,
++ GtkWidgetTapAndHoldFlags flags)
++{
++ GtkContainerTAH tah;
++ GValue instance_and_params[4] = { { 0, }, { 0, }, { 0, }, { 0, } };
++
++ g_return_if_fail (GTK_IS_WIDGET (widget));
++ g_return_if_fail (menu == NULL || GTK_IS_MENU (menu));
++
++ tah.menu = menu;
++ tah.func = func;
++ tah.flags = flags;
++
++ if (flags & GTK_TAP_AND_HOLD_NO_INTERNALS)
++ {
++ gtk_container_foreach (
++ GTK_CONTAINER (widget),
++ (GtkCallback)gtk_container_tap_and_hold_setup_forall, &tah);
++ }
++ else
++ {
++ gtk_container_forall (
++ GTK_CONTAINER (widget),
++ (GtkCallback)gtk_container_tap_and_hold_setup_forall, &tah);
++ }
++
++ g_value_init (&instance_and_params[0], GTK_TYPE_WIDGET);
++ g_value_set_object (&instance_and_params[0], widget);
++
++ g_value_init (&instance_and_params[1], GTK_TYPE_OBJECT);
++ g_value_set_object (&instance_and_params[1], menu);
++
++ g_value_init (&instance_and_params[2], G_TYPE_POINTER);
++ g_value_set_pointer (&instance_and_params[2], func);
++
++ g_value_init (&instance_and_params[3], G_TYPE_UINT);
++ g_value_set_uint (&instance_and_params[3], flags);
++
++ g_signal_chain_from_overridden (instance_and_params, NULL);
++
++ g_value_unset (&instance_and_params[0]);
++ g_value_unset (&instance_and_params[1]);
++ g_value_unset (&instance_and_params[2]);
++ g_value_unset (&instance_and_params[3]);
++}
++
+ #define __GTK_CONTAINER_C__
+ #include "gtkaliasdef.c"
+--- a/gtk/gtkcontainer.h
++++ b/gtk/gtkcontainer.h
+@@ -219,6 +219,7 @@
+ GList *children,
+ GtkDirectionType direction,
+ GtkWidget *old_focus);
++void _gtk_container_post_size_allocate (GtkContainer *container);
+
+ #ifndef GTK_DISABLE_DEPRECATED
+ #define gtk_container_border_width gtk_container_set_border_width
diff --git a/hildonize-gtk-dialog.patch b/hildonize-gtk-dialog.patch
new file mode 100644
index 000000000000..fb0b17b85626
--- /dev/null
+++ b/hildonize-gtk-dialog.patch
@@ -0,0 +1,642 @@
+--- a/gtk/gtkdialog.c
++++ b/gtk/gtkdialog.c
+@@ -29,13 +29,20 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include "config.h"
++#include "gtkalignment.h"
++#include <X11/Xlib.h>
++#include <X11/Xatom.h>
++#include "x11/gdkx.h"
+ #include "gtkbutton.h"
+ #include "gtkdialog.h"
+ #include "gtkhbbox.h"
++#include "gtkvbbox.h"
+ #include "gtklabel.h"
+ #include "gtkhseparator.h"
++#include "gtkvseparator.h"
+ #include "gtkmarshalers.h"
+ #include "gtkvbox.h"
++#include "gtkhbox.h"
+ #include "gdkkeysyms.h"
+ #include "gtkmain.h"
+ #include "gtkintl.h"
+@@ -46,8 +53,13 @@
+
+ #define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_DIALOG, GtkDialogPrivate))
+
++/* Buttons on a HildonDialog have fixed size */
++#define HILDON_DIALOG_BUTTON_WIDTH 174
++
+ typedef struct {
+ guint ignore_separator : 1;
++ GtkWidget *hbox;
++ GtkWidget *alignment;
+ } GtkDialogPrivate;
+
+ typedef struct _ResponseData ResponseData;
+@@ -75,8 +87,11 @@
+ GParamSpec *pspec);
+ static void gtk_dialog_style_set (GtkWidget *widget,
+ GtkStyle *prev_style);
++static void gtk_dialog_size_request (GtkWidget *widget,
++ GtkRequisition *requisition);
++static void gtk_dialog_realize (GtkWidget *widget);
++static void gtk_dialog_unrealize (GtkWidget *widget);
+ static void gtk_dialog_map (GtkWidget *widget);
+-
+ static void gtk_dialog_close (GtkDialog *dialog);
+
+ static ResponseData * get_response_data (GtkWidget *widget,
+@@ -101,7 +116,12 @@
+
+ enum {
+ PROP_0,
+- PROP_HAS_SEPARATOR
++ PROP_HAS_SEPARATOR,
++ PROP_TOP_PADDING,
++ PROP_BOTTOM_PADDING,
++ PROP_LEFT_PADDING,
++ PROP_RIGHT_PADDING,
++ PROP_INNER_SPACING,
+ };
+
+ enum {
+@@ -131,6 +151,9 @@
+
+ widget_class->map = gtk_dialog_map;
+ widget_class->style_set = gtk_dialog_style_set;
++ widget_class->size_request = gtk_dialog_size_request;
++ widget_class->realize = gtk_dialog_realize;
++ widget_class->unrealize = gtk_dialog_unrealize;
+
+ class->close = gtk_dialog_close;
+
+@@ -151,6 +174,56 @@
+ FALSE,
+ GTK_PARAM_READWRITE | G_PARAM_DEPRECATED));
+
++ g_object_class_install_property (gobject_class,
++ PROP_TOP_PADDING,
++ g_param_spec_uint ("top-padding",
++ P_("Top Padding"),
++ P_("The padding to insert at the top of the dialog."),
++ 0,
++ G_MAXUINT,
++ 0,
++ GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
++
++ g_object_class_install_property (gobject_class,
++ PROP_BOTTOM_PADDING,
++ g_param_spec_uint ("bottom-padding",
++ P_("Bottom Padding"),
++ P_("The padding to insert at the bottom of the dialog."),
++ 0,
++ G_MAXUINT,
++ 8,
++ GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
++
++ g_object_class_install_property (gobject_class,
++ PROP_LEFT_PADDING,
++ g_param_spec_uint ("left-padding",
++ P_("Left Padding"),
++ P_("The padding to insert at the left of the dialog."),
++ 0,
++ G_MAXUINT,
++ 16,
++ GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
++
++ g_object_class_install_property (gobject_class,
++ PROP_RIGHT_PADDING,
++ g_param_spec_uint ("right-padding",
++ P_("Right Padding"),
++ P_("The padding to insert at the right of the dialog."),
++ 0,
++ G_MAXUINT,
++ 16,
++ GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
++
++ g_object_class_install_property (gobject_class,
++ PROP_INNER_SPACING,
++ g_param_spec_int ("inner-spacing",
++ P_("Inner Spacing"),
++ P_("The spacing between content area and action area."),
++ 0,
++ G_MAXINT,
++ 16,
++ GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
++
+ /**
+ * GtkDialog::response:
+ * @dialog: the object on which the signal is emitted
+@@ -246,6 +319,11 @@
+ gint content_area_spacing;
+ gint button_spacing;
+ gint action_area_border;
++ GtkDialogPrivate *priv = GET_PRIVATE (dialog);
++ guint top_padding;
++ guint bottom_padding;
++ guint left_padding;
++ guint right_padding;
+
+ gtk_widget_style_get (GTK_WIDGET (dialog),
+ "content-area-border", &content_area_border,
+@@ -253,7 +331,12 @@
+ "button-spacing", &button_spacing,
+ "action-area-border", &action_area_border,
+ NULL);
+-
++ gtk_dialog_get_padding (dialog, &top_padding, &bottom_padding, &left_padding,
++ &right_padding);
++ gtk_alignment_set_padding (GTK_ALIGNMENT (priv->alignment), top_padding,
++ bottom_padding, left_padding, right_padding);
++ gtk_box_set_spacing (GTK_BOX (priv->hbox),
++ gtk_dialog_get_inner_spacing (dialog));
+ gtk_container_set_border_width (GTK_CONTAINER (dialog->vbox),
+ content_area_border);
+ if (!_gtk_box_get_spacing_set (GTK_BOX (dialog->vbox)))
+@@ -274,6 +357,8 @@
+
+ priv = GET_PRIVATE (dialog);
+ priv->ignore_separator = FALSE;
++ priv->hbox = gtk_hbox_new (FALSE, 0);
++ priv->alignment = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
+
+ /* To avoid breaking old code that prevents destroy on delete event
+ * by connecting a handler, we have to have the FIRST signal
+@@ -286,19 +371,19 @@
+
+ dialog->vbox = gtk_vbox_new (FALSE, 0);
+
+- gtk_container_add (GTK_CONTAINER (dialog), dialog->vbox);
++ gtk_container_add (GTK_CONTAINER (priv->alignment), priv->hbox);
++ gtk_container_add (GTK_CONTAINER (dialog), priv->alignment);
++ gtk_widget_show (priv->hbox);
++ gtk_widget_show (priv->alignment);
+ gtk_widget_show (dialog->vbox);
+
+- dialog->action_area = gtk_hbutton_box_new ();
+-
++ dialog->action_area = gtk_vbutton_box_new ();
++ gtk_widget_set_name (dialog->action_area, "hildon-dialog-action-area");
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog->action_area),
+ GTK_BUTTONBOX_END);
+-
+- gtk_box_pack_end (GTK_BOX (dialog->vbox), dialog->action_area,
+- FALSE, TRUE, 0);
++ gtk_box_pack_end (GTK_BOX (priv->hbox), dialog->action_area, FALSE, TRUE, 0);
+ gtk_widget_show (dialog->action_area);
+-
+- dialog->separator = NULL;
++ gtk_box_pack_end (GTK_BOX (priv->hbox), dialog->vbox, TRUE, TRUE, 0);
+
+ gtk_window_set_type_hint (GTK_WINDOW (dialog),
+ GDK_WINDOW_TYPE_HINT_DIALOG);
+@@ -338,14 +423,52 @@
+ GParamSpec *pspec)
+ {
+ GtkDialog *dialog;
+-
++ guint padding_top;
++ guint padding_bottom;
++ guint padding_left;
++ guint padding_right;
++
+ dialog = GTK_DIALOG (object);
+
++ gtk_dialog_get_padding (dialog, &padding_top, &padding_bottom, &padding_left,
++ &padding_right);
++
+ switch (prop_id)
+ {
+ case PROP_HAS_SEPARATOR:
+ gtk_dialog_set_has_separator (dialog, g_value_get_boolean (value));
+ break;
++ case PROP_TOP_PADDING:
++ gtk_dialog_set_padding (dialog,
++ g_value_get_uint (value),
++ padding_bottom,
++ padding_left,
++ padding_right);
++ break;
++ case PROP_BOTTOM_PADDING:
++ gtk_dialog_set_padding (dialog,
++ padding_top,
++ g_value_get_uint (value),
++ padding_left,
++ padding_right);
++ break;
++ case PROP_LEFT_PADDING:
++ gtk_dialog_set_padding (dialog,
++ padding_top,
++ padding_bottom,
++ g_value_get_uint (value),
++ padding_right);
++ break;
++ case PROP_RIGHT_PADDING:
++ gtk_dialog_set_padding (dialog,
++ padding_top,
++ padding_bottom,
++ padding_left,
++ g_value_get_uint (value));
++ break;
++ case PROP_INNER_SPACING:
++ gtk_dialog_set_inner_spacing (dialog, g_value_get_int (value));
++ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+@@ -360,14 +483,36 @@
+ GParamSpec *pspec)
+ {
+ GtkDialog *dialog;
+-
++ guint padding_top;
++ guint padding_bottom;
++ guint padding_left;
++ guint padding_right;
++
+ dialog = GTK_DIALOG (object);
+-
++
++ gtk_dialog_get_padding (dialog, &padding_top, &padding_bottom, &padding_left,
++ &padding_right);
++
+ switch (prop_id)
+ {
+ case PROP_HAS_SEPARATOR:
+ g_value_set_boolean (value, dialog->separator != NULL);
+ break;
++ case PROP_TOP_PADDING:
++ g_value_set_uint (value, padding_top);
++ break;
++ case PROP_BOTTOM_PADDING:
++ g_value_set_uint (value, padding_bottom);
++ break;
++ case PROP_LEFT_PADDING:
++ g_value_set_uint (value, padding_left);
++ break;
++ case PROP_RIGHT_PADDING:
++ g_value_set_uint (value, padding_right);
++ break;
++ case PROP_INNER_SPACING:
++ g_value_set_int (value, gtk_dialog_get_inner_spacing (dialog));
++ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+@@ -453,6 +598,189 @@
+ update_spacings (GTK_DIALOG (widget));
+ }
+
++static G_GNUC_CONST GQuark
++auto_resize_quark (void)
++{
++ static GQuark quark = 0;
++
++ if (G_UNLIKELY (quark == 0))
++ quark = g_quark_from_static_string ("gtk-dialog-widget-auto-resize");
++
++ return quark;
++}
++
++static void
++gtk_dialog_resize_button (GtkWidget *button,
++ gpointer *data)
++{
++ /* Only resize widgets added with gtk_dialog_add_button () */
++ if (g_object_get_qdata (G_OBJECT (button), auto_resize_quark ()))
++ {
++ gint width = GPOINTER_TO_INT (data);
++ g_object_set (button, "width-request", width, NULL);
++ }
++}
++
++static gboolean
++gtk_dialog_get_disable_portrait(GtkDialog *dialog)
++{
++ Atom actual_type;
++ int actual_format;
++ unsigned long num_items, bytes_left;
++ unsigned char *ret_data_ptr = 0,*leader_data;
++ Display * dpy = GDK_WINDOW_XDISPLAY (GTK_WIDGET(dialog)->window);
++ int error,result;
++ gboolean disable_portrait=False;
++
++ gdk_error_trap_push ();
++
++
++ result = XGetWindowProperty (dpy,
++ GDK_WINDOW_XWINDOW (GTK_WIDGET(dialog)->window),
++ XInternAtom(dpy,"WM_CLIENT_LEADER",False),
++ 0L, (~0L), False,
++ XA_WINDOW, &actual_type, &actual_format, &num_items,
++ &bytes_left, &leader_data);
++ error = gdk_error_trap_pop ();
++
++ if (error || (result != Success) || !leader_data)
++ {
++ g_warning("gtk_dialog_get_disable_portrait - unable to get window leader.");
++ return False;
++ }
++
++ gdk_error_trap_push ();
++
++ result = XGetWindowProperty(
++ dpy,
++ *(Window*)leader_data,
++ XInternAtom(dpy, "_HILDON_PORTRAIT_MODE_TASKNAV_DISABLE", False),
++ 0,1/*= one 32 bits item */ ,False,
++ XA_CARDINAL, &actual_type, &actual_format, &num_items,
++ &bytes_left, &ret_data_ptr);
++
++ error = gdk_error_trap_pop ();
++
++ XFree(leader_data);
++
++ if (!error && ret_data_ptr && (result == Success))
++ {
++ disable_portrait = *((int*)ret_data_ptr);
++ XFree(ret_data_ptr);
++ return disable_portrait;
++ }
++
++ return disable_portrait;
++}
++
++static void
++gtk_dialog_screen_size_changed_cb (GdkScreen *screen,
++ GtkDialog *dialog)
++{
++ GtkDialogPrivate *priv = GET_PRIVATE (dialog);
++ GtkWidget *parent = gtk_widget_get_parent (dialog->action_area);
++ gint width = gdk_screen_get_width (screen);
++ gboolean portrait = width < gdk_screen_get_height (screen);
++ gint button_width, padding;
++
++ if(portrait)
++ {
++ GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (dialog));
++
++ if (GTK_WIDGET_TOPLEVEL (toplevel) &&
++ gtk_dialog_get_disable_portrait(GTK_DIALOG(toplevel)))
++ {
++ /* we are stuck in landscape, skip the circus */
++ return;
++ }
++ }
++
++ g_object_ref (dialog->action_area);
++ gtk_container_remove (GTK_CONTAINER (parent), dialog->action_area);
++
++ if (portrait)
++ {
++ parent = dialog->vbox;
++ button_width = width - 16 /* HILDON_MARGIN_DOUBLE */ * 2;
++ padding = 16 /* HILDON_MARGIN_DOUBLE */;
++ }
++ else
++ {
++ parent = gtk_widget_get_parent (dialog->vbox);
++ button_width = 174 /* HILDON_DIALOG_BUTTON_WIDTH */;
++ padding = 0;
++ }
++
++ gtk_box_pack_end (GTK_BOX (parent), dialog->action_area, FALSE, TRUE,
++ padding);
++ gtk_box_reorder_child (GTK_BOX (parent), dialog->action_area, 0);
++ gtk_container_foreach (GTK_CONTAINER (dialog->action_area),
++ (GtkCallback) gtk_dialog_resize_button,
++ GINT_TO_POINTER (button_width));
++ g_object_unref (dialog->action_area);
++
++ if (portrait)
++ gtk_box_set_spacing (GTK_BOX (priv->hbox), padding);
++ else
++ update_spacings (dialog);
++
++ gtk_window_resize (GTK_WINDOW (dialog), 1, 1);
++}
++
++static void
++gtk_dialog_realize (GtkWidget *widget)
++{
++ GdkScreen *screen = gtk_widget_get_screen (widget);
++
++ GTK_WIDGET_CLASS (gtk_dialog_parent_class)->realize (widget);
++
++ if (gdk_screen_get_width (screen) < gdk_screen_get_height (screen))
++ gtk_dialog_screen_size_changed_cb (screen, GTK_DIALOG (widget));
++
++ g_signal_connect (screen, "size-changed",
++ G_CALLBACK (gtk_dialog_screen_size_changed_cb), widget);
++}
++
++static void
++gtk_dialog_unrealize (GtkWidget *widget)
++{
++ GdkScreen *screen = gtk_widget_get_screen (widget);
++
++ g_signal_handlers_disconnect_by_func (
++ screen, gtk_dialog_screen_size_changed_cb, widget);
++
++ GTK_WIDGET_CLASS (gtk_dialog_parent_class)->unrealize (widget);
++}
++
++static void
++gtk_dialog_size_request (GtkWidget *widget,
++ GtkRequisition *requisition)
++{
++ GtkWindow *window;
++ GdkWindowTypeHint type_hint;
++
++ GTK_WIDGET_CLASS (gtk_dialog_parent_class)->size_request (widget,
++ requisition);
++
++ window = GTK_WINDOW (widget);
++ type_hint = gtk_window_get_type_hint (window);
++
++ if (window->type == GTK_WINDOW_TOPLEVEL &&
++ (type_hint == GDK_WINDOW_TYPE_HINT_NORMAL ||
++ type_hint == GDK_WINDOW_TYPE_HINT_DIALOG))
++ {
++ gint width;
++
++ gtk_widget_get_size_request (widget, &width, NULL);
++
++ if (width == -1)
++ {
++ GdkScreen *screen = gtk_widget_get_screen (widget);
++ requisition->width = gdk_screen_get_width (screen);
++ }
++ }
++}
++
+ static GtkWidget *
+ dialog_find_button (GtkDialog *dialog,
+ gint response_id)
+@@ -711,9 +1039,22 @@
+ button = gtk_button_new_from_stock (button_text);
+
+ gtk_widget_set_can_default (button, TRUE);
+-
+- gtk_widget_show (button);
+-
++
++ if (response_id != GTK_RESPONSE_CANCEL &&
++ response_id != GTK_RESPONSE_REJECT &&
++ response_id != GTK_RESPONSE_CLOSE)
++ {
++ gtk_widget_show (button);
++ }
++ else
++ gtk_widget_set_no_show_all (button, TRUE);
++
++ hildon_gtk_widget_set_theme_size (
++ button, HILDON_SIZE_AUTO_WIDTH | HILDON_SIZE_FINGER_HEIGHT);
++ g_object_set (button, "width-request", HILDON_DIALOG_BUTTON_WIDTH, NULL);
++ g_object_set_qdata (G_OBJECT (button), auto_resize_quark (),
++ GINT_TO_POINTER (TRUE));
++
+ gtk_dialog_add_action_widget (dialog,
+ button,
+ response_id);
+@@ -877,13 +1218,14 @@
+
+ if (setting && dialog->separator == NULL)
+ {
+- dialog->separator = gtk_hseparator_new ();
+- gtk_box_pack_end (GTK_BOX (dialog->vbox), dialog->separator, FALSE, TRUE, 0);
++ dialog->separator = gtk_vseparator_new ();
++ gtk_box_pack_end (
++ GTK_BOX (priv->hbox), dialog->separator, FALSE, TRUE, 0);
+
+ /* The app programmer could screw this up, but, their own fault.
+ * Moves the separator just above the action area.
+ */
+- gtk_box_reorder_child (GTK_BOX (dialog->vbox), dialog->separator, 1);
++ gtk_box_reorder_child (GTK_BOX (priv->hbox), dialog->separator, 1);
+ gtk_widget_show (dialog->separator);
+ }
+ else if (!setting && dialog->separator != NULL)
+@@ -914,6 +1256,96 @@
+ }
+
+ /**
++ * gtk_dialog_set_padding:
++ * @dialog: a #GtkDialog
++ * @top_padding: Padding to add at the top of the dialog.
++ * @bottom_padding: Padding to add at the bottom of the dialog.
++ * @left_padding: Padding to add at the left of the dialog.
++ * @right_padding: Padding to add at the right of the dialog.
++ *
++ * Sets additional padding around the dialog.
++ *
++ * Since: maemo 5.0
++ **/
++void
++gtk_dialog_set_padding (GtkDialog *dialog,
++ guint top_padding,
++ guint bottom_padding,
++ guint left_padding,
++ guint right_padding)
++{
++ GtkDialogPrivate *priv;
++
++ g_return_if_fail (GTK_IS_DIALOG (dialog));
++
++ priv = GET_PRIVATE (dialog);
++
++ gtk_alignment_set_padding (GTK_ALIGNMENT (priv->alignment), top_padding, bottom_padding, left_padding, right_padding);
++}
++
++/**
++ * gtk_dialog_get_padding:
++ * @dialog: a #GtkDialog
++ * @padding_top: location to store the padding for the top of the dialog, or %NULL
++ * @padding_bottom: location to store the padding for the bottom of the dialog, or %NULL
++ * @padding_left: location to store the padding for the left of the dialog, or %NULL
++ * @padding_right: location to store the padding for the right of the dialog, or %NULL
++ *
++ * Gets the padding on the different sides of the dialog.
++ *
++ * Since: maemo 5.0
++ **/
++void
++gtk_dialog_get_padding (GtkDialog *dialog,
++ guint *top_padding,
++ guint *bottom_padding,
++ guint *left_padding,
++ guint *right_padding)
++{
++ GtkDialogPrivate *priv;
++
++ g_return_if_fail (GTK_IS_DIALOG (dialog));
++
++ priv = GET_PRIVATE (dialog);
++
++ guint t, b, l, r;
++
++ gtk_alignment_get_padding (GTK_ALIGNMENT (priv->alignment), &t, &b, &l, &r);
++
++ if (top_padding)
++ *top_padding = t;
++ if (bottom_padding)
++ *bottom_padding = b;
++ if (left_padding)
++ *left_padding = l;
++ if (right_padding)
++ *right_padding = r;
++}
++
++void
++gtk_dialog_set_inner_spacing (GtkDialog *dialog,
++ guint inner_spacing)
++{
++ GtkDialogPrivate *priv;
++ g_return_if_fail (GTK_IS_DIALOG (dialog));
++
++ priv = GET_PRIVATE (dialog);
++
++ gtk_box_set_spacing (GTK_BOX (priv->hbox), inner_spacing);
++}
++
++guint
++gtk_dialog_get_inner_spacing (GtkDialog *dialog)
++{
++ GtkDialogPrivate *priv;
++ g_return_val_if_fail (GTK_IS_DIALOG (dialog), 0);
++
++ priv = GET_PRIVATE (dialog);
++
++ return gtk_box_get_spacing (GTK_BOX (priv->hbox));
++}
++
++/**
+ * gtk_dialog_response:
+ * @dialog: a #GtkDialog
+ * @response_id: response ID
+--- a/gtk/gtkdialog.h
++++ b/gtk/gtkdialog.h
+@@ -159,6 +159,21 @@
+ gboolean gtk_dialog_get_has_separator (GtkDialog *dialog);
+ #endif
+
++void gtk_dialog_set_padding (GtkDialog *dialog,
++ guint padding_top,
++ guint padding_bottom,
++ guint padding_left,
++ guint padding_right);
++void gtk_dialog_get_padding (GtkDialog *dialog,
++ guint *padding_top,
++ guint *padding_bottom,
++ guint *padding_left,
++ guint *padding_right);
++
++void gtk_dialog_set_inner_spacing (GtkDialog *dialog,
++ guint inner_spacing);
++guint gtk_dialog_get_inner_spacing (GtkDialog *dialog);
++
+ gboolean gtk_alternative_dialog_button_order (GdkScreen *screen);
+ void gtk_dialog_set_alternative_button_order (GtkDialog *dialog,
+ gint first_response_id,
diff --git a/hildonize-gtk-entry.patch b/hildonize-gtk-entry.patch
new file mode 100644
index 000000000000..266b114b0c2a
--- /dev/null
+++ b/hildonize-gtk-entry.patch
@@ -0,0 +1,958 @@
+--- a/gtk/gtkentry.c
++++ b/gtk/gtkentry.c
+@@ -139,6 +139,9 @@
+ gint start_y;
+
+ gchar *im_module;
++
++ gchar *placeholder_text;
++ PangoLayout *placeholder_layout;
+ };
+
+ typedef struct _GtkEntryPasswordHint GtkEntryPasswordHint;
+@@ -172,6 +175,8 @@
+ ICON_PRESS,
+ ICON_RELEASE,
+ PREEDIT_CHANGED,
++ INVALID_INPUT,
++ SELECT_ALL,
+ LAST_SIGNAL
+ };
+
+@@ -218,7 +223,10 @@
+ PROP_TOOLTIP_MARKUP_PRIMARY,
+ PROP_TOOLTIP_MARKUP_SECONDARY,
+ PROP_IM_MODULE,
+- PROP_EDITING_CANCELED
++ PROP_EDITING_CANCELED,
++ PROP_HILDON_PLACEHOLDER_TEXT,
++ PROP_HILDON_INPUT_MODE,
++ PROP_HILDON_INPUT_DEFAULT
+ };
+
+ static guint signals[LAST_SIGNAL] = { 0 };
+@@ -406,6 +414,13 @@
+ gint offset,
+ gint n_chars,
+ GtkEntry *entry);
++static gboolean gtk_entry_has_selection_cb (GtkIMContext *context,
++ GtkEntry *entry);
++static void gtk_entry_clipboard_operation_cb (GtkIMContext *context,
++ GtkIMContextClipboardOperation op,
++ GtkEntry *entry);
++
++static PangoLayout * gtk_entry_create_placeholder_layout (GtkEntry *entry);
+
+ /* Internal routines
+ */
+@@ -770,7 +785,7 @@
+ g_param_spec_boolean ("truncate-multiline",
+ P_("Truncate multiline"),
+ P_("Whether to truncate multiline pastes to one line."),
+- FALSE,
++ TRUE,
+ GTK_PARAM_READWRITE));
+
+ /**
+@@ -1222,6 +1237,59 @@
+ GTK_PARAM_READWRITE));
+
+ /**
++ * GtkEntry:hildon-placeholder-text:
++ *
++ * Text to be displayed in the #GtkEntry when it is empty.
++ *
++ * Since: maemo 5
++ */
++ g_object_class_install_property (gobject_class,
++ PROP_HILDON_PLACEHOLDER_TEXT,
++ g_param_spec_string ("hildon-placeholder-text",
++ P_("Hildon Placeholder text"),
++ P_("Text to be displayed when the entry is empty"),
++ "",
++ G_PARAM_READWRITE));
++
++ /**
++ * GtkEntry:hildon-input-mode:
++ *
++ * Allowed characters and input mode for the entry. See #HildonGtkInputMode.
++ *
++ * Since: maemo 2.0
++ * Stability: Unstable
++ */
++ g_object_class_install_property (gobject_class,
++ PROP_HILDON_INPUT_MODE,
++ g_param_spec_flags ("hildon-input-mode",
++ P_("Hildon input mode"),
++ P_("Define widget's input mode"),
++ HILDON_TYPE_GTK_INPUT_MODE,
++ HILDON_GTK_INPUT_MODE_FULL |
++ HILDON_GTK_INPUT_MODE_AUTOCAP |
++ HILDON_GTK_INPUT_MODE_DICTIONARY,
++ GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
++
++ /**
++ * GtkEntry:hildon-input-default:
++ *
++ * Default input mode for this IM context. See #HildonGtkInputMode.
++ * The default setting for this property is %HILDON_GTK_INPUT_MODE_FULL,
++ * which means that the default input mode to be used is up to the
++ * implementation of the IM context.
++ *
++ * Since: maemo 5
++ */
++ g_object_class_install_property (gobject_class,
++ PROP_HILDON_INPUT_DEFAULT,
++ g_param_spec_flags ("hildon-input-default",
++ P_("Hildon input default"),
++ P_("Define widget's default input mode"),
++ HILDON_TYPE_GTK_INPUT_MODE,
++ HILDON_GTK_INPUT_MODE_FULL,
++ GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
++
++ /**
+ * GtkEntry:icon-prelight:
+ *
+ * The prelight style property determines whether activatable
+@@ -1572,6 +1640,46 @@
+ G_TYPE_NONE, 1,
+ G_TYPE_STRING);
+
++ /**
++ * GtkEntry::invalid-input:
++ *
++ * Emitted when the users enters a character that does not belong to the
++ * #HildonGtkInputMode of the entry, or the maximum number of characters
++ * has been reached.
++ *
++ * Since: maemo 1.0
++ * Stability: Unstable
++ */
++ signals[INVALID_INPUT] =
++ g_signal_new ("invalid_input",
++ G_OBJECT_CLASS_TYPE (gobject_class),
++ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
++ G_STRUCT_OFFSET (GtkEntryClass, invalid_input),
++ NULL, NULL,
++ _gtk_marshal_VOID__ENUM,
++ G_TYPE_NONE, 1,
++ GTK_TYPE_INVALID_INPUT_TYPE);
++
++ /**
++ * GtkEntry::select-all:
++ * @entry: the object which received the signal
++ *
++ * The ::select-all signal is a
++ * <link linkend="keybinding-signals">keybinding signal</link>
++ * which gets emitted to select the complete contents of the entry.
++ *
++ * The default bindings for this signal are Ctrl-a and Ctrl-/.
++ *
++ * Since: 2.20
++ */
++ signals[SELECT_ALL] =
++ g_signal_new_class_handler (I_("select-all"),
++ G_OBJECT_CLASS_TYPE (gobject_class),
++ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
++ G_CALLBACK (gtk_entry_select_all),
++ NULL, NULL,
++ g_cclosure_marshal_VOID__VOID,
++ G_TYPE_NONE, 0, G_TYPE_NONE);
+
+ /*
+ * Key bindings
+@@ -1631,26 +1739,9 @@
+ /* Select all
+ */
+ gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK,
+- "move-cursor", 3,
+- GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS,
+- G_TYPE_INT, -1,
+- G_TYPE_BOOLEAN, FALSE);
+- gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK,
+- "move-cursor", 3,
+- GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS,
+- G_TYPE_INT, 1,
+- G_TYPE_BOOLEAN, TRUE);
+-
+- gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK,
+- "move-cursor", 3,
+- GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS,
+- G_TYPE_INT, -1,
+- G_TYPE_BOOLEAN, FALSE);
++ "select-all", 0);
+ gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK,
+- "move-cursor", 3,
+- GTK_TYPE_MOVEMENT_STEP, GTK_MOVEMENT_BUFFER_ENDS,
+- G_TYPE_INT, 1,
+- G_TYPE_BOOLEAN, TRUE);
++ "select-all", 0);
+ /* Unselect all
+ */
+ gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_CONTROL_MASK,
+@@ -1830,7 +1921,20 @@
+ break;
+
+ case PROP_VISIBILITY:
+- gtk_entry_set_visibility (entry, g_value_get_boolean (value));
++ {
++ /* converting to hildon input mode first then through
++ * that mode changing function to reach compatible with
++ * the gtk original visibility changing
++ */
++ HildonGtkInputMode mode = hildon_gtk_entry_get_input_mode (entry);
++
++ if (g_value_get_boolean (value))
++ mode &= ~HILDON_GTK_INPUT_MODE_INVISIBLE;
++ else
++ mode |= HILDON_GTK_INPUT_MODE_INVISIBLE;
++
++ hildon_gtk_entry_set_input_mode (entry, mode);
++ }
+ break;
+
+ case PROP_HAS_FRAME:
+@@ -1999,6 +2103,18 @@
+ entry->editing_canceled = g_value_get_boolean (value);
+ break;
+
++ case PROP_HILDON_PLACEHOLDER_TEXT:
++ hildon_gtk_entry_set_placeholder_text (entry, g_value_get_string (value));
++ break;
++
++ case PROP_HILDON_INPUT_MODE:
++ hildon_gtk_entry_set_input_mode (entry, g_value_get_flags (value));
++ break;
++
++ case PROP_HILDON_INPUT_DEFAULT:
++ hildon_gtk_entry_set_input_default (entry, g_value_get_flags (value));
++ break;
++
+ case PROP_SCROLL_OFFSET:
+ case PROP_CURSOR_POSITION:
+ default:
+@@ -2215,6 +2331,18 @@
+ entry->editing_canceled);
+ break;
+
++ case PROP_HILDON_PLACEHOLDER_TEXT:
++ g_value_set_string (value, hildon_gtk_entry_get_placeholder_text (entry));
++ break;
++
++ case PROP_HILDON_INPUT_MODE:
++ g_value_set_flags (value, hildon_gtk_entry_get_input_mode (entry));
++ break;
++
++ case PROP_HILDON_INPUT_DEFAULT:
++ g_value_set_flags (value, hildon_gtk_entry_get_input_default (entry));
++ break;
++
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+@@ -2285,13 +2413,15 @@
+ entry->is_cell_renderer = FALSE;
+ entry->editing_canceled = FALSE;
+ entry->has_frame = TRUE;
+- entry->truncate_multiline = FALSE;
++ entry->truncate_multiline = TRUE;
+ priv->shadow_type = GTK_SHADOW_IN;
+ priv->xalign = 0.0;
+ priv->caps_lock_warning = TRUE;
+ priv->caps_lock_warning_shown = FALSE;
+ priv->progress_fraction = 0.0;
+ priv->progress_pulse_fraction = 0.1;
++ priv->placeholder_text = NULL;
++ priv->placeholder_layout = NULL;
+
+ gtk_drag_dest_set (GTK_WIDGET (entry),
+ GTK_DEST_DEFAULT_HIGHLIGHT,
+@@ -2312,7 +2442,10 @@
+ G_CALLBACK (gtk_entry_retrieve_surrounding_cb), entry);
+ g_signal_connect (entry->im_context, "delete-surrounding",
+ G_CALLBACK (gtk_entry_delete_surrounding_cb), entry);
+-
++ g_signal_connect (entry->im_context, "has_selection",
++ G_CALLBACK (gtk_entry_has_selection_cb), entry);
++ g_signal_connect (entry->im_context, "clipboard_operation",
++ G_CALLBACK (gtk_entry_clipboard_operation_cb), entry);
+ }
+
+ static gint
+@@ -2498,6 +2631,18 @@
+
+ g_free (priv->im_module);
+
++ if (priv->placeholder_text)
++ {
++ g_free (priv->placeholder_text);
++ priv->placeholder_text = NULL;
++ }
++
++ if (priv->placeholder_layout)
++ {
++ g_object_unref (priv->placeholder_layout);
++ priv->placeholder_layout = NULL;
++ }
++
+ G_OBJECT_CLASS (gtk_entry_parent_class)->finalize (object);
+ }
+
+@@ -3656,6 +3801,16 @@
+
+ gtk_entry_reset_blink_time (entry);
+
++ if (entry->editable)
++ {
++ if (hildon_gtk_im_context_filter_event (entry->im_context,
++ (GdkEvent *) event))
++ {
++ entry->need_im_reset = TRUE;
++ return TRUE;
++ }
++ }
++
+ entry->button = event->button;
+
+ if (!gtk_widget_has_focus (widget))
+@@ -3665,6 +3820,9 @@
+ entry->in_click = FALSE;
+ }
+
++ /* we need to reset IM context so pre-edit string can be committed */
++ _gtk_entry_reset_im_context (entry);
++
+ tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset);
+
+ if (_gtk_button_event_triggers_context_menu (event))
+@@ -3683,8 +3841,6 @@
+
+ if (event->state & GTK_EXTEND_SELECTION_MOD_MASK)
+ {
+- _gtk_entry_reset_im_context (entry);
+-
+ if (!have_selection) /* select from the current position to the clicked position */
+ sel_start = sel_end = entry->current_pos;
+
+@@ -3842,6 +3998,16 @@
+ if (event->window != entry->text_area || entry->button != event->button)
+ return FALSE;
+
++ if (entry->editable)
++ {
++ if (hildon_gtk_im_context_filter_event (entry->im_context,
++ (GdkEvent *) event))
++ {
++ entry->need_im_reset = TRUE;
++ return TRUE;
++ }
++ }
++
+ if (entry->in_drag)
+ {
+ gint tmp_pos = gtk_entry_find_position (entry, entry->drag_start_x);
+@@ -4349,6 +4515,14 @@
+ {
+ GtkEntry *entry = GTK_ENTRY (editable);
+ guint length;
++ GtkWidget *widget = GTK_WIDGET (editable);
++ gboolean flip = FALSE;
++
++ if (start == 0 && end == -1 && gtk_widget_has_screen (widget))
++ {
++ GtkSettings *settings = gtk_widget_get_settings (widget);
++ g_object_get (settings, "gtk-touchscreen-mode", &flip, NULL);
++ }
+
+ length = gtk_entry_buffer_get_length (get_buffer (entry));
+ if (start < 0)
+@@ -4356,11 +4530,14 @@
+ if (end < 0)
+ end = length;
+
+- _gtk_entry_reset_im_context (entry);
+-
+- gtk_entry_set_positions (entry,
+- MIN (end, length),
+- MIN (start, length));
++ if (flip)
++ gtk_entry_set_positions (entry,
++ MIN (start, entry->text_length),
++ MIN (end, entry->text_length));
++ else
++ gtk_entry_set_positions (entry,
++ MIN (end, entry->text_length),
++ MIN (start, entry->text_length));
+
+ gtk_entry_update_primary_selection (entry);
+ }
+@@ -4435,6 +4612,12 @@
+
+ gtk_entry_recompute (entry);
+
++ if (priv->placeholder_text)
++ {
++ g_object_unref (priv->placeholder_layout);
++ priv->placeholder_layout = gtk_entry_create_placeholder_layout (entry);
++ }
++
+ if (previous_style && gtk_widget_get_realized (widget))
+ {
+ gdk_window_set_background (widget->window, &widget->style->base[gtk_widget_get_state (widget)]);
+@@ -4507,7 +4690,6 @@
+ g_slice_free (GtkEntryPasswordHint, password_hint);
+ }
+
+-
+ static gboolean
+ gtk_entry_remove_password_hint (gpointer data)
+ {
+@@ -4519,6 +4701,113 @@
+ return FALSE;
+ }
+
++/* Returns TRUE if chr is valid in given input mode. Probably should
++ * be made public, but there's no good place for it and the input mode
++ * design might change, so for now we'll keep this here.
++ */
++static gboolean
++hildon_gtk_input_mode_is_valid_char (HildonGtkInputMode mode,
++ gunichar chr,
++ gunichar *chr_)
++{
++ static const char *tele_chars_ascii = "p#*+";
++
++ if (g_unichar_isalpha (chr) || chr == ' ')
++ {
++ if ((mode & HILDON_GTK_INPUT_MODE_ALPHA) != 0)
++ return TRUE;
++ if ((mode & HILDON_GTK_INPUT_MODE_HEXA) != 0 && g_unichar_isxdigit(chr))
++ return TRUE;
++ }
++ else if (g_unichar_isdigit (chr))
++ {
++ if ((mode & (HILDON_GTK_INPUT_MODE_NUMERIC |
++ HILDON_GTK_INPUT_MODE_HEXA |
++ HILDON_GTK_INPUT_MODE_TELE)) != 0)
++ {
++ gchar* number = g_strdup_printf ("%d", g_unichar_digit_value (chr));
++ *chr_ = g_utf8_get_char (number);
++ g_free (number);
++ return chr == *chr_;
++ }
++ }
++ else
++ {
++ /* special = anything else than alphanumeric/space */
++ if ((mode & HILDON_GTK_INPUT_MODE_SPECIAL) != 0)
++ return TRUE;
++
++ /* numeric also contains '-', but hexa doesn't */
++ if ((mode & HILDON_GTK_INPUT_MODE_NUMERIC) != 0 && chr == '-')
++ return TRUE;
++ }
++
++ /* check special tele chars last */
++ if ((mode & HILDON_GTK_INPUT_MODE_TELE) != 0 &&
++ strchr(tele_chars_ascii, chr) != NULL)
++ return TRUE;
++
++ return FALSE;
++}
++
++static gboolean
++gtk_entry_filter_text (GtkEntry *entry,
++ const gchar *str,
++ gint length,
++ gint nbytes,
++ gchar **filtered)
++{
++ HildonGtkInputMode input_mode;
++
++ g_assert (GTK_IS_ENTRY (entry));
++
++ if (!length || !str)
++ return FALSE;
++
++ if (!g_utf8_validate (str, nbytes, NULL))
++ return FALSE;
++
++ input_mode = hildon_gtk_entry_get_input_mode (entry);
++
++ if ((input_mode & HILDON_GTK_INPUT_MODE_TELE) != 0)
++ {
++ gboolean valid = TRUE;
++ GString *result = g_string_sized_new (nbytes);
++
++ while(length)
++ {
++ gunichar chr = g_utf8_get_char (str);
++ gunichar chr_ = chr;
++ gboolean valid_char;
++
++ valid_char = hildon_gtk_input_mode_is_valid_char (input_mode, chr, &chr_);
++ if (valid_char || chr != chr_)
++ g_string_append_unichar (result, chr_);
++ if (!valid_char)
++ valid = FALSE;
++
++ str = g_utf8_next_char (str);
++ length--;
++ }
++
++ *filtered = g_string_free (result, FALSE);
++ return valid;
++ }
++
++ while(length)
++ {
++ gunichar chr = g_utf8_get_char (str);
++
++ if (!hildon_gtk_input_mode_is_valid_char (input_mode, chr, &chr))
++ return FALSE;
++
++ str = g_utf8_next_char (str);
++ length--;
++ }
++
++ return TRUE;
++}
++
+ /* Default signal handlers
+ */
+ static void
+@@ -4529,9 +4818,28 @@
+ {
+ guint n_inserted;
+ gint n_chars;
++ gchar *filtered = NULL;
++ GtkEntry *entry = GTK_ENTRY (editable);
+
+ n_chars = g_utf8_strlen (new_text, new_text_length);
+
++ if (!gtk_entry_filter_text (entry, new_text, n_chars,
++ new_text_length, &filtered))
++ {
++ if (filtered)
++ {
++ new_text = filtered;
++ new_text_length = strlen (filtered);
++ n_chars = g_utf8_strlen (filtered, new_text_length);
++ }
++ else
++ {
++ g_signal_emit (entry, signals[INVALID_INPUT], 0,
++ GTK_INVALID_INPUT_MODE_RESTRICTION);
++ return;
++ }
++ }
++
+ /*
+ * The actual insertion into the buffer. This will end up firing the
+ * following signal handlers: buffer_inserted_text(), buffer_notify_display_text(),
+@@ -4540,9 +4848,13 @@
+ n_inserted = gtk_entry_buffer_insert_text (get_buffer (GTK_ENTRY (editable)), *position, new_text, n_chars);
+
+ if (n_inserted != n_chars)
+- gtk_widget_error_bell (GTK_WIDGET (editable));
++ {
++ g_signal_emit (entry, signals[INVALID_INPUT], 0,
++ GTK_INVALID_INPUT_MAX_CHARS_REACHED);
++ }
+
+ *position += n_inserted;
++ g_free (filtered);
+ }
+
+ static void
+@@ -4871,8 +5183,6 @@
+ gint end_pos = entry->current_pos;
+ gint old_n_bytes = gtk_entry_buffer_get_bytes (get_buffer (entry));
+
+- _gtk_entry_reset_im_context (entry);
+-
+ if (!entry->editable)
+ {
+ gtk_widget_error_bell (GTK_WIDGET (entry));
+@@ -4947,8 +5257,6 @@
+ GtkEditable *editable = GTK_EDITABLE (entry);
+ gint prev_pos;
+
+- _gtk_entry_reset_im_context (entry);
+-
+ if (!entry->editable)
+ {
+ gtk_widget_error_bell (GTK_WIDGET (entry));
+@@ -5193,6 +5501,36 @@
+ return TRUE;
+ }
+
++static gboolean
++gtk_entry_has_selection_cb (GtkIMContext *context,
++ GtkEntry *entry)
++{
++ return gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), NULL, NULL);
++}
++
++static void
++gtk_entry_clipboard_operation_cb (GtkIMContext *context,
++ GtkIMContextClipboardOperation op,
++ GtkEntry *entry)
++{
++ /* Similar to gtk_editable_*_clipboard(), handle these by sending
++ * signals instead of directly calling our internal functions. That
++ * way the application can hook into them if needed.
++ */
++ switch (op)
++ {
++ case GTK_IM_CONTEXT_CLIPBOARD_OP_COPY:
++ g_signal_emit_by_name (entry, "copy_clipboard");
++ break;
++ case GTK_IM_CONTEXT_CLIPBOARD_OP_CUT:
++ g_signal_emit_by_name (entry, "cut_clipboard");
++ break;
++ case GTK_IM_CONTEXT_CLIPBOARD_OP_PASTE:
++ g_signal_emit_by_name (entry, "paste_clipboard");
++ break;
++ }
++}
++
+ /* Internal functions
+ */
+
+@@ -5334,6 +5672,58 @@
+ }
+
+ static PangoLayout *
++gtk_entry_create_placeholder_layout (GtkEntry *entry)
++{
++ GtkWidget *widget = GTK_WIDGET (entry);
++ PangoLayout *layout = gtk_widget_create_pango_layout (widget, NULL);
++ GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
++ PangoDirection pango_dir;
++ GdkColor font_color;
++
++ pango_layout_set_single_paragraph_mode (layout, TRUE);
++
++ pango_dir = pango_find_base_dir (priv->placeholder_text,
++ strlen (priv->placeholder_text));
++
++ if (pango_dir == PANGO_DIRECTION_NEUTRAL)
++ {
++ if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
++ pango_dir = PANGO_DIRECTION_RTL;
++ else
++ pango_dir = PANGO_DIRECTION_LTR;
++ }
++
++ pango_context_set_base_dir (gtk_widget_get_pango_context (widget),
++ pango_dir);
++
++ pango_layout_set_alignment (layout, pango_dir);
++
++ pango_layout_set_text (layout, priv->placeholder_text,
++ strlen (priv->placeholder_text));
++
++ if (gtk_style_lookup_color (widget->style, "ReversedSecondaryTextColor",
++ &font_color))
++ {
++ PangoAttrList *list;
++ PangoAttribute *attr;
++
++ list = pango_attr_list_new ();
++ attr = pango_attr_foreground_new (font_color.red,
++ font_color.green,
++ font_color.blue);
++ attr->start_index = 0;
++ attr->end_index = G_MAXINT;
++ pango_attr_list_insert (list, attr);
++
++ pango_layout_set_attributes (layout, list);
++
++ pango_attr_list_unref (list);
++ }
++
++ return layout;
++}
++
++static PangoLayout *
+ gtk_entry_create_layout (GtkEntry *entry,
+ gboolean include_preedit)
+ {
+@@ -5441,6 +5831,19 @@
+ return entry->cached_layout;
+ }
+
++static inline gboolean
++show_placeholder (GtkEntry *entry)
++{
++ GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
++
++ if (!gtk_widget_has_focus (GTK_WIDGET (entry))
++ && gtk_entry_buffer_get_bytes (get_buffer (entry)) == 0
++ && priv->placeholder_text)
++ return TRUE;
++
++ return FALSE;
++}
++
+ static void
+ get_layout_position (GtkEntry *entry,
+ gint *x,
+@@ -5452,8 +5855,12 @@
+ GtkBorder inner_border;
+ gint y_pos;
+ PangoLayoutLine *line;
++ GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
+
+- layout = gtk_entry_ensure_layout (entry, TRUE);
++ if (show_placeholder (entry))
++ layout = priv->placeholder_layout;
++ else
++ layout = gtk_entry_ensure_layout (entry, TRUE);
+
+ gtk_entry_get_text_area_size (entry, NULL, NULL, &area_width, &area_height);
+ _gtk_entry_effective_inner_border (entry, &inner_border);
+@@ -5487,13 +5894,19 @@
+ static void
+ draw_text_with_color (GtkEntry *entry, cairo_t *cr, GdkColor *default_color)
+ {
+- PangoLayout *layout = gtk_entry_ensure_layout (entry, TRUE);
++ GtkEntryPrivate *priv = GTK_ENTRY_GET_PRIVATE (entry);
++ PangoLayout *layout;
+ GtkWidget *widget;
+ gint x, y;
+ gint start_pos, end_pos;
+
+ widget = GTK_WIDGET (entry);
+
++ if (show_placeholder (entry))
++ layout = priv->placeholder_layout;
++ else
++ layout = gtk_entry_ensure_layout (entry, TRUE);
++
+ cairo_save (cr);
+
+ get_layout_position (entry, &x, &y);
+@@ -5772,11 +6185,7 @@
+ void
+ _gtk_entry_reset_im_context (GtkEntry *entry)
+ {
+- if (entry->need_im_reset)
+- {
+- entry->need_im_reset = FALSE;
+- gtk_im_context_reset (entry->im_context);
+- }
++ gtk_im_context_reset (entry->im_context);
+ }
+
+ /**
+@@ -6898,15 +7307,19 @@
+ {
+ g_return_if_fail (GTK_IS_ENTRY (entry));
+
+- visible = visible != FALSE;
++ g_object_set (G_OBJECT (entry), "visibility", visible, NULL);
++}
+
+- if (entry->visible != visible)
+- {
+- entry->visible = visible;
++static void
++gtk_entry_set_real_visibility (GtkEntry *entry,
++ gboolean visible)
++{
++ g_return_if_fail (GTK_IS_ENTRY (entry));
+
+- g_object_notify (G_OBJECT (entry), "visibility");
+- gtk_entry_recompute (entry);
+- }
++ entry->visible = visible ? TRUE : FALSE;
++ g_object_notify (G_OBJECT (entry), "visibility");
++
++ gtk_entry_recompute (entry);
+ }
+
+ /**
+@@ -10129,5 +10542,150 @@
+ remove_capslock_feedback (entry);
+ }
+
++/**
++ * hildon_gtk_entry_set_placeholder_text:
++ * @entry: a #GtkEntry
++ * @placeholder_text: a string to be displayed when @entry is empty
++ * and unfocused or %NULL to remove current placeholder text.
++ *
++ * Sets a text string to be displayed when @entry is empty and unfocused.
++ * This can be provided to give a visual hint of the expected contents
++ * of the #GtkEntry.
++ *
++ * Since: maemo 5
++ **/
++void
++hildon_gtk_entry_set_placeholder_text (GtkEntry *entry,
++ const gchar *placeholder_text)
++{
++ GtkEntryPrivate *priv;
++
++ g_return_if_fail (GTK_IS_ENTRY (entry));
++
++ priv = GTK_ENTRY_GET_PRIVATE (entry);
++
++ if (priv->placeholder_text)
++ {
++ g_free (priv->placeholder_text);
++ g_object_unref (priv->placeholder_layout);
++ }
++
++ if (placeholder_text)
++ {
++ priv->placeholder_text = g_strdup (placeholder_text);
++ priv->placeholder_layout = gtk_entry_create_placeholder_layout (entry);
++ }
++ else
++ {
++ priv->placeholder_text = NULL;
++ priv->placeholder_layout = NULL;
++ }
++
++ if (show_placeholder (entry))
++ {
++ gtk_widget_queue_draw (GTK_WIDGET (entry));
++ }
++
++ g_object_notify (G_OBJECT (entry), "hildon-placeholder-text");
++}
++
++/**
++ * hildon_gtk_entry_get_placeholder_text:
++ * @entry: a #GtkEntry
++ *
++ * Gets the text to be displayed if @entry is empty and unfocused.
++ *
++ * Returns: a string or %NULL if no placeholder text is set
++ *
++ * Since: maemo 5
++ **/
++const gchar *
++hildon_gtk_entry_get_placeholder_text (GtkEntry *entry)
++{
++ GtkEntryPrivate *priv;
++
++ g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
++
++ priv = GTK_ENTRY_GET_PRIVATE (entry);
++
++ return priv->placeholder_text;
++}
++
++void
++hildon_gtk_entry_set_input_mode (GtkEntry *entry,
++ HildonGtkInputMode mode)
++{
++ g_return_if_fail (GTK_IS_ENTRY (entry));
++
++ if (hildon_gtk_entry_get_input_mode (entry) != mode)
++ {
++ gtk_entry_set_real_visibility (entry,
++ mode & HILDON_GTK_INPUT_MODE_INVISIBLE
++ ? FALSE : TRUE);
++ g_object_set (G_OBJECT (entry->im_context),
++ "hildon-input-mode", mode, NULL);
++ g_object_notify (G_OBJECT (entry), "hildon-input-mode");
++ }
++}
++
++HildonGtkInputMode
++hildon_gtk_entry_get_input_mode (GtkEntry *entry)
++{
++ HildonGtkInputMode mode;
++
++ g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
++
++ g_object_get (G_OBJECT (entry->im_context),
++ "hildon-input-mode", &mode, NULL);
++
++ return mode;
++}
++
++/**
++ * hildon_gtk_entry_set_input_default:
++ * @entry: a #GtkEntry
++ * @mode: a #HildonGtkInputMode
++ *
++ * Sets the default input mode of the widget.
++ *
++ * Since: maemo 5.0
++ */
++void
++hildon_gtk_entry_set_input_default (GtkEntry *entry,
++ HildonGtkInputMode mode)
++{
++ g_return_if_fail (GTK_IS_ENTRY (entry));
++
++ if (hildon_gtk_entry_get_input_default (entry) != mode)
++ {
++ g_object_set (G_OBJECT (entry->im_context),
++ "hildon-input-default", mode, NULL);
++ g_object_notify (G_OBJECT (entry), "hildon-input-default");
++ }
++}
++
++/**
++ * hildon_gtk_entry_get_input_default:
++ * @entry: a #GtkEntry
++ *
++ * Gets the default input mode of the widget.
++ *
++ * Return value: the default input mode of the widget.
++ *
++ * Since: maemo 5.0
++ */
++HildonGtkInputMode
++hildon_gtk_entry_get_input_default (GtkEntry *entry)
++{
++ HildonGtkInputMode mode;
++
++ g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
++
++ g_object_get (G_OBJECT (entry->im_context),
++ "hildon-input-default", &mode, NULL);
++
++ return mode;
++}
++
+ #define __GTK_ENTRY_C__
+ #include "gtkaliasdef.c"
+--- a/gtk/gtkentry.h
++++ b/gtk/gtkentry.h
+@@ -160,6 +160,8 @@
+
+ /* Padding for future expansion */
+ void (*_gtk_reserved1) (void);
++ void (* invalid_input) (GtkEntry *entry,
++ GtkInvalidInputType invalid_input_type);
+ void (*_gtk_reserved2) (void);
+ };
+
+@@ -329,6 +331,19 @@
+ gboolean editable);
+ #endif /* GTK_DISABLE_DEPRECATED */
+
++const gchar * hildon_gtk_entry_get_placeholder_text (GtkEntry *entry);
++
++void hildon_gtk_entry_set_placeholder_text (GtkEntry *entry,
++ const gchar *placeholder_text);
++
++void hildon_gtk_entry_set_input_mode (GtkEntry *entry,
++ HildonGtkInputMode input_mode);
++HildonGtkInputMode hildon_gtk_entry_get_input_mode (GtkEntry *entry);
++
++void hildon_gtk_entry_set_input_default (GtkEntry *entry,
++ HildonGtkInputMode input_mode);
++HildonGtkInputMode hildon_gtk_entry_get_input_default (GtkEntry *entry);
++
+ G_END_DECLS
+
+ #endif /* __GTK_ENTRY_H__ */
diff --git a/hildonize-gtk-enums.patch b/hildonize-gtk-enums.patch
new file mode 100644
index 000000000000..3d1bfda3f061
--- /dev/null
+++ b/hildonize-gtk-enums.patch
@@ -0,0 +1,92 @@
+--- a/gtk/gtkenums.h
++++ b/gtk/gtkenums.h
+@@ -579,6 +579,52 @@
+ GTK_DRAG_RESULT_ERROR
+ } GtkDragResult;
+
++typedef enum
++{
++ GTK_INVALID_INPUT_MAX_CHARS_REACHED,
++ GTK_INVALID_INPUT_MODE_RESTRICTION
++} GtkInvalidInputType;
++
++typedef enum
++{
++ HILDON_GTK_INPUT_MODE_ALPHA = 1 << 0,
++ HILDON_GTK_INPUT_MODE_NUMERIC = 1 << 1,
++ HILDON_GTK_INPUT_MODE_SPECIAL = 1 << 2,
++ HILDON_GTK_INPUT_MODE_HEXA = 1 << 3,
++ HILDON_GTK_INPUT_MODE_TELE = 1 << 4,
++ HILDON_GTK_INPUT_MODE_FULL = (HILDON_GTK_INPUT_MODE_ALPHA | HILDON_GTK_INPUT_MODE_NUMERIC | HILDON_GTK_INPUT_MODE_SPECIAL),
++ HILDON_GTK_INPUT_MODE_NO_SCREEN_PLUGINS = 1 << 27,
++ HILDON_GTK_INPUT_MODE_MULTILINE = 1 << 28,
++ HILDON_GTK_INPUT_MODE_INVISIBLE = 1 << 29,
++ HILDON_GTK_INPUT_MODE_AUTOCAP = 1 << 30,
++ HILDON_GTK_INPUT_MODE_DICTIONARY = 1 << 31
++} HildonGtkInputMode;
++
++/* Temporary compatibility define */
++#define GTK_TYPE_GTK_INPUT_MODE HILDON_TYPE_GTK_INPUT_MODE
++
++typedef enum
++{
++ HILDON_DIABLO,
++ HILDON_FREMANTLE
++} HildonMode;
++
++typedef enum
++{
++ HILDON_UI_MODE_NORMAL,
++ HILDON_UI_MODE_EDIT
++} HildonUIMode;
++
++typedef enum {
++ HILDON_SIZE_AUTO_WIDTH = 0 << 0, /* set to automatic width */
++ HILDON_SIZE_HALFSCREEN_WIDTH = 1 << 0, /* set to 50% screen width */
++ HILDON_SIZE_FULLSCREEN_WIDTH = 2 << 0, /* set to 100% screen width */
++ HILDON_SIZE_AUTO_HEIGHT = 0 << 2, /* set to automatic height */
++ HILDON_SIZE_FINGER_HEIGHT = 1 << 2, /* set to finger height */
++ HILDON_SIZE_THUMB_HEIGHT = 2 << 2, /* set to thumb height */
++ HILDON_SIZE_AUTO = (HILDON_SIZE_AUTO_WIDTH | HILDON_SIZE_AUTO_HEIGHT)
++} HildonSizeType;
++
+ G_END_DECLS
+
+ #endif /* __GTK_ENUMS_H__ */
+--- a/gtk/Makefile.am
++++ b/gtk/Makefile.am
+@@ -837,6 +837,7 @@
+ # versions in the build dir. thus a development setup requires
+ # srcdir to be writable, passing --disable-rebuilds to
+ # ../configure will supress all autogeneration rules.
++
+ gtkmarshalers.h: stamp-gtkmarshalers.h
+ @true
+ stamp-gtkmarshalers.h: @REBUILD@ gtkmarshalers.list
+@@ -844,7 +845,7 @@
+ && (cmp -s xgen-gmlh gtkmarshalers.h || cp xgen-gmlh gtkmarshalers.h) \
+ && rm -f xgen-gmlh \
+ && echo timestamp > $(@F)
+-gtkmarshalers.c: @REBUILD@ gtkmarshalers.list
++gtkmarshalers.c: gtkmarshalers.h @REBUILD@ gtkmarshalers.list
+ (echo "#include \"gtkmarshalers.h\""; \
+ echo "#include \"gtkalias.h\""; \
+ $(GLIB_GENMARSHAL) --prefix=_gtk_marshal $(srcdir)/gtkmarshalers.list --body) >> xgen-gmlc \
+@@ -860,7 +861,7 @@
+ && (cmp -s xgen-gmh gtkmarshal.h || cp xgen-gmh gtkmarshal.h) \
+ && rm -f xgen-gmh \
+ && echo timestamp > $(@F)
+-gtkmarshal.c: @REBUILD@ gtkmarshal.list
++gtkmarshal.c: gtkmarshal.h @REBUILD@ gtkmarshal.list
+ (echo "#include \"gtkmarshal.h\""; \
+ echo "#include \"gtkalias.h\""; \
+ $(GLIB_GENMARSHAL) --prefix=gtk_marshal $(srcdir)/gtkmarshal.list --body; \
+@@ -877,7 +878,7 @@
+ && (cmp -s xgen-gtbh gtktypebuiltins.h || cp xgen-gtbh gtktypebuiltins.h ) \
+ && rm -f xgen-gtbh \
+ && echo timestamp > $(@F)
+-gtktypebuiltins.c: @REBUILD@ $(gtk_public_h_sources) gtktypebuiltins.c.template
++gtktypebuiltins.c: gtktypebuiltins.h @REBUILD@ $(gtk_public_h_sources) gtktypebuiltins.c.template
+ ( cd $(srcdir) && $(GLIB_MKENUMS) --template gtktypebuiltins.c.template \
+ $(gtk_public_h_sources) ) > xgen-gtbc \
+ && cp xgen-gtbc gtktypebuiltins.c \
diff --git a/hildonize-gtk-iconview.patch b/hildonize-gtk-iconview.patch
new file mode 100644
index 000000000000..9fb2465f2eec
--- /dev/null
+++ b/hildonize-gtk-iconview.patch
@@ -0,0 +1,1311 @@
+--- a/gtk/gtkiconview.c
++++ b/gtk/gtkiconview.c
+@@ -40,12 +40,15 @@
+ #include "gtkcombobox.h"
+ #include "gtktextbuffer.h"
+ #include "gtktreednd.h"
++#include "gtkicontheme.h"
+ #include "gtkprivate.h"
+ #include "gtkalias.h"
+
+ #undef DEBUG_ICON_VIEW
+
+ #define SCROLL_EDGE_SIZE 15
++#define HILDON_TICK_MARK_SIZE 48
++#define HILDON_ROW_HEADER_HEIGHT 35
+
+ #define GTK_ICON_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ICON_VIEW, GtkIconViewPrivate))
+
+@@ -73,7 +76,7 @@
+
+ guint selected : 1;
+ guint selected_before_rubberbanding : 1;
+-
++ guint is_header : 1;
+ };
+
+ typedef struct _GtkIconViewCellInfo GtkIconViewCellInfo;
+@@ -187,6 +190,20 @@
+ guint extend_selection_pressed : 1;
+
+ guint draw_focus : 1;
++
++ guint queued_select_was_selected : 1;
++
++ HildonUIMode hildon_ui_mode;
++
++ GtkIconViewItem *queued_activate_item;
++ GtkIconViewItem *queued_select_item;
++
++ HildonIconViewRowHeaderFunc row_header_func;
++ gpointer row_header_data;
++ GDestroyNotify row_header_destroy;
++ PangoLayout *row_header_layout;
++
++ GdkPixbuf *tickmark_icon;
+ };
+
+ /* Signals */
+@@ -222,7 +239,8 @@
+ PROP_MARGIN,
+ PROP_REORDERABLE,
+ PROP_TOOLTIP_COLUMN,
+- PROP_ITEM_PADDING
++ PROP_ITEM_PADDING,
++ PROP_HILDON_UI_MODE
+ };
+
+ /* GObject vfuncs */
+@@ -453,6 +471,9 @@
+
+ static void adjust_wrap_width (GtkIconView *icon_view,
+ GtkIconViewItem *item);
++static void free_queued_activate_item (GtkIconView *icon_view);
++static void free_queued_select_item (GtkIconView *icon_view);
++static void hildon_icon_view_setup_row_header_layout (GtkIconView *icon_view);
+
+ /* GtkBuildable */
+ static GtkBuildableIface *parent_buildable_iface;
+@@ -794,7 +815,29 @@
+ 0, G_MAXINT, 6,
+ GTK_PARAM_READWRITE));
+
+-
++ /**
++ * GtkIconView::hildon-ui-mode
++ *
++ * Specifies which UI mode to use. A setting of #HILDON_UI_MODE_NORMAL
++ * will cause the icon view to disable selections and emit item-activated
++ * as soon as an item is pressed. When #HILDON_UI_MODE_EDIT is set,
++ * selections can be made according to the setting of the mode in
++ * GtkIconView::selection-mode.
++ *
++ * Toggling this property will cause the icon view to select an
++ * appropriate selection mode if not already done.
++ *
++ * Since: maemo 5.0
++ * Stability: unstable.
++ */
++ g_object_class_install_property (gobject_class,
++ PROP_HILDON_UI_MODE,
++ g_param_spec_enum ("hildon-ui-mode",
++ P_("Hildon UI Mode"),
++ P_("The mode according to which the icon view should behave"),
++ HILDON_TYPE_UI_MODE,
++ HILDON_UI_MODE_NORMAL,
++ GTK_PARAM_READWRITE));
+
+ /* Style properties */
+ gtk_widget_class_install_style_property (widget_class,
+@@ -1145,6 +1188,11 @@
+ icon_view->priv->item_padding = 6;
+
+ icon_view->priv->draw_focus = TRUE;
++
++ icon_view->priv->hildon_ui_mode = HILDON_UI_MODE_NORMAL;
++
++ icon_view->priv->queued_activate_item = NULL;
++ icon_view->priv->queued_select_item = NULL;
+ }
+
+ static void
+@@ -1184,6 +1232,24 @@
+ icon_view->priv->vadjustment = NULL;
+ }
+
++ if (icon_view->priv->row_header_destroy && icon_view->priv->row_header_data)
++ {
++ (* icon_view->priv->row_header_destroy) (icon_view->priv->row_header_data);
++ icon_view->priv->row_header_data = NULL;
++ }
++
++ if (icon_view->priv->row_header_layout != NULL)
++ {
++ g_object_unref (icon_view->priv->row_header_layout);
++ icon_view->priv->row_header_layout = NULL;
++ }
++
++ if (icon_view->priv->tickmark_icon)
++ {
++ g_object_unref (icon_view->priv->tickmark_icon);
++ icon_view->priv->tickmark_icon = NULL;
++ }
++
+ GTK_OBJECT_CLASS (gtk_icon_view_parent_class)->destroy (object);
+ }
+
+@@ -1258,6 +1324,10 @@
+ gtk_icon_view_set_item_padding (icon_view, g_value_get_int (value));
+ break;
+
++ case PROP_HILDON_UI_MODE:
++ hildon_icon_view_set_hildon_ui_mode (icon_view, g_value_get_enum (value));
++ break;
++
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+@@ -1324,6 +1394,10 @@
+ g_value_set_int (value, icon_view->priv->item_padding);
+ break;
+
++ case PROP_HILDON_UI_MODE:
++ g_value_set_enum (value, icon_view->priv->hildon_ui_mode);
++ break;
++
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+@@ -1425,6 +1499,21 @@
+ gdk_window_set_background (icon_view->priv->bin_window, &widget->style->base[widget->state]);
+ }
+
++ /* Reset the UI mode */
++ hildon_icon_view_set_hildon_ui_mode (icon_view, icon_view->priv->hildon_ui_mode);
++
++ if (icon_view->priv->row_header_layout)
++ hildon_icon_view_setup_row_header_layout (icon_view);
++
++ if (icon_view->priv->tickmark_icon)
++ g_object_unref (icon_view->priv->tickmark_icon);
++
++ icon_view->priv->tickmark_icon =
++ gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
++ "widgets_tickmark_grid",
++ HILDON_TICK_MARK_SIZE,
++ 0, NULL);
++
+ gtk_widget_queue_resize (widget);
+ }
+
+@@ -1561,12 +1650,15 @@
+ gint dest_index;
+ GtkIconViewDropPosition dest_pos;
+ GtkIconViewItem *dest_item = NULL;
++ HildonMode mode;
+
+ icon_view = GTK_ICON_VIEW (widget);
+
+ if (expose->window != icon_view->priv->bin_window)
+ return FALSE;
+
++ gtk_widget_style_get (widget, "hildon-mode", &mode, NULL);
++
+ /* If a layout has been scheduled, do it now so that all
+ * cell view items have valid sizes before we proceed. */
+ if (icon_view->priv->layout_idle_id != 0)
+@@ -1601,8 +1693,25 @@
+ gtk_icon_view_paint_item (icon_view, cr, item, &expose->area,
+ icon_view->priv->bin_window,
+ item->x, item->y,
+- icon_view->priv->draw_focus);
+-
++ icon_view->priv->draw_focus);
++
++ if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE
++ && mode == HILDON_FREMANTLE
++ && icon_view->priv->hildon_ui_mode == HILDON_UI_MODE_EDIT
++ && item->selected)
++ {
++ gdk_draw_pixbuf (icon_view->priv->bin_window,
++ NULL,
++ icon_view->priv->tickmark_icon,
++ 0, 0,
++ item->x + (item->width - HILDON_TICK_MARK_SIZE) / 2,
++ item->y + (item->height - HILDON_TICK_MARK_SIZE) / 2,
++ HILDON_TICK_MARK_SIZE,
++ HILDON_TICK_MARK_SIZE,
++ GDK_RGB_DITHER_MAX,
++ 0, 0);
++ }
++
+ if (dest_index == item->index)
+ dest_item = item;
+ }
+@@ -1713,10 +1822,28 @@
+ {
+ GtkIconView *icon_view;
+ gint abs_y;
++ HildonMode mode;
+
+ icon_view = GTK_ICON_VIEW (widget);
+
+- gtk_icon_view_maybe_begin_drag (icon_view, event);
++ gtk_widget_style_get (widget,
++ "hildon-mode", &mode,
++ NULL);
++
++ if (mode == HILDON_FREMANTLE
++ && gtk_drag_check_threshold (widget,
++ icon_view->priv->press_start_x,
++ icon_view->priv->press_start_y,
++ event->x, event->y))
++ {
++ if (icon_view->priv->hildon_ui_mode == HILDON_UI_MODE_NORMAL)
++ free_queued_activate_item (icon_view);
++ else if (icon_view->priv->hildon_ui_mode == HILDON_UI_MODE_EDIT)
++ free_queued_select_item (icon_view);
++ }
++
++ if (icon_view->priv->pressed_button >= 0 && mode == HILDON_DIABLO)
++ gtk_icon_view_maybe_begin_drag (icon_view, event);
+
+ if (icon_view->priv->doing_rubberband)
+ {
+@@ -2138,6 +2265,7 @@
+ gboolean dirty = FALSE;
+ GtkCellRendererMode mode;
+ gint cursor_cell = -1;
++ HildonMode hildon_mode;
+
+ icon_view = GTK_ICON_VIEW (widget);
+
+@@ -2154,12 +2282,14 @@
+ FALSE,
+ &info);
+
++ gtk_widget_style_get (widget, "hildon-mode", &hildon_mode, NULL);
++
+ /*
+ * We consider only the the cells' area as the item area if the
+ * item is not selected, but if it *is* selected, the complete
+ * selection rectangle is considered to be part of the item.
+ */
+- if (item != NULL && (info != NULL || item->selected))
++ if (item != NULL && (info != NULL || item->selected) && !item->is_header)
+ {
+ if (info != NULL)
+ {
+@@ -2172,44 +2302,65 @@
+
+ gtk_icon_view_scroll_to_item (icon_view, item);
+
+- if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
++ if (hildon_mode == HILDON_DIABLO)
+ {
+- gtk_icon_view_set_cursor_item (icon_view, item, cursor_cell);
+- }
+- else if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE &&
+- (event->state & GTK_EXTEND_SELECTION_MOD_MASK))
+- {
+- gtk_icon_view_unselect_all_internal (icon_view);
++ if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
++ {
++ gtk_icon_view_set_cursor_item (icon_view, item, cursor_cell);
++ }
++ else if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE &&
++ (event->state & GTK_EXTEND_SELECTION_MOD_MASK))
++ {
++ gtk_icon_view_unselect_all_internal (icon_view);
+
+- gtk_icon_view_set_cursor_item (icon_view, item, cursor_cell);
+- if (!icon_view->priv->anchor_item)
+- icon_view->priv->anchor_item = item;
+- else
+- gtk_icon_view_select_all_between (icon_view,
+- icon_view->priv->anchor_item,
+- item);
+- dirty = TRUE;
++ gtk_icon_view_set_cursor_item (icon_view, item, cursor_cell);
++ if (!icon_view->priv->anchor_item)
++ icon_view->priv->anchor_item = item;
++ else
++ gtk_icon_view_select_all_between (icon_view,
++ icon_view->priv->anchor_item,
++ item);
++ dirty = TRUE;
++ }
++ else
++ {
++ if ((icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE ||
++ ((icon_view->priv->selection_mode == GTK_SELECTION_SINGLE) && item->selected)) &&
++ (event->state & GTK_MODIFY_SELECTION_MOD_MASK))
++ {
++ item->selected = !item->selected;
++ gtk_icon_view_queue_draw_item (icon_view, item);
++ dirty = TRUE;
++ }
++ else
++ {
++ gtk_icon_view_unselect_all_internal (icon_view);
++
++ item->selected = TRUE;
++ gtk_icon_view_queue_draw_item (icon_view, item);
++ dirty = TRUE;
++ }
++ gtk_icon_view_set_cursor_item (icon_view, item, cursor_cell);
++ icon_view->priv->anchor_item = item;
++ }
+ }
+- else
++ else
+ {
+- if ((icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE ||
+- ((icon_view->priv->selection_mode == GTK_SELECTION_SINGLE) && item->selected)) &&
+- (event->state & GTK_MODIFY_SELECTION_MOD_MASK))
++ if (icon_view->priv->hildon_ui_mode == HILDON_UI_MODE_NORMAL)
+ {
+- item->selected = !item->selected;
++ icon_view->priv->queued_activate_item = item;
++
++ /* Queue a draw so it will appear highlighted */
+ gtk_icon_view_queue_draw_item (icon_view, item);
+- dirty = TRUE;
+ }
+- else
++ else if (icon_view->priv->hildon_ui_mode == HILDON_UI_MODE_EDIT)
+ {
+- gtk_icon_view_unselect_all_internal (icon_view);
++ icon_view->priv->queued_select_item = item;
+
+- item->selected = TRUE;
+- gtk_icon_view_queue_draw_item (icon_view, item);
+- dirty = TRUE;
++ /* Queue a draw so it will appear highlighted */
++ if (!item->selected)
++ gtk_icon_view_queue_draw_item (icon_view, item);
+ }
+- gtk_icon_view_set_cursor_item (icon_view, item, cursor_cell);
+- icon_view->priv->anchor_item = item;
+ }
+
+ /* Save press to possibly begin a drag */
+@@ -2236,7 +2387,7 @@
+ (GdkEvent *)event);
+ }
+ }
+- else
++ else if (hildon_mode == HILDON_DIABLO)
+ {
+ if (icon_view->priv->selection_mode != GTK_SELECTION_BROWSE &&
+ !(event->state & GTK_MODIFY_SELECTION_MOD_MASK))
+@@ -2252,26 +2403,6 @@
+ icon_view->priv->draw_focus = FALSE;
+ }
+
+- if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
+- {
+- item = gtk_icon_view_get_item_at_coords (icon_view,
+- event->x, event->y,
+- FALSE,
+- NULL);
+-
+- if (item && item == icon_view->priv->last_single_clicked)
+- {
+- GtkTreePath *path;
+-
+- path = gtk_tree_path_new_from_indices (item->index, -1);
+- gtk_icon_view_item_activated (icon_view, path);
+- gtk_tree_path_free (path);
+- }
+-
+- icon_view->priv->last_single_clicked = NULL;
+- icon_view->priv->pressed_button = -1;
+- }
+-
+ if (dirty)
+ g_signal_emit (icon_view, icon_view_signals[SELECTION_CHANGED], 0);
+
+@@ -2283,12 +2414,79 @@
+ GdkEventButton *event)
+ {
+ GtkIconView *icon_view;
++ HildonMode mode;
++ GtkIconViewItem *item = NULL;
+
+ icon_view = GTK_ICON_VIEW (widget);
+
+ if (icon_view->priv->pressed_button == event->button)
+ icon_view->priv->pressed_button = -1;
+
++ gtk_widget_style_get (widget,
++ "hildon-mode", &mode,
++ NULL);
++
++ if (mode == HILDON_FREMANTLE)
++ item = gtk_icon_view_get_item_at_coords (icon_view,
++ event->x, event->y,
++ FALSE,
++ NULL);
++
++ if (icon_view->priv->queued_activate_item
++ && mode == HILDON_FREMANTLE
++ && icon_view->priv->hildon_ui_mode == HILDON_UI_MODE_NORMAL)
++ {
++ GtkTreePath *path;
++
++ gtk_icon_view_queue_draw_item (icon_view,
++ icon_view->priv->queued_activate_item);
++
++ if (icon_view->priv->queued_activate_item == item)
++ {
++ path = gtk_tree_path_new_from_indices (icon_view->priv->queued_activate_item->index, -1);
++ gtk_icon_view_item_activated (icon_view, path);
++ gtk_tree_path_free (path);
++ }
++
++ icon_view->priv->queued_activate_item = NULL;
++ }
++
++ if (icon_view->priv->queued_select_item
++ && mode == HILDON_FREMANTLE
++ && icon_view->priv->hildon_ui_mode == HILDON_UI_MODE_EDIT)
++ {
++ GtkIconViewItem *select_item = icon_view->priv->queued_select_item;
++
++ free_queued_select_item (icon_view);
++
++ if (select_item == item)
++ {
++ if (icon_view->priv->selection_mode == GTK_SELECTION_SINGLE)
++ {
++ if (!item->selected)
++ {
++ gtk_icon_view_unselect_all_internal (icon_view);
++
++ item->selected = TRUE;
++ gtk_icon_view_queue_draw_item (icon_view, item);
++
++ g_signal_emit (icon_view,
++ icon_view_signals[SELECTION_CHANGED], 0);
++ }
++ }
++ else if (icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE)
++ {
++ item->selected = !item->selected;
++ gtk_icon_view_queue_draw_item (icon_view, item);
++
++ g_signal_emit (icon_view,
++ icon_view_signals[SELECTION_CHANGED], 0);
++ }
++
++ icon_view->priv->anchor_item = item;
++ }
++ }
++
+ gtk_icon_view_stop_rubberbanding (icon_view);
+
+ remove_scroll_timeout (icon_view);
+@@ -2447,6 +2645,9 @@
+ gboolean is_in;
+ gboolean selected;
+
++ if (item->is_header)
++ continue;
++
+ is_in = gtk_icon_view_item_hit_test (icon_view, item,
+ x, y, width, height);
+
+@@ -2687,6 +2888,74 @@
+ }
+ }
+
++static inline gboolean
++item_is_header (GtkIconView *icon_view,
++ GtkIconViewItem *item)
++{
++ gboolean is_header = FALSE;
++
++ if (icon_view->priv->row_header_func)
++ {
++ GtkTreeIter iter;
++
++ if (gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST)
++ {
++ GtkTreePath *path;
++
++ path = gtk_tree_path_new_from_indices (item->index, -1);
++ if (!gtk_tree_model_get_iter (icon_view->priv->model, &iter, path))
++ return is_header;
++ gtk_tree_path_free (path);
++ }
++ else
++ iter = item->iter;
++
++ is_header = (* icon_view->priv->row_header_func) (icon_view->priv->model,
++ &iter,
++ NULL,
++ icon_view->priv->row_header_data);
++ }
++
++ return is_header;
++}
++
++static gboolean
++search_first_selectable_path (GtkIconView *icon_view,
++ GtkTreePath **path,
++ gboolean search_forward)
++{
++ int index;
++ GList *list;
++
++ if (!path || !*path)
++ return FALSE;
++
++ index = gtk_tree_path_get_indices (*path)[0];
++ list = g_list_nth (icon_view->priv->items, index);
++
++ while (list && item_is_header (icon_view, list->data))
++ {
++ if (search_forward)
++ {
++ index++;
++ list = list->next;
++ }
++ else
++ {
++ index--;
++ list = list->prev;
++ }
++ }
++
++ if (!list)
++ return FALSE;
++
++ gtk_tree_path_up (*path);
++ gtk_tree_path_append_index (*path, index);
++
++ return TRUE;
++}
++
+ static GList *
+ gtk_icon_view_layout_single_row (GtkIconView *icon_view,
+ GList *first_item,
+@@ -2703,6 +2972,7 @@
+ gint *max_height;
+ gint i;
+ gboolean rtl;
++ GtkIconViewItem *header_item = NULL;
+
+ rtl = gtk_widget_get_direction (GTK_WIDGET (icon_view)) == GTK_TEXT_DIR_RTL;
+ max_height = g_new0 (gint, icon_view->priv->n_cells);
+@@ -2725,6 +2995,17 @@
+ GtkIconViewItem *item = items->data;
+
+ gtk_icon_view_calculate_item_size (icon_view, item);
++
++ if (item->is_header)
++ {
++ header_item = item;
++ item->y = *y + focus_width;
++
++ /* Include the header item as last item of this row */
++ items = items->next;
++ break;
++ }
++
+ colspan = 1 + (item->width - 1) / (item_width + icon_view->priv->column_spacing);
+
+ item->width = colspan * item_width + (colspan - 1) * icon_view->priv->column_spacing;
+@@ -2765,6 +3046,9 @@
+ {
+ GtkIconViewItem *item = items->data;
+
++ if (item->is_header)
++ continue;
++
+ if (rtl)
+ {
+ item->x = *maximum_width - item->width - item->x;
+@@ -2778,6 +3062,18 @@
+ *y = item->y + item->height + focus_width + icon_view->priv->row_spacing;
+ }
+
++ if (header_item)
++ {
++ /* FIXME: we might want to use allocation->width here instead. */
++ header_item->x = 0;
++ header_item->width = icon_view->priv->width;
++
++ header_item->y = *y;
++ header_item->height = HILDON_ROW_HEADER_HEIGHT;
++
++ *y += HILDON_ROW_HEADER_HEIGHT;
++ }
++
+ g_free (max_height);
+
+ return last_item;
+@@ -2991,7 +3287,7 @@
+ gint spacing;
+ GList *l;
+
+- if (item->width != -1 && item->height != -1)
++ if (item->width != -1 && item->height != -1 && !item->is_header)
+ return;
+
+ if (item->n_cells != icon_view->priv->n_cells)
+@@ -3013,6 +3309,11 @@
+
+ item->width = 0;
+ item->height = 0;
++ item->is_header = item_is_header (icon_view, item);
++
++ if (item->is_header)
++ return;
++
+ for (l = icon_view->priv->cell_list; l; l = l->next)
+ {
+ GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
+@@ -3153,6 +3454,58 @@
+ }
+
+ static void
++gtk_icon_view_paint_row_header (GtkIconView *icon_view,
++ GtkIconViewItem *item,
++ GdkRectangle *area,
++ GdkDrawable *drawable)
++{
++ gchar *label = NULL;
++ int width, height;
++ gboolean is_header;
++ GtkTreeIter iter;
++ GtkWidget *widget = GTK_WIDGET (icon_view);
++
++ g_return_if_fail (icon_view->priv->row_header_func != NULL);
++
++ if (gtk_tree_model_get_flags (icon_view->priv->model) & GTK_TREE_MODEL_ITERS_PERSIST)
++ {
++ GtkTreePath *path;
++
++ path = gtk_tree_path_new_from_indices (item->index, -1);
++ g_return_if_fail (gtk_tree_model_get_iter (icon_view->priv->model, &iter, path));
++ gtk_tree_path_free (path);
++ }
++ else
++ iter = item->iter;
++
++ is_header = (* icon_view->priv->row_header_func) (icon_view->priv->model,
++ &iter,
++ &label,
++ icon_view->priv->row_header_data);
++
++ g_return_if_fail (is_header == TRUE);
++ g_return_if_fail (icon_view->priv->row_header_layout != NULL);
++
++ pango_layout_set_text (icon_view->priv->row_header_layout,
++ label, strlen (label));
++ pango_layout_get_pixel_size (icon_view->priv->row_header_layout,
++ &width, &height);
++
++ gtk_paint_layout (widget->style,
++ drawable,
++ widget->state,
++ TRUE,
++ area,
++ widget,
++ "iconview-group-header",
++ item->x + (item->width - width) / 2,
++ item->y + item->height - height,
++ icon_view->priv->row_header_layout);
++
++ g_free (label);
++}
++
++static void
+ gtk_icon_view_paint_item (GtkIconView *icon_view,
+ cairo_t *cr,
+ GtkIconViewItem *item,
+@@ -3169,10 +3522,17 @@
+ gint i;
+ GtkStateType state;
+ GtkCellRendererState flags;
+-
++ gboolean selected = FALSE;
++
+ if (icon_view->priv->model == NULL)
+ return;
+
++ if (item->is_header)
++ {
++ gtk_icon_view_paint_row_header (icon_view, item, area, drawable);
++ return;
++ }
++
+ gtk_icon_view_set_cell_data (icon_view, item);
+
+ gtk_widget_style_get (GTK_WIDGET (icon_view),
+@@ -3181,7 +3541,12 @@
+
+ padding = focus_width;
+
+- if (item->selected)
++ if (item->selected
++ || item == icon_view->priv->queued_select_item
++ || item == icon_view->priv->queued_activate_item)
++ selected = TRUE;
++
++ if (selected)
+ {
+ flags = GTK_CELL_RENDERER_SELECTED;
+ if (gtk_widget_has_focus (GTK_WIDGET (icon_view)))
+@@ -3203,7 +3568,7 @@
+ item->width, item->height);
+ #endif
+
+- if (item->selected)
++ if (selected)
+ {
+ gtk_paint_flat_box (GTK_WIDGET (icon_view)->style,
+ (GdkWindow *) drawable,
+@@ -3215,7 +3580,7 @@
+ x, y,
+ item->width, item->height);
+ }
+-
++
+ for (l = icon_view->priv->cell_list; l; l = l->next)
+ {
+ GtkIconViewCellInfo *info = (GtkIconViewCellInfo *)l->data;
+@@ -3264,9 +3629,10 @@
+ continue;
+
+ /* If found a editable/activatable cell, draw focus on it. */
+- if (icon_view->priv->cursor_cell < 0 &&
+- info->cell->mode != GTK_CELL_RENDERER_MODE_INERT)
+- icon_view->priv->cursor_cell = i;
++ /* If found a editable/activatable cell, draw focus on it. */
++ if (icon_view->priv->cursor_cell < 0 &&
++ info->cell->mode != GTK_CELL_RENDERER_MODE_INERT)
++ icon_view->priv->cursor_cell = i;
+
+ gtk_icon_view_get_cell_box (icon_view, item, info, &box);
+
+@@ -3426,11 +3792,24 @@
+ AtkObject *obj;
+ AtkObject *item_obj;
+ AtkObject *cursor_item_obj;
++ HildonMode mode;
+
+ if (icon_view->priv->cursor_item == item &&
+ (cursor_cell < 0 || cursor_cell == icon_view->priv->cursor_cell))
+ return;
+
++ /* Cannot set cursor on header */
++ if (item->is_header)
++ return;
++
++ gtk_widget_style_get (GTK_WIDGET (icon_view),
++ "hildon-mode", &mode,
++ NULL);
++
++ /* No cursors in new-style */
++ if (mode == HILDON_FREMANTLE)
++ return;
++
+ obj = gtk_widget_get_accessible (GTK_WIDGET (icon_view));
+ if (icon_view->priv->cursor_item != NULL)
+ {
+@@ -3554,6 +3933,9 @@
+ if (item->selected)
+ return;
+
++ if (item->is_header)
++ return;
++
+ if (icon_view->priv->selection_mode == GTK_SELECTION_NONE)
+ return;
+ else if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
+@@ -3578,6 +3960,9 @@
+ if (!item->selected)
+ return;
+
++ if (item->is_header)
++ return;
++
+ if (icon_view->priv->selection_mode == GTK_SELECTION_NONE ||
+ icon_view->priv->selection_mode == GTK_SELECTION_BROWSE)
+ return;
+@@ -3590,11 +3975,12 @@
+ gtk_icon_view_queue_draw_item (icon_view, item);
+ }
+
+-static void
++static gint
+ verify_items (GtkIconView *icon_view)
+ {
+ GList *items;
+ int i = 0;
++ int selected = 0;
+
+ for (items = icon_view->priv->items; items; items = items->next)
+ {
+@@ -3604,8 +3990,13 @@
+ g_error ("List item does not match its index: "
+ "item index %d and list index %d\n", item->index, i);
+
++ if (item->selected)
++ selected++;
++
+ i++;
+ }
++
++ return selected;
+ }
+
+ static void
+@@ -3671,7 +4062,26 @@
+ item->index++;
+ }
+
+- verify_items (icon_view);
++ if (verify_items (icon_view) < 1)
++ {
++ HildonMode mode;
++
++ gtk_widget_style_get (GTK_WIDGET (icon_view),
++ "hildon-mode", &mode,
++ NULL);
++
++ if (mode == HILDON_FREMANTLE
++ && icon_view->priv->hildon_ui_mode == HILDON_UI_MODE_EDIT
++ && icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
++ {
++ GtkTreePath *tmppath;
++
++ tmppath = gtk_tree_path_copy (path);
++ search_first_selectable_path (icon_view, &tmppath, TRUE);
++ gtk_icon_view_select_path (icon_view, tmppath);
++ gtk_tree_path_free (tmppath);
++ }
++ }
+
+ gtk_icon_view_queue_layout (icon_view);
+ }
+@@ -3716,8 +4126,28 @@
+
+ icon_view->priv->items = g_list_delete_link (icon_view->priv->items, list);
+
+- verify_items (icon_view);
+-
++ if (emit && verify_items (icon_view) < 1)
++ {
++ HildonMode mode;
++
++ gtk_widget_style_get (GTK_WIDGET (icon_view),
++ "hildon-mode", &mode,
++ NULL);
++
++ if (mode == HILDON_FREMANTLE
++ && icon_view->priv->hildon_ui_mode == HILDON_UI_MODE_EDIT
++ && icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
++ {
++ GtkTreePath *path;
++
++ /* The last item was just removed, select the first one */
++ path = gtk_tree_path_new_first ();
++ search_first_selectable_path (icon_view, &path, TRUE);
++ gtk_icon_view_select_path (icon_view, path);
++ gtk_tree_path_free (path);
++ }
++ }
++
+ gtk_icon_view_queue_layout (icon_view);
+
+ if (emit)
+@@ -3908,6 +4338,10 @@
+ for (items = icon_view->priv->items; items; items = items->next)
+ {
+ item = items->data;
++
++ if (item->is_header)
++ continue;
++
+ if (item->row == row && item->col == col)
+ return item;
+ }
+@@ -4011,6 +4445,9 @@
+ {
+ for (next = item->next; next; next = next->next)
+ {
++ if (((GtkIconViewItem *)next->data)->is_header)
++ continue;
++
+ if (((GtkIconViewItem *)next->data)->col == col)
+ break;
+ }
+@@ -4026,6 +4463,9 @@
+ {
+ for (next = item->prev; next; next = next->prev)
+ {
++ if (((GtkIconViewItem *)next->data)->is_header)
++ continue;
++
+ if (((GtkIconViewItem *)next->data)->col == col)
+ break;
+ }
+@@ -4042,6 +4482,28 @@
+ return NULL;
+ }
+
++static inline GList *
++find_first_cursor_item (GtkIconView *icon_view,
++ gboolean search_forward)
++{
++ GList *list;
++
++ if (search_forward)
++ {
++ list = icon_view->priv->items;
++ while (list && ((GtkIconViewItem *)list->data)->is_header)
++ list = list->next;
++ }
++ else
++ {
++ list = g_list_last (icon_view->priv->items);
++ while (list && ((GtkIconViewItem *)list->data)->is_header)
++ list = list->prev;
++ }
++
++ return list;
++}
++
+ static gboolean
+ gtk_icon_view_select_all_between (GtkIconView *icon_view,
+ GtkIconViewItem *anchor,
+@@ -4081,7 +4543,7 @@
+ if (row1 <= item->row && item->row <= row2 &&
+ col1 <= item->col && item->col <= col2)
+ {
+- if (!item->selected)
++ if (!item->selected && !item->is_header)
+ {
+ dirty = TRUE;
+ item->selected = TRUE;
+@@ -4112,11 +4574,16 @@
+ if (!icon_view->priv->cursor_item)
+ {
+ GList *list;
++ HildonMode mode;
+
+- if (count > 0)
+- list = icon_view->priv->items;
+- else
+- list = g_list_last (icon_view->priv->items);
++ gtk_widget_style_get (GTK_WIDGET (icon_view),
++ "hildon-mode", &mode,
++ NULL);
++
++ if (mode == HILDON_FREMANTLE)
++ return;
++
++ list = find_first_cursor_item (icon_view, count > 0);
+
+ item = list ? list->data : NULL;
+ cell = -1;
+@@ -4190,11 +4657,16 @@
+ if (!icon_view->priv->cursor_item)
+ {
+ GList *list;
++ HildonMode mode;
+
+- if (count > 0)
+- list = icon_view->priv->items;
+- else
+- list = g_list_last (icon_view->priv->items);
++ gtk_widget_style_get (GTK_WIDGET (icon_view),
++ "hildon-mode", &mode,
++ NULL);
++
++ if (mode == HILDON_FREMANTLE)
++ return;
++
++ list = find_first_cursor_item (icon_view, count > 0);
+
+ item = list ? list->data : NULL;
+ }
+@@ -4250,11 +4722,16 @@
+ if (!icon_view->priv->cursor_item)
+ {
+ GList *list;
++ HildonMode mode;
+
+- if (count > 0)
+- list = icon_view->priv->items;
+- else
+- list = g_list_last (icon_view->priv->items);
++ gtk_widget_style_get (GTK_WIDGET (icon_view),
++ "hildon-mode", &mode,
++ NULL);
++
++ if (mode == HILDON_FREMANTLE)
++ return;
++
++ list = find_first_cursor_item (icon_view, count > 0);
+
+ item = list ? list->data : NULL;
+ }
+@@ -4321,15 +4798,19 @@
+ GtkIconViewItem *item;
+ GList *list;
+ gboolean dirty = FALSE;
++ HildonMode mode;
+
+ if (!gtk_widget_has_focus (GTK_WIDGET (icon_view)))
+ return;
+
+- if (count < 0)
+- list = icon_view->priv->items;
+- else
+- list = g_list_last (icon_view->priv->items);
+-
++ gtk_widget_style_get (GTK_WIDGET (icon_view),
++ "hildon-mode", &mode,
++ NULL);
++
++ if (mode == HILDON_FREMANTLE)
++ return;
++
++ list = find_first_cursor_item (icon_view, count < 0);
+ item = list ? list->data : NULL;
+
+ if (item == icon_view->priv->cursor_item)
+@@ -4858,7 +5339,7 @@
+
+ g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
+
+- item = gtk_icon_view_get_item_at_coords (icon_view, x, y, TRUE, NULL);
++ item = gtk_icon_view_get_item_at_coords (icon_view, x, y, FALSE, NULL);
+
+ if (!item)
+ return NULL;
+@@ -5278,11 +5759,25 @@
+ gtk_icon_view_set_selection_mode (GtkIconView *icon_view,
+ GtkSelectionMode mode)
+ {
++ HildonMode hildon_mode;
++
+ g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
+
+ if (mode == icon_view->priv->selection_mode)
+ return;
+
++ gtk_widget_style_get (GTK_WIDGET (icon_view),
++ "hildon-mode", &hildon_mode,
++ NULL);
++
++ if (hildon_mode == HILDON_FREMANTLE
++ && icon_view->priv->hildon_ui_mode == HILDON_UI_MODE_NORMAL
++ && mode != GTK_SELECTION_NONE)
++ {
++ g_warning ("Cannot change the selection mode to anything other than GTK_SELECTION_NONE in normal-mode.\n");
++ return;
++ }
++
+ if (mode == GTK_SELECTION_NONE ||
+ icon_view->priv->selection_mode == GTK_SELECTION_MULTIPLE)
+ gtk_icon_view_unselect_all (icon_view);
+@@ -5897,7 +6392,7 @@
+ {
+ GtkIconViewItem *item = items->data;
+
+- if (!item->selected)
++ if (!item->selected && !item->is_header)
+ {
+ dirty = TRUE;
+ item->selected = TRUE;
+@@ -7648,6 +8143,176 @@
+ g_object_notify (G_OBJECT (icon_view), "reorderable");
+ }
+
++HildonIconViewRowHeaderFunc
++hildon_icon_view_get_row_header_func (GtkIconView *icon_view)
++{
++ g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), NULL);
++
++ return icon_view->priv->row_header_func;
++}
++
++static void
++hildon_icon_view_setup_row_header_layout (GtkIconView *icon_view)
++{
++ GdkColor font_color;
++ GtkStyle *font_style;
++ GtkWidget *widget = GTK_WIDGET (icon_view);
++
++ font_style = gtk_rc_get_style_by_paths (gtk_settings_get_default (),
++ "EmpSmallSystemFont",
++ NULL, G_TYPE_NONE);
++ if (font_style)
++ {
++ pango_layout_set_font_description (icon_view->priv->row_header_layout,
++ font_style->font_desc);
++ }
++
++ if (gtk_style_lookup_color (widget->style, "SecondaryTextColor", &font_color))
++ {
++ PangoAttrList *list;
++ PangoAttribute *attr;
++
++ list = pango_attr_list_new ();
++ attr = pango_attr_foreground_new (font_color.red,
++ font_color.green,
++ font_color.blue);
++ attr->start_index = 0;
++ attr->end_index = G_MAXINT;
++ pango_attr_list_insert (list, attr);
++
++ pango_layout_set_attributes (icon_view->priv->row_header_layout,
++ list);
++
++ pango_attr_list_unref (list);
++ }
++}
++
++void
++hildon_icon_view_set_row_header_func (GtkIconView *icon_view,
++ HildonIconViewRowHeaderFunc func,
++ gpointer data,
++ GDestroyNotify destroy)
++{
++ g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
++
++ if (icon_view->priv->row_header_destroy)
++ (* icon_view->priv->row_header_destroy) (icon_view->priv->row_header_data);
++
++ icon_view->priv->row_header_func = func;
++ icon_view->priv->row_header_data = data;
++ icon_view->priv->row_header_destroy = destroy;
++
++ if (func && !icon_view->priv->row_header_layout)
++ {
++ icon_view->priv->row_header_layout =
++ gtk_widget_create_pango_layout (GTK_WIDGET (icon_view), "");
++
++ hildon_icon_view_setup_row_header_layout (icon_view);
++ }
++ else if (!func && icon_view->priv->row_header_layout)
++ {
++ g_object_unref (icon_view->priv->row_header_layout);
++ icon_view->priv->row_header_layout = NULL;
++ }
++
++ gtk_icon_view_queue_layout (icon_view);
++}
++
++static void
++free_queued_activate_item (GtkIconView *icon_view)
++{
++ if (icon_view->priv->queued_activate_item)
++ {
++ gtk_icon_view_queue_draw_item (icon_view,
++ icon_view->priv->queued_activate_item);
++
++ icon_view->priv->queued_activate_item = NULL;
++ }
++}
++
++static void
++free_queued_select_item (GtkIconView *icon_view)
++{
++ if (icon_view->priv->queued_select_item)
++ {
++ gtk_icon_view_queue_draw_item (icon_view,
++ icon_view->priv->queued_select_item);
++
++ icon_view->priv->queued_select_item = NULL;
++ }
++}
++
++HildonUIMode
++hildon_icon_view_get_hildon_ui_mode (GtkIconView *icon_view)
++{
++ g_return_val_if_fail (GTK_IS_ICON_VIEW (icon_view), 0);
++
++ return icon_view->priv->hildon_ui_mode;
++}
++
++void
++hildon_icon_view_set_hildon_ui_mode (GtkIconView *icon_view,
++ HildonUIMode hildon_ui_mode)
++{
++ HildonMode mode;
++
++ g_return_if_fail (GTK_IS_ICON_VIEW (icon_view));
++
++ icon_view->priv->hildon_ui_mode = hildon_ui_mode;
++
++ gtk_widget_style_get (GTK_WIDGET (icon_view),
++ "hildon-mode", &mode,
++ NULL);
++
++ if (mode == HILDON_DIABLO)
++ return;
++
++ if (hildon_ui_mode == HILDON_UI_MODE_NORMAL)
++ {
++ gtk_icon_view_set_selection_mode (icon_view, GTK_SELECTION_NONE);
++ }
++ else if (hildon_ui_mode == HILDON_UI_MODE_EDIT)
++ {
++ int count = 0;
++ GList *list;
++
++ if (gtk_icon_view_get_selection_mode (icon_view) == GTK_SELECTION_NONE)
++ {
++ gtk_icon_view_set_selection_mode (icon_view, GTK_SELECTION_SINGLE);
++ }
++
++ if (icon_view->priv->selection_mode != GTK_SELECTION_MULTIPLE)
++ {
++ /* Instead of using gtk_icon_view_get_selected_items() we walk
++ * over the list of items ourselves to save allocating/deallocating
++ * all paths.
++ */
++ for (list = icon_view->priv->items; list; list = list->next)
++ {
++ GtkIconViewItem *item = list->data;
++
++ if (item->selected)
++ {
++ count++;
++ break;
++ }
++ }
++
++ if (!count)
++ {
++ GtkTreePath *path;
++
++ /* Select the first item */
++ path = gtk_tree_path_new_first ();
++ search_first_selectable_path (icon_view, &path, TRUE);
++ gtk_icon_view_select_path (icon_view, path);
++ gtk_tree_path_free (path);
++ }
++ }
++ }
++ else
++ g_assert_not_reached ();
++}
+
+ /* Accessibility Support */
+
+--- a/gtk/gtkiconview.h
++++ b/gtk/gtkiconview.h
+@@ -46,6 +46,10 @@
+ typedef void (* GtkIconViewForeachFunc) (GtkIconView *icon_view,
+ GtkTreePath *path,
+ gpointer data);
++typedef gboolean (* HildonIconViewRowHeaderFunc) (GtkTreeModel *model,
++ GtkTreeIter *iter,
++ gchar **label,
++ gpointer data);
+
+ typedef enum
+ {
+@@ -236,7 +240,13 @@
+ gint column);
+ gint gtk_icon_view_get_tooltip_column (GtkIconView *icon_view);
+
+-
++HildonIconViewRowHeaderFunc hildon_icon_view_get_row_header_func (GtkIconView *icon_view);
++void hildon_icon_view_set_row_header_func (GtkIconView *icon_view,
++ HildonIconViewRowHeaderFunc func,
++ gpointer data,
++ GDestroyNotify destroy);
++void
++hildon_icon_view_set_hildon_ui_mode (GtkIconView *icon_view, HildonUIMode hildon_ui_mode);
+ G_END_DECLS
+
+ #endif /* __GTK_ICON_VIEW_H__ */
diff --git a/hildonize-gtk-imcontext.patch b/hildonize-gtk-imcontext.patch
new file mode 100644
index 000000000000..11c900fe66d7
--- /dev/null
+++ b/hildonize-gtk-imcontext.patch
@@ -0,0 +1,486 @@
+--- a/gtk/gtkimcontext.c
++++ b/gtk/gtkimcontext.c
+@@ -100,6 +100,17 @@
+ * in order for the new input method to become available to GTK+ applications.
+ */
+
++typedef struct _GtkIMContextPrivate GtkIMContextPrivate;
++
++#define GTK_IM_CONTEXT_GET_PRIVATE(obj) \
++ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
++ GTK_TYPE_IM_CONTEXT, GtkIMContextPrivate))
++
++enum {
++ PROP_HILDON_INPUT_MODE = 1,
++ PROP_HILDON_INPUT_DEFAULT
++};
++
+ enum {
+ PREEDIT_START,
+ PREEDIT_END,
+@@ -107,11 +118,30 @@
+ COMMIT,
+ RETRIEVE_SURROUNDING,
+ DELETE_SURROUNDING,
++ HAS_SELECTION,
++ CLIPBOARD_OPERATION,
+ LAST_SIGNAL
+ };
+
++struct _GtkIMContextPrivate {
++ HildonGtkInputMode mode;
++ HildonGtkInputMode default_mode;
++};
++
+ static guint im_context_signals[LAST_SIGNAL] = { 0 };
+
++static void gtk_im_context_set_property (GObject *object,
++ guint property_id,
++ const GValue *value,
++ GParamSpec *pspec);
++static void gtk_im_context_get_property (GObject *object,
++ guint property_id,
++ GValue *value,
++ GParamSpec *pspec);
++
++static gboolean gtk_im_context_real_filter_event (GtkIMContext *context,
++ GdkEvent *event);
++
+ static void gtk_im_context_real_get_preedit_string (GtkIMContext *context,
+ gchar **str,
+ PangoAttrList **attrs,
+@@ -188,10 +218,18 @@
+ static void
+ gtk_im_context_class_init (GtkIMContextClass *klass)
+ {
++ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
++
+ klass->get_preedit_string = gtk_im_context_real_get_preedit_string;
+ klass->filter_keypress = gtk_im_context_real_filter_keypress;
+ klass->get_surrounding = gtk_im_context_real_get_surrounding;
+ klass->set_surrounding = gtk_im_context_real_set_surrounding;
++ klass->filter_event = gtk_im_context_real_filter_event;
++
++ gobject_class->set_property = gtk_im_context_set_property;
++ gobject_class->get_property = gtk_im_context_get_property;
++
++ g_type_class_add_private (klass, sizeof(GtkIMContextPrivate));
+
+ /**
+ * GtkIMContext::preedit-start:
+@@ -300,6 +338,82 @@
+ G_TYPE_BOOLEAN, 2,
+ G_TYPE_INT,
+ G_TYPE_INT);
++ /**
++ * GtkIMContext::has-selection:
++ * @context: a #GtkIMContext
++ *
++ * This signal is emitted when input context needs to know if there is
++ * any text selected in the widget. Return TRUE if there is.
++ *
++ * Since: maemo 2.0
++ * Stability: Unstable
++ */
++ im_context_signals[HAS_SELECTION] =
++ g_signal_new ("has_selection",
++ G_TYPE_FROM_CLASS (klass),
++ G_SIGNAL_RUN_LAST,
++ G_STRUCT_OFFSET (GtkIMContextClass, has_selection),
++ NULL, NULL,
++ _gtk_marshal_BOOLEAN__VOID,
++ G_TYPE_BOOLEAN, 0);
++ /**
++ * GtkIMContext::clipboard-operation:
++ * @context: a #GtkIMContext
++ * @operation: a #GtkIMContextClipboardOperation
++ *
++ * This signal is emitted when input context wants to copy, cut or paste
++ * text. The widget needs to implement these operations.
++ *
++ * Since: maemo 2.0
++ * Stability: Unstable
++ */
++ im_context_signals[CLIPBOARD_OPERATION] =
++ g_signal_new ("clipboard_operation",
++ G_TYPE_FROM_CLASS (klass),
++ G_SIGNAL_RUN_LAST,
++ G_STRUCT_OFFSET (GtkIMContextClass, clipboard_operation),
++ NULL, NULL,
++ _gtk_marshal_VOID__ENUM,
++ G_TYPE_NONE, 1, GTK_TYPE_IM_CONTEXT_CLIPBOARD_OPERATION);
++
++ /**
++ * GtkIMContext:hildon-input-mode:
++ *
++ * Allowed characters and input mode for this IM context.
++ * See #HildonGtkInputMode.
++ *
++ * Since: maemo 2.0
++ * Stability: Unstable
++ */
++ g_object_class_install_property (gobject_class,
++ PROP_HILDON_INPUT_MODE,
++ g_param_spec_flags ("hildon-input-mode",
++ "Hildon input mode",
++ "Allowed characters and input mode",
++ HILDON_TYPE_GTK_INPUT_MODE,
++ HILDON_GTK_INPUT_MODE_FULL |
++ HILDON_GTK_INPUT_MODE_AUTOCAP |
++ HILDON_GTK_INPUT_MODE_DICTIONARY,
++ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
++
++ /**
++ * GtkIMContext:hildon-input-default:
++ *
++ * Default input mode for this IM context. See #HildonGtkInputMode.
++ * The default setting for this property is %HILDON_GTK_INPUT_MODE_FULL,
++ * which means that the default input mode to be used is up to the
++ * implementation of the IM context.
++ *
++ * Since: maemo 5.0
++ */
++ g_object_class_install_property (gobject_class,
++ PROP_HILDON_INPUT_DEFAULT,
++ g_param_spec_flags ("hildon-input-default",
++ "Hildon input default",
++ "Default input mode",
++ HILDON_TYPE_GTK_INPUT_MODE,
++ HILDON_GTK_INPUT_MODE_FULL,
++ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ }
+
+ static void
+@@ -308,6 +422,50 @@
+ }
+
+ static void
++gtk_im_context_set_property (GObject *object,
++ guint property_id,
++ const GValue *value,
++ GParamSpec *pspec)
++{
++ GtkIMContextPrivate *priv = GTK_IM_CONTEXT_GET_PRIVATE (object);
++
++ switch (property_id)
++ {
++ case PROP_HILDON_INPUT_MODE:
++ priv->mode = g_value_get_flags (value);
++ break;
++ case PROP_HILDON_INPUT_DEFAULT:
++ priv->default_mode = g_value_get_flags (value);
++ break;
++ default:
++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
++ break;
++ }
++}
++
++static void
++gtk_im_context_get_property (GObject *object,
++ guint property_id,
++ GValue *value,
++ GParamSpec *pspec)
++{
++ GtkIMContextPrivate *priv = GTK_IM_CONTEXT_GET_PRIVATE (object);
++
++ switch (property_id)
++ {
++ case PROP_HILDON_INPUT_MODE:
++ g_value_set_flags (value, priv->mode);
++ break;
++ case PROP_HILDON_INPUT_DEFAULT:
++ g_value_set_flags (value, priv->default_mode);
++ break;
++ default:
++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
++ break;
++ }
++}
++
++static void
+ gtk_im_context_real_get_preedit_string (GtkIMContext *context,
+ gchar **str,
+ PangoAttrList **attrs,
+@@ -328,6 +486,13 @@
+ return FALSE;
+ }
+
++static gboolean
++gtk_im_context_real_filter_event (GtkIMContext *context,
++ GdkEvent *event)
++{
++ return FALSE;
++}
++
+ typedef struct
+ {
+ gchar *text;
+@@ -710,5 +875,208 @@
+ return result;
+ }
+
++/**
++ * hildon_gtk_im_context_filter_event:
++ * @context: a #GtkIMContext
++ * @event: the event
++ *
++ * Allow an input method to internally handle an event.
++ * If this function returns %TRUE, then no further processing
++ * should be done for this event.
++ *
++ * <note><para>
++ * Input methods must be able to accept all types of events (simply
++ * returning %FALSE if the event was not handled), but there is no
++ * obligation for a widget to submit any events to this function.
++ * </para><para>
++ * Widget events that are recommended to be run through this function
++ * are %GDK_BUTTON_PRESS, %GDK_BUTTON_RELEASE, %GDK_2BUTTON_PRESS,
++ * %GDK_3BUTTON_PRESS, %GDK_KEY_PRESS and %GDK_KEY_RELEASE.
++ * </para><para>
++ * Note that if the event passes the filter with the function returning
++ * %FALSE, the widget still needs to process the event itself, this can
++ * include calling gtk_im_context_focus_in(), gtk_im_context_focus_out()
++ * or gtk_im_context_filter_keypress() for focus and keypress events
++ * where applicable.
++ * </para></note>
++ *
++ * Return value: %TRUE if the input method handled the event.
++ *
++ * Since: maemo 2.0
++ * Stability: Unstable
++ */
++gboolean hildon_gtk_im_context_filter_event (GtkIMContext *context,
++ GdkEvent *event)
++{
++ GtkIMContextClass *klass;
++
++ g_return_val_if_fail (GTK_IS_IM_CONTEXT (context), FALSE);
++ g_return_val_if_fail (event != NULL, FALSE);
++
++ klass = GTK_IM_CONTEXT_GET_CLASS (context);
++ return klass->filter_event (context, event);
++}
++
++/**
++ * gtk_im_context_show:
++ * @context: a #GtkIMContext
++ *
++ * Notify the input method that widget thinks the actual
++ * input method show be opened.
++ *
++ * Since: maemo 1.0
++ * Stability: Unstable
++ *
++ * Deprecated: Use hildon_gtk_im_context_show() instead.
++ **/
++void
++gtk_im_context_show (GtkIMContext *context)
++{
++ hildon_gtk_im_context_show (context);
++}
++
++/**
++ * gtk_im_context_hide:
++ * @context: a #GtkIMContext
++ *
++ * Notify the input method that widget thinks the actual
++ * input method show be closed.
++ *
++ * Since: maemo 1.0
++ * Stability: Unstable
++ *
++ * Deprecated: Use hildon_gtk_im_context_hide() instead.
++ **/
++void
++gtk_im_context_hide (GtkIMContext *context)
++{
++ hildon_gtk_im_context_hide (context);
++}
++
++/**
++ * hildon_gtk_im_context_show:
++ * @context: a #GtkIMContext
++ *
++ * Notify the input method that widget thinks the actual
++ * input method show be opened.
++ *
++ * Since: maemo 2.0
++ * Stability: Unstable
++ **/
++void
++hildon_gtk_im_context_show (GtkIMContext *context)
++{
++ GtkIMContextClass *klass;
++
++ g_return_if_fail (GTK_IS_IM_CONTEXT (context));
++
++ klass = GTK_IM_CONTEXT_GET_CLASS (context);
++ if (klass->show)
++ klass->show (context);
++}
++
++/**
++ * hildon_gtk_im_context_hide:
++ * @context: a #GtkIMContext
++ *
++ * Notify the input method that widget thinks the actual
++ * input method show be closed.
++ *
++ * Since: maemo 2.0
++ * Stability: Unstable
++ **/
++void
++hildon_gtk_im_context_hide (GtkIMContext *context)
++{
++ GtkIMContextClass *klass;
++
++ g_return_if_fail (GTK_IS_IM_CONTEXT (context));
++
++ klass = GTK_IM_CONTEXT_GET_CLASS (context);
++ if (klass->hide)
++ klass->hide (context);
++}
++
++/**
++ * hildon_gtk_im_context_has_selection:
++ * @context: a #GtkIMContext
++ *
++ * Returns TRUE if the widget attached to this input context has some
++ * text selected in it.
++ *
++ * Since: maemo 2.0
++ * Stability: Unstable
++ **/
++gboolean
++hildon_gtk_im_context_has_selection (GtkIMContext *context)
++{
++ gboolean result = FALSE;
++
++ g_return_val_if_fail (GTK_IS_IM_CONTEXT (context), 0);
++
++ g_signal_emit (context,
++ im_context_signals[HAS_SELECTION], 0,
++ &result);
++
++ return result;
++}
++
++/**
++ * hildon_gtk_im_context_copy:
++ * @context: a #GtkIMContext
++ *
++ * Requests from the widget attached to this input context that the
++ * selected text in it is copied to clipboard.
++ *
++ * Since: maemo 2.0
++ * Stability: Unstable
++ **/
++void
++hildon_gtk_im_context_copy (GtkIMContext *context)
++{
++ g_return_if_fail (GTK_IS_IM_CONTEXT (context));
++
++ g_signal_emit (context, im_context_signals[CLIPBOARD_OPERATION], 0,
++ GTK_IM_CONTEXT_CLIPBOARD_OP_COPY);
++}
++
++/**
++ * hildon_gtk_im_context_cut:
++ * @context: a #GtkIMContext
++ *
++ * Requests from the widget attached to this input context that the
++ * selected text is cut and copied to clipboard.
++ *
++ * Since: maemo 2.0
++ * Stability: Unstable
++ **/
++void
++hildon_gtk_im_context_cut (GtkIMContext *context)
++{
++ g_return_if_fail (GTK_IS_IM_CONTEXT (context));
++
++ g_signal_emit (context, im_context_signals[CLIPBOARD_OPERATION], 0,
++ GTK_IM_CONTEXT_CLIPBOARD_OP_CUT);
++}
++
++/**
++ * hildon_gtk_im_context_paste:
++ * @context: a #GtkIMContext
++ *
++ * Requests from the widget attached to this input context that the
++ * text in clipboard is pasted to it.
++ *
++ * Since: maemo 2.0
++ * Stability: Unstable
++ **/
++void
++hildon_gtk_im_context_paste (GtkIMContext *context)
++{
++ g_return_if_fail (GTK_IS_IM_CONTEXT (context));
++
++ g_signal_emit (context, im_context_signals[CLIPBOARD_OPERATION], 0,
++ GTK_IM_CONTEXT_CLIPBOARD_OP_PASTE);
++}
++
+ #define __GTK_IM_CONTEXT_C__
+ #include "gtkaliasdef.c"
+--- a/gtk/gtkimcontext.h
++++ b/gtk/gtkimcontext.h
+@@ -31,6 +31,13 @@
+
+ G_BEGIN_DECLS
+
++typedef enum
++{
++ GTK_IM_CONTEXT_CLIPBOARD_OP_COPY,
++ GTK_IM_CONTEXT_CLIPBOARD_OP_CUT,
++ GTK_IM_CONTEXT_CLIPBOARD_OP_PASTE
++} GtkIMContextClipboardOperation;
++
+ #define GTK_TYPE_IM_CONTEXT (gtk_im_context_get_type ())
+ #define GTK_IM_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_IM_CONTEXT, GtkIMContext))
+ #define GTK_IM_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_IM_CONTEXT, GtkIMContextClass))
+@@ -92,11 +99,18 @@
+ /*< private >*/
+ /* Padding for future expansion */
+ void (*_gtk_reserved1) (void);
+- void (*_gtk_reserved2) (void);
+- void (*_gtk_reserved3) (void);
+- void (*_gtk_reserved4) (void);
+- void (*_gtk_reserved5) (void);
+- void (*_gtk_reserved6) (void);
++
++ void (*show) (GtkIMContext *context);
++ void (*hide) (GtkIMContext *context);
++
++ /* Signals again: */
++ gboolean (*has_selection) (GtkIMContext *context);
++ void (*clipboard_operation) (GtkIMContext *context,
++ GtkIMContextClipboardOperation operation);
++
++ /* Virtual functions again: */
++ gboolean (*filter_event) (GtkIMContext *context,
++ GdkEvent *event);
+ };
+
+ GType gtk_im_context_get_type (void) G_GNUC_CONST;
+@@ -126,6 +140,18 @@
+ gboolean gtk_im_context_delete_surrounding (GtkIMContext *context,
+ gint offset,
+ gint n_chars);
++gboolean hildon_gtk_im_context_filter_event (GtkIMContext *context,
++ GdkEvent *event);
++
++void gtk_im_context_show (GtkIMContext *context);
++void gtk_im_context_hide (GtkIMContext *context);
++
++void hildon_gtk_im_context_show (GtkIMContext *context);
++void hildon_gtk_im_context_hide (GtkIMContext *context);
++gboolean hildon_gtk_im_context_has_selection(GtkIMContext *context);
++void hildon_gtk_im_context_copy (GtkIMContext *context);
++void hildon_gtk_im_context_cut (GtkIMContext *context);
++void hildon_gtk_im_context_paste (GtkIMContext *context);
+
+ G_END_DECLS
+
diff --git a/hildonize-gtk-menu.patch b/hildonize-gtk-menu.patch
new file mode 100644
index 000000000000..d06f52cf6cbb
--- /dev/null
+++ b/hildonize-gtk-menu.patch
@@ -0,0 +1,755 @@
+--- a/gtk/gtkmenu.c
++++ b/gtk/gtkmenu.c
+@@ -27,6 +27,8 @@
+ #define GTK_MENU_INTERNALS
+ #include "config.h"
+ #include <string.h>
++#include <math.h>
++#include <stdlib.h>
+ #include "gdk/gdkkeysyms.h"
+ #include "gtkaccellabel.h"
+ #include "gtkaccelmap.h"
+@@ -36,6 +38,7 @@
+ #include "gtkmain.h"
+ #include "gtkmarshalers.h"
+ #include "gtkmenu.h"
++#include "gtkmenubar.h"
+ #include "gtktearoffmenuitem.h"
+ #include "gtkwindow.h"
+ #include "gtkhbox.h"
+@@ -56,6 +59,8 @@
+ #define MENU_SCROLL_TIMEOUT1 50
+ #define MENU_SCROLL_TIMEOUT2 20
+
++#define SCROLL_DELAY_FACTOR 5 /* Scroll repeat multiplier */
++
+ #define ATTACH_INFO_KEY "gtk-menu-child-attach-info-key"
+ #define ATTACHED_MENUS "gtk-attached-menus"
+
+@@ -101,6 +106,14 @@
+ guint have_position : 1;
+ guint ignore_button_release : 1;
+ guint no_toggle_size : 1;
++
++ /* For context menu behavior */
++ gboolean context_menu;
++ int popup_pointer_x;
++ int popup_pointer_y;
++
++ /* Handling GdkScreen::size-changed */
++ guint size_changed_id;
+ };
+
+ typedef struct
+@@ -254,6 +267,11 @@
+
+ static guint menu_signals[LAST_SIGNAL] = { 0 };
+
++static gint context_menu_counter = 0;
++
++static void menu_screen_size_changed (GdkScreen *screen,
++ GtkMenu *menu);
++
+ static GtkMenuPrivate *
+ gtk_menu_get_private (GtkMenu *menu)
+ {
+@@ -670,6 +688,42 @@
+ GTK_ARROWS_BOTH,
+ GTK_PARAM_READABLE));
+
++ gtk_widget_class_install_style_property (widget_class,
++ g_param_spec_boolean ("opposite-arrows",
++ P_("Opposite Arrows"),
++ P_("Place the scroll arrows on opposite sides of the menu."),
++ FALSE,
++ GTK_PARAM_READABLE));
++ /**
++ * GtkMenuItem::arrow-scaling
++ *
++ * Arbitrary constant to scale down the size of the scroll arrow.
++ *
++ * Since: maemo 4.0
++ * Stability: Unstable
++ */
++ gtk_widget_class_install_style_property (widget_class,
++ g_param_spec_float ("maemo-arrow-scaling",
++ P_("Arrow Scaling"),
++ P_("Amount of space used up by the scroll arrows, relative to scroll-arrow-vlength"),
++ 0.0, 1.0, 0.7,
++ GTK_PARAM_READABLE));
++
++ /**
++ * GtkMenu::maemo-decorated
++ *
++ * Whether the menu window is decorated by the window manager.
++ *
++ * Since: maemo 5.0
++ * Stability: Unstable
++ */
++ gtk_widget_class_install_style_property (widget_class,
++ g_param_spec_boolean ("maemo-decorated",
++ P_("Decorated"),
++ P_("Whether the menu window is decorated by the window manager"),
++ TRUE,
++ GTK_PARAM_READABLE));
++
+ gtk_container_class_install_child_property (container_class,
+ CHILD_PROP_LEFT_ATTACH,
+ g_param_spec_int ("left-attach",
+@@ -713,7 +767,7 @@
+ g_param_spec_float ("arrow-scaling",
+ P_("Arrow Scaling"),
+ P_("Arbitrary constant to scale down the size of the scroll arrow"),
+- 0.0, 1.0, 0.7,
++ 0.0, 1.0, 1.0,
+ GTK_PARAM_READABLE));
+
+ binding_set = gtk_binding_set_by_class (class);
+@@ -971,6 +1025,28 @@
+ case GDK_KEY_RELEASE:
+ handled = gtk_widget_event (menu, event);
+ break;
++ case GDK_CLIENT_EVENT:
++ /* Close down the whole hierarchy, but not if we're torn off. Don't call
++ * cancel if the menu isn't visible to avoid extra selection-done
++ * signals.
++ */
++ if (event->client.message_type == gdk_atom_intern_static_string ("_GTK_DELETE_TEMPORARIES") &&
++ _gtk_window_is_on_client_data (GTK_WINDOW (window), (GdkEventClient*)event) == FALSE &&
++ window == GTK_MENU (menu)->toplevel &&
++ gtk_widget_get_mapped (GTK_MENU (menu)->toplevel))
++ {
++ gtk_menu_shell_cancel (GTK_MENU_SHELL (menu));
++ handled = TRUE;
++ }
++ break;
++ case GDK_DELETE:
++ if (window == GTK_MENU (menu)->toplevel &&
++ gtk_widget_get_mapped (GTK_MENU (menu)->toplevel))
++ {
++ gtk_menu_shell_cancel (GTK_MENU_SHELL (menu));
++ handled = TRUE;
++ }
++ break;
+ default:
+ break;
+ }
+@@ -1007,6 +1083,7 @@
+ gtk_menu_init (GtkMenu *menu)
+ {
+ GtkMenuPrivate *priv = gtk_menu_get_private (menu);
++ gboolean decorated = TRUE;
+
+ menu->parent_menu_item = NULL;
+ menu->old_active_menu_item = NULL;
+@@ -1016,7 +1093,7 @@
+ menu->toggle_size = 0;
+
+ menu->toplevel = g_object_connect (g_object_new (GTK_TYPE_WINDOW,
+- "type", GTK_WINDOW_POPUP,
++ "type", GTK_WINDOW_TOPLEVEL,
+ "child", menu,
+ NULL),
+ "signal::event", gtk_menu_window_event, menu,
+@@ -1026,6 +1103,11 @@
+ gtk_window_set_resizable (GTK_WINDOW (menu->toplevel), FALSE);
+ gtk_window_set_mnemonic_modifier (GTK_WINDOW (menu->toplevel), 0);
+
++ gtk_widget_style_get (GTK_WIDGET (menu), "maemo-decorated", &decorated, NULL);
++ gtk_window_set_decorated (GTK_WINDOW (menu->toplevel), decorated);
++ gtk_widget_add_events (menu->toplevel, GDK_VISIBILITY_NOTIFY_MASK);
++ gtk_window_set_is_temporary (GTK_WINDOW (menu->toplevel), TRUE);
++
+ /* Refloat the menu, so that reference counting for the menu isn't
+ * affected by it being a child of the toplevel
+ */
+@@ -1055,6 +1137,14 @@
+ priv->upper_arrow_state = GTK_STATE_NORMAL;
+ priv->lower_arrow_state = GTK_STATE_NORMAL;
+
++ priv->context_menu = FALSE;
++ priv->popup_pointer_x = -1;
++ priv->popup_pointer_y = -1;
++
++ priv->size_changed_id =
++ g_signal_connect (gtk_widget_get_screen (menu->toplevel), "size_changed",
++ G_CALLBACK (menu_screen_size_changed), menu);
++
+ priv->have_layout = FALSE;
+ priv->monitor_num = -1;
+ }
+@@ -1113,10 +1203,24 @@
+ priv->title = NULL;
+ }
+
++ if (priv->size_changed_id)
++ {
++ g_signal_handler_disconnect (gtk_widget_get_screen (GTK_WIDGET (object)),
++ priv->size_changed_id);
++ priv->size_changed_id = 0;
++ }
++
+ GTK_OBJECT_CLASS (gtk_menu_parent_class)->destroy (object);
+ }
+
+ static void
++menu_screen_size_changed (GdkScreen *screen,
++ GtkMenu *menu)
++{
++ gtk_menu_shell_cancel (GTK_MENU_SHELL (menu));
++}
++
++static void
+ menu_change_screen (GtkMenu *menu,
+ GdkScreen *new_screen)
+ {
+@@ -1128,6 +1232,13 @@
+ return;
+ }
+
++ if (private->size_changed_id)
++ {
++ g_signal_handler_disconnect (gtk_widget_get_screen (GTK_WIDGET (menu)),
++ private->size_changed_id);
++ private->size_changed_id = 0;
++ }
++
+ if (menu->torn_off)
+ {
+ gtk_window_set_screen (GTK_WINDOW (menu->tearoff_window), new_screen);
+@@ -1136,6 +1247,10 @@
+
+ gtk_window_set_screen (GTK_WINDOW (menu->toplevel), new_screen);
+ private->monitor_num = -1;
++
++ private->size_changed_id =
++ g_signal_connect (new_screen, "size_changed",
++ G_CALLBACK (menu_screen_size_changed), menu);
+ }
+
+ static void
+@@ -1384,6 +1499,54 @@
+ return FALSE;
+ }
+
++#define HILDON_MENU_NAME_SHARP "menu_with_corners"
++/* needed to allow different themeing for first level menus */
++#define HILDON_MENU_NAME_ROUND_FIRST_LEVEL "menu_without_corners_first_level"
++#define HILDON_MENU_NAME_ROUND "menu_without_corners"
++#define HILDON_MENU_NAME_FORCE_SHARP "menu_force_with_corners"
++#define HILDON_MENU_NAME_FORCE_ROUND "menu_force_without_corners"
++
++/**
++ * Little help function for making some sanity tests on this menu.
++ * Checks that given widget really is a menu and that it has no name
++ * assigned to it yet.
++ * Names used to do hildon theming:
++ * HILDON_MENU_NAME_SHARP for menu with sharp upper corners
++ * HILDON_MENU_NAME_ROUND for menu with round corners
++ */
++static gboolean
++maemo_menu_check_name (GtkWidget *widget)
++{
++ gboolean legal_name = FALSE;
++ gchar **tmp = NULL;
++ const gchar *name = NULL;
++ static gchar *menu_names[] = { "GtkMenu",
++ HILDON_MENU_NAME_SHARP,
++ HILDON_MENU_NAME_ROUND,
++ HILDON_MENU_NAME_ROUND_FIRST_LEVEL,
++ NULL };
++ if (GTK_IS_MENU (widget) &&
++ (name = gtk_widget_get_name (widget)))
++ {
++ if (!g_ascii_strcasecmp (name, HILDON_MENU_NAME_FORCE_SHARP) ||
++ !g_ascii_strcasecmp (name, HILDON_MENU_NAME_FORCE_ROUND))
++ {
++ return FALSE;
++ }
++
++ for (tmp = menu_names; *tmp; tmp++)
++ {
++ if (!g_ascii_strcasecmp (name, *tmp ))
++ {
++ legal_name = TRUE;
++ break;
++ }
++ }
++ }
++
++ return legal_name;
++}
++
+ /**
+ * gtk_menu_popup:
+ * @menu: a #GtkMenu.
+@@ -1487,6 +1650,16 @@
+ {
+ if (popup_grab_on_window (xgrab_shell->window, activate_time, grab_keyboard))
+ GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE;
++ /* Maemo: enable rc-file theming */
++ if (maemo_menu_check_name (widget))
++ {
++ if (GTK_IS_MENU_BAR (parent_menu_shell))
++ gtk_widget_set_name (widget, HILDON_MENU_NAME_SHARP);
++ else if (GTK_IS_MENU (parent_menu_shell))
++ gtk_widget_set_name( widget, HILDON_MENU_NAME_ROUND);
++ else
++ gtk_widget_set_name (widget, HILDON_MENU_NAME_ROUND_FIRST_LEVEL);
++ }
+ }
+ else
+ {
+@@ -1496,6 +1669,10 @@
+ transfer_window = menu_grab_transfer_window_get (menu);
+ if (popup_grab_on_window (transfer_window, activate_time, grab_keyboard))
+ GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE;
++
++ /* Maemo: enable rc-file theming */
++ if (maemo_menu_check_name (widget))
++ gtk_widget_set_name (widget, HILDON_MENU_NAME_ROUND_FIRST_LEVEL);
+ }
+
+ if (!GTK_MENU_SHELL (xgrab_shell)->have_xgrab)
+@@ -1585,18 +1762,14 @@
+
+ gtk_menu_scroll_to (menu, menu->scroll_offset);
+
+- /* if no item is selected, select the first one */
+- if (!menu_shell->active_menu_item)
+- {
+- gboolean touchscreen_mode;
+-
+- g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
+- "gtk-touchscreen-mode", &touchscreen_mode,
+- NULL);
++ /* Hildon: save position of the pointer during popup. Not multihead safe. */
++ priv->context_menu = (context_menu_counter > 0) && !parent_menu_item;
+
+- if (touchscreen_mode)
+- gtk_menu_shell_select_first (menu_shell, TRUE);
+- }
++ if (priv->context_menu)
++ gdk_display_get_pointer (gtk_widget_get_display (widget), NULL,
++ &priv->popup_pointer_x,
++ &priv->popup_pointer_y,
++ NULL);
+
+ /* Once everything is set up correctly, map the toplevel window on
+ the screen.
+@@ -1636,6 +1809,7 @@
+ menu_shell->ignore_enter = FALSE;
+
+ private->have_position = FALSE;
++ private->context_menu = FALSE;
+
+ gtk_menu_stop_scrolling (menu);
+
+@@ -2229,12 +2403,17 @@
+ {
+ guint scroll_arrow_height;
+ GtkArrowPlacement arrow_placement;
++ gboolean opposite_arrows;
+
+ gtk_widget_style_get (GTK_WIDGET (menu),
+ "scroll-arrow-vlength", &scroll_arrow_height,
+ "arrow_placement", &arrow_placement,
++ "opposite-arrows", &opposite_arrows,
+ NULL);
+
++ if (opposite_arrows)
++ arrow_placement = GTK_ARROWS_BOTH;
++
+ switch (arrow_placement)
+ {
+ case GTK_ARROWS_BOTH:
+@@ -2710,12 +2889,14 @@
+ guint horizontal_padding;
+ gint scroll_arrow_height;
+ GtkArrowPlacement arrow_placement;
++ gboolean opposite_arrows;
+
+ gtk_widget_style_get (widget,
+ "vertical-padding", &vertical_padding,
+ "horizontal-padding", &horizontal_padding,
+ "scroll-arrow-vlength", &scroll_arrow_height,
+ "arrow-placement", &arrow_placement,
++ "opposite-arrows", &opposite_arrows,
+ NULL);
+
+ border->x = GTK_CONTAINER (widget)->border_width + widget->style->xthickness + horizontal_padding;
+@@ -2723,6 +2904,9 @@
+ border->width = gdk_window_get_width (widget->window);
+ border->height = gdk_window_get_height (widget->window);
+
++ if (opposite_arrows)
++ arrow_placement = GTK_ARROWS_BOTH;
++
+ switch (arrow_placement)
+ {
+ case GTK_ARROWS_BOTH:
+@@ -2796,6 +2980,9 @@
+ gtk_widget_style_get (widget, "arrow-scaling", &arrow_scaling, NULL);
+ arrow_size = arrow_scaling * arrow_space;
+
++ gtk_widget_style_get (widget, "maemo-arrow-scaling", &arrow_scaling, NULL);
++ arrow_size *= arrow_scaling;
++
+ gtk_paint_box (widget->style,
+ widget->window,
+ GTK_STATE_NORMAL,
+@@ -2900,6 +3087,27 @@
+ GTK_WIDGET_CLASS (gtk_menu_parent_class)->show (widget);
+ }
+
++static gint
++distance_traveled (GtkWidget *widget)
++{
++ GtkMenuPrivate *priv;
++ GdkScreen *screen;
++ GdkDisplay *display;
++ gint x, y, dx, dy;
++
++ priv = gtk_menu_get_private (GTK_MENU (widget));
++
++ screen = gtk_widget_get_screen (widget);
++ display = gdk_screen_get_display (screen);
++
++ gdk_display_get_pointer (display, NULL, &x, &y, NULL);
++
++ dx = (priv->popup_pointer_x - x);
++ dy = (priv->popup_pointer_y - y);
++
++ return abs ((int) sqrt ((double) (dx * dx + dy * dy)));
++}
++
+ static gboolean
+ gtk_menu_button_scroll (GtkMenu *menu,
+ GdkEventButton *event)
+@@ -2983,6 +3191,7 @@
+ GdkEventButton *event)
+ {
+ GtkMenuPrivate *priv = gtk_menu_get_private (GTK_MENU (widget));
++ GtkWidget *menu_item;
+
+ if (priv->ignore_button_release)
+ {
+@@ -3001,18 +3210,35 @@
+ /* Don't pass down to menu shell if a non-menuitem part of the menu
+ * was clicked (see comment in button_press()).
+ */
+- if (GTK_IS_MENU_SHELL (gtk_get_event_widget ((GdkEvent *) event)) &&
+- pointer_in_menu_window (widget, event->x_root, event->y_root))
++ menu_item = gtk_get_event_widget ((GdkEvent*) event);
++ if (!GTK_IS_MENU_ITEM (menu_item) ||
++ !GTK_IS_MENU (menu_item->parent))
+ {
+- /* Ugly: make sure menu_shell->button gets reset to 0 when we
+- * bail out early here so it is in a consistent state for the
+- * next button_press/button_release in GtkMenuShell.
+- * See bug #449371.
+- */
+- if (GTK_MENU_SHELL (widget)->active)
+- GTK_MENU_SHELL (widget)->button = 0;
++ if (priv->context_menu &&
++ (priv->popup_pointer_x >= 0) &&
++ (priv->popup_pointer_y >= 0))
++ {
++ gint threshold;
++ gint distance;
+
+- return TRUE;
++ g_object_get (gtk_widget_get_settings (widget),
++ "gtk-dnd-drag-threshold", &threshold,
++ NULL);
++
++ distance = distance_traveled (widget);
++
++ priv->popup_pointer_x = -1;
++ priv->popup_pointer_y = -1;
++
++ /* Don't popdown if we traveled less than DND threshold
++ * since popup point, as per the Nokia 770 specs.
++ */
++ if (distance < threshold)
++ return TRUE;
++ }
++
++ if (pointer_in_menu_window (widget, event->x_root, event->y_root))
++ return TRUE;
+ }
+
+ return GTK_WIDGET_CLASS (gtk_menu_parent_class)->button_release_event (widget, event);
+@@ -3192,7 +3418,33 @@
+ }
+ }
+ }
+-
++ else if (!can_change_accels)
++ {
++ GtkWidget *toplevel = gtk_menu_get_toplevel (widget);
++
++ if (toplevel)
++ {
++ GSList *accel_groups;
++ GSList *list;
++
++ accel_groups = gtk_accel_groups_from_object (G_OBJECT (toplevel));
++
++ for (list = accel_groups; list; list = list->next)
++ {
++ GtkAccelGroup *accel_group = list->data;
++
++ if (gtk_accel_group_query (accel_group, accel_key, accel_mods,
++ NULL))
++ {
++ gtk_menu_shell_cancel (GTK_MENU_SHELL (widget));
++ gtk_window_activate_key (GTK_WINDOW (toplevel), event);
++
++ break;
++ }
++ }
++ }
++ }
++
+ return TRUE;
+ }
+
+@@ -3271,14 +3523,36 @@
+ menu_item = gtk_get_event_widget ((GdkEvent*) event);
+ if (!GTK_IS_MENU_ITEM (menu_item) ||
+ !GTK_IS_MENU (menu_item->parent))
+- return FALSE;
++ {
++ GtkMenuPrivate *priv = gtk_menu_get_private (GTK_MENU (widget));
++
++ if (priv->context_menu)
++ {
++ gint threshold;
++
++ g_object_get (gtk_widget_get_settings (widget),
++ "gtk-dnd-drag-threshold", &threshold,
++ NULL);
++
++ /* Context menu mode. If we dragged out of the menu, close
++ * the menu, as by the specs.
++ */
++ if (!pointer_in_menu_window (widget, event->x_root, event->y_root) &&
++ (distance_traveled (widget) >= threshold) &&
++ (event->state & GDK_BUTTON1_MASK))
++ {
++ gtk_menu_shell_deactivate (GTK_MENU_SHELL (widget));
++
++ return TRUE;
++ }
++ }
++
++ return FALSE;
++ }
+
+ menu_shell = GTK_MENU_SHELL (menu_item->parent);
+ menu = GTK_MENU (menu_shell);
+
+- if (definitely_within_item (menu_item, event->x, event->y))
+- menu_shell->activate_time = 0;
+-
+ need_enter = (gtk_menu_has_navigation_triangle (menu) || menu_shell->ignore_enter);
+
+ /* Check to see if we are within an active submenu's navigation region
+@@ -3346,13 +3620,15 @@
+ GtkMenuPrivate *priv = gtk_menu_get_private (menu);
+ gboolean double_arrows;
+ GtkArrowPlacement arrow_placement;
++ gboolean opposite_arrows;
+
+ gtk_widget_style_get (GTK_WIDGET (menu),
+ "double-arrows", &double_arrows,
+ "arrow-placement", &arrow_placement,
++ "opposite-arrows", &opposite_arrows,
+ NULL);
+
+- if (arrow_placement != GTK_ARROWS_BOTH)
++ if (arrow_placement != GTK_ARROWS_BOTH || !opposite_arrows)
+ return TRUE;
+
+ return double_arrows || (priv->initially_pushed_in &&
+@@ -3414,17 +3690,101 @@
+ gtk_menu_scroll_to (menu, offset);
+ }
+
++#include "gtkseparatormenuitem.h"
++
++/* Same as _gtk_menu_item_is_selectable() except that this considers
++ * insensitive items valid - otherwise scrolling would skip them over, or stop
++ * scrolling before the begin/end of the menu, both of which would look bad */
++static gboolean
++_gtk_menu_item_is_scrollable (GtkWidget *menu_item)
++{
++ if ((!GTK_BIN (menu_item)->child &&
++ G_OBJECT_TYPE (menu_item) == GTK_TYPE_MENU_ITEM) ||
++ GTK_IS_SEPARATOR_MENU_ITEM (menu_item) ||
++ !gtk_widget_get_visible (menu_item))
++ return FALSE;
++
++ return TRUE;
++}
++
+ static void
+ gtk_menu_do_timeout_scroll (GtkMenu *menu,
+ gboolean touchscreen_mode)
+ {
+ gboolean upper_visible;
+ gboolean lower_visible;
++ GtkWidget *item = NULL;
+
+ upper_visible = menu->upper_arrow_visible;
+ lower_visible = menu->lower_arrow_visible;
+
+- gtk_menu_scroll_by (menu, menu->scroll_step);
++#define VISIBILITY_THRESHOLD 0.70
++ if (touchscreen_mode)
++ {
++ GdkRectangle visible;
++ GdkRectangle rect;
++ GList *l;
++
++ /* Scroll by item picking the next item that is not sufficiently
++ * readable. The visibility threshold is to avoid the impression of
++ * skipping an item when there's only one or two pixels obscured.
++ */
++
++ visible.x = 0; /* unused */
++ visible.y = menu->scroll_offset;
++ gdk_drawable_get_size (menu->view_window, &visible.width, &visible.height);
++
++ if (menu->scroll_step < 0)
++ {
++ /* scrolling up */
++ for (l = GTK_MENU_SHELL (menu)->children; l != NULL; l = l->next)
++ {
++ GtkWidget *child = l->data;
++
++ if (!_gtk_menu_item_is_scrollable (child))
++ continue;
++
++ /* completely below the top edge, use the previous one */
++ if (child->allocation.y >= visible.y)
++ break;
++
++ /* visible/readable enough, use the previous one */
++ if (gdk_rectangle_intersect (&child->allocation, &visible, &rect) &&
++ rect.height / (float)child->allocation.height >= VISIBILITY_THRESHOLD)
++ break;
++
++ item = child;
++ }
++ }
++ else
++ {
++ /* scrolling down */
++ for (l = GTK_MENU_SHELL (menu)->children; l != NULL; l = l->next)
++ {
++ GtkWidget *child = l->data;
++
++ if (!_gtk_menu_item_is_scrollable (child))
++ continue;
++
++ /* skip all completely above the bottom edge */
++ if (child->allocation.y + child->allocation.height < visible.y + visible.height)
++ continue;
++
++ /* visible/readable enough, try the next one */
++ if (gdk_rectangle_intersect (&child->allocation, &visible, &rect) &&
++ rect.height / (float)child->allocation.height >= VISIBILITY_THRESHOLD)
++ continue;
++
++ item = child;
++ break;
++ }
++ }
++ }
++
++ if (item)
++ gtk_menu_scroll_item_visible (GTK_MENU_SHELL (menu), item);
++ else
++ gtk_menu_scroll_by (menu, menu->scroll_step);
+
+ if (touchscreen_mode &&
+ (upper_visible != menu->upper_arrow_visible ||
+@@ -3470,6 +3830,9 @@
+ "gtk-touchscreen-mode", &touchscreen_mode,
+ NULL);
+
++ if (touchscreen_mode)
++ timeout *= SCROLL_DELAY_FACTOR;
++
+ gtk_menu_do_timeout_scroll (menu, touchscreen_mode);
+
+ gtk_menu_remove_scroll_timeout (menu);
+@@ -3488,7 +3851,7 @@
+ gboolean touchscreen_mode;
+
+ g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu)),
+- "gtk-timeout-repeat", &timeout,
++ "gtk-timeout-initial", &timeout,
+ "gtk-touchscreen-mode", &touchscreen_mode,
+ NULL);
+
+@@ -3531,6 +3894,7 @@
+ gint win_x, win_y;
+ gint scroll_arrow_height;
+ GtkArrowPlacement arrow_placement;
++ gboolean opposite_arrows;
+
+ width = gdk_window_get_width (GTK_WIDGET (menu)->window);
+ height = gdk_window_get_height (GTK_WIDGET (menu)->window);
+@@ -3539,6 +3903,7 @@
+ "vertical-padding", &vertical_padding,
+ "scroll-arrow-vlength", &scroll_arrow_height,
+ "arrow-placement", &arrow_placement,
++ "opposite-arrows", &opposite_arrows,
+ NULL);
+
+ border = GTK_CONTAINER (menu)->border_width +
+@@ -3546,6 +3911,9 @@
+
+ gdk_window_get_position (GTK_WIDGET (menu)->window, &win_x, &win_y);
+
++ if (opposite_arrows)
++ arrow_placement = GTK_ARROWS_BOTH;
++
+ switch (arrow_placement)
+ {
+ case GTK_ARROWS_BOTH:
+@@ -5368,5 +5736,20 @@
+ return !priv->no_toggle_size;
+ }
+
++/* Hildon functions to make context menus behave according to spec */
++void
++_gtk_menu_push_context_menu_behavior (void)
++{
++ context_menu_counter++;
++}
++
++void
++_gtk_menu_pop_context_menu_behavior (void)
++{
++ g_return_if_fail (context_menu_counter > 0);
++
++ context_menu_counter--;
++}
++
+ #define __GTK_MENU_C__
+ #include "gtkaliasdef.c"
+--- a/gtk/gtkmenu.h
++++ b/gtk/gtkmenu.h
+@@ -213,6 +213,8 @@
+ gboolean reserve_toggle_size);
+ gboolean gtk_menu_get_reserve_toggle_size (GtkMenu *menu);
+
++void _gtk_menu_push_context_menu_behavior (void);
++void _gtk_menu_pop_context_menu_behavior (void);
+
+ G_END_DECLS
+
diff --git a/hildonize-gtk-rbtree.patch b/hildonize-gtk-rbtree.patch
new file mode 100644
index 000000000000..d4d5cedabaf8
--- /dev/null
+++ b/hildonize-gtk-rbtree.patch
@@ -0,0 +1,77 @@
+--- a/gtk/gtkrbtree.c
++++ b/gtk/gtkrbtree.c
+@@ -335,6 +335,7 @@
+ retval = g_new (GtkRBTree, 1);
+ retval->parent_tree = NULL;
+ retval->parent_node = NULL;
++ retval->base_offset = 0;
+
+ retval->nil = g_slice_new (GtkRBNode);
+ retval->nil->left = NULL;
+@@ -962,6 +963,7 @@
+ {
+ GtkRBNode *last;
+ gint retval;
++ GtkRBTree *origtree = tree;
+
+ g_assert (node);
+ g_assert (node->left);
+@@ -987,7 +989,11 @@
+ retval += node->left->offset + GTK_RBNODE_GET_HEIGHT (node);
+ }
+ }
+- return retval;
++
++ while (origtree->parent_tree)
++ origtree = origtree->parent_tree;
++
++ return retval + origtree->base_offset;
+ }
+
+ gint
+@@ -1095,6 +1101,11 @@
+ {
+ g_assert (tree);
+
++ /* We (ab)use the fact that "tree" that is passed in is always
++ * the root.
++ */
++ height -= tree->base_offset;
++
+ if ((height < 0) ||
+ (height >= tree->root->offset))
+ {
+@@ -1411,6 +1422,13 @@
+ return depth;
+ }
+
++void
++_gtk_rbtree_set_base_offset (GtkRBTree *tree,
++ short base_offset)
++{
++ tree->base_offset = base_offset;
++}
++
+ static void
+ _gtk_rbtree_traverse_pre_order (GtkRBTree *tree,
+ GtkRBNode *node,
+--- a/gtk/gtkrbtree.h
++++ b/gtk/gtkrbtree.h
+@@ -64,6 +64,7 @@
+ GtkRBNode *nil;
+ GtkRBTree *parent_tree;
+ GtkRBNode *parent_node;
++ short base_offset;
+ };
+
+ struct _GtkRBNode
+@@ -170,6 +171,9 @@
+
+ gint _gtk_rbtree_get_depth (GtkRBTree *tree);
+
++void _gtk_rbtree_set_base_offset (GtkRBTree *tree,
++ short base_offset);
++
+ /* This func checks the integrity of the tree */
+ #ifdef G_ENABLE_DEBUG
+ void _gtk_rbtree_test (const gchar *where,
diff --git a/hildonize-gtk-textview.patch b/hildonize-gtk-textview.patch
new file mode 100644
index 000000000000..3a84151073de
--- /dev/null
+++ b/hildonize-gtk-textview.patch
@@ -0,0 +1,811 @@
+--- a/gtk/gtktextview.c
++++ b/gtk/gtktextview.c
+@@ -89,6 +89,8 @@
+ #define DEBUG_VALIDATION_AND_SCROLLING
+ #endif
+
++#define TEXT_VIEW_MAX_WINDOW_SIZE 16384
++
+ #ifdef DEBUG_VALIDATION_AND_SCROLLING
+ #define DV(x) (x)
+ #else
+@@ -110,6 +112,8 @@
+ guint im_spot_idle;
+ gchar *im_module;
+ guint scroll_after_paste : 1;
++ GtkTextBuffer *placeholder_buffer;
++ GtkTextLayout *placeholder_layout;
+ };
+
+
+@@ -160,7 +164,10 @@
+ PROP_BUFFER,
+ PROP_OVERWRITE,
+ PROP_ACCEPTS_TAB,
+- PROP_IM_MODULE
++ PROP_IM_MODULE,
++ PROP_HILDON_INPUT_MODE,
++ PROP_HILDON_INPUT_DEFAULT,
++ PROP_HILDON_PLACEHOLDER_TEXT
+ };
+
+ static void gtk_text_view_destroy (GtkObject *object);
+@@ -324,7 +331,11 @@
+ gint offset,
+ gint n_chars,
+ GtkTextView *text_view);
+-
++static gboolean gtk_text_view_has_selection_handler (GtkIMContext *context,
++ GtkTextView *text_view);
++static void gtk_text_view_clipboard_operation_handler (GtkIMContext *context,
++ GtkIMContextClipboardOperation op,
++ GtkTextView *text_view);
+ static void gtk_text_view_mark_set_handler (GtkTextBuffer *buffer,
+ const GtkTextIter *location,
+ GtkTextMark *mark,
+@@ -686,6 +697,62 @@
+ NULL,
+ GTK_PARAM_READWRITE));
+
++ /**
++ * GtkTextView:hildon-input-mode:
++ *
++ * Allowed characters and input mode for the text view.
++ * See #HildonGtkInputMode.
++ *
++ * Since: maemo 2.0
++ * Stability: Unstable
++ */
++ g_object_class_install_property (gobject_class,
++ PROP_HILDON_INPUT_MODE,
++ g_param_spec_flags ("hildon-input-mode",
++ P_("Hildon input mode"),
++ P_("Define widget's input mode"),
++ HILDON_TYPE_GTK_INPUT_MODE,
++ HILDON_GTK_INPUT_MODE_FULL |
++ HILDON_GTK_INPUT_MODE_MULTILINE |
++ HILDON_GTK_INPUT_MODE_AUTOCAP |
++ HILDON_GTK_INPUT_MODE_DICTIONARY,
++ GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
++
++ /**
++ * GtkTextView:hildon-input-default:
++ *
++ * Default input mode for this IM context. See #HildonGtkInputMode.
++ * The default setting for this property is %HILDON_GTK_INPUT_MODE_FULL,
++ * which means that the default input mode to be used is up to the
++ * implementation of the IM context.
++ *
++ * Since: maemo 5.0
++ */
++ g_object_class_install_property (gobject_class,
++ PROP_HILDON_INPUT_DEFAULT,
++ g_param_spec_flags ("hildon-input-default",
++ P_("Hildon input default"),
++ P_("Define widget's default input mode"),
++ HILDON_TYPE_GTK_INPUT_MODE,
++ HILDON_GTK_INPUT_MODE_FULL,
++ GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
++
++ /**
++ * GtkTextView:hildon-placeholder-text:
++ *
++ * Text to be displayed in the #GtkTextView when it is empty and
++ * unfocused.
++ *
++ * Since: maemo 5
++ */
++ g_object_class_install_property (gobject_class,
++ PROP_HILDON_PLACEHOLDER_TEXT,
++ g_param_spec_string ("hildon-placeholder-text",
++ P_("Hildon Placeholder text"),
++ P_("Text to be displayed when the text view is empty and unfocused"),
++ "",
++ G_PARAM_READWRITE));
++
+ /*
+ * Style properties
+ */
+@@ -695,7 +762,13 @@
+ P_("Color with which to draw error-indication underlines"),
+ GDK_TYPE_COLOR,
+ GTK_PARAM_READABLE));
+-
++ gtk_widget_class_install_style_property (widget_class,
++ g_param_spec_boolean ("custom-background",
++ P_("Render a custom background"),
++ P_("Provide a hook for theme engines to render a custom background"),
++ FALSE,
++ GTK_PARAM_READABLE));
++
+ /*
+ * Signals
+ */
+@@ -1333,6 +1406,10 @@
+ G_CALLBACK (gtk_text_view_retrieve_surrounding_handler), text_view);
+ g_signal_connect (text_view->im_context, "delete-surrounding",
+ G_CALLBACK (gtk_text_view_delete_surrounding_handler), text_view);
++ g_signal_connect (text_view->im_context, "has_selection",
++ G_CALLBACK (gtk_text_view_has_selection_handler), text_view);
++ g_signal_connect (text_view->im_context, "clipboard_operation",
++ G_CALLBACK (gtk_text_view_clipboard_operation_handler), text_view);
+
+ text_view->cursor_visible = TRUE;
+
+@@ -1346,6 +1423,9 @@
+
+ text_view->pending_place_cursor_button = 0;
+
++ priv->placeholder_buffer = NULL;
++ priv->placeholder_layout = NULL;
++
+ /* We handle all our own redrawing */
+ gtk_widget_set_redraw_on_allocate (widget, FALSE);
+ }
+@@ -2929,6 +3009,18 @@
+ /* at this point, no "notify::buffer" handler should recreate the buffer. */
+ g_assert (text_view->buffer == NULL);
+
++ if (priv->placeholder_layout)
++ {
++ g_object_unref (priv->placeholder_layout);
++ priv->placeholder_layout = NULL;
++ }
++
++ if (priv->placeholder_buffer)
++ {
++ g_object_unref (priv->placeholder_buffer);
++ priv->placeholder_buffer = NULL;
++ }
++
+ cancel_pending_scroll (text_view);
+
+ if (text_view->tabs)
+@@ -3033,8 +3125,21 @@
+ case PROP_IM_MODULE:
+ g_free (priv->im_module);
+ priv->im_module = g_value_dup_string (value);
++
+ if (GTK_IS_IM_MULTICONTEXT (text_view->im_context))
+- gtk_im_multicontext_set_context_id (GTK_IM_MULTICONTEXT (text_view->im_context), priv->im_module);
++ gtk_im_multicontext_set_context_id (GTK_IM_MULTICONTEXT (text_view->im_context), priv->im_module);
++ break;
++
++ case PROP_HILDON_INPUT_MODE:
++ hildon_gtk_text_view_set_input_mode (text_view, g_value_get_flags (value));
++ break;
++
++ case PROP_HILDON_INPUT_DEFAULT:
++ hildon_gtk_text_view_set_input_default (text_view, g_value_get_flags (value));
++ break;
++
++ case PROP_HILDON_PLACEHOLDER_TEXT:
++ hildon_gtk_text_view_set_placeholder_text (text_view, g_value_get_string (value));
+ break;
+
+ default:
+@@ -3117,6 +3222,18 @@
+ g_value_set_string (value, priv->im_module);
+ break;
+
++ case PROP_HILDON_INPUT_MODE:
++ g_value_set_flags (value, hildon_gtk_text_view_get_input_mode (text_view));
++ break;
++
++ case PROP_HILDON_INPUT_DEFAULT:
++ g_value_set_flags (value, hildon_gtk_text_view_get_input_default (text_view));
++ break;
++
++ case PROP_HILDON_PLACEHOLDER_TEXT:
++ g_value_take_string (value, hildon_gtk_text_view_get_placeholder_text (text_view));
++ break;
++
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+@@ -3368,13 +3485,34 @@
+ widget->allocation.width != allocation->width ||
+ widget->allocation.height != allocation->height;
+
+- widget->allocation = *allocation;
++ widget->allocation.x = allocation->x;
++ widget->allocation.y = allocation->y;
++
++ if (allocation->width > TEXT_VIEW_MAX_WINDOW_SIZE)
++ {
++ widget->allocation.width = TEXT_VIEW_MAX_WINDOW_SIZE;
++ g_warning ("gtk_text_view_size_allocate: the text view requires too much width %d, add it directly to a scrollable widget instead of using a viewport", allocation->width);
++ }
++ else
++ {
++ widget->allocation.width = allocation->width;
++ }
++
++ if (allocation->height > TEXT_VIEW_MAX_WINDOW_SIZE)
++ {
++ widget->allocation.height = TEXT_VIEW_MAX_WINDOW_SIZE;
++ g_warning ("gtk_text_view_size_allocate: the text view requires too much height %d, add it directly to a scrollable widget instead of using a viewport", allocation->height);
++ }
++ else
++ {
++ widget->allocation.height = allocation->height;
++ }
+
+ if (gtk_widget_get_realized (widget))
+ {
+ gdk_window_move_resize (widget->window,
+- allocation->x, allocation->y,
+- allocation->width, allocation->height);
++ widget->allocation.x, widget->allocation.y,
++ widget->allocation.width, widget->allocation.height);
+ }
+
+ /* distribute width/height among child windows. Ensure all
+@@ -3391,7 +3529,7 @@
+ else
+ focus_edge_width = focus_width;
+
+- width = allocation->width - focus_edge_width * 2 - GTK_CONTAINER (text_view)->border_width * 2;
++ width = widget->allocation.width - focus_edge_width * 2 - GTK_CONTAINER (text_view)->border_width * 2;
+
+ if (text_view->left_window)
+ left_rect.width = text_view->left_window->requisition.width;
+@@ -3413,7 +3551,7 @@
+ bottom_rect.width = text_rect.width;
+
+
+- height = allocation->height - focus_edge_width * 2 - GTK_CONTAINER (text_view)->border_width * 2;
++ height = widget->allocation.height - focus_edge_width * 2 - GTK_CONTAINER (text_view)->border_width * 2;
+
+ if (text_view->top_window)
+ top_rect.height = text_view->top_window->requisition.height;
+@@ -3541,7 +3679,7 @@
+
+ DV(g_print(">Validating onscreen ("G_STRLOC")\n"));
+
+- if (SCREEN_HEIGHT (widget) > 0)
++ if (SCREEN_HEIGHT (widget) > 1)
+ {
+ GtkTextIter first_para;
+
+@@ -3969,6 +4107,7 @@
+ {
+ GtkTextView *text_view = GTK_TEXT_VIEW (widget);
+ PangoContext *ltr_context, *rtl_context;
++ GtkTextViewPrivate *priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
+
+ if (gtk_widget_get_realized (widget))
+ {
+@@ -3992,6 +4131,43 @@
+ g_object_unref (ltr_context);
+ g_object_unref (rtl_context);
+ }
++
++ /* FIXME: Of course, when coded properly this and the above would be
++ * factored out in a function and shared.
++ */
++ if (priv->placeholder_layout && previous_style)
++ {
++ GdkColor font_color;
++
++ gtk_text_view_set_attributes_from_style (text_view,
++ priv->placeholder_layout->default_style,
++ widget->style);
++
++
++ /* Override the color setting */
++ if (gtk_style_lookup_color (widget->style, "ReversedSecondaryTextColor",
++ &font_color))
++ {
++ priv->placeholder_layout->default_style->appearance.fg_color = font_color;
++ }
++
++
++ ltr_context = gtk_widget_create_pango_context (widget);
++ pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
++ rtl_context = gtk_widget_create_pango_context (widget);
++ pango_context_set_base_dir (rtl_context, PANGO_DIRECTION_RTL);
++
++ gtk_text_layout_set_contexts (priv->placeholder_layout,
++ ltr_context, rtl_context);
++
++ g_object_unref (ltr_context);
++ g_object_unref (rtl_context);
++
++ /* The call to gtk_text_layout_set_contexts() invalidates the entire
++ * layout, so re-validate the placeholder layout immediately.
++ */
++ gtk_text_layout_validate (priv->placeholder_layout, 2000);
++ }
+ }
+
+ static void
+@@ -4331,6 +4507,13 @@
+
+ gtk_widget_grab_focus (widget);
+
++ if (text_view->editable &&
++ hildon_gtk_im_context_filter_event (text_view->im_context, (GdkEvent*)event))
++ {
++ text_view->need_im_reset = TRUE;
++ return TRUE;
++ }
++
+ if (event->window != text_view->text_window->bin_window)
+ {
+ /* Remove selection if any. */
+@@ -4438,6 +4621,13 @@
+ if (event->window != text_view->text_window->bin_window)
+ return FALSE;
+
++ if (text_view->editable &&
++ hildon_gtk_im_context_filter_event (text_view->im_context, (GdkEvent*)event))
++ {
++ text_view->need_im_reset = TRUE;
++ return TRUE;
++ }
++
+ if (event->button == 1)
+ {
+ if (text_view->drag_start_x >= 0)
+@@ -4503,10 +4693,7 @@
+ gtk_text_view_check_keymap_direction (text_view);
+
+ if (text_view->editable)
+- {
+- text_view->need_im_reset = TRUE;
+ gtk_im_context_focus_in (GTK_TEXT_VIEW (widget)->im_context);
+- }
+
+ return FALSE;
+ }
+@@ -4591,6 +4778,8 @@
+ GtkTextView *text_view;
+ GList *child_exposes;
+ GList *tmp_list;
++ gboolean custom_background = FALSE;
++ GtkTextViewPrivate *priv = GTK_TEXT_VIEW_GET_PRIVATE (widget);
+
+ text_view = GTK_TEXT_VIEW (widget);
+
+@@ -4617,16 +4806,49 @@
+ area->width, area->height);
+ #endif
+
++ gtk_widget_style_get (widget,
++ "custom-background", &custom_background,
++ NULL);
++
++ if (custom_background)
++ {
++ gtk_paint_flat_box (widget->style,
++ event->window,
++ gtk_widget_get_state (widget),
++ GTK_SHADOW_NONE,
++ area,
++ widget,
++ NULL,
++ - text_view->xoffset,
++ - text_view->yoffset,
++ area->x + area->width + text_view->xoffset,
++ area->y + area->height + text_view->yoffset);
++ }
++
+ child_exposes = NULL;
+- gtk_text_layout_draw (text_view->layout,
+- widget,
+- text_view->text_window->bin_window,
+- NULL,
+- text_view->xoffset,
+- text_view->yoffset,
+- area->x, area->y,
+- area->width, area->height,
+- &child_exposes);
++
++ if (!gtk_widget_has_focus (GTK_WIDGET (text_view))
++ && priv->placeholder_layout
++ && gtk_text_buffer_get_char_count (get_buffer (text_view)) == 0)
++ gtk_text_layout_draw (priv->placeholder_layout,
++ widget,
++ text_view->text_window->bin_window,
++ NULL,
++ text_view->xoffset,
++ text_view->yoffset,
++ area->x, area->y,
++ area->width, area->height,
++ &child_exposes);
++ else
++ gtk_text_layout_draw (text_view->layout,
++ widget,
++ text_view->text_window->bin_window,
++ NULL,
++ text_view->xoffset,
++ text_view->yoffset,
++ area->x, area->y,
++ area->width, area->height,
++ &child_exposes);
+
+ tmp_list = child_exposes;
+ while (tmp_list != NULL)
+@@ -4696,12 +4918,27 @@
+ {
+ if (gtk_widget_has_focus (widget) && !interior_focus)
+ {
+- gtk_paint_focus (widget->style, widget->window, gtk_widget_get_state (widget),
++ gtk_paint_focus (widget->style, widget->window,
++ gtk_widget_get_state (widget),
+ NULL, widget, "textview",
+ 0, 0,
+ widget->allocation.width,
+ widget->allocation.height);
+ }
++ else if (!interior_focus)
++ {
++ HildonMode hildon_mode;
++
++ gtk_widget_style_get (widget, "hildon-mode", &hildon_mode, NULL);
++ if (hildon_mode == HILDON_FREMANTLE)
++ gtk_paint_shadow (widget->style, widget->window,
++ gtk_widget_get_state (widget),
++ GTK_SHADOW_OUT,
++ NULL, widget, "textview",
++ 0, 0,
++ widget->allocation.width,
++ widget->allocation.height);
++ }
+ else
+ {
+ gdk_window_clear (widget->window);
+@@ -5613,8 +5850,6 @@
+ GtkTextIter end;
+ gboolean leave_one = FALSE;
+
+- gtk_text_view_reset_im_context (text_view);
+-
+ if (type == GTK_DELETE_CHARS)
+ {
+ /* Char delete deletes the selection, if one exists */
+@@ -5754,8 +5989,6 @@
+ {
+ GtkTextIter insert;
+
+- gtk_text_view_reset_im_context (text_view);
+-
+ /* Backspace deletes the selection, if one exists */
+ if (gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
+ text_view->editable))
+@@ -6591,11 +6824,7 @@
+ {
+ g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
+
+- if (text_view->need_im_reset)
+- {
+- text_view->need_im_reset = FALSE;
+- gtk_im_context_reset (text_view->im_context);
+- }
++ gtk_im_context_reset (text_view->im_context);
+ }
+
+ /**
+@@ -7574,6 +7803,39 @@
+ return TRUE;
+ }
+
++static gboolean
++gtk_text_view_has_selection_handler (GtkIMContext *context,
++ GtkTextView *text_view)
++{
++ GtkTextBuffer *buffer;
++
++ buffer = gtk_text_view_get_buffer (text_view);
++ return gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL);
++}
++
++static void
++gtk_text_view_clipboard_operation_handler (GtkIMContext *context,
++ GtkIMContextClipboardOperation op,
++ GtkTextView *text_view)
++{
++ /* Similar to gtk_editable_*_clipboard(), handle these by sending
++ * signals instead of directly calling our internal functions. That
++ * way the application can hook into them if needed.
++ */
++ switch (op)
++ {
++ case GTK_IM_CONTEXT_CLIPBOARD_OP_COPY:
++ g_signal_emit_by_name (text_view, "copy_clipboard");
++ break;
++ case GTK_IM_CONTEXT_CLIPBOARD_OP_CUT:
++ g_signal_emit_by_name (text_view, "cut_clipboard");
++ break;
++ case GTK_IM_CONTEXT_CLIPBOARD_OP_PASTE:
++ g_signal_emit_by_name (text_view, "paste_clipboard");
++ break;
++ }
++}
++
+ static void
+ gtk_text_view_mark_set_handler (GtkTextBuffer *buffer,
+ const GtkTextIter *location,
+@@ -7595,8 +7857,10 @@
+ need_reset = TRUE;
+ }
+
++#if 0 /* FIXME HACK */
+ if (need_reset)
+ gtk_text_view_reset_im_context (text_view);
++#endif
+ }
+
+ static void
+@@ -9319,5 +9583,249 @@
+ return gtk_text_layout_move_iter_visually (text_view->layout, iter, count);
+ }
+
++/**
++ * hildon_gtk_text_view_set_input_mode:
++ * @text_view: a #GtkTextView
++ * @mode: a #HildonGtkInputMode
++ *
++ * Sets input mode of the widget.
++ *
++ * Since: maemo 2.0
++ * Stability: Unstable
++ */
++void
++hildon_gtk_text_view_set_input_mode (GtkTextView *text_view,
++ HildonGtkInputMode mode)
++{
++ g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
++
++ if (hildon_gtk_text_view_get_input_mode (text_view) != mode)
++ {
++ g_object_set (G_OBJECT (text_view->im_context),
++ "hildon-input-mode", mode, NULL);
++ g_object_notify (G_OBJECT (text_view), "hildon-input-mode");
++ }
++}
++
++/**
++ * hildon_gtk_text_view_get_input_mode:
++ * @text_view: a #GtkTextView
++ *
++ * Gets input mode of the widget.
++ *
++ * Return value: the input mode of the widget.
++ *
++ * Since: maemo 2.0
++ * Stability: Unstable
++ */
++HildonGtkInputMode
++hildon_gtk_text_view_get_input_mode (GtkTextView *text_view)
++{
++ HildonGtkInputMode mode;
++
++ g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
++
++ g_object_get (G_OBJECT (text_view->im_context),
++ "hildon-input-mode", &mode, NULL);
++
++ return mode;
++}
++
++/**
++ * hildon_gtk_text_view_set_input_default:
++ * @text_view: a #GtkTextView
++ * @mode: a #HildonGtkInputMode
++ *
++ * Sets the default input mode of the widget.
++ *
++ * Since: maemo 5.0
++ */
++void
++hildon_gtk_text_view_set_input_default (GtkTextView *text_view,
++ HildonGtkInputMode mode)
++{
++ g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
++
++ if (hildon_gtk_text_view_get_input_default (text_view) != mode)
++ {
++ g_object_set (G_OBJECT (text_view->im_context),
++ "hildon-input-default", mode, NULL);
++ g_object_notify (G_OBJECT (text_view), "hildon-input-default");
++ }
++}
++
++/**
++ * hildon_gtk_text_view_get_input_default:
++ * @text_view: a #GtkTextView
++ *
++ * Gets the default input mode of the widget.
++ *
++ * Return value: the default input mode of the widget.
++ *
++ * Since: maemo 5
++ */
++HildonGtkInputMode
++hildon_gtk_text_view_get_input_default (GtkTextView *text_view)
++{
++ HildonGtkInputMode mode;
++
++ g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), FALSE);
++
++ g_object_get (G_OBJECT (text_view->im_context),
++ "hildon-input-default", &mode, NULL);
++
++ return mode;
++}
++
++
++/* This is more or less a stripped down version of
++ * gtk_text_view_ensure_layout().
++ */
++static void
++gtk_text_view_ensure_placeholder_layout (GtkTextView *text_view)
++{
++ GtkTextViewPrivate *priv;
++
++ priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
++
++ if (priv->placeholder_layout == NULL)
++ {
++ GdkColor font_color;
++ GtkTextAttributes *style;
++ PangoContext *ltr_context, *rtl_context;
++ GtkWidget *widget = GTK_WIDGET (text_view);
++
++ priv->placeholder_layout = gtk_text_layout_new ();
++ gtk_text_layout_set_buffer (priv->placeholder_layout,
++ priv->placeholder_buffer);
++
++ gtk_text_layout_set_cursor_visible (priv->placeholder_layout,
++ FALSE);
++
++ ltr_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
++ pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
++ rtl_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
++ pango_context_set_base_dir (rtl_context, PANGO_DIRECTION_RTL);
++
++ gtk_text_layout_set_contexts (priv->placeholder_layout,
++ ltr_context, rtl_context);
++
++ g_object_unref (ltr_context);
++ g_object_unref (rtl_context);
++
++
++ style = gtk_text_attributes_new ();
++
++ gtk_widget_ensure_style (widget);
++ gtk_text_view_set_attributes_from_style (text_view,
++ style, widget->style);
++
++ /* Override the color setting */
++ if (gtk_style_lookup_color (widget->style, "ReversedSecondaryTextColor",
++ &font_color))
++ {
++ style->appearance.fg_color = font_color;
++ }
++
++ style->pixels_above_lines = text_view->pixels_above_lines;
++ style->pixels_below_lines = text_view->pixels_below_lines;
++ style->pixels_inside_wrap = text_view->pixels_inside_wrap;
++ style->left_margin = text_view->left_margin;
++ style->right_margin = text_view->right_margin;
++ style->indent = text_view->indent;
++ style->tabs = text_view->tabs ? pango_tab_array_copy (text_view->tabs) : NULL;
++
++ style->wrap_mode = text_view->wrap_mode;
++ style->justification = text_view->justify;
++ style->direction = gtk_widget_get_direction (GTK_WIDGET (text_view));
++
++ gtk_text_layout_set_default_style (priv->placeholder_layout, style);
++
++ gtk_text_attributes_unref (style);
++ }
++
++ /* Now make sure the layout is validated. Since we expect the
++ * placeholder to only be a single line, this should be quick.
++ */
++ gtk_text_layout_validate (priv->placeholder_layout, 2000);
++}
++
++/**
++ * hildon_gtk_text_view_set_placeholder_text:
++ * @text_view: a #GtkTextView.
++ * @placeholder_text: a string to be displayed when @text_view is empty
++ * and unfocused or %NULL to remove current placeholder text.
++ *
++ * Sets a text string to be displayed when @entry is empty and unfocused.
++ * This can be provided to give a visual hint of the expected contents
++ * of the #GtkEntry.
++ *
++ * Since: maemo 5.
++ */
++void
++hildon_gtk_text_view_set_placeholder_text (GtkTextView *text_view,
++ const gchar *placeholder_text)
++{
++ GtkTextViewPrivate *priv;
++
++ g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
++
++ priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
++
++ if (!priv->placeholder_buffer)
++ priv->placeholder_buffer = gtk_text_buffer_new (NULL);
++
++ if (placeholder_text)
++ {
++ gtk_text_buffer_set_text (priv->placeholder_buffer, placeholder_text, -1);
++ gtk_text_view_ensure_placeholder_layout (text_view);
++ }
++ else
++ {
++ g_object_unref (priv->placeholder_layout);
++ priv->placeholder_layout = NULL;
++
++ g_object_unref (priv->placeholder_buffer);
++ priv->placeholder_buffer = NULL;
++ }
++
++ if (gtk_text_buffer_get_char_count (get_buffer (text_view)) == 0
++ && !gtk_widget_has_focus (GTK_WIDGET (text_view)))
++ gtk_widget_queue_draw (GTK_WIDGET (text_view));
++
++ g_object_notify (G_OBJECT (text_view), "hildon-placeholder-text");
++}
++
++/**
++ * hildon_gtk_text_view_get_placeholder_text:
++ * @text_view: a #GtkTextView
++ *
++ * Gets the text to be displayed if @text_view is empty and unfocused.
++ * The returned string must be freed using g_free().
++ *
++ * Returns: an allocated string or %NULL if no placeholder text is set.
++ *
++ * Since: maemo 5.
++ */
++gchar *
++hildon_gtk_text_view_get_placeholder_text (GtkTextView *text_view)
++{
++ GtkTextViewPrivate *priv;
++ GtkTextIter start, end;
++ gchar *text;
++
++ g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
++
++ priv = GTK_TEXT_VIEW_GET_PRIVATE (text_view);
++
++ gtk_text_buffer_get_start_iter (priv->placeholder_buffer, &start);
++ gtk_text_buffer_get_end_iter (priv->placeholder_buffer, &end);
++
++ text = gtk_text_buffer_get_text (priv->placeholder_buffer,
++ &start, &end, FALSE);
++
++ return text;
++}
++
+ #define __GTK_TEXT_VIEW_C__
+ #include "gtkaliasdef.c"
+--- a/gtk/gtktextview.h
++++ b/gtk/gtktextview.h
+@@ -371,6 +371,18 @@
+ /* note that the return value of this changes with the theme */
+ GtkTextAttributes* gtk_text_view_get_default_attributes (GtkTextView *text_view);
+
++void hildon_gtk_text_view_set_input_mode (GtkTextView *text_view,
++ HildonGtkInputMode mode);
++HildonGtkInputMode hildon_gtk_text_view_get_input_mode (GtkTextView *text_view);
++
++void hildon_gtk_text_view_set_input_default (GtkTextView *text_view,
++ HildonGtkInputMode mode);
++HildonGtkInputMode hildon_gtk_text_view_get_input_default (GtkTextView *text_view);
++
++void hildon_gtk_text_view_set_placeholder_text (GtkTextView *text_view,
++ const gchar *text);
++gchar *hildon_gtk_text_view_get_placeholder_text (GtkTextView *text_view);
++
+ G_END_DECLS
+
+ #endif /* __GTK_TEXT_VIEW_H__ */
diff --git a/hildonize-gtk-widget.patch b/hildonize-gtk-widget.patch
new file mode 100644
index 000000000000..42ea933bcb5a
--- /dev/null
+++ b/hildonize-gtk-widget.patch
@@ -0,0 +1,932 @@
+--- a/gtk/gtkwidget.c
++++ b/gtk/gtkwidget.c
+@@ -54,6 +54,12 @@
+ #include "gtkbuildable.h"
+ #include "gtkbuilderprivate.h"
+ #include "gtkalias.h"
++#include <x11/gdkx.h>
++#include <stdlib.h>
++#include "gtkmenu.h"
++#include "gtkmenuitem.h"
++#include "gtkicontheme.h"
++#include "gtkdnd.h"
+
+ /**
+ * SECTION:gtkwidget
+@@ -127,6 +133,8 @@
+ #define WIDGET_CLASS(w) GTK_WIDGET_GET_CLASS (w)
+ #define INIT_PATH_SIZE (512)
+
++#define TAP_AND_HOLD_TIMER_COUNTER 6
++#define TAP_AND_HOLD_TIMER_INTERVAL 100
+
+ enum {
+ SHOW,
+@@ -197,6 +205,10 @@
+ KEYNAV_FAILED,
+ DRAG_FAILED,
+ DAMAGE_EVENT,
++ INSENSITIVE_PRESS,
++ TAP_AND_HOLD,
++ TAP_AND_HOLD_SETUP,
++ TAP_AND_HOLD_QUERY,
+ LAST_SIGNAL
+ };
+
+@@ -224,7 +236,8 @@
+ PROP_TOOLTIP_MARKUP,
+ PROP_TOOLTIP_TEXT,
+ PROP_WINDOW,
+- PROP_DOUBLE_BUFFERED
++ PROP_DOUBLE_BUFFERED,
++ PROP_TAP_AND_HOLD
+ };
+
+ typedef struct _GtkStateData GtkStateData;
+@@ -352,6 +365,46 @@
+ static void gtk_widget_get_draw_rectangle (GtkWidget *widget,
+ GdkRectangle *rect);
+
++typedef struct
++{
++ GtkWidget *menu;
++ guint timer_id;
++
++ GtkMenuPositionFunc func;
++ gint x, y;
++ gint timer_counter;
++ gint signals_connected : 1;
++ guint interval;
++ GdkWindow *tah_on_window;
++
++#ifdef TAP_AND_HOLD_ANIMATION
++ GdkPixbufAnimation *anim;
++ GdkPixbufAnimationIter *iter;
++#endif
++} TahData;
++
++/* --- Tap And Hold --- */
++static gboolean gtk_widget_tap_and_hold_timeout (GtkWidget *widget);
++static gboolean gtk_widget_tap_and_hold_button_press (GtkWidget *widget,
++ GdkEvent *event,
++ TahData *td);
++static gboolean gtk_widget_tap_and_hold_event_stop (GtkWidget *widget,
++ gpointer unused,
++ TahData *td);
++static void gtk_widget_real_tap_and_hold_setup (GtkWidget *widget,
++ GtkWidget *menu,
++ GtkCallback func,
++ GtkWidgetTapAndHoldFlags flags );
++static void gtk_widget_real_tap_and_hold (GtkWidget *widget);
++static gboolean gtk_widget_tap_and_hold_query (GtkWidget *widget,
++ GdkEvent *event);
++static gboolean gtk_widget_real_tap_and_hold_query (GtkWidget *widget,
++ GdkEvent *event);
++
++static gboolean gtk_widget_tap_and_hold_query_accumulator (GSignalInvocationHint *ihint,
++ GValue *return_accu,
++ const GValue *handler_return,
++ gpointer dummy);
+
+ /* --- variables --- */
+ static gpointer gtk_widget_parent_class = NULL;
+@@ -439,6 +492,23 @@
+ {
+ GTK_WIDGET_GET_CLASS (object)->dispatch_child_properties_changed (GTK_WIDGET (object), n_pspecs, pspecs);
+ }
++static void
++maemo_widget_constructed (GObject *object)
++{
++ static GQuark quark_maemo_widget_customizer = 0;
++
++ if (!quark_maemo_widget_customizer)
++ {
++ quark_maemo_widget_customizer =
++ g_quark_from_static_string ("maemo_widget_customizer");
++ }
++
++ void (*hook) (GtkWidget*) = g_type_get_qdata (G_OBJECT_TYPE (object),
++ quark_maemo_widget_customizer);
++
++ if (hook)
++ hook (GTK_WIDGET (object));
++}
+
+ static void
+ gtk_widget_class_init (GtkWidgetClass *klass)
+@@ -475,6 +545,7 @@
+ cpn_context.dispatcher = child_property_notify_dispatcher;
+ _gtk_widget_child_property_notify_context = &cpn_context;
+
++ gobject_class->constructed = maemo_widget_constructed;
+ gobject_class->dispose = gtk_widget_dispose;
+ gobject_class->finalize = gtk_widget_finalize;
+ gobject_class->set_property = gtk_widget_set_property;
+@@ -681,7 +752,6 @@
+ P_("Whether gtk_widget_show_all() should not affect this widget"),
+ FALSE,
+ GTK_PARAM_READWRITE));
+-
+ /**
+ * GtkWidget:has-tooltip:
+ *
+@@ -778,6 +848,28 @@
+ GTK_PARAM_READWRITE));
+
+ /**
++ * GtkWidget:tap-and-hold-state:
++ *
++ * Sets the state (#GtkStateType) to be used to the tap and hold
++ * functionality. The default is GTK_STATE_NORMAL.
++ *
++ * Deprecated: Functionality for setting and getting this propery is not
++ * implemented.
++ *
++ * Since: maemo 1.0
++ * Stability: Unstable
++ */
++ g_object_class_install_property (gobject_class,
++ PROP_TAP_AND_HOLD,
++ g_param_spec_int ("tap-and-hold-state",
++ P_("Tap and hold State type"),
++ P_("Sets the state to be used to the tap and hold functionality. The default is GTK_STATE_NORMAL"),
++ 0,
++ 4, /*4 == Last state in GTK+-2.0*/
++ GTK_STATE_NORMAL,
++ G_PARAM_READWRITE));
++
++ /**
+ * GtkWidget::show:
+ * @widget: the object which received the signal.
+ */
+@@ -2399,6 +2491,96 @@
+ _gtk_marshal_BOOLEAN__UINT,
+ G_TYPE_BOOLEAN, 1, G_TYPE_UINT);
+
++ /**
++ * GtkWidget::insensitive-press:
++ * @widget: the object which received the signal
++ *
++ * If a widget is insensitive and it receives click event,
++ * the signal is emited. Signal is made to clarify situations where
++ * a widget is not easily noticable as an insensitive widget.
++ *
++ * Deprecated: Use hildon_helper_set_insensitive_message() instead.
++ *
++ * Since: maemo 1.0
++ * Stability: Unstable
++ */
++ widget_signals[INSENSITIVE_PRESS] =
++ g_signal_new ("insensitive_press",
++ G_TYPE_FROM_CLASS (gobject_class),
++ G_SIGNAL_RUN_FIRST,
++ 0,
++ NULL, NULL,
++ _gtk_marshal_VOID__VOID,
++ G_TYPE_NONE, 0);
++ /**
++ * GtkWidget::tap-and-hold:
++ * @widget: the object which received the signal
++ *
++ * The signal is emited when tap and hold activity occurs.
++ *
++ * Since: maemo 1.0
++ * Stability: Unstable
++ */
++ widget_signals[TAP_AND_HOLD] =
++ g_signal_new_class_handler ("tap_and_hold",
++ G_TYPE_FROM_CLASS (gobject_class),
++ G_SIGNAL_RUN_LAST,
++ G_CALLBACK (gtk_widget_real_tap_and_hold),
++ NULL, NULL,
++ _gtk_marshal_VOID__VOID,
++ G_TYPE_NONE, 0);
++ /**
++ * GtkWidget::tap-and-hold-setup:
++ * @widget: the object which received the signal
++ * @menu: the menu to be opened.
++ * @func: the menu position function
++ * @flags: deprecated
++ *
++ * Enables the tap and hold functionality to the @widget.
++ * Usually a @menu is used at tap and hold signal,
++ * but this is optional. Setup can be run and some other functionality
++ * may be connected to it as well. Usually this signal is not used,
++ * instead the virtual function is over written.
++ *
++ * Since: maemo 1.0
++ * Stability: Unstable
++ */
++ widget_signals[TAP_AND_HOLD_SETUP] =
++ g_signal_new_class_handler ("tap_and_hold_setup",
++ G_TYPE_FROM_CLASS (gobject_class),
++ G_SIGNAL_RUN_LAST,
++ G_CALLBACK (gtk_widget_real_tap_and_hold_setup),
++ NULL, NULL,
++ /*FIXME -- OBJECT_POINTER_FLAGS*/
++ _gtk_marshal_VOID__OBJECT_UINT_FLAGS,
++ G_TYPE_NONE, 3,
++ G_TYPE_OBJECT,
++ G_TYPE_POINTER,
++ G_TYPE_UINT);
++
++ /**
++ * GtkWidget::tap-and-hold-query:
++ * @widget: the object which received the signal
++ * @returns: %FALSE if tap and hold is allowed to be started
++ *
++ * Signal is used in a situation where tap and hold is not allowed to be
++ * started in some mysterious reason. A good mysterious reason could be,
++ * a widget which area is big and only part of it is allowed to start
++ * tap and hold.
++ *
++ * Since: maemo 1.0
++ * Stability: Unstable
++ */
++ widget_signals[TAP_AND_HOLD_QUERY] =
++ g_signal_new_class_handler ("tap_and_hold_query",
++ G_TYPE_FROM_CLASS (gobject_class),
++ G_SIGNAL_RUN_LAST,
++ G_CALLBACK (gtk_widget_real_tap_and_hold_query),
++ gtk_widget_tap_and_hold_query_accumulator, NULL,
++ _gtk_marshal_BOOLEAN__BOXED,
++ G_TYPE_BOOLEAN, 1,
++ GDK_TYPE_EVENT);
++
+ binding_set = gtk_binding_set_by_class (klass);
+ gtk_binding_entry_add_signal (binding_set, GDK_F10, GDK_SHIFT_MASK,
+ "popup-menu", 0);
+@@ -2466,7 +2648,19 @@
+ P_("Aspect ratio with which to draw insertion cursor"),
+ 0.0, 1.0, 0.04,
+ GTK_PARAM_READABLE));
+-
++ gtk_widget_class_install_style_property (klass,
++ g_param_spec_boolean ("maemo-position-theming",
++ P_("Maemo position theming"),
++ P_("Theming hint to allow rounded corner effects on border children"),
++ FALSE,
++ GTK_PARAM_READABLE));
++ gtk_widget_class_install_style_property (klass,
++ g_param_spec_enum ("hildon-mode",
++ P_("Hildon Mode"),
++ P_("The mode according to which widgets should behave"),
++ HILDON_TYPE_MODE,
++ HILDON_DIABLO,
++GTK_PARAM_READABLE));
+ /**
+ * GtkWidget:draw-border:
+ *
+@@ -2749,6 +2943,8 @@
+ case PROP_DOUBLE_BUFFERED:
+ gtk_widget_set_double_buffered (widget, g_value_get_boolean (value));
+ break;
++ case PROP_TAP_AND_HOLD:
++ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+@@ -2858,6 +3054,8 @@
+ case PROP_DOUBLE_BUFFERED:
+ g_value_set_boolean (value, gtk_widget_get_double_buffered (widget));
+ break;
++ case PROP_TAP_AND_HOLD:
++ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+@@ -4149,6 +4347,9 @@
+ gtk_widget_invalidate_widget_windows (widget->parent, invalidate);
+ gdk_region_destroy (invalidate);
+ }
++
++ if (gtk_widget_is_toplevel (widget))
++ _gtk_container_post_size_allocate (GTK_CONTAINER (widget));
+ }
+
+ /**
+@@ -11449,5 +11650,586 @@
+ return res;
+ }
+
++void gtk_widget_set_hildon_focus_handling( GtkWidget *widget, gboolean hildon_like )
++{
++}
++
++gboolean gtk_widget_get_hildon_focus_handling( GtkWidget *widget )
++{
++ return FALSE;
++}
++
++
++/* -- Tap and hold implementation -- */
++
++static TahData*
++gtk_widget_peek_tah_data (GtkWidget *widget)
++{
++ TahData *td = g_object_get_data (G_OBJECT (widget), "MaemoGtkWidget-tap-and-hold");
++ return td;
++}
++
++static void
++tap_and_hold_stop_animation (TahData *td)
++{
++#ifdef TAP_AND_HOLD_ANIMATION
++ if (td->tah_on_window)
++ gdk_window_set_cursor (td->tah_on_window, NULL);
++ td->tah_on_window = NULL;
++
++ if (td->anim)
++ g_object_unref (td->anim);
++ td->anim = NULL;
++
++ if (td->iter)
++ g_object_unref (td->iter);
++ td->iter = NULL;
++#endif
++}
++
++static void
++tap_and_hold_free_data (gpointer data)
++{
++ TahData *td = data;
++ if (td)
++ {
++ if (td->timer_id)
++ g_source_remove (td->timer_id);
++ td->timer_id = 0;
++
++ if (GTK_IS_MENU (td->menu))
++ g_object_unref (td->menu);
++ td->menu = NULL;
++
++ tap_and_hold_stop_animation (td);
++
++ g_free (td);
++ }
++}
++
++static void
++gtk_widget_set_tah_data (GtkWidget *widget, TahData *td)
++{
++ g_object_set_data_full (G_OBJECT (widget), "MaemoGtkWidget-tap-and-hold",
++ td, tap_and_hold_free_data);
++}
++
++static TahData*
++gtk_widget_get_tah_data (GtkWidget *widget)
++{
++ TahData *td = gtk_widget_peek_tah_data (widget);
++ if (!td)
++ {
++ td = g_new0 (TahData, 1);
++ td->interval = TAP_AND_HOLD_TIMER_INTERVAL;
++ gtk_widget_set_tah_data (widget, td);
++ }
++ return td;
++}
++
++static void
++tap_and_hold_remove_timer (GtkWidget *widget)
++{
++ TahData *td = gtk_widget_peek_tah_data (widget);
++ if (td)
++ {
++ if (td->timer_id)
++ {
++ g_source_remove (td->timer_id);
++ td->timer_id = 0;
++ }
++
++ td->x = td->y = td->timer_counter = 0;
++ tap_and_hold_stop_animation (td);
++ }
++}
++
++#ifdef TAP_AND_HOLD_ANIMATION
++static GdkPixbufAnimation *
++tap_and_hold_load_animation_for_screen (GdkScreen *screen)
++{
++ GtkIconTheme *theme;
++ GtkIconInfo *info;
++ const char *filename = NULL;
++ GdkPixbufAnimation *anim = NULL;
++ GError *error = NULL;
++
++ theme = gtk_icon_theme_get_for_screen (screen);
++
++ info = gtk_icon_theme_lookup_icon (theme, "qgn_indi_tap_hold_a",
++ GTK_ICON_SIZE_BUTTON,
++ GTK_ICON_LOOKUP_NO_SVG);
++ if (info)
++ filename = gtk_icon_info_get_filename (info);
++ if (!info || !filename)
++ {
++ g_warning ("Unable to find tap and hold icon filename");
++ goto out;
++ }
++
++ anim = gdk_pixbuf_animation_new_from_file (filename, &error);
++ if (!anim)
++ {
++ g_warning ("Unable to load tap and hold animation: %s", error->message);
++ goto out;
++ }
++
++out:
++ if (info)
++ gtk_icon_info_free (info);
++ if (error)
++ g_error_free (error);
++
++ return anim;
++}
++#endif
++
++static void
++tap_and_hold_init_animation (TahData *td)
++{
++#ifdef TAP_AND_HOLD_ANIMATION
++ if (!td->anim)
++ td->anim = tap_and_hold_load_animation_for_screen (gdk_drawable_get_screen (td->tah_on_window));
++
++ if (td->anim)
++ {
++ if (td->iter)
++ g_object_unref (td->iter);
++ td->iter = gdk_pixbuf_animation_get_iter (td->anim, NULL);
++
++ td->interval = gdk_pixbuf_animation_iter_get_delay_time (td->iter);
++ }
++#endif
++}
++
++static gboolean
++tap_and_hold_animation_timeout (GtkWidget *widget)
++{
++#ifdef TAP_AND_HOLD_ANIMATION
++ TahData *td = gtk_widget_peek_tah_data (widget);
++
++ if (!td || !GDK_IS_WINDOW (td->tah_on_window))
++ {
++ tap_and_hold_remove_timer (widget);
++ return FALSE;
++ }
++
++ if (td->anim)
++ {
++ guint new_interval = 0;
++ GTimeVal time;
++ GdkScreen *screen;
++ GdkPixbuf *pic;
++ GdkCursor *cursor;
++ const gchar *x_hot, *y_hot;
++ gint x, y;
++
++ g_get_current_time (&time);
++ screen = gdk_screen_get_default ();
++ pic = gdk_pixbuf_animation_iter_get_pixbuf (td->iter);
++
++ pic = gdk_pixbuf_copy (pic);
++
++ if (!GDK_IS_PIXBUF (pic))
++ return TRUE;
++
++ x_hot = gdk_pixbuf_get_option (pic, "x_hot");
++ y_hot = gdk_pixbuf_get_option (pic, "y_hot");
++ x = (x_hot) ? atoi(x_hot) : gdk_pixbuf_get_width(pic) / 2;
++ y = (y_hot) ? atoi(y_hot) : gdk_pixbuf_get_height(pic) / 2;
++
++ cursor = gdk_cursor_new_from_pixbuf (gdk_display_get_default (), pic,
++ x, y);
++ g_object_unref (pic);
++
++ if (!cursor)
++ return TRUE;
++
++ gdk_window_set_cursor (td->tah_on_window, cursor);
++ gdk_cursor_unref (cursor);
++
++ gdk_pixbuf_animation_iter_advance (td->iter, &time);
++
++ new_interval = gdk_pixbuf_animation_iter_get_delay_time (td->iter);
++
++ if (new_interval != td->interval && td->timer_counter)
++ {
++ td->interval = new_interval;
++ td->timer_id = g_timeout_add (td->interval,
++ (GSourceFunc)gtk_widget_tap_and_hold_timeout, widget);
++ return FALSE;
++ }
++ }
++#endif
++ return TRUE;
++}
++
++/**
++ * gtk_widget_tap_and_hold_menu_position_top:
++ * @menu: a #GtkMenu
++ * @x: x cordinate to be returned
++ * @y: y cordinate to be returned
++ * @push_in: If going off screen, push it pack on the screen
++ * @widget: a #GtkWidget
++ *
++ * Pre-made menu positioning function.
++ * It positiones the @menu over the @widget.
++ *
++ * Since: maemo 1.0
++ * Stability: Unstable
++ **/
++void
++gtk_widget_tap_and_hold_menu_position_top (GtkWidget *menu,
++ gint *x,
++ gint *y,
++ gboolean *push_in,
++ GtkWidget *widget)
++{
++ /*
++ * This function positiones the menu above widgets.
++ * This is a modified version of the position function
++ * gtk_combo_box_position_over.
++ */
++ GtkWidget *topw;
++ GtkRequisition requisition;
++ gint screen_width = 0;
++ gint menu_xpos = 0;
++ gint menu_ypos = 0;
++ gint w_xpos = 0, w_ypos = 0;
++ gtk_widget_size_request (menu, &requisition);
++
++ topw = gtk_widget_get_toplevel (widget);
++ gdk_window_get_origin (topw->window, &w_xpos, &w_ypos);
++
++ menu_xpos += widget->allocation.x + w_xpos;
++ menu_ypos += widget->allocation.y + w_ypos - requisition.height;
++
++ if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
++ menu_xpos = menu_xpos + widget->allocation.width - requisition.width;
++
++ screen_width = gdk_screen_get_width (gtk_widget_get_screen (widget));
++
++ if (menu_xpos < w_xpos)
++ menu_xpos = w_xpos;
++ else if ((menu_xpos + requisition.width) > screen_width)
++ menu_xpos -= ((menu_xpos + requisition.width) - screen_width);
++ if (menu_ypos < w_ypos)
++ menu_ypos = w_ypos;
++
++ *x = menu_xpos;
++ *y = menu_ypos;
++ *push_in = TRUE;
++}
++
++/**
++ * gtk_widget_tap_and_hold_setup:
++ * @widget : a #GtkWidget
++ * @menu : a #GtkMenu or %NULL
++ * @func : a #GtkMenuPositionFunc or %NULL
++ * @flags : a #GtkWidgetTapAndHoldFlags
++ *
++ * Setups the tap and hold functionality to the @widget.
++ * The @menu is shown when the functionality is activated.
++ * If the @menu is wanted to be positioned in a different way than the
++ * gtk+ default, the menuposition @func can be passed as a third parameter.
++ * Fourth parameter, @flags is deprecated and has no effect.
++ *
++ * Since: maemo 1.0
++ * Stability: Unstable
++ */
++void
++gtk_widget_tap_and_hold_setup (GtkWidget *widget,
++ GtkWidget *menu,
++ GtkCallback func,
++ GtkWidgetTapAndHoldFlags flags)
++{
++ g_return_if_fail (GTK_IS_WIDGET (widget));
++ g_return_if_fail (menu == NULL || GTK_IS_MENU (menu));
++
++ g_signal_emit (widget, widget_signals[TAP_AND_HOLD_SETUP], 0, menu, func,
++ flags);
++}
++
++static void
++gtk_widget_real_tap_and_hold_setup (GtkWidget *widget,
++ GtkWidget *menu,
++ GtkCallback func,
++ GtkWidgetTapAndHoldFlags flags)
++{
++ TahData *td;
++
++ g_return_if_fail (GTK_IS_WIDGET (widget));
++ g_return_if_fail (menu == NULL || GTK_IS_MENU (menu));
++
++ td = gtk_widget_get_tah_data (widget);
++ if (td->signals_connected)
++ return;
++
++ if (menu != NULL)
++ {
++ g_object_ref_sink (menu);
++
++ if (gtk_menu_get_attach_widget (GTK_MENU (menu)) == NULL)
++ gtk_menu_attach_to_widget (GTK_MENU (menu), widget, NULL);
++ }
++
++ td->menu = menu;
++ td->func = (GtkMenuPositionFunc)func;
++ td->signals_connected = TRUE;
++ td->timer_counter = 0;
++
++ g_signal_connect (widget, "button-press-event",
++ G_CALLBACK (gtk_widget_tap_and_hold_button_press), td);
++ g_signal_connect (widget, "button-release-event",
++ G_CALLBACK (gtk_widget_tap_and_hold_event_stop), td);
++ g_signal_connect (widget, "leave-notify-event",
++ G_CALLBACK (gtk_widget_tap_and_hold_event_stop), td);
++ g_signal_connect (widget, "drag-begin",
++ G_CALLBACK (gtk_widget_tap_and_hold_event_stop), td);
++}
++
++static void
++gtk_widget_real_tap_and_hold (GtkWidget *widget)
++{
++ TahData *td = gtk_widget_peek_tah_data (widget);
++ if (td && GTK_IS_MENU (td->menu))
++ gtk_menu_popup (GTK_MENU (td->menu), NULL, NULL,
++ (GtkMenuPositionFunc)td->func,
++ widget, 1, gdk_x11_get_server_time (widget->window));
++}
++
++static gboolean
++gtk_widget_tap_and_hold_timeout (GtkWidget *widget)
++{
++ TahData *td = gtk_widget_peek_tah_data (widget);
++ gboolean result;
++ gint x = 0, y = 0;
++
++ GDK_THREADS_ENTER ();
++
++ if (!td || !GDK_IS_WINDOW (td->tah_on_window))
++ {
++ tap_and_hold_remove_timer (widget);
++
++ GDK_THREADS_LEAVE ();
++ return FALSE;
++ }
++
++ /* A small timeout before starting the tap and hold */
++ if (td->timer_counter == TAP_AND_HOLD_TIMER_COUNTER)
++ {
++ td->timer_counter--;
++
++ GDK_THREADS_LEAVE ();
++ return TRUE;
++ }
++
++ result = tap_and_hold_animation_timeout (widget);
++
++ if (td->timer_counter)
++ td->timer_counter--;
++ else
++ td->timer_id = 0;
++
++ gdk_display_get_pointer (gdk_drawable_get_display (td->tah_on_window),
++ NULL, &x, &y, NULL);
++
++ /* Did we dragged too far from the start point */
++ if (gtk_drag_check_threshold (widget, td->x, td->y, x, y))
++ {
++ tap_and_hold_remove_timer (widget);
++
++ GDK_THREADS_LEAVE ();
++ return FALSE;
++ }
++
++ /* Was that the last cycle -> tah starts */
++ if (!td->timer_id)
++ {
++ tap_and_hold_remove_timer (widget);
++
++ _gtk_menu_push_context_menu_behavior ();
++
++ g_signal_emit (widget, widget_signals[TAP_AND_HOLD], 0);
++
++ _gtk_menu_pop_context_menu_behavior ();
++
++ GDK_THREADS_LEAVE ();
++ return FALSE;
++ }
++
++ GDK_THREADS_LEAVE ();
++ return result;
++}
++
++static gboolean
++gtk_widget_tap_and_hold_query_accumulator (GSignalInvocationHint *ihint,
++ GValue *return_accu,
++ const GValue *handler_return,
++ gpointer dummy)
++{
++ gboolean tap_and_hold_not_allowed;
++
++ /* The semantics of the tap-and-hold-query return value differs from
++ * the normal event signal handlers.
++ */
++
++ tap_and_hold_not_allowed = g_value_get_boolean (handler_return);
++ g_value_set_boolean (return_accu, tap_and_hold_not_allowed);
++
++ /* Now that a single handler has run, we stop emission. */
++ return FALSE;
++}
++
++static gboolean
++gtk_widget_real_tap_and_hold_query (GtkWidget *widget,
++ GdkEvent *event)
++{
++ return FALSE;
++}
++
++static gboolean
++gtk_widget_tap_and_hold_query (GtkWidget *widget,
++ GdkEvent *event)
++{
++ gboolean return_value = FALSE;
++
++ g_signal_emit (G_OBJECT (widget), widget_signals[TAP_AND_HOLD_QUERY],
++ 0, event, &return_value);
++
++ return return_value;
++}
++
++static gboolean
++gtk_widget_tap_and_hold_button_press (GtkWidget *widget,
++ GdkEvent *event,
++ TahData *td)
++{
++ if (event->button.type == GDK_2BUTTON_PRESS)
++ return FALSE;
++
++ if (!gtk_widget_tap_and_hold_query (widget, event) && !td->timer_id)
++ {
++ GdkWindow *root_window;
++ gdk_display_get_pointer (gtk_widget_get_display (widget),
++ NULL, &td->x, &td->y, NULL);
++
++ td->timer_counter = TAP_AND_HOLD_TIMER_COUNTER;
++ /* We set the cursor in the root window for the TAH animation to be
++ visible in every possible case, like windows completely covering
++ some widget to filter events.
++ */
++ root_window = gtk_widget_get_root_window (widget);
++ if (root_window == NULL)
++ {
++ /* We are getting events from a widget that's not in a
++ hierarchy, it might happen (like putting a dummy widget
++ as user_data in a GdkWindow). Try really hard to get
++ the root window
++ */
++ root_window = gdk_screen_get_root_window (gdk_screen_get_default ());
++ }
++ td->tah_on_window = root_window;
++ tap_and_hold_init_animation (td);
++ td->timer_id = g_timeout_add (td->interval,
++ (GSourceFunc)
++ gtk_widget_tap_and_hold_timeout, widget);
++ }
++ return FALSE;
++}
++
++static gboolean
++gtk_widget_tap_and_hold_event_stop (GtkWidget *widget,
++ gpointer unused,
++ TahData *td)
++{
++ if (td->timer_id)
++ tap_and_hold_remove_timer (widget);
++
++ return FALSE;
++}
++
++
++/**
++ * gtk_widget_insensitive_press:
++ * @widget: a #GtkWidget
++ *
++ * Emits the "insensitive-press" signal.
++ *
++ * Deprecated: Use hildon_helper_set_insensitive_message() instead.
++ *
++ * Since: maemo 1.0
++ * Stability: Unstable
++ */
++void
++gtk_widget_insensitive_press ( GtkWidget *widget )
++{
++ g_return_if_fail (GTK_IS_WIDGET (widget));
++ g_signal_emit(widget, widget_signals[INSENSITIVE_PRESS], 0);
++}
++
++#define HILDON_HEIGHT_FINGER 70
++
++#define HILDON_HEIGHT_THUMB 105
++
++#define HILDON_WIDTH_FULLSCREEN (gdk_screen_get_width (gdk_screen_get_default ()))
++
++#define HILDON_WIDTH_HALFSCREEN (HILDON_WIDTH_FULLSCREEN / 2)
++
++/**
++ * hildon_gtk_widget_set_theme_size:
++ * @widget: A #GtkWidget
++ * @size: #HildonSizeType flags indicating the size of the widget
++ *
++ * This function sets the requested size of a widget using one of the
++ * predefined sizes.
++ *
++ * It also changes the widget name (see gtk_widget_set_name()) so it
++ * can be themed accordingly.
++ *
++ * Since: maemo 2.0
++ * Stability: Unstable
++ **/
++void
++hildon_gtk_widget_set_theme_size (GtkWidget *widget,
++ HildonSizeType size)
++{
++ gint width = -1;
++ gint height = -1;
++ gchar *widget_name = NULL;
++
++ g_return_if_fail (GTK_IS_WIDGET (widget));
++
++ /* Requested height */
++ if (size & HILDON_SIZE_FINGER_HEIGHT)
++ {
++ height = HILDON_HEIGHT_FINGER;
++ widget_name = "-finger";
++ }
++ else if (size & HILDON_SIZE_THUMB_HEIGHT)
++ {
++ height = HILDON_HEIGHT_THUMB;
++ widget_name = "-thumb";
++ }
++
++ if (widget_name)
++ widget_name = g_strconcat (g_type_name (G_OBJECT_TYPE (widget)),
++ widget_name, NULL);
++
++ /* Requested width */
++ if (size & HILDON_SIZE_HALFSCREEN_WIDTH)
++ width = HILDON_WIDTH_HALFSCREEN;
++ else if (size & HILDON_SIZE_FULLSCREEN_WIDTH)
++ width = HILDON_WIDTH_FULLSCREEN;
++
++ gtk_widget_set_size_request (widget, width, height);
++
++ if (widget_name)
++ {
++ gtk_widget_set_name (widget, widget_name);
++ g_free (widget_name);
++ }
++}
++
+ #define __GTK_WIDGET_C__
+ #include "gtkaliasdef.c"
+--- a/gtk/gtkwidget.h
++++ b/gtk/gtkwidget.h
+@@ -130,6 +130,14 @@
+ GTK_WIDGET_HELP_WHATS_THIS
+ } GtkWidgetHelpType;
+
++ typedef enum
++ {
++ GTK_TAP_AND_HOLD_NONE = 0,
++ GTK_TAP_AND_HOLD_PASS_PRESS = 1 << 0,
++ GTK_TAP_AND_HOLD_NO_SIGNALS = 1 << 1,
++ GTK_TAP_AND_HOLD_NO_INTERNALS = 1 << 2
++ } GtkWidgetTapAndHoldFlags;
++
+ /* Macro for casting a pointer to a GtkWidget or GtkWidgetClass pointer.
+ * Macros for testing whether `widget' or `klass' are of type GTK_TYPE_WIDGET.
+ */
+@@ -1345,6 +1353,20 @@
+ void _gtk_widget_buildable_finish_accelerator (GtkWidget *widget,
+ GtkWidget *toplevel,
+ gpointer user_data);
++void gtk_widget_tap_and_hold_menu_position_top (GtkWidget *menu,
++ gint *x,
++ gint *y,
++ gboolean *push_in,
++ GtkWidget *widget);
++void gtk_widget_tap_and_hold_setup (GtkWidget *widget,
++ GtkWidget *menu,
++ GtkCallback func,
++ GtkWidgetTapAndHoldFlags flags);
++
++void gtk_widget_insensitive_press ( GtkWidget *widget );
++
++void hildon_gtk_widget_set_theme_size (GtkWidget *widget,
++ HildonSizeType size);
+
+ G_END_DECLS
+
diff --git a/hildonize-gtk-window.patch b/hildonize-gtk-window.patch
new file mode 100644
index 000000000000..ccf00f227d10
--- /dev/null
+++ b/hildonize-gtk-window.patch
@@ -0,0 +1,278 @@
+--- a/gtk/gtkwindow.c
++++ b/gtk/gtkwindow.c
+@@ -103,6 +103,7 @@
+ PROP_STARTUP_ID,
+
+ PROP_MNEMONICS_VISIBLE,
++ PROP_TEMPORARY,
+
+ LAST_ARG
+ };
+@@ -190,6 +191,7 @@
+
+ guint mnemonics_visible : 1;
+ guint mnemonics_visible_set : 1;
++ guint is_temporary : 1;
+
+ GdkWindowTypeHint type_hint;
+
+@@ -805,6 +807,26 @@
+ 1.0,
+ GTK_PARAM_READWRITE));
+
++ /**
++ * GtkWindow:temporary:
++ *
++ * Whether the window is "temporary" (completion popups, menus, etc) and should be
++ * automatically closed when it receives the _GTK_DELETE_TEMPORARIES ClientMessage.
++ * If set to TRUE GTK will send a delete-event to the window whenever it receives
++ * a _GTK_DELETE_TEMPORARIES message, so this needs to be properly handled by the
++ * widget.
++ *
++ * Since: maemo 4.0
++ * Stability: Unstable
++ */
++ g_object_class_install_property (gobject_class,
++ PROP_DELETABLE,
++ g_param_spec_boolean ("temporary",
++ P_("Temporary"),
++ P_("Whether the window should be closed when it receives the _GTK_DELETE_TEMPORARIES ClientMessage"),
++ FALSE,
++ GTK_PARAM_READWRITE));
++
+ window_signals[SET_FOCUS] =
+ g_signal_new (I_("set-focus"),
+ G_TYPE_FROM_CLASS (gobject_class),
+@@ -1084,6 +1106,9 @@
+ case PROP_MNEMONICS_VISIBLE:
+ gtk_window_set_mnemonics_visible (window, g_value_get_boolean (value));
+ break;
++ case PROP_TEMPORARY:
++ gtk_window_set_is_temporary (window, g_value_get_boolean (value));
++ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+@@ -1202,6 +1227,8 @@
+ case PROP_MNEMONICS_VISIBLE:
+ g_value_set_boolean (value, priv->mnemonics_visible);
+ break;
++ case PROP_TEMPORARY:
++ g_value_set_boolean (value, gtk_window_get_is_temporary (window));
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+@@ -4699,6 +4726,9 @@
+ else
+ gdk_window_withdraw (widget->window);
+
++ /* Keep it in sync with configure_request_count. */
++ gdk_window_reset_toplevel_updates_libgtk_only (widget->window);
++
+ window->configure_request_count = 0;
+ window->configure_notify_received = FALSE;
+
+@@ -5347,6 +5377,7 @@
+
+ static GdkAtom atom_rcfiles = GDK_NONE;
+ static GdkAtom atom_iconthemes = GDK_NONE;
++static GdkAtom atom_temporaries = GDK_NONE;
+
+ static void
+ send_client_message_to_embedded_windows (GtkWidget *widget,
+@@ -5376,6 +5407,73 @@
+ }
+ }
+
++/**
++ * gtk_window_set_is_temporary:
++ * @window: a #GtkWindow
++ * @setting: %TRUE if the window should be closed when it receives the _GTK_DELETE_TEMPORARIES ClientMessage
++ *
++ * Since: maemo 4.0
++ * Stability: Unstable
++ */
++void
++gtk_window_set_is_temporary (GtkWindow *window,
++ gboolean setting)
++{
++ GtkWindowPrivate *priv;
++
++ g_return_if_fail (GTK_IS_WINDOW (window));
++
++ priv = GTK_WINDOW_GET_PRIVATE (window);
++
++ if (priv->is_temporary != setting)
++ {
++ priv->is_temporary = setting;
++
++ g_object_notify (G_OBJECT (window), "temporary");
++ }
++}
++
++/**
++ * gtk_window_get_is_temporary:
++ * @window: a #GtkWindow
++ *
++ * Return value: %TRUE if the window is marked as temporary.
++ *
++ * Since: maemo 4.0
++ * Stability: Unstable
++ */
++gboolean
++gtk_window_get_is_temporary (GtkWindow *window)
++{
++ GtkWindowPrivate *priv;
++
++ g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
++
++ priv = GTK_WINDOW_GET_PRIVATE (window);
++ return priv->is_temporary;
++}
++
++static void
++delete_if_temporary (GtkWidget *widget, GdkEventClient *client)
++{
++ GtkWindowPrivate *priv = GTK_WINDOW_GET_PRIVATE (widget);
++
++ if (priv->is_temporary &&
++ _gtk_window_is_on_client_data (GTK_WINDOW (widget), client) == FALSE)
++ {
++ /* synthesize delete-event to close the window */
++ GdkEvent *event;
++
++ event = gdk_event_new (GDK_DELETE);
++
++ event->any.window = g_object_ref (widget->window);
++ event->any.send_event = TRUE;
++
++ gtk_main_do_event (event);
++ gdk_event_free (event);
++ }
++}
++
+ static gint
+ gtk_window_client_event (GtkWidget *widget,
+ GdkEventClient *event)
+@@ -5384,18 +5482,29 @@
+ {
+ atom_rcfiles = gdk_atom_intern_static_string ("_GTK_READ_RCFILES");
+ atom_iconthemes = gdk_atom_intern_static_string ("_GTK_LOAD_ICONTHEMES");
++ atom_temporaries = gdk_atom_intern_static_string ("_GTK_DELETE_TEMPORARIES");
+ }
+
+ if (event->message_type == atom_rcfiles)
+ {
+- send_client_message_to_embedded_windows (widget, atom_rcfiles);
+- gtk_rc_reparse_all_for_settings (gtk_widget_get_settings (widget), FALSE);
++ /* The theme may have been changed and a resource file may happen to have
++ the exact same modification time, so we pass TRUE for force_reload.
++ See NB#151715 for a discussion. */
++ gtk_rc_reparse_all_for_settings (gtk_widget_get_settings (widget), TRUE);
+ }
+
+ if (event->message_type == atom_iconthemes)
+ {
+ send_client_message_to_embedded_windows (widget, atom_iconthemes);
+- _gtk_icon_theme_check_reload (gtk_widget_get_display (widget));
++ _gtk_icon_theme_check_reload (gtk_widget_get_display (widget));
++ }
++
++ if (event->message_type == atom_temporaries)
++ {
++ send_client_message_to_embedded_windows (widget, atom_temporaries);
++ if (gtk_widget_get_mapped (widget)
++ && gtk_window_get_is_temporary (GTK_WINDOW (widget)))
++ delete_if_temporary (widget, event);
+ }
+
+ return FALSE;
+@@ -8612,5 +8721,72 @@
+
+ #endif
+
++GtkWidget *gtk_window_get_prev_focus_widget( GtkWindow *window )
++{
++ return NULL;
++
++}
++
++void gtk_window_set_prev_focus_widget( GtkWindow *window, GtkWidget *widget )
++{
++}
++
++#if defined(GDK_WINDOWING_X11)
++gboolean
++_gtk_window_is_on_client_data (GtkWindow *window, GdkEventClient *event)
++{
++ XID xid = GDK_WINDOW_XID (GTK_WIDGET (window)->window);
++ return memcmp (&xid, (XID*)(&event->data.b[12]), sizeof(XID)) == 0;
++}
++
++/**
++ * gtk_window_close_other_temporaries:
++ *
++ * Sends a _GTK_DELETE_TEMPORARIES ClientEvent to all other toplevel windows
++ *
++ * Since: maemo 4.0
++ * Stability: Unstable
++ */
++void
++gtk_window_close_other_temporaries (GtkWindow *window)
++{
++ GList *toplevels;
++ GdkEventClient client;
++ XID xid = GDK_WINDOW_XID (GTK_WIDGET (window)->window);
++
++ memset(&client, 0, sizeof(client));
++ client.message_type = gdk_atom_intern ("_GTK_DELETE_TEMPORARIES", FALSE);
++ client.data_format = 8;
++ memcpy (((XID*)(&client.data.b[12])),&xid, sizeof(XID));
++ gdk_event_send_clientmessage_toall ((GdkEvent*)&client);
++
++ /* The client messages are sent out of process and won't be
++ * delivered before this function returns. If the caller is
++ * a modal dialog and thus grabs, the delete events for this
++ * process could get ignored.
++ */
++ toplevels = gtk_window_list_toplevels ();
++ g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
++
++ while (toplevels)
++ {
++ GtkWindow *toplevel = toplevels->data;
++ toplevels = g_list_delete_link (toplevels, toplevels);
++
++ /* We check for MAPPED here instead of comparing to the
++ * window argument, because there can be unmapped toplevels
++ * that are != window.
++ */
++ if (gtk_widget_get_mapped (GTK_WIDGET (toplevel))
++ && gtk_window_get_is_temporary (toplevel))
++ delete_if_temporary (GTK_WIDGET (toplevel), &client);
++
++ g_object_unref (toplevel);
++ }
++
++ g_list_free (toplevels);
++}
++#endif /* GDK_WINDOWING_X11 */
++
+ #define __GTK_WINDOW_C__
+ #include "gtkaliasdef.c"
+--- a/gtk/gtkwindow.h
++++ b/gtk/gtkwindow.h
+@@ -279,6 +279,13 @@
+ gboolean setting);
+ gboolean gtk_window_get_deletable (GtkWindow *window);
+
++void gtk_window_set_is_temporary (GtkWindow *window,
++ gboolean setting);
++gboolean gtk_window_get_is_temporary (GtkWindow *window);
++gboolean _gtk_window_is_on_client_data (GtkWindow *window,
++ GdkEventClient *event);
++void gtk_window_close_other_temporaries (GtkWindow *window);
++
+ void gtk_window_set_icon_list (GtkWindow *window,
+ GList *list);
+ GList* gtk_window_get_icon_list (GtkWindow *window);
diff --git a/xid-collision-debug.patch b/xid-collision-debug.patch
new file mode 100644
index 000000000000..187ce879589d
--- /dev/null
+++ b/xid-collision-debug.patch
@@ -0,0 +1,20 @@
+ gdk/x11/gdkxid.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git c/gdk/x11/gdkxid.c i/gdk/x11/gdkxid.c
+index 1005f9e40c..71578f8fcf 100644
+--- c/gdk/x11/gdkxid.c
++++ i/gdk/x11/gdkxid.c
+@@ -56,10 +56,10 @@ _gdk_xid_table_insert (GdkDisplay *display,
+ if (!display_x11->xid_ht)
+ display_x11->xid_ht = g_hash_table_new ((GHashFunc) gdk_xid_hash,
+ (GEqualFunc) gdk_xid_equal);
+-
++/*
+ if (g_hash_table_lookup (display_x11->xid_ht, xid))
+ g_warning ("XID collision, trouble ahead");
+-
++*/
+ g_hash_table_insert (display_x11->xid_ht, xid, data);
+ }
+