From d08c3edd159aed19a63ac08323137db0a27a3662 Mon Sep 17 00:00:00 2001
From: c4pp4
Date: Tue, 21 Apr 2026 01:29:58 +0200
Subject: [PATCH 1/1] Add Unity7 support

Add *WithTimestamp dbus methods for file operations.
Operations that might trigger a dialog, that should be presented with event time.
Bug-Ubuntu: https://launchpad.net/bugs/1445595
Bug: https://bugzilla.gnome.org/show_bug.cgi?id=758833
Based on Nautilus 20_add_timestamp_to_operations.patch.

Add Unity Launcher support
List bookmarks in the context menu and display a bar on the icon during
copies.
Based on Nautilus 12_unity_launcher_support.patch (Xenial).

Add a new dbus property
"org.freedesktop.FileManager1" dbus interface where it stores the lists of
opened locations referenced by their parent nemo window XID.
Bug-Ubuntu: https://bugs.launchpad.net/unity/+bug/887449
Based on Nautilus 19_unity_open_location_xid.patch.

Signed-off-by: c4pp4
---
 config.h.meson.in                      |   2 +
 data/dbus-interfaces.xml               |   8 +
 data/freedesktop-dbus-interfaces.xml   |   1 +
 libnemo-private/nemo-dbus-manager.c    |  91 ++++++---
 libnemo-private/nemo-dbus-manager.h    |   4 +
 libnemo-private/nemo-file-operations.c |  31 ++++
 libnemo-private/nemo-file-operations.h |   9 +
 libnemo-private/nemo-progress-info.c   |  46 +++++
 libnemo-private/nemo-progress-info.h   |   4 +
 meson.build                            |   9 +
 meson_options.txt                      |   2 +
 po/POTFILES.in                         |   1 +
 src/meson.build                        |   8 +
 src/nemo-application.c                 |  39 ++++
 src/nemo-desktop-application.c         |   5 -
 src/nemo-freedesktop-dbus.c            |  21 +++
 src/nemo-freedesktop-dbus.h            |   1 +
 src/nemo-main-application.c            | 198 +++++++++++++++++++-
 src/nemo-progress-ui-handler.c         | 244 +++++++++++++++++++++++++
 src/nemo-window-manage-views.c         |   6 +-
 src/nemo-window-pane.c                 |  11 +-
 src/unity-bookmarks-handler.c          | 158 ++++++++++++++++
 src/unity-bookmarks-handler.h          |  32 ++++
 src/unity-quicklist-handler.c          | 164 +++++++++++++++++
 src/unity-quicklist-handler.h          |  76 ++++++++
 25 files changed, 1134 insertions(+), 37 deletions(-)
 create mode 100644 src/unity-bookmarks-handler.c
 create mode 100644 src/unity-bookmarks-handler.h
 create mode 100644 src/unity-quicklist-handler.c
 create mode 100644 src/unity-quicklist-handler.h

diff --git a/config.h.meson.in b/config.h.meson.in
index 8b49bbd..f7f7a13 100644
--- a/config.h.meson.in
+++ b/config.h.meson.in
@@ -13,6 +13,8 @@
 #mesondefine ENABLE_EMPTY_VIEW
 // Define to enable xmp support
 #mesondefine HAVE_EXEMPI
+// Define to add Unity Launcher support
+#mesondefine HAVE_UNITY
 // Define to enable EXIF support
 #mesondefine HAVE_EXIF
 // Define if libselinux is available
diff --git a/data/dbus-interfaces.xml b/data/dbus-interfaces.xml
index bd8388f..a4ed3e1 100644
--- a/data/dbus-interfaces.xml
+++ b/data/dbus-interfaces.xml
@@ -29,12 +29,20 @@
       <arg type='as' name='SourceFilesURIList' direction='in'/>
       <arg type='s' name='DestinationDirectoryURI' direction='in'/>
     </method>
+    <method name='CopyURIsWithTimestamp'>
+      <arg type='as' name='SourceFilesURIList' direction='in'/>
+      <arg type='s' name='DestinationDirectoryURI' direction='in'/>
+      <arg type='u' name='EventTimestamp' direction='in'/>
+    </method>
     <method name='MoveURIs'>
       <arg type='as' name='SourceFilesURIList' direction='in'/>
       <arg type='s' name='DestinationDirectoryURI' direction='in'/>
     </method>
     <method name='EmptyTrash'>
     </method>"
+    <method name='EmptyTrashWithTimestamp'>
+      <arg type='u' name='EventTimestamp' direction='in'/>
+    </method>"
     <method name='CopyFile'>
       <arg type='s' name='SourceFileURI' direction='in'/>
       <arg type='s' name='SourceDisplayName' direction='in'/>
diff --git a/data/freedesktop-dbus-interfaces.xml b/data/freedesktop-dbus-interfaces.xml
index 3ebd049..4a51454 100644
--- a/data/freedesktop-dbus-interfaces.xml
+++ b/data/freedesktop-dbus-interfaces.xml
@@ -33,5 +33,6 @@
       <arg type='s' name='StartupId' direction='in'/>
     </method>
     <property name="OpenLocations" type="as" access="read"/>
+    <property name="XUbuntuOpenLocationsXids" type="a{uas}" access="read"/>
   </interface>
 </node>
diff --git a/libnemo-private/nemo-dbus-manager.c b/libnemo-private/nemo-dbus-manager.c
index 5c3a389..e911548 100644
--- a/libnemo-private/nemo-dbus-manager.c
+++ b/libnemo-private/nemo-dbus-manager.c
@@ -36,7 +36,6 @@
 struct _NemoDBusManager {
   GObject parent;
 
-  GDBusObjectManagerServer *object_manager;
   NemoDBusFileOperations *file_operations;
 };
 
@@ -52,16 +51,12 @@ nemo_dbus_manager_dispose (GObject *object)
   NemoDBusManager *self = (NemoDBusManager *) object;
 
   if (self->file_operations) {
-    g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self->file_operations));
+    if (g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (self->file_operations)))
+      g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self->file_operations));
     g_object_unref (self->file_operations);
     self->file_operations = NULL;
   }
 
-  if (self->object_manager) {
-    g_object_unref (self->object_manager);
-    self->object_manager = NULL;
-  }
-
   G_OBJECT_CLASS (nemo_dbus_manager_parent_class)->dispose (object);
 }
 
@@ -95,11 +90,10 @@ handle_copy_file (NemoDBusFileOperations *object,
   return TRUE; /* invocation was handled */
 }
 
-static gboolean
-handle_copy_uris (NemoDBusFileOperations *object,
-		  GDBusMethodInvocation *invocation,
-		  const gchar **sources,
-		  const gchar *destination)
+static void
+copy_uris (const gchar **sources,
+           const gchar *destination,
+           guint32 timestamp)
 {
   GList *source_files = NULL;
   GFile *dest_dir;
@@ -111,17 +105,37 @@ handle_copy_uris (NemoDBusFileOperations *object,
     source_files = g_list_prepend (source_files,
                                    g_file_new_for_uri (sources[idx]));
 
-  nemo_file_operations_copy (source_files, NULL,
-                                 dest_dir,
-                                 NULL, NULL, NULL);
+  nemo_file_operations_copy_with_time (source_files, NULL,
+                                       dest_dir, NULL,
+                                       timestamp, NULL, NULL);
 
   g_list_free_full (source_files, g_object_unref);
   g_object_unref (dest_dir);
+}
 
+static gboolean
+handle_copy_uris (NemoDBusFileOperations *object,
+		  GDBusMethodInvocation *invocation,
+		  const gchar **sources,
+		  const gchar *destination)
+{
+  copy_uris (sources, destination, GDK_CURRENT_TIME);
   nemo_dbus_file_operations_complete_copy_uris (object, invocation);
   return TRUE; /* invocation was handled */
 }
 
+static gboolean
+handle_copy_uris_with_timestamp (NemoDBusFileOperations *object,
+                                 GDBusMethodInvocation *invocation,
+                                 const gchar **sources,
+                                 const gchar *destination,
+                                 guint32 timestamp)
+{
+  copy_uris (sources, destination, timestamp);
+  nemo_dbus_file_operations_complete_copy_uris_with_timestamp (object, invocation);
+  return TRUE;
+}
+
 static gboolean
 handle_move_uris (NemoDBusFileOperations *object,
 		  GDBusMethodInvocation *invocation,
@@ -159,14 +173,20 @@ handle_empty_trash (NemoDBusFileOperations *object,
   return TRUE; /* invocation was handled */
 }
 
-static void
-nemo_dbus_manager_init (NemoDBusManager *self)
+static gboolean
+handle_empty_trash_with_timestamp (NemoDBusFileOperations *object,
+				   GDBusMethodInvocation *invocation,
+				   guint32 timestamp)
 {
-  GDBusConnection *connection;
+  nemo_file_operations_empty_trash_with_time (NULL, timestamp);
 
-  connection = g_application_get_dbus_connection (g_application_get_default ());
+  nemo_dbus_file_operations_complete_empty_trash_with_timestamp (object, invocation);
+  return TRUE; /* invocation was handled */
+}
 
-  self->object_manager = g_dbus_object_manager_server_new ("/org/Nemo");
+static void
+nemo_dbus_manager_init (NemoDBusManager *self)
+{
   self->file_operations = nemo_dbus_file_operations_skeleton_new ();
 
   g_signal_connect (self->file_operations,
@@ -185,11 +205,14 @@ nemo_dbus_manager_init (NemoDBusManager *self)
 		    "handle-empty-trash",
 		    G_CALLBACK (handle_empty_trash),
 		    self);
-
-  g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self->file_operations), connection,
-				    "/org/Nemo", NULL);
-
-  g_dbus_object_manager_server_set_connection (self->object_manager, connection);
+  g_signal_connect (self->file_operations,
+		    "handle-copy-uris-with-timestamp",
+		    G_CALLBACK (handle_copy_uris_with_timestamp),
+		    self);
+  g_signal_connect (self->file_operations,
+		    "handle-empty-trash-with-timestamp",
+		    G_CALLBACK (handle_empty_trash_with_timestamp),
+		    self);
 }
 
 static void
