The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl -w

use Qt 2.0;

$seed = 0.353535353535;
$KINDA_RAND_MAX = 32767;

sub kindaRand {
    $seed *= 147;
    $seed -= int($seed);
    return int($seed * ($KINDA_RAND_MAX + 1));
}

sub velocity {
    my $i = shift;
    my $velmax = 10;
    my $velmin = 4;

    if($i == 1 || $i == 2) {
	$i = (kindaRand()&0x7fff % $velmax)/3 + $velmin;
    } else {
	$i = (kindaRand()&0x7fff % $velmax) + $velmin;
    }
    return $i;
}

#
# Draw polygon on desktop.
#

sub poly {
    my $d = Qt::Application::desktop();
    $d->setBackgroundColor(Qt::white);

    my $maxpoints = 5;
    my $maxcurves = 8;
    my @xvel;
    my @yvel;
    my $head = 0;
    my $tail = -$maxcurves + 2;
    my @a;
    my $p;
    my $r = $d->rect();

    for(0..$maxcurves-1) {
	$a[$_] = Qt::PointArray->new;
	$a[$_]->resize($maxpoints);
    }
    $p = $a[0];
    for(0..$maxpoints-1) {
	$p->setPoint($_, (kindaRand()&0x7fff) % $r->width(),
		         (kindaRand()&0x7fff) % $r->height());
	$xvel[$_] = velocity($_);
	$yvel[$_] = velocity($_);
    }

    my $paint = Qt::Painter->new;
    $paint->begin($d);

    for(my $ntimes = 0; $ntimes < 2000; $ntimes++) {
	$paint->setBrush(Qt::Color->new(kindaRand()%360, 180, 255, Qt::Color::Hsv));
	$paint->drawPolygon($a[$head]);
	$tail = 0 if ++$tail >= $maxcurves;

	my($minx, $maxx) = ($r->left(), $r->right());
	my($miny, $maxy) = ($r->top(),  $r->bottom());
	my($x, $y);
	$p = $a[$head];
	$head = 0 if ++$head >= $maxcurves;
	for(0..$maxpoints-1) {
	    $p->point($_, $x, $y);
	    $x += $xvel[$_];
	    $y += $yvel[$_];
	    if($x > $maxx) {
		$x = $maxx - ($x - $maxx + 1);
		$xvel[$_] = -velocity($_);
	    }
	    if($x <= $minx) {
		$x = $minx + ($minx - $x + 1);
		$xvel[$_] = velocity($_);
	    }
	    if($y >= $maxy) {
		$y = $maxy - ($y - $maxy + 1);
		$yvel[$_] = -velocity($_);
	    }
	    if($y <= $miny) {
		$y = $miny + ($miny - $y + 1);
		$yvel[$_] = velocity($_);
	    }
	    $a[$head]->setPoint($_, $x, $y);
	}
    }
    $paint->end();
}

#
# Rotate pattern on desktop.
#

sub rotate {
    my $i;
    my $w = 64;
    my $h = 64;
    my $image = Qt::Image->new($w, $h, 8, 128);
    for($i = 0; $i < 128; $i++) {
	$image->setColor($i, Qt::Color::rgb($i,0,0));
    }
    for(my $y = 0; $y < $h; $y++) {
	my $p = $image->scanLine($y);
	for(my $x = 0; $x < $w; $x++) {
	    $$p[$x] = ($x+$y)%128;
	}
    }

    my $pm = Qt::Pixmap->new($image);
    $pm->optimize(1);

    my $d = Qt::Application::desktop();

    for($i = 0; $i <= 360; $i += 2) {
	my $m = Qt::WMatrix->new;
	$m->rotate($i);
	my $rpm = $pm->xForm($m);
	$d->setBackgroundPixmap($rpm);
	$d->update();
    }
}

#
# Generates a marble-like pattern in pm.
#

sub generateStone {
    my $pm = shift;
    my($c1, $c2, $c3) = @_;
    my $p = Qt::Painter->new;
    my $p1 = Qt::Pen->new($c1);
    my $p2 = Qt::Pen->new($c2);
    my $p3 = Qt::Pen->new($c3);

    $p->begin($pm);
    my $width = $pm->width();
    my $height = $pm->height();
    my $r;
    my($i, $j);
    my $krmD3 = $KINDA_RAND_MAX / 3;
    my $krmD3T2 = $KINDA_RAND_MAX / 3 * 2;
    for($i = 0; $i < $width; $i++) {
	for($j = 0; $j < $height; $j++) {
	    $r = kindaRand();
	    if($r < $krmD3) {
		$p->setPen($p1);
	    } elsif($r < $krmD3T2) {
		$p->setPen($p2);
	    } else {
		$p->setPen($p3);
	    }
	    $p->drawPoint($i, $j);
	}
    }
    $p->end();
}

