#!/usr/bin/perl -w

#Copyright (C) 1999-2001 by  Sbastien Chaumat <schaumat@ens-lyon.fr>
#                        and Loc Prylli <lprylli@lhpca.univ-lyon1.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.

#    This program 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.

#    A copy of the GNU General Public License is available as
#    `/usr/share/common-licences/GPL' in the Debian GNU/Linux distribution
#    or on the World Wide Web at http://www.gnu.org/copyleft/gpl.html.  You
#    can also obtain it by writing to the Free Software Foundation, Inc.,
#    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

require("/usr/share/replicator/repli-common");
$pci_lst='$sharedir/pci.lst';

use FileHandle;



sub error {
  die "ERROR:@_\n";
}

@monitorlist = (
[640,  '31.5'            , '60'                 ,     'Standard VGA, 640x480 @ 60 Hz'                              ],
[800,  '31.5-35.1'	    , '55-60'    	   ,     'Super VGA, 800x600 @ 56 Hz'                              ],
[1024, '31.5,35.5'	    , '60,70,87' 	   ,     '8514 Compatible, 1024x768@87 Hz interlaced (no 800x600)' ],
[1024, '31.5,35.15,35.5' , '55-90'    	   ,     'Super VGA, 1024x768 @ 87 Hz interlaced, 800x600 @ 56 Hz'         ],
[800,  '31.5-37.9'	    , '55-90'    	   ,     'Extended Super VGA, 800x600 @ 60 Hz, 640x480 @ 72 Hz'    ],
[1024, '31.5-48.5'	    , '55-90'    	   ,     'Non-Interlaced SVGA, 1024x768 @ 60 Hz, 800x600 @ 72 Hz'  ],
[1024, '31.5-57.0'	    , '50-90'    	   ,     'High Frequency SVGA, 1024x768 @ 70 Hz'                   ],
[1024, '31.5-64.3'	    , '50-90'    	   ,     'Multi-frequency that can do 1280x1024 @ 60 Hz'           ],
[1280, '31.5-79.0'	    , '50-100'   	   ,     'Multi-frequency that can do 1280x1024 @ 74 Hz'           ],
[1280, '31.5-82.0'	    , '40-100'   	   ,     'Multi-frequency that can do 1280x1024 @ 76 Hz'	   ],
);

@mouselist=(
[ "ttyS0 MouseSystems  ", 3 ],
[ "psaux PS/2  " , 2],
[ "ttyS0 Microsoft   " , 2],
);


#monitor defs
$MAXWIDTH = 0;
$HRANGE = 1;
$VRANGE = 2;
$DESC = 3;

# mouse defs
$MDEV = 0;
$MPROTO = 1;
$MNAME = 2;
$M3BUTTONS = 3;

# MOde defs
$MWIDTH = 0;
$MHEIGHT = 1;
$MDEPTH = 2;
$MHZ = 3;

sub detect_mouse {
  my $cmd='mouseconf 2>&1 > /dev/null';
  my (@res)=`$cmd`;
  my $refuse;
  my ($mouse,$mouse3);
  if (@res) {
    $refuse = system("dialog --yesno '   Autodetection found:\n\n\n    $res[0]\n\n        Is this correct??' 20 60");
  } else {
    $refuse = 1;
  }
  if ($refuse) {
    my $dialog = "dialog --radiolist 'Choose your mouse' 20 70 16 ";
    foreach (0..$#mouselist) {
      my $m = $mouselist[$_];
      $dialog .= " $_ '$m->[0]' ".($_ ? "off " : "on ");
    }
    my $num = `$dialog 2>&1 > /dev/tty`;
    $mouse = $mouselist[$num]->[0];
    $mouse3 = $mouselist[$num]->[1];
  } else {
    # $confirm = system("dialog --yesno 'mouse with 3 buttons' 20 80");
    # $mouse3 = ($confirm == 0);
    $mouse = $res[0];
    $mouse3 = 1;
  }
  $mouse =~ /^([^ ]*) ([^ ]*) (.*)$/ or die "unexpected output from mouse configuration:$res[0]\n";
  my $m = ["/dev/".$1,$2,$3,$mouse3 ];
  print STDERR "mouse:$m->[0]:$m->[1]:$m->[2],$m->[3]\n";
  return $m;
}

  

