[virt-tools-list] [PATCH 3/5] window: Replace menu bar with headerbar

Fabiano Fidêncio fidencio at redhat.com
Sat Dec 17 16:50:10 UTC 2016


From: Sagar Ghuge <ghugesss at gmail.com>

In order to give a modern look to {virt,remote}-viewer let's replace the
old menu bar with the headerbar.

In the headerbar we will have:
- fullscreen button
- send-keys button:
  - when clicked a menu is opened with the same keys to send that were
    present in the old version
- displays button:
  - when clicked a menu is opened with the same options to
  enable/disable displays as present in the old version
- change-cd button:
  This button, as the old one, is only shown when remote-viewer is built
  with oVirt support and there's a list of ISOs set up in the oVirt
  server.
  The reason we chose to show it as a button instead of as a gear's menu
  item is because we can't hide the option from the gear's menu, while
  we can do it from the header bar. We could play with its sensitive
  but, IMO, it would be way worse than presenting it as a headerbar
  button.
- gear button:
  - when clicked a menu is opened with the follow options:
    - Screenshot
    - USB device selection
    - Zoom In/Zoom Out/Normal Size
    - Guest Details

Related:
- rhbz#921218
- rhbz#921326
- rhbz#1337575

Signed-off-by: Sagar Ghuge <ghugesss at gmail.com>
Signed-off-by: Fabiano Fidêncio <fabiano at fidencio.org>
---
 src/remote-viewer.c             |   8 +-
 src/resources/ui/virt-viewer.ui | 409 +++++++++----------
 src/virt-viewer-app.c           | 171 ++++----
 src/virt-viewer-display-spice.c |  14 +-
 src/virt-viewer-display-vnc.c   |  14 +-
 src/virt-viewer-file.c          |  26 +-
 src/virt-viewer-window.c        | 866 +++++++++++++++++++++++-----------------
 src/virt-viewer-window.h        |   3 +-
 8 files changed, 843 insertions(+), 668 deletions(-)

diff --git a/src/remote-viewer.c b/src/remote-viewer.c
index e0cd139..2313d73 100644
--- a/src/remote-viewer.c
+++ b/src/remote-viewer.c
@@ -773,9 +773,11 @@ ovirt_foreign_menu_update(GtkApplication *gtkapp, GtkWindow *gtkwin, G_GNUC_UNUS
 {
     RemoteViewer *self = REMOTE_VIEWER(gtkapp);
     VirtViewerWindow *win = g_object_get_data(G_OBJECT(gtkwin), "virt-viewer-window");
-    GtkBuilder *builder = virt_viewer_window_get_builder(win);
-    GtkWidget *menu = GTK_WIDGET(gtk_builder_get_object(builder, "menu-change-cd"));
-    gtk_widget_set_visible(menu, self->priv->ovirt_foreign_menu != NULL);
+    GtkButton *button = virt_viewer_window_get_button_change_cd(win);
+    gboolean has_ovirt_foreign_menu = self->priv->ovirt_foreign_menu != NULL;
+
+    gtk_widget_set_sensitive(GTK_WIDGET(button), has_ovirt_foreign_menu);
+    gtk_widget_set_visible(GTK_WIDGET(button), has_ovirt_foreign_menu);
 }
 
 static void
diff --git a/src/resources/ui/virt-viewer.ui b/src/resources/ui/virt-viewer.ui
index 800bc0f..42cd849 100644
--- a/src/resources/ui/virt-viewer.ui
+++ b/src/resources/ui/virt-viewer.ui
@@ -2,12 +2,210 @@
 <!-- Generated with glade 3.20.0 -->
 <interface>
   <requires lib="gtk+" version="3.0"/>
+  <!-- interface-requires gtk+ 2.6 -->
+  <menu id="gears-menu">
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">_Screenshot</attribute>
+        <attribute name="action">win.screenshot</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_USB device selection</attribute>
+        <attribute name="action">win.usb-device-selection</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">Zoom _Out</attribute>
+        <attribute name="action">win.zoom-out</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Normal Size</attribute>
+        <attribute name="action">win.zoom-reset</attribute>
+      </item>
+    </section>
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">_Guest Details</attribute>
+        <attribute name="action">win.guest-details</attribute>
+      </item>
+    </section>
+  </menu>
+  <menu id="send-keys-menu">
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">Ctrl + Alt + _Del</attribute>
+        <attribute name="action">win.ctrl+alt+del</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Ctrl + Alt + _Backspace</attribute>
+        <attribute name="action">win.ctrl+alt+backspace</attribute>
+      </item>
+    </section>
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">Ctrl + Alt + F_1</attribute>
+        <attribute name="action">win.ctrl+alt+f1</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Ctrl + Alt + F_2</attribute>
+        <attribute name="action">win.ctrl+alt+f2</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Ctrl + Alt + F_3</attribute>
+        <attribute name="action">win.ctrl+alt+f3</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Ctrl + Alt + F_4</attribute>
+        <attribute name="action">win.ctrl+alt+f4</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Ctrl + Alt + F_5</attribute>
+        <attribute name="action">win.ctrl+alt+f5</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Ctrl + Alt + F_6</attribute>
+        <attribute name="action">win.ctrl+alt+f6</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Ctrl + Alt + F_7</attribute>
+        <attribute name="action">win.ctrl+alt+f7</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Ctrl + Alt + F_8</attribute>
+        <attribute name="action">win.ctrl+alt+f8</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Ctrl + Alt + F_9</attribute>
+        <attribute name="action">win.ctrl+alt+f9</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Ctrl + Alt + F_10</attribute>
+        <attribute name="action">win.ctrl+alt+f10</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Ctrl + Alt + F_11</attribute>
+        <attribute name="action">win.ctrl+alt+f11</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Ctrl + Alt + F_12</attribute>
+        <attribute name="action">win.ctrl+alt+f12</attribute>
+      </item>
+    </section>
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">_PrintScreen</attribute>
+        <attribute name="action">win.printscreen</attribute>
+      </item>
+    </section>
+  </menu>
   <object class="GtkAccelGroup" id="accelgroup"/>
   <object class="GtkApplicationWindow" id="viewer">
     <property name="can_focus">False</property>
     <property name="default_width">1024</property>
     <property name="default_height">768</property>
     <signal name="delete-event" handler="virt_viewer_window_delete" swapped="no"/>
+    <child type="titlebar">
+      <object class="GtkHeaderBar" id="header">
+        <property name="visible">True</property>
+        <property name="show-close-button">True</property>
+        <child>
+          <object class="GtkMenuButton" id="gears">
+            <property name="visible">True</property>
+            <property name="direction">none</property>
+            <property name="use-popover">True</property>
+            <style>
+              <class name="image-button"/>
+            </style>
+          </object>
+          <packing>
+            <property name="pack-type">end</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButton" id="change-cd">
+            <property name="visible">False</property>
+            <property name="tooltip-text">_Change CD</property>
+            <style>
+              <class name="image-button"/>
+            </style>
+            <child>
+              <object class="GtkImage" id="change-cd-icon">
+                <property name="visible">True</property>
+                <property name="icon-name">media-optical-symbolic</property>
+                <property name="icon-size">1</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="pack-type">end</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkMenuButton" id="displays">
+            <property name="visible">True</property>
+            <property name="use-popover">True</property>
+            <property name="tooltip-text">Select display</property>
+            <style>
+              <class name="image-button"/>
+            </style>
+            <child>
+              <object class="GtkImage" id="displays-icon">
+                <property name="visible">True</property>
+                <property name="icon-name">video-display-symbolic</property>
+                <property name="icon-size">1</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="pack-type">end</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkMenuButton" id="send-keys">
+            <property name="visible">True</property>
+            <property name="use-popover">True</property>
+            <property name="tooltip-text">Send key combination</property>
+            <style>
+              <class name="image-button"/>
+            </style>
+            <child>
+              <object class="GtkImage" id="send-keys-icon">
+                <property name="visible">True</property>
+                <property name="icon-name">input-keyboard-symbolic</property>
+                <property name="icon-size">1</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="pack-type">end</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButton" id="fullscreen">
+            <property name="visible">True</property>
+            <property name="tooltip-text">Fullscreen</property>
+            <style>
+              <class name="image-button"/>
+            </style>
+            <child>
+              <object class="GtkImage" id="fullscreen-icon">
+                <property name="visible">True</property>
+                <property name="icon-name">view-fullscreen-symbolic</property>
+                <property name="icon-size">1</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="pack-type">end</property>
+          </packing>
+        </child>
+      </object>
+    </child>
     <child>
       <object class="GtkOverlay" id="viewer-overlay">
         <property name="visible">True</property>
@@ -16,217 +214,6 @@
           <object class="GtkVBox" id="viewer-box">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <child>
-              <object class="GtkMenuBar" id="top-menu">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <child>
-                  <object class="GtkMenuItem" id="menu-file">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="use_action_appearance">False</property>
-                    <property name="label" translatable="yes">_File</property>
-                    <property name="use_underline">True</property>
-                    <child type="submenu">
-                      <object class="GtkMenu" id="menu1">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="accel_group">accelgroup</property>
-                        <child>
-                          <object class="GtkMenuItem" id="menu-file-screenshot">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="use_action_appearance">False</property>
-                            <property name="label" translatable="yes">_Screenshot</property>
-                            <property name="use_underline">True</property>
-                            <signal name="activate" handler="virt_viewer_window_menu_file_screenshot" swapped="no"/>
-                          </object>
-                        </child>
-                        <child>
-                          <object class="GtkMenuItem" id="menu-file-usb-device-selection">
-                            <property name="visible">True</property>
-                            <property name="sensitive">False</property>
-                            <property name="can_focus">False</property>
-                            <property name="use_action_appearance">False</property>
-                            <property name="label" translatable="yes">_USB device selection</property>
-                            <property name="use_underline">True</property>
-                            <signal name="activate" handler="virt_viewer_window_menu_file_usb_device_selection" swapped="no"/>
-                          </object>
-                        </child>
-                        <child>
-                          <object class="GtkMenuItem" id="menu-file-smartcard-insert">
-                            <property name="can_focus">False</property>
-                            <property name="use_action_appearance">False</property>
-                            <property name="accel_path"><virt-viewer>/file/smartcard-insert</property>
-                            <property name="label" translatable="yes">Smartcard insertion</property>
-                            <property name="use_underline">True</property>
-                            <signal name="activate" handler="virt_viewer_window_menu_file_smartcard_insert" swapped="no"/>
-                          </object>
-                        </child>
-                        <child>
-                          <object class="GtkMenuItem" id="menu-file-smartcard-remove">
-                            <property name="can_focus">False</property>
-                            <property name="use_action_appearance">False</property>
-                            <property name="accel_path"><virt-viewer>/file/smartcard-remove</property>
-                            <property name="label" translatable="yes">Smartcard removal</property>
-                            <property name="use_underline">True</property>
-                            <signal name="activate" handler="virt_viewer_window_menu_file_smartcard_remove" swapped="no"/>
-                          </object>
-                        </child>
-                        <child>
-                          <object class="GtkMenuItem" id="menu-change-cd">
-                            <property name="can_focus">False</property>
-                            <property name="label" translatable="yes">_Change CD</property>
-                            <property name="use_underline">True</property>
-                            <signal name="activate" handler="virt_viewer_window_menu_change_cd_activate" swapped="no"/>
-                          </object>
-                        </child>
-                      </object>
-                    </child>
-                  </object>
-                </child>
-                <child>
-                  <object class="GtkMenuItem" id="menu-view">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="use_action_appearance">False</property>
-                    <property name="label" translatable="yes">_View</property>
-                    <property name="use_underline">True</property>
-                    <child type="submenu">
-                      <object class="GtkMenu" id="menu2">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="accel_group">accelgroup</property>
-                        <child>
-                          <object class="GtkCheckMenuItem" id="menu-view-fullscreen">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="use_action_appearance">False</property>
-                            <property name="accel_path"><virt-viewer>/view/toggle-fullscreen</property>
-                            <property name="label" translatable="yes">_Full screen</property>
-                            <property name="use_underline">True</property>
-                            <signal name="toggled" handler="virt_viewer_window_menu_view_fullscreen" swapped="no"/>
-                          </object>
-                        </child>
-                        <child>
-                          <object class="GtkMenuItem" id="menu-view-zoom">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="use_action_appearance">False</property>
-                            <property name="label" translatable="yes">_Zoom</property>
-                            <property name="use_underline">True</property>
-                            <child type="submenu">
-                              <object class="GtkMenu" id="menu4">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="accel_group">accelgroup</property>
-                                <child>
-                                  <object class="GtkMenuItem" id="menu-view-zoom-in">
-                                    <property name="accel_path"><virt-viewer>/view/zoom-in</property>
-                                    <property name="label" translatable="yes">Zoom _In</property>
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">False</property>
-                                    <property name="use_action_appearance">False</property>
-                                    <property name="use_underline">True</property>
-                                    <signal name="activate" handler="virt_viewer_window_menu_view_zoom_in" swapped="no"/>
-                                  </object>
-                                </child>
-                                <child>
-                                  <object class="GtkMenuItem" id="menu-view-zoom-out">
-                                    <property name="accel_path"><virt-viewer>/view/zoom-out</property>
-                                    <property name="label" translatable="yes">Zoom _Out</property>
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">False</property>
-                                    <property name="use_action_appearance">False</property>
-                                    <property name="use_underline">True</property>
-                                    <signal name="activate" handler="virt_viewer_window_menu_view_zoom_out" swapped="no"/>
-                                  </object>
-                                </child>
-                                <child>
-                                  <object class="GtkSeparatorMenuItem" id="separatormenuitem4">
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">False</property>
-                                  </object>
-                                </child>
-                                <child>
-                                  <object class="GtkMenuItem" id="menu-view-zoom-reset">
-                                    <property name="accel_path"><virt-viewer>/view/zoom-reset</property>
-                                    <property name="label" translatable="yes">_Normal Size</property>
-                                    <property name="visible">True</property>
-                                    <property name="can_focus">False</property>
-                                    <property name="use_action_appearance">False</property>
-                                    <property name="use_underline">True</property>
-                                    <signal name="activate" handler="virt_viewer_window_menu_view_zoom_reset" swapped="no"/>
-                                  </object>
-                                </child>
-                              </object>
-                            </child>
-                          </object>
-                        </child>
-                        <child>
-                          <object class="GtkMenuItem" id="menu-displays">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="use_action_appearance">False</property>
-                            <property name="label" translatable="yes">_Displays</property>
-                            <property name="use_underline">True</property>
-                          </object>
-                        </child>
-                        <child>
-                          <object class="GtkMenuItem" id="menu-view-release-cursor">
-                            <property name="can_focus">False</property>
-                            <property name="use_action_appearance">False</property>
-                            <property name="accel_path"><virt-viewer>/view/release-cursor</property>
-                            <property name="label" translatable="yes">Release cursor</property>
-                            <property name="use_underline">True</property>
-                            <signal name="activate" handler="virt_viewer_window_menu_view_release_cursor" swapped="no"/>
-                          </object>
-                        </child>
-                      </object>
-                    </child>
-                  </object>
-                </child>
-                <child>
-                  <object class="GtkMenuItem" id="menu-send">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="use_action_appearance">False</property>
-                    <property name="label" translatable="yes">_Send key</property>
-                    <property name="use_underline">True</property>
-                  </object>
-                </child>
-                <child>
-                  <object class="GtkMenuItem" id="menu-help">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="use_action_appearance">False</property>
-                    <property name="label" translatable="yes">_Help</property>
-                    <property name="use_underline">True</property>
-                    <child type="submenu">
-                      <object class="GtkMenu" id="menu3">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <child>
-                          <object class="GtkMenuItem" id="menu-help-guest-details">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="use_action_appearance">False</property>
-                            <property name="label" translatable="yes">_Guest Details</property>
-                            <property name="use_underline">True</property>
-                            <signal name="activate" handler="virt_viewer_window_menu_help_guest_details" swapped="no"/>
-                          </object>
-                        </child>
-                      </object>
-                    </child>
-                  </object>
-                </child>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
           </object>
           <packing>
             <property name="index">-1</property>
diff --git a/src/virt-viewer-app.c b/src/virt-viewer-app.c
index dd1f3df..580bef0 100644
--- a/src/virt-viewer-app.c
+++ b/src/virt-viewer-app.c
@@ -1761,6 +1761,8 @@ static void
 virt_viewer_update_smartcard_accels(VirtViewerApp *self)
 {
     gboolean sw_smartcard;
+    gchar *insert_accel;
+    gchar *remove_accel;
     VirtViewerAppPrivate *priv = self->priv;
 
     if (self->priv->session != NULL) {
@@ -1772,18 +1774,21 @@ virt_viewer_update_smartcard_accels(VirtViewerApp *self)
     }
     if (sw_smartcard) {
         g_debug("enabling smartcard shortcuts");
-        gtk_accel_map_change_entry("<virt-viewer>/file/smartcard-insert",
-                                   priv->insert_smartcard_accel_key,
-                                   priv->insert_smartcard_accel_mods,
-                                   TRUE);
-        gtk_accel_map_change_entry("<virt-viewer>/file/smartcard-remove",
-                                   priv->remove_smartcard_accel_key,
-                                   priv->remove_smartcard_accel_mods,
-                                   TRUE);
+        insert_accel = gtk_accelerator_get_label(priv->insert_smartcard_accel_key,
+                                                 priv->insert_smartcard_accel_mods);
+        remove_accel = gtk_accelerator_get_label(priv->remove_smartcard_accel_key,
+                                                 priv->remove_smartcard_accel_mods);
+
+        const gchar *insert_accels[] = { insert_accel, NULL };
+        const gchar *remove_accels[] = { remove_accel, NULL };
+
+        gtk_application_set_accels_for_action(GTK_APPLICATION(self), "win.smartcard-insert", insert_accels);
+        gtk_application_set_accels_for_action(GTK_APPLICATION(self), "win.smartcard-remove", remove_accels);
     } else {
         g_debug("disabling smartcard shortcuts");
-        gtk_accel_map_change_entry("<virt-viewer>/file/smartcard-insert", 0, 0, TRUE);
-        gtk_accel_map_change_entry("<virt-viewer>/file/smartcard-remove", 0, 0, TRUE);
+        const gchar *accels[] = { NULL };
+        gtk_application_set_accels_for_action(GTK_APPLICATION(self), "win.smartcard-insert", accels);
+        gtk_application_set_accels_for_action(GTK_APPLICATION(self), "win.smartcard-remove", accels);
     }
 }
 
@@ -1858,9 +1863,30 @@ static GActionEntry app_entries[] =
     {"quit", quit_activated, NULL, NULL, NULL, {0,0,0} }
 };
 
