#!/bin/bash

# Copyright Jean-Philippe Guillemin <jp.guillemin@free.fr>. This program is free software;
# you can redistribute it and/or modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 of the License,
# or (at your option) any later version. Please take a look at http://www.gnu.org/copyleft/gpl.htm

# This script :
# - probes for videocard, monitor and keyboard
# - ask for runlevel
# - writes a configured Xorg config file.


# Path needs to be extended in case you're only half a root :)
export PATH="${PATH}:/usr/sbin:/sbin"

if [ "$(id -u)" != "0" ]; then
  echo "You need to be root to run $(basename "$0")" >&2
  exit 1
fi

# Decide whether we can run interactively: we need an X display AND yad.
# If either is missing, fall back to silent (unattended) mode automatically.
useGui="no"
if [[ "$DISPLAY" && "$(command -v yad 2>/dev/null)" ]]; then
  useGui="yes"
fi

# create the tmpDir directory
export tmpDir="$(mktemp -d -p /tmp temp.XXXXXXXX)"

##################################################################
# GUI helper functions (yad only)
##################################################################

# showInfoBox <title> <message>   (brief, self-dismissing notice)
function showInfoBox(){
  yad --center --title="$1" --text="$2" --width=400 \
    --no-buttons --timeout=1 --timeout-indicator=bottom
}

# showMenu <title> <prompt> <preselectedTag> <tag1> <desc1> [<tag2> <desc2> ...]
# <preselectedTag> is the tag that should come pre-checked (pass "" for
# "just check the first row"). Prints the chosen tag to stdout.
function showMenu(){
  local title="$1"; shift
  local prompt="$1"; shift
  local preselect="$1"; shift

  local yadRows=()
  local matched="no"
  while [ "$#" -gt 0 ]; do
    if [ "$1" = "$preselect" ]; then
      yadRows+=("TRUE" "$1" "$2")
      matched="yes"
    else
      yadRows+=("FALSE" "$1" "$2")
    fi
    shift 2
  done
  # If nothing matched the requested preselect (e.g. current setting
  # doesn't map to any offered option), default to checking the first row.
  if [ "$matched" = "no" ]; then
    yadRows[0]="TRUE"
  fi

  yad --center --title="$title" --text="$prompt" \
    --list --radiolist --width=520 --height=200 \
    --column="Pick" --column="Option" --column="Description" \
    "${yadRows[@]}" \
    --print-column=2 --separator="" \
    --button="OK:0"
}

# detectRunLevel - reads /etc/inittab and reports the current default
# runlevel as one of "Text" (3), "Graphical" (4), or "" (anything else /
# not found).
function detectRunLevel(){
  local lvl
  lvl="$(grep "^id:.*:initdefault:" /etc/inittab 2>/dev/null \
    | sed -e 's/^id:\([0-9]\):initdefault:.*/\1/')"
  case "$lvl" in
    3) echo "Text" ;;
    4) echo "Graphical" ;;
    *) echo "" ;;
  esac
}

##################################################################
function writeConf(){

# ServerFlags section:
cat << EOF >  /etc/X11/xorg.conf.d/10-server-flags.conf
Section "ServerFlags"
# Option    "NoTrapSignals"
# Option    "DontVTSwitch"
  Option    "DontZap"   "off"
# Option    "DontZoom"
# Option    "DisableVidModeExtension"
# Option    "AllowNonLocalXvidtune"
# Option    "DisableModInDev"
# Option    "AllowNonLocalModInDev"
# Option      "blank time"    "10"    # 10 minutes
# Option      "standby time"    "20"
# Option      "suspend time"    "30"
# Option    "off time"      "60"
# Option    "EstimateSizesAggresively" "0"
# Option    "AutoEnableDevices" "false"
# Option    "AutoAddDevices"  "false"
# Option    "AllowEmptyInput" "false"
EndSection

EOF

# InputClass section:

cat << EOF > /etc/X11/xorg.conf.d/90-keyboard-layout.conf
Section "InputClass"
  Identifier "keyboard-all"
  MatchIsKeyboard "on"
  MatchDevicePath "/dev/input/event*"
  Driver "libinput"
  Option "XkbLayout" "$xkbLayout"
  Option "XkbVariant" "$xkbVariant"
  Option "XkbOptions" "$xkbOptions"
EndSection
EOF

# Device section:
# Modern approach: let the kernel's KMS driver + Xorg's generic
# "modesetting" driver handle Intel/AMD/nouveau/generic framebuffers.
# We only special-case VirtualBox, which needs its own vboxvideo-aware
# handling rather than modesetting.

if [ "$isVirtualBox" == "yes" ] ; then
cat << EOF > /etc/X11/xorg.conf.d/30-devices.conf
Section "Device"
  Identifier  "VirtualBox"
  Driver      "vboxvideo"
EndSection

EOF

else
cat << EOF > /etc/X11/xorg.conf.d/30-devices.conf
Section "Device"
  Identifier  "Modesetting"
  Driver      "modesetting"
  Option      "DRI" "3"
EndSection

EOF

fi

if [ "$compositor" == "No" ] ; then

cat << EOF >  /etc/X11/xorg.conf.d/20-compositor.conf
Section "Extensions"
        Option "Composite" "disable"
EndSection

EOF

else
cat << EOF >  /etc/X11/xorg.conf.d/20-compositor.conf
Section "Extensions"
        Option "Composite" "enable"
EndSection

EOF
fi

## DRI section:
#cat << EOF >>  /etc/X11/xorg.conf

## DRI            ( DRI-specific configuration )
##_______________________________________________________________________

#Section "dri"
## Access to OpenGL ICD is allowed for all users:
    #Mode   0666
## Access to OpenGL ICD is restricted to a specific user group:
##    Group   100    # users
#EndSection
#EOF

}



