← Back to team overview

lightdm-gtk-greeter-team team mailing list archive

[Merge] lp:~kalgasnik/lightdm-gtk-greeter/screenshot into lp:lightdm-gtk-greeter

 

Andrew P. has proposed merging lp:~kalgasnik/lightdm-gtk-greeter/screenshot into lp:lightdm-gtk-greeter.

Requested reviews:
  LightDM Gtk+ Greeter Development Team (lightdm-gtk-greeter-team)

For more details, see:
https://code.launchpad.net/~kalgasnik/lightdm-gtk-greeter/screenshot/+merge/243143

1. Keyboard accelerators: controlled by greeter without passing them to GtkWindow
   Some old code removed, logic of map/unmap changed.

2. PrintScreen: taking screenshot.
   Option: max-screenshots-count = [integer_value]
value > 0: save only last [value] screenshots and remove old files
-1: allow any count of files in screenshots directory
 0: disable PrintScreen key

Default value: 10.

Path to save files: /var/log/lightdm-gtk-greeter-screenshots or %TMP/lightdm-gtk-greeter-screenshots (if %TMP defined).
-- 
Your team LightDM Gtk+ Greeter Development Team is requested to review the proposed merge of lp:~kalgasnik/lightdm-gtk-greeter/screenshot into lp:lightdm-gtk-greeter.
=== modified file 'src/greeterbackground.c'
--- src/greeterbackground.c	2014-08-31 17:45:52 +0000
+++ src/greeterbackground.c	2014-11-28 11:56:32 +0000
@@ -108,8 +108,6 @@
 
     /* Widget to display on active monitor */
     GtkWidget* child;
-    /* List of groups <GtkAccelGroup*> for greeter screens windows */
-    GSList* accel_groups;
 
     /* Mapping monitor name <gchar*> to its config <MonitorConfig*> */
     GHashTable* configs;
@@ -284,7 +282,6 @@
     self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, GREETER_BACKGROUND_TYPE, GreeterBackgroundPrivate);
     self->priv->screen = NULL;
     self->priv->screen_monitors_changed_handler_id = 0;
-    self->priv->accel_groups = NULL;
 
     self->priv->configs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)monitor_config_free);
     self->priv->default_config = monitor_config_copy(&DEFAULT_MONITOR_CONFIG, NULL);
@@ -302,7 +299,7 @@
     self->priv->laptop_lid_closed = FALSE;
 }
 
-GreeterBackground* 
+GreeterBackground*
 greeter_background_new(GtkWidget* child)
 {
     GreeterBackground* background = GREETER_BACKGROUND(g_object_new(greeter_background_get_type(), NULL));
@@ -489,9 +486,6 @@
         monitor->window_draw_handler_id = g_signal_connect(G_OBJECT(monitor->window), "draw",
                                                            G_CALLBACK(monitor_window_draw_cb),
                                                            monitor);
-        GSList* item;
-        for(item = priv->accel_groups; item != NULL; item = g_slist_next(item))
-            gtk_window_add_accel_group(monitor->window, item->data);
 
         if(priv->follow_cursor)
             g_signal_connect(G_OBJECT(monitor->window), "enter-notify-event",
@@ -859,25 +853,6 @@
     return priv->active_monitor ? &priv->active_monitor->geometry : NULL;
 }
 
-void
-greeter_background_add_accel_group(GreeterBackground* background,
-                                   GtkAccelGroup* group)
-{
-    g_return_if_fail(GREETER_IS_BACKGROUND(background));
-    g_return_if_fail(group != NULL);
-    GreeterBackgroundPrivate* priv = background->priv;
-
-    if(priv->monitors)
-    {
-        gint i;
-        for(i = 0; i < priv->monitors_size; ++i)
-            if(priv->monitors[i].window)
-                gtk_window_add_accel_group(priv->monitors[i].window, group);
-    }
-
-    priv->accel_groups = g_slist_append(priv->accel_groups, group);
-}
-
 static gboolean
 background_config_initialize(BackgroundConfig* config,
                              const gchar* value)
@@ -904,7 +879,7 @@
             config->options.image.mode = SCALING_MODE_ZOOMED;
 
         config->options.image.path = g_strdup(value);
-        config->type = BACKGROUND_TYPE_IMAGE;        
+        config->type = BACKGROUND_TYPE_IMAGE;
     }
     return TRUE;
 }