+#define MAX_KEY_COMBO 3
+struct keyComboDef {
+    const char *action_name;
+    const char *keys[MAX_KEY_COMBO];
+};
+
+static const struct keyComboDef accel_keyCombos[] = {
+    { "win.fullscreen", {"F11", NULL, NULL} },
+    { "win.zoom-in", {"<Ctrl>plus", "<Ctrl>KP_Add", NULL} },
+    { "win.zoom-out", {"<Ctrl>minus", "<Ctrl>KP_Subtract", NULL} },
+    { "win.zoom-reset", {"<Ctrl>0", "<Ctrl>KP_0", NULL} }
+};
+
+static const struct keyComboDef enable_accel_keyCombos[] = {
+    { "win.release-cursor", {"<Shift>F12", NULL, NULL} },
+    { "win.smartcard-insert", {"<Shift>F8", NULL, NULL} },
+    { "win.smartcard-remove", {"<Shift>F9", NULL, NULL} },
+    { "win.secure-attention", {"<Ctrl><Alt>End", NULL, NULL} }
+};
+
 static void
 virt_viewer_app_on_application_startup(GApplication *app)
 {
+    gint i;
     VirtViewerApp *self = VIRT_VIEWER_APP(app);
     GError *error = NULL;
 
@@ -1872,6 +1898,11 @@ virt_viewer_app_on_application_startup(GApplication *app)
                                     app_entries, G_N_ELEMENTS(app_entries),
                                     app);
 
+    for (i = 0 ; i < G_N_ELEMENTS(accel_keyCombos); i++) {
+        gtk_application_set_accels_for_action(GTK_APPLICATION(app),
+                                              accel_keyCombos[i].action_name, accel_keyCombos[i].keys);
+    }
+
     self->priv->resource = virt_viewer_get_resource();
 
     virt_viewer_app_set_debug(opt_debug);
@@ -1892,16 +1923,12 @@ virt_viewer_app_on_application_startup(GApplication *app)
         opt_zoom = NORMAL_ZOOM_LEVEL;
     }
 
-    virt_viewer_window_set_zoom_level(self->priv->main_window, opt_zoom);
+    for (i = 0 ; i < G_N_ELEMENTS(enable_accel_keyCombos); i++) {
+        gtk_application_set_accels_for_action(GTK_APPLICATION(app),
+                                              enable_accel_keyCombos[i].action_name, enable_accel_keyCombos[i].keys);
+    }
 
-    virt_viewer_set_insert_smartcard_accel(self, GDK_KEY_F8, GDK_SHIFT_MASK);
-    virt_viewer_set_remove_smartcard_accel(self, GDK_KEY_F9, GDK_SHIFT_MASK);
-    gtk_accel_map_add_entry("<virt-viewer>/view/toggle-fullscreen", GDK_KEY_F11, 0);
-    gtk_accel_map_add_entry("<virt-viewer>/view/release-cursor", GDK_KEY_F12, GDK_SHIFT_MASK);
-    gtk_accel_map_add_entry("<virt-viewer>/view/zoom-reset", GDK_KEY_0, GDK_CONTROL_MASK);
-    gtk_accel_map_add_entry("<virt-viewer>/view/zoom-out", GDK_KEY_minus, GDK_CONTROL_MASK);
-    gtk_accel_map_add_entry("<virt-viewer>/view/zoom-in", GDK_KEY_plus, GDK_CONTROL_MASK);
-    gtk_accel_map_add_entry("<virt-viewer>/send/secure-attention", GDK_KEY_End, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+    virt_viewer_window_set_zoom_level(self->priv->main_window, opt_zoom);
 
     if (!virt_viewer_app_start(self, &error)) {
         if (error && !g_error_matches(error, VIRT_VIEWER_ERROR, VIRT_VIEWER_ERROR_CANCELLED))
@@ -2111,13 +2138,17 @@ gboolean virt_viewer_app_get_direct(VirtViewerApp *self)
 void
 virt_viewer_app_clear_hotkeys(VirtViewerApp *self)
 {
+    gint i;
+    const gchar *accels[] = { NULL };
     /* Disable default bindings and replace them with our own */
-    gtk_accel_map_change_entry("<virt-viewer>/view/toggle-fullscreen", 0, 0, TRUE);
-    gtk_accel_map_change_entry("<virt-viewer>/view/release-cursor", 0, 0, TRUE);
-    gtk_accel_map_change_entry("<virt-viewer>/view/zoom-reset", 0, 0, TRUE);
-    gtk_accel_map_change_entry("<virt-viewer>/view/zoom-in", 0, 0, TRUE);
-    gtk_accel_map_change_entry("<virt-viewer>/view/zoom-out", 0, 0, TRUE);
-    gtk_accel_map_change_entry("<virt-viewer>/send/secure-attention", 0, 0, TRUE);
+    for (i = 0 ; i < G_N_ELEMENTS(accel_keyCombos); i++) {
+        gtk_application_set_accels_for_action(GTK_APPLICATION(self), accel_keyCombos[i].action_name, accels);
+    }
+
+    for (i = 0 ; i < G_N_ELEMENTS(enable_accel_keyCombos); i++) {
+        gtk_application_set_accels_for_action(GTK_APPLICATION(self), enable_accel_keyCombos[i].action_name, accels);
+    }
+
     virt_viewer_set_insert_smartcard_accel(self, 0, 0);
     virt_viewer_set_remove_smartcard_accel(self, 0, 0);
 }
@@ -2159,7 +2190,8 @@ virt_viewer_app_set_hotkeys(VirtViewerApp *self, const gchar *hotkeys_str)
         guint accel_key;
         GdkModifierType accel_mods;
         gtk_accelerator_parse(accel, &accel_key, &accel_mods);
-        g_free(accel);
+
+        const gchar *accels[] = { accel, NULL };
 
         if (accel_key == 0 && accel_mods == 0) {
             g_warning("Invalid value '%s' for key '%s'", value, *hotkey);
@@ -2167,11 +2199,11 @@ virt_viewer_app_set_hotkeys(VirtViewerApp *self, const gchar *hotkeys_str)
         }
 
         if (g_str_equal(*hotkey, "toggle-fullscreen")) {
-            gtk_accel_map_change_entry("<virt-viewer>/view/toggle-fullscreen", accel_key, accel_mods, TRUE);
+            gtk_application_set_accels_for_action(GTK_APPLICATION(self), "win.fullscreen", accels);
         } else if (g_str_equal(*hotkey, "release-cursor")) {
-            gtk_accel_map_change_entry("<virt-viewer>/view/release-cursor", accel_key, accel_mods, TRUE);
+            gtk_application_set_accels_for_action(GTK_APPLICATION(self), "win.release-cursor", accels);
         } else if (g_str_equal(*hotkey, "secure-attention")) {
-            gtk_accel_map_change_entry("<virt-viewer>/send/secure-attention", accel_key, accel_mods, TRUE);
+            gtk_application_set_accels_for_action(GTK_APPLICATION(self), "win.secure-attention", accels);
         } else if (g_str_equal(*hotkey, "smartcard-insert")) {
             virt_viewer_set_insert_smartcard_accel(self, accel_key, accel_mods);
         } else if (g_str_equal(*hotkey, "smartcard-remove")) {
@@ -2179,6 +2211,8 @@ virt_viewer_app_set_hotkeys(VirtViewerApp *self, const gchar *hotkeys_str)
         } else {
             g_warning("Unknown hotkey command %s", *hotkey);
         }
+
+        g_free(accel);
     }
     g_strfreev(hotkeys);
 
@@ -2284,23 +2318,29 @@ virt_viewer_app_set_fullscreen(VirtViewerApp *self, gboolean fullscreen)
 }
 
 static void
-menu_display_visible_toggled_cb(GtkCheckMenuItem *checkmenuitem,
-                                VirtViewerDisplay *display)
+menu_display_visible_toggled_cb(GSimpleAction *action,
+                                GVariant *parameter G_GNUC_UNUSED,
+                                gpointer data)
 {
+    VirtViewerDisplay *display = data;
     VirtViewerApp *self = virt_viewer_session_get_app(virt_viewer_display_get_session(display));
-    gboolean visible = gtk_check_menu_item_get_active(checkmenuitem);
+    GVariant *state = g_action_get_state(G_ACTION(action));;
+    gboolean visible;
     static gboolean reentering = FALSE;
     VirtViewerWindow *vwin;
 
+    g_return_if_fail(state != NULL);
     if (reentering) /* do not reenter if I switch you back */
         return;
 
     reentering = TRUE;
 
+    visible = !g_variant_get_boolean(state);
+
     vwin = ensure_window_for_display(self, display);
     visible = virt_viewer_app_window_set_visible(self, vwin, visible);
 
-    gtk_check_menu_item_set_active(checkmenuitem, /* will be toggled again */ !visible);
+    g_action_change_state(G_ACTION(action), g_variant_new_boolean(visible));
     reentering = FALSE;
 
     virt_viewer_session_update_displays_geometry(virt_viewer_display_get_session(display));
@@ -2320,48 +2360,19 @@ update_menu_displays_sort(gconstpointer a, gconstpointer b)
         return 0;
 }
 
-static GtkMenuShell *
-window_empty_display_submenu(VirtViewerWindow *window)
-{
-    /* Because of what apparently is a gtk+2 bug (rhbz#922712), we
-     * cannot recreate the submenu every time we need to refresh it,
-     * otherwise the application may get frozen with the keyboard and
-     * mouse grabbed if gtk_menu_item_set_submenu is called while
-     * the menu is displayed. Reusing the same menu every time
-     * works around this issue.
-     */
-    GtkMenuItem *menu = virt_viewer_window_get_menu_displays(window);
-    GtkMenuShell *submenu;
-
-    submenu = GTK_MENU_SHELL(gtk_menu_item_get_submenu(menu));
-    if (submenu) {
-        GList *subitems;
-        GList *it;
-        subitems = gtk_container_get_children(GTK_CONTAINER(submenu));
-        for (it = subitems; it != NULL; it = it->next) {
-            gtk_container_remove(GTK_CONTAINER(submenu), GTK_WIDGET(it->data));
-        }
-        g_list_free(subitems);
-    } else {
-        submenu = GTK_MENU_SHELL(gtk_menu_new());
-        gtk_menu_item_set_submenu(menu, GTK_WIDGET(submenu));
-    }
-
-    return submenu;
-}
-
 static void
 window_update_menu_displays_cb(gpointer value,
                                gpointer user_data)
 {
     VirtViewerApp *self = VIRT_VIEWER_APP(user_data);
-    GtkMenuShell *submenu;
     GList *keys = g_hash_table_get_keys(self->priv->displays);
     GList *tmp;
+    GMenu *menu;
     gboolean sensitive;
 
     keys = g_list_sort(keys, update_menu_displays_sort);
-    submenu = window_empty_display_submenu(VIRT_VIEWER_WINDOW(value));
+    menu = g_menu_new();
+    GtkMenuButton *button = virt_viewer_window_get_menu_button_displays(VIRT_VIEWER_WINDOW(value));
 
     sensitive = (keys != NULL);
     virt_viewer_window_set_menu_displays_sensitive(VIRT_VIEWER_WINDOW(value), sensitive);
@@ -2371,16 +2382,28 @@ window_update_menu_displays_cb(gpointer value,
         int nth = GPOINTER_TO_INT(tmp->data);
         VirtViewerWindow *vwin = virt_viewer_app_get_nth_window(self, nth);
         VirtViewerDisplay *display = VIRT_VIEWER_DISPLAY(g_hash_table_lookup(self->priv->displays, tmp->data));
-        GtkWidget *item;
+        GMenuItem *item;
+        gchar *acname;
+        gchar *acfullname;
+        GSimpleAction *action;
+        GAction *act;
         gboolean visible;
         gchar *label;
 
+        visible = vwin && gtk_widget_get_visible(GTK_WIDGET(virt_viewer_window_get_window(vwin)));
+
+        acname = g_strdup_printf ("display-action-%d", nth + 1);
+        action = g_simple_action_new_stateful(acname, NULL, g_variant_new_boolean(visible));
+
         label = g_strdup_printf(_("Display _%d"), nth + 1);
-        item = gtk_check_menu_item_new_with_mnemonic(label);
+        acfullname = g_strdup_printf ("app.%s", acname);
+        item = g_menu_item_new(label, acfullname);
         g_free(label);
+        g_free(acfullname);
 
-        visible = vwin && gtk_widget_get_visible(GTK_WIDGET(virt_viewer_window_get_window(vwin)));
-        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), visible);
+        g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (action));
+        act = g_action_map_lookup_action (G_ACTION_MAP (self), acname);
+        g_action_change_state(G_ACTION(action), g_variant_new_boolean(visible));
 
         sensitive = visible;
         if (display) {
@@ -2392,15 +2415,17 @@ window_update_menu_displays_cb(gpointer value,
             if (virt_viewer_display_get_selectable(display))
                 sensitive = TRUE;
         }
-        gtk_widget_set_sensitive(item, sensitive);
 
-        virt_viewer_signal_connect_object(G_OBJECT(item), "toggled",
+        g_simple_action_set_enabled(G_SIMPLE_ACTION(act), sensitive);
+        virt_viewer_signal_connect_object(G_OBJECT(action), "activate",
                                           G_CALLBACK(menu_display_visible_toggled_cb), display, 0);
-        gtk_menu_shell_append(submenu, item);
+        g_object_unref (action);
+
+        g_menu_append_item(menu, item);
         tmp = tmp->next;
     }
 
-    gtk_widget_show_all(GTK_WIDGET(submenu));
+    gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (button), G_MENU_MODEL(menu));
     g_list_free(keys);
 }
 
