#!/bin/bash -a
# Screencast Creator v1.5
# Copyright (C) 2010, 2012, 2015, 2016, 2017 - James Budiono
#			(C) 2016, 2020 - SFR
#			(C) 2016, 2017, 2019, 2020 - step
# License: GPL vesion 3 - see http://www.gnu.org/licenses/gpl.html
# uses: gtkdialog, Xdialog, ffmpeg, xrectsel, togif.sh
# update 1.1 - make it compatible with ffmpeg 0.9.1 in Fatdog64 600
# update 1.2 - update defaults with more sensible values - tested with vlc 2.01 and ffmpeg 0.11.1
# update 1.3 - supports custom resolution with xrectsel, need gtkdialog-r514
# update 1.4 - make it work with ffmpeg 2.8.4
# update 1.5 - SFR: re-designed GUI
# update 1.6 - step/SFR: GUI update, add session settings and improve Finish dialog
# update 1.7 - step: support creating GIF automatically, using togif.sh --gui
# update 1.8 - step: add PNG screenshot; move GIF to advanced options; fix env vars getting in the way of auto-restarting
# update 1.9 - JakeSFR: some GUI rearrangements; add lossless format; minor corrections
# update 1.10 - JakeSFR: improve selecting capture area and scaling; select individual windows; some refactoring
#
# use bash to export functions to gtkdialog

#xrandr |
#sed -n '/Screen/ {s/.*current \(.* x .*\),.*/\1/; s/\([0-9]*\) x \([0-9]*\)/\1 \2/p}' |
#while read HORZ VERT
#do
#	echo $HORZ
#	echo $VERT
#done

export TEXTDOMAIN=fatdog
export OUTPUT_CHARSET=UTF-8

# constant definitions
APPTITLE="Screencast Creator"
APPVERSION="1.10"
RECENT_SETTINGS="$HOME/.screencast.set"

# Some gettext strings need to be pre-processed and put into variables,
# because <comboboxtext> returns item's contents, so we have to compare string-to-string
STR_FORMAT_MP4="$(gettext "Linux (MP4) - smaller file size")"
STR_FORMAT_AVI="$(gettext "Windows compatible (AVI) - best for Avidemux")"
STR_FORMAT_MKV="$(gettext "Lossless (MKV) - best quality, huge file size")"
STR_FORMAT_PNG="$(gettext "Screenshot (PNG) - auto-restart")"

STR_ENTIRE_DESKTOP="$(gettext "Entire desktop")"
STR_SELECTED_WINDOW="$(gettext "Selected window")"
STR_SELECTED_AREA="$(gettext "Selected area")"

STR_QUALITY_LOW="$(gettext "Low quality (small file size)")"
STR_QUALITY_MEDIUM="$(gettext "Medium quality (medium file size)")"
STR_QUALITY_HIGH="$(gettext "High quality (large file size)")"
STR_QUALITY_CUSTOM="$(gettext "Custom quality")"

# Preset settings
# MP4
# Note: Video Bit Tolerance was removed for x264 long ago, but it's still valid for other codecs.
# http://git.videolan.org/?p=ffmpeg.git;a=commitdiff;h=2c5168afed8ddd798dae5909dba85ae3b611f894;hp=6ed3bace9708fad6a656a187a3b182bba21006fa
AUDIO_BITRATE_MP4_LOW=4
AUDIO_SAMPLERATE_MP4_LOW=11025
VIDEO_BITRATE_MP4_LOW=32
VIDEO_BIT_TOLERANCE_MP4_LOW=32

AUDIO_BITRATE_MP4_MEDIUM=4
AUDIO_SAMPLERATE_MP4_MEDIUM=11025
VIDEO_BITRATE_MP4_MEDIUM=64
VIDEO_BIT_TOLERANCE_MP4_MEDIUM=64

AUDIO_BITRATE_MP4_HIGH=8
AUDIO_SAMPLERATE_MP4_HIGH=22050
VIDEO_BITRATE_MP4_HIGH=128
VIDEO_BIT_TOLERANCE_MP4_HIGH=128

# AVI
AUDIO_BITRATE_AVI_LOW=8
AUDIO_SAMPLERATE_AVI_LOW=11025
VIDEO_BITRATE_AVI_LOW=64
VIDEO_BIT_TOLERANCE_AVI_LOW=64

AUDIO_BITRATE_AVI_MEDIUM=8
AUDIO_SAMPLERATE_AVI_MEDIUM=11025
VIDEO_BITRATE_AVI_MEDIUM=128
VIDEO_BIT_TOLERANCE_AVI_MEDIUM=128

AUDIO_BITRATE_AVI_HIGH=16
AUDIO_SAMPLERATE_AVI_HIGH=22050
VIDEO_BITRATE_AVI_HIGH=256
VIDEO_BIT_TOLERANCE_AVI_HIGH=256


# ranges for gtkdialog spinbuttons
MIN_AUDIO_CHANNELS=1
MAX_AUDIO_CHANNELS=2
MIN_FRAME_RATE=10
MAX_FRAME_RATE=60
MIN_SCALE=25
MAX_SCALE=100
MIN_PREPARE_TIME=0
MAX_PREPARE_TIME=600

# default values for gtkdialog variables
AUDIO_BITRATE="${AUDIO_BITRATE_MP4_MEDIUM}"
AUDIO_CHANNELS="2"
AUDIO_DEVICE="hw:0,0"
AUDIO_SAMPLERATE="${AUDIO_SAMPLERATE_MP4_MEDIUM}"
FILE_SAVEFILENAME="/tmp/out_%F_%H%M%S" # filename always gets date(1) time-format expanded, FAT fs doesn't like %T
FORMAT="${STR_FORMAT_MP4}"
FRAME_RATE="10"
PREPARE_TIME="5"
QUALITY="${STR_QUALITY_MEDIUM}"
RECORD_AUDIO="true"
RECORD_ICON="false"		# must be the opposite of RECORD_WINDOW
RECORD_WINDOW="true"	# must be the opposite of RECORD_ICON
RESOLUTION="${STR_ENTIRE_DESKTOP}"
SCALE="100"
TO_GIF="false"
TO_GIF_GUI="true"
VIDEO_BITRATE="${VIDEO_BITRATE_MP4_MEDIUM}"
VIDEO_BIT_TOLERANCE="${VIDEO_BIT_TOLERANCE_MP4_MEDIUM}"
VIDEO_RES=""	# intentionally empty; the default value is set with DEFAULT_RESOLUTION variable
XDISPLAY=":0"

# -----------------------------------------------------------------------------

# function definitions
function set_value_resolution {
	case "$RESOLUTION" in
		"$STR_ENTIRE_DESKTOP"	) get_screen_resolution && echo "${SCREEN_RES}+0+0" ;;
		"$STR_SELECTED_WINDOW"	) choose_window ;;
		"$STR_SELECTED_AREA"	) choose_region ;;
	esac
}

function set_value_quality {
	case "$1" in
		video_bitrate)
			if [ "$FORMAT" = "$STR_FORMAT_MP4" ]; then
				case "$QUALITY" in
					"$STR_QUALITY_LOW")		echo "${VIDEO_BITRATE_MP4_LOW}"		;;
					"$STR_QUALITY_MEDIUM")	echo "${VIDEO_BITRATE_MP4_MEDIUM}"	;;
					"$STR_QUALITY_HIGH")	echo "${VIDEO_BITRATE_MP4_HIGH}"	;;
				esac
			else	# AVI
				case "$QUALITY" in
					"$STR_QUALITY_LOW")		echo "${VIDEO_BITRATE_AVI_LOW}"		;;
					"$STR_QUALITY_MEDIUM")	echo "${VIDEO_BITRATE_AVI_MEDIUM}"	;;
					"$STR_QUALITY_HIGH")	echo "${VIDEO_BITRATE_AVI_HIGH}"	;;
				esac
			fi
		;;
		video_bit_tolerance)
			if [ "$FORMAT" = "$STR_FORMAT_MP4" ]; then
				case "$QUALITY" in
					"$STR_QUALITY_LOW")		echo "${VIDEO_BIT_TOLERANCE_MP4_LOW}"		;;
					"$STR_QUALITY_MEDIUM")	echo "${VIDEO_BIT_TOLERANCE_MP4_MEDIUM}"	;;
					"$STR_QUALITY_HIGH")	echo "${VIDEO_BIT_TOLERANCE_MP4_HIGH}"		;;
					# special case for invisible <comboboxtext>, to keep it in sync with VIDEO_BITRATE
					"$STR_QUALITY_CUSTOM")	echo "${VIDEO_BITRATE}"						;;
				esac
			else	# AVI
				case "$QUALITY" in
					"$STR_QUALITY_LOW")		echo "${VIDEO_BIT_TOLERANCE_AVI_LOW}"		;;
					"$STR_QUALITY_MEDIUM")	echo "${VIDEO_BIT_TOLERANCE_AVI_MEDIUM}"	;;
					"$STR_QUALITY_HIGH")	echo "${VIDEO_BIT_TOLERANCE_AVI_HIGH}"		;;
					# special case for invisible <comboboxtext>, to keep it in sync with VIDEO_BITRATE
					"$STR_QUALITY_CUSTOM")	echo "${VIDEO_BITRATE}"						;;
				esac
			fi
		;;
		audio_bitrate)
			if [ "$FORMAT" = "$STR_FORMAT_MP4" ]; then
				case "$QUALITY" in
					"$STR_QUALITY_LOW")		echo "${AUDIO_BITRATE_MP4_LOW}"		;;
					"$STR_QUALITY_MEDIUM")	echo "${AUDIO_BITRATE_MP4_MEDIUM}"	;;
					"$STR_QUALITY_HIGH")	echo "${AUDIO_BITRATE_MP4_HIGH}"	;;
				esac
			else	# AVI
				case "$QUALITY" in
					"$STR_QUALITY_LOW")		echo "${AUDIO_BITRATE_AVI_LOW}"		;;
					"$STR_QUALITY_MEDIUM")	echo "${AUDIO_BITRATE_AVI_MEDIUM}"	;;
					"$STR_QUALITY_HIGH")	echo "${AUDIO_BITRATE_AVI_HIGH}"	;;
				esac
			fi
		;;
		audio_samplerate)
			if [ "$FORMAT" = "$STR_FORMAT_MP4" ]; then
				case "$QUALITY" in
					"$STR_QUALITY_LOW")		echo "${AUDIO_SAMPLERATE_MP4_LOW}"		;;
					"$STR_QUALITY_MEDIUM")	echo "${AUDIO_SAMPLERATE_MP4_MEDIUM}"	;;
					"$STR_QUALITY_HIGH")	echo "${AUDIO_SAMPLERATE_MP4_HIGH}"		;;
					# without it <comboboxtext> defaults to 1st value
					"$STR_QUALITY_CUSTOM")	echo "${AUDIO_SAMPLERATE}"				;;
				esac
			else	# AVI
				case "$QUALITY" in
					"$STR_QUALITY_LOW")		echo "${AUDIO_SAMPLERATE_AVI_LOW}"		;;
					"$STR_QUALITY_MEDIUM")	echo "${AUDIO_SAMPLERATE_AVI_MEDIUM}"	;;
					"$STR_QUALITY_HIGH")	echo "${AUDIO_SAMPLERATE_AVI_HIGH}"		;;
					# without it <comboboxtext> defaults to 1st value
					"$STR_QUALITY_CUSTOM")	echo "${AUDIO_SAMPLERATE}"				;;
				esac
			fi
		;;
	esac
}

function get_screen_resolution() {
	read HORZ VERT <<EOF
		$(xrandr | sed -n '/Screen/ {s/.*current \(.* x .*\),.*/\1/; s/\([0-9]*\) x \([0-9]*\)/\1 \2/p}')
EOF
	SCREEN_RES=${HORZ}x${VERT}
}

# unused
#function get_half_resolution() {
#	local tgt_horz
#	tgt_horz=$(($HORZ/2))
#	[ $(($tgt_horz % 2)) -eq 1 ] && tgt_horz=$(( tgt_horz + 1))
#	TARGET_RES=$(($tgt_horz))x$(($VERT/2))
#	echo ${TARGET_RES}+0+0
#}
#
#function get_quarter_resolution() {
#	local tgt_horz
#	tgt_horz=$(($HORZ/4))
#	[ $(($tgt_horz % 2)) -eq 1 ] && tgt_horz=$(( tgt_horz + 1))
#	TARGET_RES=$(($tgt_horz))x$(($VERT/4))
#	echo ${TARGET_RES}+0+0
#}

function get_dialog_geometry() {
	xwininfo -root -tree |
	awk '/\x22'"$APPTITLE"'\x22.+gtkdialog/ {
		print "GEOMETRY=\""$(NF-1)"\" TOPLEFT=\""$(NF)"\""
	}'
}
export -f get_dialog_geometry

function show_about() {
	Xdialog --title "$APPTITLE" \
	--msgbox "${APPTITLE} v${APPVERSION}\n© James Budiono 2010, 2012, 2015, 2016, 2017\n© JakeSFR 2016, 2020\n© step 2016, 2017, 2019, 2020" 0 0
}

function choose_window() {
	# JakeSFR: ripped from TAS ;)
	local xpos ypos width height

	get_screen_resolution	# HORZ & VERT

	read xpos ypos width height <<< $(xwininfo -frame | awk 'NR>=8&&NR<=9 {printf "%d ", $4} NR>=12&&NR<=13 {printf "%d ", $2}')
	[ $xpos -lt 0 ] && width=$((width+xpos)) && xpos=0
	[ $ypos -lt 0 ] && height=$((height+ypos)) && ypos=0
	[ $((width+xpos)) -ge $HORZ ] && width=$((HORZ-xpos))
	[ $((height+ypos)) -ge $VERT ] && height=$((VERT-ypos))

	echo "$( align_to 2 ${width}x${height} )+${xpos}+${ypos}"
}

function choose_region() {
	local oldIFS res
	# fallback if xrectsel does not exist
	if ! type xrectsel > /dev/null; then
		echo $VIDEO_RES
	else
		oldIFS="$IFS"
		IFS='x+'
		set -- $(xrectsel)
		IFS="$oldIFS"
		echo "$(align_to 2 ${1}x${2})+${3}+${4}"
	fi
}