@@ -1165,7 +1140,7 @@
                    Display* display,
                    Pixmap xpixmap)
 {
-    
+
     Window xroot = RootWindow (display, gdk_screen_get_number (screen));
     char *atom_names[] = {"_XROOTPMAP_ID", "ESETROOT_PMAP_ID"};
     Atom atoms[G_N_ELEMENTS(atom_names)] = {0};

=== modified file 'src/greeterbackground.h'
--- src/greeterbackground.h	2014-08-31 17:45:52 +0000
+++ src/greeterbackground.h	2014-11-28 11:56:32 +0000
@@ -38,8 +38,6 @@
                                                      const gchar* path);
 void greeter_background_save_xroot                  (GreeterBackground* background);
 const GdkRectangle* greeter_background_get_active_monitor_geometry(GreeterBackground* background);
-void greeter_background_add_accel_group             (GreeterBackground* background,
-                                                     GtkAccelGroup* group);
 
 G_END_DECLS
 

=== modified file 'src/lightdm-gtk-greeter-fallback.css'
--- src/lightdm-gtk-greeter-fallback.css	2014-05-22 19:52:34 +0000
+++ src/lightdm-gtk-greeter-fallback.css	2014-11-28 11:56:32 +0000
@@ -10,3 +10,14 @@
 {
   padding: 1px;
 }
+
+/* Used as "screen-capture" effect */
+#capture-splash.capture-triggered
+{
+    background: alpha(@theme_base_color, 0.5);
+}
+
+#screen
+{
+    background: transparent;
+}

=== modified file 'src/lightdm-gtk-greeter.c'
--- src/lightdm-gtk-greeter.c	2014-09-01 07:58:56 +0000
+++ src/lightdm-gtk-greeter.c	2014-11-28 11:56:32 +0000
@@ -63,6 +63,7 @@
 
 /* Screen window */
 static GtkOverlay *screen_overlay;
+static GtkAccelGroup *greeter_accel_group;
 
 /* Login window */
 static GtkWidget    *login_window;
@@ -76,9 +77,10 @@
 /* Panel */
 static GtkWidget    *panel_window, *menubar;
 static GtkWidget    *power_menuitem, *session_menuitem, *language_menuitem, *a11y_menuitem,
-                    *layout_menuitem, *clock_menuitem, *host_menuitem;
+                    *layout_menuitem, *clock_menuitem, *host_menuitem, *tools_menuitem;
 static GtkWidget    *suspend_menuitem, *hibernate_menuitem, *restart_menuitem, *shutdown_menuitem;
 static GtkWidget    *contrast_menuitem, *font_menuitem, *keyboard_menuitem, *reader_menuitem;
+static GtkWidget    *screenshot_menuitem;
 static GtkWidget    *clock_label, *session_badge;
 static GtkMenu      *session_menu, *language_menu, *layout_menu;
 
@@ -278,6 +280,18 @@
 void a11y_keyboard_cb (GtkCheckMenuItem *item, gpointer user_data);
 void a11y_reader_cb (GtkCheckMenuItem *item, gpointer user_data);
 
+/* Screen capture */
+static const gint SCREENSHOT_BLINK_DURATION = 300;  /* Duration (in ms) of "screen capture" effect */
+static const gint SCREENSHOT_DEFAULT_MAX_COUNT = 10;
+
+static GtkWidget *screenshot_splash_widget = NULL;
+static guint screenshot_splash_finish_id = 0;
+
+static gint screenshot_max_count;
+void tools_screenshot_cb (GtkWidget *menuitem, gpointer userdata);
+static gint compare_file_info_dates (GFileInfo *a_info, GFileInfo *b_info);
+static gboolean take_screenshot (gint max_files_count);
+
 /* Power indciator */
 static void power_menu_cb (GtkWidget *menuitem, gpointer userdata);
 void suspend_cb (GtkWidget *widget, LightDMGreeter *greeter);