@@ -206,3 +229,21 @@ nemo_dbus_manager_new (void)
   return g_object_new (nemo_dbus_manager_get_type (),
                        NULL);
 }
+
+gboolean
+nemo_dbus_manager_register (NemoDBusManager *self,
+                            GDBusConnection *connection,
+                            GError         **error)
+{
+  return g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self->file_operations),
+					   connection,
+					   "/org/Nemo",
+					   error);
+}
+
+void
+nemo_dbus_manager_unregister (NemoDBusManager *self)
+{
+  if (g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (self->file_operations)))
+    g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self->file_operations));
+}
diff --git a/libnemo-private/nemo-dbus-manager.h b/libnemo-private/nemo-dbus-manager.h
index 8a5617e..64f1246 100644
--- a/libnemo-private/nemo-dbus-manager.h
+++ b/libnemo-private/nemo-dbus-manager.h
@@ -32,5 +32,9 @@ typedef struct _NemoDBusManagerClass NemoDBusManagerClass;
 
 GType nemo_dbus_manager_get_type (void);
 NemoDBusManager * nemo_dbus_manager_new (void);
+gboolean nemo_dbus_manager_register (NemoDBusManager *self,
+                                     GDBusConnection *connection,
+                                     GError         **error);
+void nemo_dbus_manager_unregister (NemoDBusManager *self);
 
 #endif /* __NEMO_DBUS_MANAGER_H__ */
diff --git a/libnemo-private/nemo-file-operations.c b/libnemo-private/nemo-file-operations.c
index 051c47d..0551261 100644
--- a/libnemo-private/nemo-file-operations.c
+++ b/libnemo-private/nemo-file-operations.c
@@ -92,6 +92,7 @@ typedef struct {
 	GtkWindow *parent_window;
     int monitor_num;
 	int inhibit_cookie;
+	guint32 action_timestamp;
 	NemoProgressInfo *progress;
 	GCancellable *cancellable;
 	GHashTable *skip_files;
@@ -1275,6 +1276,7 @@ typedef struct {
 	const char *details_text;
 	const char **button_titles;
 	gboolean show_all;
+	guint32 timestamp;
 
 	int result;
 } RunSimpleDialogData;
@@ -1324,6 +1326,7 @@ do_run_simple_dialog (gpointer _data)
 	}
 
 	/* Run it. */