# $1 - alignment, $2 - resolution WxH
function align_to () {
	local x y
	x=${2%x*}
	y=${2#*x}
	x=$(( ((x/$1)*$1) ))
	y=$(( ((y/$1)*$1) ))
	[ $x -lt 2 ] && x=2
	[ $y -lt 2 ] && y=2

	echo ${x}x${y}
	#echo ${x}x${y} > /dev/stderr
}

# $1 - scale, $2 - resolution WxH
function scale_to () {
	local x y
	x=${2%x*}
	y=${2#*x}
	x=$(( ((x*1000)/100*$1) / 1000 ))
	y=$(( ((y*1000)/100*$1) / 1000 ))
	
	echo ${x}x${y}
}

# show recording options
function show_options_gui() {
	GUI=$([ -e "$RECENT_SETTINGS" ] && . "$RECENT_SETTINGS"
[ "$FORMAT" != "$STR_FORMAT_PNG" ] && x=true || x=false
sensitize_SECTION_GIF=$x
sensitize_TO_GIF_GUI=$TO_GIF
[ "$FORMAT" != "$STR_FORMAT_MKV" ] && [ "$FORMAT" != "$STR_FORMAT_PNG" ] && x=true || x=false
sensitize_SECTION_QUALITY=$x
[ "$RESOLUTION" != "$STR_ENTIRE_DESKTOP" ] && x=true || x=false
sensitize_BUTTON_CAPTURE=$x
[ "$QUALITY" = "$STR_QUALITY_CUSTOM" ] && x=true || x=false
sensitize_VIDEO_BITRATE=$x
sensitize_VIDEO_BIT_TOLERANCE=$x # is not visible
sensitize_AUDIO_BITRATE=$x
sensitize_AUDIO_SAMPLERATE=$x
cat <<EOV|sed "s/#.*//" # enable interpolation and comments
	<window title="${APPTITLE}" resizable="false" image-name="/usr/share/pixmaps/midi-icons/camera48.png">
		<vbox spacing="2">
			<frame $(gettext "Output filename")>
				<hbox>
					<button tooltip-text="$(gettext "Start Recording")" stock-icon-size="1">
						<input file stock="gtk-media-record"></input>
						<action>get_dialog_geometry</action>
						<action>exit:record</action>
					</button>
					<entry accept="savefilename" is-focus="true" fs-title="$(gettext "Select output file")" tooltip-text="$(gettext "Tip: file name expands date(1) formats.")">
						<variable>FILE_SAVEFILENAME</variable>
						<default>$FILE_SAVEFILENAME</default>
					</entry>
					<button>
						<input file stock="gtk-open"></input>
						<action type="fileselect">FILE_SAVEFILENAME</action>
					</button>
				</hbox>
			</frame>

			<frame $(gettext "Choose format")>
				<comboboxtext>
					<variable>FORMAT</variable>
					<default>$FORMAT</default>
					<item>$STR_FORMAT_MP4</item>
					<item>$STR_FORMAT_AVI</item>
					<item>$STR_FORMAT_MKV</item>
					<item>$STR_FORMAT_PNG</item>
					<action>refresh:VIDEO_BITRATE</action>
					<action>refresh:VIDEO_BIT_TOLERANCE</action>
					<action>refresh:AUDIO_BITRATE</action>
					<action>refresh:AUDIO_SAMPLERATE</action>
					<action condition="command_is_true( [ \"\$FORMAT\" = \"\$STR_FORMAT_PNG\" ] && echo true )">disable:SECTION_GIF</action>
					<action condition="command_is_true( [ \"\$FORMAT\" != \"\$STR_FORMAT_PNG\" ] && echo true )">enable:SECTION_GIF</action>
					<action condition="command_is_true( [ \"\$FORMAT\" = \"\$STR_FORMAT_PNG\" ] || [ \"\$FORMAT\" = \"\$STR_FORMAT_MKV\" ] && echo true )">disable:SECTION_QUALITY</action>
					<action condition="command_is_true( [ \"\$FORMAT\" != \"\$STR_FORMAT_PNG\" ] && [ \"\$FORMAT\" != \"\$STR_FORMAT_MKV\" ]  && echo true )">enable:SECTION_QUALITY</action>
				</comboboxtext>
				<vbox spacing="0" sensitive="$sensitize_SECTION_GIF">
					<hbox>
						<checkbox>
							<label>$(gettext "Record sound")</label>
							<variable>RECORD_AUDIO</variable>
							<default>$RECORD_AUDIO</default>
						</checkbox>
						<text space-fill="true" space-expand="true"><label>""</label></text>
					</hbox>
					<hbox>
						<checkbox>
							<label>$(gettext "Add GIF animation from MP4/AVI/MKV")</label>
							<variable>TO_GIF</variable>
							<default>$TO_GIF</default>
							<action>if true enable:TO_GIF_GUI</action>
							<action>if false disable:TO_GIF_GUI</action>
						</checkbox>
						<text space-fill="true" space-expand="true"><label>""</label></text>
					</hbox>
					<hbox>
						<checkbox sensitive="$sensitize_TO_GIF_GUI">
							<label>$(gettext "Show GIF creator dialog")</label>
							<variable>TO_GIF_GUI</variable>
							<default>$TO_GIF_GUI</default>
						</checkbox>
						<text space-fill="true" space-expand="true"><label>""</label></text>
					</hbox>
					<variable>SECTION_GIF</variable>
				</vbox>
			</frame>

			<frame $(gettext "Choose capture area and scale")>
				<vbox spacing="2">
					<hbox>
						<comboboxtext>
							<variable>RESOLUTION</variable>
							<default>$RESOLUTION</default>
							<item>$STR_ENTIRE_DESKTOP</item>
							<item>$STR_SELECTED_WINDOW</item>
							<item>$STR_SELECTED_AREA</item>
							<action condition="command_is_true( [ \"\$RESOLUTION\" != \"\$STR_ENTIRE_DESKTOP\" ] && echo true )">enable:BUTTON_CAPTURE</action>
							<action condition="command_is_true( [ \"\$RESOLUTION\" = \"\$STR_ENTIRE_DESKTOP\" ] && echo true )">disable:BUTTON_CAPTURE</action>
							<action condition="command_is_true( [ \"\$RESOLUTION\" = \"\$STR_ENTIRE_DESKTOP\" ] && echo true )">refresh:VIDEO_RES</action>
						</comboboxtext>
						<text space-fill="true" space-expand="true"><label>""</label></text>
						<hbox>
							<button sensitive="$sensitize_BUTTON_CAPTURE" tooltip-text="\
$(gettext "In 'Selected window' mode,
to select a window, click this button,
then click the title bar of the desired window.")

$(gettext "In 'Selected area' mode,
to select capture area, click this button,
then click left mouse button and hold,
move the mouse, then release button to confirm.")">
								<variable>BUTTON_CAPTURE</variable>
								<input file stock="gtk-page-setup"></input>
								<action>refresh:VIDEO_RES</action>
							</button>
							<entry editable="false" sensitive="false">
								<variable>VIDEO_RES</variable>
								<default>${VIDEO_RES:-$DEFAULT_RESOLUTION}</default>
								<input>set_value_resolution</input>
							</entry>
						</hbox>
					</hbox>
					
					<hbox>
						<text xalign="0"><label>$(gettext "Scaling factor for the output video (%):")</label></text>
						<text space-fill="true" space-expand="true"><label>""</label></text>
						<spinbutton range-min="$MIN_SCALE" range-max="$MAX_SCALE" range-step="5">
							<variable>SCALE</variable>
							<default>$SCALE</default>
						</spinbutton>
	
					</hbox>
				</vbox>
			</frame>

			<frame $(gettext "Choose quality")>
				<vbox spacing="2" sensitive="$sensitize_SECTION_QUALITY">
					<comboboxtext>
						<variable>QUALITY</variable>
						<default>$QUALITY</default>
						<item>$STR_QUALITY_LOW</item>
						<item>$STR_QUALITY_MEDIUM</item>
						<item>$STR_QUALITY_HIGH</item>
						<item>$STR_QUALITY_CUSTOM</item>
						<action condition="command_is_true( [ \"\$QUALITY\" = \"\$STR_QUALITY_CUSTOM\" ] && echo true )">enable:VIDEO_BITRATE</action>
						<action condition="command_is_true( [ \"\$QUALITY\" = \"\$STR_QUALITY_CUSTOM\" ] && echo true )">enable:AUDIO_BITRATE</action>
						<action condition="command_is_true( [ \"\$QUALITY\" = \"\$STR_QUALITY_CUSTOM\" ] && echo true )">enable:AUDIO_SAMPLERATE</action>
						<action condition="command_is_true( [ \"\$QUALITY\" != \"\$STR_QUALITY_CUSTOM\" ] && echo true )">disable:VIDEO_BITRATE</action>
						<action condition="command_is_true( [ \"\$QUALITY\" != \"\$STR_QUALITY_CUSTOM\" ] && echo true )">disable:AUDIO_BITRATE</action>
						<action condition="command_is_true( [ \"\$QUALITY\" != \"\$STR_QUALITY_CUSTOM\" ] && echo true )">disable:AUDIO_SAMPLERATE</action>
						<action>refresh:VIDEO_BITRATE</action>
						<action>refresh:VIDEO_BIT_TOLERANCE</action>
						<action>refresh:AUDIO_BITRATE</action>
						<action>refresh:AUDIO_SAMPLERATE</action>
					</comboboxtext>
					<hbox>
						<text xalign="0"><label>$(gettext "Video/Audio bitrate (kbps):") </label></text>
						<text space-fill="true" space-expand="true"><label>""</label></text>
						<spinbutton range-min="1" range-max="8192" range-step="1">
							<variable>VIDEO_BITRATE</variable>
							<sensitive>$sensitize_VIDEO_BITRATE</sensitive>
							<default>$VIDEO_BITRATE</default>
							<input>set_value_quality video_bitrate</input>
							<action>refresh:VIDEO_BIT_TOLERANCE</action>	# sync with VIDEO_BIT_TOLERANCE
						</spinbutton>
						<text><label>/</label></text>
						<spinbutton range-min="1" range-max="320" range-step="1">
							<variable>AUDIO_BITRATE</variable>
							<sensitive>$sensitize_AUDIO_BITRATE</sensitive>
							<default>$AUDIO_BITRATE</default>
							<input>set_value_quality audio_bitrate</input>
						</spinbutton>
					</hbox>
					<hbox>
						<text xalign="0"><label>$(gettext "Audio samplerate (Hz):") </label></text>
						<text space-fill="true" space-expand="true"><label>""</label></text>
						<comboboxtext>
							<variable>AUDIO_SAMPLERATE</variable>
							<sensitive>$sensitize_AUDIO_SAMPLERATE</sensitive>
							<default>$AUDIO_SAMPLERATE</default>
							<item>11025</item>
							<item>22050</item>
							<item>44100</item>
							<item>48000</item>
							<input>set_value_quality audio_samplerate</input>
						</comboboxtext>
					</hbox>
					<hbox visible="false">
						<text xalign="0"><label>$(gettext "Video bit tolerance (kb/s):") </label></text>
						<text space-fill="true" space-expand="true"><label>""</label></text>
						<spinbutton range-min="1" range-max="8192" range-step="1">
							<variable>VIDEO_BIT_TOLERANCE</variable>
							<sensitive>$sensitize_VIDEO_BIT_TOLERANCE</sensitive>
							<default>$VIDEO_BIT_TOLERANCE</default>
							<input>set_value_quality video_bit_tolerance</input>
						</spinbutton>
					</hbox>
					<variable>SECTION_QUALITY</variable>
				</vbox>
			</frame>

			<hbox space-fill="true" space-expand="true">
				<text xalign="0"><label>$(gettext "Wait")</label></text>
				<spinbutton range-min="$MIN_PREPARE_TIME" range-max="$MAX_PREPARE_TIME" range-step="1">
					<variable>PREPARE_TIME</variable>
					<default>$PREPARE_TIME</default>
				</spinbutton>
				<text><label>$(gettext "seconds before starting to record")</label></text>
			</hbox>
			
			<hseparator></hseparator>

			<expander expanded="false" label-fill="true">
				<vbox spacing="2">
				
					<hseparator></hseparator>

					<hbox>
						<text xalign="0"><label>$(gettext "FPS:")</label></text>
						<text space-fill="true" space-expand="true"><label>""</label></text>
						<spinbutton range-min="$MIN_FRAME_RATE" range-max="$MAX_FRAME_RATE" range-step="1">
							<variable>FRAME_RATE</variable>
							<default>$FRAME_RATE</default>
						</spinbutton>

						<vseparator></vseparator>

						<text xalign="0"><label>$(gettext "Audio channels:")</label></text>
						<text space-fill="true" space-expand="true"><label>""</label></text>
						<spinbutton range-min="$MIN_AUDIO_CHANNELS" range-max="$MAX_AUDIO_CHANNELS" range-step="1">
							<variable>AUDIO_CHANNELS</variable>
							<default>$AUDIO_CHANNELS</default>
						</spinbutton>
					</hbox>

					<hseparator></hseparator>

					<hbox>
						<text xalign="0"><label>$(gettext "X display to capture from:")</label></text>
						<text space-fill="true" space-expand="true"><label>""</label></text>
						<entry width-request="50">
							<variable>XDISPLAY</variable>
							<default>$XDISPLAY</default>
						</entry>
					</hbox>
					<hbox>
						<text xalign="0"><label>$(gettext "Audio device for recording:")</label></text>
						<text space-fill="true" space-expand="true"><label>""</label></text>
						<entry width-request="50">
							<variable>AUDIO_DEVICE</variable>
							<default>$AUDIO_DEVICE</default>
						</entry>
					</hbox>

					<hseparator></hseparator>
		
					<hbox>
						<text xalign="0"><label>$(gettext "Recording dialog:")</label></text>
						<text space-fill="true" space-expand="true"><label>""</label></text>
						<radiobutton>
						<variable>RECORD_WINDOW</variable>
						<default>$RECORD_WINDOW</default>
						<label>$(gettext "Window")</label>
						</radiobutton>
						<radiobutton>
						<label>$(gettext "Tray icon")</label>
						<variable>RECORD_ICON</variable>
						<default>$RECORD_ICON</default>
						</radiobutton>
					</hbox>

				</vbox>
				<label>$(gettext "Advanced settings")</label>
			</expander>
			
			<hseparator></hseparator>

			<hbox>
				<button space-fill="false" space-expand="false">
					<input file stock="gtk-about"></input>
					<label>$(gettext "About")</label>
					<action>show_about</action>
				</button>
				<text space-fill="true" space-expand="true"><label>""</label></text>
				<button cancel></button>
				<button>
					<input file stock="gtk-media-record"></input>
					<label>$(gettext "Start Recording")</label>
					<action>get_dialog_geometry</action>
					<action type="exit">record</action>
				</button>
			</hbox>
		</vbox>
	</window>

EOV
	);

	OUT="$(gtkdialog --program=GUI)"
	#echo "$OUT" >&2
	case $OUT in
		*EXIT=?record*)
			echo "$OUT" > "$RECENT_SETTINGS"
	esac
	eval "$OUT"
	FILE_SAVEFILENAME="${FILE_SAVEFILENAME%/*}/$(date "+${FILE_SAVEFILENAME##*/}")"
}

function show_record_gui() {
	TIME_START=$(date -u +%s)
	GUI='
	<window title="'$(gettext "Capturing")'" resizable="false" image-name="/usr/share/pixmaps/midi-icons/camera48.png">
		<vbox>
			<frame '$(gettext "Recording in progress")'>
				<hbox homogeneous="false">
					<button stock-icon-size="1" tooltip-text="'$(gettext "Finish")'">
						<input file stock="gtk-media-stop"></input>
						<action>exit:Finish</action>
					</button>
					<entry editable="false" xalign="0.5" width-chars="10">
						<variable>UPTIME_MSG</variable>
						<input>date -u -d @$(( $(date -u +%s) - $TIME_START )) +%H:%M:%S</input>
					</entry>
					<entry editable="false" xalign="0.5" width-chars="10" tooltip-text="'"$FILE_SAVEFILENAME"'">
						<variable>FILESIZE</variable>
						<input>echo -n "$( [ $RECORD_AUDIO = "true" ] && du -h -c "'"$FILE_SAVEFILENAME"'.video" "'"$FILE_SAVEFILENAME"'.audio" | tail -n 1 | cut -f1 || du -h -c "'"$FILE_SAVEFILENAME"'" | tail -n 1 | cut -f1 )"</input>
					</entry>
				</hbox>
				<timer interval="1" visible="false">
					<action>refresh:UPTIME_MSG</action>
				</timer>
				<timer interval="3" visible="false">
					<action>refresh:FILESIZE</action>
				</timer>
			</frame>
		</vbox>
	</window>
'
	gtkdialog --program=GUI -G $TOPLEFT
}

function show_record_icon() {
	TOOLTIP="/tmp/screencast_tooltip_${USER}"
	FINISH_MARK="/tmp/screencast_finish_${USER}"
	: > "${TOOLTIP}"
	rm -f "${FINISH_MARK}"

	sit /usr/share/pixmaps/mini-icons/mini-record.xpm "${TOOLTIP}" "touch ${FINISH_MARK}" "touch ${FINISH_MARK}" &
	SIT_PID=$!

	TIME_START=$(date -u +%s)

  local one=0
	while [ ! -f "${FINISH_MARK}" ]; do
	  echo -e "$(gettext "Recording in progress, click to finish.")\n" > "${TOOLTIP}"
	  echo "$(gettext "Uptime"): $(date -u -d @$(( $(date -u +%s) - $TIME_START )) +%H:%M:%S)" >> "${TOOLTIP}"
	  echo "$(gettext "Output size"): $( [ $RECORD_AUDIO = "true" ] && du -h -c "$FILE_SAVEFILENAME.video" "$FILE_SAVEFILENAME.audio" | tail -n 1 | cut -f1 || du -h -c "$FILE_SAVEFILENAME" | tail -n 1 | cut -f1 )" >> "${TOOLTIP}"
    echo -n "$FILE_SAVEFILENAME" >> "${TOOLTIP}"
    sleep 1
	done

	kill $SIT_PID
	rm -f "${TOOLTIP}" "${FINISH_MARK}"
}

function checkfile_exist() {
	local user home
	# expand tilde
	if [[ "$FILE_SAVEFILENAME" == \~* ]]; then # note: bashisms
		user=${FILE_SAVEFILENAME%%/*}; user=${user:1}/
		eval home=$(printf "~%q" "$user")
		FILE_SAVEFILENAME="$home${FILE_SAVEFILENAME#*/}"
	fi

	# append the correct extension
	FILE_SAVEFILENAME="${FILE_SAVEFILENAME%.*}.${FORMAT}"

	if [ -f "$FILE_SAVEFILENAME" ]; then
		if ! Xdialog --title WARNING --yesno "$FILE_SAVEFILENAME $(gettext "already exist.")\n$(gettext "Are you sure you want to overwrite?")" 0 0; then
			exit
		fi
	fi
}

function parse_options() {
	# 1. get the source and target resolution
	SOURCE_ORG=${VIDEO_RES#*+}
	SOURCE_ORG=${SOURCE_ORG/+/,}
	SOURCE_RES=$(align_to 2 ${VIDEO_RES%%+*})
	TARGET_RES=$(scale_to $SCALE ${VIDEO_RES%%+*})
	TARGET_RES=$(align_to 2 ${TARGET_RES%%+*})

	[ ${FRAME_RATE} -le ${MIN_FRAME_RATE} ] && FRAME_RATE=${MIN_FRAME_RATE}

	# 2. format
	if [ "$FORMAT" = "$STR_FORMAT_PNG" ]; then
		FORMAT=png
	elif [ "$FORMAT" = "$STR_FORMAT_AVI" ]; then
		FORMAT=avi
	elif [ "$FORMAT" = "$STR_FORMAT_MP4" ]; then
		FORMAT=mp4
	elif [ "$FORMAT" = "$STR_FORMAT_MKV" ]; then
		FORMAT=mkv
	else
		FORMAT=mp4	# fallback
	fi

	# 3. quality
	AUDIO_BITRATE=${AUDIO_BITRATE}k
	AUDIO_SAMPLERATE=${AUDIO_SAMPLERATE}   # no k, is this right? # SFR: yes, samplerate must be a "pure" number
	VIDEO_BITRATE=${VIDEO_BITRATE}k
	VIDEO_BIT_TOLERANCE=${VIDEO_BIT_TOLERANCE}k

	# 4. combination of quality and format
	case $FORMAT in
		mp4)
			VIDEO_CODEC=libx264
			VIDEO_FORMAT=mp4
			VIDEO_OPTION="-preset slow -force_fps -pix_fmt yuv420p "
			AUDIO_CODEC=libfdk_aac # or just "aac"
			AUDIO_FORMAT=dts
			CONV_FILTER='-bsf:a aac_adtstoasc '
		;;
		avi)
			VIDEO_CODEC=wmv1
			VIDEO_FORMAT=avi
			VIDEO_OPTION=
			AUDIO_CODEC=libmp3lame
			AUDIO_FORMAT=mp3
			CONV_FILTER=
		;;
		mkv)
			VIDEO_CODEC=libx264
			VIDEO_FORMAT=matroska
			VIDEO_OPTION="-crf 0 -preset ultrafast -force_fps -pix_fmt yuv420p "
			AUDIO_CODEC=flac
			AUDIO_FORMAT=flac
			CONV_FILTER=
		;;
		png)
			VIDEO_CODEC=
			VIDEO_FORMAT=
			VIDEO_OPTION=
			AUDIO_CODEC=
			AUDIO_FORMAT=
			CONV_FILTER=
		;;
	esac

	# 5. build the ffmpeg args
	if [ $FORMAT = "png" ]; then
		DRAW_MOUSE_OPT="-draw_mouse 0" POINTER="+nomouse" # DRAW_MOUSE_OPT="-draw_mouse 1" POINTER=
		FFMPEG_VIDEO_ARGS="-f x11grab $DRAW_MOUSE_OPT -s $SOURCE_RES -i ${XDISPLAY}+${SOURCE_ORG}${POINTER} \
			-r 25 -s $TARGET_RES -vframes 1 -pix_fmt rgb24"
	elif [ "$FORMAT" = "mkv" ]; then	# lossless
		FFMPEG_VIDEO_ARGS="-y -f x11grab -s $SOURCE_RES -r $FRAME_RATE -i ${XDISPLAY}+${SOURCE_ORG} \
			-r $FRAME_RATE -vcodec $VIDEO_CODEC -s $TARGET_RES $VIDEO_OPTION -f $VIDEO_FORMAT "
		FFMPEG_AUDIO_ARGS="-y -f alsa -ac $AUDIO_CHANNELS -i $AUDIO_DEVICE -r $FRAME_RATE \
			-acodec $AUDIO_CODEC -f $AUDIO_FORMAT"
	else
		FFMPEG_VIDEO_ARGS="-y -f x11grab -s $SOURCE_RES -r $FRAME_RATE -i ${XDISPLAY}+${SOURCE_ORG} \
			-r $FRAME_RATE -vcodec $VIDEO_CODEC -s $TARGET_RES -b:v $VIDEO_BITRATE -bt $VIDEO_BIT_TOLERANCE $VIDEO_OPTION -f $VIDEO_FORMAT "
		FFMPEG_AUDIO_ARGS="-y -f alsa -ac $AUDIO_CHANNELS -i $AUDIO_DEVICE -r $FRAME_RATE \
			-acodec $AUDIO_CODEC -ar $AUDIO_SAMPLERATE -ab $AUDIO_BITRATE -f $AUDIO_FORMAT"
	fi

}

function start_recording() {
	parse_options
	checkfile_exist
	sleep $PREPARE_TIME  # wait a while to let user prepare

	# all set, now go !
	if [ $FORMAT = "png" ]; then
		ffmpeg $FFMPEG_VIDEO_ARGS "$FILE_SAVEFILENAME" #.png
		FFMPEG_VIDEO_PID=
		return
	elif [ $RECORD_AUDIO = "true" ]; then
		ffmpeg $FFMPEG_VIDEO_ARGS "$FILE_SAVEFILENAME".video &
		FFMPEG_VIDEO_PID=$!
		ffmpeg $FFMPEG_AUDIO_ARGS "$FILE_SAVEFILENAME".audio &
		FFMPEG_AUDIO_PID=$!
	else
		ffmpeg $FFMPEG_VIDEO_ARGS "$FILE_SAVEFILENAME" &
		FFMPEG_VIDEO_PID=$!
	fi

	# wait for 1 seconds, see if it is successful
	sleep 1
	if ! [ -e /proc/$FFMPEG_VIDEO_PID ]; then
		[ $RECORD_AUDIO = "true" ] && pkill -INT -P $FFMPEG_AUDIO_PID
		Xdialog --title "$(gettext "ERROR")" --msgbox "$(gettext "Screen capture failed.\nTo see error messages run again in a terminal:\n")$0 -d" 0 0
		exit
	fi
}