@@ -1345,6 +1359,7 @@
     g_hash_table_insert (builtin_items, "~layout", layout_menuitem);
     g_hash_table_insert (builtin_items, "~host", host_menuitem);
     g_hash_table_insert (builtin_items, "~clock", clock_menuitem);
+    g_hash_table_insert (builtin_items, "~tools", tools_menuitem);
 
     g_hash_table_iter_init (&iter, builtin_items);
     while (g_hash_table_iter_next (&iter, NULL, &iter_value))
@@ -1717,6 +1732,192 @@
         menu_command_stop (a11y_reader_command);
 }
 
+/* Taking screenshot */
+
+static gboolean
+screenshot_splash_timeout_cb (gpointer user_data)
+{
+    gtk_widget_hide (screenshot_splash_widget);
+    gtk_style_context_remove_class (gtk_widget_get_style_context (screenshot_splash_widget), "capture-triggered");
+    screenshot_splash_finish_id = 0;
+    return G_SOURCE_REMOVE;
+}
+
+void
+tools_screenshot_cb (GtkWidget *menuitem, gpointer userdata)
+{
+    if (screenshot_max_count == 0)
+        return;
+
+    if (take_screenshot (screenshot_max_count))
+    {
+        /* TODO: Playing "capture" sound */
+
+        if (!screenshot_splash_widget)
+        {
+            screenshot_splash_widget = gtk_event_box_new ();
+            gtk_widget_set_name (screenshot_splash_widget, "capture-splash");
+            gtk_event_box_set_visible_window (GTK_EVENT_BOX (screenshot_splash_widget), TRUE);
+            gtk_overlay_add_overlay (screen_overlay, screenshot_splash_widget);
+        }
+
+        if (!screenshot_splash_finish_id)
+        {
+            gtk_widget_show (screenshot_splash_widget);
+            gtk_style_context_add_class (gtk_widget_get_style_context (screenshot_splash_widget), "capture-triggered");
+            screenshot_splash_finish_id = g_timeout_add (SCREENSHOT_BLINK_DURATION, screenshot_splash_timeout_cb, NULL);
+        }
+    }
+    else
+    {
+        /* TODO: Playing "error" sound */
+    }
+}
+
+static gint
+compare_file_info_dates (GFileInfo *a_info, GFileInfo *b_info)
+{
+    guint64 a = g_file_info_get_attribute_uint64 (a_info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
+    guint64 b = g_file_info_get_attribute_uint64 (b_info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
+    return a < b ? -1 : a == b ? 0 : +1;
+}
+
+static gboolean
+take_screenshot (gint max_files_count)
+{
+    g_debug ("[Screenshot] Taking screenshot...");
+
+    if (max_files_count == 0)
+    {
+        g_debug ("[Screenshot] Aborting: max_files_count == 0");
+        return FALSE;
+    }
+
+    const gchar *tmp_dir_variable = g_getenv ("TMPDIR");
+    gchar *output_dir;
+    GError *error = NULL;
+    gboolean failed = FALSE;
+
+    const gint SCREENSHOT_DIR_MODE = 0700;
+    const gchar *SCREENSHOT_DIR_NAME = "lightdm-gtk-greeter-screenshots";
+
+    if (tmp_dir_variable)
+        output_dir = g_build_filename (tmp_dir_variable, SCREENSHOT_DIR_NAME, NULL);
+    else
+        /* "/var/tmp" is usually more persistent than "/tmp" */
+        output_dir = g_build_filename (G_DIR_SEPARATOR_S, "var", "tmp", SCREENSHOT_DIR_NAME, NULL);
+
+    if (g_mkdir_with_parents (output_dir, SCREENSHOT_DIR_MODE) == -1)
+    {
+        g_warning ("[Screenshot] Failed to create directory '%s': %s", output_dir, g_strerror (errno));
+        g_free (output_dir);
+        return FALSE;
+    }
+
+    GDateTime *now = g_date_time_new_now_local ();
+    gchar *output_name = now ? g_date_time_format (now, "screenshot_%F_%T.png") : g_strdup ("screenshot.png");
+    g_date_time_unref (now);
+
+    if (max_files_count > 0)
+    {
+        GFileEnumerator *enumerator;
+        GFile *parent = g_file_new_for_path (output_dir);
+        enumerator = g_file_enumerate_children (parent,
+                                                G_FILE_ATTRIBUTE_STANDARD_TYPE ","
+                                                G_FILE_ATTRIBUTE_STANDARD_NAME ","
+                                                G_FILE_ATTRIBUTE_TIME_MODIFIED,
+                                                G_FILE_QUERY_INFO_NONE,
+                                                NULL, &error);
+
+        if (!enumerator)
+        {
+            g_warning ("[Screenshot] Failed to enumerate screenshots directory: %s", error ? error->message : "unknown error");
+            g_clear_error (&error);
+            g_object_unref (parent);
+            g_free (output_name);
+            g_free (output_dir);
+            return FALSE;
+        }
+
+        gint files_count = 0;
+        GList *files = NULL;
+        GFileInfo *info;
+
+        while ((info = g_file_enumerator_next_file (enumerator, NULL, &error)))
+        {
+            if (g_file_info_get_file_type (info) == G_FILE_TYPE_REGULAR &&
+                g_strcmp0 (g_file_info_get_name (info), output_name) != 0)
+            {
+                files = g_list_prepend (files, info);
+                files_count++;
+            }
+            else
+                g_object_unref (info);
+        }
+        g_file_enumerator_close (enumerator, NULL, NULL);
+        g_object_unref (enumerator);
+
+        g_debug ("[Screenshot] Directory items count: %d, limit: %d", files_count, max_files_count);
+
+        if (files_count >= max_files_count)
+        {
+            GList *iter;
+            files = g_list_sort (files, (GCompareFunc)compare_file_info_dates);
+
+            for (iter = g_list_nth (files, files_count - max_files_count); iter && !failed; iter = g_list_previous (iter))
+            {
+                GFile *file = g_file_get_child (parent, g_file_info_get_name (iter->data));
+                if (!g_file_delete (file, NULL, &error))
+                {
+                    g_warning ("[Screenshot] Failed to delete old screenshot '%s': %s",
+                               g_file_info_get_name (iter->data),
+                               error ? error->message : "unknown error");
+                    g_clear_error (&error);
+                    failed = TRUE;
+                }
+                g_object_unref (file);
+            }
+        }
+        g_list_free_full (files, g_object_unref);
+        g_object_unref (parent);
+
+        if (failed)
+        {
+            g_free (output_name);
+            g_free (output_dir);
+            return FALSE;
+        }
+    }
+
+    /* Finally, taking screenshot */
+
+    GdkWindow *root = gdk_get_default_root_window ();
+    GdkPixbuf *screenshot = gdk_pixbuf_get_from_window (root, 0, 0, gdk_window_get_width (root), gdk_window_get_height (root));
+
+    if (!screenshot)
+        g_warning ("[Screenshot] gdk_pixbuf_get_from_window failed");
+    else
+    {
+        gchar *output_path = g_build_filename (output_dir, output_name, NULL);
+        if (!gdk_pixbuf_save (screenshot, output_path, "png", &error, NULL))
+        {
+            g_warning ("[Screenshot] Failed to save image as '%s': %s", output_path, error ? error->message : "unknown error");
+            g_clear_error (&error);
+            failed = TRUE;
+        }
+        else
+            g_debug ("[Screenshot] Image saved as '%s'", output_path);
+
+        g_object_unref (screenshot);
+        g_free (output_path);
+    }
+
+    g_free (output_name);
+    g_free (output_dir);
+
+    return screenshot && !failed;
+}
+
 /* Power indicator */
 
 static void
@@ -2400,32 +2601,25 @@
 }
 
 static GdkFilterReturn
-focus_upon_map (GdkXEvent *gxevent, GdkEvent *event, gpointer  data)
+wm_window_filter (GdkXEvent *gxevent, GdkEvent *event, gpointer  data)
 {
     XEvent* xevent = (XEvent*)gxevent;
-    GdkWindow* keyboard_win = a11y_keyboard_command && a11y_keyboard_command->widget ?
-                                    gtk_widget_get_window (GTK_WIDGET (a11y_keyboard_command->widget)) : NULL;
     if (xevent->type == MapNotify)
     {
-        Window xwin = xevent->xmap.window;
-        Window keyboard_xid = 0;
-        GdkDisplay* display = gdk_x11_lookup_xdisplay (xevent->xmap.display);
-        GdkWindow* win = gdk_x11_window_foreign_new_for_display (display, xwin);
+        GdkDisplay *display = gdk_x11_lookup_xdisplay (xevent->xmap.display);
+        GdkWindow *win = gdk_x11_window_foreign_new_for_display (display, xevent->xmap.window);
         GdkWindowTypeHint win_type = gdk_window_get_type_hint (win);
 
-        /* Check to see if this window is our onboard window, since we don't want to focus it. */
-        if (keyboard_win)
-            keyboard_xid = gdk_x11_window_get_xid (keyboard_win);
-
-        if (xwin != keyboard_xid
-            && win_type != GDK_WINDOW_TYPE_HINT_TOOLTIP
-            && win_type != GDK_WINDOW_TYPE_HINT_NOTIFICATION)
-        {
+/*        if (win_type != GDK_WINDOW_TYPE_HINT_COMBO &&
+            win_type != GDK_WINDOW_TYPE_HINT_MENU &&
+            win_type != GDK_WINDOW_TYPE_HINT_POPUP_MENU &&
+            win_type != GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU &&
+            win_type != GDK_WINDOW_TYPE_HINT_TOOLTIP &&
+            win_type != GDK_WINDOW_TYPE_HINT_NOTIFICATION)
+*/
+        if (win_type == GDK_WINDOW_TYPE_HINT_DESKTOP ||
+            win_type == GDK_WINDOW_TYPE_HINT_DIALOG)
             gdk_window_focus (win, GDK_CURRENT_TIME);
-            /* Make sure to keep keyboard above */
-            if (keyboard_win)
-                gdk_window_raise (keyboard_win);
-        }
     }
     else if (xevent->type == UnmapNotify)
     {
@@ -2434,12 +2628,25 @@
         XGetInputFocus (xevent->xunmap.display, &xwin, &revert_to);
 
         if (revert_to == RevertToNone)
-        {
-            gdk_window_focus (gtk_widget_get_window (GTK_WIDGET (login_window)), GDK_CURRENT_TIME);
-            /* Make sure to keep keyboard above */
-            if (keyboard_win)
-                gdk_window_raise (keyboard_win);
-        }
+            gdk_window_focus (gtk_widget_get_window (GTK_WIDGET (screen_overlay)), GDK_CURRENT_TIME);
+    }
+    return GDK_FILTER_CONTINUE;
+}
+
+static GdkFilterReturn
+accelerators_window_filter (GdkXEvent *gxevent, GdkEvent *event, gpointer data)
+{
+    XKeyEvent* keyevent = (XKeyEvent*)gxevent;
+    if (keyevent->type == KeyPress)
+    {
+        KeySym accel_key = XLookupKeysym (keyevent, 0);
+        GdkModifierType accel_mods = keyevent->state & ~(Mod2Mask | Mod5Mask | LockMask);
+        gchar *accel_name = gtk_accelerator_name (accel_key, (accel_mods & gtk_accelerator_get_default_mod_mask ()));
+        GQuark accel_quark = g_quark_from_string (accel_name);
+        g_free (accel_name);
+
+        if (gtk_accel_group_activate (greeter_accel_group, accel_quark, G_OBJECT (screen_overlay), accel_key, accel_mods))
+            return GDK_FILTER_REMOVE;
     }
     return GDK_FILTER_CONTINUE;
 }
@@ -2590,6 +2797,7 @@
 
     /* Screen window */
     screen_overlay = GTK_OVERLAY (gtk_builder_get_object (builder, "screen_overlay"));
+    greeter_accel_group = GTK_ACCEL_GROUP (gtk_builder_get_object (builder, "greeter_accel_group"));
 
     /* Login window */
     login_window = GTK_WIDGET (gtk_builder_get_object (builder, "login_window"));
@@ -2605,18 +2813,27 @@
     /* Panel window*/
     panel_window = GTK_WIDGET (gtk_builder_get_object (builder, "panel_window"));
     menubar = GTK_WIDGET (gtk_builder_get_object (builder, "menubar"));
+
     session_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "session_menuitem"));
     session_menu = GTK_MENU (gtk_builder_get_object (builder, "session_menu"));
+
     language_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "language_menuitem"));
     language_menu = GTK_MENU (gtk_builder_get_object (builder, "language_menu"));
+
     a11y_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "a11y_menuitem"));
     contrast_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "high_contrast_menuitem"));
     font_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "large_font_menuitem"));
     keyboard_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "keyboard_menuitem"));
     reader_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "reader_menuitem"));
+
     power_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "power_menuitem"));
+
     layout_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "layout_menuitem"));
     layout_menu = GTK_MENU (gtk_builder_get_object (builder, "layout_menu"));
+
+    tools_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "tools_menuitem"));
+    screenshot_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "screenshot_menuitem"));
+
     clock_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "clock_menuitem"));
     host_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "host_menuitem"));
 
@@ -2637,6 +2854,7 @@
     gtk_accel_map_add_entry ("<Login>/a11y/keyboard", GDK_KEY_F3, 0);
     gtk_accel_map_add_entry ("<Login>/a11y/reader", GDK_KEY_F4, 0);
     gtk_accel_map_add_entry ("<Login>/power/shutdown", GDK_KEY_F4, GDK_MOD1_MASK);
+    gtk_accel_map_add_entry ("<Login>/tools/screenshot", GDK_KEY_Print, 0);
 
 #ifdef START_INDICATOR_SERVICES
     init_indicators (config, &indicator_pid, &spi_pid);
@@ -2829,6 +3047,17 @@
         gdk_threads_add_timeout (1000, (GSourceFunc) clock_timeout_thread, NULL);
     }
 
+    /* Screen capture */
+    screenshot_max_count = g_key_file_get_integer (config, "greeter", "max-screenshots-count", &error);
+    if (error)
+    {
+        if (error->code == G_KEY_FILE_ERROR_INVALID_VALUE)
+            g_warning ("[Configuration] Invalid 'max-screenshots-count' value, using default: %d", SCREENSHOT_DEFAULT_MAX_COUNT);
+        screenshot_max_count = SCREENSHOT_DEFAULT_MAX_COUNT;
+        g_clear_error (&error);
+    }
+    gtk_widget_set_visible (screenshot_menuitem, screenshot_max_count != 0);
+
     /* A bit of CSS */
     GdkRGBA lightdm_gtk_greeter_override_defaults;
     css_provider = gtk_css_provider_new ();
@@ -2885,9 +3114,6 @@
     }
     g_strfreev (config_groups);
 
-    greeter_background_add_accel_group (greeter_background, GTK_ACCEL_GROUP (gtk_builder_get_object (builder, "a11y_accelgroup")));
-    greeter_background_add_accel_group (greeter_background, GTK_ACCEL_GROUP (gtk_builder_get_object (builder, "power_accelgroup")));
-
     greeter_background_connect (greeter_background, gdk_screen_get_default ());
 
     if (lightdm_greeter_get_hide_users_hint (greeter))
@@ -2956,10 +3182,12 @@
     }
     g_strfreev (values);
 
-    /* focus fix (source: unity-greeter) */
-    GdkWindow* root_window = gdk_get_default_root_window ();
+    GdkWindow *root_window = gdk_get_default_root_window ();
     gdk_window_set_events (root_window, gdk_window_get_events (root_window) | GDK_SUBSTRUCTURE_MASK);
-    gdk_window_add_filter (root_window, focus_upon_map, NULL);
+    /* There is no window manager, so we need to implement some of its functionality */
+    gdk_window_add_filter (root_window, wm_window_filter, NULL);
+    /* Use "manual" accelerators control instead of passing accel groups to GreeterBackground's windows */
+    gdk_window_add_filter (gtk_widget_get_window (GTK_WIDGET (screen_overlay)), accelerators_window_filter, NULL);
 
     gtk_widget_show (GTK_WIDGET (screen_overlay));
 

=== modified file 'src/lightdm-gtk-greeter.glade'
--- src/lightdm-gtk-greeter.glade	2014-09-24 17:41:33 +0000
+++ src/lightdm-gtk-greeter.glade	2014-11-28 11:56:32 +0000
@@ -1,10 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!-- Generated with glade 3.18.3 -->
 <interface>
-  <requires lib="gtk+" version="3.4"/>
+  <requires lib="gtk+" version="3.8"/>
   <requires lib="greeter_menu_bar" version="1.0"/>
