Skip to content

Instantly share code, notes, and snippets.

@s-leroux
Last active January 30, 2023 15:56
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save s-leroux/d1d2f730467857fa3afe to your computer and use it in GitHub Desktop.
Save s-leroux/d1d2f730467857fa3afe to your computer and use it in GitHub Desktop.
Running a nested xfce4-session in Xephyr
#!/bin/bash
DISPLAY=:15
X=0
Y=0
X11GRAB_OPTS=( -show_region 1 )
shopt -s extglob
while [ ! -z "$1" ]
do
case "$1" in
:*) DISPLAY="$1"
shift
;;
+([0-9])x+([0-9]))
read W H < <(tr -c "[0-9]" " " <<< "$1")
shift
;;
+([0-9])x+([0-9])++([0-9])++([0-9]))
read W H X Y < <(tr -c "[0-9]" " " <<< "$1")
shift
;;
--nomouse)
X11GRAB_OPTS+=( -draw_mouse 0 )
shift
;;
*) OUTFILE="$1"
shift
;;
esac
done
[ -f "${OUTFILE}" ] && {
echo "${OUTFILE} already exists. Aborting." >&2
exit 1
}
if which play > /dev/null 2>&1 ; then
(
sleep 1.0
play -n -c1 synth .2 sin 440 gain -12
if which espeak > /dev/null 2>&1 ; then
sleep 0.25
echo "$(basename "${OUTFILE%.*}")" | espeak
fi
) &
fi
while IFS=": " read key value ; do
echo "key=|$key| value=|$value|"
case "$key" in
Width) DWIDTH=$value
echo W
;;
Height) DHEIGHT=$value
;;
esac
done < <(xwininfo -display "${DISPLAY}" -root)
[ -z "${W}" ] && W="${DWIDTH}"
[ -z "${H}" ] && H="${DHEIGHT}"
ffmpeg -y \
-f x11grab -thread_queue_size 512 -vsync cfr -framerate 25 \
-video_size "${W}x${H}" \
"${X11GRAB_OPTS[@]}" \
-i "${DISPLAY}.0+$X,$Y" \
-f alsa -thread_queue_size 2048 -acodec pcm_s24le -sample_rate 44100 -ac 1 -i pulse \
-c:a pcm_s16le \
-c:v libx264 -pix_fmt yuv420p -preset ultrafast -tune animation -qp 1 \
-map 0:0,0:0 -map 1:0,0:0 \
-timecode 00:00:00:00 \
"$OUTFILE"
#define _XOPEN_SOURCE
#include <stdlib.h>
#include <stdio.h>
int main() {
return grantpt(0);
}
all: pts grantpt ptsname unlockpt
#!/bin/bash
function usage() {
nroff -mandoc <<-EOF | less
.TH $(basename $0) 1
$(basename $0) - open a nested X terminal
.SH SYNOPSIS
$(basename $0) [displayid] [displaysize | --fullscreen] [userlogin] [homedir]
$(basename $0) \-\-help
.SH OPTIONS
.TP
.BR \fIdisplayid\fR
Virtual display to create
Default is :15
.TP
.BR \fIdisplaysize\fR
Size of the virtual display
Default is 1280x720
.TP
.BR \fIuserlogin\fR
Open a session with the given identity.
Default is the current user. Opening a session as a different user require sudo access.
.TP
.BR \fIhomedir\fR
Set the \fIHOME\fR directory for the nested session.
Useful to run xfce4 in a clean and distinct environment
from yours. The nested session owner should have
read/write access to the directory.
.SH EXAMPLE
./nested-xfce4-session.sh
Start a new X11 server and run xfce4-session
./nested-xfce4-session.sh :12
Start a new X11 server as DISPLAY :12 and run xfce4-session
./nested-xfce4-session.sh :12 640x480
Start a new X11 server as DISPLAY :12
with a screen size of 640x480 and run xfce4-session
(eventually screen size will be resized according to
your host xfce4 configuration)
./nested-xfce4-session.sh /tmp/temp.dir
Start a new X11 server and run xfce4-session with the
home directory set to /tmp/temp.dir.
EOF
}
SCREEN="1280x720"
USER=$(whoami)
GUEST_DISPLAY=":15"
EXTRA=( -dpi 96 )
REMOTE=
shopt -s extglob
declare -A OPTS
while [ ! -z "$1" ]
do
case "$1" in
-?(-)help)
usage
exit 0
;;
+([0-9])x+([0-9]))
SCREEN="$1"
shift
;;
--fullscreen)
EXTRA+=( -fullscreen )
shift
;;
:+([0-9]))
GUEST_DISPLAY="$1"
shift
;;
*@*) USER="$1"
REMOTE=true
shift
;;
*) if id -u "$1" > /dev/null 2>&1 ; then
# valid user name on that system
USER="$1"
shift
elif [ -d "$1" ] ; then
# valid directory
OPTS[HOME]="HOME=\"$1\""
shift
else
echo Not a known user or directory : "$1" >&2
exit 1
fi
;;
esac
done
# Prepare the client to run when server will be ready
LAUNCHER="/bin/bash"
#if [ "${USER}" != $(whoami) ]
# LAUNCHER="sudo -u ${USER} -b -i"
#then
#else
# LAUNCHER="env -i PATH=${PATH}
# DISPLAY=${GUEST_DISPLAY}
# HOME=${HOME}
# LOGNAME=${LOGNAME}
# USER=${USER} bash -c"
#fi
TEMPDIR=$(mktemp -d)
FIFO="${TEMPDIR}/fifo"
mkfifo "${FIFO}"
chmod a+r "${FIFO}"
chmod a+x "${TEMPDIR}"
exec 3<>"${FIFO}"
APP=xfce4-session
#APP=xterm
if [ -n "$REMOTE" ]
then
DISPLAY=${GUEST_DISPLAY} ssh -fCY ${USER} "sleep 5 && echo \$DISPLAY && unset XAUTHORITY && "${OPTS[@]}" ${APP}"
else
LAUNCHER="sudo -u ${USER} -b -i bash -c"
DISPLAY=${GUEST_DISPLAY} ${LAUNCHER} "read DISPLAY < '${FIFO}' && \
unset XAUTHORITY && \
"${OPTS[@]}" DISPLAY=\":\${DISPLAY}\" $APP"
fi
Xephyr -displayfd 3 \
-sw-cursor -reset -terminate \
"${GUEST_DISPLAY}" -screen "${SCREEN}" "${EXTRA[@]}"
rm -rf "${TEMPDIR}"
wait
#define _XOPEN_SOURCE
#include <stdlib.h>
#include <stdio.h>
int main() {
int status;
status = grantpt(0);
if (status)
return status;
status = unlockpt(0);
if (status)
return status;
char *pts = ptsname(0);
printf("%s\n", pts ? pts : "");
return pts ? 0 : 1;
}
#define _XOPEN_SOURCE
#include <stdlib.h>
#include <stdio.h>
int main() {
char *pts = ptsname(0);
printf("%s\n", pts ? pts : "");
return 0;
}
#!/bin/bash
GEOMETRY="80x24"
USER=$(whoami)
GUEST_DISPLAY=":15"
WINNAME=$(uuidgen || echo $RANDOM)
EXTRA=( --disable-server --title "$WINNAME" )
OUTFILE="out.mov"
shopt -s extglob
declare -A OPTS
OPTS[HOME]=""
while [ ! -z "$1" ]
do
case "$1" in
-?(-)help)
usage
exit 0
;;
+([0-9])x+([0-9])*)
GEOMETRY="$1"
shift
;;
--fullscreen)
EXTRA+=( --fullscreen )
shift
;;
:+([0-9]))
GUEST_DISPLAY="$1"
shift
;;
*.mov) OUTFILE="$1"
shift
;;
*) if id -u "$1" > /dev/null 2>&1 ; then
# valid user name on that system
USER="$1"
shift
elif [ -d "$1" ] ; then
# valid directory
OPTS[HOME]="$1"
shift
else
echo Not a known user or directory : "$1" >&2
exit 1
fi
;;
esac
done
TEMPDIR=$(mktemp -d)
COMP="${TEMPDIR}/comp"
CTRL="${TEMPDIR}/ctrl"
FIFO="${TEMPDIR}/fifo"
mkfifo "${COMP}"
mkfifo "${CTRL}"
mkfifo "${FIFO}"
chmod a+r "${COMP}"
chmod a+r "${FIFO}"
chmod a+x "${TEMPDIR}"
#exec 3<>"${FIFO}"
typeit() {
while IFS='' read -rn1 C; do
if [ -z "${C}" ] ; then
echo
else
echo -n "$C"
fi
sleep .$((1+$RANDOM/15000))
[ -z "${C}" ] && sleep 1.5 # extra delay after end-of-line
done
}
sudo -u "${USER}" -b -i xfce4-terminal --geometry="${GEOMETRY}" \
--display="${GUEST_DISPLAY}" \
--hide-menubar \
--hide-toolbar \
--hide-scrollbar \
"${EXTRA[@]}" -x bash -c \
'cat < '"${FIFO}"' ; read < '"${COMP}"
sleep 1
# At this point, the terminal window is blocked.
# Start capture
./capture.sh --nomouse "${GUEST_DISPLAY}" \
$(./window-geometry.sh "${GUEST_DISPLAY}" "${WINNAME}") \
"${OUTFILE}" < "${CTRL}" &
CAPTUREPID="$!"
echo "${CAPTUREPID}"
echo > "${CTRL}"
# For obscure reasons, the following line will put the process to
# the background when reading from stdin ?!?
# Maybe `stty -tostop` would FIX that ?
# See http://www.linusakesson.net/programming/tty/
# This require a PTS, not a Pipe so 'bash -i' will be totally
# "fooled" in thinking it is connected to a terminal
exec 3<>/dev/ptmx
sudo -u "${USER}" echo -n # <- hack to force authentication here
PTS=$(./pts <&3)
echo $?
# sudo -u "${USER}" ./grantpt <&3
# echo $?
# ./unlockpt <&3
# echo $?
# PTS=$(./ptsname <&3)
# echo $?
echo PTS is ${PTS}
# stty -F "${PTS}" cooked echo iutf8 rows 22 columns 80
# stty -F "${PTS}" --all
(
sleep 3
typeit
sleep 1
# Take a screenshot after completion
xwd -silent -display "${GUEST_DISPLAY}" -name "${WINNAME}" | \
convert xwd:- "${OUTFILE%.*}.png"
echo exit
) >&3 < /dev/stdin &
sudo -nSu "${USER}" \
bash -c "
cd \"${OPTS[HOME]:-\$HOME}\"
bash -i
" <"${PTS}" 2>&1 | tee "${OUTFILE%.*}.log" >"${FIFO}"
exec 3>&-
sleep 1
echo 'q' > "${CTRL}"
wait
# Exit terminal
echo 'done' > "${COMP}"
#kill -SIGTERM "${CAPTUREPID}"
rm -rf "${TEMPDIR}"
#define _XOPEN_SOURCE
#include <stdlib.h>
#include <stdio.h>
int main() {
return unlockpt(0);
}
#!/bin/bash
# Assume window title is $1
# FIXME enforce that !
DISPLAY=:15
WINNAME=""
shopt -s extglob
while [ ! -z "$1" ]
do
case "$1" in
:*) DISPLAY="$1"
shift
;;
*) WINNAME="$1"
shift
;;
esac
done
[ -z "${WINNAME}" ] && {
echo "Missing window name Aborting." >&2
exit 1
}
declare -A WINPROPS
while IFS=": " read key value ; do
if [ -n "$key" ]; then
# echo "key=|$key| value=|$value|" >&2
WINPROPS["$key"]="$value"
fi
done < <(xwininfo -display "${DISPLAY}" -name "$WINNAME")
printf "%sx%s%s\n" \
"${WINPROPS[Width]}" \
"${WINPROPS[Height]}" \
"${WINPROPS[Corners]%% *}"
@melchisedech333
Copy link

Your codes helped me a lot. Thank you so much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment