[gnome-terminal] all: Port to GMenu



commit 0820b3853a3b7c629a93fa820d5372eac1760686
Author: Christian Persch <chpe gnome org>
Date:   Sun Oct 22 18:48:15 2017 +0200

    all: Port to GMenu
    
    Port from GtkAction and GtkMenuManager to GAction and GMenu.
    
    (Initial patch by Lars Uebernickel <lars uebernickel canonical com>)
    
    https://bugzilla.gnome.org/show_bug.cgi?id=745329

 configure.ac                                       |    5 +-
 src/Makefile.am                                    |    6 +-
 src/migration.c                                    |    4 +-
 src/org.gnome.Terminal.gschema.xml                 |   31 +-
 src/preferences.ui                                 |   71 +-
 src/profile-editor.c                               |   44 +-
 src/profile-editor.h                               |    1 -
 src/server.c                                       |   44 +-
 src/terminal-accels.c                              |  201 +-
 src/terminal-app.c                                 |  651 +++--
 src/terminal-app.h                                 |   26 +-
 src/{terminal-menus.ui => terminal-appmenu.ui}     |    8 +-
 src/terminal-debug.c                               |    3 +-
 src/terminal-debug.h                               |   16 +-
 src/terminal-encoding.c                            |  379 ++--
 src/terminal-encoding.h                            |   34 +-
 src/terminal-libgsystem.h                          |   27 +
 src/terminal-menu-button.c                         |  107 +
 src/terminal-menu-button.h                         |   57 +
 src/terminal-menubar.ui                            |  252 ++
 ...terminal-menus.ui => terminal-notebook-menu.ui} |   28 +-
 src/terminal-notebook.c                            |   24 +
 src/terminal-prefs.c                               |  217 +--
 src/terminal-prefs.h                               |    3 +-
 src/terminal-schemas.h                             |    1 -
 src/terminal-screen.c                              |   66 +-
 src/terminal-screen.h                              |    6 +-
 src/terminal-settings-list.c                       |   45 +-
 src/terminal-settings-list.h                       |   11 +
 src/terminal-tabs-menu.c                           |  468 ---
 src/terminal-tabs-menu.h                           |   55 -
 src/terminal-util.c                                |  228 ++-
 src/terminal-util.h                                |   18 +-
 src/terminal-window.c                              | 2983 +++++++-------------
 src/terminal-window.h                              |    3 -
 src/terminal.c                                     |    1 -
 src/terminal.gresource.xml                         |   11 +-
 src/terminal.xml                                   |  121 -
 38 files changed, 2753 insertions(+), 3503 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index b45627b..00d5f60 100644
--- a/configure.ac
+++ b/configure.ac
@@ -13,6 +13,8 @@ AC_CONFIG_MACRO_DIR([m4])
 
 AM_INIT_AUTOMAKE([1.9 foreign no-dist-gzip dist-bzip2])
 
+AC_USE_SYSTEM_EXTENSIONS
+
 m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
 
 GETTEXT_PACKAGE=gnome-terminal
@@ -26,7 +28,7 @@ AM_MAINTAINER_MODE([enable])
 
 PKG_PROG_PKG_CONFIG
 AC_PROG_MKDIR_P
-AC_PROG_CC
+AC_PROG_CC_C99
 AC_ISC_POSIX
 AC_HEADER_STDC
 AM_PROG_LIBTOOL
@@ -294,7 +296,6 @@ CC_CHECK_FLAGS_APPEND([WARN_CFLAGS],[CFLAGS],[ \
   -Wall \
   -Wcast-align \
   -Wendif-labels \
-  -Werror=declaration-after-statement \
   "-Werror=format=2 -Werror=format-nonliteral -Werror=format-security" \
   -Werror=implicit-function-declaration \
   -Werror=init-self \
diff --git a/src/Makefile.am b/src/Makefile.am
index aa63b7b..5c9f720 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -61,6 +61,8 @@ gnome_terminal_server_SOURCES = \
        terminal-libgsystem.h \
        terminal-mdi-container.c \
        terminal-mdi-container.h \
+       terminal-menu-button.h \
+       terminal-menu-button.c \
        terminal-notebook.c \
        terminal-notebook.h \
        terminal-pcre2.h \
@@ -80,8 +82,6 @@ gnome_terminal_server_SOURCES = \
        terminal-search-popover.h \
        terminal-tab-label.c \
        terminal-tab-label.h \
-       terminal-tabs-menu.c \
-       terminal-tabs-menu.h \
        terminal-util.c \
        terminal-util.h \
        terminal-version.h \
@@ -94,7 +94,6 @@ nodist_gnome_terminal_server_SOURCES = $(gnome_terminal_server_built)
 gnome_terminal_server_CPPFLAGS = \
        -DTERMINAL_COMPILATION \
        -DTERM_LOCALEDIR="\"$(datadir)/locale\"" \
-       -DTERM_HELPDIR="\"$(HELP_DIR)\"" \
        -DTERM_LIBEXECDIR="\"$(libexecdir)\"" \
        $(AM_CPPFLAGS)
 
@@ -416,7 +415,6 @@ CLEANFILES = \
 
 EXTRA_DIST = \
        terminal.about \
-       terminal.xml \
        terminal-menus.ui \
        terminal-window.ui \
        terminal.gresource.xml \
diff --git a/src/migration.c b/src/migration.c
index 34401c7..68acd41 100644
--- a/src/migration.c
+++ b/src/migration.c
@@ -205,6 +205,7 @@ migrate_string (GConfClient *client,
     gconf_value_free (value);
 }
 
+#if 0
 static void
 migrate_string_list (GConfClient *client,
                      const char *gconf_path,
@@ -235,6 +236,7 @@ migrate_string_list (GConfClient *client,
   if (value)
     gconf_value_free (value);
 }
+#endif
 
 static void
 migrate_enum (GConfClient *client,
@@ -328,8 +330,6 @@ migrate_global_prefs (GSettings *settings,
   migrate_bool (client, GCONF_GLOBAL_PREFIX, "use_menu_accelerator",
                 settings, TERMINAL_SETTING_ENABLE_MENU_BAR_ACCEL_KEY,
                 FALSE);
-  migrate_string_list (client, GCONF_GLOBAL_PREFIX, "active_encodings",
-                       settings, TERMINAL_SETTING_ENCODINGS_KEY);
 
   g_object_unref (client);
 
diff --git a/src/org.gnome.Terminal.gschema.xml b/src/org.gnome.Terminal.gschema.xml
index ebb450b..16fd832 100644
--- a/src/org.gnome.Terminal.gschema.xml
+++ b/src/org.gnome.Terminal.gschema.xml
@@ -310,7 +310,11 @@
         <choice value="ISO-8859-14" />
         <choice value="ISO-8859-15" />
         <choice value="ISO-8859-16" />
+        <!-- <choice value="UTF-7" /> -->
         <choice value="UTF-8" />
+        <!-- <choice value="UTF-16" /> -->
+        <!-- <choice value="UTF-32" /> -->
+        <!-- <choice value="UCS-4" /> -->
         <choice value="ARMSCII-8" />
         <choice value="BIG5" />
         <choice value="BIG5-HKSCS" />
@@ -331,6 +335,7 @@
         <choice value="ISO-2022-JP" />
         <choice value="ISO-2022-KR" />
         <choice value="ISO-IR-111" />
+        <!-- <choice value="JOHAB" /> -->
         <choice value="KOI8-R" />
         <choice value="KOI8-U" />
         <choice value="MAC_ARABIC" />
@@ -391,6 +396,14 @@
       <default>'disabled'</default>
       <summary>Keyboard shortcut to save the current tab contents to file</summary>
     </key>
+    <key name="export" type="s">
+      <default>'disabled'</default>
+      <summary>Keyboard shortcut to export the current tab contents to file in various formats</summary>
+    </key>
+    <key name="print" type="s">
+      <default>'disabled'</default>
+      <summary>Keyboard shortcut to print the current tab contents to printer or file</summary>
+    </key>
     <key name="close-tab" type="s">
       <default>'&lt;Ctrl&gt;&lt;Shift&gt;w'</default>
       <summary>Keyboard shortcut to close a tab</summary>
@@ -619,6 +632,10 @@
       <default>'disabled'</default>
       <summary>Keyboard shortcut to switch to the numbered tab</summary>
     </key>
+    <key name="switch-to-tab-last" type="s">
+      <default>'disabled'</default>
+      <summary>Keyboard shortcut to switch to the last tab</summary>
+    </key>
     <key name="help" type="s">
       <default>'F1'</default>
       <summary>Keyboard shortcut to launch help</summary>
@@ -677,21 +694,9 @@
       <summary>Whether the shell integration is enabled</summary>
     </key>
 
+    <!-- This one is deprecated and unused -->
     <key name="encodings" type="as">
-      <!-- Translators: Please note that this has to be a list of
-           valid encodings (which are to be taken from the list in src/encoding.c).
-           It has to include UTF-8 the list entries themselves are not to be
-           translated. This is provided for customization of the default encoding
-           menu; see bug 144810 for an use case. In most cases, this should be
-           left alone.
-      -->
       <default>["UTF-8"]</default>
-      <summary>List of available encodings</summary>
-      <description>
-        A subset of possible encodings are presented in
-        the Encoding submenu. This is a list of encodings
-        to appear there.
-      </description>
     </key>
 
     <key name="confirm-close" type="b">
diff --git a/src/preferences.ui b/src/preferences.ui
index 6acab38..cdccdc2 100644
--- a/src/preferences.ui
+++ b/src/preferences.ui
@@ -143,7 +143,7 @@
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkLabel" id="label480">
+                      <object class="GtkLabel" id="new-terminal-mode-label">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
                         <property name="halign">start</property>
@@ -429,75 +429,6 @@
                 <property name="tab_fill">False</property>
               </packing>
             </child>
-            <child>
-              <object class="GtkBox" id="encodings">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="border_width">12</property>
-                <property name="orientation">vertical</property>
-                <property name="spacing">6</property>
-                <child>
-                  <object class="GtkLabel" id="encodings-label">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="label" translatable="yes">E_ncodings shown in menu:</property>
-                    <property name="use_underline">True</property>
-                    <property name="mnemonic_widget">encodings-treeview</property>
-                    <property name="xalign">0</property>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">1</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkScrolledWindow" id="scrolledwindow2">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="hscrollbar_policy">never</property>
-                    <property name="shadow_type">in</property>
-                    <child>
-                      <object class="GtkTreeView" id="encodings-treeview">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="hscroll_policy">natural</property>
-                        <property name="vscroll_policy">natural</property>
-                        <property name="headers_visible">False</property>
-                        <property name="headers_clickable">False</property>
-                        <property name="rules_hint">True</property>
-                        <property name="enable_search">False</property>
-                        <child internal-child="selection">
-                          <object class="GtkTreeSelection" id="treeview-selection1"/>
-                        </child>
-                        <accessibility>
-                          <relation type="labelled-by" target="encodings-label"/>
-                        </accessibility>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="expand">True</property>
-                    <property name="fill">True</property>
-                    <property name="position">2</property>
-                  </packing>
-                </child>
-              </object>
-              <packing>
-                <property name="position">3</property>
-              </packing>
-            </child>
-            <child type="tab">
-              <object class="GtkLabel" id="label4">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="label" translatable="yes">Encodings</property>
-              </object>
-              <packing>
-                <property name="position">3</property>
-                <property name="tab_fill">False</property>
-              </packing>
-            </child>
           </object>
           <packing>
             <property name="expand">True</property>
diff --git a/src/profile-editor.c b/src/profile-editor.c
index 002561d..c23386b 100644
--- a/src/profile-editor.c
+++ b/src/profile-editor.c
@@ -2,7 +2,7 @@
 /*
  * Copyright © 2002 Havoc Pennington
  * Copyright © 2002 Mathias Hasselmann
- * Copyright © 2008, 2011 Christian Persch
+ * Copyright © 2008, 2011, 2017 Christian Persch
  *
  * 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
@@ -28,6 +28,7 @@
 #include <gio/gio.h>
 
 #include "terminal-app.h"
+#include "terminal-encoding.h"
 #include "terminal-enums.h"
 #include "profile-editor.h"
 #include "terminal-schemas.h"
@@ -486,55 +487,36 @@ init_color_scheme_menu (GtkWidget *widget)
 }
 
 enum {
-  ENCODINGS_COLUMN_ID,
-  ENCODINGS_COLUMN_MARKUP
+  ENCODINGS_COLUMN_ID = 0,
+  ENCODINGS_COLUMN_TEXT = 1
 };
 
 static void
 init_encodings_combo (GtkWidget *widget)
 {
-  GtkCellRenderer *renderer;
-  GHashTableIter ht_iter;
-  gpointer key, value;
-  gs_unref_object GtkListStore *store;
-
-  store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
-
-  g_hash_table_iter_init (&ht_iter, terminal_app_get_encodings (terminal_app_get ()));
-  while (g_hash_table_iter_next (&ht_iter, &key, &value)) {
-    TerminalEncoding *encoding = value;
-    GtkTreeIter iter;
-    gs_free char *name;
-
-    name = g_markup_printf_escaped ("%s <span size=\"small\">%s</span>",
-                                    terminal_encoding_get_charset (encoding),
-                                    encoding->name);
-    gtk_list_store_insert_with_values (store, &iter, -1,
-                                       ENCODINGS_COLUMN_MARKUP, name,
-                                       ENCODINGS_COLUMN_ID, terminal_encoding_get_charset (encoding),
-                                       -1);
-  }
+  gs_unref_object GtkListStore *store = terminal_encodings_list_store_new (ENCODINGS_COLUMN_ID,
+                                                                           ENCODINGS_COLUMN_TEXT);
 
   /* Now turn on sorting */
   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
-                                        ENCODINGS_COLUMN_MARKUP,
+                                        ENCODINGS_COLUMN_TEXT,
                                         GTK_SORT_ASCENDING);
 
   gtk_combo_box_set_id_column (GTK_COMBO_BOX (widget), ENCODINGS_COLUMN_ID);
   gtk_combo_box_set_model (GTK_COMBO_BOX (widget), GTK_TREE_MODEL (store));
 
   /* Cell renderer */
-  renderer = gtk_cell_renderer_text_new ();
+  GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (widget), renderer, TRUE);
   gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (widget), renderer,
-                                  "markup", ENCODINGS_COLUMN_MARKUP, NULL);
+                                  "text", ENCODINGS_COLUMN_TEXT, NULL);
 }
 
 static void
 editor_help_button_clicked_cb (GtkWidget *button,
                                GtkWidget *editor)
 {
-  terminal_util_show_help ("profile", GTK_WINDOW (editor));
+  terminal_util_show_help ("profile");
 }
 
 static void
@@ -799,7 +781,6 @@ fixup_color_chooser_button (void)
 /**
  * terminal_profile_edit:
  * @profile: a #GSettings
- * @transient_parent: a #GtkWindow, or %NULL
  * @widget_name: a widget name in the profile editor's UI, or %NULL
  *
  * Shows the profile editor with @profile, anchored to @transient_parent.
@@ -808,7 +789,6 @@ fixup_color_chooser_button (void)
  */
 void
 terminal_profile_edit (GSettings  *profile,
-                       GtkWindow  *transient_parent,
                        const char *widget_name)
 {
   TerminalSettingsList *profiles_list;
@@ -823,8 +803,6 @@ terminal_profile_edit (GSettings  *profile,
     {
       terminal_util_dialog_focus_widget (editor, widget_name);
 
-      gtk_window_set_transient_for (GTK_WINDOW (editor),
-                                    GTK_WINDOW (transient_parent));
       gtk_window_present (GTK_WINDOW (editor));
       return;
     }
@@ -1220,7 +1198,5 @@ terminal_profile_edit (GSettings  *profile,
 
   terminal_util_dialog_focus_widget (editor, widget_name);
 
-  gtk_window_set_transient_for (GTK_WINDOW (editor),
-                                GTK_WINDOW (transient_parent));
   gtk_window_present (GTK_WINDOW (editor));
 }
diff --git a/src/profile-editor.h b/src/profile-editor.h
index b538b74..bddb95c 100644
--- a/src/profile-editor.h
+++ b/src/profile-editor.h
@@ -24,7 +24,6 @@
 G_BEGIN_DECLS
 
 void terminal_profile_edit (GSettings  *profile,
-                            GtkWindow  *transient_parent,
                             const char *widget_name);
 
 G_END_DECLS
diff --git a/src/server.c b/src/server.c
index d516cbb..ac89ca7 100644
--- a/src/server.c
+++ b/src/server.c
@@ -100,13 +100,11 @@ increase_rlimit_nofile (void)
   return TRUE;
 }
 
-int
-main (int argc, char **argv)
+static int
+init_server (int argc,
+             char *argv[],
+             GApplication **application)
 {
-  gs_unref_object GApplication *app = NULL;
-  const char *home_dir, *charset;
-  GError *error = NULL;
-
   if (G_UNLIKELY ((getuid () != geteuid () ||
                   getgid () != getegid ()) &&
                   geteuid () == 0 &&
@@ -121,7 +119,7 @@ main (int argc, char **argv)
   }
 
   terminal_i18n_init (TRUE);
-
+  const char *charset;
   if (!g_get_charset (&charset)) {
     g_printerr ("Non UTF-8 locale (%s) is not supported!\n", charset);
     return _EXIT_FAILURE_NO_UTF8;
@@ -134,36 +132,38 @@ main (int argc, char **argv)
   if (g_getenv ("G_ENABLE_DIAGNOSTIC") == NULL)
     g_setenv ("G_ENABLE_DIAGNOSTIC", "0", TRUE);
 
-#ifndef ENABLE_DISTRO_PACKAGING
 #ifdef HAVE_UBUNTU
+#ifndef ENABLE_DISTRO_PACKAGING
   /* Set some env vars to disable the ubuntu modules. Their package will be 
    * built using --enable-distro-packaging, but anyone running from git will
    * get the right behaviour.
    */
   g_setenv ("LIBOVERLAY_SCROLLBAR", "0", TRUE);
+#endif
   g_setenv ("UBUNTU_MENUPROXY", "0", TRUE);
   g_setenv ("NO_UNITY_GTK_MODULE", "1", TRUE);
 #endif
-#endif
 
   _terminal_debug_init ();
 
-  // FIXMEchpe: just use / here but make sure #565328 doesn't regress
   /* Change directory to $HOME so we don't prevent unmounting, e.g. if the
    * factory is started by nautilus-open-terminal. See bug #565328.
    * On failure back to /.
    */
-  home_dir = g_get_home_dir ();
+  const char *home_dir = g_get_home_dir ();
   if (home_dir == NULL || chdir (home_dir) < 0)
     (void) chdir ("/");
 
   g_set_prgname ("gnome-terminal-server");
   g_set_application_name (_("Terminal"));
 
+  GError *error = NULL;
   if (!gtk_init_with_args (&argc, &argv, NULL, options, NULL, &error)) {
-    g_printerr ("Failed to parse arguments: %s\n", error->message);
-    g_error_free (error);
-    exit (_EXIT_FAILURE_GTK_INIT);
+    if (error != NULL) {
+      g_printerr ("Failed to parse arguments: %s\n", error->message);
+      g_error_free (error);
+    }
+    return _EXIT_FAILURE_GTK_INIT;
   }
 
   if (!increase_rlimit_nofile ()) {
@@ -171,11 +171,25 @@ main (int argc, char **argv)
   }
 
   /* Now we can create the app */
-  app = terminal_app_new (app_id);
+  GApplication *app = terminal_app_new (app_id);
   g_free (app_id);
+  app_id = NULL;
 
   /* We stay around a bit after the last window closed */
   g_application_set_inactivity_timeout (app, INACTIVITY_TIMEOUT);
 
+  *application = app;
+  return 0;
+}
+
+int
+main (int argc,
+      char *argv[])
+{
+  gs_unref_object GApplication *app = NULL;
+  int r = init_server (argc, argv, &app);
+  if (r != 0)
+    return r;
+
   return g_application_run (app, 0, NULL);
 }
diff --git a/src/terminal-accels.c b/src/terminal-accels.c
index 3adbfc7..1ea02ce 100644
--- a/src/terminal-accels.c
+++ b/src/terminal-accels.c
@@ -54,6 +54,7 @@
 #define KEY_COPY                "copy"
 #define KEY_COPY_HTML           "copy-html"
 #define KEY_DETACH_TAB          "detach-tab"
+#define KEY_EXPORT              "export"
 #define KEY_FIND                "find"
 #define KEY_FIND_CLEAR          "find-clear"
 #define KEY_FIND_PREV           "find-previous"
@@ -69,6 +70,7 @@
 #define KEY_PASTE               "paste"
 #define KEY_PREFERENCES         "preferences"
 #define KEY_PREV_TAB            "prev-tab"
+#define KEY_PRINT               "print"
 #define KEY_PROFILE_PREFERENCES "profile-preferences"
 #define KEY_READ_ONLY           "read-only"
 #define KEY_RESET_AND_CLEAR     "reset-and-clear"
@@ -81,40 +83,6 @@
 #define KEY_ZOOM_OUT            "zoom-out"
 #define KEY_SWITCH_TAB_PREFIX   "switch-to-tab-"
 
-/* Accel paths for the gtkuimanager based menus */
-#define ACCEL_PATH_ROOT "<Actions>/Main/"
-#define ACCEL_PATH_KEY_CLOSE_TAB            ACCEL_PATH_ROOT "FileCloseTab"
-#define ACCEL_PATH_KEY_CLOSE_WINDOW         ACCEL_PATH_ROOT "FileCloseWindow"
-#define ACCEL_PATH_KEY_COPY                 ACCEL_PATH_ROOT "EditCopy"
-#define ACCEL_PATH_KEY_COPY_HTML            ACCEL_PATH_ROOT "EditCopyHtml"
-#define ACCEL_PATH_KEY_DETACH_TAB           ACCEL_PATH_ROOT "TabsDetach"
-#define ACCEL_PATH_KEY_FIND                 ACCEL_PATH_ROOT "SearchFind"
-#define ACCEL_PATH_KEY_FIND_CLEAR           ACCEL_PATH_ROOT "SearchClearHighlight"
-#define ACCEL_PATH_KEY_FIND_PREV            ACCEL_PATH_ROOT "SearchFindPrevious"
-#define ACCEL_PATH_KEY_FIND_NEXT            ACCEL_PATH_ROOT "SearchFindNext"
-#define ACCEL_PATH_KEY_FULL_SCREEN          ACCEL_PATH_ROOT "ViewFullscreen"
-#define ACCEL_PATH_KEY_HELP                 ACCEL_PATH_ROOT "HelpContents"
-#define ACCEL_PATH_KEY_MOVE_TAB_LEFT        ACCEL_PATH_ROOT "TabsMoveLeft"
-#define ACCEL_PATH_KEY_MOVE_TAB_RIGHT       ACCEL_PATH_ROOT "TabsMoveRight"
-#define ACCEL_PATH_KEY_NEW_PROFILE          ACCEL_PATH_ROOT "FileNewProfile"
-#define ACCEL_PATH_KEY_NEW_TAB              ACCEL_PATH_ROOT "FileNewTab"
-#define ACCEL_PATH_KEY_NEW_WINDOW           ACCEL_PATH_ROOT "FileNewWindow"
-#define ACCEL_PATH_KEY_NEXT_TAB             ACCEL_PATH_ROOT "TabsNext"
-#define ACCEL_PATH_KEY_PASTE                ACCEL_PATH_ROOT "EditPaste"
-#define ACCEL_PATH_KEY_PREFERENCES          ACCEL_PATH_ROOT "EditPreferences"
-#define ACCEL_PATH_KEY_PREV_TAB             ACCEL_PATH_ROOT "TabsPrevious"
-#define ACCEL_PATH_KEY_PROFILE_PREFERENCES  ACCEL_PATH_ROOT "EditCurrentProfile"
-#define ACCEL_PATH_KEY_READ_ONLY            ACCEL_PATH_ROOT "TerminalReadOnly"
-#define ACCEL_PATH_KEY_RESET                ACCEL_PATH_ROOT "TerminalReset"
-#define ACCEL_PATH_KEY_RESET_AND_CLEAR      ACCEL_PATH_ROOT "TerminalResetClear"
-#define ACCEL_PATH_KEY_SAVE_CONTENTS        ACCEL_PATH_ROOT "FileSaveContents"
-#define ACCEL_PATH_KEY_SELECT_ALL           ACCEL_PATH_ROOT "EditSelectAll"
-#define ACCEL_PATH_KEY_TOGGLE_MENUBAR       ACCEL_PATH_ROOT "ViewMenubar"
-#define ACCEL_PATH_KEY_ZOOM_IN              ACCEL_PATH_ROOT "ViewZoomIn"
-#define ACCEL_PATH_KEY_ZOOM_NORMAL          ACCEL_PATH_ROOT "ViewZoom100"
-#define ACCEL_PATH_KEY_ZOOM_OUT             ACCEL_PATH_ROOT "ViewZoomOut"
-#define ACCEL_PATH_KEY_SWITCH_TAB_PREFIX    ACCEL_PATH_ROOT "TabsSwitch"
-
 #if 1
 /*
 * We don't want to enable content saving until vte supports it async.
@@ -137,11 +105,7 @@ typedef struct
   const GVariantType *action_parameter_type;
   const char *action_parameter;
   GVariant *parameter;
-  gboolean installed;
-#if 1
-  /* Legacy gtkuimanager menu accelerator */
-  const char *legacy_accel_path;
-#endif
+  const char *shadow_action_name;
 } KeyEntry;
 
 typedef struct
@@ -151,42 +115,52 @@ typedef struct
   const char *user_visible_name;
 } KeyEntryList;
 
+#define ENTRY_FULL(name, key, action, type, parameter, shadow_name) \
+  { name, key, "win." action, (const GVariantType *) type, parameter, NULL, shadow_name }
 #define ENTRY(name, key, action, type, parameter) \
-  { name, key, "win." action, (const GVariantType *) type, parameter, NULL, FALSE, ACCEL_PATH_##key }
+  ENTRY_FULL (name, key, action, type, parameter, "win.shadow")
+#define ENTRY_MDI(name, key, action, type, parameter) \
+  ENTRY_FULL (name, key, action, type, parameter, "win.shadow-mdi")
 
 static KeyEntry file_entries[] = {
-  ENTRY (N_("New Terminal in New Tab"),    KEY_NEW_TAB,       "new-terminal",  "(ss)",  "('tab','current')"  
 ),
-  ENTRY (N_("New Terminal in New Window"), KEY_NEW_WINDOW,    "new-terminal",  "(ss)",  
"('window','current')"),
-  ENTRY (N_("New Profile"),                KEY_NEW_PROFILE,   "new-profile",   NULL,    NULL                 
 ),
+  ENTRY (N_("New Tab"),       KEY_NEW_TAB,       "new-terminal",  "(ss)",  "('tab','current')"   ),
+  ENTRY (N_("New Window"),    KEY_NEW_WINDOW,    "new-terminal",  "(ss)",  "('window','current')"),
+  ENTRY (N_("New Profile"),   KEY_NEW_PROFILE,   "new-profile",   NULL,    NULL                  ),
 #ifdef ENABLE_SAVE
-  ENTRY (N_("Save Contents"),              KEY_SAVE_CONTENTS, "save-contents", NULL,    NULL                 
 ),
+  ENTRY (N_("Save Contents"), KEY_SAVE_CONTENTS, "save-contents", NULL,    NULL                  ),
+#endif
+#ifdef ENABLE_EXPORT
+  ENTRY (N_("Export"),        KEY_EXPORT,        "export",        NULL,    NULL                  ),
 #endif
-  ENTRY (N_("Close Terminal"),             KEY_CLOSE_TAB,     "close",         "s",     "'tab'"              
 ),
-  ENTRY (N_("Close All Terminals"),        KEY_CLOSE_WINDOW,  "close",         "s",     "'window'"           
 ),
+#ifdef ENABLE_PRINT
+  ENTRY (N_("Print"),         KEY_PRINT,         "print",         NULL,    NULL                  ),
+#endif
+  ENTRY (N_("Close Tab"),     KEY_CLOSE_TAB,     "close",         "s",     "'tab'"               ),
+  ENTRY (N_("Close Window"),  KEY_CLOSE_WINDOW,  "close",         "s",     "'window'"            ),
 };
 
 static KeyEntry edit_entries[] = {
   ENTRY (N_("Copy"),                KEY_COPY,                "copy",         "s", "'text'"   ),
   ENTRY (N_("Copy as HTML"),        KEY_COPY_HTML,           "copy",         "s", "'html'"   ),
-  ENTRY (N_("Paste"),               KEY_PASTE,               "paste",        "s",  "'normal'"),
+  ENTRY (N_("Paste"),               KEY_PASTE,               "paste-text",   NULL, NULL      ),
   ENTRY (N_("Select All"),          KEY_SELECT_ALL,          "select-all",   NULL, NULL      ),
-  ENTRY (N_("Preferences"),         KEY_PREFERENCES,         "preferences",  NULL, NULL      ),
+  ENTRY (N_("Preferences"),         KEY_PREFERENCES,         "edit-preferences",  NULL, NULL      ),
   ENTRY (N_("Profile Preferences"), KEY_PROFILE_PREFERENCES, "edit-profile", NULL, NULL      ),
 };
 
 static KeyEntry find_entries[] = {
-  ENTRY (N_("Find"),                 KEY_FIND,       "find", "s", "'find'"    ),
-  ENTRY (N_("Find Next"),            KEY_FIND_NEXT,  "find", "s", "'next'"    ),
-  ENTRY (N_("Find Previous"),        KEY_FIND_PREV,  "find", "s", "'previous'"),
-  ENTRY (N_("Clear Find Highlight"), KEY_FIND_CLEAR, "find", "s", "'clear'"   )
+  ENTRY (N_("Find"),            KEY_FIND,       "find",          NULL, NULL),
+  ENTRY (N_("Find Next"),       KEY_FIND_NEXT,  "find-forward",  NULL, NULL),
+  ENTRY (N_("Find Previous"),   KEY_FIND_PREV,  "find-backward", NULL, NULL),
+  ENTRY (N_("Clear Highlight"), KEY_FIND_CLEAR, "find-clear",    NULL, NULL)
 };
 
 static KeyEntry view_entries[] = {
-  ENTRY (N_("Hide and Show toolbar"), KEY_TOGGLE_MENUBAR, "show-menubar", NULL, NULL),
+  ENTRY (N_("Hide and Show Menubar"), KEY_TOGGLE_MENUBAR, "show-menubar", NULL, NULL),
   ENTRY (N_("Full Screen"),           KEY_FULL_SCREEN,    "fullscreen",   NULL, NULL),
-  ENTRY (N_("Zoom In"),               KEY_ZOOM_IN,        "zoom",         "i",  "1" ),
-  ENTRY (N_("Zoom Out"),              KEY_ZOOM_OUT,       "zoom",         "i",  "-1"),
-  ENTRY (N_("Normal Size"),           KEY_ZOOM_NORMAL,    "zoom",         "i",  "0" )
+  ENTRY (N_("Zoom In"),               KEY_ZOOM_IN,        "zoom-in",      NULL, NULL),
+  ENTRY (N_("Zoom Out"),              KEY_ZOOM_OUT,       "zoom-out",     NULL, NULL),
+  ENTRY (N_("Normal Size"),           KEY_ZOOM_NORMAL,    "zoom-normal",  NULL, NULL)
 };
 
 static KeyEntry terminal_entries[] = {
@@ -196,37 +170,56 @@ static KeyEntry terminal_entries[] = {
 };
 
 static KeyEntry tabs_entries[] = {
-  ENTRY (N_("Switch to Previous Terminal"), KEY_PREV_TAB,       "switch-tab", "i",  "-2"),
-  ENTRY (N_("Switch to Next Terminal"),     KEY_NEXT_TAB,       "switch-tab", "i",  "-1"),
-  ENTRY (N_("Move Terminal to the Left"),   KEY_MOVE_TAB_LEFT,  "move-tab",   "i",  "-1"),
-  ENTRY (N_("Move Terminal to the Right"),  KEY_MOVE_TAB_RIGHT, "move-tab",   "i",  "1" ),
-  ENTRY (N_("Detach Terminal"),             KEY_DETACH_TAB,     "detach-tab", NULL, NULL),
-
-#define SWITCH_TAB_ENTRY(num) \
-  ENTRY (NULL, \
-         KEY_SWITCH_TAB_PREFIX # num, \
-         "switch-tab", \
-         "i", \
-         # num)
-
-  SWITCH_TAB_ENTRY (1),  SWITCH_TAB_ENTRY (2),  SWITCH_TAB_ENTRY (3),  SWITCH_TAB_ENTRY (4),
-  SWITCH_TAB_ENTRY (5),  SWITCH_TAB_ENTRY (6),  SWITCH_TAB_ENTRY (7),  SWITCH_TAB_ENTRY (8),
-  SWITCH_TAB_ENTRY (9),  SWITCH_TAB_ENTRY (10), SWITCH_TAB_ENTRY (11), SWITCH_TAB_ENTRY (12),
-  SWITCH_TAB_ENTRY (13), SWITCH_TAB_ENTRY (14), SWITCH_TAB_ENTRY (15), SWITCH_TAB_ENTRY (16),
-  SWITCH_TAB_ENTRY (17), SWITCH_TAB_ENTRY (18), SWITCH_TAB_ENTRY (19), SWITCH_TAB_ENTRY (20),
-  SWITCH_TAB_ENTRY (21), SWITCH_TAB_ENTRY (22), SWITCH_TAB_ENTRY (23), SWITCH_TAB_ENTRY (24),
-  SWITCH_TAB_ENTRY (25), SWITCH_TAB_ENTRY (26), SWITCH_TAB_ENTRY (27), SWITCH_TAB_ENTRY (28),
-  SWITCH_TAB_ENTRY (29), SWITCH_TAB_ENTRY (30), SWITCH_TAB_ENTRY (31), SWITCH_TAB_ENTRY (32),
-  SWITCH_TAB_ENTRY (33), SWITCH_TAB_ENTRY (34), SWITCH_TAB_ENTRY (35)
-
-#undef SWITCH_TAB_ENTRY
+  ENTRY_MDI (N_("Switch to Previous Tab"), KEY_PREV_TAB,       "tab-switch-left",  NULL, NULL),
+  ENTRY_MDI (N_("Switch to Next Tab"),     KEY_NEXT_TAB,       "tab-switch-right", NULL, NULL),
+  ENTRY_MDI (N_("Move Tab to the Left"),   KEY_MOVE_TAB_LEFT,  "tab-move-left",    NULL, NULL),
+  ENTRY_MDI (N_("Move Tab to the Right"),  KEY_MOVE_TAB_RIGHT, "tab-move-right",   NULL, NULL),
+  ENTRY_MDI (N_("Detach Tab"),             KEY_DETACH_TAB,     "tab-detach",       NULL, NULL),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "1", "active-tab", "i", "0"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "2", "active-tab", "i", "1"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "3", "active-tab", "i", "2"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "4", "active-tab", "i", "3"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "5", "active-tab", "i", "4"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "6", "active-tab", "i", "5"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "7", "active-tab", "i", "6"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "8", "active-tab", "i", "7"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "9", "active-tab", "i", "8"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "10", "active-tab", "i", "9"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "11", "active-tab", "i", "10"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "12", "active-tab", "i", "11"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "13", "active-tab", "i", "12"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "14", "active-tab", "i", "13"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "15", "active-tab", "i", "14"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "16", "active-tab", "i", "15"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "17", "active-tab", "i", "16"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "18", "active-tab", "i", "17"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "19", "active-tab", "i", "18"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "20", "active-tab", "i", "19"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "21", "active-tab", "i", "20"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "22", "active-tab", "i", "21"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "23", "active-tab", "i", "22"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "24", "active-tab", "i", "23"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "25", "active-tab", "i", "24"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "26", "active-tab", "i", "25"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "27", "active-tab", "i", "26"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "28", "active-tab", "i", "27"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "29", "active-tab", "i", "28"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "30", "active-tab", "i", "29"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "31", "active-tab", "i", "30"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "32", "active-tab", "i", "31"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "33", "active-tab", "i", "32"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "34", "active-tab", "i", "33"),
+  ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "35", "active-tab", "i", "34"),
+  ENTRY_MDI (N_("Switch to Last Tab"), KEY_SWITCH_TAB_PREFIX "last", "active-tab", "i", "-1"),
 };
 
 static KeyEntry help_entries[] = {
   ENTRY (N_("Contents"), KEY_HELP, "help", NULL, NULL)
 };
 
+#undef ENTRY_FULL
 #undef ENTRY
+#undef ENTRY_MDI
 
 static KeyEntryList all_entries[] =
 {
@@ -268,14 +261,12 @@ key_changed_cb (GSettings *settings,
                 gpointer user_data)
 {
   GtkApplication *application = user_data;
-  KeyEntry *key_entry;
-  gs_free char *value = NULL;
 
   _terminal_debug_print (TERMINAL_DEBUG_ACCELS,
                          "key %s changed\n",
                          settings_key);
 
-  key_entry = g_hash_table_lookup (settings_key_to_entry, settings_key);
+  KeyEntry *key_entry = g_hash_table_lookup (settings_key_to_entry, settings_key);
   if (!key_entry)
     {
       /* shouldn't really happen, but let's be safe */
@@ -284,34 +275,38 @@ key_changed_cb (GSettings *settings,
       return;
     }
 
-  value = g_settings_get_string (settings, settings_key);
+  gs_free char *value = g_settings_get_string (settings, settings_key);
+
+  gs_free char *detailed = g_action_print_detailed_name (key_entry->action_name,
+                                                         key_entry->parameter);
+  gs_unref_variant GVariant *shadow_parameter = g_variant_new_string (detailed);
+
+  /* We want to always consume the action's accelerators, even if the corresponding
+   * action is insensitive, so the corresponding shortcut key escape code isn't sent
+   * to the terminal. See bug #453193, bug #138609, and bug #559728.
+   * Since GtkApplication's accelerators don't use GtkAccelGroup, we have no way
+   * to intercept/chain on its activation. The only way to do this that I found
+   * was to install an extra action with the same accelerator that shadows
+   * the real action and gets activated when the shadowed action is disabled.
+   */
 
   if (g_str_equal (value, "disabled")) {
-    if (key_entry->installed)
-      gtk_application_remove_accelerator (application,
-                                          key_entry->action_name,
-                                          key_entry->parameter);
-    key_entry->installed = FALSE;
+    gtk_application_remove_accelerator (application,
+                                        key_entry->action_name,
+                                        key_entry->parameter);
+    gtk_application_remove_accelerator (application,
+                                        key_entry->shadow_action_name,
+                                        shadow_parameter);
   } else {
     gtk_application_add_accelerator (application,
                                      value,
                                      key_entry->action_name,
                                      key_entry->parameter);
-    key_entry->installed = TRUE;
-  }
-
-#if 1
-  /* Legacy gtkuimanager menu accelerator */
-  {
-    GdkModifierType mods = 0;
-    guint key = 0;
-
-    if (!g_str_equal (value, "disabled"))
-      gtk_accelerator_parse (value, &key, &mods);
-
-    gtk_accel_map_change_entry (key_entry->legacy_accel_path, key, mods, TRUE);
+    gtk_application_add_accelerator (application,
+                                     value,
+                                     key_entry->shadow_action_name,
+                                     shadow_parameter);
   }
-#endif
 }
 
 void
diff --git a/src/terminal-app.c b/src/terminal-app.c
index 6c783bc..e611a70 100644
--- a/src/terminal-app.c
+++ b/src/terminal-app.c
@@ -3,7 +3,7 @@
  * Copyright © 2002 Red Hat, Inc.
  * Copyright © 2002 Sun Microsystems
  * Copyright © 2003 Mariano Suarez-Alvarez
- * Copyright © 2008, 2010, 2011, 2015 Christian Persch
+ * Copyright © 2008, 2010, 2011, 2015, 2017 Christian Persch
  *
  * 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
@@ -19,12 +19,15 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <config.h>
+#include "config.h"
 
 #include <glib.h>
 #include <glib/gi18n.h>
 #include <gio/gio.h>
 
+#define G_SETTINGS_ENABLE_BACKEND
+#include <gio/gsettingsbackend.h>
+
 #include "terminal-intl.h"
 #include "terminal-debug.h"
 #include "terminal-app.h"
@@ -74,7 +77,8 @@
 struct _TerminalAppClass {
   GtkApplicationClass parent_class;
 
-  void (* encoding_list_changed) (TerminalApp *app);
+  void (* clipboard_targets_changed) (TerminalApp *app,
+                                      GtkClipboard *clipboard);
 };
 
 struct _TerminalApp
@@ -85,9 +89,6 @@ struct _TerminalApp
 
   TerminalSettingsList *profiles_list;
 
-  GHashTable *encodings;
-  gboolean encodings_locked;
-
   GHashTable *screen_map;
 
   GSettings *global_settings;
@@ -98,16 +99,104 @@ struct _TerminalApp
 #ifdef ENABLE_SEARCH_PROVIDER
   TerminalSearchProvider *search_provider;
 #endif /* ENABLE_SEARCH_PROVIDER */
+
+  GMenuModel *menubar;
+  GMenu *menubar_new_terminal_section;
+  GMenu *menubar_set_profile_section;
+  GMenu *menubar_set_encoding_submenu;
+  GMenu *set_profile_menu;
+
+  GtkClipboard *clipboard;
+  GdkAtom *clipboard_targets;
+  int n_clipboard_targets;
 };
 
 enum
 {
-  ENCODING_LIST_CHANGED,
+  CLIPBOARD_TARGETS_CHANGED,
   LAST_SIGNAL
 };
 
 static guint signals[LAST_SIGNAL];
 
+/* Debugging helper */
+
+static void
+terminal_app_init_debug (void)
+{
+#ifdef ENABLE_DEBUG
+  const char *env = g_getenv ("GTK_TEXT_DIR");
+  if (env != NULL) {
+    if (g_str_equal (env, "help")) {
+      g_printerr ("Usage: GTK_TEXT_DIR=ltr|rtl\n");
+    } else {
+      GtkTextDirection dir;
+      if (g_str_equal (env, "rtl"))
+        dir = GTK_TEXT_DIR_RTL;
+      else
+        dir = GTK_TEXT_DIR_LTR;
+
+      gtk_widget_set_default_direction (dir);
+    }
+  }
+
+  env = g_getenv ("GTK_SETTINGS");
+  if (env == NULL)
+    return;
+
+  GObject *settings = G_OBJECT (gtk_settings_get_default ());
+  GObjectClass *settings_class = G_OBJECT_GET_CLASS (settings);
+
+  if (g_str_equal (env, "help")) {
+    g_printerr ("Usage: GTK_SETTINGS=setting[,setting…] where 'setting' is one of these:\n");
+
+    guint n_props;
+    GParamSpec **props = g_object_class_list_properties (settings_class, &n_props);
+    for (guint i = 0; i < n_props; i++) {
+      if (G_PARAM_SPEC_VALUE_TYPE (props[i]) != G_TYPE_BOOLEAN)
+        continue;
+
+      GValue value = { 0, };
+      g_value_init (&value, G_TYPE_BOOLEAN);
+      g_object_get_property (settings, props[i]->name, &value);
+      g_printerr ("  %s (%s)\n", props[i]->name, g_value_get_boolean (&value) ? "true" : "false");
+      g_value_unset (&value);
+    }
+    g_printerr ("  Use 'setting' to set to true, "
+                "'~setting' to set to false, "
+                "and '!setting' to invert.\n");
+  } else {
+    gs_strfreev char **tokens = g_strsplit (env, ",", -1);
+    for (guint i = 0; tokens[i] != NULL; i++) {
+      const char *prop = tokens[i];
+      char c = prop[0];
+      if (c == '~' || c == '!')
+        prop++;
+
+      GParamSpec *pspec = g_object_class_find_property (settings_class, prop);
+      if (pspec == NULL) {
+        g_printerr ("Setting \"%s\" does not exist.\n", prop);
+      } else if (G_PARAM_SPEC_VALUE_TYPE (pspec) != G_TYPE_BOOLEAN) {
+        g_printerr ("Setting \"%s\" is not boolean.\n", prop);
+      } else {
+        GValue value = { 0, };
+        g_value_init (&value, G_TYPE_BOOLEAN);
+        if (c == '!') {
+          g_object_get_property (settings, pspec->name, &value);
+          g_value_set_boolean (&value, !g_value_get_boolean (&value));
+        } else if (c == '~') {
+          g_value_set_boolean (&value, FALSE);
+        } else {
+          g_value_set_boolean (&value, TRUE);
+        }
+        g_object_set_property (settings, pspec->name, &value);
+        g_value_unset (&value);
+      }
+    }
+  }
+#endif
+}
+
 /* Helper functions */
 
 static void
@@ -134,6 +223,14 @@ maybe_migrate_settings (TerminalApp *app)
   }
 
 #ifdef ENABLE_MIGRATION
+  /* Only do migration if the settings backend is dconf */
+  GType type = G_OBJECT_TYPE (g_settings_backend_get_default ());
+  if (!g_type_is_a (type, g_type_from_name ("DConfSettingsBackend"))) {
+    _terminal_debug_print (TERMINAL_DEBUG_SERVER | TERMINAL_DEBUG_PROFILE,
+                           "Not migration settings to %s\n", g_type_name (type));
+    goto done;
+  }
+
   if (!g_spawn_sync (NULL /* our home directory */,
                      (char **) argv,
                      NULL /* envv */,
@@ -152,11 +249,11 @@ maybe_migrate_settings (TerminalApp *app)
   } else {
     g_printerr ("Profile migrator exited abnormally.\n");
   }
-#else
+done:
+#endif /* ENABLE_MIGRATION */
   g_settings_set_uint (terminal_app_get_global_settings (app),
                        TERMINAL_SETTING_SCHEMA_VERSION,
                        TERMINAL_SCHEMA_VERSION);
-#endif /* ENABLE_MIGRATION */
 }
 
 static gboolean
@@ -215,8 +312,7 @@ app_load_css (GApplication *application)
 
 void
 terminal_app_new_profile (TerminalApp *app,
-                          GSettings   *base_profile,
-                          GtkWindow   *transient_parent)
+                          GSettings   *base_profile)
 {
   gs_unref_object GSettings *profile = NULL;
   gs_free char *uuid;
@@ -237,99 +333,288 @@ terminal_app_new_profile (TerminalApp *app,
   if (profile == NULL)
     return;
 
-  terminal_profile_edit (profile, NULL, "profile-name-entry");
+  terminal_profile_edit (profile, "profile-name-entry");
 }
 
 void
 terminal_app_remove_profile (TerminalApp *app,
                              GSettings *profile)
 {
-  gs_free char *uuid;
+  g_return_if_fail (TERMINAL_IS_APP (app));
+  g_return_if_fail (G_IS_SETTINGS (profile));
+
+  gs_unref_object GSettings *default_profile = terminal_settings_list_ref_default_child (app->profiles_list);
+  if (default_profile == profile)
+    return;
+
+  /* First, we need to switch any screen using this profile to the default profile */
+  gs_free_list GList *screens = g_hash_table_get_values (app->screen_map);
+  for (GList *l = screens; l != NULL; l = l->next) {
+    TerminalScreen *screen = TERMINAL_SCREEN (l->data);
+    if (terminal_screen_get_profile (screen) != profile)
+      continue;
+
+    terminal_screen_set_profile (screen, default_profile);
+  }
 
-  uuid = terminal_settings_list_dup_uuid_from_child (app->profiles_list, profile);
+  /* Now we can safely remove the profile */
+  gs_free char *uuid = terminal_settings_list_dup_uuid_from_child (app->profiles_list, profile);
   terminal_settings_list_remove_child (app->profiles_list, uuid);
 }
 
-gboolean
-terminal_app_can_remove_profile (TerminalApp *app,
-                                 GSettings *profile)
+#if GTK_CHECK_VERSION (3, 19, 0)
+static void
+terminal_app_theme_variant_changed_cb (GSettings   *settings,
+                                       const char  *key,
+                                       GtkSettings *gtk_settings)
 {
-  return TRUE;
+  TerminalThemeVariant theme;
+
+  theme = g_settings_get_enum (settings, key);
+  if (theme == TERMINAL_THEME_VARIANT_SYSTEM)
+    gtk_settings_reset_property (gtk_settings, GTK_SETTING_PREFER_DARK_THEME);
+  else
+    g_object_set (gtk_settings,
+                  GTK_SETTING_PREFER_DARK_THEME,
+                  theme == TERMINAL_THEME_VARIANT_DARK,
+                  NULL);
+}
+#endif /* GTK+ 3.19 */
+
+/* Submenus for New Terminal per profile, and to change profiles */
+
+static void terminal_app_update_profile_menus (TerminalApp *app);
+
+typedef struct {
+  char *uuid;
+  char *label;
+} ProfileData;
+
+static void
+profile_data_clear (ProfileData *data)
+{
+  g_free (data->uuid);
+  g_free (data->label);
+}
+
+typedef struct {
+  GArray *array;
+  TerminalApp *app;
+} ProfilesForeachData;
+
+static void
+foreach_profile_cb (TerminalSettingsList *list,
+                    const char *uuid,
+                    GSettings *profile,
+                    ProfilesForeachData *user_data)
+{
+  ProfileData data;
+  data.uuid = g_strdup (uuid);
+  data.label = g_settings_get_string (profile, TERMINAL_PROFILE_VISIBLE_NAME_KEY);
+
+  g_array_append_val (user_data->array, data);
+
+  /* only connect if we haven't seen this profile before */
+  if (g_signal_handler_find (profile, G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
+                             0, 0, NULL, terminal_app_update_profile_menus, user_data->app) == 0)
+    g_signal_connect_swapped (profile, "changed::" TERMINAL_PROFILE_VISIBLE_NAME_KEY,
+                              G_CALLBACK (terminal_app_update_profile_menus), user_data->app);
 }
 
 static int
-compare_encodings (TerminalEncoding *a,
-                   TerminalEncoding *b)
+compare_profile_label_cb (gconstpointer ap,
+                          gconstpointer bp)
 {
-  return g_utf8_collate (a->name, b->name);
+  const ProfileData *a = ap;
+  const ProfileData *b = bp;
+
+  return g_utf8_collate (a->label, b->label);
 }
 
 static void
-encoding_mark_active (gpointer key,
-                      gpointer value,
-                      gpointer data)
+menu_append_numbered (GMenu *menu,
+                      const char *label,
+                      int num,
+                      const char *action_name,
+                      GVariant *target)
 {
-  TerminalEncoding *encoding = (TerminalEncoding *) value;
-  guint active = GPOINTER_TO_UINT (data);
+  gs_free_gstring GString *str;
+  gs_unref_object GMenuItem *item;
+  const char *p;
+
+  /* Who'd use more that 4 underscores in a profile name... */
+  str = g_string_sized_new (strlen (label) + 4 + 1 + 8);
+
+  if (num < 10)
+    g_string_append_printf (str, "%Id. ", num);
+  else if (num < 36)
+    g_string_append_printf (str, "%c. ",  (char)('A' + num - 10));
+
+  /* Append the label with underscores elided */
+  for (p = label; *p; p++) {
+    if (*p == '_')
+      g_string_append (str, "__");
+    else
+      g_string_append_c (str, *p);
+  }
 
-  encoding->is_active = active;
+  item = g_menu_item_new (str->str, NULL);
+  g_menu_item_set_action_and_target_value (item, action_name, target);
+  g_menu_append_item (menu, item);
 }
 
 static void
-terminal_app_encoding_list_notify_cb (GSettings   *settings,
-                                      const char  *key,
-                                      TerminalApp *app)
-{
-  gs_strfreev char **encodings = NULL;
-  int i;
-  TerminalEncoding *encoding;
-
-  app->encodings_locked = !g_settings_is_writable (settings, key);
-
-  /* Mark all as non-active, then re-enable the active ones */
-  g_hash_table_foreach (app->encodings, (GHFunc) encoding_mark_active, GUINT_TO_POINTER (FALSE));
-
-  /* Also always make UTF-8 available */
-  encoding = g_hash_table_lookup (app->encodings, "UTF-8");
-  g_assert (encoding);
-  g_assert (terminal_encoding_is_valid (encoding));
-  encoding->is_active = TRUE;
-
-  g_settings_get (settings, key, "^as", &encodings);
-  for (i = 0; encodings[i] != NULL; ++i)
-    {
-      /* Pre-3.13, not supported anymore */
-      if (g_str_equal (encodings[i], "current"))
-        continue;
+append_new_terminal_item (GMenu *section,
+                          const char *label,
+                          const char *target,
+                          ProfileData *data,
+                          guint n_profiles)
+{
+  gs_unref_object GMenuItem *item = g_menu_item_new (label, NULL);
 
-      encoding = terminal_app_ensure_encoding (app, encodings[i]);
-      if (!terminal_encoding_is_valid (encoding))
-        continue;
+  if (n_profiles > 1) {
+    gs_unref_object GMenu *submenu = g_menu_new ();
 
-      encoding->is_active = TRUE;
+    for (guint i = 0; i < n_profiles; i++) {
+      menu_append_numbered (submenu, data[i].label, i + 1,
+                            "win.new-terminal",
+                            g_variant_new ("(ss)", target, data[i].uuid));
     }
 
-  g_signal_emit (app, signals[ENCODING_LIST_CHANGED], 0);
+    g_menu_item_set_link (item, G_MENU_LINK_SUBMENU, G_MENU_MODEL (submenu));
+  } else {
+    g_menu_item_set_action_and_target (item, "win.new-terminal",
+                                       "(ss)", target, "default");
+  }
+  g_menu_append_item (section, item);
 }
 
-#if GTK_CHECK_VERSION (3, 19, 0)
 static void
-terminal_app_theme_variant_changed_cb (GSettings   *settings,
-                                       const char  *key,
-                                       GtkSettings *gtk_settings)
+fill_new_terminal_section (GMenu *section,
+                           ProfileData *profiles,
+                           guint n_profiles)
 {
-  TerminalThemeVariant theme;
+#ifndef DISUNIFY_NEW_TERMINAL_SECTION
+  append_new_terminal_item (section, _("New _Terminal"), "default", profiles, n_profiles);
+#else
+  append_new_terminal_item (section, _("New _Tab"), "tab", profiles, n_profiles);
+  append_new_terminal_item (section, _("New _Window"), "window", profiles, n_profiles);
+#endif
+}
 
-  theme = g_settings_get_enum (settings, key);
-  if (theme == TERMINAL_THEME_VARIANT_SYSTEM)
-    gtk_settings_reset_property (gtk_settings, GTK_SETTING_PREFER_DARK_THEME);
-  else
-    g_object_set (gtk_settings,
-                  GTK_SETTING_PREFER_DARK_THEME,
-                  theme == TERMINAL_THEME_VARIANT_DARK,
-                  NULL);
+static GMenu *
+set_profile_submenu_new (ProfileData *data,
+                         guint n_profiles)
+{
+  GMenu *menu = g_menu_new ();
+
+  /* No submenu if there's only one profile */
+  if (n_profiles <= 1)
+    return NULL;
+
+  for (guint i = 0; i < n_profiles; i++) {
+    menu_append_numbered (menu, data[i].label, i + 1,
+                          "win.profile",
+                          g_variant_new_string (data[i].uuid));
+  }
+
+  return menu;
+}
+
+static void
+terminal_app_update_profile_menus (TerminalApp *app)
+{
+  g_menu_remove_all (G_MENU (app->menubar_new_terminal_section));
+  g_menu_remove_all (G_MENU (app->menubar_set_profile_section));
+  g_clear_object (&app->set_profile_menu);
+
+  /* Get profiles list and sort by label */
+  gs_unref_array GArray *array = g_array_sized_new (FALSE, TRUE, sizeof (ProfileData),
+                                                    terminal_settings_list_get_n_children 
(app->profiles_list));
+  g_array_set_clear_func (array, (GDestroyNotify) profile_data_clear);
+
+  ProfilesForeachData data = { array, app };
+  terminal_settings_list_foreach_child (app->profiles_list,
+                                        (TerminalSettingsListForeachFunc) foreach_profile_cb,
+                                        &data);
+  g_array_sort (array, compare_profile_label_cb);
+
+  ProfileData *profiles = (ProfileData*) array->data;
+  guint n_profiles = array->len;
+
+  fill_new_terminal_section (app->menubar_new_terminal_section, profiles, n_profiles);
+
+  app->set_profile_menu = set_profile_submenu_new (profiles, n_profiles);
+
+  if (app->set_profile_menu != NULL) {
+    g_menu_append_submenu (app->menubar_set_profile_section, _("Change _Profile"),
+                           G_MENU_MODEL (app->set_profile_menu));
+  }
+}
+
+/* Clipboard */
+
+static void
+free_clipboard_targets (TerminalApp *app)
+{
+  g_free (app->clipboard_targets);
+  app->clipboard_targets = NULL;
+  app->n_clipboard_targets = 0;
+}
+
+static void
+update_clipboard_targets (TerminalApp *app,
+                          GdkAtom *targets,
+                          int n_targets)
+{
+  free_clipboard_targets (app);
+
+  /* Sometimes we receive targets == NULL but n_targets == -1 */
+  if (targets != NULL) {
+    app->clipboard_targets = g_memdup (targets, sizeof (targets[0]) * n_targets);
+    app->n_clipboard_targets = n_targets;
+  }
+}
+
+static void
+clipboard_targets_received_cb (GtkClipboard *clipboard,
+                               GdkAtom *targets,
+                               int n_targets,
+                               TerminalApp *app)
+{
+  update_clipboard_targets (app, targets, n_targets);
+
+  _TERMINAL_DEBUG_IF (TERMINAL_DEBUG_CLIPBOARD) {
+    g_printerr ("Clipboard has %d targets:", app->n_clipboard_targets);
+
+    int i;
+    for (i = 0; i < app->n_clipboard_targets; i++) {
+      gs_free char *atom_name = gdk_atom_name (app->clipboard_targets[i]);
+      g_printerr (" %s", atom_name);
+    }
+    g_printerr ("\n");
+  }
+
+  g_signal_emit (app, signals[CLIPBOARD_TARGETS_CHANGED], 0, clipboard);
+}
+
+static void
+clipboard_owner_change_cb (GtkClipboard *clipboard,
+                           GdkEvent *event G_GNUC_UNUSED,
+                           TerminalApp *app)
+{
+  _terminal_debug_print (TERMINAL_DEBUG_CLIPBOARD,
+                         "Clipboard owner changed\n");
+
+  clipboard_targets_received_cb (clipboard, NULL, 0, app); /* clear */
+
+  /* We can do this without holding a reference to @app since
+   * the app lives as long as the process.
+   */
+  gtk_clipboard_request_targets (clipboard,
+                                 (GtkClipboardTargetsReceivedFunc) clipboard_targets_received_cb,
+                                 app);
 }
-#endif /* GTK+ 3.19 */
 
 /* App menu callbacks */
 
@@ -340,7 +625,7 @@ app_menu_preferences_cb (GSimpleAction *action,
 {
   TerminalApp *app = user_data;
 
-  terminal_app_edit_preferences (app, NULL);
+  terminal_app_edit_preferences (app);
 }
 
 static void
@@ -348,7 +633,7 @@ app_menu_help_cb (GSimpleAction *action,
                   GVariant      *parameter,
                   gpointer       user_data)
 {
-  terminal_util_show_help (NULL, NULL);
+  terminal_util_show_help (NULL);
 }
 
 static void
@@ -356,7 +641,7 @@ app_menu_about_cb (GSimpleAction *action,
                    GVariant      *parameter,
                    gpointer       user_data)
 {
-  terminal_util_show_about (NULL);
+  terminal_util_show_about ();
 }
 
 static void
@@ -389,7 +674,9 @@ terminal_app_activate (GApplication *application)
 static void
 terminal_app_startup (GApplication *application)
 {
-  const GActionEntry app_menu_actions[] = {
+  TerminalApp *app = TERMINAL_APP (application);
+  GtkApplication *gtk_application = GTK_APPLICATION (application);
+  const GActionEntry action_entries[] = {
     { "preferences", app_menu_preferences_cb,   NULL, NULL, NULL },
     { "help",        app_menu_help_cb,          NULL, NULL, NULL },
     { "about",       app_menu_about_cb,         NULL, NULL, NULL },
@@ -404,12 +691,43 @@ terminal_app_startup (GApplication *application)
   gdk_set_program_class("Gnome-terminal");
 
   g_action_map_add_action_entries (G_ACTION_MAP (application),
-                                   app_menu_actions, G_N_ELEMENTS (app_menu_actions),
+                                   action_entries, G_N_ELEMENTS (action_entries),
                                    application);
 
-
   app_load_css (application);
 
+  /* App menu */
+  GMenu *appmenu_new_terminal_section = gtk_application_get_menu_by_id (gtk_application,
+                                                                        "new-terminal-section");
+  fill_new_terminal_section (appmenu_new_terminal_section, NULL, 0); /* no submenu */
+
+  /* Menubar */
+  terminal_util_load_objects_resource ("/org/gnome/terminal/ui/menubar.ui",
+                                       "menubar", &app->menubar,
+                                       "new-terminal-section", &app->menubar_new_terminal_section,
+                                       "set-profile-section", &app->menubar_set_profile_section,
+                                       "set-encoding-submenu", &app->menubar_set_encoding_submenu,
+                                       NULL);
+
+  /* Create dynamic menus and keep them updated */
+  terminal_app_update_profile_menus (app);
+  g_signal_connect_swapped (app->profiles_list, "children-changed",
+                            G_CALLBACK (terminal_app_update_profile_menus), app);
+
+  /* Install the encodings submenu */
+  terminal_encodings_append_menu (app->menubar_set_encoding_submenu);
+
+  /* If the shell wants to show the appmenu/menubar, make it available */
+  gboolean shell_shows_appmenu, shell_shows_menubar;
+  g_object_get (gtk_settings_get_default (),
+                "gtk-shell-shows-app-menu", &shell_shows_appmenu,
+                "gtk-shell-shows-menubar", &shell_shows_menubar,
+                NULL);
+  if (!shell_shows_appmenu)
+    gtk_application_set_app_menu (GTK_APPLICATION (app), NULL);
+  if (shell_shows_menubar)
+    gtk_application_set_menubar (GTK_APPLICATION (app), app->menubar);
+
   _terminal_debug_print (TERMINAL_DEBUG_SERVER, "Startup complete\n");
 }
 
@@ -418,7 +736,7 @@ terminal_app_startup (GApplication *application)
 static void
 terminal_app_init (TerminalApp *app)
 {
-  gs_unref_object GSettings *settings;
+  terminal_app_init_debug ();
 
   gtk_window_set_default_icon_name (GNOME_TERMINAL_ICON_NAME);
 
@@ -437,36 +755,34 @@ terminal_app_init (TerminalApp *app)
                                                      GTK_DEBUG_ENABLE_INSPECTOR_TYPE);
 
 #if GTK_CHECK_VERSION (3, 19, 0)
-  {
-  GtkSettings *gtk_settings;
-
-  gtk_settings = gtk_settings_get_default ();
+  GtkSettings *gtk_settings = gtk_settings_get_default ();
   terminal_app_theme_variant_changed_cb (app->global_settings,
                                          TERMINAL_SETTING_THEME_VARIANT_KEY, gtk_settings);
   g_signal_connect (app->global_settings,
                     "changed::" TERMINAL_SETTING_THEME_VARIANT_KEY,
                     G_CALLBACK (terminal_app_theme_variant_changed_cb),
                     gtk_settings);
-  }
 #endif /* GTK+ 3.19 */
 
+  /* Clipboard targets */
+  GdkDisplay *display = gdk_display_get_default ();
+  app->clipboard = gtk_clipboard_get_for_display (display, GDK_SELECTION_CLIPBOARD);
+  clipboard_owner_change_cb (app->clipboard, NULL, app);
+  g_signal_connect (app->clipboard, "owner-change",
+                    G_CALLBACK (clipboard_owner_change_cb), app);
+
+  if (!gdk_display_supports_selection_notification (display))
+    g_printerr ("Display does not support owner-change; copy/paste will be broken!\n");
+
   /* Check if we need to migrate from gconf to dconf */
   maybe_migrate_settings (app);
 
   /* Get the profiles */
   app->profiles_list = terminal_profiles_list_new ();
 
-  /* Get the encodings */
-  app->encodings = terminal_encodings_get_builtins ();
-  terminal_app_encoding_list_notify_cb (app->global_settings, "encodings", app);
-  g_signal_connect (app->global_settings,
-                    "changed::encodings",
-                    G_CALLBACK (terminal_app_encoding_list_notify_cb),
-                    app);
-
   app->screen_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
-  settings = g_settings_get_child (app->global_settings, "keybindings");
+  gs_unref_object GSettings *settings = g_settings_get_child (app->global_settings, "keybindings");
   terminal_accels_init (G_APPLICATION (app), settings);
 }
 
@@ -475,10 +791,14 @@ terminal_app_finalize (GObject *object)
 {
   TerminalApp *app = TERMINAL_APP (object);
 
-  g_signal_handlers_disconnect_by_func (app->global_settings,
-                                        G_CALLBACK (terminal_app_encoding_list_notify_cb),
+  g_signal_handlers_disconnect_by_func (app->clipboard,
+                                        G_CALLBACK (clipboard_owner_change_cb),
+                                        app);
+  free_clipboard_targets (app);
+
+  g_signal_handlers_disconnect_by_func (app->profiles_list,
+                                        G_CALLBACK (terminal_app_update_profile_menus),
                                         app);
-  g_hash_table_destroy (app->encodings);
   g_hash_table_destroy (app->screen_map);
 
   g_object_unref (app->global_settings);
@@ -486,6 +806,12 @@ terminal_app_finalize (GObject *object)
   g_object_unref (app->system_proxy_settings);
   g_clear_object (&app->gtk_debug_settings);
 
+  g_clear_object (&app->menubar);
+  g_clear_object (&app->menubar_new_terminal_section);
+  g_clear_object (&app->menubar_set_profile_section);
+  g_clear_object (&app->menubar_set_encoding_submenu);
+  g_clear_object (&app->set_profile_menu);
+
   terminal_accels_shutdown ();
 
   G_OBJECT_CLASS (terminal_app_parent_class)->finalize (object);
@@ -574,14 +900,14 @@ terminal_app_class_init (TerminalAppClass *klass)
   g_application_class->dbus_register = terminal_app_dbus_register;
   g_application_class->dbus_unregister = terminal_app_dbus_unregister;
 
-  signals[ENCODING_LIST_CHANGED] =
-    g_signal_new (I_("encoding-list-changed"),
+  signals[CLIPBOARD_TARGETS_CHANGED] =
+    g_signal_new (I_("clipboard-targets-changed"),
                   G_OBJECT_CLASS_TYPE (object_class),
                   G_SIGNAL_RUN_LAST,
-                  G_STRUCT_OFFSET (TerminalAppClass, encoding_list_changed),
+                  G_STRUCT_OFFSET (TerminalAppClass, clipboard_targets_changed),
                   NULL, NULL,
-                  g_cclosure_marshal_VOID__VOID,
-                  G_TYPE_NONE, 0);
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE, 1, G_TYPE_OBJECT);
 }
 
 /* Public API */
@@ -615,7 +941,7 @@ TerminalScreen *
 terminal_app_new_terminal (TerminalApp     *app,
                            TerminalWindow  *window,
                            GSettings       *profile,
-                           const char      *encoding,
+                           const char      *charset,
                            char           **override_command,
                            const char      *title,
                            const char      *working_dir,
@@ -626,8 +952,9 @@ terminal_app_new_terminal (TerminalApp     *app,
 
   g_return_val_if_fail (TERMINAL_IS_APP (app), NULL);
   g_return_val_if_fail (TERMINAL_IS_WINDOW (window), NULL);
+  g_return_val_if_fail (charset == NULL || terminal_encodings_is_known_charset (charset), NULL);
 
-  screen = terminal_screen_new (profile, encoding, override_command, title,
+  screen = terminal_screen_new (profile, charset, override_command, title,
                                 working_dir, child_env, zoom);
 
   terminal_window_add_screen (window, screen, -1);
@@ -669,27 +996,35 @@ terminal_app_unregister_screen (TerminalApp *app,
   g_assert (found == TRUE);
 }
 
-void
-terminal_app_edit_profile (TerminalApp     *app,
-                           GSettings       *profile,
-                           GtkWindow       *transient_parent,
-                           const char      *widget_name)
+GdkAtom *
+terminal_app_get_clipboard_targets (TerminalApp *app,
+                                    GtkClipboard *clipboard,
+                                    int *n_targets)
 {
-  terminal_profile_edit (profile, NULL, widget_name);
+  g_return_val_if_fail (TERMINAL_IS_APP (app), NULL);
+  g_return_val_if_fail (n_targets != NULL, NULL);
+
+  if (clipboard != app->clipboard) {
+    *n_targets = 0;
+    return NULL;
+  }
+
+  *n_targets = app->n_clipboard_targets;
+  return app->clipboard_targets;
 }
 
 void
-terminal_app_edit_preferences (TerminalApp     *app,
-                               GtkWindow       *transient_parent)
+terminal_app_edit_profile (TerminalApp     *app,
+                           GSettings       *profile,
+                           const char      *widget_name)
 {
-  terminal_prefs_show_preferences (NULL, "general");
+  terminal_profile_edit (profile, widget_name);
 }
 
 void
-terminal_app_edit_encodings (TerminalApp     *app,
-                             GtkWindow       *transient_parent)
+terminal_app_edit_preferences (TerminalApp *app)
 {
-  terminal_prefs_show_preferences (NULL, "encodings");
+  terminal_prefs_show_preferences ("general");
 }
 
 /**
@@ -703,88 +1038,28 @@ terminal_app_get_profiles_list (TerminalApp *app)
   return app->profiles_list;
 }
 
-GHashTable *
-terminal_app_get_encodings (TerminalApp *app)
-{
-  return app->encodings;
-}
-
-static const char *
-charset_validated (const char *charset)
-{
-  gsize i;
-
-  if (charset == NULL)
-    goto out;
-
-  for (i = 0; charset[i] != '\0'; i++) {
-    char c = charset[i];
-    if (!(g_ascii_isalnum(c) || c == '_' || c == '-'))
-      goto out;
-  }
-
-  return charset;
- out:
-  return "UTF-8";
-}
-
 /**
- * terminal_app_ensure_encoding:
- * @app:
- * @charset: (allow-none): a charset, or %NULL
- *
- * Ensures there's a #TerminalEncoding for @charset available. If @charset
- * is %NULL, returns the #TerminalEncoding for the locale's charset. If
- * @charset is not a known charset, returns a #TerminalEncoding for a
- * custom charset.
+ * terminal_app_get_menubar:
+ * @app: a #TerminalApp
  *
- * Returns: (transfer none): a #TerminalEncoding, or %NULL
+ * Returns: (tranfer none): the main window menu bar as a #GMenuModel
  */
-TerminalEncoding *
-terminal_app_ensure_encoding (TerminalApp *app,
-                              const char *charset)
-{
-  TerminalEncoding *encoding;
-
-  encoding = g_hash_table_lookup (app->encodings, charset_validated (charset));
-  if (encoding == NULL)
-    {
-      encoding = terminal_encoding_new (charset,
-                                        _("User Defined"),
-                                        TRUE,
-                                        TRUE /* scary! */);
-      g_hash_table_insert (app->encodings,
-                          (gpointer) terminal_encoding_get_charset (encoding),
-                          encoding);
-    }
-
-  return encoding;
+GMenuModel *
+terminal_app_get_menubar (TerminalApp *app)
+{
+  return app->menubar;
 }
 
 /**
- * terminal_app_get_active_encodings:
+ * terminal_app_get_profile_section:
+ * @app: a #TerminalApp
  *
- * Returns: a newly allocated list of newly referenced #TerminalEncoding objects.
+ * Returns: (tranfer none): the main window's menubar's profiles section as a #GMenuModel
  */
-GSList*
-terminal_app_get_active_encodings (TerminalApp *app)
+GMenuModel *
+terminal_app_get_profile_section (TerminalApp *app)
 {
-  GSList *list = NULL;
-  GHashTableIter iter;
-  gpointer key, value;
-
-  g_hash_table_iter_init (&iter, app->encodings);
-  while (g_hash_table_iter_next (&iter, &key, &value))
-    {
-      TerminalEncoding *encoding = (TerminalEncoding *) value;
-
-      if (!encoding->is_active)
-        continue;
-
-      list = g_slist_prepend (list, terminal_encoding_ref (encoding));
-    }
-
-  return g_slist_sort (list, (GCompareFunc) compare_encodings);
+  return G_MENU_MODEL (app->set_profile_menu);
 }
 
 /**
@@ -834,7 +1109,7 @@ terminal_app_get_gtk_debug_settings (TerminalApp *app)
  * @app:
  *
  * Creates a #PangoFontDescription for the system monospace font.
- * 
+ *
  * Returns: (transfer full): a new #PangoFontDescription
  */
 PangoFontDescription *
diff --git a/src/terminal-app.h b/src/terminal-app.h
index 39d6768..22436f1 100644
--- a/src/terminal-app.h
+++ b/src/terminal-app.h
@@ -21,7 +21,6 @@
 
 #include <gtk/gtk.h>
 
-#include "terminal-encoding.h"
 #include "terminal-screen.h"
 #include "terminal-profiles-list.h"
 
@@ -53,17 +52,16 @@ GApplication *terminal_app_new (const char *app_id);
 
 GDBusObjectManagerServer *terminal_app_get_object_manager (TerminalApp *app);
 
+GdkAtom *terminal_app_get_clipboard_targets (TerminalApp *app,
+                                             GtkClipboard *clipboard,
+                                             int *n_targets);
+
 void terminal_app_edit_profile (TerminalApp *app,
                                 GSettings   *profile,
-                                GtkWindow   *transient_parent,
                                 const char  *widget_name);
 
 void terminal_app_new_profile (TerminalApp *app,
-                               GSettings   *default_base_profile,
-                               GtkWindow   *transient_parent);
-
-gboolean terminal_app_can_remove_profile (TerminalApp *app,
-                                          GSettings *profile);
+                               GSettings   *default_base_profile);
 
 void terminal_app_remove_profile (TerminalApp *app,
                                   GSettings *profile);
@@ -74,7 +72,7 @@ TerminalWindow * terminal_app_new_window   (TerminalApp *app,
 TerminalScreen *terminal_app_new_terminal (TerminalApp     *app,
                                            TerminalWindow  *window,
                                            GSettings       *profile,
-                                           const char      *encoding,
+                                           const char      *charset,
                                            char           **override_command,
                                            const char      *title,
                                            const char      *working_dir,
@@ -90,19 +88,15 @@ void terminal_app_register_screen (TerminalApp *app,
 void terminal_app_unregister_screen (TerminalApp *app,
                                      TerminalScreen *screen);
 
-void terminal_app_edit_preferences (TerminalApp     *app,
-                                    GtkWindow       *transient_parent);
-void terminal_app_edit_encodings   (TerminalApp     *app,
-                                    GtkWindow       *transient_parent);
+void terminal_app_edit_preferences (TerminalApp *app);
 
 TerminalSettingsList *terminal_app_get_profiles_list (TerminalApp *app);
 
-TerminalEncoding *terminal_app_ensure_encoding (TerminalApp *app,
-                                                const char *charset);
+/* Menus */
 
-GHashTable *terminal_app_get_encodings (TerminalApp *app);
+GMenuModel *terminal_app_get_menubar (TerminalApp *app);
 
-GSList* terminal_app_get_active_encodings (TerminalApp *app);
+GMenuModel *terminal_app_get_profile_section (TerminalApp *app);
 
 /* GSettings */
 
diff --git a/src/terminal-menus.ui b/src/terminal-appmenu.ui
similarity index 84%
copy from src/terminal-menus.ui
copy to src/terminal-appmenu.ui
index e248590..8ea3159 100644
--- a/src/terminal-menus.ui
+++ b/src/terminal-appmenu.ui
@@ -17,13 +17,7 @@
 -->
 <interface>
   <menu id="app-menu">
-    <section>
-      <item>
-        <attribute name="label" translatable="yes">_New Terminal</attribute>
-        <attribute name="action">win.new-terminal</attribute>
-        <attribute name="target" type="(ss)">('default','default')</attribute>
-      </item>
-    </section>
+    <section id="new-terminal-section" />
     <section>
       <item>
         <attribute name="label" translatable="yes">_Preferences</attribute>
diff --git a/src/terminal-debug.c b/src/terminal-debug.c
index 0ff321f..d08829e 100644
--- a/src/terminal-debug.c
+++ b/src/terminal-debug.c
@@ -29,6 +29,7 @@ _terminal_debug_init(void)
 #ifdef ENABLE_DEBUG
   const GDebugKey keys[] = {
     { "accels",        TERMINAL_DEBUG_ACCELS        },
+    { "clipboard",     TERMINAL_DEBUG_CLIPBOARD     },
     { "encodings",     TERMINAL_DEBUG_ENCODINGS     },
     { "server",        TERMINAL_DEBUG_SERVER        },
     { "geometry",      TERMINAL_DEBUG_GEOMETRY      },
@@ -36,12 +37,12 @@ _terminal_debug_init(void)
     { "processes",     TERMINAL_DEBUG_PROCESSES     },
     { "profile",       TERMINAL_DEBUG_PROFILE       },
     { "settings-list", TERMINAL_DEBUG_SETTINGS_LIST },
-    { "appmenu",       TERMINAL_DEBUG_APPMENU       },
     { "search",        TERMINAL_DEBUG_SEARCH        },
   };
 
   _terminal_debug_flags = g_parse_debug_string (g_getenv ("GNOME_TERMINAL_DEBUG"),
                                                 keys, G_N_ELEMENTS (keys));
+
 #endif /* ENABLE_DEBUG */
 }
 
diff --git a/src/terminal-debug.h b/src/terminal-debug.h
index 5dc3ca4..0fafcc3 100644
--- a/src/terminal-debug.h
+++ b/src/terminal-debug.h
@@ -26,14 +26,14 @@ G_BEGIN_DECLS
 
 typedef enum {
   TERMINAL_DEBUG_ACCELS        = 1 << 0,
-  TERMINAL_DEBUG_ENCODINGS     = 1 << 1,
-  TERMINAL_DEBUG_SERVER        = 1 << 2,
-  TERMINAL_DEBUG_GEOMETRY      = 1 << 3,
-  TERMINAL_DEBUG_MDI           = 1 << 4,
-  TERMINAL_DEBUG_PROCESSES     = 1 << 5,
-  TERMINAL_DEBUG_PROFILE       = 1 << 6,
-  TERMINAL_DEBUG_SETTINGS_LIST = 1 << 7,
-  TERMINAL_DEBUG_APPMENU       = 1 << 8,
+  TERMINAL_DEBUG_CLIPBOARD     = 1 << 1,
+  TERMINAL_DEBUG_ENCODINGS     = 1 << 2,
+  TERMINAL_DEBUG_SERVER        = 1 << 3,
+  TERMINAL_DEBUG_GEOMETRY      = 1 << 4,
+  TERMINAL_DEBUG_MDI           = 1 << 5,
+  TERMINAL_DEBUG_PROCESSES     = 1 << 6,
+  TERMINAL_DEBUG_PROFILE       = 1 << 7,
+  TERMINAL_DEBUG_SETTINGS_LIST = 1 << 8,
   TERMINAL_DEBUG_SEARCH        = 1 << 9
 } TerminalDebugFlags;
 
diff --git a/src/terminal-encoding.c b/src/terminal-encoding.c
index 2aeb4d4..019624b 100644
--- a/src/terminal-encoding.c
+++ b/src/terminal-encoding.c
@@ -1,6 +1,6 @@
 /*
  * Copyright © 2002 Red Hat, Inc.
- * Copyright © 2008 Christian Persch
+ * Copyright © 2008, 2017 Christian Persch
  *
  * 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
@@ -19,6 +19,8 @@
 #include "config.h"
 
 #include <string.h>
+#include <search.h>
+#include <stdlib.h>
 
 #include <glib.h>
 #include <glib/gi18n.h>
@@ -29,6 +31,7 @@
 #include "terminal-encoding.h"
 #include "terminal-schemas.h"
 #include "terminal-util.h"
+#include "terminal-libgsystem.h"
 
 /* Overview
  *
@@ -45,221 +48,215 @@
  * labeled "user defined" but still appears in the menu.
  */
 
-static const struct {
+typedef enum {
+  GROUP_UNICODE,
+  GROUP_ASIAN,
+  GROUP_EUROPEAN,
+  LAST_GROUP
+} EncodingGroup;
+
+typedef struct {
   const char *charset;
   const char *name;
-} encodings[] = {
-  { "ISO-8859-1",      N_("Western") },
-  { "ISO-8859-2",      N_("Central European") },
-  { "ISO-8859-3",      N_("South European") },
-  { "ISO-8859-4",      N_("Baltic") },
-  { "ISO-8859-5",      N_("Cyrillic") },
-  { "ISO-8859-6",      N_("Arabic") },
-  { "ISO-8859-7",      N_("Greek") },
-  { "ISO-8859-8",      N_("Hebrew Visual") },
-  { "ISO-8859-8-I",    N_("Hebrew") },
-  { "ISO-8859-9",      N_("Turkish") },
-  { "ISO-8859-10",     N_("Nordic") },
-  { "ISO-8859-13",     N_("Baltic") },
-  { "ISO-8859-14",     N_("Celtic") },
-  { "ISO-8859-15",     N_("Western") },
-  { "ISO-8859-16",     N_("Romanian") },
-  { "UTF-8",   N_("Unicode") },
-  { "ARMSCII-8",       N_("Armenian") },
-  { "BIG5",    N_("Chinese Traditional") },
-  { "BIG5-HKSCS",      N_("Chinese Traditional") },
-  { "CP866",   N_("Cyrillic/Russian") },
-  { "EUC-JP",  N_("Japanese") },
-  { "EUC-KR",  N_("Korean") },
-  { "EUC-TW",  N_("Chinese Traditional") },
-  { "GB18030", N_("Chinese Simplified") },
-  { "GB2312",  N_("Chinese Simplified") },
-  { "GBK",     N_("Chinese Simplified") },
-  { "GEORGIAN-PS",     N_("Georgian") },
-  { "IBM850",  N_("Western") },
-  { "IBM852",  N_("Central European") },
-  { "IBM855",  N_("Cyrillic") },
-  { "IBM857",  N_("Turkish") },
-  { "IBM862",  N_("Hebrew") },
-  { "IBM864",  N_("Arabic") },
-  { "ISO-2022-JP",     N_("Japanese") },
-  { "ISO-2022-KR",     N_("Korean") },
-  { "ISO-IR-111",      N_("Cyrillic") },
-  { "KOI8-R",  N_("Cyrillic") },
-  { "KOI8-U",  N_("Cyrillic/Ukrainian") },
-  { "MAC_ARABIC",      N_("Arabic") },
-  { "MAC_CE",  N_("Central European") },
-  { "MAC_CROATIAN",    N_("Croatian") },
-  { "MAC-CYRILLIC",    N_("Cyrillic") },
-  { "MAC_DEVANAGARI",  N_("Hindi") },
-  { "MAC_FARSI",       N_("Persian") },
-  { "MAC_GREEK",       N_("Greek") },
-  { "MAC_GUJARATI",    N_("Gujarati") },
-  { "MAC_GURMUKHI",    N_("Gurmukhi") },
-  { "MAC_HEBREW",      N_("Hebrew") },
-  { "MAC_ICELANDIC",   N_("Icelandic") },
-  { "MAC_ROMAN",       N_("Western") },
-  { "MAC_ROMANIAN",    N_("Romanian") },
-  { "MAC_TURKISH",     N_("Turkish") },
-  { "MAC_UKRAINIAN",   N_("Cyrillic/Ukrainian") },
-  { "SHIFT_JIS",       N_("Japanese") },
-  { "TCVN",    N_("Vietnamese") },
-  { "TIS-620", N_("Thai") },
-  { "UHC",     N_("Korean") },
-  { "VISCII",  N_("Vietnamese") },
-  { "WINDOWS-1250",    N_("Central European") },
-  { "WINDOWS-1251",    N_("Cyrillic") },
-  { "WINDOWS-1252",    N_("Western") },
-  { "WINDOWS-1253",    N_("Greek") },
-  { "WINDOWS-1254",    N_("Turkish") },
-  { "WINDOWS-1255",    N_("Hebrew") },
-  { "WINDOWS-1256",    N_("Arabic") },
-  { "WINDOWS-1257",    N_("Baltic") },
-  { "WINDOWS-1258",    N_("Vietnamese") },
-#if 0
-  /* These encodings do NOT pass-through ASCII, so are always rejected.
-   * FIXME: why are they in this table; or rather why do we need
-   * the ASCII pass-through requirement?
-   */
-  { "UTF-7",  N_("Unicode") },
-  { "UTF-16", N_("Unicode") },
-  { "UCS-2",  N_("Unicode") },
-  { "UCS-4",  N_("Unicode") },
-  { "JOHAB",  N_("Korean") },
-#endif
-};
+  EncodingGroup group;
+} EncodingEntry;
 
-TerminalEncoding *
-terminal_encoding_new (const char *charset,
-                       const char *display_name,
-                       gboolean is_custom,
-                       gboolean force_valid)
-{
-  TerminalEncoding *encoding;
+/* These MUST be sorted by charset so that bsearch can work! */
+static const EncodingEntry const encodings[] = {
+  { "ARMSCII-8",      N_("Armenian"),            GROUP_ASIAN },
+  { "BIG5",           N_("Chinese Traditional"), GROUP_ASIAN },
+  { "BIG5-HKSCS",     N_("Chinese Traditional"), GROUP_ASIAN },
+  { "CP866",          N_("Cyrillic/Russian"),    GROUP_EUROPEAN },
+  { "EUC-JP",         N_("Japanese"),            GROUP_ASIAN },
+  { "EUC-KR",         N_("Korean"),              GROUP_ASIAN },
+  { "EUC-TW",         N_("Chinese Traditional"), GROUP_ASIAN },
+  { "GB18030",        N_("Chinese Simplified"),  GROUP_ASIAN },
+  { "GB2312",         N_("Chinese Simplified"),  GROUP_ASIAN },
+  { "GBK",            N_("Chinese Simplified"),  GROUP_ASIAN },
+  { "GEORGIAN-PS",    N_("Georgian"),            GROUP_ASIAN },
+  { "IBM850",         N_("Western"),             GROUP_EUROPEAN },
+  { "IBM852",         N_("Central European"),    GROUP_EUROPEAN },
+  { "IBM855",         N_("Cyrillic"),            GROUP_EUROPEAN },
+  { "IBM857",         N_("Turkish"),             GROUP_ASIAN },
+  { "IBM862",         N_("Hebrew"),              GROUP_ASIAN },
+  { "IBM864",         N_("Arabic"),              GROUP_ASIAN },
+  { "ISO-2022-JP",    N_("Japanese"),            GROUP_ASIAN },
+  { "ISO-2022-KR",    N_("Korean"),              GROUP_ASIAN },
+  { "ISO-8859-1",     N_("Western"),             GROUP_EUROPEAN },
+  { "ISO-8859-10",    N_("Nordic"),              GROUP_EUROPEAN },
+  { "ISO-8859-13",    N_("Baltic"),              GROUP_EUROPEAN },
+  { "ISO-8859-14",    N_("Celtic"),              GROUP_EUROPEAN },
+  { "ISO-8859-15",    N_("Western"),             GROUP_EUROPEAN },
+  { "ISO-8859-16",    N_("Romanian"),            GROUP_EUROPEAN },
+  { "ISO-8859-2",     N_("Central European"),    GROUP_EUROPEAN },
+  { "ISO-8859-3",     N_("South European"),      GROUP_EUROPEAN },
+  { "ISO-8859-4",     N_("Baltic"),              GROUP_EUROPEAN },
+  { "ISO-8859-5",     N_("Cyrillic"),            GROUP_EUROPEAN },
+  { "ISO-8859-6",     N_("Arabic"),              GROUP_ASIAN },
+  { "ISO-8859-7",     N_("Greek"),               GROUP_EUROPEAN },
+  { "ISO-8859-8",     N_("Hebrew Visual"),       GROUP_ASIAN },
+  { "ISO-8859-8-I",   N_("Hebrew"),              GROUP_ASIAN },
+  { "ISO-8859-9",     N_("Turkish"),             GROUP_ASIAN },
+  { "ISO-IR-111",     N_("Cyrillic"),            GROUP_EUROPEAN },
+   /* { "JOHAB",      N_("Korean"),              GROUP_ASIAN }, */
+  { "KOI8-R",         N_("Cyrillic"),            GROUP_EUROPEAN },
+  { "KOI8-U",         N_("Cyrillic/Ukrainian"),  GROUP_EUROPEAN },
+  { "MAC-CYRILLIC",   N_("Cyrillic"),            GROUP_EUROPEAN },
+  { "MAC_ARABIC",     N_("Arabic"),              GROUP_ASIAN },
+  { "MAC_CE",         N_("Central European"),    GROUP_EUROPEAN },
+  { "MAC_CROATIAN",   N_("Croatian"),            GROUP_EUROPEAN },
+  { "MAC_DEVANAGARI", N_("Hindi"),               GROUP_ASIAN },
+  { "MAC_FARSI",      N_("Persian"),             GROUP_ASIAN },
+  { "MAC_GREEK",      N_("Greek"),               GROUP_EUROPEAN },
+  { "MAC_GUJARATI",   N_("Gujarati"),            GROUP_ASIAN },
+  { "MAC_GURMUKHI",   N_("Gurmukhi"),            GROUP_ASIAN },
+  { "MAC_HEBREW",     N_("Hebrew"),              GROUP_ASIAN },
+  { "MAC_ICELANDIC",  N_("Icelandic"),           GROUP_EUROPEAN },
+  { "MAC_ROMAN",      N_("Western"),             GROUP_EUROPEAN },
+  { "MAC_ROMANIAN",   N_("Romanian"),            GROUP_EUROPEAN },
+  { "MAC_TURKISH",    N_("Turkish"),             GROUP_ASIAN },
+  { "MAC_UKRAINIAN",  N_("Cyrillic/Ukrainian"),  GROUP_EUROPEAN },
+  { "SHIFT_JIS",      N_("Japanese"),            GROUP_ASIAN },
+  { "TCVN",           N_("Vietnamese"),          GROUP_ASIAN },
+  { "TIS-620",        N_("Thai"),                GROUP_ASIAN },
+  /* { "UCS-4",       N_("Unicode"),             GROUP_UNICODE }, */
+  { "UHC",            N_("Korean"),              GROUP_ASIAN },
+  /* { "UTF-16",      N_("Unicode"),             GROUP_UNICODE }, */
+  /* { "UTF-32",      N_("Unicode"),             GROUP_UNICODE }, */
+  /* { "UTF-7",       N_("Unicode"),             GROUP_UNICODE }, */
+  { "UTF-8",          N_("Unicode"),             GROUP_UNICODE },
+  { "VISCII",         N_("Vietnamese"),          GROUP_ASIAN },
+  { "WINDOWS-1250",   N_("Central European"),    GROUP_EUROPEAN },
+  { "WINDOWS-1251",   N_("Cyrillic"),            GROUP_EUROPEAN },
+  { "WINDOWS-1252",   N_("Western"),             GROUP_EUROPEAN },
+  { "WINDOWS-1253",   N_("Greek"),               GROUP_EUROPEAN },
+  { "WINDOWS-1254",   N_("Turkish"),             GROUP_ASIAN },
+  { "WINDOWS-1255",   N_("Hebrew"),              GROUP_ASIAN },
+  { "WINDOWS-1256",   N_("Arabic"),              GROUP_ASIAN },
+  { "WINDOWS-1257",   N_("Baltic"),              GROUP_EUROPEAN },
+  { "WINDOWS-1258",   N_("Vietnamese"),          GROUP_ASIAN },
+};
 
-  encoding = g_slice_new (TerminalEncoding);
-  encoding->refcount = 1;
-  encoding->charset = g_intern_string (charset);
-  encoding->name = g_strdup (display_name);
-  encoding->valid = encoding->validity_checked = force_valid || g_str_equal (charset, "UTF-8");
-  encoding->is_custom = is_custom;
-  encoding->is_active = FALSE;
+static const struct {
+  EncodingGroup group;
+  const char *name;
+} group_names[] = {
+  { GROUP_UNICODE,  N_("Unicode") },
+  { GROUP_ASIAN,    N_("Legacy Asian Encodings") },
+  { GROUP_EUROPEAN, N_("Legacy European Encodings") },
+};
 
-  return encoding;
-}
+#define EM_DASH "—"
 
-TerminalEncoding*
-terminal_encoding_ref (TerminalEncoding *encoding)
+static int
+compare_encoding_entry_cb (const void *ap,
+                           const void *bp)
 {
-  g_return_val_if_fail (encoding != NULL, NULL);
+  const EncodingEntry *a = ap;
+  const EncodingEntry *b = bp;
 
-  encoding->refcount++;
-  return encoding;
-}
+  int r = a->group - b->group;
+  if (r != 0)
+    return r;
 
-void
-terminal_encoding_unref (TerminalEncoding *encoding)
-{
-  if (--encoding->refcount > 0)
-    return;
+  r = g_utf8_collate (a->name, b->name);
+  if (r != 0)
+    return r;
 
-  g_free (encoding->name);
-  g_slice_free (TerminalEncoding, encoding);
+  return strcmp (a->charset, b->charset);
 }
 
-const char *
-terminal_encoding_get_charset (TerminalEncoding *encoding)
+/**
+ * terminal_encodings_append_menu:
+ *
+ * Appends to known encodings to a #GMenu, sorted in groups and
+ * alphabetically by name inside the groups. The action name
+ * used when activating the menu items is "win.encoding".
+ */
+void
+terminal_encodings_append_menu (GMenu *menu)
 {
-  g_return_val_if_fail (encoding != NULL, NULL);
+  /* First, sort the encodings */
+  gs_free EncodingEntry *array = g_memdup (encodings, sizeof encodings);
+  for (guint i = 0; i < G_N_ELEMENTS (encodings); i++)
+    array[i].name = _(array[i].name); /* translate */
 
-  return encoding->charset;
-}
+  qsort (array, G_N_ELEMENTS (encodings), sizeof array[0],
+         compare_encoding_entry_cb);
 
-gboolean
-terminal_encoding_is_valid (TerminalEncoding *encoding)
-{
-  /* All of the printing ASCII characters from space (32) to the tilde (126) */
-  static const char ascii_sample[] =
-      " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
-  char *converted;
-  gsize bytes_read = 0, bytes_written = 0;
-  GError *error = NULL;
+  for (guint group = 0 ; group < LAST_GROUP; group++) {
+    gs_unref_object GMenu *section = g_menu_new ();
 
-  if (encoding->validity_checked)
-    return encoding->valid;
+    for (guint i = 0; i < G_N_ELEMENTS (encodings); i++) {
+      if (array[i].group != group)
+        continue;
 
-  /* Test that the encoding is a proper superset of ASCII (which naive
-   * apps are going to use anyway) by attempting to validate the text
-   * using the current encoding.  This also flushes out any encodings
-   * which the underlying GIConv implementation can't support.
-   */
-  converted = g_convert (ascii_sample, sizeof (ascii_sample) - 1,
-                         terminal_encoding_get_charset (encoding), "UTF-8",
-                         &bytes_read, &bytes_written, &error);
+      gs_free_gstring GString *str = g_string_sized_new (128);
+      g_string_append (str, array[i].name);
+      g_string_append (str, " " EM_DASH " ");
+      for (const char *p = array[i].charset; *p; p++) {
+        if (*p == '_')
+          g_string_append (str, "__");
+        else
+          g_string_append_c (str, *p);
+      }
 
-  /* The encoding is only valid if ASCII passes through cleanly. */
-  encoding->valid = (bytes_read == (sizeof (ascii_sample) - 1)) &&
-                    (converted != NULL) &&
-                    (strcmp (converted, ascii_sample) == 0);
+      gs_unref_object GMenuItem *item = g_menu_item_new (str->str, NULL);
+      g_menu_item_set_action_and_target (item, "win.encoding", "s", array[i].charset);
 
-#ifdef ENABLE_DEBUG
-  _TERMINAL_DEBUG_IF (TERMINAL_DEBUG_ENCODINGS)
-  {
-    if (!encoding->valid)
-      {
-        _terminal_debug_print (TERMINAL_DEBUG_ENCODINGS,
-                               "Rejecting encoding %s as invalid:\n",
-                               terminal_encoding_get_charset (encoding));
-        _terminal_debug_print (TERMINAL_DEBUG_ENCODINGS,
-                               " input  \"%s\"\n",
-                               ascii_sample);
-        _terminal_debug_print (TERMINAL_DEBUG_ENCODINGS,
-                               " output \"%s\" bytes read %" G_GSIZE_FORMAT " written %" G_GSIZE_FORMAT "\n",
-                               converted ? converted : "(null)", bytes_read, bytes_written);
-        if (error)
-          _terminal_debug_print (TERMINAL_DEBUG_ENCODINGS,
-                                 " Error: %s\n",
-                                 error->message);
-      }
-    else
-        _terminal_debug_print (TERMINAL_DEBUG_ENCODINGS,
-                               "Encoding %s is valid\n\n",
-                               terminal_encoding_get_charset (encoding));
+      g_menu_append_item (section, item);
+    }
+
+    g_menu_append_section (menu, _(group_names[group].name), G_MENU_MODEL (section));
   }
-#endif
+}
+
+/**
+ * terminal_encodings_list_store_new:
+ *
+ * Creates a #GtkListStore containing the known encodings.
+ * The model containing 2 columns, the 0th one with the
+ * charset name, and the 1st one with the label.
+ * The model is unsorted.
+ *
+ * Returns: (transfer full): a new #GtkTreeModel
+ */
+GtkListStore *
+terminal_encodings_list_store_new (int column_id,
+                                   int column_text)
+{
+  GtkListStore *store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
 
-  g_clear_error (&error);
-  g_free (converted);
+  for (guint i = 0; i < G_N_ELEMENTS (encodings); i++) {
+    gs_free char *name = g_strdup_printf ("%s " EM_DASH " %s",
+                                          encodings[i].name, encodings[i].charset);
 
-  encoding->validity_checked = TRUE;
-  return encoding->valid;
-}
+    GtkTreeIter iter;
+    gtk_list_store_insert_with_values (store, &iter, -1,
+                                       column_id, encodings[i].charset,
+                                       column_text, name,
+                                       -1);
+  }
 
-G_DEFINE_BOXED_TYPE (TerminalEncoding, terminal_encoding,
-                     terminal_encoding_ref,
-                     terminal_encoding_unref);
+  return store;
+}
 
-GHashTable *
-terminal_encodings_get_builtins (void)
+static int
+compare_charset_cb (const void *ap,
+                    const void *bp)
 {
-  GHashTable *encodings_hashtable;
-  guint i;
-  TerminalEncoding *encoding;
-
-  encodings_hashtable = g_hash_table_new_full (g_str_hash, g_str_equal,
-                                               NULL,
-                                               (GDestroyNotify) terminal_encoding_unref);
+  const EncodingEntry *a = ap;
+  const EncodingEntry *b = bp;
 
-  for (i = 0; i < G_N_ELEMENTS (encodings); ++i)
-    {
-      encoding = terminal_encoding_new (encodings[i].charset,
-                                        _(encodings[i].name),
-                                        FALSE,
-                                        FALSE);
-      g_hash_table_insert (encodings_hashtable,
-                           (gpointer) terminal_encoding_get_charset (encoding),
-                           encoding);
-    }
+  return strcmp (a->charset, b->charset);
+}
 
-  return encodings_hashtable;
+gboolean
+terminal_encodings_is_known_charset (const char *charset)
+{
+  EncodingEntry key = { charset, NULL, 0 };
+  return bsearch (&key,
+                  encodings, G_N_ELEMENTS (encodings),
+                  sizeof (encodings[0]),
+                  compare_charset_cb) != NULL;
 }
diff --git a/src/terminal-encoding.h b/src/terminal-encoding.h
index 63c27ba..c3336df 100644
--- a/src/terminal-encoding.h
+++ b/src/terminal-encoding.h
@@ -1,7 +1,6 @@
-/* Encoding stuff */
-
 /*
  * Copyright © 2002 Red Hat, Inc.
+ * Copyright © 2017 Christian Persch
  *
  * 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
@@ -22,34 +21,11 @@
 
 #include <gtk/gtk.h>
 
-#define TERMINAL_TYPE_ENCODING (terminal_encoding_get_type ())
-
-typedef struct
-{
-  int   refcount;
-  const char *charset; /* interned */
-  char *name;
-  guint valid            : 1;
-  guint validity_checked : 1;
-  guint is_custom        : 1;
-  guint is_active        : 1;
-} TerminalEncoding;
-
-GType terminal_encoding_get_type (void);
-
-TerminalEncoding *terminal_encoding_new (const char *charset,
-                                         const char *display_name,
-                                         gboolean is_custom,
-                                         gboolean force_valid);
-
-TerminalEncoding *terminal_encoding_ref (TerminalEncoding *encoding);
-
-void terminal_encoding_unref (TerminalEncoding *encoding);
-
-gboolean terminal_encoding_is_valid (TerminalEncoding *encoding);
+gboolean terminal_encodings_is_known_charset (const char *charset);
 
-const char *terminal_encoding_get_charset (TerminalEncoding *encoding);
+void terminal_encodings_append_menu (GMenu *menu);
 
-GHashTable *terminal_encodings_get_builtins (void);
+GtkListStore *terminal_encodings_list_store_new (int column_id,
+                                                 int column_text);
 
 #endif /* TERMINAL_ENCODING_H */
diff --git a/src/terminal-libgsystem.h b/src/terminal-libgsystem.h
index 90d61b9..e2e5080 100644
--- a/src/terminal-libgsystem.h
+++ b/src/terminal-libgsystem.h
@@ -53,6 +53,7 @@ GS_DEFINE_CLEANUP_FUNCTION0(GBytes*, gs_local_bytes_unref, g_bytes_unref)
 GS_DEFINE_CLEANUP_FUNCTION0(GChecksum*, gs_local_checksum_free, g_checksum_free)
 GS_DEFINE_CLEANUP_FUNCTION0(GError*, gs_local_free_error, g_error_free)
 GS_DEFINE_CLEANUP_FUNCTION0(GHashTable*, gs_local_hashtable_unref, g_hash_table_unref)
+GS_DEFINE_CLEANUP_FUNCTION0(GKeyFile*, gs_local_key_file_unref, g_key_file_unref)
 GS_DEFINE_CLEANUP_FUNCTION0(GList*, gs_local_list_free, g_list_free)
 GS_DEFINE_CLEANUP_FUNCTION0(GMatchInfo*, gs_local_match_info_free, g_match_info_free)
 GS_DEFINE_CLEANUP_FUNCTION0(GObject*, gs_local_obj_unref, g_object_unref)
@@ -67,6 +68,14 @@ GS_DEFINE_CLEANUP_FUNCTION0(GVariantIter*, gs_local_variant_iter_free, g_variant
 GS_DEFINE_CLEANUP_FUNCTION(char**, gs_local_strfreev, g_strfreev)
 GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free)
 
+/* special */
+
+static inline void gs_local_gstring_free (void *v) \
+{                                                  \
+  if (*(GString**)v)                               \
+    g_string_free (*(GString**)v, TRUE);           \
+}
+
 /**
  * gs_free:
  *
@@ -138,6 +147,15 @@ GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free)
 #define gs_unref_hashtable __attribute__ ((cleanup(gs_local_hashtable_unref)))
 
 /**
+ * gs_unref_key_file:
+ *
+ * Call g_key_file_unref() on a variable location when it goes out
+ * of scope.  Note that unlike g_key_file_unref(), the variable may
+ * be %NULL.
+ */
+#define gs_unref_key_file __attribute__ ((cleanup(gs_local_key_file_unref)))
+
+/**
  * gs_free_checksum:
  *
  * Call g_checksum_free() on a variable location when it goes out
@@ -216,6 +234,15 @@ GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free)
  */
 #define gs_unref_settings_schema_key __attribute__ ((cleanup(gs_local_settings_schema_key_unref)))
 
+/**
+ * gs_free_gstring:
+ *
+ * Call g_string_free(TRUE) on a variable location when it goes out
+ * of scope.  Note that unlike g_string_free(), the variable may
+ * be %NULL.
+ */
+#define gs_free_gstring __attribute__ ((cleanup(gs_local_gstring_free)))
+
 G_END_DECLS
 
 #endif
diff --git a/src/terminal-menu-button.c b/src/terminal-menu-button.c
new file mode 100644
index 0000000..fdaaffa
--- /dev/null
+++ b/src/terminal-menu-button.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright © 2017 Christian Persch
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANMENUILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "terminal-menu-button.h"
+#include "terminal-intl.h"
+#include "terminal-libgsystem.h"
+
+/* All this just because GtkToggleButton:toggled is RUN_FIRST (and the
+ * notify::active comes after the toggled signal). :-(
+ */
+
+enum
+{
+  UPDATE_MENU,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+/* The menu button sets itself insensitive when it has no menu.
+ * Work around this by using an empty menu.
+ */
+static void
+set_empty_menu (GtkMenuButton *button)
+{
+  gs_unref_object GMenu *menu = g_menu_new ();
+  gtk_menu_button_set_menu_model (button, G_MENU_MODEL (menu));
+}
+
+/* Class implementation */
+
+G_DEFINE_TYPE (TerminalMenuButton, terminal_menu_button, GTK_TYPE_MENU_BUTTON);
+
+static void
+terminal_menu_button_init (TerminalMenuButton *button_)
+{
+  GtkButton *button = GTK_BUTTON (button_);
+  GtkMenuButton *menu_button = GTK_MENU_BUTTON (button_);
+
+  gtk_button_set_relief (button, GTK_RELIEF_NONE);
+  gtk_button_set_focus_on_click (button, FALSE);
+  gtk_menu_button_set_use_popover (menu_button, FALSE);
+  set_empty_menu (menu_button);
+}
+
+static void
+terminal_menu_button_toggled (GtkToggleButton *button)
+{
+  gboolean active = gtk_toggle_button_get_active (button); /* this is already the new state */
+
+  /* On activate, update the menu */
+  if (active)
+    g_signal_emit (button, signals[UPDATE_MENU], 0);
+
+  GTK_TOGGLE_BUTTON_CLASS (terminal_menu_button_parent_class)->toggled (button);
+
+  /* On deactivate, clear the menu */
+  if (!active)
+    set_empty_menu (GTK_MENU_BUTTON (button));
+}
+
+static void
+terminal_menu_button_class_init (TerminalMenuButtonClass *klass)
+{
+  GtkToggleButtonClass *toggle_button_class = GTK_TOGGLE_BUTTON_CLASS (klass);
+
+  toggle_button_class->toggled = terminal_menu_button_toggled;
+
+  signals[UPDATE_MENU] =
+    g_signal_new (I_("update-menu"),
+                  G_OBJECT_CLASS_TYPE (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (TerminalMenuButtonClass, update_menu),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE,
+                  0);
+}
+
+/* public API */
+
+/**
+ * terminal_menu_button_new:
+ *
+ * Returns: a new #TerminalMenuButton
+ */
+GtkWidget *
+terminal_menu_button_new (void)
+{
+  return g_object_new (TERMINAL_TYPE_MENU_BUTTON, NULL);
+}
diff --git a/src/terminal-menu-button.h b/src/terminal-menu-button.h
new file mode 100644
index 0000000..c9362d0
--- /dev/null
+++ b/src/terminal-menu-button.h
@@ -0,0 +1,57 @@
+/*
+ *  Copyright © 2008, 2017 Christian Persch
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANMENUILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TERMINAL_MENU_BUTTON_H
+#define TERMINAL_MENU_BUTTON_H
+
+#include <gtk/gtk.h>
+
+#include "terminal-screen.h"
+
+G_BEGIN_DECLS
+
+#define TERMINAL_TYPE_MENU_BUTTON         (terminal_menu_button_get_type ())
+#define TERMINAL_MENU_BUTTON(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), TERMINAL_TYPE_MENU_BUTTON, 
TerminalMenuButton))
+#define TERMINAL_MENU_BUTTON_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), TERMINAL_TYPE_MENU_BUTTON, 
TerminalMenuButtonClass))
+#define TERMINAL_IS_MENU_BUTTON(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), TERMINAL_TYPE_MENU_BUTTON))
+#define TERMINAL_IS_MENU_BUTTON_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), TERMINAL_TYPE_MENU_BUTTON))
+#define TERMINAL_MENU_BUTTON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TERMINAL_TYPE_MENU_BUTTON, 
TerminalMenuButtonClass))
+
+typedef struct _TerminalMenuButton        TerminalMenuButton;
+typedef struct _TerminalMenuButtonClass   TerminalMenuButtonClass;
+typedef struct _TerminalMenuButtonPrivate TerminalMenuButtonPrivate;
+
+struct _TerminalMenuButton
+{
+  GtkMenuButton parent_instance;
+};
+
+struct _TerminalMenuButtonClass
+{
+  GtkMenuButtonClass parent_class;
+
+  /* Signals */
+  void (* update_menu) (TerminalMenuButton *menu_button);
+};
+
+GType      terminal_menu_button_get_type (void);
+
+GtkWidget *terminal_menu_button_new      (void);
+
+G_END_DECLS
+
+#endif /* !TERMINAL_MENU_BUTTON_H */
diff --git a/src/terminal-menubar.ui b/src/terminal-menubar.ui
new file mode 100644
index 0000000..664942c
--- /dev/null
+++ b/src/terminal-menubar.ui
@@ -0,0 +1,252 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Copyright © 2012, 2017 Christian Persch
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+-->
+<interface>
+  <menu id="menubar">
+    <submenu>
+      <attribute name="label" translatable="yes">_File</attribute>
+      <section id="new-terminal-section" />
+      <section>
+        <item>
+          <attribute name="label" translatable="yes">New _Profile…</attribute>
+          <attribute name="action">win.new-profile</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">_Save Contents…</attribute>
+          <attribute name="action">win.save-contents</attribute>
+          <attribute name="hidden-when">action-missing</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">_Export…</attribute>
+          <attribute name="action">win.export</attribute>
+          <attribute name="hidden-when">action-missing</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">_Print…</attribute>
+          <attribute name="action">win.print</attribute>
+          <attribute name="hidden-when">action-missing</attribute>
+        </item>
+      </section>
+      <section>
+        <item>
+          <attribute name="label" translatable="yes">C_lose Tab</attribute>
+          <attribute name="action">win.close</attribute>
+          <attribute name="target">tab</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">_Close Window</attribute>
+          <attribute name="action">win.close</attribute>
+          <attribute name="target">window</attribute>
+        </item>
+      </section>
+    </submenu>
+    <submenu>
+      <attribute name="label" translatable="yes">_Edit</attribute>
+      <section>
+        <item>
+          <attribute name="label" translatable="yes">_Copy</attribute>
+          <attribute name="action">win.copy</attribute>
+          <attribute name="target">text</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">Copy as _HTML</attribute>
+          <attribute name="action">win.copy</attribute>
+          <attribute name="target">html</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">_Paste</attribute>
+          <attribute name="action">win.paste-text</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">Paste as _Filenames</attribute>
+          <attribute name="action">win.paste-uris</attribute>
+          <attribute name="hidden-when">action-disabled</attribute>
+        </item>
+      </section>
+      <section>
+        <item>
+          <attribute name="label" translatable="yes">Select _All</attribute>
+          <attribute name="action">win.select-all</attribute>
+        </item>
+      </section>
+      <section>
+        <item>
+          <attribute name="label" translatable="yes">P_references…</attribute>
+          <attribute name="action">win.edit-preferences</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">Pr_ofile Preferences…</attribute>
+          <attribute name="action">win.edit-profile</attribute>
+        </item>
+      </section>
+    </submenu>
+    <submenu>
+      <attribute name="label" translatable="yes">_View</attribute>
+      <section>
+        <item>
+          <attribute name="label" translatable="yes">Show _Menubar</attribute>
+          <attribute name="action">win.menubar-visible</attribute>
+          <attribute name="hidden-when">action-disabled</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">_Full Screen</attribute>
+          <attribute name="action">win.fullscreen</attribute>
+        </item>
+      </section>
+      <section>
+        <item>
+          <attribute name="label" translatable="yes">Zoom _In</attribute>
+          <attribute name="action">win.zoom-in</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">_Normal Size</attribute>
+          <attribute name="action">win.zoom-normal</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">Zoom _Out</attribute>
+          <attribute name="action">win.zoom-out</attribute>
+        </item>
+      </section>
+    </submenu>
+    <submenu>
+      <attribute name="label" translatable="yes">_Find</attribute>
+      <section>
+        <item>
+          <attribute name="label" translatable="yes">_Find…</attribute>
+          <attribute name="action">win.find</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">Find _Next</attribute>
+          <attribute name="action">win.find-forward</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">Find _Previous</attribute>
+          <attribute name="action">win.find-backward</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">_Clear Highlight</attribute>
+          <attribute name="action">win.find-clear</attribute>
+        </item>
+      </section>
+    </submenu>
+    <submenu>
+      <attribute name="label" translatable="yes">_Terminal</attribute>
+      <section>
+        <section id="set-profile-section" />
+        <item>
+          <attribute name="label" translatable="yes">Set _Title…</attribute>
+          <attribute name="action">win.set-title</attribute>
+          <attribute name="hidden-when">action-missing</attribute>
+        </item>
+        <submenu id="set-encoding-submenu">
+          <attribute name="label" translatable="yes">Set _Character Encoding</attribute>
+        </submenu>
+      </section>
+      <section>
+        <item>
+          <attribute name="label" translatable="yes">Read-_Only</attribute>
+          <attribute name="action">win.read-only</attribute>
+        </item>
+      </section>
+      <section>
+        <item>
+          <attribute name="label" translatable="yes">_Reset</attribute>
+          <attribute name="action">win.reset</attribute>
+          <attribute name="target" type="b">false</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">Reset and C_lear</attribute>
+          <attribute name="action">win.reset</attribute>
+          <attribute name="target" type="b">true</attribute>
+        </item>
+      </section>
+      <section>
+        <item>
+          <attribute name="label" translatable="yes">_1. 80×24</attribute>
+          <attribute name="action">win.size-to</attribute>
+          <attribute name="target" type="(uu)">(80, 24)</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">_1. 80×43</attribute>
+          <attribute name="action">win.size-to</attribute>
+          <attribute name="target" type="(uu)">(80, 43)</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">_1. 132×24</attribute>
+          <attribute name="action">win.size-to</attribute>
+          <attribute name="target" type="(uu)">(132, 24)</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">_1. 132×42</attribute>
+          <attribute name="action">win.size-to</attribute>
+          <attribute name="target" type="(uu)">(132, 43)</attribute>
+        </item>
+      </section>
+    </submenu>
+    <submenu>
+      <attribute name="label" translatable="yes">Ta_bs</attribute>
+      <attribute name="action">win.tabs-menu</attribute>
+      <attribute name="hidden-when">action-disabled</attribute>
+      <section>
+        <item>
+          <attribute name="label" translatable="yes">_Previous Tab</attribute>
+          <attribute name="action">win.tab-switch-left</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">_Next Tab</attribute>
+          <attribute name="action">win.tab-switch-right</attribute>
+        </item>
+      </section>
+      <section>
+        <item>
+          <attribute name="label" translatable="yes">Move Tab _Left</attribute>
+          <attribute name="action">win.tab-move-left</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">Move Tab _Right</attribute>
+          <attribute name="action">win.tab-move-right</attribute>
+        </item>
+      </section>
+      <section>
+        <item>
+          <attribute name="label" translatable="yes">_Detach Tab</attribute>
+          <attribute name="action">win.tab-detach</attribute>
+        </item>
+      </section>
+    </submenu>
+    <submenu>
+      <attribute name="label" translatable="yes">_Help</attribute>
+      <section>
+        <item>
+          <attribute name="label" translatable="yes">_Contents</attribute>
+          <attribute name="action">win.help</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">_About</attribute>
+          <attribute name="action">win.about</attribute>
+        </item>
+      </section>
+      <section>
+        <item>
+          <attribute name="label" translatable="yes">_Inspector</attribute>
+          <attribute name="action">win.inspector</attribute>
+          <attribute name="hidden-when">action-disabled</attribute>
+        </item>
+      </section>
+    </submenu>
+  </menu>
+</interface>
diff --git a/src/terminal-menus.ui b/src/terminal-notebook-menu.ui
similarity index 54%
rename from src/terminal-menus.ui
rename to src/terminal-notebook-menu.ui
index e248590..8854a7b 100644
--- a/src/terminal-menus.ui
+++ b/src/terminal-notebook-menu.ui
@@ -16,32 +16,28 @@
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 -->
 <interface>
-  <menu id="app-menu">
+  <menu id="notebook-popup">
     <section>
       <item>
-        <attribute name="label" translatable="yes">_New Terminal</attribute>
-        <attribute name="action">win.new-terminal</attribute>
-        <attribute name="target" type="(ss)">('default','default')</attribute>
+        <attribute name="label" translatable="yes">Move Terminal _Left</attribute>
+        <attribute name="action">win.tab-move-left</attribute>
       </item>
-    </section>
-    <section>
       <item>
-        <attribute name="label" translatable="yes">_Preferences</attribute>
-        <attribute name="action">app.preferences</attribute>
+        <attribute name="label" translatable="yes">Move Terminal _Right</attribute>
+        <attribute name="action">win.tab-move-right</attribute>
       </item>
     </section>
     <section>
       <item>
-        <attribute name="label" translatable="yes">_Help</attribute>
-        <attribute name="action">app.help</attribute>
-      </item>
-      <item>
-        <attribute name="label" translatable="yes">_About</attribute>
-        <attribute name="action">app.about</attribute>
+        <attribute name="label" translatable="yes">_Detach Terminal</attribute>
+        <attribute name="action">win.tab-detach</attribute>
       </item>
+    </section>
+    <section>
       <item>
-        <attribute name="label" translatable="yes">_Quit</attribute>
-        <attribute name="action">app.quit</attribute>
+        <attribute name="label" translatable="yes">C_lose Terminal</attribute>
+        <attribute name="action">win.close</attribute>
+        <attribute name="target">tab</attribute>
       </item>
     </section>
   </menu>
diff --git a/src/terminal-notebook.c b/src/terminal-notebook.c
index 392c978..19d938e 100644
--- a/src/terminal-notebook.c
+++ b/src/terminal-notebook.c
@@ -105,6 +105,15 @@ close_button_clicked_cb (TerminalTabLabel *tab_label,
 }
 
 
+static void
+remove_reorder_bindings (GtkBindingSet    *binding_set,
+                         guint             keysym)
+{
+  guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
+  gtk_binding_entry_skip (binding_set, keysym, GDK_MOD1_MASK);
+  gtk_binding_entry_skip (binding_set, keypad_keysym, GDK_MOD1_MASK);
+}
+
 /* TerminalMdiContainer impl */
 
 static void
@@ -560,6 +569,21 @@ terminal_notebook_class_init (TerminalNotebookClass *klass)
                         GTK_TYPE_POLICY_TYPE,
                         GTK_POLICY_AUTOMATIC,
                         G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /* Remove unwanted and interfering keybindings */
+  GtkBindingSet *binding_set = gtk_binding_set_by_class (terminal_notebook_parent_class);
+  gtk_binding_entry_skip (binding_set, GDK_KEY_Page_Up, GDK_CONTROL_MASK);
+  gtk_binding_entry_skip (binding_set, GDK_KEY_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+  gtk_binding_entry_skip (binding_set, GDK_KEY_Page_Down, GDK_CONTROL_MASK);
+  gtk_binding_entry_skip (binding_set, GDK_KEY_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+  remove_reorder_bindings (binding_set, GDK_KEY_Up);
+  remove_reorder_bindings (binding_set, GDK_KEY_Down);
+  remove_reorder_bindings (binding_set, GDK_KEY_Left);
+  remove_reorder_bindings (binding_set, GDK_KEY_Right);
+  remove_reorder_bindings (binding_set, GDK_KEY_Home);
+  remove_reorder_bindings (binding_set, GDK_KEY_Home);
+  remove_reorder_bindings (binding_set, GDK_KEY_End);
+  remove_reorder_bindings (binding_set, GDK_KEY_End);
 }
 
 /* public API */
diff --git a/src/terminal-prefs.c b/src/terminal-prefs.c
index cd7b0d9..8e59ca1 100644
--- a/src/terminal-prefs.c
+++ b/src/terminal-prefs.c
@@ -34,7 +34,6 @@
 #include "terminal-schemas.h"
 #include "terminal-util.h"
 #include "terminal-profiles-list.h"
-#include "terminal-encoding.h"
 #include "terminal-libgsystem.h"
 
 typedef struct {
@@ -48,10 +47,6 @@ typedef struct {
   GtkWidget *manage_profiles_clone_button;
   GtkWidget *manage_profiles_delete_button;
   GtkWidget *profiles_default_combo;
-
-  GtkListStore *encoding_base_store;
-  GtkTreeModel *encodings_model;
-  GtkTreeView *encodings_tree_view;
 } PrefData;
 
 static GtkWidget *prefs_dialog = NULL;
@@ -60,7 +55,7 @@ static void
 prefs_dialog_help_button_clicked_cb (GtkWidget *button,
                                      PrefData *data)
 {
-  terminal_util_show_help ("pref", GTK_WINDOW (data->dialog));
+  terminal_util_show_help ("pref");
 }
 
 static void
@@ -300,7 +295,7 @@ profile_list_row_activated_cb (GtkTreeView *tree_view,
   if (selected_profile == NULL)
     return;
 
-  terminal_app_edit_profile (terminal_app_get (), selected_profile, NULL, NULL);
+  terminal_app_edit_profile (terminal_app_get (), selected_profile, NULL);
 }
 
 static GtkTreeView *
@@ -399,7 +394,7 @@ static void
 profile_list_new_button_clicked_cb (GtkWidget *button,
                                     PrefData *data)
 {
-  terminal_app_new_profile (terminal_app_get (), NULL, GTK_WINDOW (data->parent));
+  terminal_app_new_profile (terminal_app_get (), NULL);
 }
 
 static void
@@ -412,7 +407,7 @@ profile_list_clone_button_clicked_cb (GtkWidget *button,
   if (selected_profile == NULL)
     return;
 
-  terminal_app_new_profile (terminal_app_get (), selected_profile, GTK_WINDOW (data->parent));
+  terminal_app_new_profile (terminal_app_get (), selected_profile);
 }
 
 static void
@@ -425,134 +420,40 @@ profile_list_edit_button_clicked_cb (GtkWidget *button,
   if (selected_profile == NULL)
     return;
 
-  terminal_app_edit_profile (terminal_app_get (), selected_profile, NULL, NULL);
+  terminal_app_edit_profile (terminal_app_get (), selected_profile, NULL);
 }
 
 static void
 profile_list_selection_changed_cb (GtkTreeSelection *selection,
                                    PrefData *data)
 {
-  gboolean selected;
-  gs_unref_object GSettings *selected_profile;
-
-  selected = gtk_tree_selection_get_selected (selection, NULL, NULL);
-  selected_profile = profile_list_ref_selected (data);
+  gboolean selected = gtk_tree_selection_get_selected (selection, NULL, NULL);
 
   gtk_widget_set_sensitive (data->manage_profiles_edit_button, selected);
   gtk_widget_set_sensitive (data->manage_profiles_clone_button, selected);
-  gtk_widget_set_sensitive (data->manage_profiles_delete_button,
-                            selected && 
-                            terminal_app_can_remove_profile (terminal_app_get (), selected_profile));
+  gtk_widget_set_sensitive (data->manage_profiles_delete_button, selected);
 }
 
 /* Keybindings tab */
 
 /* Encodings tab */
 
-static void
-update_active_encodings_setting (void)
-{
-  TerminalApp *app;
-  GSList *list, *l;
-  GVariantBuilder builder;
-  GSettings *settings;
-
-  app = terminal_app_get ();
-
-  g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
-
-  list = terminal_app_get_active_encodings (app);
-  for (l = list; l != NULL; l = l->next)
-    {
-      TerminalEncoding *encoding = (TerminalEncoding *) l->data;
-
-      g_variant_builder_add (&builder, "s", terminal_encoding_get_charset (encoding));
-    }
-  g_slist_foreach (list, (GFunc) terminal_encoding_unref, NULL);
-  g_slist_free (list);
-
-  settings = terminal_app_get_global_settings (app);
-  g_settings_set (settings, TERMINAL_SETTING_ENCODINGS_KEY, "as", &builder);
-}
-
-enum
-{
-  COLUMN_NAME,
-  COLUMN_CHARSET,
-  COLUMN_DATA,
-  N_ENCODING_COLUMNS
-};
-
-static void
-encoding_active_toggled_cb (GtkCellRendererToggle *cell,
-                            gchar *path_as_string,
-                            PrefData *data)
-{
-  GtkTreePath *path;
-  GtkTreeIter iter;
-  TerminalEncoding *encoding;
-
-  path = gtk_tree_path_new_from_string (path_as_string);
-  if (!gtk_tree_model_get_iter (data->encodings_model, &iter, path))
-    goto out;
-
-  gtk_tree_model_get (data->encodings_model, &iter, COLUMN_DATA, &encoding, -1);
-  g_assert (encoding != NULL);
-
-  encoding->is_active = !encoding->is_active;
-  terminal_encoding_unref (encoding);
-
-  gtk_tree_model_row_changed (GTK_TREE_MODEL (data->encodings_model), path, &iter);
-
-  /* Persist the change */
-  update_active_encodings_setting ();
-
- out:
-  gtk_tree_path_free (path);
-}
-
-static void
-encoding_active_cell_data_func (GtkTreeViewColumn *tree_column,
-                                GtkCellRenderer *cell,
-                                GtkTreeModel *tree_model,
-                                GtkTreeIter *iter,
-                                PrefData *data)
-{
-  TerminalEncoding *encoding;
-
-  gtk_tree_model_get (tree_model, iter, (int) COLUMN_DATA, &encoding, -1);
-  g_object_set (G_OBJECT (cell), "active", encoding->is_active, NULL);
-  terminal_encoding_unref (encoding);
-}
-
-static void
-encodings_list_changed_cb (PrefData *data)
-{
-  /* We just queue a redraw here which will take care of everything */
-  gtk_widget_queue_draw (GTK_WIDGET (data->encodings_tree_view));
-}
-
 /* misc */
 
 static void
 prefs_dialog_destroy_cb (GtkWidget *widget,
                          PrefData *data)
 {
-  TerminalApp *app = terminal_app_get ();
-
   g_signal_handlers_disconnect_by_func (data->profiles_list, G_CALLBACK (profile_combo_box_refill), data);
   g_signal_handlers_disconnect_by_func (data->profiles_list, G_CALLBACK (profile_list_treeview_refill), 
data);
 
-  g_signal_handlers_disconnect_by_func (app, G_CALLBACK (encodings_list_changed_cb), data);
-
   /* Don't run this handler again */
   g_signal_handlers_disconnect_by_func (widget, G_CALLBACK (prefs_dialog_destroy_cb), data);
   g_free (data);
 }
 
 void
-terminal_prefs_show_preferences (GtkWindow *transient_parent,
-                                 const char *page)
+terminal_prefs_show_preferences (const char *page)
 {
   TerminalApp *app = terminal_app_get ();
   PrefData *data;
@@ -560,25 +461,20 @@ terminal_prefs_show_preferences (GtkWindow *transient_parent,
   GtkWidget *show_menubar_button, *disable_mnemonics_button, *disable_menu_accel_button;
   GtkWidget *disable_shortcuts_button;
   GtkWidget *tree_view_container, *new_button, *edit_button, *clone_button, *remove_button;
-  GtkWidget *theme_variant_label, *theme_variant_combo, *new_terminal_mode_combo;
+  GtkWidget *theme_variant_label, *theme_variant_combo;
+  GtkWidget *new_terminal_mode_label, *new_terminal_mode_combo;
   GtkWidget *default_hbox, *default_label;
   GtkWidget *close_button, *help_button;
   GtkTreeSelection *selection;
   GSettings *settings;
-  GtkCellRenderer *cell_renderer;
-  GtkTreeViewColumn *column;
-  GtkListStore *list_store;
-  GHashTableIter ht_iter;
-  gpointer key, value;
 
   if (prefs_dialog != NULL)
     goto done;
 
   data = g_new0 (PrefData, 1);
-  data->parent = transient_parent;
   data->profiles_list = terminal_app_get_profiles_list (app);
 
-  terminal_util_load_builder_resource ("/org/gnome/terminal/ui/preferences.ui",
+  terminal_util_load_widgets_resource ("/org/gnome/terminal/ui/preferences.ui",
                                        "preferences-dialog",
                                        "preferences-dialog", &dialog,
                                        "close-button", &close_button,
@@ -586,6 +482,7 @@ terminal_prefs_show_preferences (GtkWindow *transient_parent,
                                        "default-show-menubar-checkbutton", &show_menubar_button,
                                        "theme-variant-label", &theme_variant_label,
                                        "theme-variant-combobox", &theme_variant_combo,
+                                       "new-terminal-mode-label", &new_terminal_mode_label,
                                        "new-terminal-mode-combobox", &new_terminal_mode_combo,
                                        "disable-mnemonics-checkbutton", &disable_mnemonics_button,
                                        "disable-shortcuts-checkbutton", &disable_shortcuts_button,
@@ -598,7 +495,6 @@ terminal_prefs_show_preferences (GtkWindow *transient_parent,
                                        "delete-profile-button", &remove_button,
                                        "default-profile-hbox", &default_hbox,
                                        "default-profile-label", &default_label,
-                                       "encodings-treeview", &data->encodings_tree_view,
                                        NULL);
 
   data->dialog = dialog;
@@ -611,11 +507,19 @@ terminal_prefs_show_preferences (GtkWindow *transient_parent,
 
   /* General tab */
 
-  g_settings_bind (settings,
-                   TERMINAL_SETTING_DEFAULT_SHOW_MENUBAR_KEY,
-                   show_menubar_button,
-                   "active",
-                   G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+  gboolean shell_shows_menubar;
+  g_object_get (gtk_settings_get_default (),
+                "gtk-shell-shows-menubar", &shell_shows_menubar,
+                NULL);
+  if (shell_shows_menubar) {
+    gtk_widget_set_visible (show_menubar_button, FALSE);
+  } else {
+    g_settings_bind (settings,
+                     TERMINAL_SETTING_DEFAULT_SHOW_MENUBAR_KEY,
+                     show_menubar_button,
+                     "active",
+                     G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+  }
 
 #if GTK_CHECK_VERSION (3, 19, 0)
   g_settings_bind (settings,
@@ -628,11 +532,16 @@ terminal_prefs_show_preferences (GtkWindow *transient_parent,
   gtk_widget_set_visible (theme_variant_combo, FALSE);
 #endif /* GTK+ 3.19 */
 
+#ifndef DISUNIFY_NEW_TERMINAL_SECTION
   g_settings_bind (settings,
                    TERMINAL_SETTING_NEW_TERMINAL_MODE_KEY,
                    new_terminal_mode_combo,
                    "active-id",
                    G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET);
+#else
+  gtk_widget_set_visible (new_terminal_mode_label, FALSE);
+  gtk_widget_set_visible (new_terminal_mode_combo, FALSE);
+#endif
 
   /* Keybindings tab */
 
@@ -697,70 +606,6 @@ terminal_prefs_show_preferences (GtkWindow *transient_parent,
   // FIXMEchpe
   gtk_label_set_mnemonic_widget (GTK_LABEL (default_label), data->profiles_default_combo);
 
-  /* Encodings tab */
-
-  selection = gtk_tree_view_get_selection (data->encodings_tree_view);
-  gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
-
-  /* Column 1 */
-  cell_renderer = gtk_cell_renderer_toggle_new ();
-  g_object_set (cell_renderer, "xalign", 0.0, NULL);
-  g_signal_connect (cell_renderer, "toggled",
-                    G_CALLBACK (encoding_active_toggled_cb), data);
-  column = gtk_tree_view_column_new ();
-  gtk_tree_view_column_set_title (column, _("Show"));
-  gtk_tree_view_column_pack_start (column, cell_renderer, FALSE);
-  gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column),
-                                      cell_renderer,
-                                      (GtkCellLayoutDataFunc) encoding_active_cell_data_func,
-                                      data, NULL);
-
-  gtk_tree_view_append_column (data->encodings_tree_view, column);
-
-  /* Column 2 */
-  cell_renderer = gtk_cell_renderer_text_new ();
-  column = gtk_tree_view_column_new_with_attributes (_("_Encoding"),
-                                                    cell_renderer,
-                                                    "markup", COLUMN_NAME,
-                                                    NULL);
-  gtk_tree_view_append_column (data->encodings_tree_view, column);
-  gtk_tree_view_column_set_sort_column_id (column, COLUMN_CHARSET);
-
-  /* Add the data */
-
-  list_store = gtk_list_store_new (N_ENCODING_COLUMNS,
-                                   G_TYPE_STRING,
-                                   G_TYPE_STRING,
-                                   TERMINAL_TYPE_ENCODING);
-  data->encodings_model = GTK_TREE_MODEL (list_store);
-
-  g_hash_table_iter_init (&ht_iter, terminal_app_get_encodings (app));
-  while (g_hash_table_iter_next (&ht_iter, &key, &value)) {
-    TerminalEncoding *encoding = value;
-    GtkTreeIter iter;
-    gs_free char *name;
-
-    name = g_markup_printf_escaped ("%s <span size=\"small\">%s</span>",
-                                    terminal_encoding_get_charset (encoding),
-                                    encoding->name);
-    gtk_list_store_insert_with_values (list_store, &iter, -1,
-                                       COLUMN_NAME, name,
-                                       COLUMN_CHARSET, terminal_encoding_get_charset (encoding),
-                                       COLUMN_DATA, encoding,
-                                       -1);
-  }
-
-  /* Now turn on sorting */
-  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (data->encodings_model),
-                                        COLUMN_CHARSET,
-                                        GTK_SORT_ASCENDING);
-
-  gtk_tree_view_set_model (data->encodings_tree_view, data->encodings_model);
-  g_object_unref (data->encodings_model);
-
-  g_signal_connect_swapped (app, "encoding-list-changed",
-                            G_CALLBACK (encodings_list_changed_cb), data);
-
   /* misc */
 
   g_signal_connect (close_button, "clicked", G_CALLBACK (prefs_dialog_close_button_clicked_cb), data);
@@ -772,8 +617,6 @@ terminal_prefs_show_preferences (GtkWindow *transient_parent,
   g_object_add_weak_pointer (G_OBJECT (dialog), (gpointer *) &prefs_dialog);
 
 done:
-  gtk_window_set_transient_for (GTK_WINDOW (prefs_dialog), transient_parent);
-
   terminal_util_dialog_focus_widget (prefs_dialog, page);
 
   gtk_window_present (GTK_WINDOW (prefs_dialog));
diff --git a/src/terminal-prefs.h b/src/terminal-prefs.h
index 82d423b..1a4bc2d 100644
--- a/src/terminal-prefs.h
+++ b/src/terminal-prefs.h
@@ -22,8 +22,7 @@
 
 G_BEGIN_DECLS
 
-void terminal_prefs_show_preferences (GtkWindow *transient_parent,
-                                      const char *page);
+void terminal_prefs_show_preferences (const char *page);
 
 G_END_DECLS
 
diff --git a/src/terminal-schemas.h b/src/terminal-schemas.h
index 4b734a3..35ab577 100644
--- a/src/terminal-schemas.h
+++ b/src/terminal-schemas.h
@@ -74,7 +74,6 @@ G_BEGIN_DECLS
 #define TERMINAL_SETTING_ENABLE_MENU_BAR_ACCEL_KEY      "menu-accelerator-enabled"
 #define TERMINAL_SETTING_ENABLE_MNEMONICS_KEY           "mnemonics-enabled"
 #define TERMINAL_SETTING_ENABLE_SHORTCUTS_KEY           "shortcuts-enabled"
-#define TERMINAL_SETTING_ENCODINGS_KEY                  "encodings"
 #define TERMINAL_SETTING_NEW_TERMINAL_MODE_KEY          "new-terminal-mode"
 #define TERMINAL_SETTING_SCHEMA_VERSION                 "schema-version"
 #define TERMINAL_SETTING_SHELL_INTEGRATION_KEY          "shell-integration-enabled"
diff --git a/src/terminal-screen.c b/src/terminal-screen.c
index f6cc4a5..b18de53 100644
--- a/src/terminal-screen.c
+++ b/src/terminal-screen.c
@@ -17,7 +17,6 @@
  */
 
 #include "config.h"
-#define _GNU_SOURCE /* for dup3 */
 
 #include "terminal-pcre2.h"
 #include "terminal-regex.h"
@@ -49,6 +48,7 @@
 #include "terminal-accels.h"
 #include "terminal-app.h"
 #include "terminal-debug.h"
+#include "terminal-encoding.h"
 #include "terminal-enums.h"
 #include "terminal-intl.h"
 #include "terminal-marshal.h"
@@ -644,7 +644,7 @@ terminal_screen_finalize (GObject *object)
 
 TerminalScreen *
 terminal_screen_new (GSettings       *profile,
-                     const char      *encoding,
+                     const char      *charset,
                      char           **override_command,
                      const char      *title,
                      const char      *working_dir,
@@ -665,12 +665,11 @@ terminal_screen_new (GSettings       *profile,
    * override the profile encoding; otherwise use the profile
    * encoding.
    */
-  if (encoding != NULL && override_command != NULL) {
-    TerminalEncoding *enc;
-
-    enc = terminal_app_ensure_encoding (terminal_app_get (), encoding);
+  if (charset != NULL &&
+      terminal_encodings_is_known_charset (charset) &&
+      override_command != NULL) {
     vte_terminal_set_encoding (VTE_TERMINAL (screen),
-                               terminal_encoding_get_charset (enc),
+                               charset,
                                NULL);
   }
 
@@ -797,14 +796,9 @@ terminal_screen_profile_changed_cb (GSettings     *profile,
 
   if (!prop_name || prop_name == I_(TERMINAL_PROFILE_ENCODING_KEY))
     {
-      TerminalEncoding *encoding;
-      gs_free char *str;
-
-      str = g_settings_get_string (profile, TERMINAL_PROFILE_ENCODING_KEY);
-      encoding = terminal_app_ensure_encoding (terminal_app_get (), str);
-      vte_terminal_set_encoding (vte_terminal,
-                                 terminal_encoding_get_charset (encoding),
-                                 NULL);
+      gs_free char *charset = g_settings_get_string (profile, TERMINAL_PROFILE_ENCODING_KEY);
+      g_warn_if_fail (terminal_encodings_is_known_charset (charset));
+      vte_terminal_set_encoding (vte_terminal, charset, NULL);
     }
 
   if (!prop_name || prop_name == I_(TERMINAL_PROFILE_CJK_UTF8_AMBIGUOUS_WIDTH_KEY))
@@ -1204,17 +1198,17 @@ get_child_environment (TerminalScreen *screen,
   g_hash_table_remove (env_table, "COLUMNS");
   g_hash_table_remove (env_table, "LINES");
   g_hash_table_remove (env_table, "GNOME_DESKTOP_ICON");
- 
-#ifdef GDK_WINDOWING_X11
-  if (GDK_IS_X11_SCREEN (gtk_widget_get_screen (window)))
-    {
-      /* FIXME: moving the tab between windows, or the window between displays will make the next two 
invalid... */
-      g_hash_table_replace (env_table, g_strdup ("WINDOWID"),
-                           g_strdup_printf ("%lu",
-                                            GDK_WINDOW_XID (gtk_widget_get_window (window))));
-      g_hash_table_replace (env_table, g_strdup ("DISPLAY"), g_strdup (gdk_display_get_name 
(gtk_widget_get_display (window))));
-    }
-#endif
+
+  /* WINDOWID does not work correctly ever since we don't use a native
+   * GdkWindow anymore, and it also becomes incorrect if the screen is
+   * moved to a different window, or the window unrealized and re-realized.
+   * Additionally, it cannot ever work on non-X11 displays like wayland.
+   * And on X11, the only use for this is broken foreign drawing on the
+   * window (w3m etc), and trying to find the focused screen (brltty),
+   * which can now be done correctly using DECSET 1004.
+   * Therefore we do not set WINDOWID, and remove an existing variable.
+   */
+  g_hash_table_remove (env_table, "WINDOWID");
 
   /* We need to put the working directory also in PWD, so that
    * e.g. bash starts in the right directory if @cwd is a symlink.
@@ -1260,7 +1254,6 @@ info_bar_response_cb (GtkWidget *info_bar,
     case RESPONSE_EDIT_PROFILE:
       terminal_app_edit_profile (terminal_app_get (),
                                  terminal_screen_get_profile (screen),
-                                 GTK_WINDOW (terminal_screen_get_window (screen)),
                                  "custom-command-entry");
       break;
     default:
@@ -1487,9 +1480,6 @@ terminal_screen_popup_info_new (TerminalScreen *screen)
 
   info = g_slice_new0 (TerminalScreenPopupInfo);
   info->ref_count = 1;
-  info->screen = g_object_ref (screen);
-
-  g_weak_ref_init (&info->window_weak_ref, terminal_screen_get_window (screen));
 
   return info;
 }
@@ -1511,28 +1501,12 @@ terminal_screen_popup_info_unref (TerminalScreenPopupInfo *info)
   if (--info->ref_count > 0)
     return;
 
-  g_object_unref (info->screen);
-  g_weak_ref_clear (&info->window_weak_ref);
   g_free (info->hyperlink);
   g_free (info->url);
   g_free (info->number_info);
   g_slice_free (TerminalScreenPopupInfo, info);
 }
 
-/**
- * terminal_screen_popup_info_ref_window:
- * @info: a #TerminalScreenPopupInfo
- *
- * Returns: the window, or %NULL
- */
-TerminalWindow *
-terminal_screen_popup_info_ref_window (TerminalScreenPopupInfo *info)
-{
-  g_return_val_if_fail (info != NULL, NULL);
-
-  return g_weak_ref_get (&info->window_weak_ref);
-}
-
 static gboolean
 terminal_screen_popup_menu (GtkWidget *widget)
 {
diff --git a/src/terminal-screen.h b/src/terminal-screen.h
index 2e8f6dc..743071d 100644
--- a/src/terminal-screen.h
+++ b/src/terminal-screen.h
@@ -76,7 +76,7 @@ GType terminal_screen_get_type (void) G_GNUC_CONST;
 const char *terminal_screen_get_uuid (TerminalScreen *screen);
 
 TerminalScreen *terminal_screen_new (GSettings       *profile,
-                                     const char      *encoding,
+                                     const char      *charset,
                                      char           **override_command,
                                      const char      *title,
                                      const char      *working_dir,
@@ -138,8 +138,6 @@ gboolean terminal_screen_has_foreground_process (TerminalScreen *screen,
 
 struct _TerminalScreenPopupInfo {
   int ref_count;
-  GWeakRef window_weak_ref;
-  TerminalScreen *screen;
   char *url;
   TerminalURLFlavor url_flavor;
   char *hyperlink;
@@ -153,8 +151,6 @@ TerminalScreenPopupInfo *terminal_screen_popup_info_ref (TerminalScreenPopupInfo
 
 void terminal_screen_popup_info_unref (TerminalScreenPopupInfo *info);
 
-TerminalWindow *terminal_screen_popup_info_ref_window (TerminalScreenPopupInfo *info);
-
 G_END_DECLS
 
 #endif /* TERMINAL_SCREEN_H */
diff --git a/src/terminal-settings-list.c b/src/terminal-settings-list.c
index e9ed2b8..cdc80b6 100644
--- a/src/terminal-settings-list.c
+++ b/src/terminal-settings-list.c
@@ -817,7 +817,7 @@ terminal_settings_list_remove_child (TerminalSettingsList *list,
  * @list: a #TerminalSettingsList
  * @child: a #GSettings of a child in the list
  *
- * Returns the UUID of @child in the list, or %NULL if @child is in the list.
+ * Returns the UUID of @child in the list, or %NULL if @child is not in the list.
  *
  * Returns: (transfer full): the UUID of the child in the settings list, or %NULL
  */
@@ -837,6 +837,7 @@ terminal_settings_list_dup_uuid_from_child (TerminalSettingsList *list,
   g_return_val_if_fail (p[0] == ':', NULL);
   p++;
   g_return_val_if_fail (strlen (p) == 37, NULL);
+  g_return_val_if_fail (p[36] == '/', NULL);
   p[36] = '\0';
   g_assert (terminal_settings_list_valid_uuid (p));
 
@@ -850,7 +851,7 @@ terminal_settings_list_dup_uuid_from_child (TerminalSettingsList *list,
  *
  * Sets @uuid as the default child.
  */
-void 
+void
 terminal_settings_list_set_default_child (TerminalSettingsList *list,
                                           const char *uuid)
 {
@@ -862,3 +863,43 @@ terminal_settings_list_set_default_child (TerminalSettingsList *list,
 
   g_settings_set_string (&list->parent, TERMINAL_SETTINGS_LIST_DEFAULT_KEY, uuid);
 }
+
+/**
+ * terminal_settings_list_foreach_child:
+ * @list: a #TerminalSettingsList
+ * @callback: a #TerminalSettingsListForeachFunc
+ * @user_data: user data for @callback
+ *
+ * Calls @callback for each child of @list.
+ *
+ * NOTE: No changes to @list must be made from @callback.
+ */
+void
+terminal_settings_list_foreach_child (TerminalSettingsList *list,
+                                      TerminalSettingsListForeachFunc callback,
+                                      gpointer user_data)
+{
+  g_return_if_fail (TERMINAL_IS_SETTINGS_LIST (list));
+  g_return_if_fail (callback);
+
+  for (char **p = list->uuids; *p; p++) {
+    const char *uuid = *p;
+    gs_unref_object GSettings *child = terminal_settings_list_ref_child_internal (list, uuid);
+    if (child != NULL)
+      callback (list, uuid, child, user_data);
+  }
+}
+
+/**
+ * terminal_settings_list_foreach_child:
+ * @list: a #TerminalSettingsList
+ *
+ * Returns: the number of children of @list.
+ */
+guint
+terminal_settings_list_get_n_children (TerminalSettingsList *list)
+{
+  g_return_val_if_fail (TERMINAL_IS_SETTINGS_LIST (list), 0);
+
+  return g_hash_table_size (list->children);
+}
diff --git a/src/terminal-settings-list.h b/src/terminal-settings-list.h
index ed37611..c68c499 100644
--- a/src/terminal-settings-list.h
+++ b/src/terminal-settings-list.h
@@ -69,6 +69,17 @@ char *terminal_settings_list_dup_default_child (TerminalSettingsList *list);
 void terminal_settings_list_set_default_child (TerminalSettingsList *list,
                                                const char *uuid);
 
+typedef void (* TerminalSettingsListForeachFunc) (TerminalSettingsList *list,
+                                                  const char *uuid,
+                                                  GSettings *child,
+                                                  gpointer user_data);
+
+void terminal_settings_list_foreach_child (TerminalSettingsList *list,
+                                           TerminalSettingsListForeachFunc callback,
+                                           gpointer user_data);
+
+guint terminal_settings_list_get_n_children (TerminalSettingsList *list);
+
 gboolean terminal_settings_list_valid_uuid (const char *str);
 
 G_END_DECLS
diff --git a/src/terminal-util.c b/src/terminal-util.c
index b0c73e0..598d6c2 100644
--- a/src/terminal-util.c
+++ b/src/terminal-util.c
@@ -20,7 +20,6 @@
  */
 
 #include "config.h"
-#define _GNU_SOURCE /* for strchrnul */
 
 #include <string.h>
 #include <stdlib.h>
@@ -41,9 +40,7 @@
 #include "terminal-accels.h"
 #include "terminal-app.h"
 #include "terminal-intl.h"
-#include "terminal-screen.h"
 #include "terminal-util.h"
-#include "terminal-window.h"
 #include "terminal-libgsystem.h"
 
 /**
@@ -136,8 +133,7 @@ open_url (GtkWindow *parent,
 }
 
 void
-terminal_util_show_help (const char *topic, 
-                         GtkWindow  *parent)
+terminal_util_show_help (const char *topic)
 {
   gs_free_error GError *error = NULL;
   gs_free char *uri;
@@ -148,9 +144,9 @@ terminal_util_show_help (const char *topic,
     uri = g_strdup ("help:gnome-terminal");
   }
 
-  if (!open_url (GTK_WINDOW (parent), uri, gtk_get_current_event_time (), &error))
+  if (!open_url (NULL, uri, gtk_get_current_event_time (), &error))
     {
-      terminal_util_show_error_dialog (GTK_WINDOW (parent), NULL, error,
+      terminal_util_show_error_dialog (NULL, NULL, error,
                                        _("There was an error displaying help"));
     }
 }
@@ -160,13 +156,13 @@ terminal_util_show_help (const char *topic,
 #define EMAILIFY(string) (g_strdelimit ((string), "%", '@'))
 
 void
-terminal_util_show_about (GtkWindow *transient_parent G_GNUC_UNUSED)
+terminal_util_show_about (void)
 {
   static const char copyright[] =
     "Copyright © 2002–2004 Havoc Pennington\n"
     "Copyright © 2003–2004, 2007 Mariano Suárez-Alvarez\n"
     "Copyright © 2006 Guilherme de S. Pastore\n"
-    "Copyright © 2007–2016 Christian Persch";
+    "Copyright © 2007–2017 Christian Persch";
   char *licence_text;
   GKeyFile *key_file;
   GBytes *bytes;
@@ -277,11 +273,10 @@ terminal_util_set_atk_name_description (GtkWidget  *widget,
       return;
     }
 
-  
   if (!GTK_IS_ACCESSIBLE (obj))
     return; /* This means GAIL is not loaded so we have the NoOp accessible */
-      
-  g_return_if_fail (GTK_IS_ACCESSIBLE (obj));  
+
+  g_return_if_fail (GTK_IS_ACCESSIBLE (obj));
   if (desc)
     atk_object_set_description (obj, desc);
   if (name)
@@ -413,7 +408,7 @@ main_object_destroy_cb (GtkWidget *widget)
 }
 
 void
-terminal_util_load_builder_resource (const char *path,
+terminal_util_load_widgets_resource (const char *path,
                                      const char *main_object_name,
                                      const char *object_name,
                                      ...)
@@ -460,6 +455,37 @@ terminal_util_load_builder_resource (const char *path,
   }
 }
 
+void
+terminal_util_load_objects_resource (const char *path,
+                                     const char *object_name,
+                                     ...)
+{
+  gs_unref_object GtkBuilder *builder;
+  GError *error = NULL;
+  va_list args;
+
+  builder = gtk_builder_new ();
+  gtk_builder_add_from_resource (builder, path, &error);
+  g_assert_no_error (error);
+
+  va_start (args, object_name);
+
+  while (object_name) {
+    GObject **objectptr;
+
+    objectptr = va_arg (args, GObject**);
+    *objectptr = gtk_builder_get_object (builder, object_name);
+    if (*objectptr)
+      g_object_ref (*objectptr);
+    else
+      g_error ("Failed to fetch object \"%s\" from resource \"%s\"\n", object_name, path);
+
+    object_name = va_arg (args, const char*);
+  }
+
+  va_end (args);
+}
+
 gboolean
 terminal_util_dialog_response_on_delete (GtkWindow *widget)
 {
@@ -1285,3 +1311,179 @@ terminal_util_utf8_make_valid (const gchar *str,
 
   return g_string_free (string, FALSE);
 }
+
+#define TERMINAL_CACHE_DIR                 "gnome-terminal"
+#define TERMINAL_PRINT_SETTINGS_FILENAME   "print-settings.ini"
+#define TERMINAL_PRINT_SETTINGS_GROUP_NAME "Print Settings"
+#define TERMINAL_PAGE_SETUP_GROUP_NAME     "Page Setup"
+
+#define KEYFILE_FLAGS_FOR_LOAD (G_KEY_FILE_NONE)
+#define KEYFILE_FLAGS_FOR_SAVE (G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS)
+
+static char *
+get_cache_dir (void)
+{
+  return g_build_filename (g_get_user_cache_dir (), TERMINAL_CACHE_DIR, NULL);
+}
+
+static gboolean
+ensure_cache_dir (void)
+{
+  gs_free char *cache_dir;
+  int r;
+
+  cache_dir = get_cache_dir ();
+  errno = 0;
+  r = g_mkdir_with_parents (cache_dir, 0700);
+  if (r == -1 && errno != EEXIST)
+    g_printerr ("Failed to create cache dir: %m\n");
+  return r == 0;
+}
+
+static char *
+get_cache_filename (const char *filename)
+{
+  gs_free char *cache_dir = get_cache_dir ();
+  return g_build_filename (cache_dir, filename, NULL);
+}
+
+static GKeyFile *
+load_cache_keyfile (const char *filename,
+                    GKeyFileFlags flags,
+                    gboolean ignore_error)
+{
+  gs_free char *path;
+  GKeyFile *keyfile;
+
+  path = get_cache_filename (filename);
+  keyfile = g_key_file_new ();
+  if (g_key_file_load_from_file (keyfile, path, flags, NULL) || ignore_error)
+    return keyfile;
+
+  g_key_file_unref (keyfile);
+  return NULL;
+}
+
+static void
+save_cache_keyfile (GKeyFile *keyfile,
+                    const char *filename)
+{
+  gs_free char *path = NULL;
+  gs_free char *data = NULL;
+  gsize len = 0;
+
+  if (!ensure_cache_dir ())
+    return;
+
+  data = g_key_file_to_data (keyfile, &len, NULL);
+  if (data == NULL || len == 0)
+    return;
+
+  path = get_cache_filename (filename);
+
+  /* Ignore errors */
+  GError *err = NULL;
+  if (!g_file_set_contents (path, data, len, &err)) {
+    g_printerr ("Error saving print settings: %s\n", err->message);
+    g_error_free (err);
+  }
+}
+
+static void
+keyfile_remove_keys (GKeyFile *keyfile,
+                     const char *group_name,
+                     ...)
+{
+  va_list args;
+  const char *key;
+
+  va_start (args, group_name);
+  while ((key = va_arg (args, const char *)) != NULL) {
+    g_key_file_remove_key (keyfile, group_name, key, NULL);
+  }
+  va_end (args);
+}
+
+/**
+ * terminal_util_load_print_settings:
+ *
+ * Loads the saved print settings, if any.
+ */
+void
+terminal_util_load_print_settings (GtkPrintSettings **settings,
+                                   GtkPageSetup **page_setup)
+{
+  gs_unref_key_file GKeyFile *keyfile = load_cache_keyfile (TERMINAL_PRINT_SETTINGS_FILENAME,
+                                                            KEYFILE_FLAGS_FOR_LOAD,
+                                                            FALSE);
+  if (keyfile == NULL) {
+    *settings = NULL;
+    *page_setup = NULL;
+    return;
+  }
+
+  /* Ignore errors */
+  *settings = gtk_print_settings_new_from_key_file (keyfile,
+                                                    TERMINAL_PRINT_SETTINGS_GROUP_NAME,
+                                                    NULL);
+  *page_setup = gtk_page_setup_new_from_key_file (keyfile,
+                                                  TERMINAL_PAGE_SETUP_GROUP_NAME,
+                                                  NULL);
+}
+
+/**
+ * terminal_util_save_print_settings:
+ * @settings: (allow-none): a #GtkPrintSettings
+ * @page_setup: (allow-none): a #GtkPageSetup
+ *
+ * Saves the print settings.
+ */
+void
+terminal_util_save_print_settings (GtkPrintSettings *settings,
+                                   GtkPageSetup *page_setup)
+{
+  gs_unref_key_file GKeyFile *keyfile = NULL;
+
+  keyfile = load_cache_keyfile (TERMINAL_PRINT_SETTINGS_FILENAME,
+                                KEYFILE_FLAGS_FOR_SAVE,
+                                TRUE);
+  g_assert (keyfile != NULL);
+
+  if (settings != NULL)
+    gtk_print_settings_to_key_file (settings, keyfile,
+                                    TERMINAL_PRINT_SETTINGS_GROUP_NAME);
+
+  /* Some keys are not desirable to persist; remove these.
+   * This list comes from evince.
+   */
+  keyfile_remove_keys (keyfile,
+                       TERMINAL_PRINT_SETTINGS_GROUP_NAME,
+                       GTK_PRINT_SETTINGS_COLLATE,
+                       GTK_PRINT_SETTINGS_NUMBER_UP,
+                       GTK_PRINT_SETTINGS_N_COPIES,
+                       GTK_PRINT_SETTINGS_OUTPUT_URI,
+                       GTK_PRINT_SETTINGS_PAGE_RANGES,
+                       GTK_PRINT_SETTINGS_PAGE_SET,
+                       GTK_PRINT_SETTINGS_PRINT_PAGES,
+                       GTK_PRINT_SETTINGS_REVERSE,
+                       GTK_PRINT_SETTINGS_SCALE,
+                       NULL);
+
+  if (page_setup != NULL)
+    gtk_page_setup_to_key_file (page_setup, keyfile,
+                                TERMINAL_PAGE_SETUP_GROUP_NAME);
+
+  /* Some keys are not desirable to persist; remove these.
+   * This list comes from evince.
+   */
+  keyfile_remove_keys (keyfile,
+                       TERMINAL_PAGE_SETUP_GROUP_NAME,
+                       "page-setup-orientation",
+                       "page-setup-margin-bottom",
+                       "page-setup-margin-left",
+                       "page-setup-margin-right",
+                       "page-setup-margin-top",
+                       NULL);
+
+  save_cache_keyfile (keyfile, TERMINAL_PRINT_SETTINGS_FILENAME);
+}
diff --git a/src/terminal-util.h b/src/terminal-util.h
index 040f487..d3b13f2 100644
--- a/src/terminal-util.h
+++ b/src/terminal-util.h
@@ -22,8 +22,6 @@
 #include <gio/gio.h>
 #include <gtk/gtk.h>
 
-#include "terminal-screen.h"
-
 G_BEGIN_DECLS
 
 void terminal_util_show_error_dialog (GtkWindow *transient_parent,
@@ -31,9 +29,9 @@ void terminal_util_show_error_dialog (GtkWindow *transient_parent,
                                       GError *error,
                                       const char *message_format, ...) G_GNUC_PRINTF(4, 5);
 
-void terminal_util_show_help (const char *topic, GtkWindow  *transient_parent);
+void terminal_util_show_help (const char *topic);
 
-void terminal_util_show_about (GtkWindow *transient_parent);
+void terminal_util_show_about (void);
 
 void terminal_util_set_labelled_by          (GtkWidget  *widget,
                                              GtkLabel   *label);
@@ -53,11 +51,15 @@ char *terminal_util_concat_uris (char **uris,
 
 char *terminal_util_get_licence_text (void);
 
-void terminal_util_load_builder_resource (const char *path,
+void terminal_util_load_widgets_resource (const char *path,
                                           const char *main_object_name,
                                           const char *object_name,
                                           ...);
 
+void terminal_util_load_objects_resource (const char *path,
+                                          const char *object_name,
+                                          ...);
+
 void terminal_util_dialog_focus_widget (GtkWidget *dialog,
                                         const char *widget_name);
 
@@ -103,6 +105,12 @@ char *terminal_util_hyperlink_uri_label (const char *str);
 gchar *terminal_util_utf8_make_valid (const gchar *str,
                                       gssize       len) G_GNUC_MALLOC;
 
+void terminal_util_load_print_settings (GtkPrintSettings **settings,
+                                        GtkPageSetup **page_setup);
+
+void terminal_util_save_print_settings (GtkPrintSettings *settings,
+                                        GtkPageSetup *page_setup);
+
 G_END_DECLS
 
 #endif /* TERMINAL_UTIL_H */
diff --git a/src/terminal-window.c b/src/terminal-window.c
index 2719708..cd5d4a3 100644
--- a/src/terminal-window.c
+++ b/src/terminal-window.c
@@ -1,8 +1,7 @@
-
 /*
  * Copyright © 2001 Havoc Pennington
  * Copyright © 2002 Red Hat, Inc.
- * Copyright © 2007, 2008, 2009, 2011 Christian Persch
+ * Copyright © 2007, 2008, 2009, 2011, 2017 Christian Persch
  *
  * 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
@@ -36,12 +35,12 @@
 #include "terminal-icon-button.h"
 #include "terminal-intl.h"
 #include "terminal-mdi-container.h"
+#include "terminal-menu-button.h"
 #include "terminal-notebook.h"
 #include "terminal-schemas.h"
 #include "terminal-screen-container.h"
 #include "terminal-search-popover.h"
 #include "terminal-tab-label.h"
-#include "terminal-tabs-menu.h"
 #include "terminal-util.h"
 #include "terminal-window.h"
 #include "terminal-libgsystem.h"
@@ -52,24 +51,9 @@ struct _TerminalWindowPrivate
 
   GtkClipboard *clipboard;
 
-  GtkActionGroup *action_group;
-  GtkUIManager *ui_manager;
-  guint ui_id;
-
-  GtkActionGroup *profiles_action_group;
-  guint profiles_ui_id;
-
-  GtkActionGroup *encodings_action_group;
-  guint encodings_ui_id;
-
-  TerminalTabsMenu *tabs_menu;
-
   TerminalScreenPopupInfo *popup_info;
   guint remove_popup_info_idle;
 
-  GtkActionGroup *new_terminal_action_group;
-  guint new_terminal_ui_id;
-
   GtkWidget *menubar;
   TerminalMdiContainer *mdi_container;
   GtkWidget *main_vbox;
@@ -101,7 +85,6 @@ struct _TerminalWindowPrivate
   GtkWidget *confirm_close_dialog;
   TerminalSearchPopover *search_popover;
 
-  guint menubar_visible : 1;
   guint use_default_menubar_visibility : 1;
 
   guint disposed : 1;
@@ -115,22 +98,8 @@ struct _TerminalWindowPrivate
 
 #define TERMINAL_WINDOW_CSS_NAME "terminal-window"
 
-#define PROFILE_DATA_KEY "GT::Profile"
-
-#define FILE_NEW_TERMINAL_UI_PATH         "/menubar/File/FileNewTerminalProfiles"
-#define SET_ENCODING_UI_PATH              "/menubar/Terminal/TerminalSetEncoding/EncodingsPH"
-#define SET_ENCODING_ACTION_NAME_PREFIX   "TerminalSetEncoding"
-
-#define PROFILES_UI_PATH        "/menubar/Terminal/TerminalProfiles"
-#define PROFILES_POPUP_UI_PATH  "/Popup/PopupTerminalProfiles/ProfilesPH"
-
-#define SIZE_TO_UI_PATH            "/menubar/Terminal/TerminalSizeToPH"
-#define SIZE_TO_ACTION_NAME_PREFIX "TerminalSizeTo"
-
-#define STOCK_NEW_WINDOW  "window-new"
-#define STOCK_NEW_TAB     "tab-new"
-
-#define ENCODING_DATA_KEY "encoding"
+#define MIN_WIDTH_CHARS 4
+#define MIN_HEIGHT_CHARS 1
 
 #if 1
 /*
@@ -170,70 +139,15 @@ static void mdi_screen_added_cb    (TerminalMdiContainer *container,
 static void mdi_screen_removed_cb  (TerminalMdiContainer *container,
                                     TerminalScreen *screen,
                                     TerminalWindow *window);
+static void mdi_screens_reordered_cb (TerminalMdiContainer *container,
+                                      TerminalWindow  *window);
 static void screen_close_request_cb (TerminalMdiContainer *container,
                                      TerminalScreen *screen,
                                      TerminalWindow *window);
 
 /* Menu action callbacks */
-static void file_new_terminal_callback        (GtkAction *action,
-                                               TerminalWindow *window);
-static void file_new_profile_callback         (GtkAction *action,
-                                               TerminalWindow *window);
-static void file_close_window_callback        (GtkAction *action,
-                                               TerminalWindow *window);
-static void file_save_contents_callback       (GtkAction *action,
-                                               TerminalWindow *window);
-static void file_close_tab_callback           (GtkAction *action,
-                                               TerminalWindow *window);
-static void edit_copy_callback                (GtkAction *action,
-                                               TerminalWindow *window);
-static void edit_copy_html_callback           (GtkAction *action,
-                                               TerminalWindow *window);
-static void edit_paste_callback               (GtkAction *action,
-                                               TerminalWindow *window);
-static void edit_select_all_callback          (GtkAction *action,
-                                               TerminalWindow *window);
-static void edit_preferences_callback         (GtkAction *action,
-                                               TerminalWindow *window);
-static void edit_current_profile_callback     (GtkAction *action,
-                                               TerminalWindow *window);
-static void view_menubar_toggled_callback     (GtkToggleAction *action,
-                                               TerminalWindow *window);
-static void view_fullscreen_toggled_callback  (GtkToggleAction *action,
-                                               TerminalWindow *window);
-static void view_zoom_in_callback             (GtkAction *action,
-                                               TerminalWindow *window);
-static void view_zoom_out_callback            (GtkAction *action,
-                                               TerminalWindow *window);
-static void view_zoom_normal_callback         (GtkAction *action,
-                                               TerminalWindow *window);
-static void terminal_add_encoding_callback    (GtkAction *action,
-                                               TerminalWindow *window);
-static void terminal_reset_callback           (GtkAction *action,
-                                               TerminalWindow *window);
-static void terminal_reset_clear_callback     (GtkAction *action,
-                                               TerminalWindow *window);
-static void terminal_readonly_toggled_callback(GtkToggleAction *action,
-                                               TerminalWindow *window);
-static void tabs_next_or_previous_tab_cb      (GtkAction *action,
-                                               TerminalWindow *window);
-static void tabs_move_left_callback           (GtkAction *action,
-                                               TerminalWindow *window);
-static void tabs_move_right_callback          (GtkAction *action,
-                                               TerminalWindow *window);
-static void tabs_detach_tab_callback          (GtkAction *action,
-                                               TerminalWindow *window);
-static void help_contents_callback        (GtkAction *action,
-                                           TerminalWindow *window);
-static void help_about_callback           (GtkAction *action,
-                                           TerminalWindow *window);
-static void help_inspector_callback       (GtkAction *action,
-                                           TerminalWindow *window);
-
-static gboolean find_larger_zoom_factor  (double  current,
-                                          double *found);
-static gboolean find_smaller_zoom_factor (double  current,
-                                          double *found);
+static gboolean find_larger_zoom_factor  (double *zoom);
+static gboolean find_smaller_zoom_factor (double *zoom);
 static void terminal_window_update_zoom_sensitivity (TerminalWindow *window);
 static void terminal_window_update_search_sensitivity (TerminalScreen *screen,
                                                        TerminalWindow *window);
@@ -244,73 +158,12 @@ static gboolean confirm_close_window_or_tab (TerminalWindow *window,
                                              TerminalScreen *screen);
 
 static void
-profile_set_callback (TerminalScreen *screen,
-                      GSettings *old_profile,
-                      TerminalWindow *window);
-static void
 sync_screen_icon_title (TerminalScreen *screen,
                         GParamSpec *psepc,
                         TerminalWindow *window);
 
 G_DEFINE_TYPE (TerminalWindow, terminal_window, GTK_TYPE_APPLICATION_WINDOW)
 
-/* Clipboard helpers */
-
-typedef struct {
-  TerminalScreen *screen;
-  gboolean uris_as_paths;
-} PasteData;
-
-static void
-clipboard_uris_received_cb (GtkClipboard *clipboard,
-                            /* const */ char **uris,
-                            PasteData *data)
-{
-  gs_free char *text = NULL;
-  gsize len;
-
-  if (!uris) {
-    g_object_unref (data->screen);
-    g_slice_free (PasteData, data);
-    return;
-  }
-
-  /* This potentially modifies the strings in |uris| but that's ok */
-  if (data->uris_as_paths)
-    terminal_util_transform_uris_to_quoted_fuse_paths (uris);
-
-  text = terminal_util_concat_uris (uris, &len);
-  vte_terminal_feed_child (VTE_TERMINAL (data->screen), text, len);
-
-  g_object_unref (data->screen);
-  g_slice_free (PasteData, data);
-}
-
-static void
-clipboard_targets_received_cb (GtkClipboard *clipboard,
-                               GdkAtom *targets,
-                               int n_targets,
-                               PasteData *data)
-{
-  if (!targets) {
-    g_object_unref (data->screen);
-    g_slice_free (PasteData, data);
-    return;
-  }
-
-  if (gtk_targets_include_uri (targets, n_targets)) {
-    gtk_clipboard_request_uris (clipboard,
-                                (GtkClipboardURIReceivedFunc) clipboard_uris_received_cb,
-                                data);
-    return;
-  } else /* if (gtk_targets_include_text (targets, n_targets)) */ {
-    vte_terminal_paste_clipboard (VTE_TERMINAL (data->screen));
-  }
-
-  g_object_unref (data->screen);
-  g_slice_free (PasteData, data);
-}
-
 /* Zoom helpers */
 
 static const double zoom_factors[] = {
@@ -332,9 +185,9 @@ static const double zoom_factors[] = {
 };
 
 static gboolean
-find_larger_zoom_factor (double  current,
-                         double *found)
+find_larger_zoom_factor (double *zoom)
 {
+  double current = *zoom;
   guint i;
 
   for (i = 0; i < G_N_ELEMENTS (zoom_factors); ++i)
@@ -342,36 +195,125 @@ find_larger_zoom_factor (double  current,
       /* Find a font that's larger than this one */
       if ((zoom_factors[i] - current) > 1e-6)
         {
-          *found = zoom_factors[i];
+          *zoom = zoom_factors[i];
           return TRUE;
         }
     }
-  
+
   return FALSE;
 }
 
 static gboolean
-find_smaller_zoom_factor (double  current,
-                          double *found)
+find_smaller_zoom_factor (double *zoom)
 {
+  double current = *zoom;
   int i;
-  
+
   i = (int) G_N_ELEMENTS (zoom_factors) - 1;
   while (i >= 0)
     {
       /* Find a font that's smaller than this one */
       if ((current - zoom_factors[i]) > 1e-6)
         {
-          *found = zoom_factors[i];
+          *zoom = zoom_factors[i];
           return TRUE;
         }
-      
+
       --i;
     }
 
   return FALSE;
 }
 
+static inline GSimpleAction *
+lookup_action (TerminalWindow *window,
+               const char *name)
+{
+  GAction *action;
+
+  action = g_action_map_lookup_action (G_ACTION_MAP (window), name);
+  g_return_val_if_fail (action != NULL, NULL);
+
+  return G_SIMPLE_ACTION (action);
+}
+
+/* Context menu helpers */
+
+/* We don't want context menus to show accelerators.
+ * Setting the menu's accel group and/or accel path to NULL
+ * unfortunately doesn't hide accelerators; we need to walk
+ * the menu items and remove the accelerators on each,
+ * manually.
+ */
+static void
+popup_menu_remove_accelerators (GtkWidget *menu)
+{
+  gs_free_list GList *menu_items;
+  GList *l;
+
+  menu_items = gtk_container_get_children (GTK_CONTAINER (menu));
+  for (l = menu_items; l != NULL; l = l ->next) {
+    GtkWidget *label;
+
+    if (GTK_IS_BIN (l->data) &&
+        GTK_IS_ACCEL_LABEL ((label = gtk_bin_get_child (GTK_BIN (l->data)))))
+      gtk_accel_label_set_accel (GTK_ACCEL_LABEL (label), 0, 0);
+  }
+}
+
+/* Because we're using gtk_menu_attach_to_widget(), the attach
+ * widget holds a strong reference to the menu, causing it not to
+ * be automatically destroyed once popped down. So we need to
+ * detach the menu from the attach widget manually, which will
+ * cause the menu to be destroyed. We cannot do so in the
+ * "deactivate" handler however, since that causes the menu
+ * item activation to be lost. The "selection-done" signal
+ * appears to be the right place.
+ */
+
+static void
+popup_menu_destroy_cb (GtkWidget *menu,
+                       gpointer user_data)
+{
+  /* g_printerr ("Menu %p destroyed!\n", menu); */
+}
+
+static void
+popup_menu_selection_done_cb (GtkMenu *menu,
+                              gpointer user_data)
+{
+  g_signal_handlers_disconnect_by_func
+    (menu, G_CALLBACK (popup_menu_selection_done_cb), user_data);
+
+  /* g_printerr ("selection-done %p\n", menu); */
+
+  /* This will remove the ref from the attach widget widget, and destroy the menu */
+  gtk_menu_detach (menu);
+}
+
+static GtkWidget *
+context_menu_new (GMenuModel *menu,
+                  GtkWidget *widget)
+{
+  GtkWidget *popup_menu;
+
+  popup_menu = gtk_menu_new_from_model (menu);
+  gtk_style_context_add_class (gtk_widget_get_style_context (popup_menu),
+                               GTK_STYLE_CLASS_CONTEXT_MENU);
+  gtk_menu_set_screen (GTK_MENU (popup_menu), gtk_widget_get_screen (widget));
+  gtk_menu_attach_to_widget (GTK_MENU (popup_menu), widget, NULL);
+
+  popup_menu_remove_accelerators (popup_menu);
+
+  /* Staggered destruction */
+  g_signal_connect (popup_menu, "selection-done",
+                    G_CALLBACK (popup_menu_selection_done_cb), widget);
+  g_signal_connect (popup_menu, "destroy",
+                    G_CALLBACK (popup_menu_destroy_cb), widget);
+
+  return popup_menu;
+}
+
 /* GAction callbacks */
 
 static void
@@ -385,16 +327,15 @@ action_new_terminal_cb (GSimpleAction *action,
   TerminalSettingsList *profiles_list;
   gs_unref_object GSettings *profile = NULL;
   gs_free char *new_working_directory = NULL;
-  const char *mode_str, *uuid_str;
-  TerminalNewTerminalMode mode;
-  GdkModifierType modifiers;
 
   g_assert (TERMINAL_IS_WINDOW (window));
 
   app = terminal_app_get ();
 
+  const char *mode_str, *uuid_str;
   g_variant_get (parameter, "(&s&s)", &mode_str, &uuid_str);
 
+  TerminalNewTerminalMode mode;
   if (g_str_equal (mode_str, "tab"))
     mode = TERMINAL_NEW_TERMINAL_MODE_TAB;
   else if (g_str_equal (mode_str, "window"))
@@ -402,13 +343,22 @@ action_new_terminal_cb (GSimpleAction *action,
   else {
     mode = g_settings_get_enum (terminal_app_get_global_settings (app),
                                 TERMINAL_SETTING_NEW_TERMINAL_MODE_KEY);
-    if (gtk_get_current_event_state (&modifiers) &&
-        (modifiers & gtk_accelerator_get_default_mod_mask () & GDK_CONTROL_MASK)) {
-      /* Invert */
-      if (mode == TERMINAL_NEW_TERMINAL_MODE_WINDOW)
-        mode = TERMINAL_NEW_TERMINAL_MODE_TAB;
-      else
-        mode = TERMINAL_NEW_TERMINAL_MODE_WINDOW;
+
+    GdkEvent *event = gtk_get_current_event ();
+    if (event != NULL) {
+      GdkModifierType modifiers;
+      guint button;
+
+      if ((gdk_event_get_state (event, &modifiers) &&
+           (modifiers & gtk_accelerator_get_default_mod_mask () & GDK_CONTROL_MASK)) ||
+          (gdk_event_get_button (event, &button) && (button == GDK_BUTTON_SECONDARY))) {
+        /* Invert */
+        if (mode == TERMINAL_NEW_TERMINAL_MODE_WINDOW)
+          mode = TERMINAL_NEW_TERMINAL_MODE_TAB;
+        else
+          mode = TERMINAL_NEW_TERMINAL_MODE_WINDOW;
+      }
+      gdk_event_free (event);
     }
   }
 
@@ -438,47 +388,19 @@ action_new_terminal_cb (GSimpleAction *action,
 }
 
 static void
-file_new_terminal_callback (GtkAction *action,
-                            TerminalWindow *window)
-{
-  GSettings *profile;
-  gs_free char *uuid;
-  const char *name;
-  GVariant *param;
-
-  profile = g_object_get_data (G_OBJECT (action), PROFILE_DATA_KEY);
-  if (profile)
-    uuid = terminal_settings_list_dup_uuid_from_child (terminal_app_get_profiles_list (terminal_app_get ()), 
profile);
-  else
-    uuid = g_strdup ("current");
-
-  name = gtk_action_get_name (action);
-  if (g_str_has_prefix (name, "FileNewTab"))
-    param = g_variant_new ("(ss)", "tab", uuid);
-  else if (g_str_has_prefix (name, "FileNewWindow"))
-    param = g_variant_new ("(ss)", "window", uuid);
-  else
-    param = g_variant_new ("(ss)", "default", uuid);
-
-  g_action_activate (g_action_map_lookup_action (G_ACTION_MAP (window), "new-terminal"),
-                     param);
-}
-
-static void
 action_new_profile_cb (GSimpleAction *action,
                        GVariant *parameter,
                        gpointer user_data)
 {
   TerminalWindow *window = user_data;
   TerminalWindowPrivate *priv = window->priv;
-  
+
   terminal_app_new_profile (terminal_app_get (),
-                            terminal_screen_get_profile (priv->active_screen),
-                            GTK_WINDOW (window));
+                            terminal_screen_get_profile (priv->active_screen));
 }
 
-
 #ifdef ENABLE_SAVE
+
 static void
 save_contents_dialog_on_response (GtkDialog *dialog, gint response_id, gpointer terminal)
 {
@@ -524,20 +446,18 @@ save_contents_dialog_on_response (GtkDialog *dialog, gint response_id, gpointer
                                       "%s", _("Could not save contents"));
     }
 }
-#endif /* ENABLE_SAVE */
 
 static void
 action_save_contents_cb (GSimpleAction *action,
                          GVariant *parameter,
                          gpointer user_data)
 {
-#ifdef ENABLE_SAVE
   TerminalWindow *window = user_data;
   GtkWidget *dialog = NULL;
   TerminalWindowPrivate *priv = window->priv;
   VteTerminal *terminal;
 
-  if (!priv->active_screen)
+  if (priv->active_screen == NULL)
     return;
 
   terminal = VTE_TERMINAL (priv->active_screen);
@@ -554,7 +474,7 @@ action_save_contents_cb (GSimpleAction *action,
   /* XXX where should we save to? */
   gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), g_get_user_special_dir 
(G_USER_DIRECTORY_DESKTOP));
 
-  gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW(window));
+  gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window));
   gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
   gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
 
@@ -562,18 +482,114 @@ action_save_contents_cb (GSimpleAction *action,
   g_signal_connect (dialog, "delete_event", G_CALLBACK (terminal_util_dialog_response_on_delete), NULL);
 
   gtk_window_present (GTK_WINDOW (dialog));
+}
+
 #endif /* ENABLE_SAVE */
+
+#ifdef ENABLE_PRINT
+
+static void
+print_begin_cb (GtkPrintOperation *op,
+                GtkPrintContext *context,
+                TerminalApp *app)
+{
+  GtkPrintSettings *settings;
+  GtkPageSetup *page_setup;
+
+  /* Don't save if the print dialogue was cancelled */
+  if (gtk_print_operation_get_status(op) == GTK_PRINT_STATUS_FINISHED_ABORTED)
+    return;
+
+  settings = gtk_print_operation_get_print_settings (op);
+  page_setup = gtk_print_operation_get_default_page_setup (op);
+  terminal_util_save_print_settings (settings, page_setup);
 }
 
 static void
-file_save_contents_callback (GtkAction *action,
-                             TerminalWindow *window)
+print_done_cb (GtkPrintOperation *op,
+               GtkPrintOperationResult result,
+               TerminalWindow *window)
 {
-  g_action_activate (g_action_map_lookup_action (G_ACTION_MAP (window), "save-contents"),
-                     NULL);
+  if (result != GTK_PRINT_OPERATION_RESULT_ERROR)
+    return;
+
+  /* FIXME: show error */
 }
 
 static void
+action_print_cb (GSimpleAction *action,
+                 GVariant *parameter,
+                 gpointer user_data)
+{
+  TerminalWindow *window = user_data;
+  TerminalWindowPrivate *priv = window->priv;
+  gs_unref_object GtkPrintSettings *settings = NULL;
+  gs_unref_object GtkPageSetup *page_setup = NULL;
+  gs_unref_object GtkPrintOperation *op = NULL;
+  gs_free_error GError *error = NULL;
+  GtkPrintOperationResult result;
+
+  if (priv->active_screen == NULL)
+    return;
+
+  op = vte_print_operation_new (VTE_TERMINAL (priv->active_screen),
+                                VTE_PRINT_OPERATION_DEFAULT /* flags */);
+  if (op == NULL)
+    return;
+
+  terminal_util_load_print_settings (&settings, &page_setup);
+  if (settings != NULL)
+    gtk_print_operation_set_print_settings (op, settings);
+  if (page_setup != NULL)
+    gtk_print_operation_set_default_page_setup (op, page_setup);
+
+  g_signal_connect (op, "begin-print", G_CALLBACK (print_begin_cb), window);
+  g_signal_connect (op, "done", G_CALLBACK (print_done_cb), window);
+
+  /* FIXME: show progress better */
+
+  result = gtk_print_operation_run (op,
+                                    /* this is the only supported one: */
+                                    GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
+                                    GTK_WINDOW (window),
+                                    &error);
+  /* VtePrintOperation always runs async */
+  g_assert_cmpint (result, ==, GTK_PRINT_OPERATION_RESULT_IN_PROGRESS);
+}
+
+#endif /* ENABLE_PRINT */
+
+#ifdef ENABLE_EXPORT
+
+static void
+action_export_cb (GSimpleAction *action,
+                 GVariant *parameter,
+                 gpointer user_data)
+{
+  TerminalWindow *window = user_data;
+  TerminalWindowPrivate *priv = window->priv;
+  gs_unref_object VteExportOperation *op = NULL;
+  gs_free_error GError *error = NULL;
+
+  if (priv->active_screen == NULL)
+    return;
+
+  op = vte_export_operation_new (VTE_TERMINAL (priv->active_screen),
+                                 TRUE /* interactive */,
+                                 VTE_EXPORT_FORMAT_ASK /* allow user to choose export format */,
+                                 NULL, NULL /* GSettings & key to load/store default directory from, FIXME 
*/,
+                                 NULL, NULL /* progress callback & user data, FIXME */);
+  if (op == NULL)
+    return;
+
+  /* FIXME: show progress better */
+
+  vte_export_operation_run_async (op, GTK_WINDOW (window), NULL /* cancellable */);
+}
+
+#endif /* ENABLE_EXPORT */
+
+static void
 action_close_cb (GSimpleAction *action,
                  GVariant *parameter,
                  gpointer user_data)
@@ -583,7 +599,7 @@ action_close_cb (GSimpleAction *action,
   TerminalScreen *screen;
   const char *mode_str;
 
-  g_assert (parameter != NULL);
+  g_assert_nonnull (parameter);
   g_variant_get (parameter, "&s", &mode_str);
 
   if (g_str_equal (mode_str, "tab"))
@@ -591,7 +607,7 @@ action_close_cb (GSimpleAction *action,
   else if (g_str_equal (mode_str, "window"))
     screen = NULL;
   else
-    g_assert_not_reached ();
+    return;
 
   if (confirm_close_window_or_tab (window, screen))
     return;
@@ -612,10 +628,10 @@ action_copy_cb (GSimpleAction *action,
   const char *format_str;
   VteFormat format;
 
-  if (!priv->active_screen)
+  if (priv->active_screen == NULL)
     return;
 
-  g_assert (parameter != NULL);
+  g_assert_nonnull (parameter);
   g_variant_get (parameter, "&s", &format_str);
 
   if (g_str_equal (format_str, "text"))
@@ -628,64 +644,83 @@ action_copy_cb (GSimpleAction *action,
   vte_terminal_copy_clipboard_format (VTE_TERMINAL (priv->active_screen), format);
 }
 
+/* Clipboard helpers */
+
+typedef struct {
+  GWeakRef screen_weak_ref;
+} PasteData;
+
 static void
-edit_copy_callback (GtkAction *action,
-                    TerminalWindow *window)
+clipboard_uris_received_cb (GtkClipboard *clipboard,
+                            /* const */ char **uris,
+                            PasteData *data)
 {
-  g_action_activate (g_action_map_lookup_action (G_ACTION_MAP (window), "copy"),
-                     g_variant_new_string ("text"));
-}
+  gs_unref_object TerminalScreen *screen = NULL;
 
-static void edit_copy_html_callback (GtkAction *action,
-                                     TerminalWindow *window)
-{
-  g_action_activate (g_action_map_lookup_action (G_ACTION_MAP (window), "copy"),
-                     g_variant_new_string ("html"));
+  if (uris != NULL && uris[0] != NULL &&
+      (screen = g_weak_ref_get (&data->screen_weak_ref))) {
+    gs_free char *text;
+    gsize len;
+
+    /* This potentially modifies the strings in |uris| but that's ok */
+    terminal_util_transform_uris_to_quoted_fuse_paths (uris);
+    text = terminal_util_concat_uris (uris, &len);
+
+    vte_terminal_feed_child (VTE_TERMINAL (screen), text, len);
+  }
+
+  g_weak_ref_clear (&data->screen_weak_ref);
+  g_slice_free (PasteData, data);
 }
 
 static void
-action_paste_cb (GSimpleAction *action,
-                 GVariant *parameter,
-                 gpointer user_data)
+request_clipboard_contents_for_paste (TerminalWindow *window,
+                                      gboolean paste_as_uris)
 {
-  TerminalWindow *window = user_data;
   TerminalWindowPrivate *priv = window->priv;
-  GtkClipboard *clipboard;
-  PasteData *data;
-  const char *mode;
-
-  g_assert (parameter != NULL);
+  GdkAtom *targets;
+  int n_targets;
 
-  if (!priv->active_screen)
+  if (priv->active_screen == NULL)
     return;
 
-  g_variant_get (parameter, "&s", &mode);
+  targets = terminal_app_get_clipboard_targets (terminal_app_get (),
+                                                priv->clipboard,
+                                                &n_targets);
+  if (targets == NULL)
+    return;
 
-  data = g_slice_new (PasteData);
-  data->screen = g_object_ref (priv->active_screen);
-  data->uris_as_paths = g_str_equal (mode, "uri");
+  if (paste_as_uris && gtk_targets_include_uri (targets, n_targets)) {
+    PasteData *data = g_slice_new (PasteData);
+    g_weak_ref_init (&data->screen_weak_ref, priv->active_screen);
 
-  clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_CLIPBOARD);
-  gtk_clipboard_request_targets (clipboard,
-                                 (GtkClipboardTargetsReceivedFunc) clipboard_targets_received_cb,
-                                 data);
+    gtk_clipboard_request_uris (priv->clipboard,
+                                (GtkClipboardURIReceivedFunc) clipboard_uris_received_cb,
+                                data);
+    return;
+  } else if (gtk_targets_include_text (targets, n_targets)) {
+    vte_terminal_paste_clipboard (VTE_TERMINAL (priv->active_screen));
+  }
 }
 
 static void
-edit_paste_callback (GtkAction *action,
-                     TerminalWindow *window)
+action_paste_text_cb (GSimpleAction *action,
+                      GVariant *parameter,
+                      gpointer user_data)
 {
-  const char *name;
-  GVariant *parameter;
+  TerminalWindow *window = user_data;
 
-  name = gtk_action_get_name (action);
-  if ((name == I_("EditPasteURIPaths") || name == I_("PopupPasteURIPaths")))
-    parameter = g_variant_new_string ("uri");
-  else
-    parameter = g_variant_new_string ("normal");
+  request_clipboard_contents_for_paste (window, FALSE);
+}
 
-  g_action_activate (g_action_map_lookup_action (G_ACTION_MAP (window), "paste"),
-                     parameter);
+static void
+action_paste_uris_cb (GSimpleAction *action,
+                      GVariant *parameter,
+                      gpointer user_data)
+{
+  TerminalWindow *window = user_data;
+
+  request_clipboard_contents_for_paste (window, TRUE);
 }
 
 static void
@@ -696,21 +731,13 @@ action_select_all_cb (GSimpleAction *action,
   TerminalWindow *window = user_data;
   TerminalWindowPrivate *priv = window->priv;
 
-  if (!priv->active_screen)
+  if (priv->active_screen == NULL)
     return;
 
   vte_terminal_select_all (VTE_TERMINAL (priv->active_screen));
 }
 
 static void
-edit_select_all_callback (GtkAction *action,
-                          TerminalWindow *window)
-{
-  g_action_activate (g_action_map_lookup_action (G_ACTION_MAP (window), "select-all"),
-                     NULL);
-}
-
-static void
 action_reset_cb (GSimpleAction *action,
                  GVariant *parameter,
                  gpointer user_data)
@@ -718,7 +745,7 @@ action_reset_cb (GSimpleAction *action,
   TerminalWindow *window = user_data;
   TerminalWindowPrivate *priv = window->priv;
 
-  g_assert (parameter != NULL);
+  g_assert_nonnull (parameter);
 
   if (priv->active_screen == NULL)
     return;
@@ -729,101 +756,146 @@ action_reset_cb (GSimpleAction *action,
 }
 
 static void
-action_switch_tab_cb (GSimpleAction *action,
-                      GVariant *parameter,
-                      gpointer user_data)
+tab_switch_relative (TerminalWindow *window,
+                     int change)
 {
-  TerminalWindow *window = user_data;
   TerminalWindowPrivate *priv = window->priv;
-  int value;
+  int n_screens, value;
 
-  g_assert (parameter != NULL);
+  n_screens = terminal_mdi_container_get_n_screens (priv->mdi_container);
+  value = terminal_mdi_container_get_active_screen_num (priv->mdi_container) + change;
 
-  value = g_variant_get_int32 (parameter);
+  gboolean keynav_wrap_around;
+  g_object_get (gtk_widget_get_settings (GTK_WIDGET (window)),
+                "gtk-keynav-wrap-around", &keynav_wrap_around,
+                NULL);
+  if (keynav_wrap_around) {
+    if (value < 0)
+      value += n_screens;
+    else if (value >= n_screens)
+      value -= n_screens;
+  }
 
-  if (value > 0)
-    terminal_mdi_container_set_active_screen_num (priv->mdi_container, value - 1);
-  else
-    terminal_mdi_container_change_screen (priv->mdi_container, value == -2 ? -1 : 1);
+  if (value < 0 || value >= n_screens)
+    return;
+
+  g_action_change_state (G_ACTION (lookup_action (window, "active-tab")),
+                         g_variant_new_int32 (value));
 }
 
 static void
-action_move_tab_cb (GSimpleAction *action,
-                    GVariant *parameter,
-                    gpointer user_data)
+action_tab_switch_left_cb (GSimpleAction *action,
+                           GVariant *parameter,
+                           gpointer user_data)
+{
+  TerminalWindow *window = user_data;
+
+  tab_switch_relative (window, -1);
+}
+
+static void
+action_tab_switch_right_cb (GSimpleAction *action,
+                            GVariant *parameter,
+                            gpointer user_data)
+{
+  TerminalWindow *window = user_data;
+
+  tab_switch_relative (window, 1);
+}
+
+static void
+action_tab_move_left_cb (GSimpleAction *action,
+                         GVariant *parameter,
+                         gpointer user_data)
 {
   TerminalWindow *window = user_data;
   TerminalWindowPrivate *priv = window->priv;
-  int value;
-  
-  g_assert (parameter != NULL);
+  int change;
 
-  value = g_variant_get_int32 (parameter);
+  if (priv->active_screen == NULL)
+    return;
+
+  change = gtk_widget_get_direction (GTK_WIDGET (window)) == GTK_TEXT_DIR_RTL ? 1 : -1;
   terminal_mdi_container_reorder_screen (priv->mdi_container,
                                          terminal_mdi_container_get_active_screen (priv->mdi_container),
-                                         value);
+                                         change);
 }
 
 static void
-action_zoom_cb (GSimpleAction *action,
-                GVariant *parameter,
-                gpointer user_data)
+action_tab_move_right_cb (GSimpleAction *action,
+                          GVariant *parameter,
+                          gpointer user_data)
 {
   TerminalWindow *window = user_data;
   TerminalWindowPrivate *priv = window->priv;
-  int value;
-  double zoom;
-  
+  int change;
+
   if (priv->active_screen == NULL)
     return;
 
-  g_assert (parameter != NULL);
+  change = gtk_widget_get_direction (GTK_WIDGET (window)) == GTK_TEXT_DIR_RTL ? -1 : 1;
+  terminal_mdi_container_reorder_screen (priv->mdi_container,
+                                         terminal_mdi_container_get_active_screen (priv->mdi_container),
+                                         change);
+}
 
-  value = g_variant_get_int32 (parameter);
+static void
+action_zoom_in_cb (GSimpleAction *action,
+                   GVariant *parameter,
+                   gpointer user_data)
+{
+  TerminalWindow *window = user_data;
+  TerminalWindowPrivate *priv = window->priv;
+  double zoom;
 
-  if (value == 0) {
-    zoom = PANGO_SCALE_MEDIUM;
-  } else if (value == 1) {
-    zoom = vte_terminal_get_font_scale (VTE_TERMINAL (priv->active_screen));
-    if (!find_larger_zoom_factor (zoom, &zoom))
-      return;
-  } else if (value == -1) {
-    zoom = vte_terminal_get_font_scale (VTE_TERMINAL (priv->active_screen));
-    if (!find_smaller_zoom_factor (zoom, &zoom))
-      return;
-  } else
-    g_assert_not_reached ();
+  if (priv->active_screen == NULL)
+    return;
+
+  zoom = vte_terminal_get_font_scale (VTE_TERMINAL (priv->active_screen));
+  if (!find_larger_zoom_factor (&zoom))
+    return;
 
   vte_terminal_set_font_scale (VTE_TERMINAL (priv->active_screen), zoom);
   terminal_window_update_zoom_sensitivity (window);
 }
 
 static void
-view_zoom_in_callback (GtkAction *action,
-                       TerminalWindow *window)
+action_zoom_out_cb (GSimpleAction *action,
+                    GVariant *parameter,
+                    gpointer user_data)
 {
-  g_action_activate (g_action_map_lookup_action (G_ACTION_MAP (window), "zoom"),
-                     g_variant_new_int32 (1));
-}
+  TerminalWindow *window = user_data;
+  TerminalWindowPrivate *priv = window->priv;
+  double zoom;
 
-static void
-view_zoom_out_callback (GtkAction *action,
-                        TerminalWindow *window)
-{
-  g_action_activate (g_action_map_lookup_action (G_ACTION_MAP (window), "zoom"),
-                     g_variant_new_int32 (-1));
+  if (priv->active_screen == NULL)
+    return;
+
+  zoom = vte_terminal_get_font_scale (VTE_TERMINAL (priv->active_screen));
+  if (!find_smaller_zoom_factor (&zoom))
+    return;
+
+  vte_terminal_set_font_scale (VTE_TERMINAL (priv->active_screen), zoom);
+  terminal_window_update_zoom_sensitivity (window);
 }
 
 static void
-view_zoom_normal_callback (GtkAction *action,
-                           TerminalWindow *window)
+action_zoom_normal_cb (GSimpleAction *action,
+                       GVariant *parameter,
+                       gpointer user_data)
 {
-  g_action_activate (g_action_map_lookup_action (G_ACTION_MAP (window), "zoom"),
-                     g_variant_new_int32 (0));
+  TerminalWindow *window = user_data;
+  TerminalWindowPrivate *priv = window->priv;
+
+  if (priv->active_screen == NULL)
+    return;
+
+  vte_terminal_set_font_scale (VTE_TERMINAL (priv->active_screen), PANGO_SCALE_MEDIUM);
+  terminal_window_update_zoom_sensitivity (window);
 }
 
 static void
-action_detach_tab_cb (GSimpleAction *action,
+action_tab_detach_cb (GSimpleAction *action,
                       GVariant *parameter,
                       gpointer user_data)
 {
@@ -839,7 +911,6 @@ action_detach_tab_cb (GSimpleAction *action,
 
   screen = priv->active_screen;
 
-  /* FIXME: this seems wrong if tabs are shown in the window */
   terminal_screen_get_size (screen, &width, &height);
   g_snprintf (geometry, sizeof (geometry), "%dx%d", width, height);
 
@@ -853,21 +924,11 @@ action_detach_tab_cb (GSimpleAction *action,
 }
 
 static void
-tabs_detach_tab_callback (GtkAction *action,
-                          TerminalWindow *window)
-{
-  g_action_activate (g_action_map_lookup_action (G_ACTION_MAP (window), "detach-tab"),
-                     NULL);
-}
-
-static void
 action_help_cb (GSimpleAction *action,
                 GVariant *parameter,
                 gpointer user_data)
 {
-  TerminalWindow *window = user_data;
-
-  terminal_util_show_help (NULL, GTK_WINDOW (window));
+  terminal_util_show_help (NULL);
 }
 
 static void
@@ -875,19 +936,15 @@ action_about_cb (GSimpleAction *action,
                  GVariant *parameter,
                  gpointer user_data)
 {
-  TerminalWindow *window = user_data;
-
-  terminal_util_show_about (GTK_WINDOW (window));
+  terminal_util_show_about ();
 }
 
 static void
-action_preferences_cb (GSimpleAction *action,
-                       GVariant *parameter,
-                       gpointer user_data)
+action_edit_preferences_cb (GSimpleAction *action,
+                            GVariant *parameter,
+                            gpointer user_data)
 {
-  TerminalWindow *window = user_data;
-
-  terminal_app_edit_preferences (terminal_app_get (), GTK_WINDOW (window));
+  terminal_app_edit_preferences (terminal_app_get ());
 }
 
 static void
@@ -900,11 +957,122 @@ action_edit_profile_cb (GSimpleAction *action,
 
   terminal_app_edit_profile (terminal_app_get (),
                              terminal_screen_get_profile (priv->active_screen),
-                             GTK_WINDOW (window),
                              NULL);
 }
 
 static void
+action_size_to_cb (GSimpleAction *action,
+                   GVariant      *parameter,
+                   gpointer       user_data)
+{
+  TerminalWindow *window = user_data;
+  TerminalWindowPrivate *priv = window->priv;
+  guint width, height;
+
+  g_assert_nonnull (parameter);
+
+  if (priv->active_screen == NULL)
+    return;
+
+  g_variant_get (parameter, "(uu)", &width, &height);
+  if (width < MIN_WIDTH_CHARS || height < MIN_HEIGHT_CHARS ||
+      width > 256 || height > 256)
+    return;
+
+  vte_terminal_set_size (VTE_TERMINAL (priv->active_screen), width, height);
+  terminal_window_update_size (window);
+}
+
+static void
+action_open_match_cb (GSimpleAction *action,
+                      GVariant      *parameter,
+                      gpointer       user_data)
+{
+  TerminalWindow *window = user_data;
+  TerminalWindowPrivate *priv = window->priv;
+  TerminalScreenPopupInfo *info = priv->popup_info;
+
+  if (info == NULL)
+    return;
+  if (info->url == NULL)
+    return;
+
+  terminal_util_open_url (GTK_WIDGET (window), info->url, info->url_flavor,
+                          gtk_get_current_event_time ());
+}
+
+static void
+action_copy_match_cb (GSimpleAction *action,
+                      GVariant      *parameter,
+                      gpointer       user_data)
+{
+  TerminalWindow *window = user_data;
+  TerminalWindowPrivate *priv = window->priv;
+  TerminalScreenPopupInfo *info = priv->popup_info;
+
+  if (info == NULL)
+    return;
+  if (info->url == NULL)
+    return;
+
+  gtk_clipboard_set_text (priv->clipboard, info->url, -1);
+}
+
+static void
+action_open_hyperlink_cb (GSimpleAction *action,
+                          GVariant      *parameter,
+                          gpointer       user_data)
+{
+  TerminalWindow *window = user_data;
+  TerminalWindowPrivate *priv = window->priv;
+  TerminalScreenPopupInfo *info = priv->popup_info;
+
+  if (info == NULL)
+    return;
+  if (info->hyperlink == NULL)
+    return;
+
+  terminal_util_open_url (GTK_WIDGET (window), info->hyperlink, FLAVOR_AS_IS,
+                          gtk_get_current_event_time ());
+}
+
+static void
+action_copy_hyperlink_cb (GSimpleAction *action,
+                          GVariant      *parameter,
+                          gpointer       user_data)
+{
+  TerminalWindow *window = user_data;
+  TerminalWindowPrivate *priv = window->priv;
+  TerminalScreenPopupInfo *info = priv->popup_info;
+
+  if (info == NULL)
+    return;
+  if (info->hyperlink == NULL)
+    return;
+
+  gtk_clipboard_set_text (priv->clipboard, info->hyperlink, -1);
+}
+
+static void
+action_leave_fullscreen_cb (GSimpleAction *action,
+                            GVariant      *parameter,
+                            gpointer       user_data)
+{
+  TerminalWindow *window = user_data;
+
+  g_action_group_change_action_state (G_ACTION_GROUP (window), "fullscreen",
+                                      g_variant_new_boolean (FALSE));
+}
+
+static void
+action_inspector_cb (GSimpleAction *action,
+                     GVariant      *parameter,
+                     gpointer       user_data)
+{
+  gtk_window_set_interactive_debugging (TRUE);
+}
+
+static void
 search_popover_search_cb (TerminalSearchPopover *popover,
                           gboolean backward,
                           TerminalWindow *window)
@@ -953,8 +1121,11 @@ search_popover_notify_wrap_around_cb (TerminalSearchPopover *popover,
 }
 
 static void
-terminal_window_ensure_search_popover (TerminalWindow *window)
+action_find_cb (GSimpleAction *action,
+                GVariant *parameter,
+                gpointer user_data)
 {
+  TerminalWindow *window = user_data;
   TerminalWindowPrivate *priv = window->priv;
 
   if (G_UNLIKELY(priv->active_screen == NULL))
@@ -971,7 +1142,7 @@ terminal_window_ensure_search_popover (TerminalWindow *window)
   if (priv->active_screen == NULL)
     return;
 
-  priv->search_popover = terminal_search_popover_new (GTK_WIDGET (priv->menubar));
+  priv->search_popover = terminal_search_popover_new (GTK_WIDGET (window));
 
   g_signal_connect (priv->search_popover, "search", G_CALLBACK (search_popover_search_cb), window);
 
@@ -987,103 +1158,196 @@ terminal_window_ensure_search_popover (TerminalWindow *window)
 }
 
 static void
-action_find_cb (GSimpleAction *action,
-                GVariant *parameter,
-                gpointer user_data)
+action_find_forward_cb (GSimpleAction *action,
+                        GVariant *parameter,
+                        gpointer user_data)
 {
   TerminalWindow *window = user_data;
   TerminalWindowPrivate *priv = window->priv;
-  const char *mode;
 
-  if (G_UNLIKELY (!priv->active_screen))
+  if (priv->active_screen == NULL)
     return;
 
-  g_variant_get (parameter, "&s", &mode);
+  vte_terminal_search_find_next (VTE_TERMINAL (priv->active_screen));
+}
 
-  if (g_str_equal (mode, "find")) {
-    terminal_window_ensure_search_popover (window);
-  } else if (g_str_equal (mode, "next")) {
-    vte_terminal_search_find_next (VTE_TERMINAL (priv->active_screen));
-  } else if (g_str_equal (mode, "previous")) {
-    vte_terminal_search_find_previous (VTE_TERMINAL (priv->active_screen));
-  } else if (g_str_equal (mode, "clear")) {
-    vte_terminal_search_set_regex (VTE_TERMINAL (priv->active_screen), NULL, 0);
-  } else
+static void
+action_find_backward_cb (GSimpleAction *action,
+                         GVariant *parameter,
+                         gpointer user_data)
+{
+  TerminalWindow *window = user_data;
+  TerminalWindowPrivate *priv = window->priv;
+
+  if (priv->active_screen == NULL)
     return;
+
+  vte_terminal_search_find_previous (VTE_TERMINAL (priv->active_screen));
 }
 
 static void
-search_find_callback (GtkAction *action,
-                     TerminalWindow *window)
+action_find_clear_cb (GSimpleAction *action,
+                      GVariant *parameter,
+                      gpointer user_data)
 {
-  g_action_activate (g_action_map_lookup_action (G_ACTION_MAP (window), "find"),
-                     g_variant_new ("s", "find"));
+  TerminalWindow *window = user_data;
+  TerminalWindowPrivate *priv = window->priv;
+
+  if (priv->active_screen == NULL)
+    return;
+
+  vte_terminal_search_set_regex (VTE_TERMINAL (priv->active_screen), NULL, 0);
 }
 
 static void
-search_find_next_callback (GtkAction *action,
-                          TerminalWindow *window)
+action_shadow_activate_cb (GSimpleAction *action,
+                           GVariant *parameter,
+                           gpointer user_data)
 {
-  g_action_activate (g_action_map_lookup_action (G_ACTION_MAP (window), "find"),
-                     g_variant_new ("s", "next"));
+  TerminalWindow *window = user_data;
+  gs_free char *param = g_variant_print(parameter, TRUE);
+
+  _terminal_debug_print (TERMINAL_DEBUG_ACCELS,
+                         "Window %p shadow action activated for %s\n",
+                         window, param);
+
+  /* We make sure in terminal-accels to always install the keybinding
+   * for the real action first, so that it's first in line for activation.
+   * That means we can make this here a NOP, instead of forwarding the
+   * activation to the shadowed action.
+   */
 }
 
 static void
-search_find_prev_callback (GtkAction *action,
-                          TerminalWindow *window)
+action_menubar_visible_state_cb (GSimpleAction *action,
+                                 GVariant *state,
+                                 gpointer user_data)
 {
-  g_action_activate (g_action_map_lookup_action (G_ACTION_MAP (window), "find"),
-                     g_variant_new ("s", "previous"));
+  TerminalWindow *window = user_data;
+  gboolean active;
+
+  active = g_variant_get_boolean (state);
+  terminal_window_set_menubar_visible (window, active); /* this also sets the action state */
 }
 
 static void
-search_clear_highlight_callback (GtkAction *action,
-                                TerminalWindow *window)
+action_fullscreen_state_cb (GSimpleAction *action,
+                            GVariant *state,
+                            gpointer user_data)
 {
-  g_action_activate (g_action_map_lookup_action (G_ACTION_MAP (window), "find"),
-                     g_variant_new ("s", "clear"));
+  TerminalWindow *window = user_data;
+
+  if (!gtk_widget_get_realized (GTK_WIDGET (window)))
+    return;
+
+  if (g_variant_get_boolean (state))
+    gtk_window_fullscreen (GTK_WINDOW (window));
+  else
+    gtk_window_unfullscreen (GTK_WINDOW (window));
+
+  /* The window-state-changed callback will update the action's actual state */
 }
 
 static void
-action_toggle_state_cb (GSimpleAction *saction,
-                        GVariant *parameter,
-                        gpointer user_data)
+action_read_only_state_cb (GSimpleAction *action,
+                           GVariant *state,
+                           gpointer user_data)
 {
-  GAction *action = G_ACTION (saction);
-  gs_unref_variant GVariant *state;
+  TerminalWindow *window = user_data;
+  TerminalWindowPrivate *priv = window->priv;
 
-  state = g_action_get_state (action);
-  g_action_change_state (action, g_variant_new_boolean (!g_variant_get_boolean (state)));
+  g_assert_nonnull (state);
+
+  g_simple_action_set_state (action, state);
+
+  if (priv->active_screen == NULL)
+    return;
+
+  vte_terminal_set_input_enabled (VTE_TERMINAL (priv->active_screen),
+                                  !g_variant_get_boolean (state));
 }
 
 static void
-action_show_menubar_state_cb (GSimpleAction *action,
-                              GVariant *state,
-                              gpointer user_data)
+action_profile_state_cb (GSimpleAction *action,
+                         GVariant *state,
+                         gpointer user_data)
 {
   TerminalWindow *window = user_data;
+  TerminalWindowPrivate *priv = window->priv;
+  TerminalSettingsList *profiles_list;
+  const gchar *uuid;
+  gs_unref_object GSettings *profile;
+
+  g_assert_nonnull (state);
+
+  uuid = g_variant_get_string (state, NULL);
+  profiles_list = terminal_app_get_profiles_list (terminal_app_get ());
+  profile = terminal_settings_list_ref_child (profiles_list, uuid);
+  if (profile == NULL)
+    return;
 
   g_simple_action_set_state (action, state);
 
-  terminal_window_set_menubar_visible (window, g_variant_get_boolean (state));
+  terminal_screen_set_profile (priv->active_screen, profile);
 }
 
 static void
-action_fullscreen_state_cb (GSimpleAction *action,
+action_encoding_state_cb (GSimpleAction *action,
+                          GVariant *state,
+                          gpointer user_data)
+{
+  TerminalWindow *window = user_data;
+  TerminalWindowPrivate *priv = window->priv;
+
+  g_assert_nonnull (state);
+
+  if (priv->active_screen == NULL)
+    return;
+
+  const char *charset = g_variant_get_string (state, NULL);
+  g_warn_if_fail (terminal_encodings_is_known_charset (charset));
+
+  /* Only change the state if changing encoding worked */
+  if (vte_terminal_set_encoding (VTE_TERMINAL (priv->active_screen), charset, NULL)) {
+    g_simple_action_set_state (action, state);
+  }
+}
+
+static void
+action_active_tab_set_cb (GSimpleAction *action,
+                          GVariant *parameter,
+                          gpointer user_data)
+{
+  TerminalWindow *window = user_data;
+  TerminalWindowPrivate *priv = window->priv;
+  int value, n_screens;
+
+  g_assert_nonnull (parameter);
+
+  n_screens = terminal_mdi_container_get_n_screens (priv->mdi_container);
+
+  value = g_variant_get_int32 (parameter);
+  if (value < 0)
+    value += n_screens;
+  if (value < 0 || value >= n_screens)
+    return;
+
+  g_action_change_state (G_ACTION (action), g_variant_new_int32 (value));
+}
+
+static void
+action_active_tab_state_cb (GSimpleAction *action,
                             GVariant *state,
                             gpointer user_data)
 {
   TerminalWindow *window = user_data;
+  TerminalWindowPrivate *priv = window->priv;
 
-  g_simple_action_set_state (action, state);
+  g_assert_nonnull (state);
 
-  if (!gtk_widget_get_realized (GTK_WIDGET (window)))
-    return;
+  g_simple_action_set_state (action, state);
 
-  if (g_variant_get_boolean (state))
-    gtk_window_fullscreen (GTK_WINDOW (window));
-  else
-    gtk_window_unfullscreen (GTK_WINDOW (window));
+  terminal_mdi_container_set_active_screen_num (priv->mdi_container, g_variant_get_int32 (state));
 }
 
 /* Menubar mnemonics & accel settings handling */
@@ -1093,9 +1357,14 @@ enable_menubar_accel_changed_cb (GSettings *settings,
                                  const char *key,
                                  GtkSettings *gtk_settings)
 {
-  /* const */ char *saved_menubar_accel;
+#if GTK_CHECK_VERSION (3, 20, 0)
+  if (g_settings_get_boolean (settings, key))
+    gtk_settings_reset_property (gtk_settings, "gtk-menu-bar-accel");
+  else
+    g_object_set (gtk_settings, "gtk-menu-bar-accel", NULL, NULL);
+#else
+  const char *saved_menubar_accel;
 
-  /* FIXME: Once gtk+ bug 507398 is fixed, use that to reset the property instead */
   /* Now this is a bad hack on so many levels. */
   saved_menubar_accel = g_object_get_data (G_OBJECT (gtk_settings), "GT::gtk-menu-bar-accel");
 
@@ -1103,6 +1372,7 @@ enable_menubar_accel_changed_cb (GSettings *settings,
     g_object_set (gtk_settings, "gtk-menu-bar-accel", saved_menubar_accel, NULL);
   else
     g_object_set (gtk_settings, "gtk-menu-bar-accel", NULL, NULL);
+#endif
 }
 
 static void
@@ -1115,28 +1385,6 @@ app_setting_notify_destroy_cb (GtkSettings *gtk_settings)
 
 /* utility functions */
 
-static char *
-escape_underscores (const char *name)
-{
-  GString *escaped_name;
-
-  g_assert (name != NULL);
-
-  /* Who'd use more that 4 underscores in a profile name... */
-  escaped_name = g_string_sized_new (strlen (name) + 4 + 1);
-
-  while (*name)
-    {
-      if (*name == '_')
-        g_string_append (escaped_name, "__");
-      else
-        g_string_append_c (escaped_name, *name);
-      name++;
-    }
-
-  return g_string_free (escaped_name, FALSE);
-}
-
 static int
 find_tab_num_at_pos (GtkNotebook *notebook,
                      int screen_x, 
@@ -1210,7 +1458,7 @@ position_menu_under_widget (GtkMenu *menu,
   screen = gtk_widget_get_screen (GTK_WIDGET (menu));
   monitor_num = gdk_screen_get_monitor_at_window (screen, widget_window);
   if (monitor_num < 0)
-          monitor_num = 0;
+    monitor_num = 0;
   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
 
   gdk_window_get_origin (widget_window, x, y);
@@ -1219,9 +1467,9 @@ position_menu_under_widget (GtkMenu *menu,
       *x += widget_allocation.x;
       *y += widget_allocation.y;
     }
-  if (gtk_widget_get_direction (container) == GTK_TEXT_DIR_LTR) 
+  if (gtk_widget_get_direction (container) == GTK_TEXT_DIR_LTR)
     *x += widget_allocation.width - req.width;
-  else 
+  else
     *x += req.width - menu_req.width;
 
   if ((*y + widget_allocation.height + menu_req.height) <= monitor.y + monitor.height)
@@ -1237,533 +1485,49 @@ position_menu_under_widget (GtkMenu *menu,
 }
 
 static void
-terminal_set_profile_toggled_callback (GtkToggleAction *action,
-                                       TerminalWindow *window)
-{
-  TerminalWindowPrivate *priv = window->priv;
-  GSettings *profile;
-
-  if (!gtk_toggle_action_get_active (action))
-    return;
-
-  if (priv->active_screen == NULL)
-    return;
-
-  profile = g_object_get_data (G_OBJECT (action), PROFILE_DATA_KEY);
-  g_assert (profile);
-
-  g_signal_handlers_block_by_func (priv->active_screen, G_CALLBACK (profile_set_callback), window);
-  terminal_screen_set_profile (priv->active_screen, profile);
-  g_signal_handlers_unblock_by_func (priv->active_screen, G_CALLBACK (profile_set_callback), window);
-}
-
-static void
-profile_visible_name_notify_cb (GSettings  *profile,
-                                const char *key,
-                                GtkAction  *action)
-{
-  gs_free char *visible_name;
-  char *dot;
-  gs_free char *display_name;
-  guint num;
-
-  visible_name = g_settings_get_string (profile, TERMINAL_PROFILE_VISIBLE_NAME_KEY);
-  display_name = escape_underscores (visible_name);
-
-  dot = strchr (gtk_action_get_name (action), '.');
-  if (dot != NULL)
-    {
-      gs_free char *free_me;
-
-      num = g_ascii_strtoll (dot + 1, NULL, 10);
-
-      free_me = display_name;
-      if (num < 10)
-        /* Translators: This is the label of a menu item to choose a profile.
-         * _%u is used as the accelerator (with u between 1 and 9), and
-         * the %s is the name of the terminal profile.
-         */
-        display_name = g_strdup_printf (_("_%u. %s"), num, display_name);
-      else if (num < 36)
-        /* Translators: This is the label of a menu item to choose a profile.
-         * _%c is used as the accelerator (it will be a character between A and Z),
-         * and the %s is the name of the terminal profile.
-         */
-        display_name = g_strdup_printf (_("_%c. %s"), (guchar)('A' + num - 10), display_name);
-      else
-        free_me = NULL;
-    }
-
-  g_object_set (action, "label", display_name, NULL);
-}
-
-static void
-disconnect_profiles_from_actions_in_group (GtkActionGroup *action_group)
-{
-  GList *actions, *l;
-
-  actions = gtk_action_group_list_actions (action_group);
-  for (l = actions; l != NULL; l = l->next)
-    {
-      GObject *action = G_OBJECT (l->data);
-      GSettings *profile;
-
-      profile = g_object_get_data (action, PROFILE_DATA_KEY);
-      if (!profile)
-        continue;
-
-      g_signal_handlers_disconnect_by_func (profile, G_CALLBACK (profile_visible_name_notify_cb), action);
-    }
-  g_list_free (actions);
-}
-
-static void
 terminal_window_update_set_profile_menu_active_profile (TerminalWindow *window)
 {
   TerminalWindowPrivate *priv = window->priv;
   GSettings *new_active_profile;
-  GList *actions, *l;
-
-  if (!priv->profiles_action_group)
-    return;
-
-  if (!priv->active_screen)
-    return;
-
-  new_active_profile = terminal_screen_get_profile (priv->active_screen);
-
-  actions = gtk_action_group_list_actions (priv->profiles_action_group);
-  for (l = actions; l != NULL; l = l->next)
-    {
-      GObject *action = G_OBJECT (l->data);
-      GSettings *profile;
-
-      profile = g_object_get_data (action, PROFILE_DATA_KEY);
-      if (profile != new_active_profile)
-        continue;
-
-      g_signal_handlers_block_by_func (action, G_CALLBACK (terminal_set_profile_toggled_callback), window);
-      gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
-      g_signal_handlers_unblock_by_func (action, G_CALLBACK (terminal_set_profile_toggled_callback), window);
-
-      break;
-    }
-  g_list_free (actions);
-}
-
-static void
-terminal_window_update_set_profile_menu (TerminalWindow *window)
-{
-  TerminalWindowPrivate *priv = window->priv;
-  GSettings *active_profile;
-  GtkActionGroup *action_group;
-  GtkAction *action;
-  TerminalSettingsList *profiles_list;
-  GList *profiles, *p;
-  GSList *group;
-  guint n;
-  gboolean single_profile;
-
-  /* Remove the old UI */
-  if (priv->profiles_ui_id != 0)
-    {
-      gtk_ui_manager_remove_ui (priv->ui_manager, priv->profiles_ui_id);
-      priv->profiles_ui_id = 0;
-    }
-
-  if (priv->profiles_action_group != NULL)
-    {
-      disconnect_profiles_from_actions_in_group (priv->profiles_action_group);
-      gtk_ui_manager_remove_action_group (priv->ui_manager,
-                                          priv->profiles_action_group);
-      priv->profiles_action_group = NULL;
-    }
-
-  profiles_list = terminal_app_get_profiles_list (terminal_app_get ());
-  profiles = terminal_profiles_list_ref_children_sorted (profiles_list);
-
-  action = gtk_action_group_get_action (priv->action_group, "TerminalProfiles");
-  single_profile = !profiles || profiles->next == NULL; /* list length <= 1 */
-  gtk_action_set_sensitive (action, !single_profile);
-
-  if (profiles == NULL)
-    return;
-
-  if (priv->active_screen)
-    active_profile = terminal_screen_get_profile (priv->active_screen);
-  else
-    active_profile = NULL;
-
-  action_group = priv->profiles_action_group = gtk_action_group_new ("Profiles");
-  gtk_ui_manager_insert_action_group (priv->ui_manager, action_group, -1);
-  g_object_unref (action_group);
-
-  priv->profiles_ui_id = gtk_ui_manager_new_merge_id (priv->ui_manager);
-
-  group = NULL;
-  n = 0;
-  for (p = profiles; p != NULL; p = p->next)
-    {
-      GSettings *profile = (GSettings *) p->data;
-      gs_unref_object GtkRadioAction *profile_action;
-      char name[32];
-
-      g_snprintf (name, sizeof (name), "TerminalSetProfile%u", n++);
-
-      profile_action = gtk_radio_action_new (name,
-                                             NULL,
-                                             NULL,
-                                             NULL,
-                                             n);
-
-      gtk_radio_action_set_group (profile_action, group);
-      group = gtk_radio_action_get_group (profile_action);
-
-      if (profile == active_profile)
-        gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (profile_action), TRUE);
-
-      g_object_set_data_full (G_OBJECT (profile_action),
-                              PROFILE_DATA_KEY,
-                              g_object_ref (profile),
-                              (GDestroyNotify) g_object_unref);
-      profile_visible_name_notify_cb (profile, TERMINAL_PROFILE_VISIBLE_NAME_KEY, GTK_ACTION 
(profile_action));
-      g_signal_connect (profile, "changed::" TERMINAL_PROFILE_VISIBLE_NAME_KEY,
-                        G_CALLBACK (profile_visible_name_notify_cb), profile_action);
-      g_signal_connect (profile_action, "toggled",
-                        G_CALLBACK (terminal_set_profile_toggled_callback), window);
-
-      gtk_action_group_add_action (action_group, GTK_ACTION (profile_action));
-
-      gtk_ui_manager_add_ui (priv->ui_manager, priv->profiles_ui_id,
-                             PROFILES_UI_PATH,
-                             name, name,
-                             GTK_UI_MANAGER_MENUITEM, FALSE);
-      gtk_ui_manager_add_ui (priv->ui_manager, priv->profiles_ui_id,
-                             PROFILES_POPUP_UI_PATH,
-                             name, name,
-                             GTK_UI_MANAGER_MENUITEM, FALSE);
-    }
-
-  g_list_free_full (profiles, (GDestroyNotify) g_object_unref);
-}
-
-static void
-terminal_window_create_new_terminal_action (TerminalWindow *window,
-                                            GSettings *profile,
-                                            const char *name,
-                                            guint num,
-                                            GCallback callback)
-{
-  TerminalWindowPrivate *priv = window->priv;
-  gs_unref_object GtkAction *action;
-
-  action = gtk_action_new (name, NULL, NULL, NULL);
-
-  g_object_set_data_full (G_OBJECT (action),
-                          PROFILE_DATA_KEY,
-                          g_object_ref (profile),
-                          (GDestroyNotify) g_object_unref);
-  profile_visible_name_notify_cb (profile, TERMINAL_PROFILE_VISIBLE_NAME_KEY, action);
-  g_signal_connect (profile, "changed::" TERMINAL_PROFILE_VISIBLE_NAME_KEY,
-                    G_CALLBACK (profile_visible_name_notify_cb), action);
-  g_signal_connect (action, "activate", callback, window);
-
-  gtk_action_group_add_action (priv->new_terminal_action_group, action);
-}
-
-static void
-terminal_window_update_new_terminal_menus (TerminalWindow *window)
-{
-  TerminalWindowPrivate *priv = window->priv;
-  GtkActionGroup *action_group;
-  GtkAction *action;
   TerminalSettingsList *profiles_list;
-  GList *profiles, *p;
-  guint n;
-  gboolean have_single_profile;
-
-  /* Remove the old UI */
-  if (priv->new_terminal_ui_id != 0)
-    {
-      gtk_ui_manager_remove_ui (priv->ui_manager, priv->new_terminal_ui_id);
-      priv->new_terminal_ui_id = 0;
-    }
-
-  if (priv->new_terminal_action_group != NULL)
-    {
-      disconnect_profiles_from_actions_in_group (priv->new_terminal_action_group);
-      gtk_ui_manager_remove_action_group (priv->ui_manager,
-                                          priv->new_terminal_action_group);
-      priv->new_terminal_action_group = NULL;
-    }
-
-  profiles_list = terminal_app_get_profiles_list (terminal_app_get ());
-  profiles = terminal_profiles_list_ref_children_sorted (profiles_list);
-
-  have_single_profile = !profiles || !profiles->next;
-
-  action = gtk_action_group_get_action (priv->action_group, "FileNewTab");
-  gtk_action_set_visible (action, have_single_profile);
-  action = gtk_action_group_get_action (priv->action_group, "FileNewWindow");
-  gtk_action_set_visible (action, have_single_profile);
-  action = gtk_action_group_get_action (priv->action_group, "FileNewTerminal");
-  gtk_action_set_visible (action, have_single_profile);
-
-  if (have_single_profile)
-    {
-      g_list_free_full (profiles, (GDestroyNotify) g_object_unref);
-      return;
-    }
-
-  /* Now build the submenus */
-
-  action_group = priv->new_terminal_action_group = gtk_action_group_new ("NewTerminal");
-  gtk_ui_manager_insert_action_group (priv->ui_manager, action_group, -1);
-  g_object_unref (action_group);
-
-  priv->new_terminal_ui_id = gtk_ui_manager_new_merge_id (priv->ui_manager);
-
-  n = 0;
-  for (p = profiles; p != NULL; p = p->next)
-    {
-      GSettings *profile = (GSettings *) p->data;
-      char name[32];
-
-      g_snprintf (name, sizeof (name), "FileNewTerminal.%u", n);
-      terminal_window_create_new_terminal_action (window,
-                                                  profile,
-                                                  name,
-                                                  n,
-                                                  G_CALLBACK (file_new_terminal_callback));
-
-      gtk_ui_manager_add_ui (priv->ui_manager, priv->new_terminal_ui_id,
-                             FILE_NEW_TERMINAL_UI_PATH,
-                             name, name,
-                             GTK_UI_MANAGER_MENUITEM, FALSE);
-
-      ++n;
-    }
-
-  g_list_free_full (profiles, (GDestroyNotify) g_object_unref);
-}
-
-static void
-terminal_set_encoding_callback (GtkToggleAction *action,
-                                TerminalWindow *window)
-{
-  TerminalWindowPrivate *priv = window->priv;
-  TerminalEncoding *encoding;
-  
-  if (!gtk_toggle_action_get_active (action))
-    return;
+  char *uuid;
 
   if (priv->active_screen == NULL)
     return;
 
-  encoding = g_object_get_data (G_OBJECT (action), ENCODING_DATA_KEY);
-  g_assert (encoding);
-
-  vte_terminal_set_encoding (VTE_TERMINAL (priv->active_screen),
-                             terminal_encoding_get_charset (encoding),
-                             NULL);
-}
-
-static void
-terminal_window_update_encoding_menu (TerminalWindow *window)
-{
-  TerminalWindowPrivate *priv = window->priv;
-  TerminalApp *app;
-  GtkActionGroup *action_group;
-  GSList *group;
-  guint n;
-  GSList *encodings, *l;
-  const char *charset;
-  TerminalEncoding *active_encoding;
-
-  /* Remove the old UI */
-  if (priv->encodings_ui_id != 0)
-    {
-      gtk_ui_manager_remove_ui (priv->ui_manager, priv->encodings_ui_id);
-      priv->encodings_ui_id = 0;
-    }
-
-  if (priv->encodings_action_group != NULL)
-    {
-      gtk_ui_manager_remove_action_group (priv->ui_manager,
-                                          priv->encodings_action_group);
-      priv->encodings_action_group = NULL;
-    }
-
-  action_group = priv->encodings_action_group = gtk_action_group_new ("Encodings");
-  gtk_ui_manager_insert_action_group (priv->ui_manager, action_group, -1);
-  g_object_unref (action_group);
-
-  priv->encodings_ui_id = gtk_ui_manager_new_merge_id (priv->ui_manager);
-
-  if (priv->active_screen)
-    charset = vte_terminal_get_encoding (VTE_TERMINAL (priv->active_screen));
-  else
-    charset = "UTF-8";
-
-  app = terminal_app_get ();
-  active_encoding = terminal_app_ensure_encoding (app, charset);
-
-  encodings = terminal_app_get_active_encodings (app);
-
-  if (g_slist_find (encodings, active_encoding) == NULL)
-    encodings = g_slist_append (encodings, terminal_encoding_ref (active_encoding));
-
-  group = NULL;
-  n = 0;
-  for (l = encodings; l != NULL; l = l->next)
-    {
-      TerminalEncoding *e = (TerminalEncoding *) l->data;
-      gs_unref_object GtkRadioAction *encoding_action;
-      char name[128];
-      gs_free char *display_name;
-
-      g_snprintf (name, sizeof (name), SET_ENCODING_ACTION_NAME_PREFIX "%s", terminal_encoding_get_charset 
(e));
-      display_name = g_strdup_printf ("%s (%s)", e->name, terminal_encoding_get_charset (e));
-
-      encoding_action = gtk_radio_action_new (name,
-                                              display_name,
-                                              NULL,
-                                              NULL,
-                                              n);
-
-      gtk_radio_action_set_group (encoding_action, group);
-      group = gtk_radio_action_get_group (encoding_action);
-
-      if (charset && strcmp (terminal_encoding_get_charset (e), charset) == 0)
-        gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (encoding_action), TRUE);
-
-      g_signal_connect (encoding_action, "toggled",
-                        G_CALLBACK (terminal_set_encoding_callback), window);
-
-      g_object_set_data_full (G_OBJECT (encoding_action), ENCODING_DATA_KEY,
-                              terminal_encoding_ref (e),
-                              (GDestroyNotify) terminal_encoding_unref);
-
-      gtk_action_group_add_action (action_group, GTK_ACTION (encoding_action));
+  new_active_profile = terminal_screen_get_profile (priv->active_screen);
 
-      gtk_ui_manager_add_ui (priv->ui_manager, priv->encodings_ui_id,
-                             SET_ENCODING_UI_PATH,
-                             name, name,
-                             GTK_UI_MANAGER_MENUITEM, FALSE);
-    }
+  profiles_list = terminal_app_get_profiles_list (terminal_app_get ());
+  uuid = terminal_settings_list_dup_uuid_from_child (profiles_list, new_active_profile);
 
-  g_slist_foreach (encodings, (GFunc) terminal_encoding_unref, NULL);
-  g_slist_free (encodings);
+  g_simple_action_set_state (lookup_action (window, "profile"),
+                             g_variant_new_take_string (uuid));
 }
 
 static void
 terminal_window_update_encoding_menu_active_encoding (TerminalWindow *window)
 {
   TerminalWindowPrivate *priv = window->priv;
-  GtkAction *action;
-  char name[128];
-
-  if (!priv->active_screen)
-    return;
-  if (!priv->encodings_action_group)
-    return;
 
-  g_snprintf (name, sizeof (name), SET_ENCODING_ACTION_NAME_PREFIX "%s",
-              vte_terminal_get_encoding (VTE_TERMINAL (priv->active_screen)));
-  action = gtk_action_group_get_action (priv->encodings_action_group, name);
-  if (!action)
+  if (priv->active_screen == NULL)
     return;
 
-  g_signal_handlers_block_by_func (action, G_CALLBACK (terminal_set_encoding_callback), window);
-  gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
-  g_signal_handlers_unblock_by_func (action, G_CALLBACK (terminal_set_encoding_callback), window);
+  const char *charset = vte_terminal_get_encoding (VTE_TERMINAL (priv->active_screen));
+  g_simple_action_set_state (lookup_action (window, "encoding"),
+                             g_variant_new_string (charset));
 }
 
 static void
 terminal_window_update_terminal_menu (TerminalWindow *window)
 {
   TerminalWindowPrivate *priv = window->priv;
-  GtkAction *action;
-
-  if (!priv->active_screen)
-    return;
-
-  action = gtk_action_group_get_action(priv->action_group, "TerminalReadOnly");
-  g_signal_handlers_block_by_func (action, G_CALLBACK (terminal_readonly_toggled_callback), window);
-  gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
-                                !vte_terminal_get_input_enabled (VTE_TERMINAL (priv->active_screen)));
-  g_signal_handlers_unblock_by_func (action, G_CALLBACK (terminal_readonly_toggled_callback), window);
-}
-
-static void
-terminal_size_to_cb (GtkAction *action,
-                     TerminalWindow *window)
-{
-  TerminalWindowPrivate *priv = window->priv;
-  const char *name;
-  char *end = NULL;
-  guint width, height;
 
   if (priv->active_screen == NULL)
     return;
 
-  name = gtk_action_get_name (action) + strlen (SIZE_TO_ACTION_NAME_PREFIX);
-  width = g_ascii_strtoull (name, &end, 10);
-  g_assert (end && *end == 'x');
-  height = g_ascii_strtoull (end + 1, &end, 10);
-  g_assert (end && *end == '\0');
-
-  vte_terminal_set_size (VTE_TERMINAL (priv->active_screen), width, height);
-
-  terminal_window_update_size (window);
-}
-
-static void
-terminal_window_update_size_to_menu (TerminalWindow *window)
-{
-  static const struct {
-    guint grid_width;
-    guint grid_height;
-  } predefined_sizes[] = {
-    { 80, 24 },
-    { 80, 43 },
-    { 132, 24 },
-    { 132, 43 }
-  };
-  TerminalWindowPrivate *priv = window->priv;
-  guint i;
-
-  /* We only install this once, so there's no need for a separate action group
-   * and any cleanup + build-new-one action here.
-   */
-
-  for (i = 0; i < G_N_ELEMENTS (predefined_sizes); ++i)
-    {
-      guint grid_width = predefined_sizes[i].grid_width;
-      guint grid_height = predefined_sizes[i].grid_height;
-      gs_unref_object GtkAction *action;
-      char name[40];
-      gs_free char *display_name;
-
-      g_snprintf (name, sizeof (name), SIZE_TO_ACTION_NAME_PREFIX "%ux%u",
-                  grid_width, grid_height);
-
-      /* If there are ever more than 9 of these, extend this to use A..Z as mnemonics,
-       * like we do for the profiles menu.
-       */
-      display_name = g_strdup_printf ("_%u. %u×%u", i + 1, grid_width, grid_height);
-
-      action = gtk_action_new (name, display_name, NULL, NULL);
-      g_signal_connect (action, "activate",
-                        G_CALLBACK (terminal_size_to_cb), window);
-
-      gtk_action_group_add_action (priv->action_group, action);
-
-      gtk_ui_manager_add_ui (priv->ui_manager, priv->ui_id,
-                             SIZE_TO_UI_PATH,
-                             name, name,
-                             GTK_UI_MANAGER_MENUITEM, FALSE);
-    }
+  gboolean read_only = !vte_terminal_get_input_enabled (VTE_TERMINAL (priv->active_screen));
+  g_simple_action_set_state (lookup_action (window, "read-only"),
+                             g_variant_new_boolean (read_only));
 }
 
 /* Actions stuff */
@@ -1773,19 +1537,13 @@ terminal_window_update_copy_sensitivity (TerminalScreen *screen,
                                          TerminalWindow *window)
 {
   TerminalWindowPrivate *priv = window->priv;
-  GtkAction *action;
   gboolean can_copy;
 
   if (screen != priv->active_screen)
     return;
 
   can_copy = vte_terminal_get_has_selection (VTE_TERMINAL (screen));
-
-  action = gtk_action_group_get_action (priv->action_group, "EditCopy");
-  gtk_action_set_sensitive (action, can_copy);
-
-  action = gtk_action_group_get_action (priv->action_group, "EditCopyHTML");
-  gtk_action_set_sensitive (action, can_copy);
+  g_simple_action_set_enabled (lookup_action (window, "copy"), can_copy);
 }
 
 static void
@@ -1793,19 +1551,17 @@ terminal_window_update_zoom_sensitivity (TerminalWindow *window)
 {
   TerminalWindowPrivate *priv = window->priv;
   TerminalScreen *screen;
-  GtkAction *action;
-  double current, zoom;
-  
+
   screen = priv->active_screen;
   if (screen == NULL)
     return;
 
-  current = vte_terminal_get_font_scale (VTE_TERMINAL (screen));
+  double zoom = vte_terminal_get_font_scale (VTE_TERMINAL (screen));
 
-  action = gtk_action_group_get_action (priv->action_group, "ViewZoomOut");
-  gtk_action_set_sensitive (action, find_smaller_zoom_factor (current, &zoom));
-  action = gtk_action_group_get_action (priv->action_group, "ViewZoomIn");
-  gtk_action_set_sensitive (action, find_larger_zoom_factor (current, &zoom));
+  g_simple_action_set_enabled (lookup_action (window, "zoom-in"),
+                               find_larger_zoom_factor (&zoom));
+  g_simple_action_set_enabled (lookup_action (window, "zoom-out"),
+                               find_smaller_zoom_factor (&zoom));
 }
 
 static void
@@ -1813,67 +1569,36 @@ terminal_window_update_search_sensitivity (TerminalScreen *screen,
                                            TerminalWindow *window)
 {
   TerminalWindowPrivate *priv = window->priv;
-  GtkAction *action;
-  gboolean can_search;
 
   if (screen != priv->active_screen)
     return;
 
-  can_search = vte_terminal_search_get_regex (VTE_TERMINAL (screen)) != NULL;
+  gboolean can_search = vte_terminal_search_get_regex (VTE_TERMINAL (screen)) != NULL;
 
-  action = gtk_action_group_get_action (priv->action_group, "SearchFindNext");
-  gtk_action_set_sensitive (action, can_search);
-  action = gtk_action_group_get_action (priv->action_group, "SearchFindPrevious");
-  gtk_action_set_sensitive (action, can_search);
-  action = gtk_action_group_get_action (priv->action_group, "SearchClearHighlight");
-  gtk_action_set_sensitive (action, can_search);
+  g_simple_action_set_enabled (lookup_action (window, "find-forward"), can_search);
+  g_simple_action_set_enabled (lookup_action (window, "find-backward"), can_search);
+  g_simple_action_set_enabled (lookup_action (window, "find-clear"), can_search);
 }
 
 static void
-update_edit_menu_cb (GtkClipboard *clipboard,
-                     GdkAtom *targets,
-                     int n_targets,
-                     GWeakRef *ref)
+clipboard_targets_changed_cb (TerminalApp *app,
+                              GtkClipboard *clipboard,
+                              TerminalWindow *window)
 {
-  TerminalWindow *window;
-  TerminalWindowPrivate *priv;
-  GtkAction *action;
-  gboolean can_paste, can_paste_uris;
-
-  window = g_weak_ref_get (ref);
-  if (window == NULL)
-    goto out;
-
-  /* Now we know the window is still alive */
-  priv = window->priv;
-
-  can_paste = targets != NULL && gtk_targets_include_text (targets, n_targets);
-  can_paste_uris = targets != NULL && gtk_targets_include_uri (targets, n_targets);
+  TerminalWindowPrivate *priv = window->priv;
 
-  action = gtk_action_group_get_action (priv->action_group, "EditPaste");
-  gtk_action_set_sensitive (action, can_paste);
-  action = gtk_action_group_get_action (priv->action_group, "EditPasteURIPaths");
-  gtk_action_set_visible (action, can_paste_uris);
-  gtk_action_set_sensitive (action, can_paste_uris);
+  if (clipboard != priv->clipboard)
+    return;
 
-  g_object_unref (window);
- out:
-  g_weak_ref_clear (ref);
-  g_slice_free (GWeakRef, ref);
-}
+  GdkAtom *targets;
+  int n_targets;
+  targets = terminal_app_get_clipboard_targets (app, clipboard, &n_targets);
 
-static void
-update_edit_menu (GtkClipboard *clipboard,
-                  GdkEvent *event G_GNUC_UNUSED,
-                  TerminalWindow *window)
-{
-  GWeakRef *ref;
+  gboolean can_paste = gtk_targets_include_text (targets, n_targets);
+  gboolean can_paste_uris = gtk_targets_include_uri (targets, n_targets);
 
-  ref = g_slice_new0 (GWeakRef);
-  g_weak_ref_init (ref, window);
-  gtk_clipboard_request_targets (clipboard,
-                                 (GtkClipboardTargetsReceivedFunc) update_edit_menu_cb,
-                                 ref);
+  g_simple_action_set_enabled (lookup_action (window, "paste-text"), can_paste);
+  g_simple_action_set_enabled (lookup_action (window, "paste-uris"), can_paste_uris);
 }
 
 static void
@@ -1886,7 +1611,9 @@ screen_resize_window_cb (TerminalScreen *screen,
   GtkWidget *widget = GTK_WIDGET (screen);
 
   if (gtk_widget_get_realized (widget) &&
-      (gdk_window_get_state (gtk_widget_get_window (widget)) & (GDK_WINDOW_STATE_MAXIMIZED | 
GDK_WINDOW_STATE_FULLSCREEN)) != 0)
+      (gdk_window_get_state (gtk_widget_get_window (widget)) & (GDK_WINDOW_STATE_MAXIMIZED |
+                                                                GDK_WINDOW_STATE_FULLSCREEN |
+                                                                GDK_WINDOW_STATE_TILED)) != 0)
     return;
 
   vte_terminal_set_size (VTE_TERMINAL (priv->active_screen), columns, rows);
@@ -1896,55 +1623,54 @@ screen_resize_window_cb (TerminalScreen *screen,
 }
 
 static void
-terminal_window_update_tabs_menu_sensitivity (TerminalWindow *window)
+terminal_window_update_tabs_actions_sensitivity (TerminalWindow *window)
 {
   TerminalWindowPrivate *priv = window->priv;
-  GAction *gaction;
-  GtkActionGroup *action_group = priv->action_group;
-  GtkAction *action;
-  int num_pages, page_num;
-  gboolean not_first, not_last;
 
   if (priv->disposed)
     return;
 
-  num_pages = terminal_mdi_container_get_n_screens (priv->mdi_container);
-  page_num = terminal_mdi_container_get_active_screen_num (priv->mdi_container);
-  not_first = page_num > 0;
-  not_last = page_num + 1 < num_pages;
+  int num_pages = terminal_mdi_container_get_n_screens (priv->mdi_container);
+  int page_num = terminal_mdi_container_get_active_screen_num (priv->mdi_container);
+
+  gboolean not_only = num_pages > 1;
+  gboolean not_first = page_num > 0;
+  gboolean not_last = page_num + 1 < num_pages;
+
+  gboolean not_first_lr, not_last_lr;
+  if (gtk_widget_get_direction (GTK_WIDGET (window)) == GTK_TEXT_DIR_RTL) {
+    not_first_lr = not_last;
+    not_last_lr = not_first;
+  } else {
+    not_first_lr = not_first;
+    not_last_lr = not_last;
+  }
 
   /* Hide the tabs menu in single-tab windows */
-  action = gtk_action_group_get_action (action_group, "Tabs");
-  gtk_action_set_visible (action, num_pages > 1);
-  
-#if 1
-  /* NOTE: We always make next/prev actions sensitive except in
-   * single-tab windows, so the corresponding shortcut key escape code
-   * isn't sent to the terminal. See bug #453193 and bug #138609.
-   * This also makes tab cycling work, bug #92139.
-   * FIXME: Find a better way to do this.
-   */
-  action = gtk_action_group_get_action (action_group, "TabsPrevious");
-  gtk_action_set_sensitive (action, num_pages > 1);
-  action = gtk_action_group_get_action (action_group, "TabsNext");
-  gtk_action_set_sensitive (action, num_pages > 1);
-#else
-  /* This would be correct, but see the comment above. */
-  action = gtk_action_group_get_action (action_group, "TabsPrevious");
-  gtk_action_set_sensitive (action, not_first);
-  action = gtk_action_group_get_action (action_group, "TabsNext");
-  gtk_action_set_sensitive (action, not_last);
-#endif
+  g_simple_action_set_enabled (lookup_action (window, "tabs-menu"), not_only);
+
+  /* Disable shadowing of MDI actions in SDI windows */
+  g_simple_action_set_enabled (lookup_action (window, "shadow-mdi"), not_only);
 
-  gaction = g_action_map_lookup_action (G_ACTION_MAP (window), "switch-tab");
-  g_simple_action_set_enabled (G_SIMPLE_ACTION (gaction), num_pages > 1);
+  /* Disable tab switching (and all its shortcuts) in SDI windows */
+  g_simple_action_set_enabled (lookup_action (window, "active-tab"), not_only);
 
-  action = gtk_action_group_get_action (action_group, "TabsMoveLeft");
-  gtk_action_set_sensitive (action, not_first);
-  action = gtk_action_group_get_action (action_group, "TabsMoveRight");
-  gtk_action_set_sensitive (action, not_last);
-  action = gtk_action_group_get_action (action_group, "TabsDetach");
-  gtk_action_set_sensitive (action, num_pages > 1);
+  /* Set the active tab */
+  g_simple_action_set_state (lookup_action (window, "active-tab"),
+                             g_variant_new_int32 (page_num));
+
+  /* Keynav wraps around? See bug #92139 */
+  gboolean keynav_wrap_around;
+  g_object_get (gtk_widget_get_settings (GTK_WIDGET (window)),
+                "gtk-keynav-wrap-around", &keynav_wrap_around,
+                NULL);
+
+  gboolean wrap = keynav_wrap_around && not_only;
+  g_simple_action_set_enabled (lookup_action (window, "tab-switch-left"), not_first || wrap);
+  g_simple_action_set_enabled (lookup_action (window, "tab-switch-right"), not_last || wrap);
+  g_simple_action_set_enabled (lookup_action (window, "tab-move-left"), not_first_lr || wrap);
+  g_simple_action_set_enabled (lookup_action (window, "tab-move-right"), not_last_lr || wrap);
+  g_simple_action_set_enabled (lookup_action (window, "tab-detach"), not_only);
 }
 
 static GtkNotebook *
@@ -1966,86 +1692,12 @@ handle_tab_droped_on_desktop (GtkNotebook *source_notebook,
   new_priv = new_window->priv;
   new_priv->present_on_insert = TRUE;
 
-//   update_tab_visibility (source_window, -1);
-//   update_tab_visibility (new_window, +1);
-
   return GTK_NOTEBOOK (new_priv->mdi_container);
 }
 
 /* Terminal screen popup menu handling */
 
 static void
-popup_open_hyperlink_callback (GtkAction *action,
-                               TerminalWindow *window)
-{
-  TerminalWindowPrivate *priv = window->priv;
-  TerminalScreenPopupInfo *info = priv->popup_info;
-
-  if (info == NULL)
-    return;
-
-  terminal_util_open_url (GTK_WIDGET (window), info->hyperlink, FLAVOR_AS_IS,
-                          gtk_get_current_event_time ());
-}
-
-static void
-popup_copy_hyperlink_callback (GtkAction *action,
-                               TerminalWindow *window)
-{
-  TerminalWindowPrivate *priv = window->priv;
-  TerminalScreenPopupInfo *info = priv->popup_info;
-  GtkClipboard *clipboard;
-
-  if (info == NULL)
-    return;
-
-  if (info->hyperlink == NULL)
-    return;
-
-  clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_CLIPBOARD);
-  gtk_clipboard_set_text (clipboard, info->hyperlink, -1);
-}
-
-static void
-popup_open_url_callback (GtkAction *action,
-                         TerminalWindow *window)
-{
-  TerminalWindowPrivate *priv = window->priv;
-  TerminalScreenPopupInfo *info = priv->popup_info;
-
-  if (info == NULL)
-    return;
-
-  terminal_util_open_url (GTK_WIDGET (window), info->url, info->url_flavor,
-                          gtk_get_current_event_time ());
-}
-
-static void
-popup_copy_url_callback (GtkAction *action,
-                         TerminalWindow *window)
-{
-  TerminalWindowPrivate *priv = window->priv;
-  TerminalScreenPopupInfo *info = priv->popup_info;
-  GtkClipboard *clipboard;
-
-  if (info == NULL)
-    return;
-
-  if (info->url == NULL)
-    return;
-
-  clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_CLIPBOARD);
-  gtk_clipboard_set_text (clipboard, info->url, -1);
-}
-
-static void
-popup_leave_fullscreen_callback (GtkAction *action,
-                                 TerminalWindow *window)
-{
-    gtk_window_unfullscreen (GTK_WINDOW (window));
-}
-
-static void
 remove_popup_info (TerminalWindow *window)
 {
   TerminalWindowPrivate *priv = window->priv;
@@ -2090,118 +1742,154 @@ unset_popup_info (TerminalWindow *window)
 }
 
 static void
-popup_menu_deactivate_callback (GtkWidget *popup,
-                                TerminalWindow *window)
+screen_popup_menu_deactivate_cb (GtkWidget *popup,
+                                 TerminalWindow *window)
 {
   g_signal_handlers_disconnect_by_func
-    (popup, G_CALLBACK (popup_menu_deactivate_callback), window);
+    (popup, G_CALLBACK (screen_popup_menu_deactivate_cb), window);
 
   unset_popup_info (window);
 }
 
 static void
-popup_clipboard_targets_received_cb (GtkClipboard *clipboard,
-                                     GdkAtom *targets,
-                                     int n_targets,
-                                     TerminalScreenPopupInfo *info)
+screen_show_popup_menu_cb (TerminalScreen *screen,
+                           TerminalScreenPopupInfo *info,
+                           TerminalWindow *window)
 {
-  TerminalWindow *window;
-  TerminalWindowPrivate *priv;
-  TerminalScreen *screen = info->screen;
-  GtkWidget *popup_menu;
-  GtkAction *action;
-  gboolean has_selection;
-  gboolean can_paste, can_paste_uris, show_hyperlink, show_link, show_email_link, show_call_link, 
show_number_info;
+  TerminalWindowPrivate *priv = window->priv;
+  TerminalApp *app = terminal_app_get ();
 
-  window = terminal_screen_popup_info_ref_window (info);
-  if (window == NULL ||
-      !gtk_widget_get_realized (GTK_WIDGET (screen)))
-    {
-      terminal_screen_popup_info_unref (info);
-      return;
+  if (screen != priv->active_screen)
+    return;
+
+  remove_popup_info (window);
+  priv->popup_info = terminal_screen_popup_info_ref (info);
+
+  gs_unref_object GMenu *menu = g_menu_new ();
+
+  /* Hyperlink section */
+  if (info->hyperlink != NULL) {
+    gs_unref_object GMenu *section1 = g_menu_new ();
+
+    g_menu_append (section1, _("Open _Hyperlink"), "win.open-hyperlink");
+    g_menu_append (section1, _("Copy Hyperlink _Address"), "win.copy-hyperlink");
+    g_menu_append_section (menu, NULL, G_MENU_MODEL (section1));
+  }
+  /* Matched link section */
+  else if (info->url != NULL) {
+    gs_unref_object GMenu *section2 = g_menu_new ();
+
+    const char *open_label = NULL, *copy_label = NULL;
+    switch (info->url_flavor) {
+    case FLAVOR_EMAIL:
+      open_label = _("Call _To…");
+      copy_label = _("Copy Call _Address ");
+      break;
+    case FLAVOR_VOIP_CALL:
+      open_label = _("Send Mail _To…");
+      copy_label = _("Copy Mail _Address");
+      break;
+    case FLAVOR_AS_IS:
+    case FLAVOR_DEFAULT_TO_HTTP:
+    default:
+      open_label = _("_Open Link");
+      copy_label = _("Copy _Link");
+      break;
     }
 
-  /* Now we know that the window is still alive */
-  priv = window->priv;
+    g_menu_append (section2, open_label, "win.open-match");
+    g_menu_append (section2, copy_label, "win.copy-match");
+    g_menu_append_section (menu, NULL, G_MENU_MODEL (section2));
+  }
 
-  remove_popup_info (window);
-  priv->popup_info = info; /* adopt the ref added when requesting the clipboard */
-
-  has_selection = vte_terminal_get_has_selection (VTE_TERMINAL (screen));
-  can_paste = targets != NULL && gtk_targets_include_text (targets, n_targets);
-  can_paste_uris = targets != NULL && gtk_targets_include_uri (targets, n_targets);
-  show_hyperlink = info->hyperlink != NULL;
-  show_link = !show_hyperlink && info->url != NULL && (info->url_flavor == FLAVOR_AS_IS || info->url_flavor 
== FLAVOR_DEFAULT_TO_HTTP);
-  show_email_link = !show_hyperlink && info->url != NULL && info->url_flavor == FLAVOR_EMAIL;
-  show_call_link = !show_hyperlink && info->url != NULL && info->url_flavor == FLAVOR_VOIP_CALL;
-  show_number_info = info->number_info != NULL;
-
-  action = gtk_action_group_get_action (priv->action_group, "PopupOpenHyperlink");
-  gtk_action_set_visible (action, show_hyperlink);
-  action = gtk_action_group_get_action (priv->action_group, "PopupCopyHyperlinkAddress");
-  gtk_action_set_visible (action, show_hyperlink);
-
-  action = gtk_action_group_get_action (priv->action_group, "PopupSendEmail");
-  gtk_action_set_visible (action, show_email_link);
-  action = gtk_action_group_get_action (priv->action_group, "PopupCopyEmailAddress");
-  gtk_action_set_visible (action, show_email_link);
-  action = gtk_action_group_get_action (priv->action_group, "PopupCall");
-  gtk_action_set_visible (action, show_call_link);
-  action = gtk_action_group_get_action (priv->action_group, "PopupCopyCallAddress");
-  gtk_action_set_visible (action, show_call_link);
-  action = gtk_action_group_get_action (priv->action_group, "PopupOpenLink");
-  gtk_action_set_visible (action, show_link);
-  action = gtk_action_group_get_action (priv->action_group, "PopupCopyLinkAddress");
-  gtk_action_set_visible (action, show_link);
-
-  action = gtk_action_group_get_action (priv->action_group, "PopupNumberInfo");
-  gtk_action_set_label (action, info->number_info);
-  gtk_action_set_sensitive (action, FALSE);
-  gtk_action_set_visible (action, show_number_info);
-
-  action = gtk_action_group_get_action (priv->action_group, "PopupCopy");
-  gtk_action_set_sensitive (action, has_selection);
-  action = gtk_action_group_get_action (priv->action_group, "PopupCopyHTML");
-  gtk_action_set_sensitive (action, has_selection);
-  action = gtk_action_group_get_action (priv->action_group, "PopupPaste");
-  gtk_action_set_sensitive (action, can_paste);
-  action = gtk_action_group_get_action (priv->action_group, "PopupPasteURIPaths");
-  gtk_action_set_visible (action, can_paste_uris);
-
-  popup_menu = gtk_ui_manager_get_widget (priv->ui_manager, "/Popup");
-  g_signal_connect (popup_menu, "deactivate",
-                    G_CALLBACK (popup_menu_deactivate_callback), window);
+  /* Info section */
+  if (info->number_info != NULL) {
+    gs_unref_object GMenu *section3 = g_menu_new ();
+    /* Non-existent action will make this item insensitive */
+    gs_unref_object GMenuItem *item3 = g_menu_item_new (info->number_info, "win.notexist");
+    g_menu_append_item (section3, item3);
+    g_menu_append_section (menu, NULL, G_MENU_MODEL (section3));
+  }
 
-  /* Pseudo activation of the popup menu's action */
-  action = gtk_action_group_get_action (priv->action_group, "Popup");
-  gtk_action_activate (action);
+  /* Clipboard section */
+  gs_unref_object GMenu *section4 = g_menu_new ();
+
+  g_menu_append (section4, _("_Copy"), "win.copy::text");
+  g_menu_append (section4, _("Copy as _HTML"), "win.copy::html");
+  g_menu_append (section4, _("_Paste"), "win.paste-text");
+  if (g_action_get_enabled (G_ACTION (lookup_action (window, "paste-uris"))))
+    g_menu_append (section4, _("Paste as _Filenames"), "win.paste-uris");
+
+  g_menu_append_section (menu, NULL, G_MENU_MODEL (section4));
+
+  /* Profile and property section */
+  gs_unref_object GMenu *section5 = g_menu_new ();
+  g_menu_append (section5, _("Read-_Only"), "win.read-only");
+
+  GMenuModel *profiles_menu = terminal_app_get_profile_section (app);
+  if (profiles_menu != NULL && g_menu_model_get_n_items (profiles_menu) > 1) {
+    gs_unref_object GMenu *submenu5 = g_menu_new ();
+    g_menu_append_section (submenu5, NULL, profiles_menu);
+
+    gs_unref_object GMenu *section51 = g_menu_new ();
+    g_menu_append (section51, _("_Profile Preferences…"), "win.edit-profile");
+    g_menu_append_section (submenu5, NULL, G_MENU_MODEL (section51));
+
+    gs_unref_object GMenuItem *item5 = g_menu_item_new (_("P_rofiles"), NULL);
+    g_menu_item_set_submenu (item5, G_MENU_MODEL (submenu5));
+    g_menu_append_item (section5, item5);
+  } else {
+    /* If there's only a single profile, put the Profile Preferences item in the
+     * context menu itself.
+     */
+    g_menu_append (section5, _("_Profile Preferences…"), "win.edit-profile");
+  }
 
-  if (info->button == 0)
-    gtk_menu_shell_select_first (GTK_MENU_SHELL (popup_menu), FALSE);
+  g_menu_append_section (menu, NULL, G_MENU_MODEL (section5));
+
+  /* New Terminal section */
+  gs_unref_object GMenu *section6 = g_menu_new ();
+#ifndef DISUNIFY_NEW_TERMINAL_SECTION
+  gs_unref_object GMenuItem *item6 = g_menu_item_new (_("New _Terminal"), NULL);
+  g_menu_item_set_action_and_target (item6, "win.new-terminal",
+                                     "(ss)", "default", "current");
+  g_menu_append_item (section6, item6);
+#else
+  gs_unref_object GMenuItem *item61 = g_menu_item_new (_("New _Window"), NULL);
+  g_menu_item_set_action_and_target (item61, "win.new-terminal",
+                                     "(ss)", "window", "current");
+  g_menu_append_item (section6, item61);
+  gs_unref_object GMenuItem *item62 = g_menu_item_new (_("New _Tab"), NULL);
+  g_menu_item_set_action_and_target (item62, "win.new-terminal",
+                                     "(ss)", "tab", "current");
+  g_menu_append_item (section6, item62);
+#endif
+  g_menu_append_section (menu, NULL, G_MENU_MODEL (section6));
+
+  /* Window section */
+  gs_unref_object GMenu *section7 = g_menu_new ();
 
-  if (gtk_menu_get_attach_widget (GTK_MENU (popup_menu)))
-    gtk_menu_detach (GTK_MENU (popup_menu));
-  gtk_menu_attach_to_widget (GTK_MENU (popup_menu), GTK_WIDGET (screen), NULL);
-  gtk_menu_popup (GTK_MENU (popup_menu),
+  /* Only show this if the WM doesn't show the menubar */
+  if (g_action_get_enabled (G_ACTION (lookup_action (window, "menubar-visible"))))
+    g_menu_append (section7, _("Show _Menubar"), "win.menubar-visible");
+  if (g_action_get_enabled (G_ACTION (lookup_action (window, "leave-fullscreen"))))
+    g_menu_append (section7, _("L_eave Full Screen"), "win.leave-fullscreen");
+
+  g_menu_append_section (menu, NULL, G_MENU_MODEL (section7));
+
+  /* Now create the popup menu and show it */
+  GtkWidget *popup_menu = context_menu_new (G_MENU_MODEL (menu), GTK_WIDGET (window));
+
+  g_signal_connect (popup_menu, "deactivate",
+                    G_CALLBACK (screen_popup_menu_deactivate_cb), window);
+
+  gtk_menu_popup (GTK_MENU (popup_menu), NULL, NULL,
                   NULL, NULL,
-                  NULL, NULL, 
                   info->button,
                   info->timestamp);
 
-  g_object_unref (window);
-}
-
-static void
-screen_show_popup_menu_callback (TerminalScreen *screen,
-                                 TerminalScreenPopupInfo *info,
-                                 TerminalWindow *window)
-{
-  GtkClipboard *clipboard;
-
-  clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_CLIPBOARD);
-  gtk_clipboard_request_targets (clipboard,
-                                  (GtkClipboardTargetsReceivedFunc) popup_clipboard_targets_received_cb,
-                                  terminal_screen_popup_info_ref (info));
+  if (info->button == 0)
+    gtk_menu_shell_select_first (GTK_MENU_SHELL (popup_menu), FALSE);
 }
 
 static gboolean
@@ -2230,83 +1918,59 @@ screen_close_cb (TerminalScreen *screen,
   terminal_window_remove_screen (window, screen);
 }
 
-static gboolean
-terminal_window_accel_activate_cb (GtkAccelGroup  *accel_group,
-                                   GObject        *acceleratable,
-                                   guint           keyval,
-                                   GdkModifierType modifier,
-                                   TerminalWindow *window)
+static void
+notebook_update_tabs_menu_cb (GtkMenuButton *button,
+                              TerminalWindow *window)
 {
-  GtkAccelGroupEntry *entries;
-  guint n_entries;
-  gboolean retval = FALSE;
+  gs_unref_object GMenu *menu;
+  gs_free_list GList *tabs;
+  GList *t;
+  int i;
 
-  entries = gtk_accel_group_query (accel_group, keyval, modifier, &n_entries);
-  if (n_entries > 0)
-    {
-      const char *accel_path;
+  menu = g_menu_new ();
+  tabs = terminal_window_list_screen_containers (window);
 
-      accel_path = g_quark_to_string (entries[0].accel_path_quark);
+  for (t = tabs, i = 0; t != NULL; t = t->next, i++) {
+    TerminalScreenContainer *container = t->data;
+    TerminalScreen *screen = terminal_screen_container_get_screen (container);
+    gs_unref_object GMenuItem *item;
+    const char *title;
 
-      if (g_str_has_prefix (accel_path, "<Actions>/Main/"))
-        {
-          const char *action_name;
+    title = terminal_screen_get_title (screen);
 
-          /* We want to always consume these accelerators, even if the corresponding
-           * action is insensitive, so the corresponding shortcut key escape code
-           * isn't sent to the terminal. See bug #453193, bug #138609 and bug #559728.
-           * This also makes tab cycling work, bug #92139. (NOT!)
-           */
+    item = g_menu_item_new (title && title[0] ? title : _("Terminal"), NULL);
+    g_menu_item_set_action_and_target (item, "win.active-tab", "i", i);
+    g_menu_append_item (menu, item);
+  }
 
-          action_name = I_(accel_path + strlen ("<Actions>/Main/"));
+  gtk_menu_button_set_menu_model (button, G_MENU_MODEL (menu));
 
-#if 0
-          if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook)) > 1 &&
-              (action_name == I_("TabsPrevious") || action_name == I_("TabsNext")))
-            retval = TRUE;
-          else
-#endif
-               if (action_name == I_("EditCopy") ||
-                   action_name == I_("PopupCopy") ||
-                   action_name == I_("EditPaste") ||
-                   action_name == I_("PopupPaste"))
-            retval = TRUE;
-        }
-    }
-
-  return retval;
+  /* Need this so the menu is positioned correctly */
+  gtk_widget_set_halign (GTK_WIDGET (gtk_menu_button_get_popup (button)), GTK_ALIGN_END);
 }
 
 static void
 terminal_window_fill_notebook_action_box (TerminalWindow *window)
 {
   TerminalWindowPrivate *priv = window->priv;
-  GtkWidget *box, *button;
-  GtkAction *action;
-  GtkWidget *menu;
+  GtkWidget *box, *new_tab_button, *tabs_menu_button;
 
   box = terminal_notebook_get_action_box (TERMINAL_NOTEBOOK (priv->mdi_container), GTK_PACK_END);
 
   /* Create the NewTerminal button */
-  action = gtk_action_group_get_action (priv->action_group, "FileNewTab");
-
-  button = terminal_icon_button_new ("tab-new-symbolic");
-  gtk_activatable_set_related_action (GTK_ACTIVATABLE (button), action);
-  gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
-  gtk_widget_show (button);
+  new_tab_button = terminal_icon_button_new ("tab-new-symbolic");
+  gtk_actionable_set_action_name (GTK_ACTIONABLE (new_tab_button), "win.new-terminal");
+  gtk_actionable_set_action_target (GTK_ACTIONABLE (new_tab_button), "(ss)", "tab", "current");
+  gtk_box_pack_start (GTK_BOX (box), new_tab_button, FALSE, FALSE, 0);
+  gtk_widget_show (new_tab_button);
 
   /* Create Tabs menu button */
-  menu = gtk_ui_manager_get_widget (priv->ui_manager, "/TabsPopup");
-  gtk_widget_set_halign (menu, GTK_ALIGN_END);
-
-  button = gtk_menu_button_new ();
-  gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
-  gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE);
-  gtk_menu_button_set_popup (GTK_MENU_BUTTON (button), menu);
-
-  gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
-  gtk_menu_button_set_align_widget (GTK_MENU_BUTTON (button), box);
-  gtk_widget_show (button);
+  tabs_menu_button = terminal_menu_button_new ();
+  g_signal_connect (tabs_menu_button, "update-menu",
+                    G_CALLBACK (notebook_update_tabs_menu_cb), window);
+  gtk_box_pack_start (GTK_BOX (box), tabs_menu_button, FALSE, FALSE, 0);
+  gtk_menu_button_set_align_widget (GTK_MENU_BUTTON (tabs_menu_button), box);
+  gtk_widget_show (tabs_menu_button);
 }
 
 /*****************************************/
@@ -2366,24 +2030,21 @@ terminal_window_state_event (GtkWidget            *widget,
                              GdkEventWindowState  *event)
 {
   gboolean (* window_state_event) (GtkWidget *, GdkEventWindowState *event) =
-      GTK_WIDGET_CLASS (terminal_window_parent_class)->window_state_event;
+    GTK_WIDGET_CLASS (terminal_window_parent_class)->window_state_event;
 
   if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN)
     {
       TerminalWindow *window = TERMINAL_WINDOW (widget);
-      TerminalWindowPrivate *priv = window->priv;
-      GtkAction *action;
       gboolean is_fullscreen;
 
       is_fullscreen = (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) != 0;
 
-      action = gtk_action_group_get_action (priv->action_group, "ViewFullscreen");
-      gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), is_fullscreen);
-  
-      action = gtk_action_group_get_action (priv->action_group, "PopupLeaveFullscreen");
-      gtk_action_set_visible (action, is_fullscreen);
+      g_simple_action_set_state (lookup_action (window, "fullscreen"),
+                                 g_variant_new_boolean (is_fullscreen));
+      g_simple_action_set_enabled (lookup_action (window, "leave-fullscreen"),
+                                   is_fullscreen);
     }
-  
+
   if (window_state_event)
     return window_state_event (widget, event);
 
@@ -2421,9 +2082,11 @@ terminal_window_screen_update (TerminalWindow *window,
                    G_SETTINGS_BIND_GET);
 
   g_object_get (gtk_settings, "gtk-menu-bar-accel", &value, NULL);
+#if !GTK_CHECK_VERSION (3, 20, 0)
   g_object_set_data_full (G_OBJECT (gtk_settings), "GT::gtk-menu-bar-accel",
                           value, (GDestroyNotify) g_free);
-  enable_menubar_accel_changed_cb (settings, 
+#endif
+  enable_menubar_accel_changed_cb (settings,
                                    TERMINAL_SETTING_ENABLE_MENU_BAR_ACCEL_KEY,
                                    gtk_settings);
   g_signal_connect (settings, "changed::" TERMINAL_SETTING_ENABLE_MENU_BAR_ACCEL_KEY,
@@ -2454,261 +2117,73 @@ terminal_window_screen_changed (GtkWidget *widget,
 }
 
 static void
-terminal_window_profile_list_changed_cb (TerminalSettingsList *profiles_list,
-                                         TerminalWindow *window)
-{
-  terminal_window_update_set_profile_menu (window);
-  terminal_window_update_new_terminal_menus (window);
-}
-
-static void
-terminal_window_encoding_list_changed_cb (TerminalApp *app,
-                                          TerminalWindow *window)
-{
-  terminal_window_update_encoding_menu (window);
-}
-
-static void
 terminal_window_init (TerminalWindow *window)
 {
-  const GActionEntry gaction_entries[] = {
-    { "new-terminal",        action_new_terminal_cb,   "(ss)", NULL, NULL },
-    { "new-profile",         action_new_profile_cb,    NULL,   NULL, NULL },
-    { "save-contents",       action_save_contents_cb,  NULL,   NULL, NULL },
-    { "close",               action_close_cb,          "s",    NULL, NULL },
-    { "copy",                action_copy_cb,           "s",    NULL, NULL },
-    { "paste",               action_paste_cb,          "s",    NULL, NULL },
-    { "select-all",          action_select_all_cb,     NULL,   NULL, NULL },
-    { "reset",               action_reset_cb,          "b",    NULL, NULL },
-    { "switch-tab",          action_switch_tab_cb,     "i",    NULL, NULL },
-    { "move-tab",            action_move_tab_cb,       "i",    NULL, NULL },
-    { "zoom",                action_zoom_cb,           "i",    NULL, NULL },
-    { "detach-tab",          action_detach_tab_cb,     NULL,   NULL, NULL },
-    { "find",                action_find_cb,           "s",    NULL, NULL },
-    { "help",                action_help_cb,           NULL,   NULL, NULL },
-    { "about",               action_about_cb,          NULL,   NULL, NULL },
-    { "preferences",         action_preferences_cb,    NULL,   NULL, NULL },
-    { "edit-profile",        action_edit_profile_cb,   "s",    NULL, NULL },
-
-    { "show-menubar",        action_toggle_state_cb,   NULL, "true",  action_show_menubar_state_cb },
-    { "fullscreen",          action_toggle_state_cb,   NULL, "false", action_fullscreen_state_cb   },
-  };
-
-  const GtkActionEntry menu_entries[] =
-    {
-      /* Toplevel */
-      { "File", NULL, N_("_File") },
-      { "FileNewTerminalProfiles", STOCK_NEW_WINDOW, N_("Open _Terminal")},
-      { "Edit", NULL, N_("_Edit") },
-      { "View", NULL, N_("_View") },
-      { "Search", NULL, N_("_Search") },
-      { "Terminal", NULL, N_("_Terminal") },
-      { "Tabs", NULL, N_("Ta_bs") },
-      { "Help", NULL, N_("_Help") },
-      { "Popup", NULL, NULL },
-      { "NotebookPopup", NULL, "" },
-      { "TabsPopup", NULL, "" },
-
-      /* File menu */
-      { "FileNewWindow", STOCK_NEW_WINDOW, N_("Open _Terminal"), "<shift><control>N",
-        NULL,
-        G_CALLBACK (file_new_terminal_callback) },
-      { "FileNewTab", STOCK_NEW_TAB, N_("Open Ta_b"), "<shift><control>T",
-        NULL,
-        G_CALLBACK (file_new_terminal_callback) },
-      { "FileNewTerminal", STOCK_NEW_TAB, N_("Open _Terminal"), NULL,
-        NULL,
-        G_CALLBACK (file_new_terminal_callback) },
-      { "FileNewProfile", "document-open", N_("New _Profile"), "",
-        NULL,
-        G_CALLBACK (file_new_profile_callback) },
-      { "FileSaveContents", "document-save", N_("_Save Contents"), "",
-        NULL,
-        G_CALLBACK (file_save_contents_callback) },
-      { "FileCloseTab", "window-close", N_("C_lose Terminal"), "<shift><control>W",
-        NULL,
-        G_CALLBACK (file_close_tab_callback) },
-      { "FileCloseWindow", "window-close", N_("_Close All Terminals"), "<shift><control>Q",
-        NULL,
-        G_CALLBACK (file_close_window_callback) },
-
-      /* Edit menu */
-      { "EditCopy", "edit-copy", N_("_Copy"), "<shift><control>C",
-        NULL,
-        G_CALLBACK (edit_copy_callback) },
-      { "EditCopyHTML", "edit-copy", N_("Copy as _HTML"), NULL,
-        NULL,
-        G_CALLBACK (edit_copy_html_callback) },
-      { "EditPaste", "edit-paste", N_("_Paste"), "<shift><control>V",
-        NULL,
-        G_CALLBACK (edit_paste_callback) },
-      { "EditPasteURIPaths", "edit-paste", N_("Paste _Filenames"), "",
-        NULL,
-        G_CALLBACK (edit_paste_callback) },
-      { "EditSelectAll", "edit-select-all", N_("Select All"), NULL,
-        NULL,
-        G_CALLBACK (edit_select_all_callback) },
-      { "EditPreferences", NULL, N_("Pre_ferences"), NULL,
-        NULL,
-        G_CALLBACK (edit_preferences_callback) },
-      { "EditCurrentProfile", "preferences-system", N_("_Profile Preferences"), NULL,
-        NULL,
-        G_CALLBACK (edit_current_profile_callback) },
-
-      /* View menu */
-      { "ViewZoomIn", "zoom-in", N_("Zoom In"), "<control>plus",
-        NULL,
-        G_CALLBACK (view_zoom_in_callback) },
-      { "ViewZoomOut", "zoom-out", N_("Zoom Out"), "<control>minus",
-        NULL,
-        G_CALLBACK (view_zoom_out_callback) },
-      { "ViewZoom100", "zoom-original", N_("Normal Size"), "<control>0",
-        NULL,
-        G_CALLBACK (view_zoom_normal_callback) },
-
-      /* Search menu */
-      { "SearchFind", "edit-find", N_("_Find…"), "<shift><control>F",
-       NULL,
-       G_CALLBACK (search_find_callback) },
-      { "SearchFindNext", NULL, N_("Find Ne_xt"), "<shift><control>G",
-       NULL,
-       G_CALLBACK (search_find_next_callback) },
-      { "SearchFindPrevious", NULL, N_("Find Pre_vious"), "<shift><control>H",
-       NULL,
-       G_CALLBACK (search_find_prev_callback) },
-      { "SearchClearHighlight", NULL, N_("_Clear Highlight"), "<shift><control>J",
-       NULL,
-       G_CALLBACK (search_clear_highlight_callback) },
-#if 0
-      { "SearchGoToLine", "go-jump", N_("Go to _Line…"), "<shift><control>I",
-       NULL,
-       G_CALLBACK (search_goto_line_callback) },
-      { "SearchIncrementalSearch", "edit-find", N_("_Incremental Search…"), "<shift><control>K",
-       NULL,
-       G_CALLBACK (search_incremental_search_callback) },
+  const GActionEntry action_entries[] = {
+    /* Actions without state */
+    { "about",               action_about_cb,            NULL,   NULL, NULL },
+    { "close",               action_close_cb,            "s",    NULL, NULL },
+    { "copy",                action_copy_cb,             "s",    NULL, NULL },
+    { "copy-hyperlink",      action_copy_hyperlink_cb,   NULL,   NULL, NULL },
+    { "copy-match",          action_copy_match_cb,       NULL,   NULL, NULL },
+    { "edit-profile",        action_edit_profile_cb,     NULL,   NULL, NULL },
+    { "edit-preferences",    action_edit_preferences_cb, NULL,   NULL, NULL },
+    { "find",                action_find_cb,             NULL,   NULL, NULL },
+    { "find-backward",       action_find_backward_cb,    NULL,   NULL, NULL },
+    { "find-clear",          action_find_clear_cb,       NULL,   NULL, NULL },
+    { "find-forward",        action_find_forward_cb,     NULL,   NULL, NULL },
+    { "help",                action_help_cb,             NULL,   NULL, NULL },
+    { "inspector",           action_inspector_cb,        NULL,   NULL, NULL },
+    { "leave-fullscreen",    action_leave_fullscreen_cb, NULL,   NULL, NULL },
+    { "new-profile",         action_new_profile_cb,      NULL,   NULL, NULL },
+    { "new-terminal",        action_new_terminal_cb,     "(ss)", NULL, NULL },
+    { "open-match",          action_open_match_cb,       NULL,   NULL, NULL },
+    { "open-hyperlink",      action_open_hyperlink_cb,   NULL,   NULL, NULL },
+    { "paste-text",          action_paste_text_cb,       NULL,   NULL, NULL },
+    { "paste-uris",          action_paste_uris_cb,       NULL,   NULL, NULL },
+    { "reset",               action_reset_cb,            "b",    NULL, NULL },
+    { "select-all",          action_select_all_cb,       NULL,   NULL, NULL },
+    { "size-to",             action_size_to_cb,          "(uu)", NULL, NULL },
+    { "tab-detach",          action_tab_detach_cb,       NULL,   NULL, NULL },
+    { "tab-move-left",       action_tab_move_left_cb,    NULL,   NULL, NULL },
+    { "tab-move-right",      action_tab_move_right_cb,   NULL,   NULL, NULL },
+    { "tab-switch-left",     action_tab_switch_left_cb,  NULL,   NULL, NULL },
+    { "tab-switch-right",    action_tab_switch_right_cb, NULL,   NULL, NULL },
+    { "tabs-menu",           NULL,                       NULL,   NULL, NULL },
+    { "zoom-in",             action_zoom_in_cb,          NULL,   NULL, NULL },
+    { "zoom-normal",         action_zoom_normal_cb,      NULL,   NULL, NULL },
+    { "zoom-out",            action_zoom_out_cb,         NULL,   NULL, NULL },
+#ifdef ENABLE_EXPORT
+    { "export",              action_export_cb,           NULL,   NULL, NULL },
+#endif
+#ifdef ENABLE_PRINT
+    { "print",               action_print_cb,            NULL,   NULL, NULL },
+#endif
+#ifdef ENABLE_SAVE
+    { "save-contents",       action_save_contents_cb,    NULL,   NULL, NULL },
 #endif
 
-      /* Terminal menu */
-      { "TerminalProfiles", NULL, N_("Change _Profile") },
-      { "TerminalSetEncoding", NULL, N_("Set _Character Encoding") },
-      { "TerminalReset", NULL, N_("_Reset"), NULL,
-        NULL,
-        G_CALLBACK (terminal_reset_callback) },
-      { "TerminalResetClear", NULL, N_("Reset and C_lear"), NULL,
-        NULL,
-        G_CALLBACK (terminal_reset_clear_callback) },
-
-      /* Terminal/Encodings menu */
-      { "TerminalAddEncoding", NULL, N_("_Add or Remove…"), NULL,
-        NULL,
-        G_CALLBACK (terminal_add_encoding_callback) },
-
-      /* Tabs menu */
-      { "TabsPrevious", NULL, N_("_Previous Terminal"), "<control>Page_Up",
-        NULL,
-        G_CALLBACK (tabs_next_or_previous_tab_cb) },
-      { "TabsNext", NULL, N_("_Next Terminal"), "<control>Page_Down",
-        NULL,
-        G_CALLBACK (tabs_next_or_previous_tab_cb) },
-      { "TabsMoveLeft", NULL, N_("Move Terminal _Left"), "<shift><control>Page_Up",
-        NULL,
-        G_CALLBACK (tabs_move_left_callback) },
-      { "TabsMoveRight", NULL, N_("Move Terminal _Right"), "<shift><control>Page_Down",
-        NULL,
-        G_CALLBACK (tabs_move_right_callback) },
-      { "TabsDetach", NULL, N_("_Detach Terminal"), NULL,
-        NULL,
-        G_CALLBACK (tabs_detach_tab_callback) },
-
-      /* Help menu */
-      { "HelpContents", "help-browser", N_("_Contents"), "F1",
-        NULL,
-        G_CALLBACK (help_contents_callback) },
-      { "HelpAbout", "help-about", N_("_About"), NULL,
-        NULL,
-        G_CALLBACK (help_about_callback) },
-      { "HelpInspector", NULL, N_("_Inspector"), NULL,
-        NULL,
-        G_CALLBACK (help_inspector_callback) },
-
-      /* Popup menu */
-      { "PopupOpenHyperlink", NULL, N_("_Open Hyperlink"), NULL,
-        NULL,
-        G_CALLBACK (popup_open_hyperlink_callback) },
-      { "PopupCopyHyperlinkAddress", NULL, N_("_Copy Hyperlink Address"), NULL,
-        NULL,
-        G_CALLBACK (popup_copy_hyperlink_callback) },
-      { "PopupSendEmail", NULL, N_("_Send Mail To…"), NULL,
-        NULL,
-        G_CALLBACK (popup_open_url_callback) },
-      { "PopupCopyEmailAddress", NULL, N_("_Copy E-mail Address"), NULL,
-        NULL,
-        G_CALLBACK (popup_copy_url_callback) },
-      { "PopupCall", NULL, N_("C_all To…"), NULL,
-        NULL,
-        G_CALLBACK (popup_open_url_callback) },
-      { "PopupCopyCallAddress", NULL, N_("_Copy Call Address"), NULL,
-        NULL,
-        G_CALLBACK (popup_copy_url_callback) },
-      { "PopupOpenLink", NULL, N_("_Open Link"), NULL,
-        NULL,
-        G_CALLBACK (popup_open_url_callback) },
-      { "PopupCopyLinkAddress", NULL, N_("_Copy Link Address"), NULL,
-        NULL,
-        G_CALLBACK (popup_copy_url_callback) },
-      { "PopupNumberInfo", NULL, "", NULL,
-        NULL,
-        NULL },
-      { "PopupTerminalProfiles", NULL, N_("P_rofiles") },
-      { "PopupCopy", "edit-copy", N_("_Copy"), "",
-        NULL,
-        G_CALLBACK (edit_copy_callback) },
-      { "PopupCopyHTML", "edit-copy", N_("Copy as _HTML"), "",
-        NULL,
-        G_CALLBACK (edit_copy_html_callback) },
-      { "PopupPaste", "edit-paste", N_("_Paste"), "",
-        NULL,
-        G_CALLBACK (edit_paste_callback) },
-      { "PopupPasteURIPaths", "edit-paste", N_("Paste _Filenames"), "",
-        NULL,
-        G_CALLBACK (edit_paste_callback) },
-      { "PopupNewTerminal", NULL, N_("Open _Terminal"), NULL,
-        NULL,
-        G_CALLBACK (file_new_terminal_callback) },
-      { "PopupLeaveFullscreen", NULL, N_("L_eave Full Screen"), NULL,
-        NULL,
-        G_CALLBACK (popup_leave_fullscreen_callback) },
-    };
-  
-  const GtkToggleActionEntry toggle_menu_entries[] =
-    {
-      /* View Menu */
-      { "ViewMenubar", NULL, N_("Show _Menubar"), NULL,
-        NULL,
-        G_CALLBACK (view_menubar_toggled_callback),
-        FALSE },
-      { "ViewFullscreen", NULL, N_("_Full Screen"), NULL,
-        NULL,
-        G_CALLBACK (view_fullscreen_toggled_callback),
-        FALSE },
-      /* Terminal menu */
-      { "TerminalReadOnly", NULL, N_("Read-_Only"), NULL,
-        NULL,
-        G_CALLBACK (terminal_readonly_toggled_callback),
-        FALSE }
-    };
+    /* Shadow actions for keybinding comsumption, see comment in terminal-accels.c */
+    { "shadow",              action_shadow_activate_cb,  "s",    NULL, NULL },
+    { "shadow-mdi",          action_shadow_activate_cb,  "s",    NULL, NULL },
+
+    /* Actions with state */
+    { "active-tab",          action_active_tab_set_cb,   "i",  "@i 0",    action_active_tab_state_cb      },
+    { "encoding",            NULL /* changes state */,   "s",  "'UTF-8'", action_encoding_state_cb        },
+    { "fullscreen",          NULL /* toggles state */,   NULL, "false",   action_fullscreen_state_cb      },
+    { "menubar-visible",     NULL /* toggles state */,   NULL, "true",    action_menubar_visible_state_cb },
+    { "profile",             NULL /* changes state */,   "s",  "''",      action_profile_state_cb         },
+    { "read-only",           NULL /* toggles state */,   NULL, "false",   action_read_only_state_cb       },
+  };
   TerminalWindowPrivate *priv;
   TerminalApp *app;
-  TerminalSettingsList *profiles_list;
   GSettings *gtk_debug_settings;
-  GtkActionGroup *action_group;
-  GtkAction *action;
-  GtkUIManager *manager;
-  GError *error;
   GtkWindowGroup *window_group;
-  GtkAccelGroup *accel_group;
+  //  GtkAccelGroup *accel_group;
   uuid_t u;
   char uuidstr[37], role[64];
+  gboolean shell_shows_menubar;
+  GSimpleAction *action;
 
   app = terminal_app_get ();
 
@@ -2748,9 +2223,8 @@ terminal_window_init (TerminalWindow *window)
                           G_CALLBACK (mdi_screen_added_cb), window);
   g_signal_connect_after (priv->mdi_container, "screen-removed",
                           G_CALLBACK (mdi_screen_removed_cb), window);
-  g_signal_connect_data (priv->mdi_container, "screens-reordered",
-                         G_CALLBACK (terminal_window_update_tabs_menu_sensitivity),
-                         window, NULL, G_CONNECT_SWAPPED | G_CONNECT_AFTER);
+  g_signal_connect_after (priv->mdi_container, "screens-reordered",
+                          G_CALLBACK (mdi_screens_reordered_cb), window);
 
   g_signal_connect_swapped (priv->mdi_container, "notify::tab-pos",
                             G_CALLBACK (terminal_window_update_geometry), window);
@@ -2759,16 +2233,13 @@ terminal_window_init (TerminalWindow *window)
 
   /* FIXME hack hack! */
   if (GTK_IS_NOTEBOOK (priv->mdi_container)) {
-  g_signal_connect (priv->mdi_container, "button-press-event",
-                    G_CALLBACK (notebook_button_press_cb), window);    
-  g_signal_connect (priv->mdi_container, "popup-menu",
-                    G_CALLBACK (notebook_popup_menu_cb), window);
-  }
-
-  /* FIXME hack */
-  if (GTK_IS_NOTEBOOK (priv->mdi_container))
+    g_signal_connect (priv->mdi_container, "button-press-event",
+                      G_CALLBACK (notebook_button_press_cb), window);
+    g_signal_connect (priv->mdi_container, "popup-menu",
+                      G_CALLBACK (notebook_popup_menu_cb), window);
     g_signal_connect (priv->mdi_container, "create-window",
                       G_CALLBACK (handle_tab_droped_on_desktop), window);
+  }
 
   gtk_box_pack_end (GTK_BOX (priv->main_vbox), GTK_WIDGET (priv->mdi_container), TRUE, TRUE, 0);
   gtk_widget_show (GTK_WIDGET (priv->mdi_container));
@@ -2787,86 +2258,43 @@ terminal_window_init (TerminalWindow *window)
 
   /* GAction setup */
   g_action_map_add_action_entries (G_ACTION_MAP (window),
-                                   gaction_entries, G_N_ELEMENTS (gaction_entries),
+                                   action_entries, G_N_ELEMENTS (action_entries),
                                    window);
 
-  /* Create the UI manager */
-  manager = priv->ui_manager = gtk_ui_manager_new ();
-
-  accel_group = gtk_ui_manager_get_accel_group (manager);
-  gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
-  /* Workaround for bug #453193, bug #138609 and bug #559728 */
-  g_signal_connect_after (accel_group, "accel-activate",
-                          G_CALLBACK (terminal_window_accel_activate_cb), window);
-
-  /* Create the actions */
-  /* Note that this action group name is used in terminal-accels.c; do not change it */
-  priv->action_group = action_group = gtk_action_group_new ("Main");
-  gtk_action_group_set_translation_domain (action_group, NULL);
-  gtk_action_group_add_actions (action_group, menu_entries,
-                                G_N_ELEMENTS (menu_entries), window);
-  gtk_action_group_add_toggle_actions (action_group,
-                                       toggle_menu_entries,
-                                       G_N_ELEMENTS (toggle_menu_entries),
-                                       window);
-  gtk_ui_manager_insert_action_group (manager, action_group, 0);
-  g_object_unref (action_group);
-
-  priv->clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_CLIPBOARD);
-  update_edit_menu (priv->clipboard, NULL, window);
-  g_signal_connect (priv->clipboard, "owner-change",
-                    G_CALLBACK (update_edit_menu), window);
-
-  /* Idem for this action, since the window is not fullscreen. */
-  action = gtk_action_group_get_action (priv->action_group, "PopupLeaveFullscreen");
-  gtk_action_set_visible (action, FALSE);
-
-#ifndef ENABLE_SAVE
-  action = gtk_action_group_get_action (priv->action_group, "FileSaveContents");
-  gtk_action_set_visible (action, FALSE);
-#endif
-  
-  /* Load the UI */
-  error = NULL;
-  priv->ui_id = gtk_ui_manager_add_ui_from_resource (manager,
-                                                     TERMINAL_RESOURCES_PATH_PREFIX "/ui/terminal.xml",
-                                                     &error);
-  g_assert_no_error (error);
-
-  priv->menubar = gtk_ui_manager_get_widget (manager, "/menubar");
-  gtk_box_pack_start (GTK_BOX (priv->main_vbox),
-                     priv->menubar,
-                     FALSE, FALSE, 0);
-
+  g_simple_action_set_enabled (lookup_action (window, "leave-fullscreen"), FALSE);
+
+  /* Hide "menubar-visible" when the menubar is shown by the shell */
+  g_object_get (gtk_widget_get_settings (GTK_WIDGET (window)),
+                "gtk-shell-shows-menubar", &shell_shows_menubar,
+                NULL);
+  if (shell_shows_menubar) {
+    g_simple_action_set_enabled (lookup_action (window, "menubar-visible"), FALSE);
+  } else {
+    priv->menubar = gtk_menu_bar_new_from_model (terminal_app_get_menubar (app));
+    gtk_box_pack_start (GTK_BOX (priv->main_vbox),
+                        priv->menubar,
+                        FALSE, FALSE, 0);
+
+    terminal_window_set_menubar_visible (window, TRUE);
+    priv->use_default_menubar_visibility = TRUE;
+  }
 
   /* Maybe make Inspector available */
-  action = gtk_action_group_get_action (priv->action_group, "HelpInspector");
+  action = lookup_action (window, "inspector");
   gtk_debug_settings = terminal_app_get_gtk_debug_settings (app);
   if (gtk_debug_settings != NULL)
     g_settings_bind (gtk_debug_settings,
                      "enable-inspector-keybinding",
                      action,
-                     "visible",
+                     "enabled",
                      G_SETTINGS_BIND_GET | G_SETTINGS_BIND_NO_SENSITIVITY);
   else
-    gtk_action_set_visible (action, FALSE);
-
-  /* Add tabs menu */
-  priv->tabs_menu = terminal_tabs_menu_new (window);
+    g_simple_action_set_enabled (action, FALSE);
 
-  profiles_list = terminal_app_get_profiles_list (app);
-  terminal_window_profile_list_changed_cb (profiles_list, window);
-  g_signal_connect (profiles_list, "children-changed",
-                    G_CALLBACK (terminal_window_profile_list_changed_cb), window);
-  
-  terminal_window_encoding_list_changed_cb (app, window);
-  g_signal_connect (app, "encoding-list-changed",
-                    G_CALLBACK (terminal_window_encoding_list_changed_cb), window);
-
-  terminal_window_set_menubar_visible (window, TRUE);
-  priv->use_default_menubar_visibility = TRUE;
-
-  terminal_window_update_size_to_menu (window);
+  priv->clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_CLIPBOARD);
+  clipboard_targets_changed_cb (app, priv->clipboard, window);
+  g_signal_connect (app, "clipboard-targets-changed",
+                    G_CALLBACK (clipboard_targets_changed_cb), window);
 
   terminal_window_fill_notebook_action_box (window);
 
@@ -2938,20 +2366,16 @@ terminal_window_dispose (GObject *object)
 {
   TerminalWindow *window = TERMINAL_WINDOW (object);
   TerminalWindowPrivate *priv = window->priv;
-  TerminalApp *app;
-  TerminalSettingsList *profiles_list;
-  GSList *list, *l;
+  TerminalApp *app = terminal_app_get ();
 
   priv->disposed = TRUE;
 
-  /* Deactivate open popup menus. This fixes a crash if the window is closed
-   * while the context menu is open.
-   */
-  list = gtk_ui_manager_get_toplevels (priv->ui_manager, GTK_UI_MANAGER_POPUP);
-  for (l = list; l != NULL; l = l->next)
-    if (GTK_IS_MENU (l->data))
-      gtk_menu_popdown (GTK_MENU (l->data));
-  g_slist_free (list);
+  if (priv->clipboard != NULL) {
+    g_signal_handlers_disconnect_by_func (app,
+                                          G_CALLBACK (clipboard_targets_changed_cb),
+                                          window);
+    priv->clipboard = NULL;
+  }
 
   remove_popup_info (window);
 
@@ -2963,30 +2387,6 @@ terminal_window_dispose (GObject *object)
       priv->search_popover = NULL;
     }
 
-  if (priv->tabs_menu)
-    {
-      g_object_unref (priv->tabs_menu);
-      priv->tabs_menu = NULL;
-    }
-
-  if (priv->profiles_action_group != NULL)
-    disconnect_profiles_from_actions_in_group (priv->profiles_action_group);
-  if (priv->new_terminal_action_group != NULL)
-    disconnect_profiles_from_actions_in_group (priv->new_terminal_action_group);
-
-  app = terminal_app_get ();
-  profiles_list = terminal_app_get_profiles_list (app);
-  g_signal_handlers_disconnect_by_func (profiles_list,
-                                        G_CALLBACK (terminal_window_profile_list_changed_cb),
-                                        window);
-  g_signal_handlers_disconnect_by_func (app,
-                                        G_CALLBACK (terminal_window_encoding_list_changed_cb),
-                                        window);
-
-  g_signal_handlers_disconnect_by_func (priv->clipboard,
-                                        G_CALLBACK (update_edit_menu),
-                                        window);
-
   G_OBJECT_CLASS (terminal_window_parent_class)->dispose (object);
 }
 
@@ -2996,8 +2396,6 @@ terminal_window_finalize (GObject *object)
   TerminalWindow *window = TERMINAL_WINDOW (object);
   TerminalWindowPrivate *priv = window->priv;
 
-  g_object_unref (priv->ui_manager);
-
   if (priv->confirm_close_dialog)
     gtk_dialog_response (GTK_DIALOG (priv->confirm_close_dialog),
                          GTK_RESPONSE_DELETE_EVENT);
@@ -3030,7 +2428,7 @@ terminal_window_show (GtkWidget *widget)
                          widget_allocation.width, widget_allocation.height,
                          widget_allocation.x, widget_allocation.y);
 
-  /* Because of the unexpected reentrancy caused by notebook_page_added_callback()
+  /* Because of the unexpected reentrancy caused by adding the tab to the notebook
    * showing the TerminalWindow, we can get here when the first page has been
    * added but not yet set current. By setting the page current, we get the
    * right size when we first show the window */
@@ -3053,18 +2451,14 @@ terminal_window_new (GApplication *app)
 {
   return g_object_new (TERMINAL_TYPE_WINDOW,
                        "application", app,
-#ifdef ENABLE_DEBUG
-                       "show-menubar", _terminal_debug_on (TERMINAL_DEBUG_APPMENU),
-#else
                        "show-menubar", FALSE,
-#endif
                        NULL);
 }
 
 static void
-profile_set_callback (TerminalScreen *screen,
-                      GSettings *old_profile,
-                      TerminalWindow *window)
+profile_set_cb (TerminalScreen *screen,
+                GSettings *old_profile,
+                TerminalWindow *window)
 {
   TerminalWindowPrivate *priv = window->priv;
 
@@ -3084,12 +2478,12 @@ sync_screen_title (TerminalScreen *screen,
 {
   TerminalWindowPrivate *priv = window->priv;
   const char *title;
-  
+
   if (screen != priv->active_screen)
     return;
 
   title = terminal_screen_get_title (screen);
-  gtk_window_set_title (GTK_WINDOW (window), 
+  gtk_window_set_title (GTK_WINDOW (window),
                         title && title[0] ? title : _("Terminal"));
 }
 
@@ -3177,6 +2571,16 @@ screen_hyperlink_hover_uri_changed (TerminalScreen *screen,
   gtk_widget_set_tooltip_text (GTK_WIDGET (screen), label);
 }
 
+static void
+screen_encoding_changed_cb (TerminalScreen *screen,
+                            GParamSpec     *psepc,
+                            gpointer        user_data)
+{
+  TerminalWindow *window = user_data;
+
+  terminal_window_update_encoding_menu_active_encoding (window);
+}
+
 /* MDI container callbacks */
 
 static void
@@ -3267,21 +2671,18 @@ terminal_window_set_menubar_visible (TerminalWindow *window,
                                      gboolean        setting)
 {
   TerminalWindowPrivate *priv = window->priv;
-  GtkAction *action;
+
+  if (priv->menubar == NULL)
+    return;
 
   /* it's been set now, so don't override when adding a screen.
    * this side effect must happen before we short-circuit below.
    */
   priv->use_default_menubar_visibility = FALSE;
-  
-  if (setting == priv->menubar_visible)
-    return;
 
-  priv->menubar_visible = setting;
+  g_simple_action_set_state (lookup_action (window, "menubar-visible"),
+                             g_variant_new_boolean (setting));
 
-  action = gtk_action_group_get_action (priv->action_group, "ViewMenubar");
-  gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), setting);
-  
   g_object_set (priv->menubar, "visible", setting, NULL);
 
   /* FIXMEchpe: use gtk_widget_get_realized instead? */
@@ -3295,19 +2696,11 @@ terminal_window_set_menubar_visible (TerminalWindow *window,
     }
 }
 
-gboolean
-terminal_window_get_menubar_visible (TerminalWindow *window)
-{
-  TerminalWindowPrivate *priv = window->priv;
-  
-  return priv->menubar_visible;
-}
-
 GtkWidget *
 terminal_window_get_mdi_container (TerminalWindow *window)
 {
   TerminalWindowPrivate *priv = window->priv;
-       
+
   g_return_val_if_fail (TERMINAL_IS_WINDOW (window), NULL);
 
   return GTK_WIDGET (priv->mdi_container);
@@ -3372,20 +2765,48 @@ terminal_window_get_active (TerminalWindow *window)
   return terminal_mdi_container_get_active_screen (priv->mdi_container);
 }
 
+static void
+notebook_show_context_menu (TerminalWindow *window,
+                            GdkEvent *event,
+                            guint button,
+                            guint32 timestamp)
+{
+  TerminalWindowPrivate *priv = window->priv;
+  GtkNotebook *notebook = GTK_NOTEBOOK (priv->mdi_container);
+  int page_num;
+  GtkWidget *tab, *tab_label;
+
+  page_num = gtk_notebook_get_current_page (notebook);
+  tab = gtk_notebook_get_nth_page (notebook, page_num);
+  tab_label = gtk_notebook_get_tab_label (notebook, tab);
+
+  /* Load the UI */
+  gs_unref_object GMenu *menu;
+  terminal_util_load_objects_resource ("/org/gnome/terminal/ui/notebook-menu.ui",
+                                       "notebook-popup", &menu,
+                                       NULL);
+
+  GtkWidget *popup_menu = context_menu_new (G_MENU_MODEL (menu), GTK_WIDGET (window));
+
+  gtk_widget_set_halign (popup_menu, GTK_ALIGN_START);
+  gtk_menu_popup (GTK_MENU (popup_menu), NULL, NULL,
+                  position_menu_under_widget, tab_label,
+                  button, timestamp);
+
+  if (button == 0)
+    gtk_menu_shell_select_first (GTK_MENU_SHELL (popup_menu), FALSE);
+}
+
 static gboolean
 notebook_button_press_cb (GtkWidget *widget,
                           GdkEventButton *event,
                           TerminalWindow *window)
 {
-  TerminalWindowPrivate *priv = window->priv;
   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
-  GtkWidget *tab;
-  GtkWidget *menu;
-  GtkAction *action;
   int tab_clicked;
 
   if (event->type != GDK_BUTTON_PRESS ||
-      event->button != 3 ||
+      event->button != GDK_BUTTON_SECONDARY ||
       (event->state & gtk_accelerator_get_default_mod_mask ()) != 0)
     return FALSE;
 
@@ -3396,18 +2817,7 @@ notebook_button_press_cb (GtkWidget *widget,
   /* switch to the page the mouse is over */
   gtk_notebook_set_current_page (notebook, tab_clicked);
 
-  action = gtk_action_group_get_action (priv->action_group, "NotebookPopup");
-  gtk_action_activate (action);
-
-  menu = gtk_ui_manager_get_widget (priv->ui_manager, "/NotebookPopup");
-  if (gtk_menu_get_attach_widget (GTK_MENU (menu)))
-    gtk_menu_detach (GTK_MENU (menu));
-  tab = gtk_notebook_get_nth_page (notebook, tab_clicked);
-  gtk_menu_attach_to_widget (GTK_MENU (menu), tab, NULL);
-  gtk_menu_popup (GTK_MENU (menu), NULL, NULL, 
-                  NULL, NULL, 
-                  event->button, event->time);
-
+  notebook_show_context_menu (window, (GdkEvent*)event, event->button, event->time);
   return TRUE;
 }
 
@@ -3416,32 +2826,14 @@ notebook_popup_menu_cb (GtkWidget *widget,
                         TerminalWindow *window)
 {
   TerminalWindowPrivate *priv = window->priv;
-  GtkNotebook *notebook = GTK_NOTEBOOK (priv->mdi_container);
-  GtkWidget *focus_widget, *tab, *tab_label, *menu;
-  GtkAction *action;
-  int page_num;
+  GtkWidget *focus_widget;
 
   focus_widget = gtk_window_get_focus (GTK_WINDOW (window));
   /* Only respond if the notebook is the actual focus */
   if (focus_widget != GTK_WIDGET (priv->mdi_container))
     return FALSE;
 
-  page_num = gtk_notebook_get_current_page (notebook);
-  tab = gtk_notebook_get_nth_page (notebook, page_num);
-  tab_label = gtk_notebook_get_tab_label (notebook, tab);
-
-  action = gtk_action_group_get_action (priv->action_group, "NotebookPopup");
-  gtk_action_activate (action);
-
-  menu = gtk_ui_manager_get_widget (priv->ui_manager, "/NotebookPopup");
-  if (gtk_menu_get_attach_widget (GTK_MENU (menu)))
-    gtk_menu_detach (GTK_MENU (menu));
-  gtk_menu_attach_to_widget (GTK_MENU (menu), tab_label, NULL);
-  gtk_menu_popup (GTK_MENU (menu), NULL, NULL, 
-                  position_menu_under_widget, tab_label,
-                  0, gtk_get_current_event_time ());
-  gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE);
-
+  notebook_show_context_menu (window, NULL, 0, gtk_get_current_event_time ());
   return TRUE;
 }
 
@@ -3500,7 +2892,7 @@ mdi_screen_switched_cb (TerminalMdiContainer *container,
                          window);
   terminal_window_update_size (window);
 
-  terminal_window_update_tabs_menu_sensitivity (window);
+  terminal_window_update_tabs_actions_sensitivity (window);
   terminal_window_update_encoding_menu_active_encoding (window);
   terminal_window_update_terminal_menu (window);
   terminal_window_update_set_profile_menu_active_profile (window);
@@ -3523,7 +2915,7 @@ mdi_screen_added_cb (TerminalMdiContainer *container,
 
   g_signal_connect (G_OBJECT (screen),
                     "profile-set",
-                    G_CALLBACK (profile_set_callback),
+                    G_CALLBACK (profile_set_cb),
                     window);
 
   /* FIXME: only connect on the active screen, not all screens! */
@@ -3537,13 +2929,15 @@ mdi_screen_added_cb (TerminalMdiContainer *container,
                     G_CALLBACK (screen_font_any_changed_cb), window);
   g_signal_connect (screen, "notify::font-scale",
                     G_CALLBACK (screen_font_any_changed_cb), window);
+  g_signal_connect (screen, "notify::encoding",
+                    G_CALLBACK (screen_encoding_changed_cb), window);
   g_signal_connect (screen, "selection-changed",
                     G_CALLBACK (terminal_window_update_copy_sensitivity), window);
   g_signal_connect (screen, "hyperlink-hover-uri-changed",
                     G_CALLBACK (screen_hyperlink_hover_uri_changed), window);
 
   g_signal_connect (screen, "show-popup-menu",
-                    G_CALLBACK (screen_show_popup_menu_callback), window);
+                    G_CALLBACK (screen_show_popup_menu_cb), window);
   g_signal_connect (screen, "match-clicked",
                     G_CALLBACK (screen_match_clicked_cb), window);
   g_signal_connect (screen, "resize-window",
@@ -3552,7 +2946,7 @@ mdi_screen_added_cb (TerminalMdiContainer *container,
   g_signal_connect (screen, "close-screen",
                     G_CALLBACK (screen_close_cb), window);
 
-  terminal_window_update_tabs_menu_sensitivity (window);
+  terminal_window_update_tabs_actions_sensitivity (window);
   terminal_window_update_search_sensitivity (screen, window);
 
 #if 0
@@ -3601,7 +2995,7 @@ mdi_screen_removed_cb (TerminalMdiContainer *container,
                          window, screen);
 
   g_signal_handlers_disconnect_by_func (G_OBJECT (screen),
-                                        G_CALLBACK (profile_set_callback),
+                                        G_CALLBACK (profile_set_cb),
                                         window);
 
   g_signal_handlers_disconnect_by_func (G_OBJECT (screen),
@@ -3621,6 +3015,10 @@ mdi_screen_removed_cb (TerminalMdiContainer *container,
                                         window);
 
   g_signal_handlers_disconnect_by_func (G_OBJECT (screen),
+                                        G_CALLBACK (screen_encoding_changed_cb),
+                                        window);
+
+  g_signal_handlers_disconnect_by_func (G_OBJECT (screen),
                                         G_CALLBACK (terminal_window_update_copy_sensitivity),
                                         window);
 
@@ -3629,7 +3027,7 @@ mdi_screen_removed_cb (TerminalMdiContainer *container,
                                         window);
 
   g_signal_handlers_disconnect_by_func (screen,
-                                        G_CALLBACK (screen_show_popup_menu_callback),
+                                        G_CALLBACK (screen_show_popup_menu_cb),
                                         window);
 
   g_signal_handlers_disconnect_by_func (screen,
@@ -3658,7 +3056,7 @@ mdi_screen_removed_cb (TerminalMdiContainer *container,
       return;
     }
 
-  terminal_window_update_tabs_menu_sensitivity (window);
+  terminal_window_update_tabs_actions_sensitivity (window);
   terminal_window_update_search_sensitivity (screen, window);
 
   if (pages == 1)
@@ -3670,6 +3068,13 @@ mdi_screen_removed_cb (TerminalMdiContainer *container,
     }
 }
 
+static void
+mdi_screens_reordered_cb (TerminalMdiContainer *container,
+                          TerminalWindow  *window)
+{
+  terminal_window_update_tabs_actions_sensitivity (window);
+}
+
 gboolean
 terminal_window_parse_geometry (TerminalWindow *window,
                                const char     *geometry)
@@ -3809,9 +3214,6 @@ terminal_window_update_geometry (TerminalWindow *window)
       hints.base_width = chrome_width + csd_width;
       hints.base_height = chrome_height + csd_height;
 
-#define MIN_WIDTH_CHARS 4
-#define MIN_HEIGHT_CHARS 1
-      
       hints.width_inc = char_width;
       hints.height_inc = char_height;
 
@@ -3970,195 +3372,6 @@ confirm_close_window_or_tab (TerminalWindow *window,
   return TRUE;
 }
 
-static void
-file_close_window_callback (GtkAction *action,
-                            TerminalWindow *window)
-{
-  terminal_window_request_close (window);
-}
-
-static void
-file_close_tab_callback (GtkAction *action,
-                         TerminalWindow *window)
-{
-  TerminalWindowPrivate *priv = window->priv;
-  TerminalScreen *active_screen = priv->active_screen;
-  
-  if (!active_screen)
-    return;
-
-  if (confirm_close_window_or_tab (window, active_screen))
-    return;
-
-  terminal_window_remove_screen (window, active_screen);
-}
-
-static void
-edit_preferences_callback (GtkAction *action,
-                           TerminalWindow *window)
-{
-  terminal_app_edit_preferences (terminal_app_get (), GTK_WINDOW (window));
-}
-
-static void
-edit_current_profile_callback (GtkAction *action,
-                               TerminalWindow *window)
-{
-  TerminalWindowPrivate *priv = window->priv;
-  
-  terminal_app_edit_profile (terminal_app_get (),
-                             terminal_screen_get_profile (priv->active_screen),
-                             GTK_WINDOW (window),
-                             NULL);
-}
-
-static void
-file_new_profile_callback (GtkAction *action,
-                           TerminalWindow *window)
-{
-  TerminalWindowPrivate *priv = window->priv;
-  
-  terminal_app_new_profile (terminal_app_get (),
-                            terminal_screen_get_profile (priv->active_screen),
-                            GTK_WINDOW (window));
-}
-
-static void
-view_menubar_toggled_callback (GtkToggleAction *action,
-                               TerminalWindow *window)
-{
-  terminal_window_set_menubar_visible (window, gtk_toggle_action_get_active (action));
-}
-
-static void
-view_fullscreen_toggled_callback (GtkToggleAction *action,
-                                  TerminalWindow *window)
-{
-  g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (window)));
-
-  if (gtk_toggle_action_get_active (action))
-    gtk_window_fullscreen (GTK_WINDOW (window));
-  else
-    gtk_window_unfullscreen (GTK_WINDOW (window));
-}
-
-static void
-terminal_add_encoding_callback (GtkAction *action,
-                                TerminalWindow *window)
-{
-  terminal_app_edit_encodings (terminal_app_get (),
-                               GTK_WINDOW (window));
-}
-
-static void
-terminal_reset_callback (GtkAction *action,
-                         TerminalWindow *window)
-{
-  TerminalWindowPrivate *priv = window->priv;
-
-  if (priv->active_screen == NULL)
-    return;
-      
-  vte_terminal_reset (VTE_TERMINAL (priv->active_screen), TRUE, FALSE);
-}
-
-static void
-terminal_reset_clear_callback (GtkAction *action,
-                               TerminalWindow *window)
-{
-  TerminalWindowPrivate *priv = window->priv;
-
-  if (priv->active_screen == NULL)
-    return;
-      
-  vte_terminal_reset (VTE_TERMINAL (priv->active_screen), TRUE, TRUE);
-}
-
-static void
-terminal_readonly_toggled_callback (GtkToggleAction *action,
-                                    TerminalWindow *window)
-{
-  TerminalWindowPrivate *priv = window->priv;
-
-  if (priv->active_screen == NULL)
-    return;
-
-  vte_terminal_set_input_enabled(VTE_TERMINAL(priv->active_screen),
-                                 !gtk_toggle_action_get_active (action));
-}
-
-static void
-tabs_next_or_previous_tab_cb (GtkAction *action,
-                              TerminalWindow *window)
-{
-  TerminalWindowPrivate *priv = window->priv;
-  const char *name;
-  guint keyval = 0;
-
-  name = gtk_action_get_name (action);
-  if (strcmp (name, "TabsNext") == 0) {
-    keyval = GDK_KEY_Page_Down;
-  } else if (strcmp (name, "TabsPrevious") == 0) {
-    keyval = GDK_KEY_Page_Up;
-  }
-
-  /* FIXMEchpe this is GtkNotebook specific */
-  gtk_bindings_activate (G_OBJECT (priv->mdi_container),
-                         keyval,
-                         GDK_CONTROL_MASK);
-}
-
-static void
-tabs_move_left_callback (GtkAction *action,
-                         TerminalWindow *window)
-{
-  TerminalWindowPrivate *priv = window->priv;
-
-  terminal_mdi_container_reorder_screen (priv->mdi_container,
-                                         terminal_mdi_container_get_active_screen (priv->mdi_container),
-                                         -1);
-}
-
-static void
-tabs_move_right_callback (GtkAction *action,
-                          TerminalWindow *window)
-{
-  TerminalWindowPrivate *priv = window->priv;
-
-  terminal_mdi_container_reorder_screen (priv->mdi_container,
-                                         terminal_mdi_container_get_active_screen (priv->mdi_container),
-                                         +1);
-}
-
-static void
-help_contents_callback (GtkAction *action,
-                        TerminalWindow *window)
-{
-  terminal_util_show_help (NULL, GTK_WINDOW (window));
-}
-
-static void
-help_about_callback (GtkAction *action,
-                     TerminalWindow *window)
-{
-  terminal_util_show_about (NULL);
-}
-
-static void
-help_inspector_callback (GtkAction *action,
-                         TerminalWindow *window)
-{
-  gtk_window_set_interactive_debugging (TRUE);
-}
-
-GtkUIManager *
-terminal_window_get_ui_manager (TerminalWindow *window)
-{
-  TerminalWindowPrivate *priv = window->priv;
-
-  return priv->ui_manager;
-}
-
 void
 terminal_window_request_close (TerminalWindow *window)
 {
@@ -4170,14 +3383,6 @@ terminal_window_request_close (TerminalWindow *window)
   gtk_widget_destroy (GTK_WIDGET (window));
 }
 
-GtkActionGroup *
-terminal_window_get_main_action_group (TerminalWindow *window)
-{
-  TerminalWindowPrivate *priv = window->priv;
-
-  return priv->action_group;
-}
-
 const char *
 terminal_window_get_uuid (TerminalWindow *window)
 {
diff --git a/src/terminal-window.h b/src/terminal-window.h
index f090835..a76469a 100644
--- a/src/terminal-window.h
+++ b/src/terminal-window.h
@@ -70,7 +70,6 @@ void terminal_window_move_screen (TerminalWindow *source_window,
  */
 void terminal_window_set_menubar_visible     (TerminalWindow *window,
                                               gboolean        setting);
-gboolean terminal_window_get_menubar_visible (TerminalWindow *window);
 
 void terminal_window_update_size (TerminalWindow *window);
 
@@ -89,8 +88,6 @@ GtkWidget* terminal_window_get_mdi_container (TerminalWindow *window);
 
 void terminal_window_request_close (TerminalWindow *window);
 
-GtkActionGroup *terminal_window_get_main_action_group (TerminalWindow *window);
-
 const char *terminal_window_get_uuid (TerminalWindow *window);
 
 G_END_DECLS
diff --git a/src/terminal.c b/src/terminal.c
index 149c480..b3ebe9c 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -20,7 +20,6 @@
  */
 
 #include "config.h"
-#define _GNU_SOURCE
 
 #include <errno.h>
 #include <locale.h>
diff --git a/src/terminal.gresource.xml b/src/terminal.gresource.xml
index 9638b5b..411c570 100644
--- a/src/terminal.gresource.xml
+++ b/src/terminal.gresource.xml
@@ -17,13 +17,14 @@
 -->
 <gresources>
   <gresource prefix="/org/gnome/terminal">
-    <file alias="ui/terminal.xml" compressed="true" preprocess="xml-stripblanks">terminal.xml</file>
-    <file alias="ui/terminal.about" compressed="true">terminal.about</file>
-    <file alias="ui/search-popover.ui" compressed="true" 
preprocess="xml-stripblanks">search-popover.ui</file>
+    <file alias="css/terminal.css" compressed="true">terminal.common.css</file>
+    <file alias="gtk/menus.ui" compressed="true" preprocess="xml-stripblanks">terminal-appmenu.ui</file>
+    <file alias="ui/menubar.ui" compressed="true" preprocess="xml-stripblanks">terminal-menubar.ui</file>
+    <file alias="ui/notebook-menu.ui" compressed="true" 
preprocess="xml-stripblanks">terminal-notebook-menu.ui</file>
     <file alias="ui/preferences.ui" compressed="true" preprocess="xml-stripblanks">preferences.ui</file>
     <file alias="ui/profile-preferences.ui" compressed="true" 
preprocess="xml-stripblanks">profile-preferences.ui</file>
+    <file alias="ui/search-popover.ui" compressed="true" 
preprocess="xml-stripblanks">search-popover.ui</file>
+    <file alias="ui/terminal.about" compressed="true">terminal.about</file>
     <file alias="ui/window.ui" compressed="true" preprocess="xml-stripblanks">terminal-window.ui</file>
-    <file alias="gtk/menus.ui" compressed="true" preprocess="xml-stripblanks">terminal-menus.ui</file>
-    <file alias="css/terminal.css" compressed="true">terminal.common.css</file>
   </gresource>
 </gresources>


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