-  <object class="GtkAccelGroup" id="a11y_accelgroup"/>
-  <object class="GtkAccelGroup" id="power_accelgroup"/>
+  <object class="GtkAccelGroup" id="greeter_accel_group"/>
   <object class="GtkEventBox" id="panel_window">
     <property name="name">panel_window</property>
     <property name="visible">True</property>
@@ -26,12 +25,13 @@
               <object class="GtkMenu" id="power_menu">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="accel_group">power_accelgroup</property>
+                <property name="accel_group">greeter_accel_group</property>
                 <child>
                   <object class="GtkMenuItem" id="suspend_menuitem">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
                     <property name="label" translatable="yes">Suspend</property>
+                    <property name="use_underline">True</property>
                     <signal name="activate" handler="suspend_cb" swapped="no"/>
                   </object>
                 </child>
@@ -40,6 +40,7 @@
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
                     <property name="label" translatable="yes">Hibernate</property>
+                    <property name="use_underline">True</property>
                     <signal name="activate" handler="hibernate_cb" swapped="no"/>
                   </object>
                 </child>
@@ -48,16 +49,17 @@
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
                     <property name="label" translatable="yes">Restart...</property>
+                    <property name="use_underline">True</property>
                     <signal name="activate" handler="restart_cb" swapped="no"/>
                   </object>
                 </child>
                 <child>
                   <object class="GtkMenuItem" id="shutdown_menuitem">
-                    <property name="use_action_appearance">False</property>
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
                     <property name="accel_path">&lt;Login&gt;/power/shutdown</property>
                     <property name="label" translatable="yes">Shut Down...</property>
+                    <property name="use_underline">True</property>
                     <signal name="activate" handler="shutdown_cb" swapped="no"/>
                   </object>
                 </child>
@@ -74,30 +76,29 @@
               <object class="GtkMenu" id="a11y_menu">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="accel_group">a11y_accelgroup</property>
+                <property name="accel_group">greeter_accel_group</property>
                 <child>
                   <object class="GtkCheckMenuItem" id="large_font_menuitem">
-                    <property name="use_action_appearance">False</property>
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
                     <property name="accel_path">&lt;Login&gt;/a11y/font</property>
                     <property name="label" translatable="yes">Large Font</property>
+                    <property name="use_underline">True</property>
                     <signal name="toggled" handler="a11y_font_cb" swapped="no"/>
                   </object>
                 </child>
                 <child>
                   <object class="GtkCheckMenuItem" id="high_contrast_menuitem">
