diff --git a/README.md b/README.md index ef107a86..5db5eb94 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,6 @@ You'll need the following dependencies: - libaccountsservice-dev libgirepository1.0-dev libglib2.0-dev libgranite-dev >= 5.3.0 diff --git a/meson.build b/meson.build index b668e1c5..53001678 100644 --- a/meson.build +++ b/meson.build @@ -30,14 +30,10 @@ shared_module( meson.project_name(), 'src/Indicator.vala', 'src/Widgets/EndSessionDialog.vala', - 'src/Widgets/UserBox.vala', - 'src/Widgets/UserListBox.vala', 'src/Services/DbusInterfaces.vala', - 'src/Services/UserManager.vala', 'src/Services/EndSessionDialogServer.vala', config_vala, dependencies: [ - dependency('accountsservice'), dependency('glib-2.0'), dependency('gobject-2.0'), dependency('granite', version: '>=5.3.0'), diff --git a/po/POTFILES b/po/POTFILES index 4246b6da..ce48030d 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -1,6 +1,3 @@ src/Indicator.vala src/Widgets/EndSessionDialog.vala -src/Widgets/UserBox.vala -src/Widgets/UserListBox.vala src/Services/DbusInterfaces.vala -src/Services/UserManager.vala diff --git a/src/Indicator.vala b/src/Indicator.vala index c575757d..9eb81d53 100644 --- a/src/Indicator.vala +++ b/src/Indicator.vala @@ -33,11 +33,9 @@ public class Session.Indicator : Wingpanel.Indicator { private Gtk.ModelButton shutdown; private Gtk.ModelButton log_out; - private Session.Services.UserManager manager; private Widgets.EndSessionDialog? current_dialog = null; private Gtk.Box? main_box; - private string active_user_real_name; private static GLib.Settings? keybinding_settings; @@ -51,8 +49,6 @@ public class Session.Indicator : Wingpanel.Indicator { EndSessionDialogServer.init (); EndSessionDialogServer.get_default ().show_dialog.connect ((type) => show_dialog ((Widgets.EndSessionDialogType)type)); - - manager = new Session.Services.UserManager (); } static construct { @@ -65,13 +61,10 @@ public class Session.Indicator : Wingpanel.Indicator { if (indicator_icon == null) { indicator_icon = new Gtk.Image () { icon_name = ICON_NAME, - pixel_size = 24 + pixel_size = 24, + tooltip_markup = Granite.TOOLTIP_SECONDARY_TEXT_MARKUP.printf (_("Middle-click to prompt to shut down")) }; - manager.changed.connect (() => { - update_tooltip.begin (); - }); - indicator_icon.button_press_event.connect ((e) => { if (e.button == Gdk.BUTTON_MIDDLE) { if (session_interface == null) { @@ -132,25 +125,6 @@ public class Session.Indicator : Wingpanel.Indicator { }; if (server_type == Wingpanel.IndicatorManager.ServerType.SESSION) { - if (!is_running_in_demo_mode ()) { - var users_separator = new Gtk.Separator (Gtk.Orientation.HORIZONTAL) { - margin_top = 3, - margin_bottom = 3 - }; - - var scrolled_box = new Gtk.ScrolledWindow (null, null) { - hexpand = true, - hscrollbar_policy = Gtk.PolicyType.NEVER, - max_content_height = 300, - propagate_natural_height = true - }; - scrolled_box.add (manager.user_grid); - - main_box.add (scrolled_box); - main_box.add (user_settings); - main_box.add (users_separator); - } - var logout_separator = new Gtk.Separator (Gtk.Orientation.HORIZONTAL) { margin_top = 3, margin_bottom = 3 @@ -192,8 +166,6 @@ public class Session.Indicator : Wingpanel.Indicator { } } - manager.close.connect (() => close ()); - user_settings.clicked.connect (() => { close (); @@ -291,13 +263,7 @@ public class Session.Indicator : Wingpanel.Indicator { } } - public override void opened () { - if (server_type == Wingpanel.IndicatorManager.ServerType.SESSION && !is_running_in_demo_mode ()) { - manager.update_all (); - } - - main_box.show_all (); - } + public override void opened () {} public override void closed () {} @@ -356,56 +322,6 @@ public class Session.Indicator : Wingpanel.Indicator { current_dialog.show_all (); } - - private async void update_tooltip () { - string description; - - if (server_type == Wingpanel.IndicatorManager.ServerType.SESSION && !is_running_in_demo_mode ()) { - if (active_user_real_name == null) { - active_user_real_name = Environment.get_real_name (); - } - - int n_online_users = (yield manager.get_n_active_and_online_users ()) - 1; - - if (n_online_users > 0) { - description = dngettext ( - GETTEXT_PACKAGE, - "Logged in as “%s”, %i other user logged in", - "Logged in as “%s”, %i other users logged in", - n_online_users - ); - description = description.printf (active_user_real_name, n_online_users); - } else { - description = _("Logged in as “%s”").printf (active_user_real_name); - } - } else { - description = _("Not logged in"); - } - - string accel_label = Granite.TOOLTIP_SECONDARY_TEXT_MARKUP.printf (_("Middle-click to prompt to shut down")); - - indicator_icon.tooltip_markup = "%s\n%s".printf ( - description, - accel_label - ); - } - - private bool is_running_in_demo_mode () { - var proc_cmdline = File.new_for_path ("/proc/cmdline"); - try { - var @is = proc_cmdline.read (); - var dis = new DataInputStream (@is); - - var line = dis.read_line (); - if ("boot=casper" in line || "boot=live" in line || "rd.live.image" in line) { - return true; - } - } catch (Error e) { - critical ("Couldn't detect if running in Demo Mode: %s", e.message); - } - - return false; - } } public Wingpanel.Indicator? get_indicator (Module module, Wingpanel.IndicatorManager.ServerType server_type) { diff --git a/src/Services/DbusInterfaces.vala b/src/Services/DbusInterfaces.vala index b6170c92..b9c4877d 100644 --- a/src/Services/DbusInterfaces.vala +++ b/src/Services/DbusInterfaces.vala @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2017 elementary LLC. (http://launchpad.net/wingpanel) + * Copyright 2011-2023 elementary, Inc. (http://launchpad.net/wingpanel) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public @@ -17,12 +17,6 @@ * Boston, MA 02110-1301 USA */ -struct UserInfo { - uint32 uid; - string user_name; - ObjectPath? user_object; -} - [DBus (name = "org.gnome.SessionManager")] interface SessionInterface : Object { public abstract async void logout (uint type) throws GLib.Error; @@ -41,18 +35,4 @@ interface SystemInterface : Object { public abstract void suspend (bool interactive) throws GLib.Error; public abstract void reboot (bool interactive) throws GLib.Error; public abstract void power_off (bool interactive) throws GLib.Error; - - public abstract UserInfo[] list_users () throws GLib.Error; -} - -[DBus (name = "org.freedesktop.login1.User")] -interface UserInterface : Object { - public abstract string state { owned get; } -} - -[DBus (name = "org.freedesktop.DisplayManager.Seat")] -interface SeatInterface : Object { - public abstract bool has_guest_account { get; } - public abstract void switch_to_guest (string session_name) throws GLib.Error; - public abstract void switch_to_user (string username, string session_name) throws GLib.Error; } diff --git a/src/Services/UserManager.vala b/src/Services/UserManager.vala deleted file mode 100644 index bcfdc9f8..00000000 --- a/src/Services/UserManager.vala +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (c) 2011-2020 elementary, Inc. (https://elementary.io) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -public enum UserState { - ACTIVE, - ONLINE, - OFFLINE; - - public static UserState to_enum (string state) { - switch (state) { - case "active": - return UserState.ACTIVE; - case "online": - return UserState.ONLINE; - } - - return UserState.OFFLINE; - } -} - -public class Session.Services.UserManager : Object { - public signal void close (); - public signal void changed (); - - public Session.Widgets.UserListBox user_grid { get; private set; } - - private const uint GUEST_USER_UID = 999; - private const uint NOBODY_USER_UID = 65534; - private const uint RESERVED_UID_RANGE_END = 1000; - - private const string DM_DBUS_ID = "org.freedesktop.DisplayManager"; - private const string LOGIN_IFACE = "org.freedesktop.login1"; - private const string LOGIN_PATH = "/org/freedesktop/login1"; - - private Act.UserManager manager; - private Gee.HashMap? user_boxes; - private SeatInterface? dm_proxy = null; - - private static SystemInterface? login_proxy; - - static construct { - init_login_proxy.begin (); - } - - private static async void init_login_proxy () { - try { - login_proxy = yield Bus.get_proxy (BusType.SYSTEM, LOGIN_IFACE, LOGIN_PATH, DBusProxyFlags.NONE); - } catch (IOError e) { - critical ("Failed to create login1 dbus proxy: %s", e.message); - } - } - - public static async UserState get_user_state (uint32 uuid) { - if (login_proxy == null) { - return UserState.OFFLINE; - } - - try { - UserInfo[] users = login_proxy.list_users (); - if (users == null) { - return UserState.OFFLINE; - } - - foreach (UserInfo user in users) { - if (user.uid == uuid) { - if (user.user_object == null) { - return UserState.OFFLINE; - } - UserInterface? user_interface = yield Bus.get_proxy (BusType.SYSTEM, LOGIN_IFACE, user.user_object, DBusProxyFlags.NONE); - if (user_interface == null) { - return UserState.OFFLINE; - } - return UserState.to_enum (user_interface.state); - } - } - - } catch (GLib.Error e) { - critical ("Failed to get user state: %s", e.message); - } - - return UserState.OFFLINE; - } - - public static async UserState get_guest_state () { - if (login_proxy == null) { - return UserState.OFFLINE; - } - - try { - UserInfo[] users = login_proxy.list_users (); - foreach (UserInfo user in users) { - var state = yield get_user_state (user.uid); - if (user.user_name.has_prefix ("guest-") - && state == UserState.ACTIVE) { - return UserState.ACTIVE; - } - } - } catch (GLib.Error e) { - critical ("Failed to get Guest state: %s", e.message); - } - - return UserState.OFFLINE; - } - - construct { - user_boxes = new Gee.HashMap (); - - user_grid = new Session.Widgets.UserListBox (); - user_grid.close.connect (() => close ()); - - manager = Act.UserManager.get_default (); - init_users (); - - manager.user_added.connect (add_user); - manager.user_removed.connect (remove_user); - manager.user_is_logged_in_changed.connect (update_user); - - manager.notify["is-loaded"].connect (() => { - init_users (); - }); - - var seat_path = Environment.get_variable ("XDG_SEAT_PATH"); - var session_path = Environment.get_variable ("XDG_SESSION_PATH"); - - if (seat_path != null) { - try { - dm_proxy = Bus.get_proxy_sync (BusType.SYSTEM, DM_DBUS_ID, seat_path, DBusProxyFlags.NONE); - if (dm_proxy.has_guest_account) { - add_guest (); - } - } catch (IOError e) { - critical ("UserManager error: %s", e.message); - } - } - - if (dm_proxy != null) { - user_grid.switch_to_guest.connect (() => { - try { - dm_proxy.switch_to_guest (""); - } catch (Error e) { - warning ("Error switching to guest account: %s", e.message); - } - }); - - user_grid.switch_to_user.connect ((username) => { - try { - dm_proxy.switch_to_user (username, session_path); - } catch (Error e) { - warning ("Error switching to user '%s': %s", username, e.message); - } - }); - } - } - - private void init_users () { - if (!manager.is_loaded) { - return; - } - - foreach (Act.User user in manager.list_users ()) { - add_user (user); - } - } - - private void add_user (Act.User? user) { - // Don't add any of the system reserved users - var uid = user.get_uid (); - if (uid < RESERVED_UID_RANGE_END || uid == NOBODY_USER_UID || user_boxes.has_key (uid)) { - return; - } - - user_boxes[uid] = new Session.Widgets.Userbox (user); - user_grid.add (user_boxes[uid]); - - changed (); - } - - private void remove_user (Act.User user) { - var uid = user.get_uid (); - var userbox = user_boxes[uid]; - if (userbox == null) { - return; - } - - user_boxes.unset (uid); - user_grid.remove (userbox); - changed (); - } - - private void update_user (Act.User user) { - var userbox = user_boxes[user.get_uid ()]; - if (userbox == null) { - return; - } - - userbox.update_state.begin (); - changed (); - } - - public void update_all () { - foreach (var userbox in user_boxes.values) { - userbox.update_state.begin (); - } - } - - private void add_guest () { - if (user_boxes[GUEST_USER_UID] != null) { - return; - } - - user_boxes[GUEST_USER_UID] = new Session.Widgets.Userbox.guest (); - user_boxes[GUEST_USER_UID].show (); - - user_grid.add (user_boxes[GUEST_USER_UID]); - } - - // Can't use JUST online users, see comment below. - public async int get_n_active_and_online_users () { - int n_active_and_online_users = 0; - - if (!manager.is_loaded) { - critical ("UserManager not yet loaded"); - return n_active_and_online_users; - } - - foreach (var user in manager.list_users ()) { - // Skip system reserved users - if (user.uid < RESERVED_UID_RANGE_END || user.uid == NOBODY_USER_UID) { - continue; - } - - var state = yield get_user_state (user.uid); - - /* Because the user_changed signal gets emitted - BEFORE the next user is logged in/ACTIVE, we'll - need to check for both cases and deduct by 1 - later (there can only be one ACTIVE user) unless - Act.UserManager has a signal that I can connect - that gets emitted AFTER login. */ - if (state == UserState.ACTIVE || state == UserState.ONLINE) { - n_active_and_online_users++; - } - } - - return n_active_and_online_users; - } -} diff --git a/src/Widgets/UserBox.vala b/src/Widgets/UserBox.vala deleted file mode 100644 index 387da167..00000000 --- a/src/Widgets/UserBox.vala +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2011-2017 elementary LLC. (http://launchpad.net/wingpanel) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -public class Session.Widgets.Userbox : Gtk.ListBoxRow { - private const int ICON_SIZE = 48; - - public Act.User? user { get; construct; default = null; } - public string fullname { get; construct set; } - public UserState state { get; private set; } - - public bool is_guest { - get { - return user == null; - } - } - - private Hdy.Avatar avatar; - private Gtk.Label fullname_label; - private Gtk.Label status_label; - - public Userbox (Act.User user) { - Object (user: user); - } - - public Userbox.guest () { - Object (fullname: _("Guest")); - } - - construct { - fullname_label = new Gtk.Label ("%s".printf (fullname)) { - use_markup = true, - valign = Gtk.Align.END, - halign = Gtk.Align.START - }; - - status_label = new Gtk.Label (null) { - valign = Gtk.Align.START, - halign = Gtk.Align.START - }; - - if (user == null) { - avatar = new Hdy.Avatar (ICON_SIZE, null, false); - // We want to use the user's accent, not a random color - unowned Gtk.StyleContext avatar_context = avatar.get_style_context (); - avatar_context.remove_class ("color1"); - avatar_context.remove_class ("color2"); - avatar_context.remove_class ("color3"); - avatar_context.remove_class ("color4"); - avatar_context.remove_class ("color5"); - avatar_context.remove_class ("color6"); - avatar_context.remove_class ("color7"); - avatar_context.remove_class ("color8"); - avatar_context.remove_class ("color9"); - avatar_context.remove_class ("color10"); - avatar_context.remove_class ("color11"); - avatar_context.remove_class ("color12"); - avatar_context.remove_class ("color13"); - avatar_context.remove_class ("color14"); - } else { - avatar = new Hdy.Avatar (ICON_SIZE, fullname, true); - avatar.set_image_load_func (avatar_image_load_func); - - user.changed.connect (() => { - update (); - update_state.begin (); - }); - - user.bind_property ("locked", this, "visible", BindingFlags.SYNC_CREATE | BindingFlags.INVERT_BOOLEAN); - user.bind_property ("locked", this, "no-show-all", BindingFlags.SYNC_CREATE); - user.bind_property ("real-name", avatar, "text", BindingFlags.SYNC_CREATE); - - update (); - } - - var grid = new Gtk.Grid () { - column_spacing = 12 - }; - grid.attach (avatar, 0, 0, 3, 3); - grid.attach (fullname_label, 3, 0, 2, 1); - grid.attach (status_label, 3, 1, 2, 1); - - get_style_context ().add_class ("menuitem"); - add (grid); - - update_state.begin (); - } - - private Gdk.Pixbuf? avatar_image_load_func (int size) { - try { - var pixbuf = new Gdk.Pixbuf.from_file (user.get_icon_file ()); - return pixbuf.scale_simple (size, size, Gdk.InterpType.BILINEAR); - } catch (Error e) { - debug (e.message); - return null; - } - } - - // For some reason Act.User.is_logged_in () does not work - public async UserState get_user_state () { - if (is_guest) { - return yield Services.UserManager.get_guest_state (); - } else { - return yield Services.UserManager.get_user_state (user.get_uid ()); - } - } - - private void update () { - if (user == null) { - return; - } - - fullname_label.label = "%s".printf (user.real_name); - avatar.set_image_load_func (avatar_image_load_func); - } - - public async void update_state () { - state = yield get_user_state (); - - selectable = state != UserState.ACTIVE; - activatable = state != UserState.ACTIVE; - - if (state == UserState.ONLINE || state == UserState.ACTIVE) { - status_label.label = _("Logged in"); - } else { - status_label.label = _("Logged out"); - } - - changed (); - show_all (); - } - - public override bool draw (Cairo.Context ctx) { - if (!get_selectable ()) { - get_style_context ().set_state (Gtk.StateFlags.NORMAL); - } - - return base.draw (ctx); - } -} diff --git a/src/Widgets/UserListBox.vala b/src/Widgets/UserListBox.vala deleted file mode 100644 index 62cde108..00000000 --- a/src/Widgets/UserListBox.vala +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2011-2017 elementary LLC. (http://launchpad.net/wingpanel) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - - public class Session.Widgets.UserListBox : Gtk.ListBox { - public signal void close (); - public signal void switch_to_guest (); - public signal void switch_to_user (string username); - - construct { - set_sort_func (sort_func); - activate_on_single_click = true; - } - - public override void row_activated (Gtk.ListBoxRow row) { - var userbox = (Userbox) row; - if (userbox == null) { - return; - } - - close (); - if (userbox.is_guest) { - switch_to_guest (); - } else { - var user = userbox.user; - if (user != null) { - switch_to_user (user.get_user_name ()); - } - } - } - - // We could use here Act.User.collate () but we want to show the logged user first - public int sort_func (Gtk.ListBoxRow row1, Gtk.ListBoxRow row2) { - var userbox1 = (Userbox) row1; - var userbox2 = (Userbox) row2; - - if (userbox1.state == UserState.ACTIVE) { - return -1; - } else if (userbox2.state == UserState.ACTIVE) { - return 1; - } - - if (userbox1.is_guest && !userbox2.is_guest) { - return 1; - } else if (!userbox1.is_guest && userbox2.is_guest) { - return -1; - } - - return 0; - } -}