sub drawShadeText {
    my $p = shift;
    my $x = shift;
    my $y = shift;
    my $text = shift;
    my $topColor = shift;
    my $bottomColor = shift;
    my $sw = @_ ? shift : 2;

    return unless $p->isActive();

    $p->setPen($bottomColor);
    $p->drawText($x+$sw, $y+$sw, $text);
    $p->setPen($topColor);
    $p->drawText($x, $y, $text);
}


package DesktopWidget;

use Qt 2.0;

@ISA = qw(Qt::Widget);

sub new {
    my $s = shift;
    my $self = shift->SUPER::new(@_[0..1], Qt::WType_Desktop |
				 Qt::WPaintDesktop);

    $self->{'text'} = $s;
    return $self;
}

sub paintEvent {
    my $c1 = $self->backgroundColor();
    my $c2 = $c1->light(104);
    my $c3 = $c1->dark(106);
    unless(exists $self->{'pm'}) {
	my $pm = $self->{'pm'} = Qt::Pixmap->new(64, 64);
	generateStone($pm, $c1, $c2, $c3);
	$self->setBackgroundPixmap($pm);
	$self->update();
    }
    my $br = $self->fontMetrics()->boundingRect($self->{'text'});
    my $offscreen = Qt::Pixmap->new($br->width(), $br->height());
    my $x = $self->width()/2 - $br->width()/2;
    my $y = $self->height()/2 - $br->height()/2;
    $offscreen->fill($self, $x, $y);
    my $p = Qt::Painter->new;
    $p->begin($offscreen);
    main::drawShadeText($p, -$br->x(), -$br->y(), $self->{'text'}, $c2, $c3, 3);
    $p->end();
    $self->bitBlt($x, $y, $offscreen);
}


package main;

import Qt::app;

sub desktopWidget {
    my $t = DesktopWidget->new(@_);
    $t->update();
    $app->exec();
}

sub desktopText {
    my $s = @_ ? shift : 'PerlQt rocks';
    my $border = 20;

    my $c1 = Qt::Application::palette()->normal()->background();
    my $c2 = $c1->light(104);
    my $c3 = $c1->dark(106);

    my $pm = Qt::Pixmap->new(10, 10);

    my $p = Qt::Painter->new;
    $p->begin($pm);
    my $r = $p->fontMetrics()->boundingRect($s);
    $p->end();

    my $appWidth  = Qt::Application::desktop()->width();
    my $appHeight = Qt::Application::desktop()->height();
    if($r->width() > $appWidth - $border*2) {
	$r->setWidth($appWidth - $border*2);
    }
    if($r->height() > $appHeight - $border*2) {
	$r->setHeight($appHeight - $border*2);
    }

    $pm->resize($r->size() + Qt::Size->new($border*2, $border*2));
    generateStone($pm, $c1, $c2, $c3);
    $p->begin($pm);
    drawShadeText($p, -$r->x() + $border, -$r->y() + $border, $s, $c2, $c3);
    $p->end();

    Qt::Application::desktop()->setBackgroundPixmap($pm);
}

#
# The program starts here.
#

use Qt 2.0;

if(@ARGV) {
    my $f = Qt::Font->new('Charter', 96, Qt::Font::Black);
    $f->setStyleHint(Qt::Font::Times);
    Qt::Application::setFont($f);
}

$validOptions = 0;

if(@ARGV == 1) {
    $validOptions = 1;
    if($ARGV[0] eq '-poly') {
	poly();
    } elsif($ARGV[0] eq '-rotate') {
	rotate();
    } elsif($ARGV[0] eq '-perlqt') {
	desktopText();
    } elsif($ARGV[0] eq '-perlqtwidget') {
	desktopWidget();
    } else {
	$validOptions = 0;
    }
} elsif(@ARGV == 2) {
    $validOptions = 1;
    if($ARGV[0] eq '-shadetext') {
	desktopText($ARGV[1]);
    } elsif($ARGV[0] eq '-shadewidget') {
	desktopWidget($ARGV[1]);
    } else {
	$validOptions = 0;
    }
}
die <<CROAK unless $validOptions;
Usage:
	$0 -poly
	$0 -rotate
	$0 -perlqt
	$0 -perlqtwidget
	$0 -shadetext <text>
	$0 -shadewidget <text>
CROAK