##################################################################
# Converts keyboard map from kmap (/usr/share/kbd/keymaps) to xkb (/etc/X11/xkb)
function xkbConvert(){

# Probing the keymap

  key="$(grep "^[[:space:]]*\/usr\/bin\/loadkeys" /etc/rc.d/rc.keymap \
    | sed -e 's/^.*loadkeys *\([^\.]*\)\(\.map\)*$/\1/')"



  # We convert keymap into XkbLayout  -- The fields are  keymap | XkbLayout | XkbOptions

  cat << "EOF" | grep "^$key|.*|.*" \
    | sed -e "s/^.*|\(.*\)|\(.*\)|\(.*\)/\1|\2|\3/" > $tmpDir/xkb
ANSI-dvorak|dvorak||
al|al||
am|am||
ar|ar||
azerty|fr||
az|az||
be-latin1|be||
bg-cp1251|bg||
bg-cp855|bg||
bg_bds-cp1251|bg||
bg_bds-utf8|bg||
bg_pho-cp1251|bg||
bg_pho-utf8|bg||
br-abnt2|br||
br-abnt|br||
br-latin1-abnt2|br||
br-latin1-us|br||
brdk|brdk||
by|by||
by|by||
cf|ca_enhanced||
croat|hr||
cz-cp1250|cz||
cz-lat2-prog|cz||
cz-lat2|cz||
cz-us-qwertz|cz_qwerty||
cz|cz||
de-latin1-nodeadkeys|de||
de-latin1|de||
de_CH-latin1|de_CH||
de|de||
dk-latin1|dk||
dk|dk||
dvorak-l|dvorak||
dvorak-r|dvorak||
dvorak|dvorak||
es-cp850|es||
es|es||
fi-latin1|fi-latin1||
fi-latin9|fi-latin9||
fi|fi||
fr-latin0|fr-latin0||
fr-latin1|fr-latin1||
fr-latin9|fr-latin9||
fr-pc|fr||
fr_CH-latin1|fr_CH||
fr_CH|fr_CH||
fr|fr||
gr-pc|us,el|grp:alt_shift_toggle|
gr|us,el|grp:alt_shift_toggle|
hu|hu||
il|us,il|grp:alt_shift_toggle|
il-heb|us,il-heb|grp:alt_shift_toggle|
il-phonetic|us,il-phonetic|grp:alt_shift_toggle|
is-latin1-us|us,is|grp:alt_shift_toggle|
is-latin1|is||
it-ibm|it||
it2|it||
it|it||
jp106|jp||
lt.baltic|lt_std||
lt.l4|lt_std||
lt|lt_std||
lt|lt||
lv|lv||
lv-latin7|lv||
mk-cp1251|mk||
mk-utf|mk||
mk0|mk||
mk|mk||
nl2|nl|
nl|nl||
nl|nl||
no-latin1|no||
no|no||
pl2|pl2||
pl|pl||
pt-latin1|pt||
pt-latin9|pt||
ro_win|ro_microsoft||
ru-cp1251|ru|grp:switch,grp:alt_shift_toggle,grp_led:scroll|
ru-ms|us,ru(winkeys)|grp:switch,grp:alt_shift_toggle,grp_led:scroll|
ru-yawerty|ru||
ru1|us,ru(winkeys)|grp:switch,grp:alt_shift_toggle,grp_led:scroll|
ru2|us,ru(winkeys)|grp:switch,grp:alt_shift_toggle,grp_led:scroll|
ru3|us,ru(winkeys)|grp:switch,grp:alt_shift_toggle,grp_led:scroll|
ru4|us,ru(winkeys)|grp:switch,grp:alt_shift_toggle,grp_led:scroll|
ru_win|us,ru(winkeys)|grp:switch,grp:alt_shift_toggle,grp_led:scroll|
ru|us,ru(winkeys)|grp:switch,grp:alt_shift_toggle,grp_led:scroll|
se-fi-ir209|se_FI||
se-fi-lat6|se_FI||
se-ir209|se_SE||
se-lat6|se_SE||
sg-latin1-lk450|sg||
sg-latin1|de_CH||
sg|de_CH||
sk-prog-qwerty|sk_qwerty||
sk-prog-qwertz|sk_qwerty||
sk-prog-qwertz|sk||
sk-qwerty|sk_qwerty||
sk-qwertz|sk_qwerty||
slovene|si||
sr-cy|sry||
sv-latin1|se||
syr|syr||
tel|tel||
th_pat|th_pat||
th_tis|th_tis||
th|th||
tj|tj||
tml|tml||
tr_f-latin5|tr_f||
tr_q-latin5|tr||
tralt|tr||
tralt|tr||
trq|tr||
ua-utf-ws|ua||
ua-utf|ua||
ua-ws|ua||
ua|ua||
ua|ua||
uk|gb||
us-acentos|us||
us|us||
uz|uz||
vn|vn||
wangbe2|fr||
wangbe|fr||
fr-dvorak-bepo|fr|grp:alt_shift_toggle|bepo
fr-dvorak-bepo-utf8|fr|grp:alt_shift_toggle|bepo
EOF

  xkbLayout="$(sed -e "s/^\(.*\)|.*|.*$/\1/" $tmpDir/xkb)"
  xkbOptions="terminate:ctrl_alt_bksp"
  specialXkbOptions="$(sed -e "s/^.*|\(.*\)|.*$/\1/" $tmpDir/xkb)"
  [ "${specialXkbOptions}" ] && xkbOptions="${xkbOptions},${specialXkbOptions}"
  xkbVariant="$(sed -e "s/^.*|.*|\(.*\)$/\1/" $tmpDir/xkb)"

  rm -f $tmpDir/xkb
  # Fall back to keymap if no xkb maping available
  if [ ! "$xkbLayout" ]; then
    xkbLayout="$key"
  fi

}

##################################################################
function updateFc(){
  # Update the X font indexes
  if [ -x /usr/bin/fc-cache ]; then
    for dir in /usr/share/fonts/* ; do touch $dir ; done
    /usr/bin/fc-cache 2>&1 1>/dev/null &
  fi
}


##################################################################
function updateMime(){
  # Update the X font indexes
  if [ -x /usr/bin/update-mime-database ]; then
    /usr/bin/update-mime-database /usr/share/mime 2>&1 1>/dev/null &
  fi
}

##################################################################
function updateScrollkeeper(){
  # Generate GNOME documentation
  if [ -x /usr/bin/scrollkeeper-update ]; then
    /usr/bin/scrollkeeper-update 2>&1 1>/dev/null &
  fi
}

##################################################################
function runSilent(){
  echo "Configuring the X server (silent mode)"
  (
  isVirtualBox="no"
  [ "$( lspci | grep -i "VirtualBox Graphic" )" ] && isVirtualBox="yes"
  compositor="Yes"
  xkbConvert
  writeConf
  updateFc
  updateMime
  sed -i "s/^id:.*:initdefault:$/id:4:initdefault:/" /etc/inittab
  ) 2>&1 1>/dev/null
}


     ########################################
########### HERE COMES THE SUN ####################
     ########################################

# Explicit "silent" argument always forces unattended mode.
# Otherwise, unattended mode kicks in automatically whenever we don't
# have a usable GUI (no X display, or yad isn't installed).
if [ "$1" = "silent" ] || [ "$useGui" = "no" ] ; then
  runSilent
  exit
fi


  # probe for videocard
  clear
  isVirtualBox="no"
  [ "$( lspci | grep -i "VirtualBox Graphic" )" ] && isVirtualBox="yes"
  showInfoBox "Please wait" "Configuring the X server..."
  xkbConvert


  # Compositor support ?

  compositor="$(showMenu \
    "Compositor" \
    "Do you want to enable the compositor (transparency, shadows, ... it can be slow on some videocards) ?" \
    "Yes" \
    "Yes" "Enable the compositor" \
    "No" "Disable the compositor")"

  writeConf
  updateFc
  updateMime

  # Runlevel 3 or 4 ? - preselect whatever /etc/inittab is currently set to.

  currentRunLevel="$(detectRunLevel)"

  runLevel="$(showMenu \
    "Login mode configuration" \
    "Select the login mode you want to enable on startup:" \
    "$currentRunLevel" \
    "Text" "Text mode login - runlevel 3" \
    "Graphical" "Graphical Xwindow login - runlevel 4" \
    "Skip" "No change")"

  case $runLevel in
    Text)
    sed -i "s/^id:.*:initdefault:$/id:3:initdefault:/" /etc/inittab
    ;;
    Graphical)
    sed -i "s/^id:.*:initdefault:$/id:4:initdefault:/" /etc/inittab
    ;;
    Skip|"")
      exit
    ;;
  esac