sub detect_xserver {
  my (@lines)=`lspci -n`;
  my (@vgadevs)=grep(/Class 0300/,@lines);
  @vgadevs == 1 or die scalar(@vgadevs)." vga devices found\n";
  my $vgadev = $vgadevs[0];
  $vgadev =~ /Class 0300: (\w{4}):(\w{4})/ or die "invalide vgadev:$_\n";
  my $pci_id = "$1$2";
  print STDERR "found PCI VGA ($pci_id): ($vgadev)\n";
  my $f = new FileHandle "$pci_lst" or die "opening pci.lst";
  my @video = grep(/$pci_id/,$f->getlines);
  $f->close;
  @video == 1 or die  scalar(@video)." entries found for id $pci_id in pci.lst\n";
  my $video = $video[0];
  $video =~ /$pci_id\s+video\s+(\w+)\s+(.*)$/ or die "cannot parse $video\n";
  my ($card,$desc) = ($1,$2);
  
  my %mapping = ( 'RIVA128' => 'SVGA',
		  'ET4000' => 'SVGA',
		  'ET9000' => 'SVGA',
		  '3DLabs' => 'Glint',
	  );
  my $server = $mapping{$card} || $card;
  
  print STDERR "found video for X server card= $card, server = $server : ($desc)\n";
  
  $server ne 'unknown' or die "do not know server for $desc\n";
  return $server;
}





