#!/usr/bin/env perl

# setupxorg - Sets up XOrg video drivers
# License:  Creative Commons Attribution-NonCommercial-ShareAlike 3.0
# Revision: 170704

# Note:  The license indicated above applies to this file.  It doesn't
# apply to the official XOrg package, or to any file derived from that
# package.

#---------------------------------------------------------------------
#                         license information
#---------------------------------------------------------------------

# This section may not be modified except as approved by the author or
# licensor, or to make non-content changes such as adjustments to par-
# agraph formatting or white space.

# This  version of this software is  distributed  under  the following
# license:
#
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0

# You may use, modify, and redistribute this software without fees  or
# royalties, but only under the terms and conditions set forth  by the
# license.  In particular, copies and derived works cannot be used for
# commercial purposes.  Additionally, the license propagates to copies
# and derived works. Furthermore, you must provide attribution "in the
# manner  specified  by the  author or licensor".  The latter point is
# discussed below.

# The author (and licensor) hereby specifies that  attribution must be
# handled in the following manner:  a. If the software is interactive,
# any  About or Credits dialog boxes, windows, or output text provided
# by the  original version must be preserved and readily accessible to
# the end user at runtime.  b. If the software is non-interactive,  or
# if it does not  provide  About or Credits dialog boxes, windows,  or
# output text,  the  operating system and/or  desktop environment used
# must provide attribution that is  visible and/or  readily accessible
# to the end user at runtime.

# The following techniques  do not meet the  attribution requirements:
# Attribution through text  files, attribution  through  printed docu-
# mentation,  verbal  attribution, or postings on  external web sites;
# i.e.,  web  sites  that are  not an intrinsic local component of the
# operating system or  desktop environment used.  These  examples  are
# provided for illustrative purposes only.

# It should be noted that trademarks are an additional issue.  If this
# software  uses any  trademarks,  trademark-related  restrictions may
# apply.

# This is not a  complete explanation of the  terms and conditions in-
# volved.  For more information, see the Creative Commons Attribution-
# NonCommercial-ShareAlike 3.0 license.

#---------------------------------------------------------------------
#                              overview
#---------------------------------------------------------------------

# 1. "setupxorg" is a boot-time setup script that configures  XOrg ap-
# propriately. In particular, "setupxorg" handles the following opera-
# tions:
#
#     a. Create directory  "/tmp/.ICE-unix" and set its attributes ap-
#        propriately
#
#     b. Modify XOrg configuration file appropriately

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

# 2. "setupxorg"  relies on a  distro-specific  utility program  named
# "pci2xorg". "pci2xorg" takes a PCI vendor:model ID pair as input and
# prints an  XOrg driver name  as output.  For  more information,  see
# "pci2xorg's" source code.

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

# 3. If  various conditions are met,  accelerated graphics (i.e., DRI)
# may be enabled automatically. Requirements include:
#
#     a. Linux 2.6 or above
#     b. PCI graphics card (or later technology)
#     c. "pci2xorg" must recognize the graphics card
#     d. XOrg must support DRI for the card in question
#     e. XOrg, Mesa, libdrm, etc. must be compiled correctly
#     f. User isn't running a MiniCD distro
#     g. User isn't running inside a virtual machine (QEMU, etc.)

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

# 4. If "pci2xorg" doesn't  recognize  the  current  system's graphics
# card  (or if XOrg doesn't support the  card  directly),  this script
# sets up an alternate XOrg driver (which may be based on frame-buffer
# and/or VESA interfaces).

# The alternate driver should work, in most cases;  however, it gener-
# ally won't support accelerated graphics (i.e., DRI).

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

# 5. If you use GRUB or a  similar tool to boot Linux,  you can select
# various alternate modes  of operation at boot time.  To do so,  edit
# the appropriate system-boot configuration file, add some of the fol-
# lowing strings to one or more kernel command lines,  and modify  the
# associated menu entries accordingly:
#
#     setupxorg=default     # Select the best available driver for the
#                           # system's graphics chipset. Try to enable
#                           # accelerated graphics  (including DRI and
#                           # GLX) where possible.
#
#                           # This mode  should work with  most modern
#                           # systems, but there will be exceptions.
#
#     setupxorg=normal      # Same as "setupxorg=default"
#     setupxorg=standard    # Ditto
#
#     setupxorg=fbdev       # Try  "fbdev" mode  if the  standard mode
#                           # fails. "fbdev" mode uses a native frame-
#                           # buffer driver, if one exists.
#
#                           # "fbdev" mode  works for some modern sys-
#                           # tems but not others.  When it works, ev-
#                           # erything should run except programs that
#                           # need accelerated graphics.
#
#     setupxorg=nativefb    # Same as "setupxorg=fbdev"
#
#     setupxorg=uvesafb     # If  the other modes fail,  try "uvesafb"
#                           # mode. This one uses a framebuffer driver
#                           # that's based on the VESA standard.
#
#                           # "uvesafb" mode should  work to  some ex-
#                           # tent with almost all systems built after
#                           # the year 2000, but some programs may run
#                           # incorrectly with this driver  (games and
#                           # multimedia players, in particular).
#
#     setupxorg=vesa        # This mode (vesa) selects an old-fashion-
#                           # ed VESA driver.  It'll  work  with  some
#                           # systems (both old and new), but not oth-
#                           # ers.  When it works,  everything  should
#                           # run except programs that need accelerat-
#                           # ed graphics.

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

# 6. Alternatively, you can tell this  program which mode of operation
# to use by writing one  of the following strings to a text file named
# "/etc/sysconfig/xorgboot" before this program is executed:
#
#     default
#     fbdev
#     uvesafb
#     vesa

# If you  specify  a mode both  with  GRUB and with the  text-file ap-
# proach, the GRUB-level setting presently takes precedence.

#---------------------------------------------------------------------
#                            module setup
#---------------------------------------------------------------------

require 5.8.1;
use strict;
use Carp;
use warnings;
                                # Trap warnings
$SIG {__WARN__} = sub { die @_; };

#---------------------------------------------------------------------
#                           basic constants
#---------------------------------------------------------------------

use constant ZERO  => 0;        # Zero
use constant ONE   => 1;        # One

use constant FALSE => 0;        # Boolean FALSE
use constant TRUE  => 1;        # Boolean TRUE

#---------------------------------------------------------------------
#                         program parameters
#---------------------------------------------------------------------

my $ICEDIR    = '/tmp/.ICE-unix'     ;
my $XORG_CONF = '/etc/X11/xorg.conf' ;

my $LACARCH  = $ENV {'LACARCH'};
   $LACARCH  =  "" unless defined $LACARCH;
   $LACARCH  =~ s@\s+\z@@s;
die unless length $LACARCH;

my $PRODTREE = "/$LACARCH/pkg";

#---------------------------------------------------------------------
#                   starting point for "xorg.conf"
#---------------------------------------------------------------------

my $XORG_CONF_BASE = << "END";
Section "ServerLayout"
    Identifier     "X.org Configured"
#   Screen          0 "Screen0" 0 0
#   InputDevice    "Mouse0"    "CorePointer"
#   InputDevice    "Mouse1"    "AlwaysCore"
#   InputDevice    "Synaptics" "AlwaysCore"
#   InputDevice    "Keyboard0" "CoreKeyboard"

# This block is an attempt to stop hangs.  The "0"  settings  can  be
# overridden by ".xinitrc" using  "xset".  Note: This block is dupli-
# cated elsewhere in this file; this is intentional.

    Option "BlankTime"   "0"
    Option "StandbyTime" "0"
    Option "SuspendTime" "0"
    Option "OffTime"     "0"
EndSection

# The "DontZap" and "HandleSpecialKeys" options specified here are in-
# tended  to enable Control-Alt-Backspace,  but this doesn't presently
# work.

Section "ServerFlags"
    Option "DontZap" "Off"
    Option "HandleSpecialKeys" "Always"

# This block is an attempt to stop hangs.  The "0"  settings  can  be
# overridden by ".xinitrc" using  "xset".  Note: This block is dupli-
# cated elsewhere in this file; this is intentional.

    Option "BlankTime"   "0"
    Option "StandbyTime" "0"
    Option "SuspendTime" "0"
    Option "OffTime"     "0"
    Option "AutoAddDevices" "True"
EndSection

Section "Files"
    FontPath     "/usr/share/fonts/ttf/bakoma/"
    FontPath     "/usr/share/fonts/ttf/bitvera/"
    FontPath     "/usr/share/fonts/ttf/dejavu/"
    FontPath     "/usr/share/fonts/ttf/freefont/"
    FontPath     "/usr/share/fonts/ttf/gentium/"
    FontPath     "/usr/share/fonts/ttf/googlefonts/"
    FontPath     "/usr/share/fonts/ttf/liberation/"
    FontPath     "/usr/share/fonts/ttf/misc/"
    FontPath     "/usr/share/fonts/ttf/replacems/"
    FontPath     "/usr/share/fonts/ttf/texgyre/"
EndSection

Section "Module"
    Load        "record"
    Load        "extmod"
    Load        "dbe"
    Load        "glx"
    Load        "dri"
    Load        "freetype"
    Load        "libinput"
    Load        "type1"
#   Load        "synaptics"
EndSection

#Section "InputDevice"
#   Identifier  "Keyboard0"
#   Driver      "kbd"
#   Option      "XkbModel" "pc101"
#   Option      "XkbLayout" "us"
#EndSection

# Section "InputDevice"
#   Identifier  "Mouse0"
#   Driver      "mouse"
#   Option      "Protocol" "IMPS/2"
#   Option      "Device" "/dev/input/mouse1"
#   Option      "ChordMiddle"
#EndSection

#Section "InputDevice"
#   Identifier  "Mouse1"
#   Driver      "mouse"
#   Option      "Device" "/dev/input/mice"
#   Option      "Protocol" "IMPS/2"
#   Option      "Emulate3Buttons" "off"
#   Option      "ZAxisMapping" "4 5"
#EndSection

#Section        "InputDevice"
#   Identifier  "Synaptics"
#   Driver      "synaptics"
#   Option      "Protocol" "auto"
#   Option      "Device" "/dev/psaux"
#   Option      "Emulate3Buttons" "no"
#   Option      "ZAxisMapping" "4 5"
#   Option      "TapButton1" "1"
#   Option      "SpecialScrollAreaRight" "true"
#   Option      "VertEdgeScroll"         "true"
#   Option      "VertTwoFingerScroll"    "true"
#EndSection
                        
Section "Monitor"
    Identifier   "Monitor0"
#   VendorName   "Monitor"
#   ModelName    "Monitor"
#   HorizSync    35-59
#   VertRefresh  55.0-74.0
    Option       "DPMS"
EndSection

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

Section "InputClass"
        Identifier "libinput pointer catchall"
        MatchIsPointer "on"
        MatchDevicePath "/dev/input/event*"
        Driver "libinput"
EndSection

Section "InputClass"
        Identifier "libinput keyboard catchall"
        MatchIsKeyboard "on"
        MatchDevicePath "/dev/input/event*"
        Driver "libinput"
EndSection

Section "InputClass"
        Identifier "libinput touchpad catchall"
        MatchIsTouchpad "on"
        MatchDevicePath "/dev/input/event*"
        Driver "libinput"
EndSection

Section "InputClass"
        Identifier "libinput touchscreen catchall"
        MatchIsTouchscreen "on"
        MatchDevicePath "/dev/input/event*"
        Driver "libinput"
EndSection

Section "InputClass"
        Identifier "libinput tablet catchall"
        MatchIsTablet "on"
        MatchDevicePath "/dev/input/event*"
        Driver "libinput"
EndSection

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

# Seems to cause crashes now:
# Section "Extensions"
#     Option      "Composite" "Disable"
# EndSection

Section "DRI"
    Mode        0666
EndSection
END

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

my $SCREEN_NATIVEFB = << 'END';
Section "Screen"
    Identifier "Screen0"
#   Device     "Card0"
#   Monitor    "Monitor0"
    DefaultDepth     16
    SubSection "Display"
        Viewport  0 0
        Modes     "1680x1050" "1280x1024" "1280x768" "1024x768" "800x600"
        Depth     16
    EndSubSection
EndSection
END

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

# "load-uvesafb" is a  magic comment that's  used to tell  "kms-start"
# that we're running in "uvesafb" mode.

my $SCREEN_UVESAFB = << 'END';
# Don't remove this comment: load-uvesafb
Section "Screen"
    Identifier "Screen0"
#   Device     "Card0"
#   Monitor    "Monitor0"
    DefaultDepth __DEPTH__
    SubSection "Display"
        Viewport 0 0
        Modes "__WIDTH__x__HEIGHT__"
        Depth __DEPTH__
    EndSubSection
EndSection
END

#---------------------------------------------------------------------
#                          support routines
#---------------------------------------------------------------------

# Future change: Document this routine.

