From d6191b99cfbecea3e448044fc20b2f061aa84c91 Mon Sep 17 00:00:00 2001 From: Juan Fernandez Date: Tue, 24 Feb 2026 11:59:35 -0400 Subject: [PATCH] Icon mis sized on KDE envs (#40259) Resolves #36522: Icon mis-sized on KDE Added new icon artifact to be used on KDE environments due to the fact that previous icon appeared mis-sized on KDE envs. --- .../36522-fleet-desktop-icon-mis-sized-kde | 1 + orbit/cmd/desktop/desktop_linux.go | 24 ++++- orbit/cmd/desktop/icon_dark_kde.png | Bin 0 -> 499 bytes orbit/pkg/user/user_linux.go | 96 +++++++++++++----- tools/qacheck/go.mod | 2 - 5 files changed, 94 insertions(+), 29 deletions(-) create mode 100644 orbit/changes/36522-fleet-desktop-icon-mis-sized-kde create mode 100644 orbit/cmd/desktop/icon_dark_kde.png diff --git a/orbit/changes/36522-fleet-desktop-icon-mis-sized-kde b/orbit/changes/36522-fleet-desktop-icon-mis-sized-kde new file mode 100644 index 0000000000..23e5a8b761 --- /dev/null +++ b/orbit/changes/36522-fleet-desktop-icon-mis-sized-kde @@ -0,0 +1 @@ +* Fixed icon size on KDE environments. diff --git a/orbit/cmd/desktop/desktop_linux.go b/orbit/cmd/desktop/desktop_linux.go index 6ba8c06655..ce15d342c3 100644 --- a/orbit/cmd/desktop/desktop_linux.go +++ b/orbit/cmd/desktop/desktop_linux.go @@ -5,13 +5,35 @@ import ( "fmt" "os" "slices" + "strings" + "github.com/fleetdm/fleet/v4/orbit/pkg/user" "github.com/godbus/dbus/v5" "github.com/rs/zerolog/log" ) //go:embed icon_dark.png -var iconDark []byte +var iconDarkDefault []byte + +//go:embed icon_dark_kde.png +var iconDarkKDE []byte + +var iconDark = getIcon() + +func getIcon() []byte { + if isKDE() { + return iconDarkKDE + } + return iconDarkDefault +} + +func isKDE() bool { + session, err := user.GetCurrentUserDisplaySession() + if err != nil { + return false + } + return session != nil && strings.ToLower(session.Desktop) == "kde" +} func blockWaitForStopEvent(_ string) error { log.Debug().Msg("communication channel helpers are not implemented for this platform") diff --git a/orbit/cmd/desktop/icon_dark_kde.png b/orbit/cmd/desktop/icon_dark_kde.png new file mode 100644 index 0000000000000000000000000000000000000000..f58dd916edaff610626fc47ff7db9ce6d098047b GIT binary patch literal 499 zcmeAS@N?(olHy`uVBq!ia0vp^S|H591|*LjJ{b+97>k44ofvPP)Tsw@SkfJR9T^xl z_H+M9WCijSl0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPV z+ueoXKL{?^yL>WGgtNdSvY3HEPZ@+6E0)@q0R`DhJbhi+Uoi;_%geOHl&uB2z}(Zt zF(l&f+vyK`n+CVeNPX0V~zU5l{(>tukjvm=%>16$M4{uL*XYTWwUq&B_)1rEpJ@YXQ zF*b0weDv$|fv;aXUN;v>u?ZGB^rpE?`Tlls>a#4BGV=_3QRDLLUVrr+H@(#u3qI?1sS8rYZJU=Er zJNACryIV)uzTPtWd{wPsU1~OFoevCE22WQ%mvv4FO#o8z!Z`o{ literal 0 HcmV?d00001 diff --git a/orbit/pkg/user/user_linux.go b/orbit/pkg/user/user_linux.go index d812f23ad4..36616f4846 100644 --- a/orbit/pkg/user/user_linux.go +++ b/orbit/pkg/user/user_linux.go @@ -8,6 +8,7 @@ import ( "errors" "fmt" "os/exec" + "os/user" "strconv" "strings" @@ -19,6 +20,30 @@ type User struct { ID int64 } +func getDisplaySessionFor(user User) *UserDisplaySession { + // Skip system/display manager users since they aren't GUI users. + // User gdm-greeter is active during the GUI log-in prompt (GNOME 49). + if user.Name == "gdm" || user.Name == "root" || user.Name == "gdm-greeter" { + return nil + } + // Check if the user has an active GUI session. + userID := strconv.FormatInt(user.ID, 10) + session, err := GetUserDisplaySessionType(userID) + if err != nil { + log.Debug().Err(err).Msgf("failed to get user display session for user %s", user.Name) + return nil + } + if !session.Active { + log.Debug().Msgf("user %s has an inactive display session, skipping", user.Name) + return nil + } + if session.Type == GuiSessionTypeTty { + log.Debug().Msgf("user %s is logged in via TTY, not GUI", user.Name) + return nil + } + return session +} + // UserLoggedInViaGui returns the username that has an active GUI session. // It returns nil, nil if there's no user with an active GUI session. func UserLoggedInViaGui() (*string, error) { @@ -27,27 +52,33 @@ func UserLoggedInViaGui() (*string, error) { return nil, fmt.Errorf("get login users: %w", err) } - for _, user := range users { - // Skip system/display manager users since they aren't GUI users. - // User gdm-greeter is active during the GUI log-in prompt (GNOME 49). - if user.Name == "gdm" || user.Name == "root" || user.Name == "gdm-greeter" { - continue + for _, u := range users { + if session := getDisplaySessionFor(u); session != nil { + return &u.Name, nil } - // Check if the user has an active GUI session. - session, err := GetUserDisplaySessionType(strconv.FormatInt(user.ID, 10)) - if err != nil { - log.Debug().Err(err).Msgf("failed to get user display session for user %s", user.Name) - continue - } - if !session.Active { - log.Debug().Msgf("user %s has an inactive display session, skipping", user.Name) - continue - } - if session.Type == GuiSessionTypeTty { - log.Debug().Msgf("user %s is logged in via TTY, not GUI", user.Name) - continue - } - return &user.Name, nil + } + + // No valid user found + return nil, nil +} + +// GetCurrentUserDisplaySession returns the Display session of the user associated with the current process +func GetCurrentUserDisplaySession() (*UserDisplaySession, error) { + currentUser, err := user.Current() + if err != nil { + return nil, fmt.Errorf("get current user: %w", err) + } + if currentUser == nil { + return nil, nil + } + + uid, err := strconv.ParseInt(currentUser.Uid, 10, 64) + if err != nil { + return nil, fmt.Errorf("parse uid: %w", err) + } + + if session := getDisplaySessionFor(User{Name: currentUser.Username, ID: uid}); session != nil { + return session, nil } // No valid user found @@ -95,12 +126,13 @@ func parseLoginctlUsersOutput(s string) ([]User, error) { // UserDisplaySession holds the display session type and active status for a user. type UserDisplaySession struct { - Type GuiSessionType - Active bool + Type GuiSessionType + Active bool + Desktop string } -// GetUserDisplaySessionType returns the display session type (X11 or Wayland) -// and active status of the given user. Returns an error if the user doesn't have +// GetUserDisplaySessionType returns the display session type (X11 or Wayland), +// active status, and desktop session env var of the given user. Returns an error if the user doesn't have // a Display session. func GetUserDisplaySessionType(uid string) (*UserDisplaySession, error) { // Get the "Display" session ID of the user. @@ -144,9 +176,21 @@ func GetUserDisplaySessionType(uid string) (*UserDisplaySession, error) { return nil, fmt.Errorf("run 'loginctl' to get session active status: %w", err) } active := strings.TrimSpace(stdout.String()) == "yes" + + // Get the "Desktop" property of the session. + cmd = exec.Command("loginctl", "show-session", guiSessionID, "-p", "Desktop", "--value") + stdout.Reset() + cmd.Stdout = &stdout + desktop := "" + if err := cmd.Run(); err != nil { + log.Debug().Err(err).Msgf("failed to get desktop session for user %s", uid) + } else { + desktop = strings.TrimSpace(stdout.String()) + } return &UserDisplaySession{ - Type: sessionType, - Active: active, + Type: sessionType, + Active: active, + Desktop: desktop, }, nil } diff --git a/tools/qacheck/go.mod b/tools/qacheck/go.mod index ecc3b425ff..d175bd75b0 100644 --- a/tools/qacheck/go.mod +++ b/tools/qacheck/go.mod @@ -2,8 +2,6 @@ module qacheck go 1.25.7 -toolchain go1.24.5 - require ( github.com/shurcooL/githubv4 v0.0.0-20260209031235-2402fdf4a9ed golang.org/x/oauth2 v0.35.0