From 085fd7b7925a028c989e6d18e3bc3d4cdb4c2780 Mon Sep 17 00:00:00 2001 From: Kyle K Date: Thu, 30 Jan 2020 16:07:31 -0600 Subject: begin theming, patch firefox for KDE global menu --- GentooX Breeze Dark Transparent.tar.gz | Bin 0 -> 363009 bytes ToDo.txt | 10 + arch-chroot | 347 ++++ genfstab | 494 +++++ gentoox_build.sh | 26 +- .../www-client/firefox/firefox-branded-icons.patch | 51 + patches/www-client/firefox/firefox-kde.patch | 283 +++ patches/www-client/firefox/mozilla-kde.patch | 1940 ++++++++++++++++++++ postinstall.sh | 73 +- zfs-ungpl-rcu_read_unlock-export.diff | 22 + 10 files changed, 3206 insertions(+), 40 deletions(-) create mode 100644 GentooX Breeze Dark Transparent.tar.gz create mode 100755 arch-chroot create mode 100755 genfstab create mode 100644 patches/www-client/firefox/firefox-branded-icons.patch create mode 100644 patches/www-client/firefox/firefox-kde.patch create mode 100644 patches/www-client/firefox/mozilla-kde.patch create mode 100644 zfs-ungpl-rcu_read_unlock-export.diff diff --git a/GentooX Breeze Dark Transparent.tar.gz b/GentooX Breeze Dark Transparent.tar.gz new file mode 100644 index 0000000..dac3436 Binary files /dev/null and b/GentooX Breeze Dark Transparent.tar.gz differ diff --git a/ToDo.txt b/ToDo.txt index 7bde892..6cb4203 100644 --- a/ToDo.txt +++ b/ToDo.txt @@ -21,4 +21,14 @@ for (i=0;i ERROR:" "$@"; } >&2 +warning() { out "==> WARNING:" "$@"; } >&2 +msg() { out "==>" "$@"; } +msg2() { out " ->" "$@";} +die() { error "$@"; exit 1; } + +ignore_error() { + "$@" 2>/dev/null + return 0 +} + +in_array() { + local i + for i in "${@:2}"; do + [[ $1 = "$i" ]] && return 0 + done + return 1 +} + +chroot_add_mount() { + mount "$@" && CHROOT_ACTIVE_MOUNTS=("$2" "${CHROOT_ACTIVE_MOUNTS[@]}") +} + +chroot_maybe_add_mount() { + local cond=$1; shift + if eval "$cond"; then + chroot_add_mount "$@" + fi +} + +chroot_setup() { + CHROOT_ACTIVE_MOUNTS=() + [[ $(trap -p EXIT) ]] && die '(BUG): attempting to overwrite existing EXIT trap' + trap 'chroot_teardown' EXIT + + chroot_add_mount proc "$1/proc" -t proc -o nosuid,noexec,nodev && + chroot_add_mount sys "$1/sys" -t sysfs -o nosuid,noexec,nodev,ro && + ignore_error chroot_maybe_add_mount "[[ -d '$1/sys/firmware/efi/efivars' ]]" \ + efivarfs "$1/sys/firmware/efi/efivars" -t efivarfs -o nosuid,noexec,nodev && + chroot_add_mount udev "$1/dev" -t devtmpfs -o mode=0755,nosuid && + chroot_add_mount devpts "$1/dev/pts" -t devpts -o mode=0620,gid=5,nosuid,noexec && + chroot_add_mount shm "$1/dev/shm" -t tmpfs -o mode=1777,nosuid,nodev && + chroot_add_mount /run "$1/run" --bind && + chroot_add_mount tmp "$1/tmp" -t tmpfs -o mode=1777,strictatime,nodev,nosuid +} + +chroot_teardown() { + if (( ${#CHROOT_ACTIVE_MOUNTS[@]} )); then + umount "${CHROOT_ACTIVE_MOUNTS[@]}" + fi + unset CHROOT_ACTIVE_MOUNTS +} + +try_cast() ( + _=$(( $1#$2 )) +) 2>/dev/null + +valid_number_of_base() { + local base=$1 len=${#2} i= + + for (( i = 0; i < len; i++ )); do + try_cast "$base" "${2:i:1}" || return 1 + done + + return 0 +} + +mangle() { + local i= chr= out= + local {a..f}= {A..F}= + + for (( i = 0; i < ${#1}; i++ )); do + chr=${1:i:1} + case $chr in + [[:space:]\\]) + printf -v chr '%03o' "'$chr" + out+=\\ + ;; + esac + out+=$chr + done + + printf '%s' "$out" +} + +unmangle() { + local i= chr= out= len=$(( ${#1} - 4 )) + local {a..f}= {A..F}= + + for (( i = 0; i < len; i++ )); do + chr=${1:i:1} + case $chr in + \\) + if valid_number_of_base 8 "${1:i+1:3}" || + valid_number_of_base 16 "${1:i+1:3}"; then + printf -v chr '%b' "${1:i:4}" + (( i += 3 )) + fi + ;; + esac + out+=$chr + done + + printf '%s' "$out${1:i}" +} + +optstring_match_option() { + local candidate pat patterns + + IFS=, read -ra patterns <<<"$1" + for pat in "${patterns[@]}"; do + if [[ $pat = *=* ]]; then + # "key=val" will only ever match "key=val" + candidate=$2 + else + # "key" will match "key", but also "key=anyval" + candidate=${2%%=*} + fi + + [[ $pat = "$candidate" ]] && return 0 + done + + return 1 +} + +optstring_remove_option() { + local o options_ remove=$2 IFS=, + + read -ra options_ <<<"${!1}" + + for o in "${!options_[@]}"; do + optstring_match_option "$remove" "${options_[o]}" && unset 'options_[o]' + done + + declare -g "$1=${options_[*]}" +} + +optstring_normalize() { + local o options_ norm IFS=, + + read -ra options_ <<<"${!1}" + + # remove empty fields + for o in "${options_[@]}"; do + [[ $o ]] && norm+=("$o") + done + + # avoid empty strings, reset to "defaults" + declare -g "$1=${norm[*]:-defaults}" +} + +optstring_append_option() { + if ! optstring_has_option "$1" "$2"; then + declare -g "$1=${!1},$2" + fi + + optstring_normalize "$1" +} + +optstring_prepend_option() { + local options_=$1 + + if ! optstring_has_option "$1" "$2"; then + declare -g "$1=$2,${!1}" + fi + + optstring_normalize "$1" +} + +optstring_get_option() { + local opts o + + IFS=, read -ra opts <<<"${!1}" + for o in "${opts[@]}"; do + if optstring_match_option "$2" "$o"; then + declare -g "$o" + return 0 + fi + done + + return 1 +} + +optstring_has_option() { + local "${2%%=*}" + + optstring_get_option "$1" "$2" +} + +dm_name_for_devnode() { + read dm_name <"/sys/class/block/${1#/dev/}/dm/name" + if [[ $dm_name ]]; then + printf '/dev/mapper/%s' "$dm_name" + else + # don't leave the caller hanging, just print the original name + # along with the failure. + print '%s' "$1" + error 'Failed to resolve device mapper name for: %s' "$1" + fi +} + +fstype_is_pseudofs() { + (( pseudofs_types["$1"] )) +} + +fstype_has_fsck() { + (( fsck_types["$1"] )) +} + + +usage() { + cat <[:group] Specify non-root user and optional group to use + +If 'command' is unspecified, ${0##*/} will launch /bin/bash. + +Note that when using arch-chroot, the target chroot directory *should* be a +mountpoint. This ensures that tools such as pacman(8) or findmnt(8) have an +accurate hierarchy of the mounted filesystems within the chroot. + +If your chroot target is not a mountpoint, you can bind mount the directory on +itself to make it a mountpoint, i.e. 'mount --bind /your/chroot /your/chroot'. + +EOF +} + +chroot_add_resolv_conf() { + local chrootdir=$1 resolv_conf=$1/etc/resolv.conf + + [[ -e /etc/resolv.conf ]] || return 0 + + # Handle resolv.conf as a symlink to somewhere else. + if [[ -L $chrootdir/etc/resolv.conf ]]; then + # readlink(1) should always give us *something* since we know at this point + # it's a symlink. For simplicity, ignore the case of nested symlinks. + resolv_conf=$(readlink "$chrootdir/etc/resolv.conf") + if [[ $resolv_conf = /* ]]; then + resolv_conf=$chrootdir$resolv_conf + else + resolv_conf=$chrootdir/etc/$resolv_conf + fi + + # ensure file exists to bind mount over + if [[ ! -f $resolv_conf ]]; then + install -Dm644 /dev/null "$resolv_conf" || return 1 + fi + elif [[ ! -e $chrootdir/etc/resolv.conf ]]; then + # The chroot might not have a resolv.conf. + return 0 + fi + + chroot_add_mount /etc/resolv.conf "$resolv_conf" --bind +} + +while getopts ':hu:' flag; do + case $flag in + h) + usage + exit 0 + ;; + u) + userspec=$OPTARG + ;; + :) + die '%s: option requires an argument -- '\''%s'\' "${0##*/}" "$OPTARG" + ;; + ?) + die '%s: invalid option -- '\''%s'\' "${0##*/}" "$OPTARG" + ;; + esac +done +shift $(( OPTIND - 1 )) + +(( EUID == 0 )) || die 'This script must be run with root privileges' +(( $# )) || die 'No chroot directory specified' +chrootdir=$1 +shift + +[[ -d $chrootdir ]] || die "Can't create chroot on non-directory %s" "$chrootdir" + +if ! mountpoint -q "$chrootdir"; then + warning "$chrootdir is not a mountpoint. This may have undesirable side effects." +fi + +chroot_setup "$chrootdir" || die "failed to setup chroot %s" "$chrootdir" +chroot_add_resolv_conf "$chrootdir" || die "failed to setup resolv.conf" + +chroot_args=() +[[ $userspec ]] && chroot_args+=(--userspec "$userspec") + +SHELL=/bin/bash unshare --fork --pid chroot "${chroot_args[@]}" -- "$chrootdir" "$@" diff --git a/genfstab b/genfstab new file mode 100755 index 0000000..883e56a --- /dev/null +++ b/genfstab @@ -0,0 +1,494 @@ +#!/bin/bash + +shopt -s extglob + +# generated from util-linux source: libmount/src/utils.c +declare -A pseudofs_types=([anon_inodefs]=1 + [autofs]=1 + [bdev]=1 + [bpf]=1 + [binfmt_misc]=1 + [cgroup]=1 + [cgroup2]=1 + [configfs]=1 + [cpuset]=1 + [debugfs]=1 + [devfs]=1 + [devpts]=1 + [devtmpfs]=1 + [dlmfs]=1 + [efivarfs]=1 + [fuse.gvfs-fuse-daemon]=1 + [fusectl]=1 + [hugetlbfs]=1 + [mqueue]=1 + [nfsd]=1 + [none]=1 + [pipefs]=1 + [proc]=1 + [pstore]=1 + [ramfs]=1 + [rootfs]=1 + [rpc_pipefs]=1 + [securityfs]=1 + [sockfs]=1 + [spufs]=1 + [sysfs]=1 + [tmpfs]=1) + +# generated from: pkgfile -vbr '/fsck\..+' | awk -F. '{ print $NF }' | sort +declare -A fsck_types=([cramfs]=1 + [exfat]=1 + [ext2]=1 + [ext3]=1 + [ext4]=1 + [ext4dev]=1 + [jfs]=1 + [minix]=1 + [msdos]=1 + [reiserfs]=1 + [vfat]=1 + [xfs]=1) + +out() { printf "$1 $2\n" "${@:3}"; } +error() { out "==> ERROR:" "$@"; } >&2 +warning() { out "==> WARNING:" "$@"; } >&2 +msg() { out "==>" "$@"; } +msg2() { out " ->" "$@";} +die() { error "$@"; exit 1; } + +ignore_error() { + "$@" 2>/dev/null + return 0 +} + +in_array() { + local i + for i in "${@:2}"; do + [[ $1 = "$i" ]] && return 0 + done + return 1 +} + +chroot_add_mount() { + mount "$@" && CHROOT_ACTIVE_MOUNTS=("$2" "${CHROOT_ACTIVE_MOUNTS[@]}") +} + +chroot_maybe_add_mount() { + local cond=$1; shift + if eval "$cond"; then + chroot_add_mount "$@" + fi +} + +chroot_setup() { + CHROOT_ACTIVE_MOUNTS=() + [[ $(trap -p EXIT) ]] && die '(BUG): attempting to overwrite existing EXIT trap' + trap 'chroot_teardown' EXIT + + chroot_add_mount proc "$1/proc" -t proc -o nosuid,noexec,nodev && + chroot_add_mount sys "$1/sys" -t sysfs -o nosuid,noexec,nodev,ro && + ignore_error chroot_maybe_add_mount "[[ -d '$1/sys/firmware/efi/efivars' ]]" \ + efivarfs "$1/sys/firmware/efi/efivars" -t efivarfs -o nosuid,noexec,nodev && + chroot_add_mount udev "$1/dev" -t devtmpfs -o mode=0755,nosuid && + chroot_add_mount devpts "$1/dev/pts" -t devpts -o mode=0620,gid=5,nosuid,noexec && + chroot_add_mount shm "$1/dev/shm" -t tmpfs -o mode=1777,nosuid,nodev && + chroot_add_mount /run "$1/run" --bind && + chroot_add_mount tmp "$1/tmp" -t tmpfs -o mode=1777,strictatime,nodev,nosuid +} + +chroot_teardown() { + if (( ${#CHROOT_ACTIVE_MOUNTS[@]} )); then + umount "${CHROOT_ACTIVE_MOUNTS[@]}" + fi + unset CHROOT_ACTIVE_MOUNTS +} + +try_cast() ( + _=$(( $1#$2 )) +) 2>/dev/null + +valid_number_of_base() { + local base=$1 len=${#2} i= + + for (( i = 0; i < len; i++ )); do + try_cast "$base" "${2:i:1}" || return 1 + done + + return 0 +} + +mangle() { + local i= chr= out= + local {a..f}= {A..F}= + + for (( i = 0; i < ${#1}; i++ )); do + chr=${1:i:1} + case $chr in + [[:space:]\\]) + printf -v chr '%03o' "'$chr" + out+=\\ + ;; + esac + out+=$chr + done + + printf '%s' "$out" +} + +unmangle() { + local i= chr= out= len=$(( ${#1} - 4 )) + local {a..f}= {A..F}= + + for (( i = 0; i < len; i++ )); do + chr=${1:i:1} + case $chr in + \\) + if valid_number_of_base 8 "${1:i+1:3}" || + valid_number_of_base 16 "${1:i+1:3}"; then + printf -v chr '%b' "${1:i:4}" + (( i += 3 )) + fi + ;; + esac + out+=$chr + done + + printf '%s' "$out${1:i}" +} + +optstring_match_option() { + local candidate pat patterns + + IFS=, read -ra patterns <<<"$1" + for pat in "${patterns[@]}"; do + if [[ $pat = *=* ]]; then + # "key=val" will only ever match "key=val" + candidate=$2 + else + # "key" will match "key", but also "key=anyval" + candidate=${2%%=*} + fi + + [[ $pat = "$candidate" ]] && return 0 + done + + return 1 +} + +optstring_remove_option() { + local o options_ remove=$2 IFS=, + + read -ra options_ <<<"${!1}" + + for o in "${!options_[@]}"; do + optstring_match_option "$remove" "${options_[o]}" && unset 'options_[o]' + done + + declare -g "$1=${options_[*]}" +} + +optstring_normalize() { + local o options_ norm IFS=, + + read -ra options_ <<<"${!1}" + + # remove empty fields + for o in "${options_[@]}"; do + [[ $o ]] && norm+=("$o") + done + + # avoid empty strings, reset to "defaults" + declare -g "$1=${norm[*]:-defaults}" +} + +optstring_append_option() { + if ! optstring_has_option "$1" "$2"; then + declare -g "$1=${!1},$2" + fi + + optstring_normalize "$1" +} + +optstring_prepend_option() { + local options_=$1 + + if ! optstring_has_option "$1" "$2"; then + declare -g "$1=$2,${!1}" + fi + + optstring_normalize "$1" +} + +optstring_get_option() { + local opts o + + IFS=, read -ra opts <<<"${!1}" + for o in "${opts[@]}"; do + if optstring_match_option "$2" "$o"; then + declare -g "$o" + return 0 + fi + done + + return 1 +} + +optstring_has_option() { + local "${2%%=*}" + + optstring_get_option "$1" "$2" +} + +dm_name_for_devnode() { + read dm_name <"/sys/class/block/${1#/dev/}/dm/name" + if [[ $dm_name ]]; then + printf '/dev/mapper/%s' "$dm_name" + else + # don't leave the caller hanging, just print the original name + # along with the failure. + print '%s' "$1" + error 'Failed to resolve device mapper name for: %s' "$1" + fi +} + +fstype_is_pseudofs() { + (( pseudofs_types["$1"] )) +} + +fstype_has_fsck() { + (( fsck_types["$1"] )) +} + + +write_source() { + local src=$1 spec= label= uuid= comment=() + + label=$(lsblk -rno LABEL "$1" 2>/dev/null) + uuid=$(lsblk -rno UUID "$1" 2>/dev/null) + + # bind mounts do not have a UUID! + + case $bytag in + '') + [[ $uuid ]] && comment=("UUID=$uuid") + [[ $label ]] && comment+=("LABEL=$(mangle "$label")") + ;; + LABEL) + spec=$label + [[ $uuid ]] && comment=("$src" "UUID=$uuid") + ;; + UUID) + spec=$uuid + comment=("$src") + [[ $label ]] && comment+=("LABEL=$(mangle "$label")") + ;; + *) + [[ $uuid ]] && comment=("$1" "UUID=$uuid") + [[ $label ]] && comment+=("LABEL=$(mangle "$label")") + [[ $bytag ]] && spec=$(lsblk -rno "$bytag" "$1" 2>/dev/null) + ;; + esac + + [[ $comment ]] && printf '# %s\n' "${comment[*]}" + + if [[ $spec ]]; then + printf '%-20s' "$bytag=$(mangle "$spec")" + else + printf '%-20s' "$(mangle "$src")" + fi +} + +optstring_apply_quirks() { + local varname=$1 fstype=$2 + + # SELinux displays a 'seclabel' option in /proc/self/mountinfo. We can't know + # if the system we're generating the fstab for has any support for SELinux (as + # one might install Arch from a Fedora environment), so let's remove it. + optstring_remove_option "$varname" seclabel + + # Prune 'relatime' option for any pseudofs. This seems to be a rampant + # default which the kernel often exports even if the underlying filesystem + # doesn't support it. Example: https://bugs.archlinux.org/task/54554. + if awk -v fstype="$fstype" '$1 == fstype { exit 1 }' /proc/filesystems; then + optstring_remove_option "$varname" relatime + fi + + case $fstype in + f2fs) + # These are Kconfig options for f2fs. Kernels supporting the options will + # only provide the negative versions of these (e.g. noacl), and vice versa + # for kernels without support. + optstring_remove_option "$varname" noacl,acl,nouser_xattr,user_xattr + ;; + vfat) + # Before Linux v3.8, "cp" is prepended to the value of the codepage. + if optstring_get_option "$varname" codepage && [[ $codepage = cp* ]]; then + optstring_remove_option "$varname" codepage + optstring_append_option "$varname" "codepage=${codepage#cp}" + fi + ;; + esac +} + +usage() { + cat < Restrict output to mountpoints matching the prefix FILTER + -L Use labels for source identifiers (shortcut for -t LABEL) + -p Exclude pseudofs mounts (default behavior) + -P Include pseudofs mounts + -t Use TAG for source identifiers (TAG should be one of: LABEL, + UUID, PARTLABEL, PARTUUID) + -U Use UUIDs for source identifiers (shortcut for -t UUID) + + -h Print this help message + +genfstab generates output suitable for addition to an fstab file based on the +devices mounted under the mountpoint specified by the given root. + +EOF +} + +if [[ -z $1 || $1 = @(-h|--help) ]]; then + usage + exit $(( $# ? 0 : 1 )) +fi + +while getopts ':f:LPpt:U' flag; do + case $flag in + L) + bytag=LABEL + ;; + U) + bytag=UUID + ;; + f) + prefixfilter=$OPTARG + ;; + P) + pseudofs=1 + ;; + p) + pseudofs=0 + ;; + t) + bytag=${OPTARG^^} + ;; + :) + die '%s: option requires an argument -- '\''%s'\' "${0##*/}" "$OPTARG" + ;; + ?) + die '%s: invalid option -- '\''%s'\' "${0##*/}" "$OPTARG" + ;; + esac +done +shift $(( OPTIND - 1 )) + +(( $# )) || die "No root directory specified" +root=$(realpath -mL "$1"); shift + +if ! mountpoint -q "$root"; then + die "$root is not a mountpoint" +fi + +# handle block devices +findmnt -Recvruno SOURCE,TARGET,FSTYPE,OPTIONS,FSROOT "$root" | + while read -r src target fstype opts fsroot; do + if (( !pseudofs )) && fstype_is_pseudofs "$fstype"; then + continue + fi + + [[ $target = "$prefixfilter"* ]] || continue + + # default 5th and 6th columns + dump=0 pass=2 + + src=$(unmangle "$src") + target=$(unmangle "$target") + target=${target#$root} + + if (( !foundroot )) && findmnt "$src" "$root" >/dev/null; then + # this is root. we can't possibly have more than one... + pass=1 foundroot=1 + fi + + # if there's no fsck tool available, then only pass=0 makes sense. + if ! fstype_has_fsck "$fstype"; then + pass=0 + fi + + if [[ $fsroot != / ]]; then + if [[ $fstype = btrfs ]]; then + opts+=,subvol=${fsroot#/} + else + # it's a bind mount + src=$(findmnt -funcevo TARGET "$src")$fsroot + if [[ $src -ef $target ]]; then + # hrmm, this is weird. we're probably looking at a file or directory + # that was bound into a chroot from the host machine. Ignore it, + # because this won't actually be a valid mount. Worst case, the user + # just re-adds it. + continue + fi + fstype=none + opts+=,bind + pass=0 + fi + fi + + # filesystem quirks + case $fstype in + fuseblk) + # well-behaved FUSE filesystems will report themselves as fuse.$fstype. + # this is probably NTFS-3g, but let's just make sure. + if ! newtype=$(lsblk -no FSTYPE "$src") || [[ -z $newtype ]]; then + # avoid blanking out fstype, leading to an invalid fstab + error 'Failed to derive real filesystem type for FUSE device on %s' "$target" + else + fstype=$newtype + fi + ;; + esac + + optstring_apply_quirks "opts" "$fstype" + + # write one line + write_source "$src" + printf '\t%-10s' "/$(mangle "${target#/}")" "$fstype" "$opts" + printf '\t%s %s' "$dump" "$pass" + printf '\n\n' +done + +# handle swaps devices +{ + # ignore header + read + + while read -r device type _ _ prio; do + options=defaults + if (( prio >= 0 )); then + options+=,pri=$prio + fi + + # skip files marked deleted by the kernel + [[ $device = *'\040(deleted)' ]] && continue + + if [[ $type = file ]]; then + printf '%-20s' "${device#${root%/}}" + elif [[ $device = /dev/dm-+([0-9]) ]]; then + # device mapper doesn't allow characters we need to worry + # about being mangled, and it does the escaping of dashes + # for us in sysfs. + write_source "$(dm_name_for_devnode "$device")" + else + write_source "$(unmangle "$device")" + fi + + printf '\t%-10s\t%-10s\t%-10s\t0 0\n\n' 'none' 'swap' "$options" + done +} > /etc/portage/package.use/gentoox emerge -v --autounmask=y --autounmask-write=y --keep-going=y --deep --newuse xorg-server elogind sudo vim weston wpa_supplicant snapper \ -nfs-utils cifs-utils samba dhcpcd nss-mdns zsh zsh-completions powertop lm-sensors #plymouth-openrc-plugin +nfs-utils cifs-utils samba dhcpcd nss-mdns zsh zsh-completions powertop lm-sensors screenfetch #plymouth-openrc-plugin #emerge -v --depclean touch /tmp/gentoox-weston-done HEREDOC @@ -280,7 +284,7 @@ sed -i '1s/^/NTHREADS="12"\n/' /etc/portage/make.conf echo -e '\nkde-plasma/plasma-meta discover networkmanager thunderbolt kde-apps/kio-extras samba' >> /etc/portage/package.use/gentoox -emerge -v --jobs=4 --keep-going=y --autounmask=y --autounmask-write=y --deep --newuse kde-plasma/plasma-meta kde-apps/kde-apps-meta kde-apps/kmail latte-dock calamares firefox mpv +emerge -v --jobs=4 --keep-going=y --autounmask=y --autounmask-write=y --deep --newuse kde-plasma/plasma-meta kde-apps/kde-apps-meta kde-apps/kmail latte-dock calamares gparted plasma-sdk gdb dos2unix qt-creator firefox mpv app-misc/screen yes | layman -o https://raw.githubusercontent.com/fosero/flatpak-overlay/master/repositories.xml -f -a flatpak-overlay -q emerge -v sys-apps/flatpak @@ -347,10 +351,11 @@ fi if [[ ! -z $configure_user ]] && [[ ! -f 'tmp/gentoox-user-configured' ]]; then +cp ../../postinstall.sh . cp ../../1518039301698.png . +cp '../../GentooX Breeze Dark Transparent.tar.gz' . cat < /etc/conf.d/net echo 'nameserver 1.1.1.1 nameserver 2606:4700:4700::1111' > /etc/resolv.conf +# theme related +(cd /usr/share/icons; git clone https://github.com/keeferrourke/la-capitaine-icon-theme.git) +cd /usr/src/ +git clone https://github.com/ishovkun/SierraBreeze.git +cd SierraBreeze/ +mkdir build && cd build +cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DKDE_INSTALL_LIBDIR=lib -DBUILD_TESTING=OFF -DKDE_INSTALL_USE_QT_SYS_PATHS=ON +make install +cd / + #echo "root:$rootpassword" | chpasswd yes "$rootpassword" | passwd root useradd $username @@ -389,12 +404,15 @@ rc-update add avahi-daemon default rc-update add samba default +mv /postinstall.sh /home/$username/ mv /1518039301698.png /home/$username/ +mv '/GentooX Breeze Dark Transparent.tar.gz' /home/$username/ cd /home/$username/ echo 'exec dbus-launch --exit-with-session startplasma-x11' > .xinitrc chown -R $username /home/$username/ su - gentoox flatpak --user remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo +kpackagetool5 -i "GentooX Breeze Dark Transparent.tar.gz" touch /tmp/gentoox-user-configured HEREDOC @@ -465,7 +483,7 @@ xorriso -as mkisofs -r -J \ -b isolinux/isolinux.bin -c isolinux/boot.cat \ -no-emul-boot -boot-load-size 4 -boot-info-table \ -eltorito-alt-boot -e gentoo.efimg -no-emul-boot -isohybrid-gpt-basdat \ - -V "GentooX Live" -o Gentoox-x86_64-$builddate.iso iso/ + -V "GentooX Live" -o GentooX-x86_64-$builddate.iso iso/ #rm -Rf image/ iso/ kernel-gentoox.tar.lzma fi diff --git a/patches/www-client/firefox/firefox-branded-icons.patch b/patches/www-client/firefox/firefox-branded-icons.patch new file mode 100644 index 0000000..d7d2552 --- /dev/null +++ b/patches/www-client/firefox/firefox-branded-icons.patch @@ -0,0 +1,51 @@ +# HG changeset patch +# Parent e0751ad74e835e80041a61ea00c2a63bf6fbe2de +# Parent 127964dc93cc35715852bc811dcc67016d918628 + +diff --git a/browser/branding/branding-common.mozbuild b/browser/branding/branding-common.mozbuild +--- a/browser/branding/branding-common.mozbuild ++++ b/browser/branding/branding-common.mozbuild +@@ -22,12 +22,15 @@ def FirefoxBranding(): + FINAL_TARGET_FILES.VisualElements += [ + 'VisualElements_150.png', + 'VisualElements_70.png', + ] + elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk': + FINAL_TARGET_FILES.chrome.icons.default += [ + 'default128.png', + 'default16.png', ++ 'default22.png', ++ 'default24.png', ++ 'default256.png', + 'default32.png', + 'default48.png', + 'default64.png', + ] +diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in +--- a/browser/installer/package-manifest.in ++++ b/browser/installer/package-manifest.in +@@ -246,20 +246,23 @@ + @RESPATH@/browser/chrome/pdfjs.manifest + @RESPATH@/browser/chrome/pdfjs/* + @RESPATH@/chrome/toolkit@JAREXT@ + @RESPATH@/chrome/toolkit.manifest + @RESPATH@/chrome/recording.manifest + @RESPATH@/chrome/recording/* + #ifdef MOZ_GTK + @RESPATH@/browser/chrome/icons/default/default16.png ++@RESPATH@/browser/chrome/icons/default/default22.png ++@RESPATH@/browser/chrome/icons/default/default24.png + @RESPATH@/browser/chrome/icons/default/default32.png + @RESPATH@/browser/chrome/icons/default/default48.png + @RESPATH@/browser/chrome/icons/default/default64.png + @RESPATH@/browser/chrome/icons/default/default128.png ++@RESPATH@/browser/chrome/icons/default/default256.png + #endif + @RESPATH@/browser/features/* + + ; [DevTools Startup Files] + @RESPATH@/browser/chrome/devtools-startup@JAREXT@ + @RESPATH@/browser/chrome/devtools-startup.manifest + + ; DevTools + diff --git a/patches/www-client/firefox/firefox-kde.patch b/patches/www-client/firefox/firefox-kde.patch new file mode 100644 index 0000000..cb5578b --- /dev/null +++ b/patches/www-client/firefox/firefox-kde.patch @@ -0,0 +1,283 @@ +# HG changeset patch +# User msirringhaus@suse.de +# Date 1559300151 -7200 +# Fri May 31 12:55:51 2019 +0200 +# Node ID 54d41b0033b8d649d842a1f862c6fed8b9874dec +# Parent 4faaad3619f286bd6077754d8e59d339a5142b80 +How to apply this patch: +1. Import and apply it +2. cp browser/base/content/browser.xul browser/base/content/browser-kde.xul +3. Find editBookmarkPanelDoneButton +4. Replace #ifndef with #ifdef in the line above (this hanges the button order from Gnome-style to KDE-style) +5. hg qrefresh + +diff --git a/browser/components/preferences/in-content/main.js b/browser/components/preferences/in-content/main.js +--- a/browser/components/preferences/in-content/main.js ++++ b/browser/components/preferences/in-content/main.js +@@ -341,16 +341,23 @@ var gMainPane = { + }, backoffTimes[this._backoffIndex + 1 < backoffTimes.length ? this._backoffIndex++ : backoffTimes.length - 1]); + }; + + window.setTimeout(() => { + window.requestIdleCallback(pollForDefaultBrowser); + }, backoffTimes[this._backoffIndex]); + } + ++ var env = Components.classes["@mozilla.org/process/environment;1"] ++ .getService(Components.interfaces.nsIEnvironment); ++ var kde_session = 0; ++ if (env.get('KDE_FULL_SESSION') == "true") { ++ kde_session = 1; ++ } ++ + this.initBrowserContainers(); + this.buildContentProcessCountMenuList(); + + let performanceSettingsLink = document.getElementById( + "performanceSettingsLearnMore" + ); + let performanceSettingsUrl = + Services.urlFormatter.formatURLPref("app.support.baseURL") + +@@ -1199,16 +1206,27 @@ var gMainPane = { + this._backoffIndex = 0; + + let shellSvc = getShellService(); + if (!shellSvc) { + return; + } + try { + shellSvc.setDefaultBrowser(true, false); ++ if (kde_session == 1) { ++ var shellObj = Components.classes["@mozilla.org/file/local;1"] ++ .createInstance(Components.interfaces.nsILocalFile); ++ shellObj.initWithPath("/usr/bin/kwriteconfig"); ++ var process = Components.classes["@mozilla.org/process/util;1"] ++ .createInstance(Components.interfaces.nsIProcess); ++ process.init(shellObj); ++ var args = ["--file", "kdeglobals", "--group", "General", "--key", ++ "BrowserApplication", "firefox"]; ++ process.run(false, args, args.length); ++ } + } catch (ex) { + Cu.reportError(ex); + return; + } + + let selectedIndex = shellSvc.isDefaultBrowser(false, true) ? 1 : 0; + document.getElementById("setDefaultPane").selectedIndex = selectedIndex; + } +diff --git a/browser/components/shell/moz.build b/browser/components/shell/moz.build +--- a/browser/components/shell/moz.build ++++ b/browser/components/shell/moz.build +@@ -28,16 +28,18 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'coco + ] + elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk': + XPIDL_SOURCES += [ + 'nsIGNOMEShellService.idl', + ] + + SOURCES += [ + 'nsGNOMEShellService.cpp', ++ 'nsKDEShellService.cpp', ++ 'nsUnixShellService.cpp', + ] + elif CONFIG['OS_ARCH'] == 'WINNT': + SOURCES += [ + 'nsWindowsShellService.cpp', + ] + LOCAL_INCLUDES += [ + '../../../other-licenses/nsis/Contrib/CityHash/cityhash', + ] +diff --git a/browser/components/shell/nsKDEShellService.cpp b/browser/components/shell/nsKDEShellService.cpp +new file mode 100644 +--- /dev/null ++++ b/browser/components/shell/nsKDEShellService.cpp +@@ -0,0 +1,103 @@ ++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#include "mozilla/ArrayUtils.h" ++ ++#include "nsCOMPtr.h" ++#include "nsKDEShellService.h" ++#include "nsShellService.h" ++#include "nsKDEUtils.h" ++#include "nsIPrefService.h" ++#include "nsIProcess.h" ++#include "nsIFile.h" ++#include "nsServiceManagerUtils.h" ++#include "nsComponentManagerUtils.h" ++#include "nsIMutableArray.h" ++#include "nsISupportsPrimitives.h" ++#include "nsArrayUtils.h" ++ ++using namespace mozilla; ++ ++nsresult ++nsKDEShellService::Init() ++{ ++ if( !nsKDEUtils::kdeSupport()) ++ return NS_ERROR_NOT_AVAILABLE; ++ return NS_OK; ++} ++ ++NS_IMPL_ISUPPORTS(nsKDEShellService, nsIGNOMEShellService, nsIShellService) ++ ++NS_IMETHODIMP ++nsKDEShellService::IsDefaultBrowser(bool aForAllTypes, ++ bool* aIsDefaultBrowser) ++{ ++ *aIsDefaultBrowser = false; ++ ++ nsCOMPtr command = do_CreateInstance( NS_ARRAY_CONTRACTID ); ++ if (!command) ++ return NS_ERROR_FAILURE; ++ ++ nsCOMPtr str = do_CreateInstance( NS_SUPPORTS_CSTRING_CONTRACTID ); ++ if (!str) ++ return NS_ERROR_FAILURE; ++ ++ str->SetData( NS_LITERAL_CSTRING( "ISDEFAULTBROWSER" )); ++ command->AppendElement( str ); ++ ++ if( nsKDEUtils::command( command )) ++ *aIsDefaultBrowser = true; ++ return NS_OK; ++} ++ ++NS_IMETHODIMP ++nsKDEShellService::SetDefaultBrowser(bool aClaimAllTypes, ++ bool aForAllUsers) ++{ ++ nsCOMPtr command = do_CreateInstance( NS_ARRAY_CONTRACTID ); ++ if (!command) ++ return NS_ERROR_FAILURE; ++ ++ nsCOMPtr cmdstr = do_CreateInstance( NS_SUPPORTS_CSTRING_CONTRACTID ); ++ nsCOMPtr paramstr = do_CreateInstance( NS_SUPPORTS_CSTRING_CONTRACTID ); ++ if (!cmdstr || !paramstr) ++ return NS_ERROR_FAILURE; ++ ++ cmdstr->SetData( NS_LITERAL_CSTRING( "SETDEFAULTBROWSER" )); ++ command->AppendElement( cmdstr ); ++ ++ paramstr->SetData( aClaimAllTypes ? NS_LITERAL_CSTRING( "ALLTYPES" ) : NS_LITERAL_CSTRING( "NORMAL" )); ++ command->AppendElement( paramstr ); ++ ++ return nsKDEUtils::command( command ) ? NS_OK : NS_ERROR_FAILURE; ++} ++ ++NS_IMETHODIMP ++nsKDEShellService::GetCanSetDesktopBackground(bool* aResult) ++{ ++ *aResult = true; ++ return NS_OK; ++} ++ ++NS_IMETHODIMP ++nsKDEShellService::SetDesktopBackground(dom::Element* aElement, ++ int32_t aPosition, ++ const nsACString& aImageName) ++{ ++ return NS_ERROR_NOT_IMPLEMENTED; ++} ++ ++NS_IMETHODIMP ++nsKDEShellService::GetDesktopBackgroundColor(PRUint32 *aColor) ++{ ++ return NS_ERROR_NOT_IMPLEMENTED; ++} ++ ++NS_IMETHODIMP ++nsKDEShellService::SetDesktopBackgroundColor(PRUint32 aColor) ++{ ++ return NS_ERROR_NOT_IMPLEMENTED; ++} ++ +diff --git a/browser/components/shell/nsKDEShellService.h b/browser/components/shell/nsKDEShellService.h +new file mode 100644 +--- /dev/null ++++ b/browser/components/shell/nsKDEShellService.h +@@ -0,0 +1,32 @@ ++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#ifndef nskdeshellservice_h____ ++#define nskdeshellservice_h____ ++ ++#include "nsIGNOMEShellService.h" ++#include "nsToolkitShellService.h" ++#include "nsString.h" ++#include "mozilla/Attributes.h" ++ ++class nsKDEShellService final : public nsIGNOMEShellService, ++ public nsToolkitShellService ++{ ++public: ++ nsKDEShellService() : mCheckedThisSession(false) { } ++ ++ NS_DECL_ISUPPORTS ++ NS_DECL_NSISHELLSERVICE ++ NS_DECL_NSIGNOMESHELLSERVICE ++ ++ nsresult Init(); ++ ++private: ++ ~nsKDEShellService() {} ++ ++ bool mCheckedThisSession; ++}; ++ ++#endif // nskdeshellservice_h____ +diff --git a/browser/components/shell/nsUnixShellService.cpp b/browser/components/shell/nsUnixShellService.cpp +new file mode 100644 +--- /dev/null ++++ b/browser/components/shell/nsUnixShellService.cpp +@@ -0,0 +1,22 @@ ++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++ ++#include "nsUnixShellService.h" ++#include "nsGNOMEShellService.h" ++#include "nsKDEShellService.h" ++#include "nsKDEUtils.h" ++#include "mozilla/ModuleUtils.h" ++ ++NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGNOMEShellService, Init) ++NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsKDEShellService, Init) ++ ++NS_IMETHODIMP ++nsUnixShellServiceConstructor(nsISupports *aOuter, REFNSIID aIID, void **aResult) ++{ ++ if( nsKDEUtils::kdeSupport()) ++ return nsKDEShellServiceConstructor( aOuter, aIID, aResult ); ++ return nsGNOMEShellServiceConstructor( aOuter, aIID, aResult ); ++} +diff --git a/browser/components/shell/nsUnixShellService.h b/browser/components/shell/nsUnixShellService.h +new file mode 100644 +--- /dev/null ++++ b/browser/components/shell/nsUnixShellService.h +@@ -0,0 +1,15 @@ ++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++ ++#ifndef nsunixshellservice_h____ ++#define nsunixshellservice_h____ ++ ++#include "nsIGNOMEShellService.h" ++ ++NS_IMETHODIMP ++nsUnixShellServiceConstructor(nsISupports *aOuter, REFNSIID aIID, void **aResult); ++ ++#endif // nsunixshellservice_h____ + diff --git a/patches/www-client/firefox/mozilla-kde.patch b/patches/www-client/firefox/mozilla-kde.patch new file mode 100644 index 0000000..281f29b --- /dev/null +++ b/patches/www-client/firefox/mozilla-kde.patch @@ -0,0 +1,1940 @@ +# HG changeset patch +# User msirringhaus@suse.de +# Date 1559294891 -7200 +# Fri May 31 11:28:11 2019 +0200 +# Node ID c2aa7198fb925e7fde96abf65b6f68b9b755f112 +# Parent 52a515e07938d75f7c33e7b724845ce6dc315c0c +Description: Add KDE integration to Firefox (toolkit parts) +Author: Wolfgang Rosenauer +Author: Lubos Lunak +Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=140751 + https://bugzilla.novell.com/show_bug.cgi?id=170055 + +diff --git a/modules/libpref/Preferences.cpp b/modules/libpref/Preferences.cpp +--- a/modules/libpref/Preferences.cpp ++++ b/modules/libpref/Preferences.cpp +@@ -88,16 +88,17 @@ + #include "nsXPCOM.h" + #include "nsXULAppAPI.h" + #include "nsZipArchive.h" + #include "plbase64.h" + #include "PLDHashTable.h" + #include "plstr.h" + #include "prlink.h" + #include "xpcpublic.h" ++#include "nsKDEUtils.h" + + #ifdef DEBUG + # include + #endif + + #ifdef MOZ_MEMORY + # include "mozmemory.h" + #endif +@@ -4543,25 +4544,37 @@ nsresult Preferences::InitInitialObjects + // application pref files for backwards compatibility. + static const char* specialFiles[] = { + #if defined(XP_MACOSX) + "macprefs.js" + #elif defined(XP_WIN) + "winpref.js" + #elif defined(XP_UNIX) + "unix.js" ++ , "" // placeholder for KDE (empty is otherwise harmless) + # if defined(_AIX) + , + "aix.js" + # endif + #elif defined(XP_BEOS) + "beos.js" + #endif + }; + ++ if(nsKDEUtils::kdeSession()) { // TODO what if some setup actually requires the helper? ++ for(int i = 0; ++ i < MOZ_ARRAY_LENGTH(specialFiles); ++ ++i ) { ++ if( *specialFiles[ i ] == '\0' ) { ++ specialFiles[ i ] = "kde.js"; ++ break; ++ } ++ } ++ } ++ + rv = pref_LoadPrefsInDir(defaultPrefDir, specialFiles, + ArrayLength(specialFiles)); + if (NS_FAILED(rv)) { + NS_WARNING("Error parsing application default preferences."); + } + + // Load jar:$app/omni.jar!/defaults/preferences/*.js + // or jar:$gre/omni.jar!/defaults/preferences/*.js. +@@ -4607,17 +4620,17 @@ nsresult Preferences::InitInitialObjects + } + + nsCOMPtr path = do_QueryInterface(elem); + if (!path) { + continue; + } + + // Do we care if a file provided by this process fails to load? +- pref_LoadPrefsInDir(path, nullptr, 0); ++ pref_LoadPrefsInDir(path, specialFiles, ArrayLength(specialFiles)); + } + } + + if (XRE_IsParentProcess()) { + SetupTelemetryPref(); + } + + NS_CreateServicesFromCategory(NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID, nullptr, +diff --git a/modules/libpref/moz.build b/modules/libpref/moz.build +--- a/modules/libpref/moz.build ++++ b/modules/libpref/moz.build +@@ -113,16 +113,20 @@ EXPORTS.mozilla += [ + ] + EXPORTS.mozilla += sorted(['!' + g for g in gen_h]) + + UNIFIED_SOURCES += [ + 'Preferences.cpp', + 'SharedPrefMap.cpp', + ] + ++LOCAL_INCLUDES += [ ++ '/toolkit/xre' ++] ++ + gen_all_tuple = tuple(gen_h + gen_cpp + gen_rs) + + GENERATED_FILES += [gen_all_tuple] + + static_pref_list = GENERATED_FILES[gen_all_tuple] + static_pref_list.script = 'init/generate_static_pref_list.py:emit_code' + static_pref_list.inputs = ['init/StaticPrefList.yaml'] + +diff --git a/python/mozbuild/mozpack/chrome/flags.py b/python/mozbuild/mozpack/chrome/flags.py +--- a/python/mozbuild/mozpack/chrome/flags.py ++++ b/python/mozbuild/mozpack/chrome/flags.py +@@ -227,16 +227,17 @@ class Flags(OrderedDict): + 'contentaccessible': Flag, + 'os': StringFlag, + 'osversion': VersionFlag, + 'abi': StringFlag, + 'platform': Flag, + 'xpcnativewrappers': Flag, + 'tablet': Flag, + 'process': StringFlag, ++ 'desktop': StringFlag, + } + RE = re.compile(r'([!<>=]+)') + + def __init__(self, *flags): + ''' + Initialize a set of flags given in string form. + flags = Flags('contentaccessible=yes', 'appversion>=3.5') + ''' +diff --git a/python/mozbuild/mozpack/chrome/manifest.py b/python/mozbuild/mozpack/chrome/manifest.py +--- a/python/mozbuild/mozpack/chrome/manifest.py ++++ b/python/mozbuild/mozpack/chrome/manifest.py +@@ -36,16 +36,17 @@ class ManifestEntry(object): + 'platformversion', + 'os', + 'osversion', + 'abi', + 'xpcnativewrappers', + 'tablet', + 'process', + 'contentaccessible', ++ 'desktop', + ] + + def __init__(self, base, *flags): + ''' + Initialize a manifest entry with the given base path and flags. + ''' + self.base = base + self.flags = Flags(*flags) +diff --git a/toolkit/components/downloads/moz.build b/toolkit/components/downloads/moz.build +--- a/toolkit/components/downloads/moz.build ++++ b/toolkit/components/downloads/moz.build +@@ -41,10 +41,14 @@ XPCOM_MANIFESTS += [ + + if CONFIG['MOZ_PLACES']: + EXTRA_JS_MODULES += [ + 'DownloadHistory.jsm', + ] + + FINAL_LIBRARY = 'xul' + ++LOCAL_INCLUDES += [ ++ '/toolkit/xre' ++] ++ + with Files('**'): + BUG_COMPONENT = ('Toolkit', 'Downloads API') +diff --git a/toolkit/mozapps/downloads/HelperAppDlg.jsm b/toolkit/mozapps/downloads/HelperAppDlg.jsm +--- a/toolkit/mozapps/downloads/HelperAppDlg.jsm ++++ b/toolkit/mozapps/downloads/HelperAppDlg.jsm +@@ -1199,36 +1199,66 @@ nsUnknownContentTypeDialog.prototype = { + params.handlerApp && + params.handlerApp.executable && + params.handlerApp.executable.isFile() + ) { + // Remember the file they chose to run. + this.chosenApp = params.handlerApp; + } + } else if ("@mozilla.org/applicationchooser;1" in Cc) { +- var nsIApplicationChooser = Ci.nsIApplicationChooser; +- var appChooser = Cc["@mozilla.org/applicationchooser;1"].createInstance( +- nsIApplicationChooser +- ); +- appChooser.init( +- this.mDialog, +- this.dialogElement("strings").getString("chooseAppFilePickerTitle") +- ); +- var contentTypeDialogObj = this; +- let appChooserCallback = function appChooserCallback_done(aResult) { +- if (aResult) { +- contentTypeDialogObj.chosenApp = aResult.QueryInterface( +- Ci.nsILocalHandlerApp +- ); +- } +- contentTypeDialogObj.finishChooseApp(); +- }; +- appChooser.open(this.mLauncher.MIMEInfo.MIMEType, appChooserCallback); +- // The finishChooseApp is called from appChooserCallback +- return; ++ // handle the KDE case which is implemented in the filepicker ++ // therefore falling back to Gtk2 like behaviour if KDE is running ++ // FIXME this should be better handled in the nsIApplicationChooser ++ // interface ++ var env = Components.classes["@mozilla.org/process/environment;1"] ++ .getService(Components.interfaces.nsIEnvironment); ++ if (env.get('KDE_FULL_SESSION') == "true") ++ { ++ var nsIFilePicker = Ci.nsIFilePicker; ++ var fp = Cc["@mozilla.org/filepicker;1"] ++ .createInstance(nsIFilePicker); ++ fp.init(this.mDialog, ++ this.dialogElement("strings").getString("chooseAppFilePickerTitle"), ++ nsIFilePicker.modeOpen); ++ ++ fp.appendFilters(nsIFilePicker.filterApps); ++ ++ fp.open(aResult => { ++ if (aResult == nsIFilePicker.returnOK && fp.file) { ++ // Remember the file they chose to run. ++ var localHandlerApp = ++ Cc["@mozilla.org/uriloader/local-handler-app;1"]. ++ createInstance(Ci.nsILocalHandlerApp); ++ localHandlerApp.executable = fp.file; ++ this.chosenApp = localHandlerApp; ++ } ++ this.finishChooseApp(); ++ }); ++ } else { ++ var nsIApplicationChooser = Ci.nsIApplicationChooser; ++ var appChooser = Cc["@mozilla.org/applicationchooser;1"].createInstance( ++ nsIApplicationChooser ++ ); ++ appChooser.init( ++ this.mDialog, ++ this.dialogElement("strings").getString("chooseAppFilePickerTitle") ++ ); ++ var contentTypeDialogObj = this; ++ let appChooserCallback = function appChooserCallback_done(aResult) { ++ if (aResult) { ++ contentTypeDialogObj.chosenApp = aResult.QueryInterface( ++ Ci.nsILocalHandlerApp ++ ); ++ } ++ contentTypeDialogObj.finishChooseApp(); ++ }; ++ appChooser.open(this.mLauncher.MIMEInfo.MIMEType, appChooserCallback); ++ // The finishChooseApp is called from appChooserCallback ++ return; ++ } + } else { + var nsIFilePicker = Ci.nsIFilePicker; + var fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker); + fp.init( + this.mDialog, + this.dialogElement("strings").getString("chooseAppFilePickerTitle"), + nsIFilePicker.modeOpen + ); +diff --git a/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp b/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp +--- a/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp ++++ b/toolkit/system/unixproxy/nsUnixSystemProxySettings.cpp +@@ -14,16 +14,17 @@ + #include "nsPrintfCString.h" + #include "nsNetCID.h" + #include "nsNetUtil.h" + #include "nsISupportsPrimitives.h" + #include "nsIGSettingsService.h" + #include "nsInterfaceHashtable.h" + #include "mozilla/Attributes.h" + #include "nsIURI.h" ++#include "nsKDEUtils.h" + + using namespace mozilla; + + class nsUnixSystemProxySettings final : public nsISystemProxySettings { + public: + NS_DECL_ISUPPORTS + NS_DECL_NSISYSTEMPROXYSETTINGS + +@@ -37,16 +38,18 @@ class nsUnixSystemProxySettings final : + nsCOMPtr mProxySettings; + nsInterfaceHashtable + mSchemeProxySettings; + nsresult GetProxyFromGSettings(const nsACString& aScheme, + const nsACString& aHost, int32_t aPort, + nsACString& aResult); + nsresult SetProxyResultFromGSettings(const char* aKeyBase, const char* aType, + nsACString& aResult); ++ nsresult GetProxyFromKDE(const nsACString& aScheme, const nsACString& aHost, ++ PRInt32 aPort, nsACString& aResult); + }; + + NS_IMPL_ISUPPORTS(nsUnixSystemProxySettings, nsISystemProxySettings) + + NS_IMETHODIMP + nsUnixSystemProxySettings::GetMainThreadOnly(bool* aMainThreadOnly) { + // dbus prevents us from being threadsafe, but this routine should not block + // anyhow +@@ -381,21 +384,50 @@ nsresult nsUnixSystemProxySettings::GetP + return NS_OK; + } + + nsresult nsUnixSystemProxySettings::GetProxyForURI(const nsACString& aSpec, + const nsACString& aScheme, + const nsACString& aHost, + const int32_t aPort, + nsACString& aResult) { ++ if (nsKDEUtils::kdeSupport()) ++ return GetProxyFromKDE(aScheme, aHost, aPort, aResult); ++ + if (mProxySettings) { + nsresult rv = GetProxyFromGSettings(aScheme, aHost, aPort, aResult); + if (NS_SUCCEEDED(rv)) return rv; + } + + return GetProxyFromEnvironment(aScheme, aHost, aPort, aResult); + } + ++nsresult ++nsUnixSystemProxySettings::GetProxyFromKDE(const nsACString& aScheme, ++ const nsACString& aHost, ++ PRInt32 aPort, ++ nsACString& aResult) ++{ ++ nsAutoCString url; ++ url = aScheme; ++ url += "://"; ++ url += aHost; ++ if( aPort >= 0 ) ++ { ++ url += ":"; ++ url += nsPrintfCString("%d", aPort); ++ } ++ nsTArray command; ++ command.AppendElement( NS_LITERAL_CSTRING( "GETPROXY" )); ++ command.AppendElement( url ); ++ nsTArray result; ++ if( !nsKDEUtils::command( command, &result ) || result.Length() != 1 ) ++ return NS_ERROR_FAILURE; ++ aResult = result[0]; ++ return NS_OK; ++} ++ ++ + NS_IMPL_COMPONENT_FACTORY(nsUnixSystemProxySettings) { + auto result = MakeRefPtr(); + result->Init(); + return result.forget().downcast(); + } +diff --git a/toolkit/xre/moz.build b/toolkit/xre/moz.build +--- a/toolkit/xre/moz.build ++++ b/toolkit/xre/moz.build +@@ -87,17 +87,19 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'co + '../components/printingui', + ] + elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'uikit': + UNIFIED_SOURCES += [ + 'nsNativeAppSupportDefault.cpp', + 'UIKitDirProvider.mm', + ] + elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk': ++ EXPORTS += ['nsKDEUtils.h'] + UNIFIED_SOURCES += [ ++ 'nsKDEUtils.cpp', + 'nsNativeAppSupportUnix.cpp', + ] + else: + UNIFIED_SOURCES += [ + 'nsNativeAppSupportDefault.cpp', + ] + + if CONFIG['MOZ_HAS_REMOTE']: +diff --git a/toolkit/xre/nsKDEUtils.cpp b/toolkit/xre/nsKDEUtils.cpp +new file mode 100644 +--- /dev/null ++++ b/toolkit/xre/nsKDEUtils.cpp +@@ -0,0 +1,344 @@ ++/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++#include "nsKDEUtils.h" ++#include "nsIWidget.h" ++#include "nsISupportsPrimitives.h" ++#include "nsIMutableArray.h" ++#include "nsComponentManagerUtils.h" ++#include "nsArrayUtils.h" ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++// copied from X11/X.h as a hack since for an unknown ++// reason it's not picked up from X11/X.h ++#ifndef None ++#define None 0L /* universal null resource or null atom */ ++#endif ++ ++//#define DEBUG_KDE ++#ifdef DEBUG_KDE ++#define KMOZILLAHELPER "kmozillahelper" ++#else ++// not need for lib64, it's a binary ++#define KMOZILLAHELPER "/usr/lib/mozilla/kmozillahelper" ++#endif ++ ++#define KMOZILLAHELPER_VERSION 6 ++#define MAKE_STR2( n ) #n ++#define MAKE_STR( n ) MAKE_STR2( n ) ++ ++static bool getKdeSession() ++ { ++ Display* dpy = XOpenDisplay( NULL ); ++ if( dpy == NULL ) ++ return false; ++ Atom kde_full_session = XInternAtom( dpy, "KDE_FULL_SESSION", true ); ++ bool kde = false; ++ if( kde_full_session != None ) ++ { ++ int cnt; ++ if( Atom* props = XListProperties( dpy, DefaultRootWindow( dpy ), &cnt )) ++ { ++ for( int i = 0; ++ i < cnt; ++ ++i ) ++ { ++ if( props[ i ] == kde_full_session ) ++ { ++ kde = true; ++#ifdef DEBUG_KDE ++ fprintf( stderr, "KDE SESSION %d\n", kde ); ++#endif ++ break; ++ } ++ } ++ XFree( props ); ++ } ++ } ++ XCloseDisplay( dpy ); ++ return kde; ++ } ++ ++static bool getKdeSupport() ++ { ++ nsTArray command; ++ command.AppendElement( NS_LITERAL_CSTRING( "CHECK" )); ++ command.AppendElement( NS_LITERAL_CSTRING( MAKE_STR( KMOZILLAHELPER_VERSION ))); ++ bool kde = nsKDEUtils::command( command ); ++#ifdef DEBUG_KDE ++ fprintf( stderr, "KDE RUNNING %d\n", kde ); ++#endif ++ return kde; ++ } ++ ++nsKDEUtils::nsKDEUtils() ++ : commandFile( NULL ) ++ , replyFile( NULL ) ++ { ++ } ++ ++nsKDEUtils::~nsKDEUtils() ++ { ++// closeHelper(); not actually useful, exiting will close the fd too ++ } ++ ++nsKDEUtils* nsKDEUtils::self() ++ { ++ static nsKDEUtils s; ++ return &s; ++ } ++ ++static bool helperRunning = false; ++static bool helperFailed = false; ++ ++bool nsKDEUtils::kdeSession() ++ { ++ static bool session = getKdeSession(); ++ return session; ++ } ++ ++bool nsKDEUtils::kdeSupport() ++ { ++ static bool support = kdeSession() && getKdeSupport(); ++ return support && helperRunning; ++ } ++ ++struct nsKDECommandData ++ { ++ FILE* file; ++ nsTArray* output; ++ GMainLoop* loop; ++ bool success; ++ }; ++ ++static gboolean kdeReadFunc( GIOChannel*, GIOCondition, gpointer data ) ++ { ++ nsKDECommandData* p = static_cast< nsKDECommandData* >( data ); ++ char buf[ 8192 ]; // TODO big enough ++ bool command_done = false; ++ bool command_failed = false; ++ while( !command_done && !command_failed && fgets( buf, 8192, p->file ) != NULL ) ++ { // TODO what if the kernel splits a line into two chunks? ++//#ifdef DEBUG_KDE ++// fprintf( stderr, "READ: %s %d\n", buf, feof( p->file )); ++//#endif ++ if( char* eol = strchr( buf, '\n' )) ++ *eol = '\0'; ++ command_done = ( strcmp( buf, "\\1" ) == 0 ); ++ command_failed = ( strcmp( buf, "\\0" ) == 0 ); ++ nsAutoCString line( buf ); ++ line.ReplaceSubstring( "\\n", "\n" ); ++ line.ReplaceSubstring( "\\" "\\", "\\" ); // \\ -> \ , i.e. unescape ++ if( p->output && !( command_done || command_failed )) ++ p->output->AppendElement( nsCString( buf )); // TODO utf8? ++ } ++ bool quit = false; ++ if( feof( p->file ) || command_failed ) ++ { ++ quit = true; ++ p->success = false; ++ } ++ if( command_done ) ++ { // reading one reply finished ++ quit = true; ++ p->success = true; ++ } ++ if( quit ) ++ { ++ if( p->loop ) ++ g_main_loop_quit( p->loop ); ++ return FALSE; ++ } ++ return TRUE; ++ } ++ ++bool nsKDEUtils::command( const nsTArray& command, nsTArray* output ) ++ { ++ return self()->internalCommand( command, NULL, false, output ); ++ } ++ ++bool nsKDEUtils::command( nsIArray* command, nsIArray** output) ++ { ++ nsTArray in; ++ PRUint32 length; ++ command->GetLength( &length ); ++ for ( PRUint32 i = 0; i < length; i++ ) ++ { ++ nsCOMPtr str = do_QueryElementAt( command, i ); ++ if( str ) ++ { ++ nsAutoCString s; ++ str->GetData( s ); ++ in.AppendElement( s ); ++ } ++ } ++ ++ nsTArray out; ++ bool ret = self()->internalCommand( in, NULL, false, &out ); ++ ++ if ( !output ) return ret; ++ ++ nsCOMPtr result = do_CreateInstance( NS_ARRAY_CONTRACTID ); ++ if ( !result ) return false; ++ ++ for ( PRUint32 i = 0; i < out.Length(); i++ ) ++ { ++ nsCOMPtr rstr = do_CreateInstance( NS_SUPPORTS_CSTRING_CONTRACTID ); ++ if ( !rstr ) return false; ++ ++ rstr->SetData( out[i] ); ++ result->AppendElement( rstr ); ++ } ++ ++ NS_ADDREF( *output = result); ++ return ret; ++ } ++ ++ ++bool nsKDEUtils::commandBlockUi( const nsTArray& command, GtkWindow* parent, nsTArray* output ) ++ { ++ return self()->internalCommand( command, parent, true, output ); ++ } ++ ++bool nsKDEUtils::internalCommand( const nsTArray& command, GtkWindow* parent, bool blockUi, ++ nsTArray* output ) ++ { ++ if( !startHelper()) ++ return false; ++ feedCommand( command ); ++ // do not store the data in 'this' but in extra structure, just in case there ++ // is reentrancy (can there be? the event loop is re-entered) ++ nsKDECommandData data; ++ data.file = replyFile; ++ data.output = output; ++ data.success = false; ++ if( blockUi ) ++ { ++ data.loop = g_main_loop_new( NULL, FALSE ); ++ GtkWidget* window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); ++ if( parent && gtk_window_get_group(parent) ) ++ gtk_window_group_add_window( gtk_window_get_group(parent), GTK_WINDOW( window )); ++ gtk_widget_realize( window ); ++ gtk_widget_set_sensitive( window, TRUE ); ++ gtk_grab_add( window ); ++ GIOChannel* channel = g_io_channel_unix_new( fileno( data.file )); ++ g_io_add_watch( channel, static_cast< GIOCondition >( G_IO_IN | G_IO_ERR | G_IO_HUP ), kdeReadFunc, &data ); ++ g_io_channel_unref( channel ); ++ g_main_loop_run( data.loop ); ++ g_main_loop_unref( data.loop ); ++ gtk_grab_remove( window ); ++ gtk_widget_destroy( window ); ++ } ++ else ++ { ++ data.loop = NULL; ++ while( kdeReadFunc( NULL, static_cast< GIOCondition >( 0 ), &data )) ++ ; ++ } ++ return data.success; ++ } ++ ++bool nsKDEUtils::startHelper() ++ { ++ if( helperRunning ) ++ return true; ++ if( helperFailed ) ++ return false; ++ helperFailed = true; ++ int fdcommand[ 2 ]; ++ int fdreply[ 2 ]; ++ if( pipe( fdcommand ) < 0 ) ++ return false; ++ if( pipe( fdreply ) < 0 ) ++ { ++ close( fdcommand[ 0 ] ); ++ close( fdcommand[ 1 ] ); ++ return false; ++ } ++ char* args[ 2 ] = { const_cast< char* >( KMOZILLAHELPER ), NULL }; ++ switch( fork()) ++ { ++ case -1: ++ { ++ close( fdcommand[ 0 ] ); ++ close( fdcommand[ 1 ] ); ++ close( fdreply[ 0 ] ); ++ close( fdreply[ 1 ] ); ++ return false; ++ } ++ case 0: // child ++ { ++ if( dup2( fdcommand[ 0 ], STDIN_FILENO ) < 0 ) ++ _exit( 1 ); ++ if( dup2( fdreply[ 1 ], STDOUT_FILENO ) < 0 ) ++ _exit( 1 ); ++ int maxfd = 1024; // close all other fds ++ struct rlimit rl; ++ if( getrlimit( RLIMIT_NOFILE, &rl ) == 0 ) ++ maxfd = rl.rlim_max; ++ for( int i = 3; ++ i < maxfd; ++ ++i ) ++ close( i ); ++#ifdef DEBUG_KDE ++ execvp( KMOZILLAHELPER, args ); ++#else ++ execv( KMOZILLAHELPER, args ); ++#endif ++ _exit( 1 ); // failed ++ } ++ default: // parent ++ { ++ commandFile = fdopen( fdcommand[ 1 ], "w" ); ++ replyFile = fdopen( fdreply[ 0 ], "r" ); ++ close( fdcommand[ 0 ] ); ++ close( fdreply[ 1 ] ); ++ if( commandFile == NULL || replyFile == NULL ) ++ { ++ closeHelper(); ++ return false; ++ } ++ // ok, helper ready, getKdeRunning() will check if it works ++ } ++ } ++ helperFailed = false; ++ helperRunning = true; ++ return true; ++ } ++ ++void nsKDEUtils::closeHelper() ++ { ++ if( commandFile != NULL ) ++ fclose( commandFile ); // this will also make the helper quit ++ if( replyFile != NULL ) ++ fclose( replyFile ); ++ helperRunning = false; ++ } ++ ++void nsKDEUtils::feedCommand( const nsTArray& command ) ++ { ++ for( int i = 0; ++ i < command.Length(); ++ ++i ) ++ { ++ nsCString line = command[ i ]; ++ line.ReplaceSubstring( "\\", "\\" "\\" ); // \ -> \\ , i.e. escape ++ line.ReplaceSubstring( "\n", "\\n" ); ++#ifdef DEBUG_KDE ++ fprintf( stderr, "COMM: %s\n", line.get()); ++#endif ++ fputs( line.get(), commandFile ); ++ fputs( "\n", commandFile ); ++ } ++ fputs( "\\E\n", commandFile ); // done as \E, so it cannot happen in normal data ++ fflush( commandFile ); ++ } +diff --git a/toolkit/xre/nsKDEUtils.h b/toolkit/xre/nsKDEUtils.h +new file mode 100644 +--- /dev/null ++++ b/toolkit/xre/nsKDEUtils.h +@@ -0,0 +1,48 @@ ++/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ ++