← Back to team overview

lightdm-gtk-greeter-team team mailing list archive

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

 

Andrew P. has proposed merging lp:~kalgasnik/lightdm-gtk-greeter/post-2.0.0 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/post-2.0.0/+merge/251694

1. Greeter can go to infinite loop at launch when used with two monitors in mirrored mode and active-monitor=#cursor
http://ubuntuforums.org/showthread.php?t=2267474
https://bugs.archlinux.org/task/43999

2. gtk_widget_reparent marked as deprecated in 3.14 but gtk_container_remove/add is not equal replacement if widget contains GtkPlug.
gtk_widget_replacement used in greeter to move screen_overlay from on monitor window to another.
Looks like remove/add leaves GtkPlug in invalid state.

http://i.imgur.com/E7BtTRx.png
http://i.imgur.com/dlvjay5.png

3. Sending "WM_TAKE_FOCUS" to active monitor window, "onboard" just doesn't work in xembed mode without it.
-- 
Your team LightDM Gtk+ Greeter Development Team is requested to review the proposed merge of lp:~kalgasnik/lightdm-gtk-greeter/post-2.0.0 into lp:lightdm-gtk-greeter.
=== modified file 'src/greeterbackground.c'
--- src/greeterbackground.c	2014-12-10 07:59:02 +0000
+++ src/greeterbackground.c	2015-03-04 07:33:32 +0000
@@ -58,7 +58,7 @@
 } BackgroundConfig;
 
 /* Transition configuration
-   Used to as part of <MonitorConfig> and <Monitor> */
+   Used as part of <MonitorConfig> and <Monitor> */
 typedef struct
 {
     /* Transition duration, in ms */
@@ -177,9 +177,6 @@
     gboolean follow_cursor;
     /* Use cursor position to determinate initial active monitor */
     gboolean follow_cursor_to_init;
-
-    /* Name => transition function, inited in set_monitor_config() */
-    GHashTable* transition_types;
 };
 
 enum
@@ -296,7 +293,7 @@
 static void set_surface_as_root                     (GdkScreen* screen,
                                                      cairo_surface_t* surface);
 static gdouble transition_func_linear               (gdouble x);
-static gdouble transition_func_easy_in_out          (gdouble x);
+static gdouble transition_func_ease_in_out          (gdouble x);
 
 /* Implemented in lightdm-gtk-greeter.c */
 gpointer greeter_save_focus(GtkWidget* widget);
@@ -317,7 +314,7 @@
     .transition =
     {
         .duration = 500,
-        .func = transition_func_easy_in_out,
+        .func = transition_func_ease_in_out,
         .draw = (TransitionDraw)monitor_transition_draw_alpha
     }
 };
@@ -434,14 +431,13 @@
 
     if(transition_type)
     {
-        if(!priv->transition_types)
-        {
-            priv->transition_types = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
-            g_hash_table_insert(priv->transition_types, g_strdup("none"), NULL);
-            g_hash_table_insert(priv->transition_types, g_strdup("linear"), transition_func_linear);
-            g_hash_table_insert(priv->transition_types, g_strdup("easy-in-out"), transition_func_easy_in_out);
-        }
-        if(!g_hash_table_lookup_extended(priv->transition_types, transition_type, NULL, (gpointer*)&config->transition.func))
+        if(g_strcmp0(transition_type, "none") == 0)
+            config->transition.func = NULL;
+        else if(g_strcmp0(transition_type, "ease-in-out") == 0)
+            config->transition.func = transition_func_ease_in_out;
+        else if(g_strcmp0(transition_type, "linear") == 0)
+            config->transition.func = transition_func_linear;
+        else
         {
             g_warning("[Background] Invalid transition type for '%s' monitor: '%s'. Using fallback value.",
                       name, transition_type);
@@ -495,12 +491,18 @@
     g_return_if_fail(GREETER_IS_BACKGROUND(background));
     g_return_if_fail(GDK_IS_SCREEN(screen));
 
-    g_debug("[Background] Connecting to screen: %p", screen);
+    g_debug("[Background] Connecting to screen: %p (%dx%dpx, %dx%dmm)", screen,
+            gdk_screen_get_width(screen), gdk_screen_get_height(screen),
+            gdk_screen_get_width_mm(screen), gdk_screen_get_height_mm(screen));
 
     GreeterBackgroundPrivate* priv = background->priv;
-
+    gpointer saved_focus = NULL;
     if(priv->screen)
+    {
+        if (priv->active_monitor)
+            saved_focus = greeter_save_focus(priv->child);
         greeter_background_disconnect(background);
+    }
 
     priv->screen = screen;
     priv->monitors_size = gdk_screen_get_n_monitors(screen);
@@ -513,7 +515,9 @@
     Monitor* first_not_skipped_monitor = NULL;
 
     GHashTable* images_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+    cairo_region_t *screen_region = cairo_region_create();
     gint i;
+
     for(i = 0; i < priv->monitors_size; ++i)
     {
         const MonitorConfig* config;
@@ -553,6 +557,15 @@
                 config = &DEFAULT_MONITOR_CONFIG;
         }
 
+        /* Simple check to skip fully overlapped monitors.
+           Actually, it's can track only monitors in "mirrors" mode. Nothing more. */
+        if(cairo_region_contains_rectangle(screen_region, &monitor->geometry) == CAIRO_REGION_OVERLAP_IN)
+        {
+            g_debug("[Background] Skipping monitor %s #%d, its area is already used by other monitors", printable_name, i);
+            continue;
+        }
+        cairo_region_union_rectangle(screen_region, &monitor->geometry);
+
         if(!first_not_skipped_monitor)
             first_not_skipped_monitor = monitor;
 
@@ -578,9 +591,8 @@
         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",
-                             G_CALLBACK(monitor_window_enter_notify_cb), monitor);
+        g_signal_connect(G_OBJECT(monitor->window), "enter-notify-event",
+                         G_CALLBACK(monitor_window_enter_notify_cb), monitor);
 
         if(config->user_bg)
             priv->customized_monitors = g_slist_prepend(priv->customized_monitors, monitor);
@@ -624,9 +636,16 @@
             }
         }
     }
+
     if(!priv->active_monitor)
         greeter_background_set_active_monitor(background, NULL);
 
+    if(saved_focus)
+    {
+        greeter_restore_focus(saved_focus);
+        g_free(saved_focus);
+    }
+
     priv->screen_monitors_changed_handler_id = g_signal_connect(G_OBJECT(screen), "monitors-changed",
                                                                 G_CALLBACK(greeter_background_monitors_changed_cb),
                                                                 background);
@@ -768,8 +787,9 @@
         gpointer focus = greeter_save_focus(priv->child);
 
         if(old_parent)
-            gtk_container_remove(GTK_CONTAINER(old_parent), priv->child);
-        gtk_container_add(GTK_CONTAINER(active->window), priv->child);
+            gtk_widget_reparent(priv->child, GTK_WIDGET(active->window));
+        else
+            gtk_container_add(GTK_CONTAINER(active->window), priv->child);
 
         gtk_window_present(active->window);
         greeter_restore_focus(focus);
@@ -1393,8 +1413,30 @@
                                GdkEventCrossing* event,
                                const Monitor* monitor)
 {
-    if(monitor->object->priv->active_monitor != monitor &&
-       greeter_background_monitor_enabled(monitor->object, monitor))
+    if(monitor->object->priv->active_monitor == monitor)
+    {
+        GdkWindow *gdkwindow = gtk_widget_get_window (widget);
+        Window window = GDK_WINDOW_XID (gdkwindow);
+        Display *display = GDK_WINDOW_XDISPLAY (gdkwindow);
+
+        static Atom wm_protocols = None;
+        static Atom wm_take_focus = None;
+
+        if (!wm_protocols)
+            wm_protocols = XInternAtom(display, "WM_PROTOCOLS", False);
+        if (!wm_take_focus)
+            wm_take_focus = XInternAtom(display, "WM_TAKE_FOCUS", False);
+
+        XEvent ev = {0};
+        ev.xclient.type = ClientMessage;
+        ev.xclient.window = window;
+        ev.xclient.message_type = wm_protocols;
+        ev.xclient.format = 32;
+        ev.xclient.data.l[0] = wm_take_focus;
+        ev.xclient.data.l[1] = CurrentTime;
+        XSendEvent(display, window, False, 0L, &ev);
+    }
+    else if(monitor->object->priv->follow_cursor && greeter_background_monitor_enabled(monitor->object, monitor))
         greeter_background_set_active_monitor(monitor->object, monitor);
     return FALSE;
 }
@@ -1633,7 +1675,7 @@
 }
 
 static gdouble
-transition_func_easy_in_out(gdouble x)
+transition_func_ease_in_out(gdouble x)
 {
     return (1 - cos(M_PI*x))/2;
 }

=== 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	2015-03-04 07:33:32 +0000
@@ -1,12 +1,12 @@
 #layout_menuitem>GtkLabel
 {
-  border: 1px solid alpha(@menu_fg_color, 0.8);
-  border-radius: 0.5em;
-  padding: 0px 0.25em;
-  background: alpha(@menu_fg_color, 0.2);
+    border: 1px solid alpha(@menu_fg_color, 0.8);
+    border-radius: 0.5em;
+    padding: 0px 0.25em;
+    background: alpha(@menu_fg_color, 0.2);
 }
 
 #layout_menuitem
 {
-  padding: 1px;
+    padding: 1px;
 }

=== modified file 'src/lightdm-gtk-greeter.c'
--- src/lightdm-gtk-greeter.c	2015-01-26 14:41:10 +0000
+++ src/lightdm-gtk-greeter.c	2015-03-04 07:33:32 +0000
@@ -53,6 +53,7 @@
 #include "src/lightdm-gtk-greeter-css-fallback.h"
 #include "src/lightdm-gtk-greeter-css-application.h"
 
+
 static LightDMGreeter *greeter;
 
 /* State file */
@@ -70,7 +71,8 @@
 static void sigterm_cb (gpointer user_data);
 
 /* Screen window */
-static GtkOverlay *screen_overlay;
+static GtkOverlay   *screen_overlay;
+static GtkWidget    *screen_overlay_child;
 
 /* Login window */
 static GtkWidget    *login_window;
@@ -283,7 +285,7 @@
 void a11y_keyboard_cb (GtkCheckMenuItem *item, gpointer user_data);
 void a11y_reader_cb (GtkCheckMenuItem *item, gpointer user_data);
 
-/* Power indciator */
+/* Power indicator */
 static void power_menu_cb (GtkWidget *menuitem, gpointer userdata);
 void suspend_cb (GtkWidget *widget, LightDMGreeter *greeter);
 void hibernate_cb (GtkWidget *widget, LightDMGreeter *greeter);
@@ -316,12 +318,12 @@
 void
 greeter_restore_focus(const gpointer saved_data)
 {
-    if (!saved_data)
-        return;
-
     struct SavedFocusData *data = saved_data;
-    if (GTK_IS_WIDGET (data->widget))
-        gtk_widget_grab_focus (data->widget);
+
+    if (!saved_data || !GTK_IS_WIDGET (data->widget))
+        return;
+
+    gtk_widget_grab_focus (data->widget);
     if (GTK_IS_EDITABLE(data->widget) && data->editable_pos > -1)
         gtk_editable_set_position(GTK_EDITABLE(data->widget), data->editable_pos);
 }
@@ -732,7 +734,7 @@
             }
             else
             {
-                g_warning ("Failed to load user image: %s", error->message);
+                g_debug ("Failed to load user image: %s", error->message);
                 g_clear_error (&error);
             }
         }
@@ -849,6 +851,7 @@
                 if (id != 0 && end_ptr > text)
                 {
                     socket = GTK_SOCKET (gtk_socket_new ());
+                    gtk_container_foreach (GTK_CONTAINER (command->widget), (GtkCallback)gtk_widget_destroy, NULL);
                     gtk_container_add (GTK_CONTAINER (command->widget), GTK_WIDGET (socket));
                     gtk_socket_add_id (socket, id);
                     gtk_widget_show_all (GTK_WIDGET (command->widget));
@@ -879,6 +882,7 @@
             g_warning ("[Command/%s] Failed to run: %s", command->name, error->message);
         gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (command->menu_item), FALSE);
     }
+
     g_clear_error (&error);
 
     return command->pid;
@@ -2513,54 +2517,40 @@
             set_displayed_user (greeter, name);
             g_free (name);
         }
-
     }
 
     g_free (last_user);
 }
 
 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;
+    XEvent *xevent = (XEvent*)gxevent;
     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_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)
     {
         Window xwin;
-        int revert_to;
+        int revert_to = RevertToNone;
+
         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_lower (gtk_widget_get_window (gtk_widget_get_toplevel (GTK_WIDGET (screen_overlay))));
     }
+
     return GDK_FILTER_CONTINUE;
 }
 
@@ -2769,6 +2759,7 @@
 
     /* Screen window */
     screen_overlay = GTK_OVERLAY (gtk_builder_get_object (builder, "screen_overlay"));
+    screen_overlay_child = GTK_WIDGET (gtk_builder_get_object (builder, "screen_overlay_child"));
 
     /* Login window */
     login_window = GTK_WIDGET (gtk_builder_get_object (builder, "login_window"));
@@ -3140,10 +3131,10 @@
     }
     g_strfreev (values);
 
-    /* focus fix (source: unity-greeter) */
+    /* There is no window manager, so we need to implement some of its functionality */
     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);
+    gdk_window_add_filter (root_window, wm_window_filter, NULL);
 
     gtk_widget_show (GTK_WIDGET (screen_overlay));
 

=== modified file 'src/lightdm-gtk-greeter.glade'
--- src/lightdm-gtk-greeter.glade	2014-12-10 07:59:02 +0000
+++ src/lightdm-gtk-greeter.glade	2015-03-04 07:33:32 +0000
@@ -282,6 +282,7 @@
                     <property name="name">cancel_button</property>
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
                     <signal name="clicked" handler="power_button_clicked_cb" swapped="no"/>
                   </object>
                   <packing>
@@ -296,6 +297,7 @@
                     <property name="name">power_ok_button</property>
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
                     <signal name="clicked" handler="power_button_clicked_cb" swapped="no"/>
                   </object>
                   <packing>
@@ -326,10 +328,9 @@
     <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_overlay_child">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
-        <property name="orientation">vertical</property>
         <child>
           <placeholder/>
         </child>
@@ -541,6 +542,7 @@
                     <property name="name">cancel_button</property>
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
                     <signal name="clicked" handler="cancel_cb" swapped="no"/>
                   </object>
                   <packing>
@@ -555,6 +557,7 @@
                     <property name="name">login_button</property>
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
                     <signal name="clicked" handler="login_cb" swapped="no"/>
                   </object>
                   <packing>


Follow ups