diff --git a/src/virt-viewer-display-spice.c b/src/virt-viewer-display-spice.c
index a604230..554fb4c 100644
--- a/src/virt-viewer-display-spice.c
+++ b/src/virt-viewer-display-spice.c
@@ -243,11 +243,17 @@ enable_accel_changed(VirtViewerApp *app,
                      GParamSpec *pspec G_GNUC_UNUSED,
                      VirtViewerDisplaySpice *self)
 {
-    GtkAccelKey key = {0, 0, 0};
-    if (virt_viewer_app_get_enable_accel(app))
-        gtk_accel_map_lookup_entry("<virt-viewer>/view/release-cursor", &key);
+    guint accel_key = 0;
+    GdkModifierType accel_mods = 0;
+    gchar **accels;
+
+    if (virt_viewer_app_get_enable_accel(app)){
+        accels = gtk_application_get_accels_for_action(GTK_APPLICATION(app), "win.release-cursor");
+        gtk_accelerator_parse(accels[0], &accel_key, &accel_mods);
+        g_strfreev(accels);
+    }
 
-    if (key.accel_key || key.accel_mods) {
+    if (accel_key || accel_mods) {
         SpiceGrabSequence *seq = spice_grab_sequence_new(0, NULL);
         /* disable default grab sequence */
         spice_display_set_grab_keys(self->priv->display, seq);
diff --git a/src/virt-viewer-display-vnc.c b/src/virt-viewer-display-vnc.c
index cb45c23..33828d3 100644
--- a/src/virt-viewer-display-vnc.c
+++ b/src/virt-viewer-display-vnc.c
@@ -190,11 +190,17 @@ enable_accel_changed(VirtViewerApp *app,
                      GParamSpec *pspec G_GNUC_UNUSED,
                      VncDisplay *vnc)
 {
-    GtkAccelKey key = {0, 0, 0};
-    if (virt_viewer_app_get_enable_accel(app))
-        gtk_accel_map_lookup_entry("<virt-viewer>/view/release-cursor", &key);
+    guint accel_key = 0;
+    GdkModifierType accel_mods = 0;
+    gchar **accels;
+
+    if (virt_viewer_app_get_enable_accel(app)){
+        accels = gtk_application_get_accels_for_action(GTK_APPLICATION(app), "win.release-cursor");
+        gtk_accelerator_parse(accels[0], &accel_key, &accel_mods);
+        g_strfreev(accels);
+    }
 
-    if (key.accel_key || key.accel_mods) {
+    if (accel_key || accel_mods) {
         VncGrabSequence *seq = vnc_grab_sequence_new(0, NULL);
         /* disable default grab sequence */
         vnc_display_set_grab_keys(vnc, seq);
diff --git a/src/virt-viewer-file.c b/src/virt-viewer-file.c
index 9ff2a05..ef10b11 100644
--- a/src/virt-viewer-file.c
+++ b/src/virt-viewer-file.c
@@ -790,17 +790,17 @@ virt_viewer_file_set_ovirt_admin(VirtViewerFile* self, gint value)
 }
 
 static void
-spice_hotkey_set_accel(const gchar *accel_path, const gchar *key)
+spice_hotkey_set_accel(VirtViewerApp *app, const gchar *action_name, const gchar *key)
 {
     gchar *accel;
-    guint accel_key;
-    GdkModifierType accel_mods;
 
     accel = spice_hotkey_to_gtk_accelerator(key);
-    gtk_accelerator_parse(accel, &accel_key, &accel_mods);
-    g_free(accel);
 
-    gtk_accel_map_change_entry(accel_path, accel_key, accel_mods, TRUE);
+    const gchar *accels[] = { accel, NULL };
+
+    gtk_application_set_accels_for_action(GTK_APPLICATION(app), action_name, accels);
+
+    g_free(accel);
 }
 
 static gboolean
@@ -881,13 +881,13 @@ virt_viewer_file_fill_app(VirtViewerFile* self, VirtViewerApp *app, GError **err
         gchar *val;
         static const struct {
             const char *prop;
-            const char *accel;
+            const char *action_name;
         } accels[] = {
-            { "release-cursor", "<virt-viewer>/view/release-cursor" },
-            { "toggle-fullscreen", "<virt-viewer>/view/toggle-fullscreen" },
-            { "smartcard-insert", "<virt-viewer>/file/smartcard-insert" },
-            { "smartcard-remove", "<virt-viewer>/file/smartcard-remove" },
-            { "secure-attention", "<virt-viewer>/send/secure-attention" }
+            { "release-cursor", "win.release-cursor" },
+            { "toggle-fullscreen", "win.fullscreen" },
+            { "smartcard-insert", "win.smartcard-insert" },
+            { "smartcard-remove", "win.smartcard-remove" },
+            { "secure-attention", "win.secure-attention" }
         };
         int i;
 
@@ -895,7 +895,7 @@ virt_viewer_file_fill_app(VirtViewerFile* self, VirtViewerApp *app, GError **err
             if (!virt_viewer_file_is_set(self, accels[i].prop))
                 continue;
             g_object_get(self, accels[i].prop, &val, NULL);
-            spice_hotkey_set_accel(accels[i].accel, val);
+            spice_hotkey_set_accel(app, accels[i].action_name, val);
             g_free(val);
         }
     }
diff --git a/src/virt-viewer-window.c b/src/virt-viewer-window.c
index 27c0be0..c1278ca 100644
--- a/src/virt-viewer-window.c
+++ b/src/virt-viewer-window.c
@@ -48,31 +48,22 @@
 #define ZOOM_STEP 10
 
 /* Signal handlers for main window (move in a VirtViewerMainWindow?) */
-void virt_viewer_window_menu_view_zoom_out(GtkWidget *menu, VirtViewerWindow *self);
-void virt_viewer_window_menu_view_zoom_in(GtkWidget *menu, VirtViewerWindow *self);
-void virt_viewer_window_menu_view_zoom_reset(GtkWidget *menu, VirtViewerWindow *self);
 gboolean virt_viewer_window_delete(GtkWidget *src, void *dummy, VirtViewerWindow *self);
 void virt_viewer_window_guest_details_response(GtkDialog *dialog, gint response_id, gpointer user_data);
-void virt_viewer_window_menu_help_guest_details(GtkWidget *menu, VirtViewerWindow *self);
-void virt_viewer_window_menu_view_fullscreen(GtkWidget *menu, VirtViewerWindow *self);
 void virt_viewer_window_menu_send(GtkWidget *menu, VirtViewerWindow *self);
-void virt_viewer_window_menu_file_screenshot(GtkWidget *menu, VirtViewerWindow *self);
-void virt_viewer_window_menu_file_usb_device_selection(GtkWidget *menu, VirtViewerWindow *self);
-void virt_viewer_window_menu_file_smartcard_insert(GtkWidget *menu, VirtViewerWindow *self);
-void virt_viewer_window_menu_file_smartcard_remove(GtkWidget *menu, VirtViewerWindow *self);
-void virt_viewer_window_menu_view_release_cursor(GtkWidget *menu, VirtViewerWindow *self);
-void virt_viewer_window_menu_preferences_cb(GtkWidget *menu, VirtViewerWindow *self);
-void virt_viewer_window_menu_change_cd_activate(GtkWidget *menu, VirtViewerWindow *self);
 
 /* Internal methods */
 static void virt_viewer_window_enable_modifiers(VirtViewerWindow *self);
 static void virt_viewer_window_disable_modifiers(VirtViewerWindow *self);
 static void virt_viewer_window_queue_resize(VirtViewerWindow *self);
 static void virt_viewer_window_toolbar_setup(VirtViewerWindow *self);
+static void virt_viewer_window_menu_view_fullscreen(VirtViewerWindow *self);
+static void usb_device_selection_activated(GSimpleAction *action, GVariant *parameter, gpointer window);
+
 static GtkMenu* virt_viewer_window_get_keycombo_menu(VirtViewerWindow *self);
-static void virt_viewer_window_get_minimal_dimensions(VirtViewerWindow *self, guint *width, guint *height);
 static gint virt_viewer_window_get_minimal_zoom_level(VirtViewerWindow *self);
 
+
 G_DEFINE_TYPE (VirtViewerWindow, virt_viewer_window, G_TYPE_OBJECT)
 
 #define GET_PRIVATE(o)                                                  \
@@ -92,6 +83,7 @@ struct _VirtViewerWindowPrivate {
     GtkBuilder *builder;
     GtkWidget *window;
     GtkWidget *toolbar;
+    GtkWidget *header;
     GtkWidget *toolbar_usb_device_selection;
     GtkWidget *toolbar_send_key;
     GtkAccelGroup *accel_group;
@@ -206,33 +198,6 @@ virt_viewer_window_dispose (GObject *object)
 }
 
 static void
-rebuild_combo_menu(GObject    *gobject G_GNUC_UNUSED,
-                   GParamSpec *pspec G_GNUC_UNUSED,
-                   gpointer    user_data)
-{
-    VirtViewerWindow *self = user_data;
-    GtkWidget *menu;
-
-    menu = GTK_WIDGET(gtk_builder_get_object(self->priv->builder, "menu-send"));
-    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu),
-                              GTK_WIDGET(virt_viewer_window_get_keycombo_menu(self)));
-    gtk_widget_set_sensitive(menu, (self->priv->display != NULL));
-}
-
-static void
-virt_viewer_window_constructed(GObject *object)
-{
-    VirtViewerWindowPrivate *priv = VIRT_VIEWER_WINDOW(object)->priv;
-
-    if (G_OBJECT_CLASS(virt_viewer_window_parent_class)->constructed)
-        G_OBJECT_CLASS(virt_viewer_window_parent_class)->constructed(object);
-
-    g_signal_connect(priv->app, "notify::enable-accel",
-                     G_CALLBACK(rebuild_combo_menu), object);
-    rebuild_combo_menu(NULL, NULL, object);
-}
-
-static void
 virt_viewer_window_class_init (VirtViewerWindowClass *klass)
 {
     GObjectClass *object_class = G_OBJECT_CLASS (klass);
@@ -242,7 +207,6 @@ virt_viewer_window_class_init (VirtViewerWindowClass *klass)
     object_class->get_property = virt_viewer_window_get_property;
     object_class->set_property = virt_viewer_window_set_property;
     object_class->dispose = virt_viewer_window_dispose;
-    object_class->constructed = virt_viewer_window_constructed;
 
     g_object_class_install_property(object_class,
                                     PROP_SUBTITLE,
@@ -293,11 +257,424 @@ can_activate_cb (GtkWidget *widget G_GNUC_UNUSED,
 }
 
 static void
+fullscreen_activated(GSimpleAction *action G_GNUC_UNUSED,
+                     GVariant *parameter G_GNUC_UNUSED,
+                     gpointer data)
+{
+    VirtViewerWindow *self = VIRT_VIEWER_WINDOW(data);;
+
+    virt_viewer_window_menu_view_fullscreen(self);
+}
+
+static GActionEntry headerbar_entries[] = {
+    { "fullscreen", fullscreen_activated, NULL, NULL, NULL, {0,0,0} },
+};
+
+static void
+ctrl_alt_del_activated(GSimpleAction *action G_GNUC_UNUSED,
+                       GVariant *parameter G_GNUC_UNUSED,
+                       gpointer window)
+{
+    VirtViewerWindow *self =  VIRT_VIEWER_WINDOW(window);
+    guint keys[] = { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_Delete };
+
+    virt_viewer_display_send_keys(VIRT_VIEWER_DISPLAY(self->priv->display),
+                                  keys, G_N_ELEMENTS(keys));
+}
+
+static void
+ctrl_alt_backspace_activated(GSimpleAction *action G_GNUC_UNUSED,
+                             GVariant *parameter G_GNUC_UNUSED,
+                             gpointer window)
+{
+    VirtViewerWindow *self =  VIRT_VIEWER_WINDOW(window);
+    guint keys[] = { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_BackSpace };
+
+    virt_viewer_display_send_keys(VIRT_VIEWER_DISPLAY(self->priv->display),
+                                  keys, G_N_ELEMENTS(keys));
+}
+
+static void
+ctrl_alt_fn_activated(GSimpleAction *action G_GNUC_UNUSED,
+                      GVariant      *parameter G_GNUC_UNUSED,
+                      gpointer       window)
+{
+    VirtViewerWindow *self =  VIRT_VIEWER_WINDOW(window);
+    guint keys[] = { GDK_KEY_Control_L, GDK_KEY_Alt_L, 0 };
+    const char *name = g_action_get_name(G_ACTION(action));
+
+    if (g_str_has_suffix(name, "f1")) {
+        keys[2] = GDK_KEY_F1;
+    } else if (g_str_has_suffix(name, "f2")) {
+        keys[2] = GDK_KEY_F2;
+    } else if (g_str_has_suffix(name, "f3")) {
+        keys[2] = GDK_KEY_F3;
+    } else if (g_str_has_suffix(name, "f4")) {
+        keys[2] = GDK_KEY_F4;
+    } else if (g_str_has_suffix(name, "f5")) {
+        keys[2] = GDK_KEY_F5;
+    } else if (g_str_has_suffix(name, "f6")) {
+        keys[2] = GDK_KEY_F6;
+    } else if (g_str_has_suffix(name, "f7")) {
+        keys[2] = GDK_KEY_F7;
+    } else if (g_str_has_suffix(name, "f8")) {
+        keys[2] = GDK_KEY_F8;
+    } else if (g_str_has_suffix(name, "f9")) {
+        keys[2] = GDK_KEY_F9;
+    } else if (g_str_has_suffix(name, "f10")) {
+        keys[2] = GDK_KEY_F10;
+    } else if (g_str_has_suffix(name, "f11")) {
+        keys[2] = GDK_KEY_F11;
+    } else if (g_str_has_suffix(name, "f12")) {
+        keys[2] = GDK_KEY_F12;
+    } else {
+        return;
+    }
+
+    virt_viewer_display_send_keys(VIRT_VIEWER_DISPLAY(self->priv->display),
+                                  keys, G_N_ELEMENTS(keys));
+}
+
+static void
+printscreen_activated(GSimpleAction *action G_GNUC_UNUSED,
+                      GVariant *parameter G_GNUC_UNUSED,
+                      gpointer window)
+{
+    VirtViewerWindow *self =  VIRT_VIEWER_WINDOW(window);
+    guint keys[] = { GDK_KEY_Print };
+
+    virt_viewer_display_send_keys(VIRT_VIEWER_DISPLAY(self->priv->display),
+                                  keys, G_N_ELEMENTS(keys));
+}
+
+static void
+iso_dialog_response(GtkDialog *dialog,
+                    gint response_id,
+                    gpointer user_data G_GNUC_UNUSED)
+{
+    if (response_id == GTK_RESPONSE_NONE)
+        return;
+
+    gtk_widget_destroy(GTK_WIDGET(dialog));
+}
+
+static void
+virt_viewer_window_menu_change_cd(VirtViewerWindow *self)
+{
+    VirtViewerWindowPrivate *priv = self->priv;
+    GtkWidget *dialog;
+    GObject *foreign_menu;
+
+    g_object_get(G_OBJECT(priv->app), "ovirt-foreign-menu", &foreign_menu, NULL);
+    dialog = remote_viewer_iso_list_dialog_new(GTK_WINDOW(priv->window), foreign_menu);
+    g_object_unref(foreign_menu);
+
+    if (!dialog)
+        dialog = gtk_message_dialog_new(GTK_WINDOW(priv->window),
+                                        GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+                                        GTK_MESSAGE_ERROR,
+                                        GTK_BUTTONS_CLOSE,
+                                        _("Unable do connnect to oVirt"));
+
+    g_signal_connect(dialog, "response", G_CALLBACK(iso_dialog_response), NULL);
+    gtk_widget_show_all(dialog);
+    gtk_dialog_run(GTK_DIALOG(dialog));
+}
+
+static GActionEntry send_keys_entries[] = {
+    { "ctrl+alt+del", ctrl_alt_del_activated, NULL, NULL, NULL, {0,0,0} },
+    { "ctrl+alt+backspace", ctrl_alt_backspace_activated, NULL, NULL, NULL, {0,0,0} },
+    { "ctrl+alt+f1", ctrl_alt_fn_activated, NULL, NULL, NULL, {0,0,0} },
+    { "ctrl+alt+f2", ctrl_alt_fn_activated, NULL, NULL, NULL, {0,0,0} },
+    { "ctrl+alt+f3", ctrl_alt_fn_activated, NULL, NULL, NULL, {0,0,0} },
+    { "ctrl+alt+f4", ctrl_alt_fn_activated, NULL, NULL, NULL, {0,0,0} },
+    { "ctrl+alt+f5", ctrl_alt_fn_activated, NULL, NULL, NULL, {0,0,0} },
+    { "ctrl+alt+f6", ctrl_alt_fn_activated, NULL, NULL, NULL, {0,0,0} },
+    { "ctrl+alt+f7", ctrl_alt_fn_activated, NULL, NULL, NULL, {0,0,0} },
+    { "ctrl+alt+f8", ctrl_alt_fn_activated, NULL, NULL, NULL, {0,0,0} },
+    { "ctrl+alt+f9", ctrl_alt_fn_activated, NULL, NULL, NULL, {0,0,0} },
+    { "ctrl+alt+f10", ctrl_alt_fn_activated, NULL, NULL, NULL, {0,0,0} },
+    { "ctrl+alt+f11", ctrl_alt_fn_activated, NULL, NULL, NULL, {0,0,0} },
+    { "ctrl+alt+f12", ctrl_alt_fn_activated, NULL, NULL, NULL, {0,0,0} },
+    { "printscreen", printscreen_activated, NULL, NULL, NULL, {0,0,0} },
+};
+
+static void add_if_writable (GdkPixbufFormat *data, GHashTable *formats)
+{
+    if (gdk_pixbuf_format_is_writable(data)) {
+        gchar **extensions;
+        gchar **it;
+        extensions = gdk_pixbuf_format_get_extensions(data);
+        for (it = extensions; *it != NULL; it++) {
+            g_hash_table_insert(formats, g_strdup(*it), data);
+        }
+        g_strfreev(extensions);
+    }
+}
+
+static GHashTable *init_image_formats(void)
+{
+    GHashTable *format_map;
+    GSList *formats = gdk_pixbuf_get_formats();
+
+    format_map = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
+    g_slist_foreach(formats, (GFunc)add_if_writable, format_map);
+    g_slist_free (formats);
+
+    return format_map;
+}
+
+static GdkPixbufFormat *get_image_format(const char *filename)
+{
+    static GOnce image_formats_once = G_ONCE_INIT;
+    const char *ext;
+
+    g_once(&image_formats_once, (GThreadFunc)init_image_formats, NULL);
+
+    ext = strrchr(filename, '.');
+    if (ext == NULL)
+        return NULL;
+
+    ext++; /* skip '.' */
+
+    return g_hash_table_lookup(image_formats_once.retval, ext);
+}
+
+static void
+virt_viewer_window_save_screenshot(VirtViewerWindow *self,
+                                   const char *file)
+{
+    VirtViewerWindowPrivate *priv = self->priv;
+    GdkPixbuf *pix = virt_viewer_display_get_pixbuf(VIRT_VIEWER_DISPLAY(priv->display));
+    GdkPixbufFormat *format = get_image_format(file);
+
+    if (format == NULL) {
+        g_debug("unknown file extension, falling back to png");
+        if (!g_str_has_suffix(file, ".png")) {
+            char *png_filename;
+            png_filename = g_strconcat(file, ".png", NULL);
+            gdk_pixbuf_save(pix, png_filename, "png", NULL,
+                            "tEXt::Generator App", PACKAGE, NULL);
+            g_free(png_filename);
+        } else {
+            gdk_pixbuf_save(pix, file, "png", NULL,
+                            "tEXt::Generator App", PACKAGE, NULL);
+        }
+    } else {
+        char *type = gdk_pixbuf_format_get_name(format);
+        g_debug("saving to %s", type);
+        gdk_pixbuf_save(pix, file, type, NULL, NULL);
+        g_free(type);
+    }
+
+    g_object_unref(pix);
+}
+
+static void
+screenshot_activated(GSimpleAction *action G_GNUC_UNUSED,
+                     GVariant *parameter G_GNUC_UNUSED,
+                     gpointer data)
+{
+    VirtViewerWindow *self = VIRT_VIEWER_WINDOW(data);;
+    VirtViewerWindowPrivate *priv = self->priv;
+    GtkWidget *dialog;
+    const char *image_dir;
+
+    g_return_if_fail(priv->display != NULL);
+
+    dialog = gtk_file_chooser_dialog_new("Save screenshot",
+                                         NULL,
+                                         GTK_FILE_CHOOSER_ACTION_SAVE,
+                                         _("_Cancel"), GTK_RESPONSE_CANCEL,
+                                         _("_Save"), GTK_RESPONSE_ACCEPT,
+                                         NULL);
+    gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER (dialog), TRUE);
+    gtk_window_set_transient_for(GTK_WINDOW(dialog),
+                                 GTK_WINDOW(self->priv->window));
+    image_dir = g_get_user_special_dir(G_USER_DIRECTORY_PICTURES);
+    if (image_dir != NULL)
+        gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER (dialog), image_dir);
+    gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER (dialog), _("Screenshot"));
+
+    if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
+        char *filename;
+
+        filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (dialog));
+        virt_viewer_window_save_screenshot(self, filename);
+        g_free(filename);
+    }
+
+    gtk_widget_destroy(dialog);
+}
+
+static void
+usb_device_selection_activated(GSimpleAction *action G_GNUC_UNUSED,
+                               GVariant *parameter G_GNUC_UNUSED,
+                               gpointer window)
+{
+    VirtViewerWindow *self =  VIRT_VIEWER_WINDOW(window);
+
+    virt_viewer_session_usb_device_selection(virt_viewer_app_get_session(self->priv->app),
+                                             GTK_WINDOW(self->priv->window));
+}
+
+static gint
+virt_viewer_window_get_real_zoom_level(VirtViewerWindow *self)
+{
+    GtkAllocation allocation;
+    guint width, height;
+
+    g_return_val_if_fail(self->priv->display != NULL, NORMAL_ZOOM_LEVEL);
+
+    gtk_widget_get_allocation(GTK_WIDGET(self->priv->display), &allocation);
+    virt_viewer_display_get_desktop_size(self->priv->display, &width, &height);
+
+    return round((double) NORMAL_ZOOM_LEVEL * allocation.width / width);
+}
+
+static void
+zoom_in_activated(GSimpleAction *action G_GNUC_UNUSED,
+                  GVariant *parameter G_GNUC_UNUSED,
+                  gpointer data)
+{
+    VirtViewerWindow *self = VIRT_VIEWER_WINDOW(data);;
+
+    virt_viewer_window_set_zoom_level(self,
+                                      virt_viewer_window_get_real_zoom_level(self) + ZOOM_STEP);
+}
+
+static void
+zoom_out_activated(GSimpleAction *action G_GNUC_UNUSED,
+                   GVariant *parameter G_GNUC_UNUSED,
+                   gpointer data)
+{
+    VirtViewerWindow *self = VIRT_VIEWER_WINDOW(data);;
+
+    virt_viewer_window_set_zoom_level(self,
+                                      virt_viewer_window_get_real_zoom_level(self) - ZOOM_STEP);
+}
+
+static void
+zoom_reset_activated(GSimpleAction *action G_GNUC_UNUSED,
+                     GVariant *parameter G_GNUC_UNUSED,
+                     gpointer data)
+{
+    VirtViewerWindow *self = VIRT_VIEWER_WINDOW(data);;
+
+    virt_viewer_window_set_zoom_level(self, NORMAL_ZOOM_LEVEL);
+}
+
+static void
+guest_details_activated(GSimpleAction *action G_GNUC_UNUSED,
+                        GVariant *parameter G_GNUC_UNUSED,
+                        gpointer data)
+{
+    VirtViewerWindow *self = VIRT_VIEWER_WINDOW(data);
+    GtkBuilder *ui = virt_viewer_util_load_ui("virt-viewer-guest-details.ui");
+    char *name = NULL;
+    char *uuid = NULL;
+
+    g_return_if_fail(ui != NULL);
+
+    GtkWidget *dialog = GTK_WIDGET(gtk_builder_get_object(ui, "guestdetailsdialog"));
+    GtkWidget *namelabel = GTK_WIDGET(gtk_builder_get_object(ui, "namevaluelabel"));
+    GtkWidget *guidlabel = GTK_WIDGET(gtk_builder_get_object(ui, "guidvaluelabel"));
+
+    g_return_if_fail(dialog && namelabel && guidlabel);
+
+    g_object_get(self->priv->app, "guest-name", &name, "uuid", &uuid, NULL);
+
+    if (!name || *name == '\0')
+        name = g_strdup(_("Unknown"));
+    if (!uuid || *uuid == '\0')
+        uuid = g_strdup(_("Unknown"));
+    gtk_label_set_text(GTK_LABEL(namelabel), name);
+    gtk_label_set_text(GTK_LABEL(guidlabel), uuid);
+    g_free(name);
+    g_free(uuid);
+
+    gtk_window_set_transient_for(GTK_WINDOW(dialog),
+                                 GTK_WINDOW(self->priv->window));
+
+    gtk_builder_connect_signals(ui, self);
+
+    gtk_widget_show_all(dialog);
+
+    g_object_unref(G_OBJECT(ui));
+}
+
+static void
+release_cursor_activated(GSimpleAction *action G_GNUC_UNUSED,
+                         GVariant *parameter G_GNUC_UNUSED,
+                         gpointer app)
+{
+
+    VirtViewerWindow *self = VIRT_VIEWER_WINDOW(app);
+
+    VirtViewerDisplay *display = virt_viewer_window_get_display(self);
+
+    virt_viewer_display_release_cursor(display);
+}
+
+static void
+smartcard_insert_activated(GSimpleAction *action G_GNUC_UNUSED,
+                           GVariant *parameter G_GNUC_UNUSED,
+                           gpointer app)
+{
+
+    VirtViewerWindow *self = VIRT_VIEWER_WINDOW(app);
+
+    virt_viewer_session_smartcard_insert(virt_viewer_app_get_session(self->priv->app));
+}
+
+static void
+smartcard_remove_activated(GSimpleAction *action G_GNUC_UNUSED,
+                           GVariant *parameter G_GNUC_UNUSED,
+                           gpointer app)
+{
+
+    VirtViewerWindow *self = VIRT_VIEWER_WINDOW(app);
+
+    virt_viewer_session_smartcard_remove(virt_viewer_app_get_session(self->priv->app));
+}
+
+static GActionEntry gear_entries[] = {
+    { "screenshot", screenshot_activated, NULL, NULL, NULL, {0,0,0} },
+    { "usb-device-selection", usb_device_selection_activated, NULL, NULL, NULL, {0,0,0} },
+    { "zoom-in", zoom_in_activated, NULL, NULL, NULL, {0,0,0} },
+    { "zoom-out", zoom_out_activated, NULL, NULL, NULL, {0,0,0} },
+    { "zoom-reset", zoom_reset_activated, NULL, NULL, NULL, {0,0,0} },
+    { "guest-details", guest_details_activated, NULL, NULL, NULL, {0,0,0} },
+    { "release-cursor", release_cursor_activated, NULL, NULL, NULL, {0, 0, 0} },
+    { "smartcard-insert", smartcard_insert_activated, NULL, NULL, NULL, {0, 0, 0} },
+    { "smartcard-remove", smartcard_remove_activated, NULL, NULL, NULL, {0, 0, 0} },
+    { "secure-attention", ctrl_alt_del_activated, NULL, NULL, NULL, {0, 0, 0} },
+};
+
+static void
+virt_viewer_window_fullscreen_cb(GtkButton *button G_GNUC_UNUSED, VirtViewerWindow *self)
+{
+    virt_viewer_window_menu_view_fullscreen(self);
+}
+
+static void
+virt_viewer_window_change_cd_cb(GtkButton *button G_GNUC_UNUSED, VirtViewerWindow *self)
+{
+    virt_viewer_window_menu_change_cd(self);
+}
+
+static void
 virt_viewer_window_init (VirtViewerWindow *self)
 {
     VirtViewerWindowPrivate *priv;
     GtkWidget *vbox;
     GSList *accels;
+    GtkWidget *gears;
+    GtkWidget *fullscreen;
+    GtkWidget *send_keys;
+    GtkWidget *change_cd;
+    GMenuModel *gears_menu;
+    GMenuModel *send_keys_menu;
 
     self->priv = GET_PRIVATE(self);
     priv = self->priv;
@@ -310,35 +687,33 @@ virt_viewer_window_init (VirtViewerWindow *self)
 
     priv->builder = virt_viewer_util_load_ui("virt-viewer.ui");
 
-    gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(self->priv->builder, "menu-send")), FALSE);
-    gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(self->priv->builder, "menu-view-zoom")), FALSE);
-    gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(self->priv->builder, "menu-file-screenshot")), FALSE);
-
     gtk_builder_connect_signals(priv->builder, self);
 
     priv->accel_group = GTK_ACCEL_GROUP(gtk_builder_get_object(priv->builder, "accelgroup"));
 
