Xfce Forum

Sub domains
 

You are not logged in.

#1 2024-06-04 10:40:00

Misko_2083
Member
Registered: 2015-10-13
Posts: 211
Website

Fun with xfconf-query and yad

Not for general use just as an experiment and fun.
And don't use it unless you know what you are doing.

I made a script to list and change some xfconf properties.
Uses latest yad for UI and xmllint to scrape property value types  from xml (becase xfconf-query doesn't print types).

#!/bin/bash

# install libxml2-utils and latest yad from github
hash xmllint 2>/dev/null || { echo >&2 "This script requires xmllint but it's not installed.  Aborting."; exit 1; }

# Function to get properties of a channel
get_properties() {
    local channel="${1/?*" "}"
    local properties=$(xfconf-query -l -c "$channel")
    local prop_array=($properties)
    local prop_string=""
    for ((i=0; i<${#prop_array[@]}; i++)); do
        prop_string+="${prop_array[i]}"
        if [ $i -lt $((${#prop_array[@]}-1)) ]; then
            prop_string+="!"
        fi
    done
    # If no properties are found, add a message indicating this
    if [ -z "$prop_string" ]; then
        prop_string="@disabled@"
    fi
    echo "${prop_string}"
}
export -f get_properties

# Function to handle channel change
handle_channel_change() {
    if [ "$1" -eq 1 ]; then
        local channel="$2"
        local properties=$(xfconf-query -l -c "$channel")
        local prop_array=($properties)
        local prop_string=""
        for ((i=0; i<${#prop_array[@]}; i++)); do
            prop_string+="${prop_array[i]}"
            if [ $i -lt $((${#prop_array[@]}-1)) ]; then
                prop_string+="!"
            fi
        done
        # If no properties are found, add a message indicating this
        if [ -z "$prop_string" ]; then
            prop_string="@disabled@"
        fi
        echo "2:${prop_string}"
    fi
}
export -f handle_channel_change

# Function to handle button click to set selected property
set_property() {
    local selected_channel="$1"
    local selected_property="$2"
    local type="$3"
    local value="$4"

    # Set the property with the selected value
    xfconf-query -c "$selected_channel" -p "$selected_property" -t "$type" -s "$value"
    yad --info --text="Property $selected_property set to $value"
}
export -f set_property

# Function to get property type and value from XML file
get_property_info() {
    local channel="$1"
    local property="$2"
    local filename="$HOME/.config/xfce4/xfconf/xfce-perchannel-xml/${channel}.xml"
    if [[ ! -f "$filename" ]]; then
        echo "Property file $filename not found."
        return 1
    fi

    local type=$(xmllint --xpath "string(//property[@name='$property']/@type)" "$filename")
    local value=$(xmllint --xpath "string(//property[@name='$property']/@value)" "$filename")

    if [[ -z "$type" ]]; then
        # Handle nested properties
        type=$(xmllint --xpath "string(//property[@name='$property']//value/@type)" "$filename")
        value=$(xmllint --xpath "string(//property[@name='$property']//value/@value)" "$filename")
    fi

    if [[ -z "$type" ]]; then
        echo "Property \"$property\" not found in channel \"$channel\"."
        return 1
    fi

    echo "$type $value"
    return 0
}
export -f get_property_info

# Function to handle button click to get selected property
get_property() {
    local selected_channel="$1"
    local selected_property="$2"
    local value=$(xfconf-query -c "$selected_channel" -p "$selected_property")
    create_set_dialog "$selected_channel" "$selected_property"
}
export -f get_property

# Function to create a form dialog for setting array property
create_set_array_dialog() {
    local selected_channel="$1"
    local selected_property="${2}"
    local filename="$HOME/.config/xfce4/xfconf/xfce-perchannel-xml/${selected_channel}.xml"
    local current_values=()
    local current_types=()
    local form_fields=()
    local count=0

    # Read array elements from the XML file
    while IFS= read -r line; do
        [[ -z "$line" ]] && continue
        local value=$(printf '%b\n' "$line" | xmllint --xpath "string(//value/@value)" -)
        local type=$(printf '%b\n' "$line" | xmllint --xpath "string(//value/@type)" -)

        case "$type" in
            "string")
                form_fields+=("--field=Value $count:TXT")
                ;;
            "int" | "uint" | "int64" | "uint64")
                form_fields+=("--field=Value $count:NUM")
                ;;
            "double")
                field="--field=${selected_property}:NUM"
                current_value="${current_value}!0..1!0.1"
                ;;
            "bool")
                form_fields+=("--field=Value-$count:CHK")
                if [[ "$value" == "true" ]]; then
                    value="TRUE"
                else
                    value="FALSE"
                fi
                ;;
            *)
                form_fields+=("--field=Value $count:TXT")
                ;;
        esac
        current_types+=("$type")
        current_values+=("$value")
        count=$((count + 1))
    done < <(xmllint --xpath "//property[@name='${selected_property/#*'/'}']//value" "$filename" 2>/dev/null)

    # If xmllint cannot get the current values, use xfconf-query 
    if [[ -z "${current_values[*]}" ]]; then
        for line in "$(xfconf-query -c "$selected_channel" -p "$selected_property" | tail -n +2)"; do
            current_types+="$(xmllint --xpath "string(//property[@name='$property']/@type)" "$filename")"
            current_values+="$line"
            form_fields+=("--field=Value $count:TXT")
        done
    fi

    # Create form dialog for setting array property
    result=$(yad --form "${form_fields[@]}" --separator="|" --title="Set Array Property: $selected_property" --width=300 ${current_values[@]})
    
    if [ $? -eq 0 ]; then
        # Convert |-separated string back to array
        IFS=$'|' read -r -a new_values <<< "$result"

        # Clear the property and set the new array values
        xfconf-query -c "$selected_channel" -p "$selected_property" --reset
        local type_value=""
        for ((i=0; i<${#new_values[@]}; i++)); do
            type_value="${type_value} -t \"${current_types[$i]}\" -s \"${new_values[$i]}\" --create  "
        done 
        xfconf-query -c "$selected_channel" -p "$selected_property" -a ${type_value}
        yad --info --text="Array property $selected_property set to ${new_values[*]}"
    fi
}
export -f create_set_array_dialog

# Function to create a form dialog for setting property
create_set_dialog() {
    local selected_channel="$1"
    local selected_property="$2"
    local prop_info
    prop_info=$(get_property_info "$selected_channel" "${selected_property/#*'/'}")
    
    if [ $? -ne 0 ]; then
        yad --error --text="$prop_info"
        return
    fi

    local type=$(echo "$prop_info" | cut -d' ' -f1)
    local current_value=$(echo "$prop_info" | cut -d' ' -f2-)
    if [[ -z "$current_value" ]]; then
        current_value="$(xfconf-query -c "$selected_channel" -p "$selected_property")"
    fi
    if [[ "$type" == "empty" ]]; then 
        local test_type="$(xfconf-query -c "$selected_channel" -p "$selected_property" | head -n +1)"
        if [[ "$test_type" =~ "Value is an array" ]]; then
            type="array"
        fi
    fi

    local dialog_title="Set Property: $selected_property"
    local field=""

    case "$type" in
        "bool")
            field="--field=${selected_property}:CHK"
            if [[ "$current_value" == "true" ]]; then
                current_value="TRUE"
            else
                current_value="FALSE"
            fi
            ;;
        "int" | "uint" | "int64" | "uint64")
            field="--field=${selected_property}:NUM"
            ;;
        "double")
            field="--field=${selected_property}:NUM"
            current_value="${current_value}!0..1!0.1"
            ;;
        "string")
            field="--field=${selected_property}:TXT"
            ;;
        "array")
            create_set_array_dialog "$selected_channel" "${selected_property}"
            return
            ;;
        *)
            field="--field=${selected_property}:TXT"
            ;;
    esac

    # Create form dialog with appropriate form field
    result=$(yad --form $field --title="$dialog_title" --width=300 "$current_value" --separator="")
    
    # If user clicks OK, set the property with the selected value
    if [ $? -eq 0 ]; then
        [ "$result" == "TRUE" ] && result="true"     # can't convert 'TRUE' to gboolean, so set to 'true'
        [ "$result" == "FALSE" ] && result="false"
        set_property "$selected_channel" "$selected_property" "$type" "$result"
    fi
}
export -f create_set_dialog


prop_array=($properties)

# List of XFCE channels, excluding the first line "Channels:"
channels="$(xfconf-query -l | tail -n +2)"
channel_array=($channels)
channel_options=""

# Generate ComboBox field options for channels
for ((i=0; i<${#channel_array[@]}; i++)); do
    channel_options+="${channel_array[i]}"
    if [ $i -lt $((${#channel_array[@]}-1)) ]; then
        channel_options+="!"
    fi
done

if [ -z "$channel_options" ]; then
    channel_options="@disabled@"
fi

# Get properties of the first channel to initialize the properties ComboBox
initial_channel="$(echo "$channels" | head -n 1)"
initial_properties="$(get_properties "$initial_channel")"

# Main dialog
yad --form --field="Channel:CB" "$channel_options" \
             --field="Properties:CB" "$initial_properties" \
             --field="Get Property:BTN" "get_property %1 %2" \
             --title="Select Channel and Properties" \
             --changed-action="handle_channel_change" --use-interp

Takes some time for xfconf-query to change the property as you see:
scrot


Do you want to exit the Circus?
https://www.youtube.com/watch?v=ZJwQicZHp_c

Offline

#2 2024-06-05 10:02:41

Jerry3904
Member
Registered: 2013-11-09
Posts: 863

Re: Fun with xfconf-query and yad

Hi Misko, good to see you around! Hope all is well.

Thanks for posting this clever little item. We use yad a lot, as you know, and will enjoy giving it a spin ;-)


MX-23 (based on Debian Stable) with our flagship Xfce 4.18.

Offline

#3 2024-06-05 13:28:17

Misko_2083
Member
Registered: 2015-10-13
Posts: 211
Website

Re: Fun with xfconf-query and yad

Jerry3904 wrote:

Hi Misko, good to see you around! Hope all is well.

Thanks for posting this clever little item. We use yad a lot, as you know, and will enjoy giving it a spin ;-)

Doing much better now, last year was rough.
https://i.ibb.co/Bnk7w8q/IMG-47522adac8 … e582-V.jpg
I contributed only gtkswitch to yad a while ago.
Don't know how is Victor doing, haven't heard of him for quite a while.
He hasn't posted anything on git for some time, I hope he is alive.

Last edited by Misko_2083 (2024-06-05 13:28:46)


Do you want to exit the Circus?
https://www.youtube.com/watch?v=ZJwQicZHp_c

Offline

Registered users online in this topic: 0, guests: 1
[Bot] CCBot

Board footer

Powered by FluxBB
Modified by Visman

[ Generated in 0.009 seconds, 7 queries executed - Memory usage: 576.36 KiB (Peak: 593.2 KiB) ]