Changing login screen wallpaper

I made a script to easily change the wallpaper of the loginscreen.

It lets the user select an image and set it as the desktop background on Ubuntu MATE. It copies the image to the /usr/share/backgrounds directory, updates the background setting, and recompiles the schemas.

#!/bin/bash

# This script lets the user select an image and
# set it as the desktop background on Ubuntu MATE. It copies
# the image to the /usr/share/backgrounds directory,
# updates the background setting, and recompiles the schemas.
# Philippe734 @ 2025

# Check if YAD installed
if ! command -v yad &> /dev/null; then
    pkexec bash -c "apt install yad -y"
fi

yad --title="Change background login screen" --height=150 --width=400 --fixed --text="<span foreground='blue'><b><big><big>Select your image</big></big></b></span>" --text-align=center --center --borders=20 --image='./design.png'

if [ $? = 1 ]; then
    echo "canceled"
    exit 0
fi

DEST_DIR="/usr/share/backgrounds"
SCHEMA_FILE="/usr/share/glib-2.0/schemas/30_ubuntu-mate.gschema.override"

while true; do
    # Let the user select an image
    IMAGE_PATH=$(yad --file --center --title="Select an image" --width=600 --height=400)
    
    # If no image is selected, exit
    test -z "$IMAGE_PATH" && exit 1
    
    # Check if the selected file is an image
    MIME_TYPE=$(file --mime-type -b "$IMAGE_PATH")
    if [[ $MIME_TYPE =~ ^image/ ]]; then
        break  # Exit the loop if the file is a valid image
    else
        yad --title "Error" --width=400 --height=100 --center --button=OK:0 \
            --text "The selected file is not an image. Please select a valid image file."
    fi
done

# Get the file name without modification
IMAGE_NAME=$(basename "$IMAGE_PATH")

# Final path in /usr/share/backgrounds
FINAL_IMAGE_PATH="$DEST_DIR/$IMAGE_NAME"

# Escape the apostrophes in the image path before running pkexec
ESCAPED_IMAGE_PATH=$(echo "$FINAL_IMAGE_PATH" | sed "s/'/'\\\\''/g")

# Call pkexec to execute commands as root
pkexec bash -c "

    # Copy the image and modify the schema
    cp -f \"$IMAGE_PATH\" \"$FINAL_IMAGE_PATH\"

    # Change permissions of the copied image to make it readable by others
    chmod 644 "$FINAL_IMAGE_PATH"

    # Modify the schema file to set the new background image path
    sed -i \"s|^background=.*|background='$ESCAPED_IMAGE_PATH'|\" \"$SCHEMA_FILE\"
    
    # Compile the schemas
    glib-compile-schemas /usr/share/glib-2.0/schemas/
"

# Display the final result
echo "### result:"
grep "^background=" "$SCHEMA_FILE"
echo "###"

notify-send "Done" "You should logout"

exit 0

10 Likes

Excellent !!
I am just curious about the line IMAGE_NAME=$(basename "$IMAGE_PATH") since you do not use $IMAGE_NAME in the rest of the script.

1 Like

try again :slight_smile:

2 Likes

Thank you, Philippe! That was excellent.

I hope you don't mind, but I have modified/extended the program, because I was expecting to see a visual of the image overlap, as you showed in you posted image, and was surprised/disappointed that I was not getting that. So, I modified the code to make it show the two choices side-by-side, before confirming a final commit.

:slight_smile:


First Dialog:


Third Dialog:


Modified code:

[Edit: Script updated with improved, more robust logic, to identify the correct relevant schema file.]

[Edit: Version 5 - Final error correction to make language-specfic customization work as intended.]

#!/bin/bash

