#!/bin/sh

#  Copyright (C) 2014-2018, 2021-2022, 2024 D. R. Commander.
#                                           All Rights Reserved.
#  Copyright (C) 2005-2008 Sun Microsystems, Inc.  All Rights Reserved.
#  Copyright (C) 2002 Constantin Kaplinsky.  All Rights Reserved.
#
#  This 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.
#
#  This software is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this software; if not, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
#  USA.

# If a TurboVNC session running GNOME or MATE is started from a local GNOME or
# MATE session on the TurboVNC host, then the SESSION_MANAGER environment
# variable will be set.  We must unset that environment variable in order to
# prevent interference between the host's window manager instance and the
# TurboVNC session's window manager instance.
unset SESSION_MANAGER
# Similarly, if a TurboVNC session is started from a local Wayland session on
# the TurboVNC host, then the WAYLAND_DISPLAY environment variable will be set.
# We must unset that environment variable in order to prevent applications in
# the TurboVNC session from using Wayland instead of X11.
unset WAYLAND_DISPLAY
# By default, GTK applications (including the GNOME window manager) will
# attempt to display to a local Wayland session if one is active.  This forces
# those applications to display to the TurboVNC session.
GDK_BACKEND=x11;  export GDK_BACKEND
# If a TurboVNC session will run a (reasonably modern) window manager, then the
# session must have a D-Bus session bus instance.  On Red Hat/Fedora (and
# derivatives), SuSE/openSUSE, FreeBSD, and Solaris 11, xinitrc and Xsession
# automatically create a new session bus instance if the
# DBUS_SESSION_BUS_ADDRESS environment variable is empty, so we used to unset
# that variable at this point in the script.  However, on other operating
# systems (particularly Debian 10+ and Ubuntu 18.04+), it is necessary to
# explicitly create a new session bus instance by invoking dbus-launch.
#
# Using a separate D-Bus session bus instance for each TurboVNC session is
# necessary in order to run multiple TurboVNC sessions (or a local session and
# a TurboVNC session) simultaneously under the same user account, but this also
# causes issues with Control Group (cgroup) v2 on some systems.  If
# TVNC_USERDBUS is set to 1 in the environment (currently undocumented except
# here), then we forego creating a unique D-Bus session bus instance for the
# TurboVNC session and use the per-user D-Bus session bus instance provided by
# systemd instead.  That improves cgroup v2 compatibility at the expense of
# multi-session capability.
case "$DBUS_SESSION_BUS_ADDRESS" in
unix:path=/run/user/*)
  ;;
*)
  unset TVNC_USERDBUS
  ;;
esac
if [ "$TVNC_USERDBUS" != "1" ]; then
  DBUS_LAUNCH=
  if [ -x /usr/bin/dbus-launch ]; then
    DBUS_LAUNCH=/usr/bin/dbus-launch
  elif [ -x /usr/local/bin/dbus-launch ]; then
    DBUS_LAUNCH=/usr/local/bin/dbus-launch
  fi
  if [ "$DBUS_LAUNCH" != "" ]; then
    eval `$DBUS_LAUNCH --sh-syntax --exit-with-session`
    export DBUS_SESSION_BUS_ADDRESS
    echo "xstartup.turbovnc: Creating new session bus instance:"
    echo "xstartup.turbovnc:   $DBUS_SESSION_BUS_ADDRESS"
  else
    # If we get here, then dbus-launch was not found, DBUS_SESSION_BUS_ADDRESS
    # is unlikely to be set, and xinitrc or Xsession would subsequently fail on
    # the aforementioned operating systems.  Thus, unsetting
    # DBUS_SESSION_BUS_ADDRESS here is just a belt-and-suspenders measure to
    # help ensure that any window manager that requires D-Bus will fail sooner
    # rather than later.
    unset DBUS_SESSION_BUS_ADDRESS
  fi
  unset DBUS_LAUNCH
fi
# Specify that the window manager should use X11 rather than Wayland.
XDG_SESSION_TYPE=x11;  export XDG_SESSION_TYPE

OS=`uname -s`

# Emulate GDM

find_session()
{
  for SESSION in $SESSIONS; do
    if [ "$XSESSIONSDIR" != "" -a -f $XSESSIONSDIR/$SESSION.desktop ]; then
      DESKTOP_SESSION=$SESSION;  export DESKTOP_SESSION
    fi
  done
  if [ "$DESKTOP_SESSION" = "" ]; then
    if [ "$TVNC_WM" = "" ]; then
      echo "xstartup.turbovnc: The session desktop file for the default window manager was"
      echo "xstartup.turbovnc:   not found at:"
    else
      echo "xstartup.turbovnc: The session desktop file for the '$TVNC_WM'"
      echo "xstartup.turbovnc:   window manager was not found at:"
    fi
    for SESSION in $SESSIONS; do
      echo "xstartup.turbovnc:   $XSESSIONSDIR/$SESSION.desktop"
    done
    if [ "$TVNC_WM" != "" ]; then
      exit 1
    fi
  fi
  unset SESSIONS
}

# Use Unity 2D on Ubuntu 12 if no WM is specified.  Historically, Unity 3D
# 5.20.x didn't even pretend to work properly with our X server, although it
# probably would now.
if [ -f /usr/share/gnome-session/sessions/ubuntu-2d.session -a -z "$TVNC_WM" ]; then
  TVNC_WM=2d
fi
XSESSIONSDIR=
if [ -d /usr/share/xsessions ]; then
  XSESSIONSDIR=/usr/share/xsessions
elif [ -d /usr/local/share/xsessions ]; then
  XSESSIONSDIR=/usr/local/share/xsessions
fi
GREP=grep
if [ -x /usr/bin/ggrep ]; then
  GREP=ggrep
fi
SED=sed
if [ -x /usr/bin/gsed ]; then
  SED=gsed
fi
NOXSESSION=0
case "$TVNC_WM" in
  # Appending :noxsession to the window manager name causes the window manager
  # to be launched directly rather than through the Xsession script.  No window
  # managers are known to require this, but the feature is retained for
  # testing/debugging purposes.
  2d | 2d:noxsession)
    if [ "$TVNC_WM" = "2d:noxsession" ]; then
      NOXSESSION=1
      TVNC_WM=`echo $TVNC_WM | $SED -r 's/:noxsession$//g'`
    fi
    # RHEL 7+, Fedora: gnome-classic
    # Ubuntu 12: ubuntu-2d
    # Ubuntu 14: gnome-fallback
    # Ubuntu 16+: gnome-flashback-metacity
    SESSIONS="gnome-classic gnome-fallback ubuntu-2d 2d-gnome gnome-flashback-metacity"
    find_session
    unset TVNC_WM
    ;;
  *)
    case "$TVNC_WM" in
      *:noxsession)
        NOXSESSION=1
        TVNC_WM=`echo $TVNC_WM | $SED -r 's/:noxsession$//g'`
        ;;
      *)
        ;;
    esac
    if [ "$TVNC_WM" = "" ]; then
      # No window manager was specified.  Use GNOME or Unity if it exists.
      SESSIONS="gnome ubuntu"
      find_session
    else
      # For backward compatibility with TurboVNC 2.2.x, we allow a window
      # manager's startup script (e.g. mate-session, gnome-session) to be
      # specified using -wm / $wm, but if there is a matching session desktop
      # file for it, we use that instead.
      SESSIONS="`echo $TVNC_WM | $SED -r 's/^.*\/|-session$//g'`"
      find_session
      unset TVNC_WM
    fi
    ;;
esac
XSESSION=
if [ "$DESKTOP_SESSION" != "" ]; then
  # A window manager was specified, or the default window manager will be used,
  # and the corresponding session desktop file exists.  Set the appropriate
  # environment variables.
  GDMSESSION=$DESKTOP_SESSION;  export GDMSESSION
  XDG_SESSION_DESKTOP=$DESKTOP_SESSION;  export XDG_SESSION_DESKTOP
  echo "xstartup.turbovnc: Using '$DESKTOP_SESSION' window manager in"
  echo "xstartup.turbovnc:   $XSESSIONSDIR/$DESKTOP_SESSION.desktop"
  # Parse the session desktop file to determine the window manager's startup
  # command, and set the TVNC_WM environment variable accordingly.
  if $GREP -qE "^Exec\s*=" $XSESSIONSDIR/$DESKTOP_SESSION.desktop; then
    TVNC_WM=`$GREP -E "^Exec\s*=" $XSESSIONSDIR/$DESKTOP_SESSION.desktop | $SED -r 's/^[^=]+=[[:space:]]*//g'`
    if [ "$NOXSESSION" != "1" ]; then
      if [ -x /etc/X11/xinit/Xsession ]; then
        XSESSION=/etc/X11/xinit/Xsession
      elif [ -x /etc/X11/Xsession ]; then
        XSESSION=/etc/X11/Xsession
      fi
    fi
  fi
  # Parse the session desktop file to determine the window manager's desktop
  # name.
  for KEY in DesktopNames X-LightDM-DesktopName; do
    if $GREP -qE "^$KEY\s*=" $XSESSIONSDIR/$DESKTOP_SESSION.desktop; then
      XDG_CURRENT_DESKTOP=`$GREP -E "^$KEY\s*=" $XSESSIONSDIR/$DESKTOP_SESSION.desktop | $SED -r 's/(^[^=]+=[[:space:]]*|;$)//g' | $SED -r 's/;/:/g'`
      export XDG_CURRENT_DESKTOP
    fi
  done
fi

if [ "$TVNC_VGL" = "1" ]; then
  # If launching the window manager using VirtualGL, invoke vglrun through
  # ssh-agent.  On some operating systems, xinitrc and Xsession launch the
  # window manager using ssh-agent if there is no active ssh-agent session, and
  # ssh-agent clobbers LD_PRELOAD.  Thus, we explicitly create an ssh-agent
  # session for VirtualGL.
  if [ -z "$SSH_AGENT_PID" -a -x /usr/bin/ssh-agent ]; then
    TVNC_SSHAGENT=/usr/bin/ssh-agent
  fi
  if [ -z "$TVNC_VGLRUN" ]; then
    TVNC_VGLRUN="vglrun +wm"
  fi
fi

if [ "$TVNC_WM" = "" ]; then
  # No window manager was specified, and the default window manager is
  # unavailable.  Try to launch the window manager via the system-wide WM
  # startup script.  (This is mostly for the benefit of legacy operating
  # systems.  Modern operating systems typically do not use xinitrc.)

  # Typical system-wide WM startup script on Linux and Solaris 11
  if [ -f /etc/X11/xinit/xinitrc ]; then
    TVNC_WM=/etc/X11/xinit/xinitrc
  fi
fi
if [ "$TVNC_WM" != "" ]; then
  # Start the window manager.
  if [ "$XSESSION" != "" ]; then
    echo xstartup.turbovnc: Executing $TVNC_SSHAGENT $TVNC_VGLRUN $XSESSION \"$TVNC_WM\"
    exec $TVNC_SSHAGENT $TVNC_VGLRUN $XSESSION "$TVNC_WM"
  else
    echo xstartup.turbovnc: Executing $TVNC_SSHAGENT $TVNC_VGLRUN $TVNC_WM
    exec $TVNC_SSHAGENT $TVNC_VGLRUN $TVNC_WM
  fi
else
  # No window manager was specified, the default window manager is unavailable,
  # and no known system-wide WM startup script was found.  Start TWM if it
  # exists.
  echo "xstartup.turbovnc: No window manager specified or found.  Falling back to TWM."
  which twm >/dev/null && {
    if [ -f $HOME/.Xresources ]; then xrdb $HOME/.Xresources; fi
    xsetroot -solid grey
    xterm -geometry 80x24+10+10 -ls -title "$VNCDESKTOP Desktop" &
    twm
  } || {
    echo "xstartup.turbovnc: TWM not found.  I give up."
    exit 1
  }
fi
