#!/usr/bin/perl
# This is a virtually complete test of all of the protocol's features
# -- it was used by the author during development. It generates a lot
# of output to STDOUT, uses a bunch of memory, and messes with your
# display in various ways. (Though some of the most egregious have
# been commented out). Run it at your own risk.
use X11::Protocol 0.02;
use X11::Keysyms qw(%Keysyms MISCELLANY XKB_KEYS LATIN1);
%Keysyms_name = reverse %Keysyms;
sub pretty
{
my($x) = @_;
if (not ref $x)
{
if ($x == 0 and $x ne "0")
{
$x = "..." if $x =~ /[\cA-\cZ]/;
print "`$x'";
}
else
{
printf "$x=0x%x", $x;
}
}
elsif (ref($x) eq "ARRAY")
{
my($i);
print "[";
for $i (@$x) { pretty($i); print ", ";}
print "]";
}
elsif (ref($x) eq "HASH" or ref($x) eq "X11::Protocol")
{
my($k, $v);
print "{";
while (($k, $v) = each(%$x))
{
print "$k => ";
pretty($v);
print ", ";
}
print "}";
}
else
{
print $x;
}
}
sub my_sleep {
my($secs) = @_;
$x->flush();
sleep($secs);
}
%opts = @ARGV;
$display = $opts{'-d'} || $opts{'-display'} || $ENV{'DISPLAY'} || ":0.0";
$x = X11::Protocol->new($display);
pretty $x;
print "\n";
$win = $x->new_rsrc;
print "$win\n";
$x->error_handler(sub {});
$x->error_handler(\&X11::Protocol::default_error_handler);
sub print_event
{
my(%e) = @_;
my($i);
$last_event_time = $e{'time'} if $e{'time'};
exit if $e{'name'} eq "KeyPress" and ($e{'detail'} == 24 or $done);
print delete($e{'name'}), ": ";
print join(", ", map("$_ $e{$_}", keys %e)), "\n";
}
$x->{'event_handler'} = \&print_event;
#$x->{'event_handler'} = 'queue';
$x->req('CreateWindow', $win, $x->{'root'}, "InputOutput",
$x->{'root_depth'}, "CopyFromParent",
(0, 0), 100, 100, 1, "backing_store" => "WhenMapped",
'background_pixel' => $x->{'white_pixel'});
$x->req('ChangeProperty', $win,
$x->req('InternAtom', "WM_NAME", 0),
$x->req('InternAtom', "STRING", 0), 8, "Replace", "Perl X11 Client");
$x->req('ChangeWindowAttributes', $win, "event_mask" => #0x01ebffff);
$x->pack_event_mask('KeyPress', 'KeyRelease', 'ButtonPress',
'ButtonRelease', 'EnterWindow', 'LeaveWindow',
'PointerMotion', 'ButtonMotion', 'KeymapState',
'Exposure', 'VisibilityChange', 'StuctureNotify',
'SubstructureNotify', 'FocusChange',
'PropertyChange', 'ColormapChange'));
print join " ", $x->req('GetWindowAttributes', $win), "\n";
$x->request('MapWindow', $win);
req $x 'ConfigureWindow', $win, "height" => 200, "width" => 200;
$kid1 = $x->new_rsrc;
$x->req('CreateWindow', $kid1, $win, 'InputOutput', $x->{'root_depth'},
'CopyFromParent', (50, 50), 75, 75, 4);
$kid2 = $x->new_rsrc;
$x->req('CreateWindow', $kid2, $win, 'InputOutput', $x->{'root_depth'},
'CopyFromParent', (100, 100), 75, 75, 4);
$x->req('MapSubwindows', $win);
my_sleep 2;
$x->req('CirculateWindow', $win, "LowerHighest");
my_sleep 2;
$x->req('DestroySubwindows', $win);
print join " ", $x->req('GetGeometry', $win), "\n";
print join " ",
$x->req('GetGeometry', $x->{'root'}), "\n";
($root, $parent, @kids) = $x->req('QueryTree', $x->{'root'});
for $kid (@kids) {
print join " ", $x->req('GetGeometry', $kid), "\n";
}
print $x->req('InternAtom', "WM_NAME", 0), "\n";
for $atom (1 .. 90) {
print "$atom: ", $x->req('GetAtomName', $atom), ", ";
}
print "\n\n";
for $atom ($x->req('ListProperties', $win)) {
print $x->atom_name($atom), " => ";
print join(",", $x->req('GetProperty', $win, $atom, "AnyPropertyType",
0, 200, 0)), "\n";
}
$root_wid = $x->{'root'};
for (1 .. 10)
{
my($e) = $x->pack_event('code' => 2, 'detail' => 25, 'time' => 0,
'root' => $root_wid, 'event' => $win, 'child' => 0,
'root_x' => 100, 'root_y' => 100, 'event_x' => 5,
'event_y' => 5, 'state' => 0, 'same_screen' => 1,
'synthetic' => 0);
$x->req('SendEvent', "PointerWindow", 0, 0, $e);
$x->req('SendEvent', "PointerWindow", 0, 0,
$x->pack_event('name' => "KeyRelease", 'detail' => 25, 'time' => 0,
'root' => $root_wid, 'event' => $win, 'child' => 0,
'root_x' => 100, 'root_y' => 100, 'event_x' => 5,
'event_y' => 5, 'state' => 0, 'same_screen' => 1));
}
print "Grabbing...";
$x->req('GrabPointer', $win, 0, 0, 'Asynchronous', 'Asynchronous', $win, 0, 0);
my_sleep 2;
$x->req('UngrabPointer', 0);
print "done.\n";
my_sleep 2;
print "Grabbing server...";
$x->req('GrabServer');
my_sleep 2;
$x->req('UngrabServer');
print "done.\n";
print "->", join(" ", $x->req('QueryPointer', $win)), "\n";
for $motion ($x->req('GetMotionEvents', $last_event_time, 'CurrentTime', $win))
{
print "$motion->[0]: ($motion->[1], $motion->[2])\n";
}
print "-->", join(" ", $x->req('TranslateCoordinates',
$win => $root_wid, 50, 50)), "\n";
for (1 .. 10)
{
$x->req('WarpPointer', 'None', $root_wid, 0, 0, 0, 0,
rand($x->{'width_in_pixels'} * .9),
rand($x->{'height_in_pixels'} * .9));
my_sleep 1;
}
print "--->", join(" ", $x->req('GetInputFocus')), "\n";
print "---->", $x->req('QueryKeymap'), "\n";
$fid = $x->new_rsrc;
$x->req('OpenFont', $fid, 'fixed');
print "`fixed' = $fid\n";
%fixed = $x->req('QueryFont', $fid);
print join(" ", %fixed), "\n";
print join(" ", @{$fixed{'min_bounds'}}), "\n";
print join(" ", @{$fixed{'max_bounds'}}), "\n";
%prop = %{$fixed{'properties'}};
foreach $atom (keys %prop)
{
print $x->atom_name($atom), " => ", $prop{$atom}, "; ";
}
print "\n";
foreach $ci (@{$fixed{'char_infos'}})
{
print join (" ", @$ci), "; ";
}
print "\n";
print join(" ", $x->req('QueryTextExtents', $fid, "\0H\0e\0l\0l\0o")), "\n";
print join("\n", $x->req('ListFonts', '-adobe-*', 50)), "\n";
foreach $font ($x->req('ListFontsWithInfo', '-adobe-*', 5))
{
%info = %$font;
print join(" ", %info), "\n";
print join(" ", @{$info{'min_bounds'}}), "\n";
print join(" ", @{$info{'max_bounds'}}), "\n";
%prop = %{$info{'properties'}};
foreach $atom (keys %prop)
{
print $x->atom_name($atom), " => ", $prop{$atom}, "; ";
}
print "\n";
}
print join(", ", $x->req('GetFontPath')), "\n";
#$x->req('SetFontPath', $x->req('GetFontPath'));
#print join(", ", $x->req('GetFontPath')), "\n";
$pixmap = $x->new_rsrc;
$x->req('CreatePixmap', $pixmap, $win, $x->{'root_depth'}, 50, 50);
$x->req('FreePixmap', $pixmap);
$gc = $x->new_rsrc;
$x->req('CreateGC', $gc, $win, 'function' => 'Xor', 'line_width' => 2,
'join_style' => 'Miter', 'font' => $fid, 'arc_mode' => 'PieSlice',
'foreground' => $x->{'white_pixel'},
'background' => $x->{'black_pixel'},
'graphics_exposures' => 0);
$x->req('ChangeGC', $gc, 'join_style' => 'Round');
$fancy_gc = $x->new_rsrc;
$x->req('CreateGC', $fancy_gc, $win);
$x->req('CopyGC', $gc, $fancy_gc, 'function', 'line_width', 'join_style',
'font', 'arc_mode', 'background', 'graphics_exposures');
$x->req('ChangeGC', $fancy_gc, 'line_style' => 'OnOffDash');
$x->req('SetDashes', $fancy_gc, 0, (1, 2, 1, 3, 1));
$x->req('SetClipRectangles', $fancy_gc, (0, 0), 'UnSorted', [0, 40, 100, 20],
[40, 0, 20, 100]);
$x->req('ClearArea', $win, (0, 0), 200, 200, 0);
$white = $x->{'white_pixel'};
$black = $x->{'black_pixel'};
$x->req('ChangeGC', $gc, 'function' => 'Copy', 'background' => $white,
'foreground' => $black);
for (1 .. 500)
{
push @points, rand(200);
}
$x->PolyPoint($win, $gc, 'Origin', @points);
for $c (@points)
{
$c = 200 - $c;
}
$x->PolySegment($win, $gc, @points);
for $c (@points)
{
$c /= 10;
$c -= 10;
}
$x->ClearArea($win, (0, 0), 200, 200, 0);
$x->PolyLine($win, $gc, 'Previous', (100, 100), @points);
$x->ChangeGC($gc, 'function' => "Xor");
for (1 .. 200)
{
$x->req('CopyArea', $win, $win, $gc, (rand(160), rand(160)), 40, 40,
(rand(160), rand(160)));
}
$x->req('ChangeGC', $gc, 'function' => "Copy");
for (1 .. 200)
{
$x->req('CopyPlane', $win, $win, $fancy_gc, (rand(160), rand(160)),
40, 40, (rand(160), rand(160)), 1 << 0);
}
$x->req('ClearArea', $win, (0, 0), 200, 200, 0);
for (1 .. 25)
{
push @rects, [rand(100), rand(100), rand(100), rand(100)];
}
$x->req('PolyRectangle', $win, $gc, @rects);
for (1 .. 16)
{
push @arcs, [rand(150), rand(150), 50, 50, 0, rand(360 * 64)];
}
$x->req('PolyArc', $win, $gc, @arcs);
$x->req('FillPoly', $win, $gc, 'Convex', 'Origin',
(100,0)=>(150,150)=>(0,100));
@rects = ();
for (1 .. 100)
{
push @rects, [rand(190), rand(190), rand(10), rand(10)];
}
$x->req('PolyFillRectangle', $win, $gc, @rects);
@arcs = ();
for (1 .. 25)
{
push @arcs, [rand(175), rand(175), 25, 25, 90 * 64, rand(360 * 64)];
}
$x->req('PolyFillArc', $win, $gc, @arcs);
$x->req('ClearArea', $win, (0, 0), 200, 200, 0);
if ($x->{'bitmap_bit_order'} eq 'LeastSignificant'
and $x->{'bitmap_scanline_unit'} == 32
and $x->{'bitmap_scanline_pad'} == 32)
{
$bmap =
"\0\0\xff\xff\xff\xff\x0f\0" x 8 .
"\0\0\xff\0\0\0\xff\0" x 8 .
"\0\0\xff\xff\xff\xff\x0f\0" x 8 .
"\0\0\xff\0\0\0\0\0" x 8 .
"\0\0\xff\0\0\0\0\0" x 8;
for $shift (0 .. 3)
{
$x->req('PutImage', $win, $gc, 1, 56, 40,
(0, 2 + 42 * $shift), 8, 'Bitmap', $bmap);
}
}
if (0)
{
$pixmap =
# 1234567890123456789012345678
" ".
" #### ##### #### # ".
" # # # # # # ".
" #### #### #### # ".
" # # # # # ".
" # ##### # # ##### ".
" ";
@pixels = unpack("C*", $pixmap);
for $p (@pixels)
{
$p = 0 if $p == ord("#");
}
for (1 .. 50)
{
@p = @pixels;
for $p (@p)
{
$p = rand(256) if $p;
}
$x->req('PutImage', $win, $gc, 8, 25, 7,
(rand(175), rand(193)), 0, 'ZPixmap', pack("C*", @p));
}
}
($d, $v, $image) = $x->req('GetImage', $win, (0, 0), 79, 24, 0xff, 'ZPixmap');
$image =~ tr/\0/ /;
$image =~ tr/ -~/./c;
for $row (0 .. 23)
{
print substr($image, $row * 80, 80), "\n";
}
$x->req('ClearArea', $win, (0, 0), 200, 200, 0);
$smallfid = $x->new_rsrc;
$x->req('OpenFont', $smallfid, '6x10');
$x->req('PolyText8', $win, $gc, 2, 20, [0, "Hello, "],
$smallfid, [-3, "world!"]);
$x->req('PolyText8', $win, $gc, 2, 35, [0, "Perl " x 300]);
#$largefid = $x->new_rsrc;
#$x->req('OpenFont', $largefid,
# '-*-*-medium-r-normal--14-*-*-*-c-*-jisx0208.1983-0');
#$x->req('PolyText16', $win, $gc, 2, 50, $largefid,
# [0, "\061\101\061\104\061\106\061\110\061\112\061\113\061\114\061\115"
# . "\061\116\061\117\061\122\061\125\061\130\061\133"]);
$x->req('ChangeGC', $gc, 'font' => $smallfid);
$x->req('ImageText8', $win, $gc, 2, 70, "Perl");
$x->req('ImageText16', $win, $gc, 2, 80, "\0P\0e\0r\0l");
if ($x->{'root_depth'} == 8) {
$cmap = $x->new_rsrc;
$x->req('CreateColormap', $cmap, $x->{'root_visual'}, $win, 'All');
$new_cmap = $x->new_rsrc;
$x->req('CopyColormapAndFree', $new_cmap, $cmap);
$x->req('FreeColormap', $cmap);
}
$cmap = $x->{'default_colormap'};
print join(", ", $x->req('ListInstalledColormaps', $win)), "\n";
print join(", ", $x->req('ListInstalledColormaps', $root_wid)), "\n";
($color1, $r, $g, $b) = $x->req('AllocColor', $cmap,
1 * 65535, 0 * 65535, 0 * 65535);
print "$color1 = ($r, $g, $b)\n";
($color2, $r1, $g1, $b1, $r2, $g2, $b2) =
$x->req('AllocNamedColor', $cmap, 'orange');
print "orange =~= $color2 =~= ($r1, $g1, $b1) =~= ($r2, $g2, $b2)\n";
if ($x->{'root_depth'} == 8) {
($pixels, $masks) = $x->req('AllocColorCells', $cmap, 1, 0, 0);
$color3 = $pixels->[0];
print "$color3\n";
($rm, $gm, $bm, @pixels) =
$x->req('AllocColorPlanes', $cmap, 1, (0,0,1), 0);
print "$rm|$gm|$bm = ", join(", ", @pixels), "\n";
$x->req('StoreColors', $cmap, [$color3 => (65535, 0, 0)],
[$pixels[0] => (0, 0, 0), 1]);
$x->req('StoreNamedColor', $cmap, $color3, 'salmon', 7);
}
@colors = $x->req('QueryColors', $cmap, 0 .. 255);
for $c (@colors)
{
printf "(0x%04x, 0x%04x, 0x%04x), ", @$c;
print "\n" unless ++$i % 3;
}
print "\n";
($r1, $g1, $b1, $r2, $g2, $b2) = $x->req('LookupColor', $cmap, 'bisque');
print "bisque =~= ($r1, $g1, $b1) =~= ($r2, $g2, $b2)\n";
$fg_pm = $x->new_rsrc;
$x->send('CreatePixmap', $fg_pm, $win, 1, 16, 16);
$mask_pm = $x->new_rsrc;
$x->send('CreatePixmap', $mask_pm, $win, 1, 16, 16);
$cursor_gc = $x->new_rsrc;
$x->send('CreateGC', $cursor_gc, $fg_pm, 'line_width' => 2,'foreground' => 0);
$x->send('PolyFillRectangle', $fg_pm, $cursor_gc, [(0, 0), 16, 16]);
$x->send('PolyFillRectangle', $mask_pm, $cursor_gc, [(0, 0), 16, 16]);
$x->send('ChangeGC', $cursor_gc, 'foreground' => 1);
$x->send('PolyArc', $mask_pm, $cursor_gc, [1, 1, 13, 13, 0, 360*64]);
$x->send('ChangeGC', $cursor_gc, 'line_style' => 'OnOffDash');
$x->send('PolyArc', $fg_pm, $cursor_gc, [1, 1, 13, 13, 0, 360*64]);
$cursor = $x->new_rsrc;
$x->send('CreateCursor', $cursor, $fg_pm, $mask_pm, (65535, 0, 0),
(45000, 45000, 45000), (8, 8));
$x->send('ChangeWindowAttributes', $win, 'cursor' => $cursor);
$x->send('FreePixmap', $fg_pm);
$x->send('FreePixmap', $mask_pm);
$x->send('FreeGC', $cursor_gc);
my_sleep 5;
$cursor_fnt = $x->new_rsrc;
$x->req('OpenFont', $cursor_fnt, 'cursor');
$new_cursor = $x->new_rsrc;
$x->req('CreateGlyphCursor', $new_cursor, $cursor_fnt, $cursor_fnt, 0, 1,
(65535, 65535, 65535), (0, 0, 0));
$x->req('CloseFont', $cursor_fnt);
$x->req('ChangeWindowAttributes', $win, 'cursor' => $new_cursor);
$x->req('FreeCursor', $cursor);
$cursor = $new_cursor;
for $p (0 .. 10)
{
$x->req('RecolorCursor', $cursor,
(65535, 65535 - $p*6553.5, 65535- $p*6553.5), (0, 0, 0));
my_sleep 1;
}
($w, $h) = $x->req('QueryBestSize', 'Cursor', $root_wid, 16, 16);
print "$w x $h is a good size for a cursor.\n";
for $ext ($x->req('ListExtensions'))
{
($major, $event, $error) = $x->req('QueryExtension', $ext);
print "$ext: request $major, event $event, error $error\n";
}
($old) = $x->req('GetKeyboardMapping', $x->{'max_keycode'}, 1);
#$x->req('ChangeKeyboardMapping', $x->{'max_keycode'} - 1, 4,
# [$Keysyms{"a"}, $Keysyms{"A"}, 0, 0],);
$i = $x->min_keycode;
for $ar ($x->req('GetKeyboardMapping', $x->{'min_keycode'},
$x->{'max_keycode'} - $x->{'min_keycode'} + 1))
# 10))
{
print "$i: ", join(", ", map($Keysyms_name{$_} || 'NoSymbol',
@$ar)), "\n";
$i++;
}
#$x->req('ChangeKeyboardMapping', $x->{'max_keycode'}, scalar(@$old), $old);
%kc = $x->req('GetKeyboardControl');
print join(" ", %kc), "\n";
$bp = $kc{'bell_pitch'};
$x->req('Bell', 100);
$x->req('ChangeKeyboardControl', 'bell_pitch' => 2 * $bp);
my_sleep 1;
$x->req('Bell', 100);
$x->req('ChangeKeyboardControl', 'bell_pitch' => $bp);
($num, $denom, $thresh) = $x->req('GetPointerControl');
print "Acceleration: $num/$denom; Threshold: $thresh\n";
$x->req('ChangePointerControl', 1, 0, $num * 2, $denom, $thresh);
my_sleep 2;
$x->req('ChangePointerControl', 1, 0, $num, $denom, $thresh);
($t_out, $interv, $pb, $allow_exp) = $x->req('GetScreenSaver');
print "Timeout: $t_out, Interval: $interv, Blanking: $pb, ";
print "Exposures: $allow_exp\n";
$x->req('SetScreenSaver', $t_out, $interv, $pb, $allow_exp);
($t_out, $interv, $pb, $allow_exp) = $x->req('GetScreenSaver');
print "Timeout: $t_out, Interval: $interv, Blanking: $pb, ";
print "Exposures: $allow_exp\n";
#$addr = pack("C4", (127, 0, 0, 1));
#sen('ChangeHosts', 'Insert', 'Internet', $addr);
($mode, @hosts) = $x->req('ListHosts');
for $ar (@hosts)
{
print "$ar->[0]: ", join(".", unpack("C4", $ar->[1])), "\n";
}
$x->req('SetAccessControl', $mode);
$x->req('SetCloseDownMode', 'Destroy');
#$x->req('KillClient', 0x200004b);
$x->req('RotateProperties', $win, 1, ($x->req('InternAtom', 'WM_NAME', 1)));
$x->req('ForceScreenSaver', 'Activate');
@map = $x->req('GetPointerMapping');
print join(", ", @map), "\n";
$x->req('SetPointerMapping', @map);
@map = $x->req('GetModifierMapping');
for $ar (@map)
{
print "[", join(",", @$ar), "]\n";
}
#$x->req('SetModifierMapping', @map);
$x->req('NoOperation', 4);
if ($x->{'root_depth'} == 8) {
$x->req('FreeColors', $cmap, 0, $color1, $color2, $color3, @pixels);
} else {
$x->FreeColors($cmap, 0, $color1, $color2);
}
$x->req('FreeGC', $fancy_gc);
$x->req('CloseFont', $fid);
$x->req('CloseFont', $smallfid);
#$x->req('CloseFont', $largefid);
$x->init_extensions;
if ($x->{'ext'}{"SHAPE"})
{
$x->req('ShapeSelectInput', $win, 1);
$x->req('ShapeRectangles', $win, 'Bounding', 'Set', (0, 0), 'UnSorted',
[(0, 0), 50, 50], [(50, 50), 50, 50]);
$shape_pm = $x->new_rsrc;
$x->req('CreatePixmap', $shape_pm, $win, 1, 100, 100);
$shape_gc = $x->new_rsrc;
$x->req('CreateGC', $shape_gc, $shape_pm, 'foreground' => 0);
$x->req('PolyFillRectangle', $shape_pm, $shape_gc, [0, 0, 100, 100]);
$x->req('ChangeGC', $shape_gc, 'foreground' => 1);
$x->req('PolyFillArc', $shape_pm, $shape_gc, [0, 0, 100, 100, 0, 360*64]);
$x->req('ShapeMask', $win, 'Bounding', 'Union', 100, 100, $shape_pm);
$x->req('ShapeCombine', $win, 'Bounding', 'Invert', 0, 0, $x->{'root'},
'Bounding');
$x->req('ShapeOffset', $win, 'Bounding', 25, 25);
print join(", ", $x->req('ShapeQueryExtents', $win)), "\n";
print $x->req('ShapeInputSelected', $win), "\n";
($ordering, @rects) = $x->req('ShapeGetRectangles', $win, 'Bounding');
print "Ordering: $ordering\n";
for $rr (@rects)
{
print "[", join(", ", @$rr), "], ";
}
print "\n";
}
# This should be last, since it's a REAL memory hog.
if ($x->{'ext'}{'BIG_REQUESTS'})
{
print "Maximum request length: ", $x->maximum_request_length * 4, "\n";
for $i (1 .. 65536)
{
push @points, int(rand(200)), int(rand(200));
}
$x->PolyPoint($win, $gc, 'Origin', @points);
}
#print_event(%e) while %e = $x->dequeue_event;
#$x->{'event_handler'} = \&print_event;
$x->req('FreeGC', $gc);
$done = 1;
$x->handle_input while 1;
#print_event(%e) while %e = $x->next_event
|