From 8a991c0c073486c05b65441a1fe2fed2b82c4fa3 Mon Sep 17 00:00:00 2001 From: lenemter Date: Fri, 24 Jul 2026 16:03:50 +0200 Subject: [PATCH 1/5] Port to Gtk4 --- compositor/meson.build | 1 + data/Application.css | 3 +- src/Application.vala | 5 +- src/Cards/BaseCard.vala | 2 +- src/Cards/ManualCard.vala | 33 +++++---- src/Cards/UserCard.vala | 110 +++++++++++++++++++----------- src/MainWindow.vala | 61 +++++++++-------- src/Widgets/BackgroundImage.vala | 89 ------------------------ src/Widgets/CapsLockRevealer.vala | 32 ++++----- src/Widgets/DateTimeWidget.vala | 8 +-- src/Widgets/PasswordEntry.vala | 2 +- src/Widgets/SessionButton.vala | 8 +-- src/meson.build | 14 ++-- 13 files changed, 155 insertions(+), 213 deletions(-) delete mode 100644 src/Widgets/BackgroundImage.vala diff --git a/compositor/meson.build b/compositor/meson.build index e84533107..df96dd6d0 100644 --- a/compositor/meson.build +++ b/compositor/meson.build @@ -3,6 +3,7 @@ glib_dep = [dependency('gio-2.0'), dependency('gio-unix-2.0'), dependency('gmodule-2.0')] gtk_dep = [dependency('gtk+-3.0'), dependency('gdk-x11-3.0')] gee_dep = dependency('gee-0.8') +gnome_desktop_dep = dependency('gnome-desktop-3.0') m_dep = meson.get_compiler('c').find_library('m', required: false) posix_dep = meson.get_compiler('vala').find_library('posix', required: false) diff --git a/data/Application.css b/data/Application.css index de5f8631f..b5aea3be4 100644 --- a/data/Application.css +++ b/data/Application.css @@ -4,6 +4,8 @@ */ window.background { + background: transparent; + box-shadow: none; opacity: 0; transition: opacity 1s ease; } @@ -63,7 +65,6 @@ check { margin: 2px; min-height: 20px; min-width: 20px; - -gtk-icon-source: -gtk-icontheme("check-active-symbolic"); -gtk-icon-transform: scale(0.6); } diff --git a/src/Application.vala b/src/Application.vala index 162211b50..e6a92a000 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -39,10 +39,12 @@ public class Greeter.Application : Gtk.Application { protected override void startup () { base.startup (); + Granite.init (); + var css_provider = new Gtk.CssProvider (); css_provider.load_from_resource ("/io/elementary/greeter/Application.css"); - Gtk.StyleContext.add_provider_for_screen (Gdk.Screen.get_default (), css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); + Gtk.StyleContext.add_provider_for_display (Gdk.Display.get_default (), css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); GLib.Bus.own_name ( SESSION, @@ -106,7 +108,6 @@ public class Greeter.Application : Gtk.Application { public override void activate () { add_window (new Greeter.MainWindow (lightdm_greeter)); - active_window.show_all (); active_window.present (); } diff --git a/src/Cards/BaseCard.vala b/src/Cards/BaseCard.vala index 2128e5110..973c0e880 100644 --- a/src/Cards/BaseCard.vala +++ b/src/Cards/BaseCard.vala @@ -5,7 +5,7 @@ * Authors: Corentin Noël */ -public abstract class Greeter.BaseCard : Gtk.Bin { +public abstract class Greeter.BaseCard : Granite.Bin { public signal void do_connect (string? credential = null); public signal void go_left (); public signal void go_right (); diff --git a/src/Cards/ManualCard.vala b/src/Cards/ManualCard.vala index cae3c34a5..97340d989 100644 --- a/src/Cards/ManualCard.vala +++ b/src/Cards/ManualCard.vala @@ -11,8 +11,6 @@ public class Greeter.ManualCard : Greeter.BaseCard { private Gtk.Box main_box; construct { - width_request = 350; - var icon = new Gtk.Image () { icon_name = "avatar-default", pixel_size = 64 @@ -22,7 +20,7 @@ public class Greeter.ManualCard : Greeter.BaseCard { hexpand = true, margin_bottom = 16 }; - label.get_style_context ().add_class (Granite.STYLE_CLASS_H2_LABEL); + label.add_css_class (Granite.STYLE_CLASS_H2_LABEL); username_entry = new Gtk.Entry () { hexpand = true, @@ -58,21 +56,22 @@ public class Greeter.ManualCard : Greeter.BaseCard { margin_start = 12, margin_end = 12 }; - main_box.add (form_grid); + main_box.append (form_grid); - main_box.get_style_context ().add_class (Granite.STYLE_CLASS_CARD); - main_box.get_style_context ().add_class (Granite.STYLE_CLASS_ROUNDED); + main_box.add_css_class (Granite.CssClass.CARD); child = main_box; bind_property ("connecting", username_entry, "sensitive", INVERT_BOOLEAN); bind_property ("connecting", password_entry, "sensitive", INVERT_BOOLEAN); - username_entry.focus_out_event.connect (() => { + var focus_controller = new Gtk.EventControllerFocus (); + focus_controller.leave.connect (() => { if (username_entry.text != "") { do_connect_username (username_entry.text); } }); + username_entry.add_controller (focus_controller); password_entry.activate.connect (on_login); } @@ -89,14 +88,14 @@ public class Greeter.ManualCard : Greeter.BaseCard { public override void wrong_credentials () { password_entry.text = ""; - username_entry.get_style_context ().add_class (Gtk.STYLE_CLASS_ERROR); - password_entry.get_style_context ().add_class (Gtk.STYLE_CLASS_ERROR); - main_box.get_style_context ().add_class ("shake"); + username_entry.add_css_class (Granite.CssClass.ERROR); + password_entry.add_css_class (Granite.CssClass.ERROR); + main_box.add_css_class ("shake"); Timeout.add (ERROR_SHAKE_DURATION, () => { - username_entry.get_style_context ().remove_class (Gtk.STYLE_CLASS_ERROR); - password_entry.get_style_context ().remove_class (Gtk.STYLE_CLASS_ERROR); - main_box.get_style_context ().remove_class ("shake"); + username_entry.remove_css_class (Granite.CssClass.ERROR); + password_entry.remove_css_class (Granite.CssClass.ERROR); + main_box.remove_css_class ("shake"); connecting = false; username_entry.grab_focus_without_selecting (); @@ -112,12 +111,12 @@ public class Greeter.ManualCard : Greeter.BaseCard { username_entry.grab_focus_without_selecting (); username_entry.text = ""; - username_entry.get_style_context ().add_class (Gtk.STYLE_CLASS_ERROR); - main_box.get_style_context ().add_class ("shake"); + username_entry.add_css_class (Granite.CssClass.ERROR); + main_box.add_css_class ("shake"); Timeout.add (ERROR_SHAKE_DURATION, () => { - username_entry.get_style_context ().remove_class (Gtk.STYLE_CLASS_ERROR); - main_box.get_style_context ().remove_class ("shake"); + username_entry.remove_css_class (Granite.CssClass.ERROR); + main_box.remove_css_class ("shake"); return Source.REMOVE; }); diff --git a/src/Cards/UserCard.vala b/src/Cards/UserCard.vala index 938bfa926..3e51157ea 100644 --- a/src/Cards/UserCard.vala +++ b/src/Cards/UserCard.vala @@ -13,8 +13,6 @@ public class Greeter.UserCard : Greeter.BaseCard { public Act.User user { get; construct; } public bool show_input { get; set; default = false; } public bool is_24h { get; set; default = true; } - // TODO: In Gtk4 remove this gesture and move it to MainWindow - public Gtk.GestureMultiPress click_gesture { get; private set; } private Pantheon.AccountsService greeter_act; private Pantheon.SettingsDaemon.AccountsService settings_act; @@ -43,14 +41,13 @@ public class Greeter.UserCard : Greeter.BaseCard { margin_start = 24, margin_end = 24, }; - username_label.get_style_context ().add_class (Granite.STYLE_CLASS_H2_LABEL); + username_label.add_css_class (Granite.STYLE_CLASS_H2_LABEL); user.bind_property ("locked", username_label, "sensitive", SYNC_CREATE | INVERT_BOOLEAN); password_entry = new Greeter.PasswordEntry (); bind_property ("connecting", password_entry, "sensitive", INVERT_BOOLEAN); - var fingerprint_image = new Gtk.Image.from_icon_name ("fingerprint-symbolic", BUTTON); - bind_property ("use-fingerprint", fingerprint_image, "no-show-all", SYNC_CREATE | INVERT_BOOLEAN); + var fingerprint_image = new Gtk.Image.from_icon_name ("fingerprint-symbolic"); bind_property ("use-fingerprint", fingerprint_image, "visible", SYNC_CREATE); password_session_button = new Greeter.SessionButton () { @@ -67,7 +64,7 @@ public class Greeter.UserCard : Greeter.BaseCard { password_grid.attach (new Greeter.CapsLockRevealer (), 0, 1, 3); var login_button = new Gtk.Button.with_label (_("Log In")); - login_button.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); + login_button.add_css_class (Granite.CssClass.SUGGESTED); bind_property ("connecting", login_button, "sensitive", INVERT_BOOLEAN); login_button_session_button = new Greeter.SessionButton () { @@ -75,16 +72,16 @@ public class Greeter.UserCard : Greeter.BaseCard { }; var login_box = new Gtk.Box (HORIZONTAL, 6); - login_box.add (login_button); - login_box.add (login_button_session_button); + login_box.append (login_button); + login_box.append (login_button_session_button); var disabled_box = new Gtk.Box (HORIZONTAL, 6) { halign = Gtk.Align.CENTER, margin_top = 3 }; - disabled_box.add (new Gtk.Image.from_icon_name ("changes-prevent-symbolic", MENU)); - disabled_box.add (new Gtk.Label (_("Account disabled"))); - disabled_box.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL); + disabled_box.append (new Gtk.Image.from_icon_name ("changes-prevent-symbolic")); + disabled_box.append (new Gtk.Label (_("Account disabled"))); + disabled_box.add_css_class (Granite.CssClass.DIM); login_stack = new Gtk.Stack () { margin_top = 12, @@ -105,24 +102,29 @@ public class Greeter.UserCard : Greeter.BaseCard { bind_property ("show-input", form_revealer, "reveal-child", SYNC_CREATE); main_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0) { - margin_bottom = 48 + margin_bottom = 48, + overflow = HIDDEN // Without this, Gtk.Picture won't have rounded corners }; - // in reverse order because pack_end is used - main_box.pack_end (form_revealer); - main_box.pack_end (username_label); - main_box.get_style_context ().add_class (Granite.STYLE_CLASS_CARD); - main_box.get_style_context ().add_class (Granite.STYLE_CLASS_ROUNDED); + main_box.append (username_label); + main_box.append (form_revealer); + main_box.add_css_class (Granite.CssClass.CARD); update_collapsed_class (); - var avatar = new Hdy.Avatar (64, user.real_name, true) { + var avatar = new Adw.Avatar (64, user.real_name, true) { margin_top = 6, margin_bottom = 6, margin_start = 6, margin_end = 6, - loadable_icon = new FileIcon (File.new_for_path (user.icon_file)) }; + var user_icon_file = File.new_for_path (user.icon_file); + try { + avatar.custom_image = Gdk.Texture.from_file (user_icon_file ); + } catch (Error e) { + avatar.custom_image = null; + } + avatar_overlay = new Gtk.Overlay () { halign = CENTER, valign = START, @@ -153,21 +155,26 @@ public class Greeter.UserCard : Greeter.BaseCard { user.sessions_changed.connect (on_sessions_changed); on_sessions_changed (); - click_gesture = new Gtk.GestureMultiPress (this); - notify["show-input"].connect (update_collapsed_class); password_entry.activate.connect (on_login); login_button.clicked.connect (on_login); - grab_focus.connect (password_entry.grab_focus_without_selecting); + var focus_controller = new Gtk.EventControllerFocus (); + focus_controller.enter.connect (() => { + if (focus_controller.is_focus) { + password_entry.grab_focus_without_selecting (); + } + }); + + add_controller (focus_controller); connect_to_dbus_interfaces (); } private void set_check_style () { // Override check's accent_color so that it *always* uses user's preferred color - logged_in.get_style_context ().add_class (accent_to_string (settings_act.accent_color)); + logged_in.add_css_class (accent_to_string (settings_act.accent_color)); } private string generate_background_image_path () { @@ -184,20 +191,42 @@ public class Greeter.UserCard : Greeter.BaseCard { } private void set_background_image () { - Greeter.BackgroundImage background_image; + var background_picture = new Gtk.Picture () { + content_fit = COVER + }; var background_path = generate_background_image_path (); if (settings_act.picture_options != 0) { - background_image = new Greeter.BackgroundImage.from_path (background_path); + background_picture.set_filename (background_path); } else if (settings_act.primary_color != null) { - background_image = new Greeter.BackgroundImage.from_color (settings_act.primary_color); + Gdk.RGBA rgba_color = {}; + rgba_color.parse (settings_act.primary_color); + + uint32 f = 0x0; + f += (uint) Math.round (rgba_color.red * 255); + f <<= 8; + f += (uint) Math.round (rgba_color.green * 255); + f <<= 8; + f += (uint) Math.round (rgba_color.blue * 255); + f <<= 8; + f += 255; + + var pixbuf = new Gdk.Pixbuf (Gdk.Colorspace.RGB, false, 8, 1, 1); + pixbuf.fill (f); + + background_picture.paintable = (Gdk.Texture.for_pixbuf (pixbuf)); } else { - background_image = new Greeter.BackgroundImage.from_path (null); + background_picture.set_filename ("/usr/share/backgrounds/elementaryos-default"); } - main_box.pack_start (background_image); - main_box.show_all (); + var clamp = new Adw.Clamp () { + child = background_picture, + orientation = VERTICAL, + maximum_size = 150 + }; + + main_box.prepend (clamp); } private string accent_to_string (int i) { @@ -275,9 +304,8 @@ public class Greeter.UserCard : Greeter.BaseCard { if (user_is_logged_in) { avatar_overlay.add_overlay (logged_in); - logged_in.show_all (); } else { - avatar_overlay.remove (logged_in); + avatar_overlay.remove_overlay (logged_in); } } @@ -296,9 +324,9 @@ public class Greeter.UserCard : Greeter.BaseCard { private void update_collapsed_class () { if (show_input) { - main_box.get_style_context ().remove_class ("collapsed"); + main_box.remove_css_class ("collapsed"); } else { - main_box.get_style_context ().add_class ("collapsed"); + main_box.add_css_class ("collapsed"); } } @@ -450,12 +478,12 @@ public class Greeter.UserCard : Greeter.BaseCard { } public override void wrong_credentials () { - password_entry.get_style_context ().add_class (Gtk.STYLE_CLASS_ERROR); - main_box.get_style_context ().add_class ("shake"); + password_entry.add_css_class (Granite.CssClass.ERROR); + main_box.add_css_class ("shake"); Timeout.add (ERROR_SHAKE_DURATION, () => { - password_entry.get_style_context ().remove_class (Gtk.STYLE_CLASS_ERROR); - main_box.get_style_context ().remove_class ("shake"); + password_entry.remove_css_class (Granite.CssClass.ERROR); + main_box.remove_css_class ("shake"); connecting = false; password_entry.grab_focus (); @@ -463,9 +491,13 @@ public class Greeter.UserCard : Greeter.BaseCard { }); } - private class SelectionCheck : Gtk.Spinner { + private class SelectionCheck : Granite.Bin { class construct { - set_css_name (Gtk.STYLE_CLASS_CHECK); + set_css_name ("check"); + } + + construct { + child = new Gtk.Image.from_icon_name ("check-active-symbolic"); } } } diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 783f0282f..03501f2bd 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -11,7 +11,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { private Pantheon.Desktop.Greeter? desktop_greeter; private GLib.Queue user_cards; private Gtk.SizeGroup card_size_group; - private Hdy.Carousel carousel; + private Adw.Carousel carousel; private Greeter.Settings settings; private GLib.Settings gsettings; private Gtk.Revealer datetime_revealer; @@ -22,16 +22,12 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { private bool installer_mode = false; - private Gtk.EventControllerKey key_controller; - public MainWindow (LightDM.Greeter lightdm_greeter) { Object (lightdm_greeter: lightdm_greeter); } construct { - app_paintable = true; decorated = false; - set_visual (get_screen ().get_rgba_visual ()); gsettings = new GLib.Settings ("io.elementary.greeter"); settings = new Greeter.Settings (); @@ -50,10 +46,10 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { vexpand = true }; if (lightdm_greeter.has_guest_account_hint) { - extra_login_box.add (guest_login_button); + extra_login_box.append (guest_login_button); } if (lightdm_greeter.show_manual_login_hint) { - extra_login_box.add (manual_login_button); + extra_login_box.append (manual_login_button); } datetime_widget = new Greeter.DateTimeWidget (); @@ -69,7 +65,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { var manual_card = new Greeter.ManualCard (); - carousel = new Hdy.Carousel () { + carousel = new Adw.Carousel () { allow_long_swipes = true, vexpand = true }; @@ -77,16 +73,16 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { var manual_login_stack = new Gtk.Stack () { transition_type = Gtk.StackTransitionType.CROSSFADE }; - manual_login_stack.add (carousel); - manual_login_stack.add (manual_card); + manual_login_stack.add_child (carousel); + manual_login_stack.add_child (manual_card); var main_box = new Gtk.Box (VERTICAL, 24) { margin_top = 24, margin_bottom = 24 }; - main_box.add (datetime_revealer); - main_box.add (manual_login_stack); - main_box.add (extra_login_box); + main_box.append (datetime_revealer); + main_box.append (manual_login_stack); + main_box.append (extra_login_box); child = main_box; @@ -149,7 +145,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { manual_card.do_connect_username.connect (do_connect_username); manual_card.do_connect.connect (do_connect); - key_controller = new Gtk.EventControllerKey (this) { + var key_controller = new Gtk.EventControllerKey () { propagation_phase = CAPTURE }; key_controller.key_pressed.connect ((keyval, keycode, state) => { @@ -157,7 +153,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { return Gdk.EVENT_PROPAGATE; } - unowned var focused_entry = (Gtk.Entry) get_focus (); + unowned var focused_entry = get_focus () as Gtk.Entry; if (focused_entry == null || !focused_entry.is_ancestor (current_card) || focused_entry.text != "") { return Gdk.EVENT_PROPAGATE; } @@ -182,6 +178,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { return Gdk.EVENT_PROPAGATE; }); + ((Gtk.Widget) this).add_controller (key_controller); carousel.page_changed.connect (handle_page_changed); @@ -203,7 +200,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { */ private void show_greeter_window () { Timeout.add (500, () => { - get_style_context ().add_class ("initialized"); + add_css_class ("initialized"); current_card?.grab_focus (); @@ -241,9 +238,9 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { public void registry_handle_global (Wl.Registry wl_registry, uint32 name, string @interface, uint32 version) { if (@interface == "io_elementary_pantheon_shell_v1") { var desktop_shell = wl_registry.bind (name, ref Pantheon.Desktop.Shell.iface, uint32.min (version, 1)); - unowned var window = get_window (); - if (window is Gdk.Wayland.Window) { - unowned var wl_surface = ((Gdk.Wayland.Window) window).get_wl_surface (); + unowned var surface = get_surface (); + if (surface is Gdk.Wayland.Surface) { + unowned var wl_surface = ((Gdk.Wayland.Surface) surface).get_wl_surface (); desktop_greeter = desktop_shell.get_greeter (wl_surface); desktop_greeter.make_greeter (); } @@ -255,7 +252,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { if (display is Gdk.X11.Display) { unowned var xdisplay = ((Gdk.X11.Display) display).get_xdisplay (); - var window = ((Gdk.X11.Window) get_window ()).get_xid (); + var window = ((Gdk.X11.Surface) get_surface ()).get_xid (); var prop = xdisplay.intern_atom ("_MUTTER_HINTS", false); @@ -361,7 +358,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { bool user_selected = false; user_cards.head.foreach ((card) => { if (card.user.user_name == user_to_select) { - carousel.scroll_to (card); + carousel.scroll_to (card, true); user_selected = true; } }); @@ -369,7 +366,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { if (!user_selected) { unowned var user_card = user_cards.peek_head (); user_card.show_input = true; - carousel.scroll_to (user_card); + carousel.scroll_to (user_card, true); } } else { datetime_revealer.reveal_child = false; @@ -401,17 +398,19 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { private void add_card (Act.User user) { var user_card = new Greeter.UserCard (user); - user_card.show_all (); - user_card.do_connect.connect (do_connect); - user_card.click_gesture.pressed.connect ((gesture, n_press, x, y) => { + + var click_gesture = new Gtk.GestureClick (); + click_gesture.pressed.connect ((gesture, n_press, x, y) => { assert (gesture.widget is UserCard); var _user_card = (UserCard) gesture.widget; if (!_user_card.show_input) { - carousel.scroll_to (_user_card); + carousel.scroll_to (_user_card, true); _user_card.grab_focus (); } }); + user_card.add_controller (click_gesture); + user_card.go_left.connect (() => { if (Gtk.StateFlags.DIR_LTR in get_state_flags ()) { go_previous (); @@ -427,7 +426,9 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { } }); - carousel.add (user_card); + user_card.do_connect.connect (do_connect); + + carousel.append (user_card); card_size_group.add_widget (user_card); user_cards.push_tail (user_card); @@ -497,7 +498,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { } carousel.interactive = false; - carousel.scroll_to (current_card); + carousel.scroll_to (current_card, true); } private void go_previous () { @@ -507,7 +508,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { unowned Greeter.UserCard? next_card = user_cards.peek_nth (current_user_card_index - 1); if (next_card != null) { - carousel.scroll_to (next_card); + carousel.scroll_to (next_card, true); } } @@ -518,7 +519,7 @@ public class Greeter.MainWindow : Gtk.ApplicationWindow { unowned Greeter.UserCard? next_card = user_cards.peek_nth (current_user_card_index + 1); if (next_card != null) { - carousel.scroll_to (next_card); + carousel.scroll_to (next_card, true); } } } diff --git a/src/Widgets/BackgroundImage.vala b/src/Widgets/BackgroundImage.vala deleted file mode 100644 index c52274ca0..000000000 --- a/src/Widgets/BackgroundImage.vala +++ /dev/null @@ -1,89 +0,0 @@ -public class Greeter.BackgroundImage : Gtk.EventBox { - private uint last_size_hash = 0; - private Gdk.Pixbuf full_pixbuf; - private Gdk.Pixbuf fitting_pixbuf; - - construct { - height_request = 150; - } - - public BackgroundImage.from_path (string? path) { - if (path == null) { - path = "/usr/share/backgrounds/elementaryos-default"; - } - - try { - full_pixbuf = new Gdk.Pixbuf.from_file (path); - } catch (GLib.Error e) { - critical (e.message); - critical ("Fallback to default wallpaper"); - - try { - full_pixbuf = new Gdk.Pixbuf.from_file ("/usr/share/backgrounds/elementaryos-default"); - } catch (GLib.Error e) { - critical (e.message); - } - } - } - - public BackgroundImage.from_color (string color) { - full_pixbuf = new Gdk.Pixbuf (Gdk.Colorspace.RGB, false, 8, 1, 1); - - Gdk.RGBA rgba_color = {}; - rgba_color.parse (color); - - uint32 f = 0x0; - f += (uint) Math.round (rgba_color.red * 255); - f <<= 8; - f += (uint) Math.round (rgba_color.green * 255); - f <<= 8; - f += (uint) Math.round (rgba_color.blue * 255); - f <<= 8; - f += 255; - - full_pixbuf.fill (f); - } - - public override bool draw (Cairo.Context cr) { - var scale = get_scale_factor (); - var width = get_allocated_width () * scale; - var height = get_allocated_height () * scale; - var radius = 5 * scale; // Off-by-one to prevent light bleed - - var new_hash = GLib.int_hash (width) + GLib.int_hash (height); - if (new_hash != last_size_hash) { - last_size_hash = new_hash; - double full_ratio = (double)full_pixbuf.height / (double)full_pixbuf.width; - fitting_pixbuf = new Gdk.Pixbuf (full_pixbuf.colorspace, full_pixbuf.has_alpha, full_pixbuf.bits_per_sample, width, height); - - // Get a scaled pixbuf that preserves aspect ratio but is at least as big as the desired destination pixbuf - Gdk.Pixbuf scaled_pixbuf; - if ((int)(width * full_ratio) < height) { - scaled_pixbuf = full_pixbuf.scale_simple ((int)(width * (1 / full_ratio)), height, Gdk.InterpType.BILINEAR); - } else { - scaled_pixbuf = full_pixbuf.scale_simple (width, (int)(width * full_ratio), Gdk.InterpType.BILINEAR); - } - - // Find the offset we need to center the source pixbuf on the destination - int y = ((height - scaled_pixbuf.height) / 2).abs (); - int x = ((width - scaled_pixbuf.width) / 2).abs (); - - scaled_pixbuf.copy_area (x, y, width, height, fitting_pixbuf, 0, 0); - } - - cr.save (); - cr.scale (1.0 / scale, 1.0 / scale); - cr.new_sub_path (); - cr.arc (width - radius, radius, radius, -Math.PI_2, 0); - cr.line_to (width, height); - cr.line_to (0, height); - - cr.arc (radius, radius, radius, Math.PI, Math.PI + Math.PI_2); - cr.close_path (); - Gdk.cairo_set_source_pixbuf (cr, fitting_pixbuf, 0, 0); - cr.clip (); - cr.paint (); - cr.restore (); - return true; - } -} diff --git a/src/Widgets/CapsLockRevealer.vala b/src/Widgets/CapsLockRevealer.vala index 71125a506..519f473d7 100644 --- a/src/Widgets/CapsLockRevealer.vala +++ b/src/Widgets/CapsLockRevealer.vala @@ -1,28 +1,28 @@ /* * SPDX-License-Identifier: GPL-2.0-or-later - * SPDX-FileCopyrightText: 2018-2025 elementary, Inc. (https://elementary.io) + * SPDX-FileCopyrightText: 2018-2026 elementary, Inc. (https://elementary.io) */ -public class Greeter.CapsLockRevealer : Gtk.Bin { +public class Greeter.CapsLockRevealer : Granite.Bin { private Gtk.Image caps_lock_image; private Gtk.Image num_lock_image; private Gtk.Label lock_label; private Gtk.Revealer revealer; construct { - caps_lock_image = new Gtk.Image.from_icon_name ("input-keyboard-capslock-symbolic", MENU); - num_lock_image = new Gtk.Image.from_icon_name ("input-keyboard-numlock-symbolic", MENU); + caps_lock_image = new Gtk.Image.from_icon_name ("input-keyboard-capslock-symbolic"); + num_lock_image = new Gtk.Image.from_icon_name ("input-keyboard-numlock-symbolic"); lock_label = new Gtk.Label (null); - lock_label.get_style_context ().add_class (Granite.STYLE_CLASS_SMALL_LABEL); + lock_label.add_css_class (Granite.CssClass.SMALL); var caps_lock_box = new Gtk.Box (HORIZONTAL, 3) { halign = CENTER }; - caps_lock_box.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL); - caps_lock_box.add (caps_lock_image); - caps_lock_box.add (num_lock_image); - caps_lock_box.add (lock_label); + caps_lock_box.add_css_class (Granite.CssClass.DIM); + caps_lock_box.append (caps_lock_image); + caps_lock_box.append (num_lock_image); + caps_lock_box.append (lock_label); revealer = new Gtk.Revealer () { child = caps_lock_box, @@ -31,20 +31,18 @@ public class Greeter.CapsLockRevealer : Gtk.Bin { child = revealer; - var keymap = Gdk.Keymap.get_for_display (Gdk.Display.get_default ()); - keymap.state_changed.connect (update_visibility); + var device = Gdk.Display.get_default ().get_default_seat ().get_keyboard (); + device.changed.connect (update_visibility); - update_visibility (keymap); + update_visibility (device); } - private void update_visibility (Gdk.Keymap keymap) { - var caps_lock = keymap.get_caps_lock_state (); - var num_lock = keymap.get_num_lock_state (); + private void update_visibility (Gdk.Device device) { + var caps_lock = device.get_caps_lock_state (); + var num_lock = device.get_num_lock_state (); revealer.reveal_child = caps_lock || num_lock; - caps_lock_image.no_show_all = !caps_lock; - num_lock_image.no_show_all = !num_lock; caps_lock_image.visible = caps_lock; num_lock_image.visible = num_lock; diff --git a/src/Widgets/DateTimeWidget.vala b/src/Widgets/DateTimeWidget.vala index b4d4f801b..238ea1edb 100644 --- a/src/Widgets/DateTimeWidget.vala +++ b/src/Widgets/DateTimeWidget.vala @@ -27,14 +27,14 @@ public class Greeter.DateTimeWidget : Gtk.Box { construct { time_label = new Gtk.Label (null); - time_label.get_style_context ().add_class ("time"); + time_label.add_css_class ("time"); date_label = new Gtk.Label (null); - date_label.get_style_context ().add_class ("date"); + date_label.add_css_class ("date"); orientation = VERTICAL; - add (time_label); - add (date_label); + append (time_label); + append (date_label); update_labels (); diff --git a/src/Widgets/PasswordEntry.vala b/src/Widgets/PasswordEntry.vala index f9bd6a26f..5ebc9aa87 100644 --- a/src/Widgets/PasswordEntry.vala +++ b/src/Widgets/PasswordEntry.vala @@ -29,7 +29,7 @@ public class Greeter.PasswordEntry : Gtk.Entry { visibility = false; input_purpose = Gtk.InputPurpose.PASSWORD; - icon_press.connect ((pos, event) => { + icon_press.connect ((pos) => { if (pos == Gtk.EntryIconPosition.SECONDARY) { activate (); } diff --git a/src/Widgets/SessionButton.vala b/src/Widgets/SessionButton.vala index f21b5f52c..69447e3df 100644 --- a/src/Widgets/SessionButton.vala +++ b/src/Widgets/SessionButton.vala @@ -5,7 +5,7 @@ * Authors: Corentin Noël */ -public class Greeter.SessionButton : Gtk.Bin { +public class Greeter.SessionButton : Granite.Bin { construct { var menu = new GLib.Menu (); unowned var application = (Gtk.Application) GLib.Application.get_default (); @@ -18,11 +18,11 @@ public class Greeter.SessionButton : Gtk.Bin { } var menu_button = new Gtk.MenuButton () { - child = new Gtk.Image.from_icon_name ("open-menu-symbolic", Gtk.IconSize.BUTTON), + child = new Gtk.Image.from_icon_name ("open-menu-symbolic"), direction = DOWN, - menu_model = menu + menu_model = menu, + has_frame = false }; - menu_button.get_style_context ().add_class (Gtk.STYLE_CLASS_FLAT); child = menu_button; } diff --git a/src/meson.build b/src/meson.build index 50c87f9db..ca1b15f03 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,12 +1,11 @@ accountsservice_dep = dependency('accountsservice') gobject_dep = dependency('gobject-2.0') glib_dep = dependency('glib-2.0') -gdk_wl_dep = dependency('gdk-wayland-3.0') -gdk_x11_dep = dependency('gdk-x11-3.0') -gnome_desktop_dep = dependency('gnome-desktop-3.0') -gtk_dep = dependency('gtk+-3.0') -granite_dep = dependency('granite', version: '>= 5.5.0') -hdy_dep = dependency('libhandy-1', version: '>= 1.1.90') +gdk_wl_dep = dependency('gtk4-wayland') +gdk_x11_dep = dependency('gtk4-x11') +gtk_dep = dependency('gtk4') +granite_dep = dependency('granite-7') +adw_dep = dependency('libadwaita-1') lightdm_dep = dependency('liblightdm-gobject-1', version: '>= 1.30.0') m_dep = meson.get_compiler('c').find_library('m') wl_client_dep = dependency('wayland-client') @@ -26,13 +25,12 @@ executable( 'Cards/BaseCard.vala', 'Cards/ManualCard.vala', 'Cards/UserCard.vala', - 'Widgets/BackgroundImage.vala', 'Widgets/CapsLockRevealer.vala', 'Widgets/DateTimeWidget.vala', 'Widgets/PasswordEntry.vala', 'Widgets/SessionButton.vala', config_header, - dependencies: [ accountsservice_dep, gobject_dep, glib_dep, gdk_wl_dep, gdk_x11_dep, gtk_dep, granite_dep, hdy_dep, lightdm_dep, m_dep, pantheon_desktop_shell_dep, wl_client_dep, x11_dep ], + dependencies: [ accountsservice_dep, gobject_dep, glib_dep, gdk_wl_dep, gdk_x11_dep, gtk_dep, granite_dep, adw_dep, lightdm_dep, m_dep, pantheon_desktop_shell_dep, wl_client_dep, x11_dep ], install : true, install_dir: install_path ) From c02dccc082a1050b2cd2f7b3a8e40889a3b80c8d Mon Sep 17 00:00:00 2001 From: lenemter Date: Fri, 24 Jul 2026 17:12:05 +0200 Subject: [PATCH 2/5] Fix warning --- src/Cards/UserCard.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cards/UserCard.vala b/src/Cards/UserCard.vala index 3e51157ea..4652fb9a7 100644 --- a/src/Cards/UserCard.vala +++ b/src/Cards/UserCard.vala @@ -304,7 +304,7 @@ public class Greeter.UserCard : Greeter.BaseCard { if (user_is_logged_in) { avatar_overlay.add_overlay (logged_in); - } else { + } else if (logged_in.parent == avatar_overlay) { avatar_overlay.remove_overlay (logged_in); } } From 950abd0a19b41ac9217128cb363a32d28d6d00f7 Mon Sep 17 00:00:00 2001 From: lenemter Date: Fri, 24 Jul 2026 17:17:10 +0200 Subject: [PATCH 3/5] Update CI --- .github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6dcfb8a8b..b472efbb7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -32,7 +32,7 @@ jobs: - name: Install Dependencies run: | apt update - apt install -y desktop-file-utils libaccountsservice-dev libgdk-pixbuf-2.0-dev libgnome-desktop-3-dev libgranite-dev libgtk-3-dev libhandy-1-dev libjson-glib-dev liblightdm-gobject-1-dev ${{ matrix.mutter_pkg }} libsoup-3.0-dev libx11-dev ${{ matrix.lightdm_vala }} meson valac + apt install -y desktop-file-utils libaccountsservice-dev libgdk-pixbuf-2.0-dev libgnome-desktop-3-dev libgranite-7-dev libgtk-4-dev libadwaita-1-dev libjson-glib-dev liblightdm-gobject-1-dev ${{ matrix.mutter_pkg }} libsoup-3.0-dev libx11-dev ${{ matrix.lightdm_vala }} meson valac - name: Build env: DESTDIR: out @@ -50,7 +50,7 @@ jobs: - uses: actions/checkout@v7 - name: Install Dependencies run: | - dnf install -y accountsservice-devel desktop-file-utils gdk-pixbuf2-devel gnome-desktop3-devel granite-devel gtk3-devel libhandy-devel lightdm-gobject-devel mutter-devel libX11-devel meson valac + dnf install -y accountsservice-devel desktop-file-utils gdk-pixbuf2-devel gnome-desktop3-devel granite-7-devel gtk4-devel libadwaita-devel lightdm-gobject-devel mutter-devel libX11-devel meson valac - name: Build env: DESTDIR: out @@ -69,7 +69,7 @@ jobs: run: | zypper addrepo https://download.opensuse.org/repositories/X11:Pantheon/16.0/X11:Pantheon.repo zypper --gpg-auto-import-keys refresh - zypper --non-interactive install accountsservice-devel accountsservice-vala tar git desktop-file-utils gdk-pixbuf-devel libgnome-desktop-3-devel granite6-devel gtk3-devel libhandy-devel lightdm-gobject-devel mutter-devel meson vala gcc + zypper --non-interactive install accountsservice-devel accountsservice-vala tar git desktop-file-utils gdk-pixbuf-devel libgnome-desktop-3-devel granite-devel gtk4-devel libadwaita-devel lightdm-gobject-devel mutter-devel meson vala gcc - uses: actions/checkout@v7 - name: Build env: From 070c1f44bd6f8537da7381776c8b3186df0dc3d2 Mon Sep 17 00:00:00 2001 From: lenemter Date: Mon, 27 Jul 2026 01:45:23 +0900 Subject: [PATCH 4/5] Remove gdk-wayland-3.0.vapi --- vapi/gdk-wayland-3.0.vapi | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 vapi/gdk-wayland-3.0.vapi diff --git a/vapi/gdk-wayland-3.0.vapi b/vapi/gdk-wayland-3.0.vapi deleted file mode 100644 index f38aab437..000000000 --- a/vapi/gdk-wayland-3.0.vapi +++ /dev/null @@ -1,16 +0,0 @@ -[CCode (cheader_filename = "gdk/gdkwayland.h")] -namespace Gdk.Wayland { - [CCode (type_id = "GDK_TYPE_WAYLAND_WINDOW", type_check_function = "GDK_IS_WAYLAND_WINDOW")] - public class Window : Gdk.Window { - protected Window (); - - public unowned Wl.Surface get_wl_surface (); - } - - [CCode (type_id = "GDK_TYPE_WAYLAND_DISPLAY", type_check_function = "GDK_IS_WAYLAND_DISPLAY")] - public class Display : Gdk.Display { - protected Display (); - - public unowned Wl.Display get_wl_display (); - } -} From 305fbcb19ac0ec141fc1edc4df407f8740d4ce63 Mon Sep 17 00:00:00 2001 From: lenemter Date: Mon, 27 Jul 2026 19:43:03 +0300 Subject: [PATCH 5/5] Don't load css file manually --- src/Application.vala | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Application.vala b/src/Application.vala index e6a92a000..f16745c42 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -41,11 +41,6 @@ public class Greeter.Application : Gtk.Application { Granite.init (); - var css_provider = new Gtk.CssProvider (); - css_provider.load_from_resource ("/io/elementary/greeter/Application.css"); - - Gtk.StyleContext.add_provider_for_display (Gdk.Display.get_default (), css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); - GLib.Bus.own_name ( SESSION, "org.freedesktop.portal.Desktop",