# This script lets the user select an image and
# set it as the desktop background on Ubuntu MATE. It copies
# the image to the /usr/share/backgrounds directory,
# updates the background setting, and recompiles the schemas.
# Philippe734 @ 2025
#
#	REF:	https://ubuntu-mate.community/t/changing-wallpaper-login-screen/29222
#
# REVISED:
# 	by Eric Marceau
# 	Version 1 - Expanded logic added and dialog presentation modified
# 	Version 2 - Revised logic to make identification of relevant schema file more robust
# 	Version 3 - Revised logic to identify locale and created file allowing language-specific customization
# 	Version 4 - Corrected error of omission to load locale-driven language-specific customization
# 	Version 5 - Final error correction to make language-specfic customization work as intended
#


setupLang()
{
	scriptName=$0
	scriptLocn=$( dirname "$0" )
	scriptBase=$( basename "$0" ".sh" )

	msgStrng=( \
	"Login Screen Wallpaper" \
	"    Choose different image?" \
	"Keep Old" \
	"Choose New" \
	"Current Login Wallpaper" \
	"Chosen Replacement" \
	"Confirm Choice To Replace" \
	"Retain Current" \
	"Confirm Change" \
	"Login configuration updated." \
	"You should confirm the change by performing logout." )

	thisLocale=$( env | grep 'LANG=' | cut -f2- -d"=" | cut -f1 -d":" | cut -f1 -d"." | cut -f1 -d"_" )
	thisLocale=fr

	scriptLang="${scriptLocn}/${scriptBase}.${thisLocale}"

	if [ -s "${scriptLang}" ]
	then
		if [ -n "$( diff "${scriptLocn}/${scriptBase}.en" "${scriptLang}" | head -1 )" ]
		then
			echo "differences" >&2
			indx=0
			while read line
			do
				msgStrng[${indx}]="${line}"
				indx=$(expr ${indx} + 1 )
			done <"${scriptLang}"
		else
			echo -e "\n Please note that you can use prompt strings in your own language by replacing the strings for each line in file intended for your locale:"
			{ ls -l "${scriptLocn}/${scriptBase}.en"
			  ls -l "${scriptLang}"
			} | awk '{ printf("\t %s\n", $0 ) ; }'
			echo -e "\n The '${scriptLocn}/${scriptBase}.en' file has been provided as a baseline for the meaning of those strings.\n"
		fi
	else
		if [ ! -s "${scriptLocn}/${scriptBase}.en" ]
		then
			count=${#msgStrng[@]}
			indx=0
			while [ ${indx} -lt ${count} ]
			do
				echo "${msgStrng[${indx}]}"
				indx=$(expr ${indx} + 1 )
			done >"${scriptLocn}/${scriptBase}.en"
		fi

		if [ ! -s "${scriptLang}" ]
		then
			cp -p "${scriptLocn}/${scriptBase}.en" "${scriptLang}"
		fi
	fi

}


getThumb()
{
	local imageIn="$1"
	local imageOut="$2"
	convert ${imageIn} -resize 15% ${imageOut}
}


#########################################################################################
#########################################################################################


if [ "$1" = "--verbose" ] ; then  dbg=1 ; else  dbg=0 ; fi

destDir="/usr/share/backgrounds"

setupLang

###
###	Ensuring required functionality is available
###

if [ -z "$(which yad 2>>/dev/null)" ]
then
	echo -e "\n The required 'YAD' utility is missing.  Install? [y|N] => \c" ; read ans
	test -n "${ans}" || { ans="N" ; }
	case "${ans}" in
		y* | Y* ) ;;
		* ) echo "\n Abandonning attempt to change the Login wallpaper.\n" ; exit 1 ;;
	esac
	pkexec bash -c "apt install yad -y"
fi


###
###	Identify system's active login greeter
###

method1()
{
	###
	###	Approach which would be more generic and suited to both X-Window and Wayland
	###
	sysGreeter=$( grep "session" /var/log/syslog | head -40 | grep 'greeter' | head -1 | 
		awk '{
			pos=index( $0, "comm=" ) ;
			if( pos > 0 ){
				rem=substr( $0, pos ) ;
					n=split( rem, val, "\"" ) ;
				print val[2] ;
				exit ;
				#substr( rem, pos+6, psp-2 ) ;
			} ;
		}' | sed 's+[ ]$++' )
	sysGreeter=$( basename "${sysGreeter}" )
}
method1