-    /* make sure they can be activated even if the menu item is not visible */
-    g_signal_connect(gtk_builder_get_object(priv->builder, "menu-view-fullscreen"),
-                     "can-activate-accel", G_CALLBACK(can_activate_cb), self);
-    g_signal_connect(gtk_builder_get_object(priv->builder, "menu-file-smartcard-insert"),
-                     "can-activate-accel", G_CALLBACK(can_activate_cb), self);
-    g_signal_connect(gtk_builder_get_object(priv->builder, "menu-file-smartcard-remove"),
-                     "can-activate-accel", G_CALLBACK(can_activate_cb), self);
-    g_signal_connect(gtk_builder_get_object(priv->builder, "menu-view-release-cursor"),
-                     "can-activate-accel", G_CALLBACK(can_activate_cb), self);
-    g_signal_connect(gtk_builder_get_object(priv->builder, "menu-view-zoom-reset"),
-                     "can-activate-accel", G_CALLBACK(can_activate_cb), self);
-    g_signal_connect(gtk_builder_get_object(priv->builder, "menu-view-zoom-in"),
-                     "can-activate-accel", G_CALLBACK(can_activate_cb), self);
-    g_signal_connect(gtk_builder_get_object(priv->builder, "menu-view-zoom-out"),
-                     "can-activate-accel", G_CALLBACK(can_activate_cb), self);
-
     vbox = GTK_WIDGET(gtk_builder_get_object(priv->builder, "viewer-box"));
     virt_viewer_window_toolbar_setup(self);
 
     gtk_box_pack_end(GTK_BOX(vbox), GTK_WIDGET(priv->notebook), TRUE, TRUE, 0);
 
