#!/bin/sh

#  Copyright (C) 2014-2018, 2021-2022, 2024-2025 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, and FreeBSD, 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.
#
# If TVNC_USERDBUS is set to 1 in the environment (which will be the case if
# $userDBus = 1 in turbovncserver.conf or -userdbus is passed to vncserver),
# 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 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
      break
    # On Fedora 40+, gnome-classic.desktop lives in
    # /usr/share/wayland-sessions.  On RHEL 10+, gnome.desktop lives there too.
    # More generally, there is nothing Wayland-specific about the session
    # desktop files in /usr/share/wayland-sessions, so we can safely use them
    # as well.
    elif [ "$XSESSIONSDIR" = "/usr/share/xsessions" -a \
           -f /usr/share/wayland-sessions/$SESSION.desktop ]; then
      DESKTOP_SESSION=$SESSION;  export DESKTOP_SESSION
      XSESSIONSDIR=/usr/share/wayland-sessions
      break
    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"
      if [ "$XSESSIONSDIR" = "/usr/share/xsessions" -a \
           -d /usr/share/wayland-sessions ]; then
        echo "xstartup.turbovnc:   /usr/share/wayland-sessions/$SESSION.desktop"
      fi
    done
    exit 1
  fi
  unset SESSIONS
}

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, Unity, MATE, or Xfce (in
      # that order) if a corresponding session desktop file exists.
      SESSIONS="gnome ubuntu mate xfce"
      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, Xsession launches 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
  echo "xstartup.turbovnc: No window manager was specified, and the default window"
  echo "xstartup.turbovnc:   manager is unavailable."
  exit 1
fi

# 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