sub UpdateConf
{
    my $lspci_data;
    my $xorg_data;
    my $xorg_driver = "";
    my $n;                      # Scratch (integer)
    my $str;                    # Scratch (string )

#---------------------------------------------------------------------
# Initial setup.

    my $WS = '[\011\040]';      # Matches a tab or space
    undef $/;                   # Set "read entire file" mode

#---------------------------------------------------------------------
# Check "boot command".

# "setupxorg" supports boot-time kernel-level arguments of the follow-
# ing form:
#
#     setupxorg=word

# If an argument of this type is specified  at boot time,  $BootCmd is
# set to the specified value.  For information about supported  "word"
# values, see the notes near the start of this file.

# To override boot-time  kernel-level arguments,  execute this program
# using any of the following four approaches:
#
#     xorgboot=word setupxorg
#     XORGBOOT=word setupxorg
#     export xorgboot=word ; setupxorg
#     export XORGBOOT=word ; setupxorg

# These four approaches support the same "word" values as "setupxorg="
# does.

# If none of these approaches used,  $BootCmd  defaults  to the string
# 'default'.

    my $BootCmd = 'default';

    if (open (IFD, "</etc/sysconfig/xorgboot"))
    {
        $str =  <IFD>;
        close (IFD);

        $str     =  "" unless defined $str;
        $str     =~ s@^\s+@@s;
        $str     =~ s@\s+\z@@s;
        $str     =  lc ($str);
        $BootCmd =  $str if $str =~
            m@^(fbdev|uvesafb|vesa)\z@;
    }

    $str =  $ENV {'xorgboot'};
    $str =  $ENV {'XORGBOOT'} unless defined $str;
    $str =  "" unless defined $str;
    $str =~ s@\b(fbdev)\b@nativefb@gi;
    $str =~ s@\b(default|normal|standard)\b@normal@i;

    if ($str =~ m@\b(normal|nativefb|uvesafb|vesa)\b@i)
    {
        $BootCmd = $1;
    }
    else
    {
        $str =  `/bin/cat /proc/cmdline 2>&1`;
        $str =  "" unless defined $str;
        $str =~ s@\s+@ @gs;
        $str =~ s@^\s*@ @s;
        $str =~ s@\s*\z@ @s;
        $BootCmd = $1 if $str =~ m@ xorgboot=(\S+)@;
    }
                                # Translate aliases and map mode names
                                # to lower case
    $BootCmd =~ s@\b(fbdev)\b@nativefb@gi;
    $BootCmd =~ s@\b(default|normal|standard)\b@normal@i;
    $BootCmd =  lc ($BootCmd);

#---------------------------------------------------------------------
# Additional setup.

    my $IsNativeFB = FALSE;
    my $IsUVESAFB  = FALSE;

    $xorg_driver = $1 if $BootCmd =~ m@\b(vesa)\b@;
    $xorg_driver = 'fbdev'
        if $BootCmd =~ m@\b(nativefb|uvesafb)\b@;
    $IsNativeFB = TRUE if $BootCmd =~ m@\b(nativefb)\b@;
    $IsUVESAFB  = TRUE if $BootCmd =~ m@\b(uvesafb)\b@;

    if (TRUE)
    {
        my $driver;
        my $hex4d = '[A-Fa-z0-9]{4}';

        $lspci_data = `lspci -n 2>&1`;
        $lspci_data = "" unless defined $lspci_data;

        if ($lspci_data =~ m@\b0300: +($hex4d:$hex4d)\b@i)
        {
            my $pci_id = uc ($1);
            $driver = `/laclin/lacutil/pci2xorg $pci_id 2>&1`;
        }

        $driver =  "" unless defined $driver;
        $driver =~ s@^\s+@@s;
        $driver =~ s@\s+\z@@s;

# The following block is a workaround for a "uvesafb" problem.  It re-
# places the  "uvesafb" approach with the native framebuffer  approach
# for NVidia chipsets.

        if ($IsUVESAFB && ($driver eq 'nouveau'))
        {
            $IsNativeFB  = TRUE;
            $IsUVESAFB   = FALSE;
            $driver      = "";
            $xorg_driver = 'fbdev';
        }

        my $SmallCheck  =  << 'END';
$PRODTREE/xorg/lib/xorg/modules/drivers/nouveau_drv.so
END
           $SmallCheck  =~ s@\s+\z@@s;

        my $SmallSystem = FALSE;
           $SmallSystem = TRUE unless -f $SmallCheck;
           $SmallSystem = TRUE if -f '/etc/sysconfig/ISMINICD';

        if ($SmallSystem && ($driver =~ m@^(nouveau|radeon)\z@))
        {
            $driver = "";
        }

        if (($driver =~ m@^\S+\z@) &&
            ($driver !~ m@(error|^none\z)@i))
        {
            $xorg_driver = $driver unless length $xorg_driver;
        }
    }

    if ((!-f "$PRODTREE/xorg/lib/libGL.so") &&
        ($xorg_driver !~ m@^(fbdev|vesa|modesetting)\z@))
    {
         $xorg_driver = "";
    }

# If a driver hasn't been selected, this code falls back to the native
# framebuffer approach.  In the past,  regular  "vesa"  (as opposed to
# "uvesafb") was the safest fallback; however, as of late 2011, regul-
# ar "vesa"  crashed for some versions of XOrg and some chipsets.  The
# native framebuffer approach won't  work for  some systems,  but it's
# probably the best way to go.

    if (!length ($xorg_driver))
    {
        $xorg_driver = 'fbdev' ;
        $IsNativeFB  = TRUE    ;
        $IsUVESAFB   = FALSE   ;
    }

#---------------------------------------------------------------------
# Prepare initial "xorg.conf" text.

    $xorg_data = $XORG_CONF_BASE;

    if ($IsNativeFB)
    {
        $xorg_data =~
s@\s*# Screen-Start.*# Screen-End\s*@\n\n$SCREEN_NATIVEFB@gis;
    }
    elsif ($IsUVESAFB)
    {
        $xorg_data =~
s@\s*# Screen-Start.*# Screen-End\s*@\n\n$SCREEN_UVESAFB@gis;
    }
    else
    {
        $xorg_data =~ s@\s*# Screen-Start\s*@\n\n@gis;
        $xorg_data =~ s@\s*# Screen-End\s*@\n@gis;
    }

    if ($xorg_driver =~ m@^(fbdev|vesa)\z@)
    {
    }
    elsif ($xorg_driver =~ m@^(intel|nouveau|radeon)\z@)
    {
        my $hw = 'false';
           $hw = 'true' if $xorg_driver eq 'nouveau';

        $xorg_data .= "\n";
        $xorg_data .= << "END"; # "END" must be double-quoted here
Section "Device"
    Identifier  "Card0"
    Driver "$xorg_driver"
    Option "HWCursor" "$hw"
    Option "AccelMethod" "sna"
EndSection
END
    }
    elsif ($xorg_driver =~ m@^(modesetting)\z@)
    {
        $xorg_data .= "\n";
        $xorg_data .= << "END"; # "END" must be double-quoted here
Section "Device"
    Identifier  "Card0"
    Driver "$xorg_driver"
EndSection
END
    }

    if ($xorg_driver =~ m@^(fbdev|vesa)\z@)
    {
        $xorg_data =~ s@(\n${WS}*)Load\s+"(dri|glx)"@${1}#Load "$2"@g;
    }

#---------------------------------------------------------------------
# Additional "uvesafb" setup.

# The basic idea behind this code is  to proceed  as follows  if we're
# running in "uvesafb" mode:
#
#     (a) Unload the "uvesafb" driver if it's loaded (safety measure)
#     (b) Reload the "uvesafb" driver
#     (c) Ask the reloaded driver for supported mode settings
#     (d) Unload the "uvesafb" driver again
#     (e) Choose an appropriate mode setting
#     (f) Update a   "uvesafb" configuration file to set the mode
#     (g) Update an  XOrg      configuration file to set the mode

    my $MODPROBE_DIR = '/etc/modprobe.d';
    my $UVESAFB_CONF = "$MODPROBE_DIR/uvesafb.conf";

    if ($IsUVESAFB)
    {
        my $VBE_MODES    =
            '/sys/bus/platform/drivers/uvesafb/uvesafb.0/vbe_modes';

        system "mkdir -p $MODPROBE_DIR";
        open (OFD, ">$UVESAFB_CONF") ||
            die "Error: Can't create file: $!: $UVESAFB_CONF\n";
        print OFD << "END";
options uvesafb mode_option=1024x768-16 mtrr=3 scroll=ywrap
END
        close (OFD) ||
            die "Error: Can't create file: $!: $UVESAFB_CONF\n";

        $str = `rmmod uvesafb 2>&1`;
        $str = "" unless defined $str;

        if ($str =~ m@ in use @)
        {
die "Error: uvesafb is already in use, reboot the system\n";
        }

        $str =  `modprobe uvesafb 2>&1`;
        $str =  "" unless defined $str;
        $str =~ s@\s+\z@@s;

        if (length ($str))
        {
die "Error: Can't modprobe uvesafb, check config or reboot\n";
        }

        if (!open (IFD, "<$VBE_MODES"))
        {
die "Error: uvesafb setup failed, missing:\n$VBE_MODES\n";
        }

        my $ssmodes = $/;
        undef $/;
        my $modedata = <IFD>;
           $modedata = "" unless defined $modedata;
        $/ = $ssmodes;
        close IFD;

        $str =  `rmmod uvesafb 2>&1`;
        $str =  "" unless defined $str;
        $str =~ s@\s+\z@@s;

        if (length ($str))
        {
die "Error: Can't rmmod uvesafb, reboot the system\n";
        }

        my @modes = ();

        for my $line (split (/\n+/, $modedata))
        {
            next unless $line =~ m@^(\d+)x(\d+)-(\d+),@;
            my $mode = sprintf ('%04d %04d %03d', $1, $2, $3);
            push (@modes, $mode);
        }

        @modes = reverse sort @modes;
        my $NumModes = scalar (@modes);
        my ($width, $height, $bits);

        die "Internal error: modes array-1\n"
            unless $NumModes > ZERO;

        for my $ii (ZERO..$#modes)
        {
            my ($w, $h, $b) = $modes [$ii] =~
                m@^(\d+) (\d+) (\d+)\b@;
            die "Internal error: modes array-2\n"
                unless defined $b;
            $w =~ s@^0+@@; $h =~ s@^0+@@; $b =~ s@^0+@@;
            last if ($w < 1280) && defined ($width);
            $width = $w; $height = $h; $bits = $b;
            last if $w == 1280;
        }

        die "Internal error: modes array-3\n"
            unless defined $width;

        open (OFD, ">$UVESAFB_CONF") ||
            die "Error: Can't create file: $!: $UVESAFB_CONF\n";
        print OFD << "END";
options uvesafb mode_option=${width}x$height-$bits mtrr=3 scroll=ywrap
END
        close (OFD) ||
            die "Error: Can't create file: $!: $UVESAFB_CONF\n";

                                # Work-around for an XOrg problem
        $bits = 24 if $bits == 32;

        $xorg_data =~ s@__WIDTH__@$width@g;
        $xorg_data =~ s@__HEIGHT__@$height@g;
        $xorg_data =~ s@__DEPTH__@$bits@g;
    }
    else
    {
        unlink $UVESAFB_CONF;
    }

#---------------------------------------------------------------------
# Get old contents of "xorg.conf";

    my $old_data = "";

    if (open (IFD, "<$XORG_CONF"))
    {
        undef $/;
        $old_data = <IFD>;
        $old_data = "" unless defined $old_data;
        close IFD;
    }

#---------------------------------------------------------------------
# Create (or update) "xorg.conf".

    if ($xorg_data ne $old_data)
    {
        open (OFD, ">$XORG_CONF") ||
            die "Error: Can't write file: $!\n$XORG_CONF\n";
        print OFD $xorg_data;
        close (OFD) ||
            die "Error: Can't write file: $!\n$XORG_CONF\n";
        print "setupxorg: Created new $XORG_CONF\n";
    }

    undef;
}

#---------------------------------------------------------------------
#                            main routine
#---------------------------------------------------------------------

sub Main
{
    my $str;                    # Scratch

    select STDERR; $| = ONE;
    select STDOUT; $| = ONE;
                                # Safety measure
    $str =  $ENV {DISPLAY};
    $str =  "" unless defined $str;
    $str =~ s@\s+\z@@s;

    if (FALSE && length ($str))
    {
        $str = `/bin/ps ax 2>&1`;
        $str = "" unless defined $str;

        if ($str =~ m@ /usr/X11R6/bin/@)
        {
            print STDERR << 'END';
Error: It's not safe to run "setupxorg" under XOrg.
END
            exit ONE;
        }
    }

    system "mkdir -p   $ICEDIR";
    system "chown 0.0  $ICEDIR";
    system "chmod 1777 $ICEDIR";

    my $xkb_compiled = '/usr/X11R6/share/X11/xkb/compiled';
    my $x            = $xkb_compiled;
    unlink $x if !-d $x;
    system "mkdir -p $x";

    my $file1 = '/usr/X11R6/share/X11/rgb.txt';
    my $file2 = '/usr/X11R6/lib/X11/rgb.txt';

    if ((-f $file1) && (!-f $file2))
    {
        unlink $file2;

        if ((!-e $file2) && (!-l $file2))
        {
            symlink ($file1, $file2);
        }
    }

    &UpdateConf();
    undef;
}

#---------------------------------------------------------------------
#                            main program
#---------------------------------------------------------------------

&Main();                        # Call the main routine
exit ZERO;                      # Normal exit