+    priv->header = GTK_WIDGET(gtk_builder_get_object(priv->builder, "header"));
+
+    gears = GTK_WIDGET(gtk_builder_get_object(priv->builder, "gears"));
+
+    gears_menu = G_MENU_MODEL (gtk_builder_get_object (priv->builder, "gears-menu"));
+    gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (gears), gears_menu);
+
+    fullscreen = GTK_WIDGET(gtk_builder_get_object(priv->builder, "fullscreen"));
+    g_signal_connect(fullscreen, "clicked", G_CALLBACK(virt_viewer_window_fullscreen_cb), self);
+
+    send_keys = GTK_WIDGET(gtk_builder_get_object(priv->builder, "send-keys"));
+
+    send_keys_menu = G_MENU_MODEL (gtk_builder_get_object (priv->builder, "send-keys-menu"));
+    gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (send_keys), send_keys_menu);
+
+    change_cd = GTK_WIDGET(gtk_builder_get_object(priv->builder, "change-cd"));
+    g_signal_connect(change_cd, "clicked", G_CALLBACK(virt_viewer_window_change_cd_cb), self);
+
     priv->window = GTK_WIDGET(gtk_builder_get_object(priv->builder, "viewer"));
     gtk_window_add_accel_group(GTK_WINDOW(priv->window), priv->accel_group);
 
@@ -353,7 +728,24 @@ virt_viewer_window_init (VirtViewerWindow *self)
         g_object_ref(G_OBJECT(accels->data));
     }
 
-    priv->zoomlevel = NORMAL_ZOOM_LEVEL;
+    priv->zoomlevel = NORMAL_ZOOM_LEVEL;
+
+    g_action_map_add_action_entries (G_ACTION_MAP (priv->window),
+                                    headerbar_entries,
+                                    G_N_ELEMENTS (headerbar_entries),
+                                    self);
+
+    g_action_map_add_action_entries (G_ACTION_MAP (priv->window),
+                                    send_keys_entries,
+                                    G_N_ELEMENTS (send_keys_entries),
+                                    self);
+
+    g_action_map_add_action_entries (G_ACTION_MAP (priv->window),
+                                     gear_entries,
+                                     G_N_ELEMENTS (gear_entries),
+                                     self);
+
+    gtk_window_set_titlebar(GTK_WINDOW(priv->window), priv->header);
 }
 
 static void
@@ -367,43 +759,6 @@ virt_viewer_window_desktop_resize(VirtViewerDisplay *display G_GNUC_UNUSED,
     virt_viewer_window_queue_resize(self);
 }
 
-static gint
-virt_viewer_window_get_real_zoom_level(VirtViewerWindow *self)
-{
-    GtkAllocation allocation;
-    guint width, height;
-
-    g_return_val_if_fail(self->priv->display != NULL, NORMAL_ZOOM_LEVEL);
-
-    gtk_widget_get_allocation(GTK_WIDGET(self->priv->display), &allocation);
-    virt_viewer_display_get_desktop_size(self->priv->display, &width, &height);
-
-    return round((double) NORMAL_ZOOM_LEVEL * allocation.width / width);
-}
-
-G_MODULE_EXPORT void
-virt_viewer_window_menu_view_zoom_out(GtkWidget *menu G_GNUC_UNUSED,
-                                      VirtViewerWindow *self)
-{
-    virt_viewer_window_set_zoom_level(self,
-                                      virt_viewer_window_get_real_zoom_level(self) - ZOOM_STEP);
-}
-
-G_MODULE_EXPORT void
-virt_viewer_window_menu_view_zoom_in(GtkWidget *menu G_GNUC_UNUSED,
-                                     VirtViewerWindow *self)
-{
-    virt_viewer_window_set_zoom_level(self,
-                                      virt_viewer_window_get_real_zoom_level(self) + ZOOM_STEP);
-}
-
-G_MODULE_EXPORT void
-virt_viewer_window_menu_view_zoom_reset(GtkWidget *menu G_GNUC_UNUSED,
-                                        VirtViewerWindow *self)
-{
-    virt_viewer_window_set_zoom_level(self, NORMAL_ZOOM_LEVEL);
-}
-
 /* Kick GtkWindow to tell it to adjust to our new widget sizes */
 static void
 virt_viewer_window_queue_resize(VirtViewerWindow *self)