method2()
{
	###
	###	Alternate approach, but X-windows specific
	###
	if [ ! -s /var/log/lightdm/seat0-greeter.log ]
	then
		echo -e "\n\t LightDM does not appear to be the active Display Manager.  Unable to proceed.\n" ; exit 1
	fi

	#[+3.90s] DEBUG: arctica-greeter.vala:937: Starting main loop
	sysGreeter=$( grep '[:][ ]Starting main loop' /var/log/lightdm/seat0-greeter.log | awk '{ print $3 }' | cut -f1 -d"." )
}
#method2()

test ${dbg} -eq 1 && echo "${sysGreeter}"


###
###	Allow for local extra schema override file being distinct from default file
###
greetMatch=$( grep "${sysGreeter}" /usr/share/glib-2.0/schemas/*.gschema.override | sort -r | head -1 )
test ${dbg} -eq 1 && echo "${greetMatch}"

#schemaFile="$(ls -r /usr/share/glib-2.0/schemas/*_ubuntu-mate.gschema.override | head -1 )"
schemaFile="$( echo "${greetMatch}" | cut -f1 -d":" )"
test ${dbg} -eq 1 && echo "${schemaFile}"


###
###	Identify fullpathname to current Login Greeter background image
###

greeterSchema=$( gsettings list-schemas | grep ${sysGreeter} )
if [ -z "${greeterSchema}" ] ; then  echo -e "\n\t Unable to identify schema for greeter '${sysGreeter}'. Unable to proceed.\n" ; exit 1 ; fi

current="$( gsettings get "${greeterSchema}" background | cut -f2 -d\'  | sed 's+^file://++' )" 
test ${dbg} -eq 1 && echo ${current}

tCurrent="/tmp/$$.orig" ; rm -f "${tCurrent}"

getThumb "${current}" "${tCurrent}"
test $? -eq 0 || { echo "\t Failed to create thumbnail for existing wallpaper.\n" ; exit 1 ; }
test ${dbg} -eq 1 && eom "${tCurrent}"


###
###	Prompt for selection of new wallpaper image
###

yad	--width=500 \
	--height=200 \
	--borders=20 \
	--title="${msgStrng[0]}" \
	--fixed \
	--text="<span foreground='orange'><b><big><big>\n${msgStrng[1]}</big></big></b></span>" \
	--text-align=left \
	--center \
	--button="${msgStrng[2]}":1 \
	--button="${msgStrng[3]}":0 \
	--image="${tCurrent}"

if [ $? -ne 0 ]
then
	echo -e "Login configuration specifying existing wallpaper not modified."
	exit 0
fi

while true
do
	# Let the user select an image
	newImg=$(yad --file --center --title="Select an image" --width=1000 --height=500)
    
	# If no image is selected, exit
	test -z "${newImg}" && exit 1
    
	# Check if the selected file is an image
	mimeType=$(file --mime-type -b "${newImg}")
	if [[ ${mimeType} =~ ^image/ ]]
	then
		break  # Exit the loop if the file is a valid image
	else
		yad --title "Error" --width=400 --height=100 --center --button=OK:0 \
		    --text "The selected file is not an image. Please select a valid image file."
	fi
done

newImg="${newImg}"
tNewImg="/tmp/$$.new" ; rm -f "${tNewImg}"

getThumb "${newImg}" "${tNewImg}"
test $? -eq 0 || { echo "\t Failed to create thumbnail for selected new wallpaper.\n" ; exit 1 ; }
test ${dbg} -eq 1 && eom "${tNewImg}"


###
###	Setting up compound yad pane with 2 panels, to confirm choices and final action
###

# Generate a unique key for the plug mechanism
assemblyPlugPrivKey="${RANDOM}987"
test ${dbg} -eq 1 && echo ${assemblyPlugPrivKey}

# Panel dialog for first image in plug mode in background
yad	--plug=${assemblyPlugPrivKey} \
	--tabnum=1 \
	--picture \
	--filename="${tCurrent}" \
	--size=fit \
	--text-align=center \
	--text="<span foreground='orange'><b><big>\n${msgStrng[4]}</big></b></span>" &

# Panel dialog for second image in plug mode in background
yad	--plug=${assemblyPlugPrivKey} \
	--tabnum=2 \
	--picture \
	--filename="${tNewImg}" \
	--size=fit \
	--text-align=center \
	--text="<span foreground='orange'><b><big>\n${msgStrng[5]}</big></b></span>" &

# Display combined two-paned dialog using the background dialog plugs
yad	--title="${msgStrng[6]}" \
	--paned \
	--key=${assemblyPlugPrivKey} \
	--center \
	--orient=Horizontal \
	--splitter=275 \
	--width=550 \
	--height=300 \
	--buttons-layout=spread \
	--button="${msgStrng[7]}":1 \
	--button="${msgStrng[8]}":0

if [ $? -ne 0 ]
then
	echo -e "Login configuration specifying existing wallpaper not modified."
	exit 0
fi

###
###	Update the Login Greeter configuration to apply the selected change
###

# Get the file name without modification
imageName=$(basename "${newImg}")

# Final path in /usr/share/backgrounds
finalNewImg="${destDir}/${imageName}"

# Escape the apostrophes in the image path before running pkexec
# NOTE:  maintaining single quotes in filenames is not recommended.
escapedNewImg=$(echo "${finalNewImg}" | sed "s/'/'\\\\''/g")

# Call pkexec to execute commands as root
pkexec bash -c "

	# Copy the image and modify the schema
	cp -f \"${newImg}\" \"${finalNewImg}\"

	# Change permissions of the copied image to make it readable by others
	chmod 644 "${finalNewImg}"

	# Modify the schema file to set the new background image path
	sed -i \"s|^background=.*|background='${escapedNewImg}'|\" \"${schemaFile}\"
    
	# Compile the schemas
	glib-compile-schemas /usr/share/glib-2.0/schemas/
"

# Display the final result
echo -e "\n Summary of applied changes:"
echo -e "\t File:     '${schemaFile}'"
echo -e "\t Revised:  $( grep "^background=" "${schemaFile}" ) \n"

notify-send "${msgStrng[9]}" "${msgStrng[10]}"

exit 0
5 Likes

Wonderful! I prefer yours!

2 Likes

The only issue I have with this script is the automatic installation of yad if it isn't present. Personally, I like and use yad, but there is no user choice given that this is going to happen. That violates what I consider being "user-friendly." I'd prefer to be given the option, i.e. a prompt that asks the user if it's alright to install yad and to bail out if the answer is 'no.'

A small nit, but my personal opinion is that the user should be made aware of attempts to modify the system in this way.

2 Likes

My bad …. I used my eyes instead of a search-word tool :grin: :man_shrugging:

2 Likes

Good point, Fred! I've added logic to cover that and updated the script in my posting above.

:slight_smile:

2 Likes

Much better! It's always nice to be polite and considerate. :slight_smile:

1 Like

Can anyone out there try out the new logic I thru in there to allow for string-value load for user-defined strings in locale-oriented file?

Default file for English:

Login Screen Wallpaper
    Choose different image?
Keep Old
Choose New
Current Login Wallpaper
Chosen Replacement
Confirm Choice To Replace
Retain Current
Confirm Change
Login configuration updated.
You should confirm the change by performing logout.

Sample file for French:

Fond d'écran d'accès
    Choisir une autre image ?
Conserver l'ancienne
Choisir une nouvelle
Fond d'écran actuel
Remplacement choisi
Confirmer le choix
Conserver l'actuelle
Confirmer la modification
Configuration d'acceuil a été mise à jour
Vous devriez confirmer la modification en vous déconnectant.
1 Like