sub create_xfc {
  my ($server,$depth,$mouse,$mon) = @_;
  my $cf = new FileHandle "> /tmp/XF86Config.new" or die "creating /tmp/XF86Config.new\n";
  my $hrange = $mon->[$HRANGE];
  my $vrange = $mon->[$VRANGE];
  my $maxwidth = $mon->[$MAXWIDTH];
  
  my %w2h = ( 1600 => 1200, 1280 => 1024, 1152 => 854, 1024 => 768, 800 => 600, 640 => 480);
  $maxheight = $w2h{$maxwidth} or error "unknown Width: $maxwidth";
  my @depth=(8,16,32);
  my @width=($maxwidth,$maxwidth,$maxwidth);
  my @height=($maxheight,$maxheight,$maxheight);
  
  my $driver = $server eq 'SVGA'  ? 'svga' : 'accel';
  
  my $blanktime = 10;
  my $mousebuttons = $mouse->[$M3BUTTONS] ? "#Buttons 3\n" : "#Buttons 2\nEmulate3Buttons\n";

print $cf <<EOF;

# Autogenerated by repli-xconfig

Section "Files"
   RgbPath    "/usr/X11R6/lib/X11/rgb"
   FontPath   "/usr/X11R6/lib/X11/fonts/misc:unscaled"
   FontPath   "/usr/X11R6/lib/X11/fonts/75dpi:unscaled"
   FontPath   "/usr/X11R6/lib/X11/fonts/100dpi:unscaled"
   FontPath   "/usr/X11R6/lib/X11/fonts/Type1"
   FontPath   "/usr/X11R6/lib/X11/fonts/Speedo"
   FontPath   "/usr/X11R6/lib/X11/fonts/misc"
   FontPath   "/usr/X11R6/lib/X11/fonts/75dpi"
   FontPath   "/usr/X11R6/lib/X11/fonts/100dpi"
EndSection

Section "ServerFlags"
EndSection

Section "Keyboard"
   Protocol        "Standard"
   ServerNumLock
   RightAlt ModeShift
   XkbDisable
#   XkbRules        "xfree86"
#   XkbModel        "pc104"
#   XkbLayout       "fr"
EndSection

Section "Pointer"

 Protocol "$mouse->[$MPROTO]"
 Device "$mouse->[$MDEV]"
$mousebuttons
EndSection

Section "Monitor"
  Identifier "UnknownMonitor"
  VendorName "UnknownMonitorVendor"
  ModelName "UnknownModel"
  HorizSync $hrange
  VertRefresh $vrange
# 640x400 @ 70 Hz, 31.5 kHz hsync
Modeline "640x400"     25.175 640  664  760  800   400  409  411  450
# 640x480 @ 60 Hz, 31.5 kHz hsync
Modeline "640x480"     25.175 640  664  760  800   480  491  493  525
# 800x600 @ 56 Hz, 35.15 kHz hsync
ModeLine "800x600"     36     800  824  896 1024   600  601  603  625
# 1024x768 @ 87 Hz interlaced, 35.5 kHz hsync
Modeline "1024x768"    44.9  1024 1048 1208 1264   768  776  784  817 Interlace
# 640x400 @ 85 Hz, 37.86 kHz hsync
Modeline "640x400"     31.5   640  672 736   832   400  401  404  445 -HSync +VSync
# 640x480 @ 72 Hz, 36.5 kHz hsync
Modeline "640x480"     31.5   640  680  720  864   480  488  491  521
# 640x480 @ 75 Hz, 37.50 kHz hsync
ModeLine  "640x480"    31.5   640  656  720  840   480  481  484  500 -HSync -VSync
# 800x600 @ 60 Hz, 37.8 kHz hsync
Modeline "800x600"     40     800  840  968 1056   600  601  605  628 +hsync +vsync
# 640x480 @ 85 Hz, 43.27 kHz hsync
Modeline "640x400"     36     640  696  752  832   480  481  484  509 -HSync -VSync
# 1152x864 @ 89 Hz interlaced, 44 kHz hsync
ModeLine "1152x864"    65    1152 1168 1384 1480   864  865  875  985 Interlace
# 800x600 @ 72 Hz, 48.0 kHz hsync
Modeline "800x600"     50     800  856  976 1040   600  637  643  666 +hsync +vsync
# 1024x768 @ 60 Hz, 48.4 kHz hsync
Modeline "1024x768"    65    1024 1032 1176 1344   768  771  777  806 -hsync -vsync
# 640x480 @ 100 Hz, 53.01 kHz hsync
Modeline "640x480"     45.8   640  672  768  864   480  488  494  530 -HSync -VSync
# 1152x864 @ 60 Hz, 53.5 kHz hsync
Modeline  "1152x864"   89.9  1152 1216 1472 1680   864  868  876  892 -HSync -VSync
# 800x600 @ 85 Hz, 55.84 kHz hsync
Modeline  "800x600"    60.75  800  864  928 1088   600  616  621  657 -HSync -VSync
# 1024x768 @ 70 Hz, 56.5 kHz hsync
Modeline "1024x768"    75    1024 1048 1184 1328   768  771  777  806 -hsync -vsync
# 1280x1024 @ 87 Hz interlaced, 51 kHz hsync
Modeline "1280x1024"   80    1280 1296 1512 1568  1024 1025 1037 1165 Interlace
# 800x600 @ 100 Hz, 64.02 kHz hsync
Modeline  "800x600"    69.65  800  864  928 1088   600  604  610  640 -HSync -VSync
# 1024x768 @ 76 Hz, 62.5 kHz hsync
Modeline "1024x768"    85    1024 1032 1152 1360   768  784  787  823
# 1152x864 @ 70 Hz, 62.4 kHz hsync
Modeline  "1152x864"   92    1152 1208 1368 1474   864  865  875  895
# 1280x1024 @ 61 Hz, 64.2 kHz hsync
Modeline "1280x1024"  110    1280 1328 1512 1712  1024 1025 1028 1054
# 1024x768 @ 85 Hz, 70.24 kHz hsync
Modeline "1024x768"   98.9  1024 1056 1216 1408   768 782 788 822 -HSync -VSync
# 1152x864 @ 78 Hz, 70.8 kHz hsync
Modeline "1152x864"   110   1152 1240 1324 1552   864  864  876  908
# 1280x1024 @ 70 Hz, 74.59 kHz hsync
Modeline "1280x1024"  126.5 1280 1312 1472 1696  1024 1032 1040 1068 -HSync -VSync
# 1600x1200 @ 60Hz, 75.00 kHz hsync
Modeline "1600x1200"  162   1600 1664 1856 2160  1200 1201 1204 1250 +HSync +VSync
# 1152x864 @ 84 Hz, 76.0 kHz hsync
Modeline "1152x864"   135    1152 1464 1592 1776   864  864  876  908
# 1280x1024 @ 74 Hz, 78.85 kHz hsync
Modeline "1280x1024"  135    1280 1312 1456 1712  1024 1027 1030 1064
# 1024x768 @ 100Hz, 80.21 kHz hsync
Modeline "1024x768"   115.5  1024 1056 1248 1440  768  771  781  802 -HSync -VSync
# 1280x1024 @ 76 Hz, 81.13 kHz hsync
Modeline "1280x1024"  135    1280 1312 1416 1664  1024 1027 1030 1064
# 1600x1200 @ 70 Hz, 87.50 kHz hsync
Modeline "1600x1200"  189    1600 1664 1856 2160  1200 1201 1204 1250 -HSync -VSync
# 1152x864 @ 100 Hz, 89.62 kHz hsync
Modeline "1152x864"   137.65 1152 1184 1312 1536   864  866  885  902 -HSync -VSync
# 1280x1024 @ 85 Hz, 91.15 kHz hsync
Modeline "1280x1024"  157.5  1280 1344 1504 1728  1024 1025 1028 1072 +HSync +VSync
# 1600x1200 @ 75 Hz, 93.75 kHz hsync
Modeline "1600x1200"  202.5  1600 1664 1856 2160  1200 1201 1204 1250 +HSync +VSync
# 1600x1200 @ 85 Hz, 105.77 kHz hsync
Modeline "1600x1200"  220    1600 1616 1808 2080  1200 1204 1207 1244 +HSync +VSync
# 1280x1024 @ 100 Hz, 107.16 kHz hsync
Modeline "1280x1024"  181.75 1280 1312 1440 1696  1024 1031 1046 1072 -HSync -VSync
# 1800x1440 @ 64Hz, 96.15 kHz hsync
ModeLine "1800X1440"  230    1800 1896 2088 2392 1440 1441 1444 1490 +HSync +VSync
# 1800x1440 @ 70Hz, 104.52 kHz hsync
ModeLine "1800X1440"  250    1800 1896 2088 2392 1440 1441 1444 1490 +HSync +VSync
# 512x384 @ 78 Hz, 31.50 kHz hsync
Modeline "512x384"    20.160 512  528  592  640   384  385  388  404 -HSync -VSync
# 512x384 @ 85 Hz, 34.38 kHz hsync
Modeline "512x384"    22     512  528  592  640   384  385  388  404 -HSync -VSync

EndSection

Section "Device"
 Identifier "UnknownDevice"
 VendorName "UnknwonDeviceVendor"
 BoardName "UnknownBoardName"
EndSection

Section "Screen"
  Driver "$driver"
  Device "UnknownDevice"
  Monitor "UnknownMonitor"
  DefaultColorDepth $depth
  BlankTime $blanktime
  SubSection "Display"
    Depth 8
    Virtual $width[0] $height[0]
    Modes "1600x1200" "1280x1024" "1152x1024" "1024x768" "800x600" "640x480"
  EndSubsection
  SubSection "Display"
    Depth 16
    Virtual $width[1] $height[1]
    Modes "1600x1200" "1280x1024" "1152x1024" "1024x768" "800x600" "640x480"
  EndSubsection
  SubSection "Display"
    Depth 32
    Virtual $width[2] $height[2]
    Modes "1600x1200" "1280x1024" "1152x1024" "1024x768" "800x600" "640x480"
  EndSubsection
EndSection

EOF

$cf->close;

}



sub select_monitor {
  my @dialog = ('dialog','--radiolist','"Select your monitor"','20','80','16');
  foreach (0..$#monitorlist) {
    my $m = $monitorlist[$_];
    #push @dialog,"$_","'$m->[$DESC] Hrange:$m->[$HRANGE] Vrange:$m->[$HRANGE]  '","off";
    push @dialog,"$_","'$m->[$DESC] '",($_ == @monitorlist/2 ? "on" : "off");
  }
  
  my $cmd = join(" ",@dialog);
  print STDERR "exec:$cmd\n";
  my $res = `$cmd 2>&1 > /dev/tty`;
  $res =~ /^\d$/ or die "dialog failed,res=$res\n";
  
  print STDERR  "res=$res\n";
  
  print STDERR "selected monitor:@{$monitorlist[$res]}\n";
  
  return $monitorlist[$res];
}

sub detect_modes {
  my ($server,$mon) = @_;
  my @widths = qw(1600 1280 1152 1024 800 640 );
  
  while ($widths[0] > $mon->[$MAXWIDTH]) {
    shift @widths
  }

  my @modes=();
  do {
    my $tryw = $widths[0];
    for $d (qw(32 16 8)) {
      my $command = "/usr/X11R6/bin/XF86_${server} -xf86config /tmp/XF86Config.new -probeonly  :2 -bpp $d";
      print STDERR "executing:$command\n";
      my @res = `$command 2>&1`;
      @res = grep(/Mode ".*": mode clock =\s*[\d.]*/,@res);
      #  print STDERR "result=@res\n";
      next if @res < 1;
      print STDERR "best mode with depth $d:$res[0]\n";
      foreach (@res) {
	/Mode "(\d+)x(\d+)": mode clock =\s*([\d.]+)/ or die "oops";
	my ($w,$h,$freq) = ($1,$2,$3);
	if ($w <= $tryw) {
	  my $freq = int($freq*1024*1024/($w*1.3)/($h*1.125));
	  print STDERR "depth $d,mode  ${w}x${h} : Freq=$freq\n";
	  push @modes,[$w,$h,$d,$freq];
	}
      }
    }
    shift @widths;
  } while (@widths && @modes == 0);
  print STDERR "".scalar(@modes). " modes found\n";
  return \@modes;
}

sub select_mode {
  my @modes = @{$_[0]};
  my $dialog='dialog --radiolist "Choose a mode" 20 80 16 ';
  foreach (0..$#modes) {
    my $m = $modes[$_];
    $dialog .= "$_ '$m->[0]x$m->[1] $m->[2]bits $m->[3]Hz' ".($_ == 0 ? "on " : "off ");
  }
  
  print STDERR "exec: $dialog\n";
  my $res = `$dialog 2>&1 > /dev/tty`;
  $res ne '' or die "not choice given\n";
  return $modes[int($res)];
}

sub final_xfc {
  my ($server,$m,$mouse,$mon) = @_;
  $mon->[0] = $m->[$MWIDTH];
  print STDERR "generating XF86Config for $m->[0]x$m->[1] $m->[2]bits $m->[3]Hz' off\n";
  create_xfc($server,$m->[$MDEPTH],$mouse,$mon);
}

my $mouse = detect_mouse;
my $server = detect_xserver;
my $mon = select_monitor;
print STDERR "MON:@{$mon}\n";
print STDERR "MOUSE:@{$mouse}\n";
create_xfc($server,'8',$mouse,$mon);
my $modes = detect_modes($server,$mon);
my $mode = select_mode($modes);
final_xfc($server,$mode,$mouse,$mon);

rename("/tmp/XF86Config.new","/etc/X11/XF86Config");

$f = new FileHandle "> /etc/X11/Xserver" or die "ERROR opening /etc/X11/Xserver";
print $f "/usr/X11R6/bin/XF86_$server
Console

The first line in this file is the full pathname of the default X server.
The second line shows who is allowed to run the X server:
RootOnly
Console      (anyone whose controlling tty is on the console)
Anybody
";

$f->close;