function finish_recording() {
	local ret
	[ -z "$FFMPEG_VIDEO_PID" ] && return
	pkill -INT -P $FFMPEG_VIDEO_PID
	if [ $RECORD_AUDIO = "true" ]; then
		pkill -INT -P $FFMPEG_AUDIO_PID
		# join video and audio
		Xdialog --title "$APPTITLE" --no-buttons --infobox "$(gettext "Joining video and audio, please wait ...")" 0 0 1000000 &
		XPID=$!
 		# wait for ffmpegs to stop
		sleep 3
		ffmpeg -y -i "$FILE_SAVEFILENAME".video -i "$FILE_SAVEFILENAME".audio \
			-acodec copy -vcodec copy $CONV_FILTER -f $VIDEO_FORMAT "$FILE_SAVEFILENAME"
		ret=$?
		[ 0 = $ret ] && rm -f "$FILE_SAVEFILENAME".video "$FILE_SAVEFILENAME".audio
		kill $XPID
	fi
	return $ret
}

function postprocessing() {
	local ret gif gui
	! [ -f "$FILE_SAVEFILENAME" ] && return
	sleep 1
	gif="${FILE_SAVEFILENAME%.*}.gif"
	[ "$TO_GIF_GUI" = true ] && gui=--gui
	if [ "$TO_GIF" = true ]; then
		# IN OUT SCALE(300) QUALITY(low,lowers,high,high2)
		togif.sh $gui "$FILE_SAVEFILENAME" "$gif"
		ret=$?
	fi
	[ 0 = "$ret" ] && [ -z "$gui" ] &&
		echo "\n\n$(gettext "GIF animation saved in:\n")$gif\n\n$(gettext "For higher quality run:")\ntogif.sh --gui"
	return $ret
}

# -----------------------------------------------------------------------------

# ==== main ====
if [ "$1" = "-d" ]; then
	echo "Debug mode - ffmpeg output to terminal."
else
	exec < /dev/null > /dev/null 2>&1 # enable it to run in the background
fi

DEFAULT_RESOLUTION="$(get_screen_resolution && echo "${SCREEN_RES}+0+0")"

show_options_gui;

if [ "$EXIT" = "record" ]; then

	start_recording

	if [ $FORMAT = "png" ]; then

		[ -s "$FILE_SAVEFILENAME" ] && exec "$0" # auto-restart to take another screenshot
		msg="$(gettext "Screenshot failed:")\n$FILE_SAVEFILENAME"

	else

		if [ "$RECORD_WINDOW" = "true" ]; then
		  show_record_gui
		else
		  show_record_icon
		fi
		
		if finish_recording; then
			msg="$(gettext "Done! Screencast is saved in:")\n$FILE_SAVEFILENAME"
			msg="${msg}$(postprocessing)"
		else
			msg="$(gettext "Done with errors. Partial tracks are salvaged as:")\n$FILE_SAVEFILENAME.{video,audio}"
		fi

	fi

	Xdialog --title "$APPTITLE" --infobox "$msg" 0 0 10000

fi
