From abc02a72f5bd4284fcc05b1bdfac591f0563d64f Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Thu, 22 Mar 2012 17:02:09 +1100 Subject: [PATCH] Make gnome-screensaver look like Unity Greeter --- src/gs-lock-plug.c | 334 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/gs-window-x11.c | 6 +- 2 files changed, 338 insertions(+), 2 deletions(-) diff --git a/src/gs-lock-plug.c b/src/gs-lock-plug.c index b33a9c0..13a12fb 100644 --- a/src/gs-lock-plug.c +++ b/src/gs-lock-plug.c @@ -66,6 +66,10 @@ static void gs_lock_plug_finalize (GObject *object); struct GSLockPlugPrivate { + GtkWidget *fixed; + GtkWidget *background; + GdkPixbuf *background_image; + GtkWidget *frame; GtkWidget *vbox; GtkWidget *auth_action_area; @@ -1487,8 +1491,294 @@ delete_handler (GSLockPlug *plug, } static void +cairo_rounded_rectangle (cairo_t *cr, double x, double y, double width, double height, double radius) +{ + double w = width - radius * 2; + double h = height - radius * 2; + double kappa = 0.5522847498 * radius; + + cairo_move_to (cr, x + radius, y); + cairo_rel_line_to (cr, w, 0); + cairo_rel_curve_to (cr, kappa, 0, radius, radius - kappa, radius, radius); + cairo_rel_line_to (cr, 0, h); + cairo_rel_curve_to (cr, 0, kappa, kappa - radius, radius, -radius, radius); + cairo_rel_line_to (cr, -w, 0); + cairo_rel_curve_to (cr, -kappa, 0, -radius, kappa - radius, -radius, -radius); + cairo_rel_line_to (cr, 0, -h); + cairo_rel_curve_to (cr, 0, -kappa, radius - kappa, -radius, radius, -radius); +} + +static GdkPixbuf * +get_background (GSLockPlug *plug, int width, int height) +{ + GError *error = NULL; + GDBusConnection *system_bus; + GVariant *reply; + GVariant *value; + gchar *user; + gchar *background_file; + GdkPixbuf *pixbuf, *scaled_pixbuf; + int image_width, image_height; + double target_aspect, aspect, scale, offset_x = 0, offset_y = 0; + + if (plug->priv->background_image != NULL) { + if (gdk_pixbuf_get_width (plug->priv->background_image) == width && + gdk_pixbuf_get_height (plug->priv->background_image) == height) { + return plug->priv->background_image; + } + g_object_unref (plug->priv->background_image); + plug->priv->background_image = NULL; + } + + system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); + if (error != NULL) { + g_warning ("Unable to get system bus: %s", error->message); + g_error_free (error); + return NULL; + } + + reply = g_dbus_connection_call_sync (system_bus, + "org.freedesktop.Accounts", + "/org/freedesktop/Accounts", + "org.freedesktop.Accounts", + "FindUserByName", + g_variant_new ("(s)", + g_get_user_name ()), + G_VARIANT_TYPE ("(o)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if (error != NULL) { + g_warning ("Couldn't find user in accounts service: %s", error->message); + g_error_free (error); + return NULL; + } + + g_variant_get (reply, "(o)", &user); + g_variant_unref (reply); + + reply = g_dbus_connection_call_sync (system_bus, + "org.freedesktop.Accounts", + user, + "org.freedesktop.DBus.Properties", + "Get", + g_variant_new ("(ss)", + "org.freedesktop.Accounts.User", + "BackgroundFile"), + G_VARIANT_TYPE ("(v)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + g_free (user); + g_object_unref (system_bus); + + if (error != NULL) { + g_warning ("Couldn't find background file in accounts service: %s", error->message); + g_error_free (error); + return NULL; + } + + g_variant_get (reply, "(v)", &value); + g_variant_unref (reply); + background_file = g_strdup (g_variant_get_string (value, NULL)); + g_variant_unref (value); + + pixbuf = gdk_pixbuf_new_from_file (background_file, &error); + g_free (background_file); + if (error != NULL) { + g_warning ("Couldn't load background file: %s", error->message); + g_error_free (error); + } + if (pixbuf == NULL) { + return NULL; + } + image_width = gdk_pixbuf_get_width (pixbuf); + image_height = gdk_pixbuf_get_height (pixbuf); + + target_aspect = (double) width / height; + aspect = (double) image_width / image_height; + if (aspect > target_aspect) { + /* Fit height and trim sides */ + scale = (double) height / image_height; + offset_x = (image_width * scale - width) / 2; + } + else { + /* Fit width and trim top and bottom */ + scale = (double) width / image_width; + offset_y = (image_height * scale - height) / 2; + } + + scaled_pixbuf = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (pixbuf), + gdk_pixbuf_get_has_alpha (pixbuf), + gdk_pixbuf_get_bits_per_sample (pixbuf), + width, + height); + gdk_pixbuf_scale (pixbuf, scaled_pixbuf, 0, 0, width, height, -offset_x, -offset_y, scale, scale, GDK_INTERP_BILINEAR); + g_object_unref (pixbuf); + + return scaled_pixbuf; +} + + +static gboolean +draw_cb (GtkWidget *widget, cairo_t *cr, GSLockPlug *plug) +{ + GdkPixbuf *background; + cairo_surface_t *overlay_surface; + cairo_t *overlay_cr; + cairo_matrix_t matrix; + cairo_pattern_t *overlay; + int width, height; + int grid_size = 40, border = 4, grid_x, grid_y; + int box_x, box_y, box_width, box_height, row; + PangoLayout *layout; + PangoFontDescription *font_description; + int layout_width, layout_height; + const gchar *name; + gchar *utf8_name; + + width = gtk_widget_get_allocated_width (widget); + height = gtk_widget_get_allocated_height (widget); + grid_x = (width % grid_size) / 2; + grid_y = (height % grid_size) / 2; + + /* Draw background */ + background = get_background (plug, width, height); + cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0); + if (background) { + gdk_cairo_set_source_pixbuf (cr, background, 0, 0); + g_object_unref (background); + } + cairo_paint (cr); + + /* Draw overlay */ + overlay_surface = cairo_surface_create_similar (cairo_get_target (cr), CAIRO_CONTENT_COLOR_ALPHA, grid_size, grid_size); + overlay_cr = cairo_create (overlay_surface); + cairo_rectangle (overlay_cr, 0, 0, 1, 1); + cairo_rectangle (overlay_cr, grid_size - 1, 0, 1, 1); + cairo_rectangle (overlay_cr, 0, grid_size - 1, 1, 1); + cairo_rectangle (overlay_cr, grid_size - 1, grid_size - 1, 1, 1); + cairo_set_source_rgba (overlay_cr, 1.0, 1.0, 1.0, 0.25); + cairo_fill (overlay_cr); + overlay = cairo_pattern_create_for_surface (overlay_surface); + cairo_matrix_init_translate (&matrix, -grid_x, -grid_y); + cairo_pattern_set_matrix (overlay, &matrix); + cairo_pattern_set_extend (overlay, CAIRO_EXTEND_REPEAT); + + cairo_set_source (cr, overlay); + cairo_rectangle (cr, 0, 0, width, height); + cairo_fill (cr); + + cairo_surface_destroy (overlay_surface); + cairo_destroy (overlay_cr); + cairo_pattern_destroy (overlay); + + /* Draw login box */ + box_width = 7 * grid_size; + box_height = 3 * grid_size; + row = (height / grid_size - 3) / 2; + box_x = grid_x + grid_size; + box_y = grid_y + row * grid_size; + cairo_rounded_rectangle (cr, box_x + 6, box_y + 3, box_width - 12, box_height - 6, 0.2 * grid_size); + cairo_set_source_rgba (cr, 0.1, 0.1, 0.1, 0.4); + cairo_fill_preserve (cr); + cairo_set_source_rgba (cr, 0.4, 0.4, 0.4, 0.4); + cairo_set_line_width (cr, 1); + cairo_stroke (cr); + + /* Draw username label */ + // FIXME: Fade long names + name = g_get_real_name (); + if (name == NULL || strcmp (name, "Unknown") == 0) + name = g_get_user_name (); + utf8_name = NULL; + if (name != NULL) + utf8_name = g_locale_to_utf8 (name, -1, NULL, NULL, NULL); + layout = gtk_widget_create_pango_layout (widget, utf8_name); + font_description = pango_font_description_from_string ("Ubuntu 16"); + pango_layout_set_font_description (layout, font_description); + pango_font_description_free (font_description); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + pango_layout_get_pixel_size (layout, &layout_width, &layout_height); + cairo_move_to (cr, box_x + grid_size / 2, box_y + (grid_size - layout_height) / 2 + border); + pango_cairo_show_layout (cr, layout); + g_object_unref (layout); + + gtk_container_propagate_draw (GTK_CONTAINER (plug->priv->fixed), plug->priv->auth_prompt_entry, cr); + gtk_container_propagate_draw (GTK_CONTAINER (plug->priv->fixed), plug->priv->auth_switch_button, cr); + + return TRUE; +} + +static void +size_allocate_cb (GtkWidget *widget, GtkAllocation *allocation, GSLockPlug *plug) +{ + int width, height; + int grid_size = 40, grid_x, grid_y; + int box_x, box_y, box_width, row; + GtkAllocation child_allocation; + + width = allocation->width; + height = allocation->height; + grid_x = (width % grid_size) / 2; + grid_y = (height % grid_size) / 2; + + box_width = 7 * grid_size; + row = (height / grid_size - 3) / 2; + box_x = grid_x + grid_size; + box_y = grid_y + row * grid_size; + child_allocation.x = box_x + grid_size / 2; + child_allocation.y = box_y + grid_size * 2 - grid_size / 2; + child_allocation.width = box_width - grid_size; + child_allocation.height = grid_size; + gtk_widget_size_allocate (plug->priv->auth_prompt_entry, &child_allocation); + + child_allocation.x = box_x - grid_size; + child_allocation.y = box_y + grid_size; + child_allocation.width = grid_size; + child_allocation.height = grid_size; + gtk_widget_size_allocate (plug->priv->auth_switch_button, &child_allocation); +} + +static gboolean +draw_prompt_cb (GtkWidget *widget, cairo_t *cr, GSLockPlug *plug) +{ + /* Show prompt if haven't typed */ + if (strcmp (gtk_entry_get_text (GTK_ENTRY (plug->priv->auth_prompt_entry)), "") == 0) { + int x, y; + gchar *text; + PangoLayout *layout; + PangoFontDescription *font_description; + + gtk_entry_get_layout_offsets (GTK_ENTRY (widget), &x, &y); + cairo_move_to (cr, x, y); + + /* Strip whitespace colons from prompt */ + text = g_strdup (gtk_label_get_text (GTK_LABEL (plug->priv->auth_prompt_label))); + if (g_str_has_suffix (text, ":")); + text[strlen (text) - 1] = '\0'; + + layout = gtk_widget_create_pango_layout (widget, text); + g_free (text); + font_description = pango_font_description_from_string ("Ubuntu 14"); + pango_layout_set_font_description (layout, font_description); + pango_font_description_free (font_description); + cairo_set_source_rgb (cr, 0.8, 0.8, 0.8); + pango_cairo_show_layout (cr, layout); + g_object_unref (layout); + } + + return FALSE; +} + +static void gs_lock_plug_init (GSLockPlug *plug) { + GdkScreen *screen; + int width, height; + gs_profile_start (NULL); plug->priv = GS_LOCK_PLUG_GET_PRIVATE (plug); @@ -1497,7 +1787,8 @@ gs_lock_plug_init (GSLockPlug *plug) plug->priv->frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (plug->priv->frame), GTK_SHADOW_OUT); - gtk_container_add (GTK_CONTAINER (plug), plug->priv->frame); + // Don't add the widgets, we will override them below + //gtk_container_add (GTK_CONTAINER (plug), plug->priv->frame); plug->priv->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_add (GTK_CONTAINER (plug->priv->frame), plug->priv->vbox); @@ -1596,6 +1887,47 @@ gs_lock_plug_init (GSLockPlug *plug) g_signal_connect (plug, "delete_event", G_CALLBACK (delete_handler), NULL); gtk_widget_set_size_request (GTK_WIDGET (plug), 450, -1); + + /* Override with the Unity Greeter style */ + + plug->priv->background = gtk_event_box_new (); + g_signal_connect (plug->priv->background, "draw", G_CALLBACK (draw_cb), plug); + g_signal_connect (plug->priv->background, "size-allocate", G_CALLBACK (size_allocate_cb), plug); + gtk_widget_show (plug->priv->background); + gtk_container_add (GTK_CONTAINER (plug), plug->priv->background); + + plug->priv->fixed = gtk_fixed_new (); + gtk_widget_show (plug->priv->fixed); + gtk_container_add (GTK_CONTAINER (plug->priv->background), plug->priv->fixed); + + // FIXME: Use monitors + screen = gdk_screen_get_default (); + width = gdk_screen_get_width (screen); + height = gdk_screen_get_height (screen); + + plug->priv->auth_prompt_entry = gtk_entry_new (); + gtk_style_context_add_class (gtk_widget_get_style_context (plug->priv->auth_prompt_entry), "lightdm"); + g_signal_connect (plug->priv->auth_prompt_entry, "draw", G_CALLBACK (draw_prompt_cb), plug); + g_signal_connect (plug->priv->auth_prompt_entry, "button_press_event", G_CALLBACK (entry_button_press), NULL); + g_signal_connect (plug->priv->auth_prompt_entry, "activate", G_CALLBACK (unlock_button_clicked), plug); + gtk_entry_set_activates_default (GTK_ENTRY (plug->priv->auth_prompt_entry), TRUE); + gtk_entry_set_visibility (GTK_ENTRY (plug->priv->auth_prompt_entry), FALSE); + gtk_widget_show (plug->priv->auth_prompt_entry); + gtk_container_add (GTK_CONTAINER (plug->priv->fixed), plug->priv->auth_prompt_entry); + + gtk_window_set_default (GTK_WINDOW (plug), plug->priv->auth_prompt_entry); + + plug->priv->auth_switch_button = gtk_button_new_with_label ("<"); + gtk_button_set_focus_on_click (GTK_BUTTON (plug->priv->auth_switch_button), FALSE); + gtk_style_context_add_class (gtk_widget_get_style_context (plug->priv->auth_switch_button), "lightdm"); + g_signal_connect (plug->priv->auth_switch_button, "clicked", G_CALLBACK (switch_user_button_clicked), plug); + if (plug->priv->switch_enabled) { + gtk_widget_show (plug->priv->auth_switch_button); + } + gtk_container_add (GTK_CONTAINER (plug->priv->fixed), plug->priv->auth_switch_button); + + /* Fill the whole window */ + gtk_widget_set_size_request (GTK_WIDGET (plug), width, height); gs_profile_end (NULL); } diff --git a/src/gs-window-x11.c b/src/gs-window-x11.c index 4c1d47c..57aff3c 100644 --- a/src/gs-window-x11.c +++ b/src/gs-window-x11.c @@ -1272,6 +1272,9 @@ shake_dialog (GSWindow *window) int i; guint left; guint right; + + // Disabled in Unity + return; window->priv->dialog_shake_in_progress = TRUE; @@ -2337,7 +2340,8 @@ gs_window_init (GSWindow *window) window->priv->panel = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); gtk_widget_show (window->priv->panel); - gtk_box_pack_start (GTK_BOX (window->priv->vbox), window->priv->panel, FALSE, FALSE, 0); + // Disabled in Unity + //gtk_box_pack_start (GTK_BOX (window->priv->vbox), window->priv->panel, FALSE, FALSE, 0); create_panel (window); window->priv->drawing_area = gtk_drawing_area_new (); -- 1.7.9.1