+        gtk_window_present_with_time (GTK_WINDOW (dialog), data->timestamp);
         result = gtk_dialog_run (GTK_DIALOG (dialog));
 
 	while ((result == GTK_RESPONSE_NONE || result == GTK_RESPONSE_DELETE_EVENT) && data->ignore_close_box) {
@@ -1365,6 +1368,7 @@ run_simple_dialog_va (CommonJob *job,
 	data->secondary_text = secondary_text;
 	data->details_text = details_text;
 	data->show_all = show_all;
+	data->timestamp = job->action_timestamp;
 
 	ptr_array = g_ptr_array_new ();
 	while ((button_title = va_arg (varargs, const char *)) != NULL) {
@@ -5039,6 +5043,24 @@ nemo_file_operations_copy (GList *files,
 			       GtkWindow *parent_window,
 			       NemoCopyCallback  done_callback,
 			       gpointer done_callback_data)
+{
+    nemo_file_operations_copy_with_time (files,
+                                         relative_item_points,
+                                         target_dir,
+                                         parent_window,
+                                         GDK_CURRENT_TIME,
+                                         done_callback,
+                                         done_callback_data);
+}
+
+void
+nemo_file_operations_copy_with_time (GList            *files,
+                                     GArray           *relative_item_points,
+                                     GFile            *target_dir,
+                                     GtkWindow        *parent_window,
+                                     guint32           timestamp,
+                                     NemoCopyCallback  done_callback,
+                                     gpointer          done_callback_data)
 {
 	CopyMoveJob *job;
 
@@ -5048,6 +5070,7 @@ nemo_file_operations_copy (GList *files,
 	job->done_callback_data = done_callback_data;
 	job->files = eel_g_object_list_copy (files);
 	job->destination = g_object_ref (target_dir);
+	((CommonJob *)job)->action_timestamp = timestamp;
 	if (relative_item_points != NULL &&
 	    relative_item_points->len > 0) {
 		job->icon_positions =
@@ -6852,6 +6875,13 @@ empty_trash_job (GIOSchedulerJob *io_job,
 
 void
 nemo_file_operations_empty_trash (GtkWidget *parent_view)
+{
+	nemo_file_operations_empty_trash_with_time (parent_view, GDK_CURRENT_TIME);
+}
+
+void
+nemo_file_operations_empty_trash_with_time (GtkWidget *parent_view,
+					    guint32    timestamp)
 {
 	EmptyTrashJob *job;
 	GtkWindow *parent_window;
@@ -6865,6 +6895,7 @@ nemo_file_operations_empty_trash (GtkWidget *parent_view)
 	job->trash_dirs = g_list_prepend (job->trash_dirs,
 					  g_file_new_for_uri ("trash:"));
 	job->should_confirm = TRUE;
+	((CommonJob *)job)->action_timestamp = timestamp;
 
 	inhibit_power_manager ((CommonJob *)job, _("Emptying Trash"));
 
diff --git a/libnemo-private/nemo-file-operations.h b/libnemo-private/nemo-file-operations.h
index 04924bd..64aef63 100644
--- a/libnemo-private/nemo-file-operations.h
+++ b/libnemo-private/nemo-file-operations.h
@@ -63,6 +63,8 @@ void nemo_file_operations_copy_file (GFile *source_file,
 					 NemoCopyCallback done_callback,
 					 gpointer done_callback_data);
 void nemo_file_operations_empty_trash (GtkWidget                 *parent_view);
+void nemo_file_operations_empty_trash_with_time (GtkWidget *parent_view,
+						 guint32    timestamp);
 void nemo_file_operations_new_folder  (GtkWidget                 *parent_view,
 					   GdkPoint                  *target_point,
 					   const char                *parent_dir_uri,
@@ -125,6 +127,13 @@ void nemo_file_operations_copy      (GList                *files,
 					 GtkWindow            *parent_window,
 					 NemoCopyCallback  done_callback,
 					 gpointer              done_callback_data);
+void nemo_file_operations_copy_with_time (GList                *files,
+                                          GArray               *relative_item_points,
+                                          GFile                *target_dir,
+                                          GtkWindow            *parent_window,
+                                          guint32               timestamp,
+                                          NemoCopyCallback      done_callback,
+                                          gpointer              done_callback_data);
 void nemo_file_operations_move      (GList                *files,
 					 GArray               *relative_item_points,
 					 GFile                *target_dir,
diff --git a/libnemo-private/nemo-progress-info.c b/libnemo-private/nemo-progress-info.c
index f0e97e7..d105080 100644
--- a/libnemo-private/nemo-progress-info.c
+++ b/libnemo-private/nemo-progress-info.c
@@ -53,6 +53,10 @@ struct _NemoProgressInfo
 	char *details;
     char *initial_details;
 	double progress;
+#ifdef HAVE_UNITY
+	double current;
+	double total;
+#endif
 	gboolean activity_mode;
 	gboolean started;
 	gboolean finished;
@@ -264,6 +268,44 @@ nemo_progress_info_get_progress (NemoProgressInfo *info)
 	return res;
 }
 
+#ifdef HAVE_UNITY
+double
+nemo_progress_info_get_current (NemoProgressInfo *info)
+{
+	double current;
+
+	g_mutex_lock (&info->info_lock);
+
+	if (info->activity_mode) {
+		current = 0.0;
+	} else {
+		current = info->current;
+	}
+
+	g_mutex_unlock (&info->info_lock);
+
+	return current;
+}
+
+double
+nemo_progress_info_get_total (NemoProgressInfo *info)
+{
+	double total;
+
+	g_mutex_lock (&info->info_lock);
+
+	if (info->activity_mode) {
+		total = -1.0;
+	} else {
+		total = info->total;
+	}
+
+	g_mutex_unlock (&info->info_lock);
+
+	return total;
+}
+#endif
+
 void
 nemo_progress_info_cancel (NemoProgressInfo *info)
 {
@@ -640,6 +682,10 @@ nemo_progress_info_set_progress (NemoProgressInfo *info,
 	    ) {
 		info->activity_mode = FALSE;
 		info->progress = current_percent;
+#ifdef HAVE_UNITY
+		info->current = current;
+		info->total = total;
+#endif
 		info->progress_at_idle = TRUE;
 		queue_idle (info, FALSE);
 	}
diff --git a/libnemo-private/nemo-progress-info.h b/libnemo-private/nemo-progress-info.h
index 235e58c..45c922e 100644
--- a/libnemo-private/nemo-progress-info.h
+++ b/libnemo-private/nemo-progress-info.h
@@ -63,6 +63,10 @@ void          nemo_progress_info_cancel          (NemoProgressInfo *info);
 gboolean      nemo_progress_info_get_is_started  (NemoProgressInfo *info);
 gboolean      nemo_progress_info_get_is_finished (NemoProgressInfo *info);
 gboolean      nemo_progress_info_get_is_paused   (NemoProgressInfo *info);
+#ifdef HAVE_UNITY
+double        nemo_progress_info_get_current     (NemoProgressInfo *info);
+double        nemo_progress_info_get_total       (NemoProgressInfo *info);
+#endif
 
 void          nemo_progress_info_queue           (NemoProgressInfo *info);
 void          nemo_progress_info_start           (NemoProgressInfo *info);
diff --git a/meson.build b/meson.build
index 5eee1ed..34feda1 100644
--- a/meson.build
+++ b/meson.build
@@ -143,6 +143,14 @@ else
   message('................using pango @0@ instead'.format(new_pango.version()))
 endif
 
+unity_enabled = get_option('unity-launcher')
+if unity_enabled
+  unity = dependency('unity',                       version: '>=4.0.0')
+  dbusmenu = dependency('dbusmenu-glib-0.4',        version: '>=0.4.90')
+endif
+conf.set('HAVE_UNITY', unity_enabled)
+
+
 enableEmptyView = get_option('empty_view')
 conf.set10('ENABLE_EMPTY_VIEW', enableEmptyView)
 
@@ -197,6 +205,7 @@ message('\n'.join(['',
 '    prefix:                 @0@'.format(prefix),
 '    source code location:   @0@'.format(meson.project_source_root()),
 '    compiler:               @0@'.format(cc.get_id()),
+'    Unity support:          @0@'.format(unity_enabled),
 '    libexif support:        @0@'.format(libexif_enabled),
 '    exempi  support:        @0@'.format(exempi_enabled),
 '    Tracker support:        @0@'.format(tracker_enabled),
diff --git a/meson_options.txt b/meson_options.txt
index 68814d6..ba541de 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -4,6 +4,8 @@ option('exif', type : 'boolean', value : true,
        description: 'EXIF parsing support (requires libexif)')
 option('xmp', type : 'boolean', value : true,
        description: 'XMP support (requires Exempi)')
+option ('unity-launcher', type : 'boolean', value : true,
+       description: 'Add Unity Launcher support')
 option('gtk_doc', type : 'boolean', value : false,
        description: 'Generate API reference (requires GTK-Doc)')
 option('selinux', type : 'boolean', value : false,
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 2f1eec6..0e83dab 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -107,3 +107,4 @@ src/nemo-window-pane.c
 src/nemo-window-private.h
 src/nemo-window-slot.c
 src/nemo-x-content-bar.c
+src/unity-quicklist-handler.h
diff --git a/src/meson.build b/src/meson.build
index 6f6cd55..12e9290 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -113,6 +113,14 @@ if libexif_enabled
   nemo_deps += libexif
 endif
 
+if unity_enabled
+    nemo_deps += [ unity, dbusmenu ]
+    nemoCommon_sources += [
+        'unity-quicklist-handler.c',
+        'unity-bookmarks-handler.c',
+    ]
+endif
+
 nemo = executable('nemo',
   nemoCommon_sources + nemoWindow_sources,
   include_directories: [ rootInclude ],
diff --git a/src/nemo-application.c b/src/nemo-application.c
index 060cb76..ddce997 100644
--- a/src/nemo-application.c
+++ b/src/nemo-application.c
@@ -86,6 +86,7 @@ G_DEFINE_TYPE (NemoApplication, nemo_application, GTK_TYPE_APPLICATION);
 
 struct _NemoApplicationPriv {
 	NemoProgressUIHandler *progress_handler;
+	NemoDBusManager *dbus_manager;
 
     gboolean cache_problem;
     gboolean ignore_cache_problem;
@@ -593,6 +594,42 @@ nemo_application_startup (GApplication *app)
     }
 }
 
+static gboolean
+nemo_application_dbus_register (GApplication        *app,
+                                GDBusConnection     *connection,
+                                const gchar         *object_path,
+                                GError	           **error)
+{
+	NemoApplication *self = NEMO_APPLICATION (app);
+
+	if (!G_APPLICATION_CLASS (nemo_application_parent_class)->dbus_register (app, connection, object_path, error)) {
+		return FALSE;
+	}
+
+	self->priv->dbus_manager = nemo_dbus_manager_new ();
+	if (!nemo_dbus_manager_register (self->priv->dbus_manager, connection, error)) {
+		g_clear_object (&self->priv->dbus_manager);
+        return FALSE;
+	}
+
+	return TRUE;
+}
+
+static void
+nemo_application_dbus_unregister (GApplication      *app,
+                                  GDBusConnection   *connection,
+                                  const gchar   	*object_path)
+{
+	NemoApplication *self = NEMO_APPLICATION (app);
+
+	if (self->priv->dbus_manager) {
+		nemo_dbus_manager_unregister (self->priv->dbus_manager);
+		g_clear_object (&self->priv->dbus_manager);
+	}
+
+	G_APPLICATION_CLASS (nemo_application_parent_class)->dbus_unregister (app, connection, object_path);
+}
+
 static void
 nemo_application_quit_mainloop (GApplication *app)
 {
@@ -636,6 +673,8 @@ nemo_application_class_init (NemoApplicationClass *class)
 
     application_class = G_APPLICATION_CLASS (class);
     application_class->startup = nemo_application_startup;
+    application_class->dbus_register = nemo_application_dbus_register;
+    application_class->dbus_unregister = nemo_application_dbus_unregister;
     application_class->quit_mainloop = nemo_application_quit_mainloop;
 
     gtkapp_class = GTK_APPLICATION_CLASS (class);
diff --git a/src/nemo-desktop-application.c b/src/nemo-desktop-application.c
index 59a3f1e..0e644eb 100644
--- a/src/nemo-desktop-application.c
+++ b/src/nemo-desktop-application.c
@@ -69,7 +69,6 @@ G_DEFINE_TYPE (NemoDesktopApplication, nemo_desktop_application, NEMO_TYPE_APPLI
 
 struct _NemoDesktopApplicationPriv {
     NemoDesktopManager *desktop_manager;
-    NemoFreedesktopDBus *fdb_manager;
 };
 
 static void
@@ -85,8 +84,6 @@ nemo_desktop_application_finalize (GObject *object)
 {
     NemoDesktopApplication *app = NEMO_DESKTOP_APPLICATION (object);
 
-    g_clear_object (&app->priv->fdb_manager);
-
     G_OBJECT_CLASS (nemo_desktop_application_parent_class)->finalize (object);
 }
 
@@ -351,8 +348,6 @@ nemo_desktop_application_continue_startup (NemoApplication *app)
     nemo_application_check_required_directory (app, nemo_get_desktop_directory ());
     nemo_application_check_required_directory (app, nemo_get_user_directory ());
 
-    NEMO_DESKTOP_APPLICATION (app)->priv->fdb_manager = nemo_freedesktop_dbus_new ();
-
 	/* register views */
 	nemo_desktop_icon_view_register ();
     nemo_desktop_icon_grid_view_register ();
diff --git a/src/nemo-freedesktop-dbus.c b/src/nemo-freedesktop-dbus.c
index 0985c18..b89d278 100644
--- a/src/nemo-freedesktop-dbus.c
+++ b/src/nemo-freedesktop-dbus.c
@@ -226,7 +226,28 @@ nemo_freedesktop_dbus_set_open_locations (NemoFreedesktopDBus *fdb,
 {
 	g_return_if_fail (NEMO_IS_FREEDESKTOP_DBUS (fdb));
 
+	if (fdb->skeleton) {
 	nemo_freedesktop_file_manager1_set_open_locations (fdb->skeleton, locations);
+	}
+}
+
+void
+nemo_freedesktop_dbus_set_open_locations_xids (NemoFreedesktopDBus *fdb,
+					       GVariant *locations)
+{
+	/* Sink the floating reference immediately so we own it in all code paths. */
+	g_variant_ref_sink (locations);
+
+	if (!NEMO_IS_FREEDESKTOP_DBUS (fdb)) {
+		g_variant_unref (locations);
+		g_return_if_reached ();
+	}
+
+	if (fdb->skeleton) {
+		nemo_freedesktop_file_manager1_set_xubuntu_open_locations_xids (fdb->skeleton, locations);
+	}
+
+	g_variant_unref (locations);
 }
 
 /* Tries to own the org.freedesktop.FileManager1 service name */
diff --git a/src/nemo-freedesktop-dbus.h b/src/nemo-freedesktop-dbus.h
index 4f3ae84..ae825b8 100644
--- a/src/nemo-freedesktop-dbus.h
+++ b/src/nemo-freedesktop-dbus.h
@@ -44,5 +44,6 @@ GType nemo_freedesktop_dbus_get_type (void);
 NemoFreedesktopDBus * nemo_freedesktop_dbus_new (void);
 
 void nemo_freedesktop_dbus_set_open_locations (NemoFreedesktopDBus *fdb, const gchar **locations);
+void nemo_freedesktop_dbus_set_open_locations_xids (NemoFreedesktopDBus *fdb, GVariant *locations);
 
 #endif /* __NEMO_FREEDESKTOP_DBUS_H__ */
diff --git a/src/nemo-main-application.c b/src/nemo-main-application.c
index b0f4258..507ce81 100644
--- a/src/nemo-main-application.c
+++ b/src/nemo-main-application.c
@@ -78,6 +78,10 @@
 
 #include <libcinnamon-desktop/gnome-desktop-thumbnail.h>
 
+#ifdef HAVE_UNITY
+#include "unity-bookmarks-handler.h"
+#endif
+
 /* Keep window from shrinking down ridiculously small; numbers are somewhat arbitrary */
 #define APPLICATION_WINDOW_MIN_WIDTH	300
 #define APPLICATION_WINDOW_MIN_HEIGHT	100
@@ -105,7 +109,6 @@ G_DEFINE_TYPE (NemoMainApplication, nemo_main_application, NEMO_TYPE_APPLICATION
 struct _NemoMainApplicationPriv {
 	GVolumeMonitor *volume_monitor;
 
-	NemoDBusManager *dbus_manager;
 	NemoFreedesktopDBus *fdb_manager;
 
 	gchar *geometry;
@@ -581,9 +584,12 @@ nemo_main_application_finalize (GObject *object)
     g_clear_object (&application->priv->volume_monitor);
     g_free (application->priv->geometry);
 
-    g_clear_object (&application->priv->dbus_manager);
     g_clear_object (&application->priv->fdb_manager);
 
+#ifdef HAVE_UNITY
+    unity_bookmarks_handler_shutdown ();
+#endif
+
     free_search_helpers ();
 
     G_OBJECT_CLASS (nemo_main_application_parent_class)->finalize (object);
@@ -906,7 +912,6 @@ nemo_main_application_continue_startup (NemoApplication *app)
 	NemoMainApplication *self = NEMO_MAIN_APPLICATION (app);
 
 	/* create DBus manager */
-	self->priv->dbus_manager = nemo_dbus_manager_new ();
 	self->priv->fdb_manager = nemo_freedesktop_dbus_new ();
 
     /* Check the user's ~/.config/nemo directory and post warnings
@@ -933,6 +938,10 @@ nemo_main_application_continue_startup (NemoApplication *app)
 
     g_signal_connect_swapped (nemo_window_state, "changed::" NEMO_WINDOW_STATE_START_WITH_MENU_BAR,
                               G_CALLBACK (menu_state_changed_callback), self);
+
+#ifdef HAVE_UNITY
+    unity_bookmarks_handler_initialize ();
+#endif
 }
 
 static void
@@ -948,11 +957,190 @@ nemo_main_application_quit_mainloop (GApplication *app)
     G_APPLICATION_CLASS (nemo_main_application_parent_class)->quit_mainloop (app);
 }
 
+static void
+update_dbus_opened_locations (NemoApplication *app)
+{
+	gint i;
+	GList *l, *lp, *sl;
+	GList *locations = NULL;
+	gsize locations_size = 0;
+	gchar **locations_array;
+	NemoWindow *win;
+	GFile *location;
+
+	GVariantBuilder b;
+	GVariantBuilder wb;
+
+	g_return_if_fail (NEMO_IS_APPLICATION (app));
+
+	NemoMainApplication *self = NEMO_MAIN_APPLICATION (app);
+
+	if (!self->priv->fdb_manager) {
+		return;
+	}
+
+	g_variant_builder_init (&b, G_VARIANT_TYPE ("a{uas}"));
+
+	for (l = gtk_application_get_windows (GTK_APPLICATION (self)); l; l = l->next) {
+		NemoWindowSlot *active_slot;
+
+		if (!NEMO_IS_WINDOW (l->data))
+			continue;
+
+		win = NEMO_WINDOW (l->data);
+
+		g_variant_builder_init (&wb, G_VARIANT_TYPE ("as"));
+
+		active_slot = nemo_window_get_active_slot (win);
+
+		if (active_slot != NULL) {
+			location = nemo_window_slot_get_location (active_slot);
+
+			if (location != NULL) {
+				gchar *active_uri = g_file_get_uri (location);
+				g_variant_builder_add (&wb, "s", active_uri);
+				g_free (active_uri);
+				g_object_unref (location);
+			}
+		}
+
+		for (lp = nemo_window_get_panes (win); lp; lp = lp->next) {
+			NemoWindowPane *pane;
+
+			pane = (NemoWindowPane*) lp->data;
+
+			for (sl = pane->slots; sl; sl = sl->next) {
+				NemoWindowSlot *slot = NEMO_WINDOW_SLOT (sl->data);
+				location = nemo_window_slot_get_location (slot);
+
+				if (location != NULL) {
+					gchar *uri = g_file_get_uri (location);
+					g_object_unref (location);
+
+					if (slot != active_slot) {
+						g_variant_builder_add (&wb, "s", uri);
+					}
+
+					GList *found = g_list_find_custom (locations, uri, (GCompareFunc) g_strcmp0);
+
+					if (!found) {
+						locations = g_list_prepend (locations, uri);
+						++locations_size;
+					} else {
+						g_free (uri);
+					}
+				}
+			}
+		}
+
+		if (gtk_widget_get_realized (GTK_WIDGET (win))) {
+			GdkWindow *gdk_win;
+			Window xid;
+
+			gdk_win = gtk_widget_get_window (GTK_WIDGET (win));
+			xid = gdk_x11_window_get_xid (gdk_win);
+			g_variant_builder_add (&b, "{uas}", xid, &wb);
+		} else {
+			g_variant_builder_clear (&wb);
+		}
+	}
+
+	locations_array = g_new (gchar*, locations_size + 1);
+
+	for (i = 0, l = locations; l; l = l->next, ++i) {
+		locations_array[i] = l->data;
+	}
+
+	locations_array[locations_size] = NULL;
+
+	nemo_freedesktop_dbus_set_open_locations (self->priv->fdb_manager,
+						  (const gchar**) locations_array);
+	nemo_freedesktop_dbus_set_open_locations_xids (self->priv->fdb_manager,
+						       g_variant_builder_end (&b));
+
+	g_free (locations_array);
+	g_list_free_full (locations, g_free);
+}
+
+static void
+on_slot_location_changed (NemoWindowSlot  *slot,
+			  const char      *from,
+ 			  const char      *to,
+			  NemoApplication *application)
+{
+	update_dbus_opened_locations (application);
+}
+
+static void
+on_slot_active_changed (NemoWindowSlot  *slot,
+			NemoApplication *application)
+{
+	update_dbus_opened_locations (application);
+}
+
+static void
+on_slot_added (NemoWindow      *window,
+	       NemoWindowSlot  *slot,
+	       NemoApplication *application)
+{
+	if (nemo_window_slot_get_location (slot)) {
+		update_dbus_opened_locations (application);
+	}
+
+	g_signal_connect (slot, "location-changed", G_CALLBACK (on_slot_location_changed), application);
+	g_signal_connect (slot, "active", G_CALLBACK (on_slot_active_changed), application);
+}
+
+static void
+on_slot_removed (NemoWindow      *window,
+		 NemoWindowSlot  *slot,
+		 NemoApplication *application)
+{
+	update_dbus_opened_locations (application);
+
+	g_signal_handlers_disconnect_by_func (slot, on_slot_location_changed, application);
+	g_signal_handlers_disconnect_by_func (slot, on_slot_active_changed, application);
+}
+
+static void
+on_realize (GtkWidget       *widget,
+	    NemoApplication *application)
+{
+	update_dbus_opened_locations (application);
+}
+
+static void
+nemo_main_application_window_added (GtkApplication *app,
+				    GtkWindow      *window)
+{
+	GTK_APPLICATION_CLASS (nemo_main_application_parent_class)->window_added (app, window);
+
+	if (NEMO_IS_WINDOW (window)) {
+		g_signal_connect (window, "realize", G_CALLBACK (on_realize), app);
+		g_signal_connect (window, "slot-added", G_CALLBACK (on_slot_added), app);
+		g_signal_connect (window, "slot-removed", G_CALLBACK (on_slot_removed), app);
+	}
+}
+
+static void
+nemo_main_application_window_removed (GtkApplication *app,
+				      GtkWindow      *window)
+{
+	GTK_APPLICATION_CLASS (nemo_main_application_parent_class)->window_removed (app, window);
+
+	if (NEMO_IS_WINDOW (window)) {
+		g_signal_handlers_disconnect_by_func (window, on_realize, app);
+		g_signal_handlers_disconnect_by_func (window, on_slot_added, app);
+		g_signal_handlers_disconnect_by_func (window, on_slot_removed, app);
+	}
+}
+
 static void
 nemo_main_application_class_init (NemoMainApplicationClass *class)
 {
     GObjectClass *object_class;
     GApplicationClass *application_class;
+    GtkApplicationClass *gtkapp_class;
     NemoApplicationClass *nemo_app_class;
 
     object_class = G_OBJECT_CLASS (class);
@@ -963,6 +1151,10 @@ nemo_main_application_class_init (NemoMainApplicationClass *class)
     application_class->local_command_line = nemo_main_application_local_command_line;
     application_class->quit_mainloop = nemo_main_application_quit_mainloop;
 
+    gtkapp_class = GTK_APPLICATION_CLASS (class);
+    gtkapp_class->window_added = nemo_main_application_window_added;
+    gtkapp_class->window_removed = nemo_main_application_window_removed;
+
     nemo_app_class = NEMO_APPLICATION_CLASS (class);
     nemo_app_class->open_location = nemo_main_application_open_location;
     nemo_app_class->create_window = nemo_main_application_create_window;
diff --git a/src/nemo-progress-ui-handler.c b/src/nemo-progress-ui-handler.c
index 0787a68..6ae3811 100644
--- a/src/nemo-progress-ui-handler.c
+++ b/src/nemo-progress-ui-handler.c
@@ -42,6 +42,11 @@
 #include <libxapp/xapp-gtk-window.h>
 #include <libxapp/xapp-status-icon.h>
 
+#ifdef HAVE_UNITY
+#include <unity.h>
+#include "unity-quicklist-handler.h"
+#endif
+
 struct _NemoProgressUIHandlerPriv {
 	NemoProgressInfoManager *manager;
 
@@ -56,6 +61,9 @@ struct _NemoProgressUIHandlerPriv {
 
 	XAppStatusIcon *status_icon;
     gboolean should_show_status_icon;
+#ifdef HAVE_UNITY
+	UnityQuicklistHandler *unity_quicklist_handler;
+#endif
 };
 
 G_DEFINE_TYPE (NemoProgressUIHandler, nemo_progress_ui_handler, G_TYPE_OBJECT);
@@ -128,6 +136,231 @@ progress_ui_handler_update_status_icon (NemoProgressUIHandler *self)
 	xapp_status_icon_set_visible (self->priv->status_icon, self->priv->should_show_status_icon);
 }
 
+#ifdef HAVE_UNITY
+static void
+progress_ui_handler_unity_progress_changed (NemoProgressInfo *info,
+                                            NemoProgressUIHandler *self)
+{
+	g_return_if_fail (self);
+	g_return_if_fail (self->priv->unity_quicklist_handler);
+	g_return_if_fail (self->priv->manager);
+
+	GList *infos, *l;
+	double progress = 0;
+	double c, current = 0;
+	double t, total = 0;
+
+	infos = nemo_progress_info_manager_get_all_infos (self->priv->manager);
+
+	for (l = infos; l; l = l->next) {
+		NemoProgressInfo *i = l->data;
+		c = nemo_progress_info_get_current (i);
+		t = nemo_progress_info_get_total (i);
+
+		if (c < 0) c = 0;
+		if (t <= 0) continue;
+
+		total += t;
+		current += c;
+	}
+
+	if (current >= 0 && total > 0)
+		progress = current / total;
+
+	if (progress > 1.0)
+		progress = 1.0;
+
+	for (l = unity_quicklist_get_launcher_entries (self->priv->unity_quicklist_handler); l; l = l->next) {
+		UnityLauncherEntry *entry = l->data;
+		unity_launcher_entry_set_progress (entry, progress);
+	}
+}
+
+static gboolean
+progress_ui_handler_disable_unity_urgency (UnityLauncherEntry *entry)
+{
+	g_return_val_if_fail (entry, FALSE);
+
+	unity_launcher_entry_set_urgent (entry, FALSE);
+	return FALSE;
+}
+
+static void
+progress_ui_handler_unity_quicklist_show_activated (DbusmenuMenuitem *menu,
+                                                    guint timestamp,
+                                                    NemoProgressUIHandler *self)
+{
+	g_return_if_fail (self);
+
+	if (!self->priv->progress_window)
+		return;
+
+	gtk_window_present_with_time (GTK_WINDOW (self->priv->progress_window), timestamp);
+}
+
+static void
+progress_ui_handler_unity_quicklist_cancel_activated (DbusmenuMenuitem *menu,
+                                                      guint timestamp,
+                                                      NemoProgressUIHandler *self)
+{
+	g_return_if_fail (self);
+	g_return_if_fail (self->priv->manager);
+
+	GList *infos, *l;
+	infos = nemo_progress_info_manager_get_all_infos (self->priv->manager);
+
+	for (l = infos; l; l = l->next) {
+		NemoProgressInfo *info = l->data;
+		nemo_progress_info_cancel (info);
+	}
+}
+
+static void
+progress_ui_handler_build_unity_quicklist (NemoProgressUIHandler *self)
+{
+	g_return_if_fail (self);
+	GList *l;
+
+	for (l = unity_quicklist_get_launcher_entries (self->priv->unity_quicklist_handler); l; l = l->next) {
+		UnityLauncherEntry *entry = l->data;
+		DbusmenuMenuitem *ql = unity_launcher_entry_get_quicklist (entry);
+		DbusmenuMenuitem *quickmenu;
+
+		if (ql) {
+			quickmenu = dbusmenu_menuitem_new ();
+			dbusmenu_menuitem_property_set (quickmenu,
+			                                DBUSMENU_MENUITEM_PROP_TYPE,
+			                                DBUSMENU_CLIENT_TYPES_SEPARATOR);
+			dbusmenu_menuitem_property_set_bool (quickmenu,
+			                                     DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
+			dbusmenu_menuitem_property_set_bool (quickmenu,
+			                                     UNITY_QUICKLIST_PROGRESS_ITEM, TRUE);
+			unity_quicklist_handler_append_menuitem (entry, quickmenu);
+		}
+
+		quickmenu = dbusmenu_menuitem_new ();
+		dbusmenu_menuitem_property_set (quickmenu,
+		                                DBUSMENU_MENUITEM_PROP_LABEL,
+		                                UNITY_QUICKLIST_SHOW_COPY_DIALOG);
+		dbusmenu_menuitem_property_set_bool (quickmenu,
+		                                     DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
+		dbusmenu_menuitem_property_set_bool (quickmenu,
+		                                     UNITY_QUICKLIST_PROGRESS_ITEM, TRUE);
+		unity_quicklist_handler_append_menuitem (entry, quickmenu);
+		g_signal_connect (quickmenu, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
+		                  (GCallback) progress_ui_handler_unity_quicklist_show_activated,
+		                  self);
+
+		quickmenu = dbusmenu_menuitem_new ();
+		dbusmenu_menuitem_property_set (quickmenu,
+		                                DBUSMENU_MENUITEM_PROP_LABEL,
+		                                UNITY_QUICKLIST_CANCEL_COPY);
+		dbusmenu_menuitem_property_set_bool (quickmenu,
+		                                     DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
+		dbusmenu_menuitem_property_set_bool (quickmenu,
+		                                     UNITY_QUICKLIST_PROGRESS_ITEM, TRUE);
+		unity_quicklist_handler_append_menuitem (entry, quickmenu);
+		g_signal_connect (quickmenu, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
+		                  (GCallback) progress_ui_handler_unity_quicklist_cancel_activated,
+		                  self);
+	}
+}
+
+static void
+progress_ui_handler_show_unity_quicklist (NemoProgressUIHandler *self,
+                                          UnityLauncherEntry *entry,
+                                          gboolean show)
+{
+	g_return_if_fail (self);
+	g_return_if_fail (entry);
+
+	DbusmenuMenuitem *ql;
+	GList *children, *l;
+
+	ql = unity_launcher_entry_get_quicklist (entry);
+	if (!ql)
+		return;
+	children = dbusmenu_menuitem_get_children (ql);
+
+	for (l = children; l; l = l->next) {
+		DbusmenuMenuitem *child = l->data;
+		if (unity_quicklist_handler_menuitem_is_progress_item (child))
+			dbusmenu_menuitem_property_set_bool(child,
+	                                    DBUSMENU_MENUITEM_PROP_VISIBLE, show);
+	}
+}
+
+static void
+progress_ui_handler_update_unity_launcher_entry (NemoProgressUIHandler *self,
+                                                 NemoProgressInfo *info,
+                                                 UnityLauncherEntry *entry)
+{
+	g_return_if_fail (self);
+	g_return_if_fail (entry);
+
+	if (self->priv->active_infos > 0) {
+		unity_launcher_entry_set_progress_visible (entry, TRUE);
+		progress_ui_handler_show_unity_quicklist (self, entry, TRUE);
+		progress_ui_handler_unity_progress_changed (NULL, self);
+
+		if (self->priv->active_infos > 1) {
+			unity_launcher_entry_set_count (entry, self->priv->active_infos);
+			unity_launcher_entry_set_count_visible (entry, TRUE);
+		} else {
+			unity_launcher_entry_set_count_visible (entry, FALSE);
+		}
+	} else {
+		unity_launcher_entry_set_progress_visible (entry, FALSE);
+		unity_launcher_entry_set_progress (entry, 0.0);
+		unity_launcher_entry_set_count_visible (entry, FALSE);
+		progress_ui_handler_show_unity_quicklist (self, entry, FALSE);
+		GCancellable *pc = nemo_progress_info_get_cancellable (info);
+
+		if (!g_cancellable_is_cancelled (pc)) {
+			unity_launcher_entry_set_urgent (entry, TRUE);
+
+			g_timeout_add_seconds (2, (GSourceFunc)
+				               progress_ui_handler_disable_unity_urgency,
+					       entry);
+		}
+
+		g_object_unref (pc);
+	}
+}
+
+static void
+progress_ui_handler_update_unity_launcher (NemoProgressUIHandler *self,
+                                           NemoProgressInfo *info,
+                                           gboolean added)
+{
+	g_return_if_fail (self);
+	GList *l;
+
+	if (!self->priv->unity_quicklist_handler) {
+		UnityQuicklistHandler *singleton = unity_quicklist_handler_get_singleton ();
+		if (!singleton)
+			return;
+		self->priv->unity_quicklist_handler = g_object_ref (singleton);
+
+		progress_ui_handler_build_unity_quicklist (self);
+	}
+
+	for (l = unity_quicklist_get_launcher_entries (self->priv->unity_quicklist_handler); l; l = l->next) {
+		UnityLauncherEntry *entry = l->data;
+		progress_ui_handler_update_unity_launcher_entry (self, info, entry);
+	}
+
+	if (added) {
+		g_signal_connect (info, "progress-changed",
+				  (GCallback) progress_ui_handler_unity_progress_changed,
+				  self);
+	} else {
+		g_signal_handlers_disconnect_by_func (info,
+			progress_ui_handler_unity_progress_changed, self);
+	}
+}
+#endif
+
 static gboolean
 progress_window_delete_event (GtkWidget *widget,
 			      GdkEvent *event,
@@ -301,6 +534,10 @@ progress_info_finished_cb (NemoProgressInfo *info,
 			progress_ui_handler_show_complete_notification (self);
 		}
 	}
+
+#ifdef HAVE_UNITY
+	progress_ui_handler_update_unity_launcher (self, info, FALSE);
+#endif
 }
 
 static void
@@ -372,6 +609,10 @@ handle_new_progress_info (NemoProgressUIHandler *self,
             gtk_window_present (GTK_WINDOW (self->priv->progress_window));
         }
 	}
+
+#ifdef HAVE_UNITY
+	progress_ui_handler_update_unity_launcher (self, info, TRUE);
+#endif
 }
 
 typedef struct {
@@ -468,6 +709,9 @@ nemo_progress_ui_handler_dispose (GObject *obj)
 	NemoProgressUIHandler *self = NEMO_PROGRESS_UI_HANDLER (obj);
 
 	g_clear_object (&self->priv->manager);
+#ifdef HAVE_UNITY
+	g_clear_object (&self->priv->unity_quicklist_handler);
+#endif
 
 	G_OBJECT_CLASS (nemo_progress_ui_handler_parent_class)->dispose (obj);
 }
diff --git a/src/nemo-window-manage-views.c b/src/nemo-window-manage-views.c
index c1bc864..1c47e20 100644
--- a/src/nemo-window-manage-views.c
+++ b/src/nemo-window-manage-views.c
@@ -1470,6 +1470,7 @@ update_for_new_location (NemoWindowSlot *slot)
 {
 	NemoWindow *window;
         GFile *new_location;
+        GFile *old_location;
         NemoFile *file;
 	NemoDirectory *directory;
 	gboolean location_really_changed;
@@ -1487,11 +1488,12 @@ update_for_new_location (NemoWindowSlot *slot)
 		slot->location == NULL ||
 		!g_file_equal (slot->location, new_location);
 
-	nemo_window_slot_emit_location_change (slot, slot->location, new_location);
 
         /* Set the new location. */
-	g_clear_object (&slot->location);
+	old_location = slot->location;
 	slot->location = new_location;
+	nemo_window_slot_emit_location_change (slot, old_location, new_location);
+	g_clear_object (&old_location);
 
         /* Create a NemoFile for this location, so we can catch it
          * if it goes away.
diff --git a/src/nemo-window-pane.c b/src/nemo-window-pane.c
index 5b4d8de..c446b61 100644
--- a/src/nemo-window-pane.c
+++ b/src/nemo-window-pane.c
@@ -1333,15 +1333,19 @@ nemo_window_pane_remove_slot_unsafe (NemoWindowPane *pane,
 
 	DEBUG ("Removing slot %p", slot);
 
-	/* save pane because slot is not valid anymore after this call */
+	/* save pane because slot->pane may be cleared during close */
 	pane = slot->pane;
 	notebook = GTK_NOTEBOOK (pane->notebook);
 
 	nemo_window_manage_views_close_slot (slot);
 
+	pane->slots = g_list_remove (pane->slots, slot);
+
 	page_num = gtk_notebook_page_num (notebook, GTK_WIDGET (slot));
 	g_assert (page_num >= 0);
 
+	g_object_ref (slot);
+
 	g_signal_handlers_block_by_func (notebook,
 					 G_CALLBACK (notebook_switch_page_cb),
 					 pane);
@@ -1353,7 +1357,9 @@ nemo_window_pane_remove_slot_unsafe (NemoWindowPane *pane,
 
 	gtk_notebook_set_show_tabs (notebook,
 				    gtk_notebook_get_n_pages (notebook) > 1);
-	pane->slots = g_list_remove (pane->slots, slot);
+
+	nemo_window_slot_removed (pane->window, slot);
+	g_object_unref (slot);
 }
 
 NemoWindowSlot *
@@ -1381,6 +1387,7 @@ nemo_window_pane_open_slot (NemoWindowPane *pane,
 					   pane);
 
 	pane->slots = g_list_append (pane->slots, slot);
+	nemo_window_slot_added (pane->window, slot);
 
 	return slot;
 }
diff --git a/src/unity-bookmarks-handler.c b/src/unity-bookmarks-handler.c
new file mode 100644
index 0000000..f3f5021
--- /dev/null
+++ b/src/unity-bookmarks-handler.c
@@ -0,0 +1,158 @@
+/*unity-bookmarks-handler.c: handle Unity bookmark for quicklist
+ *
+ * Copyright (C) 2012 Canonical
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Didier Roche <didrocks@ubuntu.com>
+ *
+ */
+
+#include <config.h>
+
+#include "unity-bookmarks-handler.h"
+
+#include <libdbusmenu-glib/dbusmenu-glib.h>
+#include "unity-quicklist-handler.h"
+
+#include "nemo-application.h"
+#include "nemo-bookmark-list.h"
+
+#include <eel/eel-string.h>
+#include <gdk/gdkx.h>
+
+static UnityQuicklistHandler* unity_quicklist_handler = NULL;
+static NemoBookmarkList* bookmarks = NULL;
+
+static void
+activate_bookmark_by_quicklist (DbusmenuMenuitem *menu,
+								guint timestamp,
+								NemoBookmark *bookmark)
+{
+	g_return_if_fail (NEMO_IS_BOOKMARK (bookmark));
+
+	GFile *locations[2];
+	GList *l;
+	NemoApplication *application;
+
+	locations[0] = nemo_bookmark_get_location (bookmark);
+	locations[1] = NULL;
+
+	application = NEMO_APPLICATION (g_application_get_default ());
+
+	/* Make sure that the application timestamp matches the event */
+	for (l = gtk_application_get_windows (GTK_APPLICATION (application)); l; l = l->next) {
+		GdkWindow *gdk_window = gtk_widget_get_window (GTK_WIDGET (l->data));
+		if (gdk_window)
+			gdk_x11_window_set_user_time (gdk_window, timestamp);
+	}
+
+	g_application_open (G_APPLICATION (application), locations, 1, "");
+
+	g_object_unref (locations[0]);
+}
+
+static void
+unity_bookmarks_handler_remove_bookmark_quicklists (void) {
+
+	GList *children, *l;
+
+	/* remove unity quicklist bookmarks to launcher entries */
+	for (l = unity_quicklist_get_launcher_entries (unity_quicklist_handler); l; l = l->next) {
+		UnityLauncherEntry *entry = l->data;
+		DbusmenuMenuitem *ql = unity_launcher_entry_get_quicklist (entry);
+		if (!ql)
+			continue;
+
+		children = dbusmenu_menuitem_get_children (ql);
+		while (children) {
+			DbusmenuMenuitem *child = children->data;
+			children = children->next;
+			if (unity_quicklist_handler_menuitem_is_bookmark_item (child)) {
+				g_signal_handlers_disconnect_matched (child, G_SIGNAL_MATCH_FUNC, 0, 0, 0, (GCallback) activate_bookmark_by_quicklist, 0);
+				dbusmenu_menuitem_child_delete (ql, child);
+			}
+		}
+	}
+}
+
+static void
+unity_bookmarks_handler_update_bookmarks () {
+
+	NemoBookmark *bookmark;
+	guint bookmark_count;
+	guint index;
+	GList *l;
+
+	/* append new set of bookmarks */
+	bookmark_count = nemo_bookmark_list_length (bookmarks);
+	for (index = 0; index < bookmark_count; ++index) {
+
+		bookmark = nemo_bookmark_list_item_at (bookmarks, index);
+
+		for (l = unity_quicklist_get_launcher_entries (unity_quicklist_handler); l; l = l->next) {
+			UnityLauncherEntry *entry = l->data;
+
+			DbusmenuMenuitem* menuitem = dbusmenu_menuitem_new();
+			gchar *bookmark_name_dbusmenu = eel_str_replace_substring (nemo_bookmark_get_name (bookmark), "_", "__");
+			dbusmenu_menuitem_property_set (menuitem, "label", bookmark_name_dbusmenu);
+			g_free (bookmark_name_dbusmenu);
+			g_signal_connect_data (menuitem, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
+			                       (GCallback) activate_bookmark_by_quicklist,
+			                       g_object_ref (bookmark),
+			                       (GClosureNotify) g_object_unref,
+			                       0);
+
+			unity_quicklist_handler_append_menuitem (entry, menuitem);
+		}
+	}
+}
+
+static void
+unity_bookmarks_handler_refresh_bookmarks (void)
+{
+	unity_bookmarks_handler_remove_bookmark_quicklists ();
+	unity_bookmarks_handler_update_bookmarks ();
+}
+
+void
+unity_bookmarks_handler_initialize ()
+{
+	unity_quicklist_handler = unity_quicklist_handler_get_singleton ();
+	if (!unity_quicklist_handler)
+	    return;
+	// get the singleton
+	bookmarks = nemo_bookmark_list_get_default ();
+	unity_bookmarks_handler_refresh_bookmarks ();
+
+    /* Recreate dynamic part of menu if bookmark list changes */
+	g_signal_connect (bookmarks, "changed",
+					G_CALLBACK (unity_bookmarks_handler_refresh_bookmarks), NULL);
+}
+
+void
+unity_bookmarks_handler_shutdown (void)
+{
+	if (bookmarks) {
+		g_signal_handlers_disconnect_by_func (bookmarks,
+		                                      unity_bookmarks_handler_refresh_bookmarks,
+		                                      NULL);
+		bookmarks = NULL;
+	}
+
+	unity_quicklist_handler_destroy_singleton ();
+	unity_quicklist_handler = NULL;
+}
diff --git a/src/unity-bookmarks-handler.h b/src/unity-bookmarks-handler.h
new file mode 100644
index 0000000..bd2a49c
--- /dev/null
+++ b/src/unity-bookmarks-handler.h
@@ -0,0 +1,32 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * unity-bookmarks-handler.h: handle Unity bookmark for quicklist
+ *
+ * Copyright (C) 2012 Canonical
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Didier Roche <didrocks@ubuntu.com>
+ *
+ */
+
+#ifndef __UNITY_BOOKMARKS_HANDLER_H__
+#define __UNITY_BOOKMARKS_HANDLER_H__
+
+void unity_bookmarks_handler_initialize (void);
+void unity_bookmarks_handler_shutdown (void);
+
+#endif /* __UNITY_BOOKMARKS_HANDLER_H__*/
diff --git a/src/unity-quicklist-handler.c b/src/unity-quicklist-handler.c
new file mode 100644
index 0000000..ba8f039
--- /dev/null
+++ b/src/unity-quicklist-handler.c
@@ -0,0 +1,164 @@
+/*unity-quicklist-handler.c: handle Unity quicklists
+ *
+ * Copyright (C) 2012 Canonical
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Didier Roche <didrocks@ubuntu.com>
+ *
+ */
+
+#include <config.h>
+
+#include "unity-quicklist-handler.h"
+
+struct _UnityQuicklistHandlerPriv {
+    GList *launcher_entries;
+};
+
+G_DEFINE_TYPE (UnityQuicklistHandler, unity_quicklist_handler, G_TYPE_OBJECT);
+
+static UnityQuicklistHandler *unity_quicklist_handler_singleton = NULL;
+
+GList *
+unity_quicklist_get_launcher_entries (UnityQuicklistHandler *self)
+{
+	return self->priv->launcher_entries;
+}
+
+gboolean
+unity_quicklist_handler_menuitem_is_progress_item (DbusmenuMenuitem *ql)
+{
+	g_return_val_if_fail(ql, FALSE);
+	return dbusmenu_menuitem_property_get_bool (ql, UNITY_QUICKLIST_PROGRESS_ITEM);
+}
+
+gboolean
+unity_quicklist_handler_menuitem_is_bookmark_item (DbusmenuMenuitem *ql)
+{
+	g_return_val_if_fail(ql, FALSE);
+	return (!unity_quicklist_handler_menuitem_is_progress_item(ql));
+}
+
+void
+unity_quicklist_handler_append_menuitem (UnityLauncherEntry *entry, DbusmenuMenuitem *elem)
+{
+	g_return_if_fail (entry);
+
+	GList *children, *l;
+	int position = 0;
+	DbusmenuMenuitem *ql = unity_launcher_entry_get_quicklist (entry);
+
+	gboolean is_bookmark = unity_quicklist_handler_menuitem_is_bookmark_item (elem);
+	gboolean is_progress = unity_quicklist_handler_menuitem_is_progress_item (elem);
+
+	if (!ql) {
+		ql = dbusmenu_menuitem_new ();
+		unity_launcher_entry_set_quicklist (entry, ql);
+	}
+
+	children = dbusmenu_menuitem_get_children (ql);
+	for (l = children; l; l = l->next) {
+		DbusmenuMenuitem *child = l->data;
+		/* set quicklist groups together, and bookmarks group after progress group.
+		   bookmarks elements are ordered alphabetically */
+		if ((is_bookmark && unity_quicklist_handler_menuitem_is_bookmark_item (child) &&
+                (g_strcmp0 (dbusmenu_menuitem_property_get (child, DBUSMENU_MENUITEM_PROP_LABEL), dbusmenu_menuitem_property_get (elem, DBUSMENU_MENUITEM_PROP_LABEL)) < 0)) ||
+			(is_progress && unity_quicklist_handler_menuitem_is_progress_item (child)) ||
+			(is_progress && unity_quicklist_handler_menuitem_is_bookmark_item (child)))
+			position++;
+		else
+			break;
+	}
+
+	dbusmenu_menuitem_child_add_position (ql, elem, position);
+}
+
+static void
+unity_quicklist_handler_dispose (GObject *obj)
+{
+	UnityQuicklistHandler *self = UNITY_QUICKLIST_HANDLER (obj);
+
+	if (self->priv->launcher_entries) {
+		g_list_free_full (self->priv->launcher_entries, g_object_unref);
+		self->priv->launcher_entries = NULL;
+	}
+
+	G_OBJECT_CLASS (unity_quicklist_handler_parent_class)->dispose (obj);
+}
+
+static void
+unity_quicklist_handler_launcher_entry_add (UnityQuicklistHandler *self,
+                                            const gchar *entry_id)
+{
+	GList **entries;
+	UnityLauncherEntry *entry;
+
+	entries = &(self->priv->launcher_entries);
+	entry = unity_launcher_entry_get_for_desktop_id (entry_id);
+
+	if (entry) {
+		*entries = g_list_prepend (*entries, entry);
+	}
+}
+
+static void
+unity_quicklist_handler_init (UnityQuicklistHandler *self)
+{
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, UNITY_TYPE_QUICKLIST_HANDLER,
+	                                          UnityQuicklistHandlerPriv);
+
+	unity_quicklist_handler_launcher_entry_add (self, "nemo.desktop");
+}
+
+static void
+unity_quicklist_handler_class_init (UnityQuicklistHandlerClass *klass)
+{
+	GObjectClass *oclass;
+
+	oclass = G_OBJECT_CLASS (klass);
+	oclass->dispose = unity_quicklist_handler_dispose;
+
+	g_type_class_add_private (klass, sizeof (UnityQuicklistHandlerPriv));
+}
+
+UnityQuicklistHandler *
+unity_quicklist_handler_get_singleton (void)
+{
+	if (!unity_quicklist_handler_singleton)
+		unity_quicklist_handler_singleton = unity_quicklist_handler_new ();
+	return unity_quicklist_handler_singleton;
+}
+
+void
+unity_quicklist_handler_destroy_singleton (void)
+{
+	g_clear_object (&unity_quicklist_handler_singleton);
+}
+
+UnityQuicklistHandler *
+unity_quicklist_handler_new (void)
+{
+    UnityQuicklistHandler *self = g_object_new (UNITY_TYPE_QUICKLIST_HANDLER, NULL);
+
+    if (!self->priv->launcher_entries) {
+        g_object_unref (self);
+        return NULL;
+    }
+
+    return self;
+}
+
diff --git a/src/unity-quicklist-handler.h b/src/unity-quicklist-handler.h
new file mode 100644
index 0000000..b8005ff
--- /dev/null
+++ b/src/unity-quicklist-handler.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * unity-quicklist.h: handle unity quicklists.
+ *
+ * Copyright (C) 2012 Canonical
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Didier Roche <didrocks@ubuntu.com>
+ *
+ */
+
+#ifndef __UNITY_QUICKLIST_HANDLER_H__
+#define __UNITY_QUICKLIST_HANDLER_H__
+
+#include <glib-object.h>
+#include <glib/gi18n.h>
+
+#include <libdbusmenu-glib/dbusmenu-glib.h>
+#include <unity.h>
+
+#define UNITY_TYPE_QUICKLIST_HANDLER unity_quicklist_handler_get_type()
+#define UNITY_QUICKLIST_HANDLER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_TYPE_QUICKLIST_HANDLER, UnityQuicklistHandler))
+#define UNITY_QUICKLIST_HANDLER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_TYPE_QUICKLIST_HANDLER, UnityQuicklistHandlerClass))
+#define UNITY_IS_QUICKLIST_HANDLER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_TYPE_QUICKLIST_HANDLER))
+#define UNITY_IS_QUICKLIST_HANDLER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_TYPE_QUICKLIST_HANDLER))
+#define UNITY_QUICKLIST_HANDLER_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_TYPE_QUICKLIST_HANDLER, UnityQuicklistHandlerClass))
+
+typedef struct _UnityQuicklistHandlerPriv UnityQuicklistHandlerPriv;
+
+#define UNITY_QUICKLIST_PROGRESS_ITEM "unity-quicklist-progress-item"
+
+typedef struct {
+  GObject parent;
+
+  /* private */
+  UnityQuicklistHandlerPriv *priv;
+} UnityQuicklistHandler;
+
+typedef struct {
+  GObjectClass parent_class;
+} UnityQuicklistHandlerClass;
+
+GType unity_quicklist_handler_get_type (void);
+
+UnityQuicklistHandler * unity_quicklist_handler_new (void);
+UnityQuicklistHandler * unity_quicklist_handler_get_singleton (void);
+void unity_quicklist_handler_destroy_singleton (void);
+
+GList * unity_quicklist_get_launcher_entries (UnityQuicklistHandler *unity_quicklist_handler);
+gboolean unity_quicklist_handler_menuitem_is_progress_item (DbusmenuMenuitem *ql);
+gboolean unity_quicklist_handler_menuitem_is_bookmark_item (DbusmenuMenuitem *ql);
+void unity_quicklist_handler_append_menuitem (UnityLauncherEntry *entry, DbusmenuMenuitem *elem);
+
+#define UNITY_QUICKLIST_SHOW_COPY_DIALOG _("Show Copy Dialog")
+#define UNITY_QUICKLIST_CANCEL_COPY _("Cancel All In-progress Actions")
+
+#endif /* __UNITY_QUICKLIST_HANDLER_H__ */
-- 
2.53.0