@@ -448,21 +803,10 @@ mapped(GtkWidget *widget, GdkEvent *event G_GNUC_UNUSED,
     return FALSE;
 }
 
-static void
-virt_viewer_window_menu_fullscreen_set_active(VirtViewerWindow *self, gboolean active)
-{
-    GtkCheckMenuItem *check = GTK_CHECK_MENU_ITEM(gtk_builder_get_object(self->priv->builder, "menu-view-fullscreen"));
-
-    g_signal_handlers_block_by_func(check, virt_viewer_window_menu_view_fullscreen, self);
-    gtk_check_menu_item_set_active(check, active);
-    g_signal_handlers_unblock_by_func(check, virt_viewer_window_menu_view_fullscreen, self);
-}
-
 void
 virt_viewer_window_leave_fullscreen(VirtViewerWindow *self)
 {
     VirtViewerWindowPrivate *priv = self->priv;
-    GtkWidget *menu = GTK_WIDGET(gtk_builder_get_object(priv->builder, "top-menu"));
 
     /* if we enter and leave fullscreen mode before being shown, make sure to
      * disconnect the mapped signal handler */
@@ -471,7 +815,6 @@ virt_viewer_window_leave_fullscreen(VirtViewerWindow *self)
     if (!priv->fullscreen)
         return;
 
-    virt_viewer_window_menu_fullscreen_set_active(self, FALSE);
     priv->fullscreen = FALSE;
     priv->fullscreen_monitor = -1;
     if (priv->display) {
@@ -479,7 +822,6 @@ virt_viewer_window_leave_fullscreen(VirtViewerWindow *self)
         virt_viewer_display_set_fullscreen(priv->display, FALSE);
     }
     virt_viewer_timed_revealer_force_reveal(priv->revealer, FALSE);
-    gtk_widget_show(menu);
     gtk_widget_hide(priv->toolbar);
     gtk_widget_set_size_request(priv->window, -1, -1);
     gtk_window_unfullscreen(GTK_WINDOW(priv->window));
@@ -490,7 +832,6 @@ void
 virt_viewer_window_enter_fullscreen(VirtViewerWindow *self, gint monitor)
 {
     VirtViewerWindowPrivate *priv = self->priv;
-    GtkWidget *menu = GTK_WIDGET(gtk_builder_get_object(priv->builder, "top-menu"));
 
     if (priv->fullscreen && priv->fullscreen_monitor != monitor)
         virt_viewer_window_leave_fullscreen(self);
@@ -512,8 +853,6 @@ virt_viewer_window_enter_fullscreen(VirtViewerWindow *self, gint monitor)
         return;
     }
 
-    virt_viewer_window_menu_fullscreen_set_active(self, TRUE);
-    gtk_widget_hide(menu);
     gtk_widget_show(priv->toolbar);
     virt_viewer_timed_revealer_force_reveal(priv->revealer, TRUE);
 
@@ -533,6 +872,11 @@ struct keyComboDef {
     const gchar* accel_path;
 };
 
+struct gkeyComboDef {
+    const char *label;
+    const gchar* action;
+};
+
 static const struct keyComboDef keyCombos[] = {
     { { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_Delete, GDK_KEY_VoidSymbol }, N_("Ctrl+Alt+_Del"), "<virt-viewer>/send/secure-attention"},
     { { GDK_KEY_Control_L, GDK_KEY_Alt_L, GDK_KEY_BackSpace, GDK_KEY_VoidSymbol }, N_("Ctrl+Alt+_Backspace"), NULL},
@@ -824,187 +1168,10 @@ virt_viewer_window_toolbar_send_key(GtkWidget *button G_GNUC_UNUSED,
     g_object_unref(menu);
 }
 
-
-G_MODULE_EXPORT void
-virt_viewer_window_menu_view_fullscreen(GtkWidget *menu,
-                                        VirtViewerWindow *self)
-{
-    gboolean fullscreen = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu));
-
-    virt_viewer_window_set_fullscreen(self, fullscreen);
-}
-
-static void add_if_writable (GdkPixbufFormat *data, GHashTable *formats)
-{
-    if (gdk_pixbuf_format_is_writable(data)) {
-        gchar **extensions;
-        gchar **it;
-        extensions = gdk_pixbuf_format_get_extensions(data);
-        for (it = extensions; *it != NULL; it++) {
-            g_hash_table_insert(formats, g_strdup(*it), data);
-        }
-        g_strfreev(extensions);
-    }
-}
-
-static GHashTable *init_image_formats(void)
-{
-    GHashTable *format_map;
-    GSList *formats = gdk_pixbuf_get_formats();
-
-    format_map = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
-    g_slist_foreach(formats, (GFunc)add_if_writable, format_map);
-    g_slist_free (formats);
-
-    return format_map;
-}
-
-static GdkPixbufFormat *get_image_format(const char *filename)
-{
-    static GOnce image_formats_once = G_ONCE_INIT;
-    const char *ext;
-
-    g_once(&image_formats_once, (GThreadFunc)init_image_formats, NULL);
-
-    ext = strrchr(filename, '.');
-    if (ext == NULL)
-        return NULL;
-
-    ext++; /* skip '.' */
-
-    return g_hash_table_lookup(image_formats_once.retval, ext);
-}
-
 static void
-virt_viewer_window_save_screenshot(VirtViewerWindow *self,
-                                   const char *file)
-{
-    VirtViewerWindowPrivate *priv = self->priv;
-    GdkPixbuf *pix = virt_viewer_display_get_pixbuf(VIRT_VIEWER_DISPLAY(priv->display));
-    GdkPixbufFormat *format = get_image_format(file);
-
-    if (format == NULL) {
-        g_debug("unknown file extension, falling back to png");
-        if (!g_str_has_suffix(file, ".png")) {
-            char *png_filename;
-            png_filename = g_strconcat(file, ".png", NULL);
-            gdk_pixbuf_save(pix, png_filename, "png", NULL,
-                            "tEXt::Generator App", PACKAGE, NULL);
-            g_free(png_filename);
-        } else {
-            gdk_pixbuf_save(pix, file, "png", NULL,
-                            "tEXt::Generator App", PACKAGE, NULL);
-        }
-    } else {
-        char *type = gdk_pixbuf_format_get_name(format);
-        g_debug("saving to %s", type);
-        gdk_pixbuf_save(pix, file, type, NULL, NULL);
-        g_free(type);
-    }
-
-    g_object_unref(pix);
-}
-
-G_MODULE_EXPORT void
-virt_viewer_window_menu_file_screenshot(GtkWidget *menu G_GNUC_UNUSED,
-                                        VirtViewerWindow *self)
-{
-    GtkWidget *dialog;
-    VirtViewerWindowPrivate *priv = self->priv;
-    const char *image_dir;
-
-    g_return_if_fail(priv->display != NULL);
-
-    dialog = gtk_file_chooser_dialog_new("Save screenshot",
-                                         NULL,
-                                         GTK_FILE_CHOOSER_ACTION_SAVE,
-                                         _("_Cancel"), GTK_RESPONSE_CANCEL,
-                                         _("_Save"), GTK_RESPONSE_ACCEPT,
-                                         NULL);
-    gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER (dialog), TRUE);
-    gtk_window_set_transient_for(GTK_WINDOW(dialog),
-                                 GTK_WINDOW(self->priv->window));
-    image_dir = g_get_user_special_dir(G_USER_DIRECTORY_PICTURES);
-    if (image_dir != NULL)
-        gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER (dialog), image_dir);
-    gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER (dialog), _("Screenshot"));
-
-    if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
-        char *filename;
-
-        filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (dialog));
-        virt_viewer_window_save_screenshot(self, filename);
-        g_free(filename);
-    }
-
-    gtk_widget_destroy(dialog);
-}
-
-G_MODULE_EXPORT void
-virt_viewer_window_menu_file_usb_device_selection(GtkWidget *menu G_GNUC_UNUSED,
-                                                  VirtViewerWindow *self)
-{
-    virt_viewer_session_usb_device_selection(virt_viewer_app_get_session(self->priv->app),
-                                             GTK_WINDOW(self->priv->window));
-}
-
-G_MODULE_EXPORT void
-virt_viewer_window_menu_file_smartcard_insert(GtkWidget *menu G_GNUC_UNUSED,
-                                              VirtViewerWindow *self)
-{
-    virt_viewer_session_smartcard_insert(virt_viewer_app_get_session(self->priv->app));
-}
-
-G_MODULE_EXPORT void
-virt_viewer_window_menu_file_smartcard_remove(GtkWidget *menu G_GNUC_UNUSED,
-                                              VirtViewerWindow *self)
-{
-    virt_viewer_session_smartcard_remove(virt_viewer_app_get_session(self->priv->app));
-}
-
-G_MODULE_EXPORT void
-virt_viewer_window_menu_view_release_cursor(GtkWidget *menu G_GNUC_UNUSED,
-                                            VirtViewerWindow *self)
-{
-    g_return_if_fail(self->priv->display != NULL);
-    virt_viewer_display_release_cursor(VIRT_VIEWER_DISPLAY(self->priv->display));
-}
-
-G_MODULE_EXPORT void
-virt_viewer_window_menu_help_guest_details(GtkWidget *menu G_GNUC_UNUSED,
-                                           VirtViewerWindow *self)
+virt_viewer_window_menu_view_fullscreen(VirtViewerWindow *self)
 {
-    GtkBuilder *ui = virt_viewer_util_load_ui("virt-viewer-guest-details.ui");
-    char *name = NULL;
-    char *uuid = NULL;
-
-    g_return_if_fail(ui != NULL);
-
-    GtkWidget *dialog = GTK_WIDGET(gtk_builder_get_object(ui, "guestdetailsdialog"));
-    GtkWidget *namelabel = GTK_WIDGET(gtk_builder_get_object(ui, "namevaluelabel"));
-    GtkWidget *guidlabel = GTK_WIDGET(gtk_builder_get_object(ui, "guidvaluelabel"));
-
-    g_return_if_fail(dialog && namelabel && guidlabel);
-
-    g_object_get(self->priv->app, "guest-name", &name, "uuid", &uuid, NULL);
-
-    if (!name || *name == '\0')
-        name = g_strdup(_("Unknown"));
-    if (!uuid || *uuid == '\0')
-        uuid = g_strdup(_("Unknown"));
-    gtk_label_set_text(GTK_LABEL(namelabel), name);
-    gtk_label_set_text(GTK_LABEL(guidlabel), uuid);
-    g_free(name);
-    g_free(uuid);
-
-    gtk_window_set_transient_for(GTK_WINDOW(dialog),
-                                 GTK_WINDOW(self->priv->window));
-
-    gtk_builder_connect_signals(ui, self);
-
-    gtk_widget_show_all(dialog);
-
-    g_object_unref(G_OBJECT(ui));
+    virt_viewer_window_set_fullscreen(self, !self->priv->fullscreen);
 }
 
 G_MODULE_EXPORT void