-                    <property name="use_action_appearance">False</property>
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
                     <property name="accel_path">&lt;Login&gt;/a11y/contrast</property>
                     <property name="label" translatable="yes">High Contrast</property>
+                    <property name="use_underline">True</property>
                     <signal name="toggled" handler="a11y_contrast_cb" swapped="no"/>
                   </object>
                 </child>
                 <child>
                   <object class="GtkCheckMenuItem" id="keyboard_menuitem">
-                    <property name="use_action_appearance">False</property>
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
                     <property name="accel_path">&lt;Login&gt;/a11y/keyboard</property>
@@ -108,7 +109,6 @@
                 </child>
                 <child>
                   <object class="GtkCheckMenuItem" id="reader_menuitem">
-                    <property name="use_action_appearance">False</property>
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
                     <property name="accel_path">&lt;Login&gt;/a11y/reader</property>
@@ -126,7 +126,6 @@
             <property name="name">language_menuitem</property>
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="label">[language_code]</property>
             <child type="submenu">
               <object class="GtkMenu" id="language_menu">
                 <property name="visible">True</property>
@@ -153,7 +152,6 @@
             <property name="name">layout_menuitem</property>
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="label">[layout]</property>
             <child type="submenu">
               <object class="GtkMenu" id="layout_menu">
                 <property name="visible">True</property>
@@ -163,6 +161,30 @@
           </object>
         </child>
         <child>
+          <object class="GtkMenuItem" id="tools_menuitem">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="use_underline">True</property>
+            <child type="submenu">
+              <object class="GtkMenu" id="tools_menu">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="accel_group">greeter_accel_group</property>
+                <child>
+                  <object class="GtkMenuItem" id="screenshot_menuitem">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="accel_path">&lt;Login&gt;/tools/screenshot</property>
+                    <property name="label" translatable="yes">Take screenshot</property>
+                    <property name="use_underline">True</property>
+                    <signal name="activate" handler="tools_screenshot_cb" swapped="no"/>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
           <object class="GtkSeparatorMenuItem" id="clock_menuitem">
             <property name="name">clock_menuitem</property>
             <property name="can_focus">False</property>
@@ -219,6 +241,7 @@
                   <packing>
                     <property name="left_attach">0</property>
                     <property name="top_attach">0</property>
+                    <property name="width">1</property>
                     <property name="height">2</property>
                   </packing>
                 </child>
@@ -237,6 +260,8 @@
                   <packing>
                     <property name="left_attach">1</property>
                     <property name="top_attach">0</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
                   </packing>
                 </child>
                 <child>
@@ -250,6 +275,8 @@
                   <packing>
                     <property name="left_attach">1</property>
                     <property name="top_attach">1</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
                   </packing>
                 </child>
               </object>
@@ -328,10 +355,11 @@
     <property name="vexpand">True</property>
     <signal name="get-child-position" handler="screen_overlay_get_child_position_cb" swapped="no"/>
     <child>
-      <object class="GtkBox" id="screen-child">
+      <object class="GtkEventBox" id="screen-child">
+        <property name="name">screen-child</property>
         <property name="visible">True</property>
         <property name="can_focus">False</property>
-        <property name="orientation">vertical</property>
+        <property name="visible_window">False</property>
         <child>
           <placeholder/>
         </child>
@@ -401,6 +429,7 @@
                   <packing>
                     <property name="left_attach">0</property>
                     <property name="top_attach">0</property>
+                    <property name="width">1</property>
                     <property name="height">3</property>
                   </packing>
                 </child>
@@ -426,6 +455,8 @@
                   <packing>
                     <property name="left_attach">1</property>
                     <property name="top_attach">0</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
                   </packing>
                 </child>
                 <child>
@@ -442,6 +473,8 @@
                   <packing>
                     <property name="left_attach">1</property>
                     <property name="top_attach">1</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
                   </packing>
                 </child>
                 <child>
@@ -463,6 +496,8 @@
                   <packing>
                     <property name="left_attach">1</property>
                     <property name="top_attach">2</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
                   </packing>
                 </child>
               </object>


Follow ups