@@ -1017,41 +1184,6 @@ virt_viewer_window_guest_details_response(GtkDialog *dialog,
 }
 
 static void
-iso_dialog_response(GtkDialog *dialog,
-                    gint response_id,
-                    gpointer user_data G_GNUC_UNUSED)
-{
-    if (response_id == GTK_RESPONSE_NONE)
-        return;
-
-    gtk_widget_destroy(GTK_WIDGET(dialog));
-}
-
-void
-virt_viewer_window_menu_change_cd_activate(GtkWidget *menu G_GNUC_UNUSED,
-                                           VirtViewerWindow *self)
-{
-    VirtViewerWindowPrivate *priv = self->priv;
-    GtkWidget *dialog;
-    GObject *foreign_menu;
-
-    g_object_get(G_OBJECT(priv->app), "ovirt-foreign-menu", &foreign_menu, NULL);
-    dialog = remote_viewer_iso_list_dialog_new(GTK_WINDOW(priv->window), foreign_menu);
-    g_object_unref(foreign_menu);
-
-    if (!dialog)
-        dialog = gtk_message_dialog_new(GTK_WINDOW(priv->window),
-                                        GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
-                                        GTK_MESSAGE_ERROR,
-                                        GTK_BUTTONS_CLOSE,
-                                        _("Unable do connnect to oVirt"));
-
-    g_signal_connect(dialog, "response", G_CALLBACK(iso_dialog_response), NULL);
-    gtk_widget_show_all(dialog);
-    gtk_dialog_run(GTK_DIALOG(dialog));
-}
-
-static void
 virt_viewer_window_toolbar_setup(VirtViewerWindow *self)
 {
     GtkWidget *button;
@@ -1077,7 +1209,7 @@ virt_viewer_window_toolbar_setup(VirtViewerWindow *self)
     gtk_tool_button_set_label(GTK_TOOL_BUTTON(button), _("USB device selection"));
     gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(button), _("USB device selection"));
     gtk_toolbar_insert(GTK_TOOLBAR(priv->toolbar), GTK_TOOL_ITEM(button), 0);
-    g_signal_connect(button, "clicked", G_CALLBACK(virt_viewer_window_menu_file_usb_device_selection), self);
+    g_signal_connect(button, "clicked", G_CALLBACK(usb_device_selection_activated), self);
     priv->toolbar_usb_device_selection = button;
     gtk_widget_show_all(button);
 
@@ -1158,17 +1290,22 @@ virt_viewer_window_update_title(VirtViewerWindow *self)
     VirtViewerWindowPrivate *priv = self->priv;
     char *title;
     gchar *ungrab = NULL;
+    gchar **accels;
 
     if (priv->grabbed) {
         gchar *label;
-        GtkAccelKey key = {0, 0, 0};
+        guint accel_key = 0;
+        GdkModifierType accel_mods = 0;
 
-        if (virt_viewer_app_get_enable_accel(priv->app))
-            gtk_accel_map_lookup_entry("<virt-viewer>/view/release-cursor", &key);
+        if (virt_viewer_app_get_enable_accel(priv->app)){
+            accels = gtk_application_get_accels_for_action(GTK_APPLICATION(priv->app), "win.release-cursor");
+            gtk_accelerator_parse(accels[0], &accel_key, &accel_mods);
+            g_strfreev(accels);
+        }
 
-        if (key.accel_key || key.accel_mods) {
-            g_debug("release-cursor accel key: key=%u, mods=%x, flags=%u", key.accel_key, key.accel_mods, key.accel_flags);
-            label = gtk_accelerator_get_label(key.accel_key, key.accel_mods);
+        if (accel_key || accel_mods) {
+            g_debug("release-cursor accel key: key=%u, mods=%x", accel_key, accel_mods);
+            label = gtk_accelerator_get_label(accel_key, accel_mods);
         } else {
             label = g_strdup(_("Ctrl+Alt"));
         }
@@ -1192,7 +1329,7 @@ virt_viewer_window_update_title(VirtViewerWindow *self)
                                 priv->subtitle,
                                 g_get_application_name());
 
-    gtk_window_set_title(GTK_WINDOW(priv->window), title);
+    gtk_header_bar_set_title(GTK_HEADER_BAR(priv->header), title);
 
     g_free(title);
     g_free(ungrab);
@@ -1207,7 +1344,8 @@ virt_viewer_window_set_menu_displays_sensitive(VirtViewerWindow *self, gboolean
     g_return_if_fail(VIRT_VIEWER_IS_WINDOW(self));
 
     priv = self->priv;
-    menu = GTK_WIDGET(gtk_builder_get_object(priv->builder, "menu-displays"));
+
+    menu = GTK_WIDGET(gtk_builder_get_object(priv->builder, "displays"));
     gtk_widget_set_sensitive(menu, sensitive);
 }
 
@@ -1215,13 +1353,15 @@ void
 virt_viewer_window_set_usb_options_sensitive(VirtViewerWindow *self, gboolean sensitive)
 {
     VirtViewerWindowPrivate *priv;
-    GtkWidget *menu;
+    GAction *action;
 
     g_return_if_fail(VIRT_VIEWER_IS_WINDOW(self));
 
     priv = self->priv;
-    menu = GTK_WIDGET(gtk_builder_get_object(priv->builder, "menu-file-usb-device-selection"));
-    gtk_widget_set_sensitive(menu, sensitive);
+
+    action = g_action_map_lookup_action(G_ACTION_MAP(priv->window), "usb-device-selection");
+    g_simple_action_set_enabled(G_SIMPLE_ACTION(action), sensitive);
+
     gtk_widget_set_visible(priv->toolbar_usb_device_selection, sensitive);
 }
 
@@ -1229,20 +1369,26 @@ void
 virt_viewer_window_set_menus_sensitive(VirtViewerWindow *self, gboolean sensitive)
 {
     VirtViewerWindowPrivate *priv;
-    GtkWidget *menu;
+    GAction *action;
 
     g_return_if_fail(VIRT_VIEWER_IS_WINDOW(self));
 
     priv = self->priv;
 
-    menu = GTK_WIDGET(gtk_builder_get_object(priv->builder, "menu-file-screenshot"));
-    gtk_widget_set_sensitive(menu, sensitive);
+    action = g_action_map_lookup_action(G_ACTION_MAP(priv->window), "screenshot");
+    g_simple_action_set_enabled(G_SIMPLE_ACTION(action), sensitive);
 
-    menu = GTK_WIDGET(gtk_builder_get_object(priv->builder, "menu-view-zoom"));
-    gtk_widget_set_sensitive(menu, sensitive);
+    action = g_action_map_lookup_action(G_ACTION_MAP(priv->window), "zoom-in");
+    g_simple_action_set_enabled(G_SIMPLE_ACTION(action), sensitive);
 
-    menu = GTK_WIDGET(gtk_builder_get_object(priv->builder, "menu-send"));
-    gtk_widget_set_sensitive(menu, sensitive);
+    action = g_action_map_lookup_action(G_ACTION_MAP(priv->window), "zoom-out");
+    g_simple_action_set_enabled(G_SIMPLE_ACTION(action), sensitive);
+
+    action = g_action_map_lookup_action(G_ACTION_MAP(priv->window), "zoom-reset");
+    g_simple_action_set_enabled(G_SIMPLE_ACTION(action), sensitive);
+
+    action = g_action_map_lookup_action(G_ACTION_MAP(priv->window), "guest-details");
+    g_simple_action_set_enabled(G_SIMPLE_ACTION(action), sensitive);
 }
 
 static void
@@ -1260,12 +1406,10 @@ display_show_hint(VirtViewerDisplay *display,
         self->priv->initial_zoom_set = TRUE;
         virt_viewer_window_set_zoom_level(self, self->priv->zoomlevel);
     }
-
-    gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(self->priv->builder, "menu-file-screenshot")), hint);
 }
 static gboolean
 window_key_pressed (GtkWidget *widget G_GNUC_UNUSED,
-                    GdkEvent  *event,
+                    GdkEvent *event,
                     GtkWidget *display)
 {
     gtk_widget_grab_focus(display);
@@ -1322,10 +1466,6 @@ virt_viewer_window_set_display(VirtViewerWindow *self, VirtViewerDisplay *displa
 
         if (virt_viewer_display_get_enabled(display))
             virt_viewer_window_desktop_resize(display, self);
-
-        gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(self->priv->builder, "menu-view-zoom")), TRUE);
-        gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(self->priv->builder, "menu-send")), TRUE);
-        gtk_widget_set_sensitive(self->priv->toolbar_send_key, TRUE);
     }
 }
 
@@ -1421,12 +1561,20 @@ gint virt_viewer_window_get_zoom_level(VirtViewerWindow *self)
     return self->priv->zoomlevel;
 }
 
-GtkMenuItem*
-virt_viewer_window_get_menu_displays(VirtViewerWindow *self)
+GtkMenuButton*
+virt_viewer_window_get_menu_button_displays(VirtViewerWindow *self)
+{
+    g_return_val_if_fail(VIRT_VIEWER_IS_WINDOW(self), NULL);
+
+    return GTK_MENU_BUTTON(gtk_builder_get_object(self->priv->builder, "displays"));
+}
+
+GtkButton*
+virt_viewer_window_get_button_change_cd(VirtViewerWindow *self)
 {
     g_return_val_if_fail(VIRT_VIEWER_IS_WINDOW(self), NULL);
 
-    return GTK_MENU_ITEM(gtk_builder_get_object(self->priv->builder, "menu-displays"));
+    return GTK_BUTTON(gtk_builder_get_object(self->priv->builder, "change-cd"));
 }
 
 GtkBuilder*
@@ -1463,7 +1611,7 @@ virt_viewer_window_set_kiosk(VirtViewerWindow *self, gboolean enabled)
 }
 
 static void
-virt_viewer_window_get_minimal_dimensions(VirtViewerWindow *self,
+virt_viewer_window_get_minimal_dimensions(VirtViewerWindow *self G_GNUC_UNUSED,
                                           guint *width,
                                           guint *height)
 {
diff --git a/src/virt-viewer-window.h b/src/virt-viewer-window.h
index e9aae4b..f578637 100644
--- a/src/virt-viewer-window.h
+++ b/src/virt-viewer-window.h
@@ -78,7 +78,8 @@ void virt_viewer_window_set_zoom_level(VirtViewerWindow *self, gint zoom_level);
 gint virt_viewer_window_get_zoom_level(VirtViewerWindow *self);
 void virt_viewer_window_leave_fullscreen(VirtViewerWindow *self);
 void virt_viewer_window_enter_fullscreen(VirtViewerWindow *self, gint monitor);
-GtkMenuItem *virt_viewer_window_get_menu_displays(VirtViewerWindow *self);
+GtkMenuButton *virt_viewer_window_get_menu_button_displays(VirtViewerWindow *self);
+GtkButton *virt_viewer_window_get_button_change_cd(VirtViewerWindow *self);
 GtkBuilder* virt_viewer_window_get_builder(VirtViewerWindow *window);
 void virt_viewer_window_set_kiosk(VirtViewerWindow *self, gboolean enabled);
 
-- 
2.9.3




More information about the virt-tools-list mailing list