File Coverage

blib/lib/X11/Protocol.pm
Criterion Covered Total %
statement 27 465 5.8
branch 8 176 4.5
condition 1 51 1.9
subroutine 5 47 10.6
pod 27 38 71.0
total 68 777 8.7


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3             package X11::Protocol;
4              
5             # Copyright (C) 1997-2000, 2003-2006 Stephen McCamant. All rights
6             # reserved. This program is free software; you can redistribute and/or
7             # modify it under the same terms as Perl itself.
8              
9 1     1   1231 use Carp;
  1         2  
  1         97  
10 1     1   5 use strict;
  1         1  
  1         34  
11 1     1   5 use vars qw($VERSION $AUTOLOAD @ISA @EXPORT_OK);
  1         10  
  1         26131  
12             require Exporter;
13              
14             @ISA = ('Exporter');
15              
16             @EXPORT_OK = qw(pad padding padded hexi make_num_hash default_error_handler);
17              
18             $VERSION = "0.56";
19              
20             sub padding ($) {
21 0     0 1 0 my($x) = @_;
22 0         0 -$x & 3;
23             }
24              
25             sub pad ($) {
26 0     0 1 0 my($x) = @_;
27 0         0 padding(length($x));
28             }
29              
30             sub padded ($) {
31 0     0 1 0 my $l = length($_[0]);
32 0         0 "a" . $l . "x" x (-$l & 3);
33             }
34              
35             sub hexi ($) {
36 0     0 1 0 "0x" . sprintf("%x", $_[0]);
37             }
38              
39              
40             length(pack("L", 0)) == 4 or croak "can't happen";
41              
42             my($Byte_Order, $Card16, $Int16, $Card8, $Int8);
43              
44             if (pack("L", 1) eq "\0\0\0\1") {
45             $Byte_Order = 'B';
46             $Int8 = "xxxc";
47             $Card8 = "xxxC";
48             $Int16 = "xxs";
49             $Card16 = "xxS";
50             } elsif (pack("L", 1) eq "\1\0\0\0") {
51             $Byte_Order = 'l';
52             $Int8 = "cxxx";
53             $Card8 = "Cxxx";
54             $Int16 = "sxx";
55             $Card16 = "Sxx";
56             } else {
57             croak "Can't determine byte order!\n";
58             }
59              
60             my($Default_Display);
61              
62             if ($^O eq "MSWin32") {
63             $Default_Display = "localhost";
64             } else {
65             $Default_Display = "unix";
66             }
67              
68             sub give {
69 0     0 0 0 my($self) = shift;
70 0         0 $self->{'connection'}->give(@_);
71             }
72              
73             sub get {
74 0     0 0 0 my($self) = shift;
75 0         0 return $self->{'connection'}->get(@_);
76             }
77              
78             sub flush {
79 0     0 0 0 my $self = shift;
80 0         0 $self->{'connection'}->flush();
81             }
82              
83             my(%Const) =
84             (
85             'VisualClass' => ['StaticGray', 'GrayScale', 'StaticColor',
86             'PseudoColor', 'TrueColor', 'DirectColor'],
87             'BitGravity' => ['Forget', 'Static', 'NorthWest', 'North',
88             'NorthEast', 'West', 'Center', 'East',
89             'SouthWest', 'South', 'SouthEast'],
90             'WinGravity' => ['Unmap', 'Static', 'NorthWest', 'North',
91             'NorthEast', 'West', 'Center', 'East', 'SouthWest',
92             'South', 'SouthEast'],
93             'EventMask' => ['KeyPress', 'KeyRelease', 'ButtonPress', 'ButtonRelease',
94             'EnterWindow', 'LeaveWindow', 'PointerMotion',
95             'PointerMotionHint', 'Button1Motion', 'Button2Motion',
96             'Button3Motion', 'Button4Motion', 'Button5Motion',
97             'ButtonMotion', 'KeymapState', 'Exposure',
98             'VisibilityChange', 'StructureNotify', 'ResizeRedirect',
99             'SubstructureNotify', 'SubstructureRedirect',
100             'FocusChange', 'PropertyChange', 'ColormapChange',
101             'OwnerGrabButton'],
102             'Events' => [0, 0, 'KeyPress' , 'KeyRelease', 'ButtonPress',
103             'ButtonRelease', 'MotionNotify', 'EnterNotify',
104             'LeaveNotify', 'FocusIn', 'FocusOut', 'KeymapNotify',
105             'Expose', 'GraphicsExposure', 'NoExposure',
106             'VisibilityNotify', 'CreateNotify', 'DestroyNotify',
107             'UnmapNotify', 'MapNotify', 'MapRequest',
108             'ReparentNotify', 'ConfigureNotify', 'ConfigureRequest',
109             'GravityNotify', 'ResizeRequest', 'CirculateNotify',
110             'CirculateRequest', 'PropertyNotify', 'SelectionClear',
111             'SelectionRequest', 'SelectionNotify',
112             'ColormapNotify', 'ClientMessage', 'MappingNotify'],
113             'PointerEvent' => [0, 0, 'ButtonPress', 'ButtonRelease',
114             'EnterWindow', 'LeaveWindow', 'PointerMotion',
115             'PointerMotionHint', 'Button1Motion',
116             'Button2Motion', 'Button3Motion', 'Button4Motion',
117             'Button5Motion', 'ButtonMotion', 'KeymapState'],
118             'DeviceEvent' => ['KeyPress', 'KeyRelease', 'ButtonPress',
119             'ButtonRelease', 0, 0, 'PointerMotion',
120             'PointerMotionHint', 'Button1Motion',
121             'Button2Motion', 'Button3Motion', 'Button4Motion',
122             'Button5Motion', 'ButtonMotion'],
123             'KeyMask' => ['Shift', 'Lock', 'Control', 'Mod1', 'Mod2', 'Mod3',
124             'Mod4', 'Mod5'],
125             'Significance' => ['LeastSignificant', 'MostSignificant'],
126             'BackingStore' => ['Never', 'WhenMapped', 'Always'],
127             'Bool' => ['False', 'True'],
128             'Class' => ['CopyFromParent', 'InputOutput', 'InputOnly'],
129             'MapState' => ['Unmapped', 'Unviewable', 'Viewable'],
130             'StackMode' => ['Above', 'Below', 'TopIf', 'BottomIf', 'Opposite'],
131             'CirculateDirection' => ['RaiseLowest', 'LowerHighest'],
132             'ChangePropertyMode' => ['Replace', 'Prepend', 'Append'],
133             'CrossingNotifyDetail' => ['Ancestor', 'Virtual', 'Inferior',
134             'Nonlinear', 'NonlinearVirtual'],
135             'CrossingNotifyMode' => ['Normal', 'Grab', 'Ungrab'],
136             'FocusDetail' => ['Ancestor', 'Virtual', 'Inferior', 'Nonlinear',
137             'NonlinearVirtual', 'Pointer', 'PointerRoot',
138             'None'],
139             'FocusMode' => ['Normal', 'Grab', 'Ungrab', 'WhileGrabbed'],
140             'VisibilityState' => ['Unobscured', 'PartiallyObscured',
141             'FullyObscured'],
142             'CirculatePlace' => ['Top', 'Bottom'],
143             'PropertyNotifyState' => ['NewValue', 'Deleted'],
144             'ColormapNotifyState' => ['Uninstalled', 'Installed'],
145             'MappingNotifyRequest' => ['Modifier', 'Keyboard', 'Pointer'],
146             'SyncMode' => ['Synchronous', 'Asynchronous'],
147             'GrabStatus' => ['Success', 'AlreadyGrabbed', 'InvalidTime',
148             'NotViewable', 'Frozen'],
149             'AllowEventsMode' => ['AsyncPointer', 'SyncPointer', 'ReplayPointer',
150             'AsyncKeyboard', 'SyncKeyboard',
151             'ReplayKeyboard', 'AsyncBoth', 'SyncBoth'],
152             'InputFocusRevertTo' => ['None', 'PointerRoot', 'Parent'],
153             'DrawDirection' => ['LeftToRight', 'RightToLeft'],
154             'ClipRectangleOrdering' => ['UnSorted', 'YSorted', 'YXSorted',
155             'YXBanded'],
156             'CoordinateMode' => ['Origin', 'Previous'],
157             'PolyShape' => ['Complex', 'Nonconvex', 'Convex'],
158             'ImageFormat' => ['Bitmap', 'XYPixmap', 'ZPixmap'],
159             'SizeClass' => ['Cursor', 'Tile', 'Stipple'],
160             'LedMode' => ['Off', 'On'],
161             'AutoRepeatMode' => ['Off', 'On', 'Default'],
162             'ScreenSaver' => ['No', 'Yes', 'Default'],
163             'HostChangeMode' => ['Insert', 'Delete'],
164             'HostFamily' => ['Internet', 'DECnet', 'Chaos', 0, 0,
165             'ServerInterpreted', 'InternetV6'],
166             'AccessMode' => ['Disabled', 'Enabled'],
167             'CloseDownMode' => ['Destroy', 'RetainPermanent', 'RetainTemporary'],
168             'ScreenSaverAction' => ['Reset', 'Activate'],
169             'MappingChangeStatus' => ['Success', 'Busy', 'Failed'],
170             'GCFunction' => ['Clear', 'And', 'AndReverse', 'Copy',
171             'AndInverted', 'NoOp', 'Xor', 'Or', 'Nor', 'Equiv',
172             'Invert', 'OrReverse', 'CopyInverted', 'OrInverted',
173             'Nand', 'Set'],
174             'GCLineStyle' => ['Solid', 'OnOffDash', 'DoubleDash'],
175             'GCCapStyle' => ['NotLast', 'Butt', 'Round', 'Projecting'],
176             'GCJoinStyle' => ['Miter', 'Round', 'Bevel'],
177             'GCFillStyle' => ['Solid', 'Tiled', 'Stippled', 'OpaqueStippled'],
178             'GCFillRule' => ['EvenOdd', 'Winding'],
179             'GCSubwindowMode' => ['ClipByChildren', 'IncludeInferiors'],
180             'GCArcMode' => ['Chord', 'PieSlice'],
181             'Error' => [0, 'Request', 'Value', 'Window', 'Pixmap', 'Atom',
182             'Cursor', 'Font', 'Match', 'Drawable', 'Access', 'Alloc',
183             'Colormap', 'GContext', 'IDChoice', 'Name', 'Length',
184             'Implementation'],
185             );
186              
187             my(%Const_num) = (); # Filled in dynamically
188              
189             sub interp {
190 0     0 1 0 my($self) = shift;
191 0 0       0 return $_[1] unless $self->{'do_interp'};
192 0         0 return $self->do_interp(@_);
193             }
194              
195             sub do_interp {
196 0     0 0 0 my $self = shift;
197 0         0 my($type, $num) = @_;
198 0 0 0     0 carp "Unknown constant type `$type'\n"
199             unless exists $self->{'const'}{$type}
200             or exists $self->{'ext_const'}{$type};
201 0 0       0 return $num if $num < 0;
202 0   0     0 return $self->{'const'}{$type}[$num] || $self->{'ext_const'}{$type}[$num];
203             }
204              
205             sub make_num_hash {
206 0     0 1 0 my($from) = @_;
207 0         0 my(%hash);
208 0         0 @hash{@$from} = (0 .. $#{$from});
  0         0  
209 0         0 return %hash;
210             }
211              
212             sub num ($$) {
213 0     0 1 0 my($self) = shift;
214 0         0 my($type, $x) = @_;
215 0 0 0     0 carp "Unknown constant type `$type'\n"
216             unless exists $self->{'const'}{$type}
217             or exists $self->{'ext_const'}{$type};
218 0 0       0 $self->{'const_num'}{$type} = {make_num_hash($self->{'const'}{$type})}
219             unless exists $self->{'const_num'}{$type};
220 0 0       0 if (exists $self->{'const_num'}{$type}{$x}) {
    0          
221 0         0 return $self->{'const_num'}{$type}{$x};
222             } elsif (exists $self->{'ext_const_num'}{$type}{$x}) {
223 0         0 return $self->{'ext_const_num'}{$type}{$x};
224             } else {
225 0         0 return $x;
226             }
227             }
228              
229             my(@Attributes_ValueMask) =
230             (["background_pixmap", sub {$_[1] = 0 if $_[1] eq "None";
231             $_[1] = 1 if $_[1] eq "ParentRelative";
232             pack "L", $_[1];}],
233             ["background_pixel", sub {pack "L", $_[1];}],
234             ["border_pixmap", sub {$_[1] = 0 if $_[1] eq "CopyFromParent";
235             pack "L", $_[1];}],
236             ["border_pixel", sub {pack "L", $_[1];}],
237             ["bit_gravity", sub {$_[1] = $_[0]->num('BitGravity', $_[1]);
238             pack $Card8, $_[1];}],
239             ["win_gravity", sub {$_[1] = $_[0]->num('WinGravity', $_[1]);
240             pack $Card8, $_[1];}],
241             ["backing_store", sub {$_[1] = 0 if $_[1] eq "NotUseful";
242             $_[1] = 1 if $_[1] eq "WhenMapped";
243             $_[1] = 2 if $_[1] eq "Always";
244             pack $Card8, $_[1];}],
245             ["backing_planes", sub {pack "L", $_[1];}],
246             ["backing_pixel", sub {pack "L", $_[1];}],
247             ["override_redirect", sub {pack $Card8, $_[1];}],
248             ["save_under", sub {pack $Card8, $_[1];}],
249             ["event_mask", sub {pack "L", $_[1];}],
250             ["do_not_propagate_mask", sub {pack "L", $_[1];}],
251             ["colormap", sub {$_[1] = 0 if $_[1] eq "CopyFromParent";
252             pack "L", $_[1];}],
253             ["cursor", sub {$_[1] = 0 if $_[1] eq "None";
254             pack "L", $_[1];}]);
255              
256             my(@Configure_ValueMask) =
257             (["x", sub {pack $Int16, $_[1];}],
258             ["y", sub {pack $Int16, $_[1];}],
259             ["width", sub {pack $Card16, $_[1];}],
260             ["height", sub {pack $Card16, $_[1];}],
261             ["border_width", sub {pack $Card16, $_[1];}],
262             ["sibling", sub {pack "L", $_[1];}],
263             ["stack_mode", sub {$_[1] = $_[0]->num('StackMode', $_[1]);
264             pack $Card8, $_[1];}]);
265              
266             my(@GC_ValueMask) =
267             (['function', sub {
268             $_[1] = $_[0]->num('GCFunction', $_[1]);
269             $_[1] = pack($Card8, $_[1]);
270             }, sub {}],
271             ['plane_mask', sub {$_[1] = pack("L", $_[1]);}, sub {}],
272             ['foreground', sub {$_[1] = pack("L", $_[1]);}, sub {}],
273             ['background', sub {$_[1] = pack("L", $_[1]);}, sub {}],
274             ['line_width', sub {$_[1] = pack($Card16, $_[1]);}, sub {}],
275             ['line_style', sub {
276             $_[1] = $_[0]->num('GCLineStyle', $_[1]);
277             $_[1] = pack($Card8, $_[1]);
278             }, sub {}],
279             ['cap_style', sub {
280             $_[1] = $_[0]->num('GCCapStyle', $_[1]);
281             $_[1] = pack($Card8, $_[1]);
282             }, sub {}],
283             ['join_style', sub {
284             $_[1] = $_[0]->num('GCJoinStyle', $_[1]);
285             $_[1] = pack($Card8, $_[1]);
286             }, sub {}],
287             ['fill_style', sub {
288             $_[1] = $_[0]->num('GCFillStyle', $_[1]);
289             $_[1] = pack($Card8, $_[1]);
290             }, sub {}],
291             ['fill_rule', sub {
292             $_[1] = $_[0]->num('GCFillRule', $_[1]);
293             $_[1] = pack($Card8, $_[1]);
294             }, sub {}],
295             ['tile', sub {$_[1] = pack("L", $_[1]);}, sub {}],
296             ['stipple', sub {$_[1] = pack("L", $_[1]);}, sub {}],
297             ['tile_stipple_x_origin', sub {$_[1] = pack($Int16, $_[1]);}, sub {}],
298             ['tile_stipple_y_origin', sub {$_[1] = pack($Int16, $_[1]);}, sub {}],
299             ['font', sub {$_[1] = pack("L", $_[1]);}, sub {}],
300             ['subwindow_mode', sub {
301             $_[1] = $_[0]->num('GCSubwindowMode', $_[1]);
302             $_[1] = pack($Card8, $_[1]);
303             }, sub {}],
304             ['graphics_exposures', sub {$_[1] = pack($Card8, $_[1]);}, sub {}],
305             ['clip_x_origin', sub {$_[1] = pack($Int16, $_[1]);}, sub {}],
306             ['clip_y_origin', sub {$_[1] = pack($Int16, $_[1]);}, sub {}],
307             ['clip_mask', sub {
308             $_[1] = 0 if $_[1] eq "None";
309             $_[1] = pack("L", $_[1]);
310             }, sub {}],
311             ['dash_offset', sub {$_[1] = pack($Card16, $_[1]);}, sub {}],
312             ['dashes', sub {$_[1] = pack($Card8, $_[1]);}, sub {}],
313             ['arc_mode', sub {
314             $_[1] = $_[0]->num('GCArcMode', $_[1]);
315             $_[1] = pack($Card8, $_[1]);
316             }, sub {}]);
317              
318             my(@KeyboardControl_ValueMask) =
319             (['key_click_percent', sub {$_[1] = pack($Int8, $_[1]);}],
320             ['bell_percent', sub {$_[1] = pack($Int8, $_[1]);}],
321             ['bell_pitch', sub {$_[1] = pack($Int16, $_[1])}],
322             ['bell_duration', sub {$_[1] = pack($Int16, $_[1])}],
323             ['led', sub {$_[1] = pack($Card8, $_[1])}],
324             ['led_mode', sub {$_[1] = $_[0]->num('LedMode', $_[1]);
325             $_[1] = pack($Card8, $_[1]);}],
326             ['key', sub {$_[1] = pack($Card8, $_[1]);}],
327             ['auto_repeat_mode', sub {$_[1] = $_[0]->num('AutoRepeatMode', $_[1]);
328             $_[1] = pack($Card8, $_[1]);}]);
329              
330             my(@Events) =
331             (0, 0,
332             # if ($code >= 2 and $code <= 5) # (Key|Button)(Press|Release)
333             (["xCxxLLLLssssSCx", 'detail', 'time', 'root', 'event',
334             ['child', ['None']], 'root_x', 'root_y', 'event_x', 'event_y',
335             'state', 'same_screen']) x 4,
336             # elsif ($code == 6) # MotionNotify
337             ["xCxxLLLLssssSCx", ['detail', ['Normal', 'Hint']], 'time', 'root',
338             'event', ['child', ['None']], 'root_x', 'root_y', 'event_x',
339             'event_y', 'state', 'same_screen'],
340             # elsif ($code == 7 or $code == 8) # (Enter|Leave)Notify
341             (["xCxxLLLLssssSCC", ['detail', 'CrossingNotifyDetail'], 'time',
342             'root', 'event', ['child', ['None']], 'root_x', 'root_y',
343             'event_x', 'event_y', 'state', ['mode', 'CrossingNotifyMode'],
344             [0, sub {$_[0]{'flags'} |= 1 if $_[0]{'focus'};
345             $_[0]{'flags'} |= 2 if $_[0]{'same_screen'};}],
346             'flags',
347             [sub {$_[0]{'focus'} = $_[0]{'flags'} & 1;
348             $_[0]{'same_screen'} = (($_[0]{'flags'} & 2) != 0)}, 0]
349             ]) x 2,
350             # elsif ($code == 9 or $code == 10) # Focus(In|Out)
351             (["xCxxLCxxxxxxxxxxxxxxxxxxxxxxx", ['detail', 'FocusDetail'], 'event',
352             ['mode', 'FocusMode']]) x 2,
353             # elsif ($code == 11) # KeymapNotify (weird)
354             [sub {
355             my($self, $data, %h) = @_;
356             my($keys) = "\0" . substr($data, 1, 31);
357             $h{'keys'} = $keys;
358             delete $h{sequence_number};
359             return %h;
360             }, sub {
361             my $self = shift;
362             my(%h) = @_;
363             my($data) = "\0" . substr($h{"keys"}, 1, 31);
364             return ($data, 0);
365             }],
366             # elsif ($code == 12) # Expose
367             ["xxxxLSSSSSxxxxxxxxxxxxxx", 'window', 'x', 'y', 'width', 'height',
368             'count'],
369             # elsif ($code == 13) # GraphicsExposure
370             ["xxxxLSSSSSSCxxxxxxxxxxx", 'drawable', 'x', 'y', 'width', 'height',
371             'minor_opcode', 'count', 'major_opcode'],
372             # elsif ($code == 14) # NoExposure
373             ["xxxxLSCxxxxxxxxxxxxxxxxxxxxx", 'drawable', 'minor_opcode',
374             'major_opcode'],
375             # elsif ($code == 15) # VisibilityNotify
376             ["xxxxLCxxxxxxxxxxxxxxxxxxxxxxx", 'window', ['state', 'VisibilityState']],
377             # elsif ($code == 16) # CreateNotify
378             ["xxxxLLssSSSCxxxxxxxxx", 'parent', 'window', 'x', 'y', 'width',
379             'height', 'border_width', 'override_redirect'],
380             # elsif ($code == 17) # DestroyNotify
381             ["xxxxLLxxxxxxxxxxxxxxxxxxxx", 'event', 'window'],
382             # elsif ($code == 18) # UnmapNotify
383             ["xxxxLLCxxxxxxxxxxxxxxxxxxx", 'event', 'window', 'from_configure'],
384             # elsif ($code == 19) # MapNotify
385             ["xxxxLLCxxxxxxxxxxxxxxxxxxx", 'event', 'window', 'override_redirect'],
386             # elsif ($code == 20) # MapRequest
387             ["xxxxLLxxxxxxxxxxxxxxxxxxxx", 'parent', 'window'],
388             # elsif ($code == 21) # ReparentNotify
389             ["xxxxLLLssCxxxxxxxxxxx", 'event', 'window', 'parent', 'x', 'y',
390             'override_redirect'],
391             # elsif ($code == 22) # ConfigureNotify
392             ["xxxxLLLssSSSCxxxxx", 'event', 'window', 'above_sibling', 'x', 'y',
393             'width', 'height', 'border_width', 'override_redirect'],
394             # elsif ($code == 23) # ConfigureRequest
395             ["xCxxLLLssSSSSxxxx", ['stack_mode', 'StackMode'], 'parent', 'window',
396             [0, sub {
397             my($m) = 0;
398             $m = 1 if exists $_[0]{'x'};
399             $m |= 2 if exists $_[0]{'y'};
400             $m |= 4 if exists $_[0]{'width'};
401             $m |= 8 if exists $_[0]{'height'};
402             $m |= 16 if exists $_[0]{'border_width'};
403             $m |= 32 if exists $_[0]{'sibling'};
404             $m |= 64 if exists $_[0]{'stack_mode'};
405             $_[0]{'mask'} = $m;
406             }],
407             ['sibling', ['None']], 'x', 'y', 'width', 'height', 'border_width',
408             'mask',
409             [sub {
410             my($m) = $_[0]{'mask'};
411             delete $_[0]{'x'} unless $m & 1;
412             delete $_[0]{'y'} unless $m & 2;
413             delete $_[0]{'width'} unless $m & 4;
414             delete $_[0]{'height'} unless $m & 8;
415             delete $_[0]{'border_width'} unless $m & 16;
416             delete $_[0]{'sibling'} unless $m & 32;
417             delete $_[0]{'stack_mode'} unless $m & 64;
418             }, 0]],
419             # elsif ($code == 24) # GravityNotify
420             ["xxxxLLssxxxxxxxxxxxxxxxx", 'event', 'window', 'x', 'y'],
421             # elsif ($code == 25) # ResizeRequest
422             ["xxxxLSSxxxxxxxxxxxxxxxxxxxx", 'window', 'width', 'height'],
423             # elsif ($code == 26 or $code == 27) # Circulate(Notify|Request)
424             (["xxxxLLxxxxCxxxxxxxxxxxxxxx", 'event', 'window',
425             ['place', 'CirculatePlace']]) x 2,
426             # elsif ($code == 28) # PropertyNotify
427             ["xxxxLLLCxxxxxxxxxxxxxxx", 'window', 'atom', 'time',
428             ['state', 'PropertyNotifyState']],
429             # elsif ($code == 29) # SelectionClear
430             ["xxxxLLLxxxxxxxxxxxxxxxx", 'time', 'owner', 'selection'],
431             # elsif ($code == 30) # SelectionRequest
432             ["xxxxLLLLLLxxxx", ['time', ['CurrentTime']], 'owner', 'requestor',
433             'selection', 'target', ['property', ['None']]],
434             # elsif ($code == 31) # SelectionNotify
435             ["xxxxLLLLLxxxxxxxx", ['time', ['CurrentTime']], 'requestor', 'selection',
436             'target', ['property', ['None']]],
437             # elsif ($code == 32) # ColormapNotify
438             ["xxxxLLCCxxxxxxxxxxxxxxxxxx", 'window', ['colormap', ['None']], 'new',
439             ['state', 'ColormapNotifyState']],
440             # elsif ($code == 33) # ClientMessage
441             [sub {
442             my($self, $data, %h) = @_;
443             my($format) = unpack("C", substr($data, 1, 1));
444             my($win, $type) = unpack("LL", substr($data, 4, 8));
445             my($dat) = substr($data, 12, 20);
446             return (%h, 'window' => $win, 'type' => $type, 'data' => $dat,
447             'format' => $format);
448             }, sub {
449             my $self = shift;
450             my(%h) = @_;
451             my($data) = pack("xCxxLL", $h{'format'}, $h{window}, $h{type})
452             . substr($h{data}, 0, 20);
453             return ($data, 1);
454             }],
455             # elsif ($code == 34) # MappingNotify
456             ["xxxxCCCxxxxxxxxxxxxxxxxxxxxxxxxx", ['request', 'MappingNotifyRequest'],
457             'first_keycode', 'count']
458             );
459              
460             sub unpack_event {
461 0     0 1 0 my $self = shift;
462 0         0 my($data) = @_;
463 0         0 my($code, $detail, $seq) = unpack("CCS", substr($data, 0, 4));
464 0         0 my($name) = $self->do_interp('Events', $code & 127);
465 0         0 my(%ret);
466 0 0       0 $ret{'synthetic'} = 1 if $code & 128; $code &= 127;
  0         0  
467 0         0 $ret{'name'} = $name;
468 0         0 $ret{'code'} = $code;
469 0         0 $ret{'sequence_number'} = $seq;
470 0         0 my($info);
471 0   0     0 $info = $self->{'events'}[$code] || $self->{'ext_events'}[$code];
472              
473 0 0       0 if ($info) {
474 0         0 my(@i) = @$info;
475 0 0       0 if (ref $i[0] eq "CODE") {
476 0         0 %ret = &{$i[0]}($self, $data, %ret);
  0         0  
477             } else {
478 0         0 my($format, @fields) = @i;
479 0         0 my(@unpacked) = unpack($format, $data);
480 0         0 my($f);
481 0         0 for $f (@fields) {
482 0 0       0 if (not ref $f) {
483 0         0 $ret{$f} = shift @unpacked;
484             } else {
485 0         0 my(@f) = @$f;
486 0 0 0     0 if (ref $f[0] eq "CODE" or ref $f[1] eq "CODE") {
    0          
487 0 0       0 &{$f[0]}(\%ret) if $f[0];
  0         0  
488             } elsif (not ref $f[1]) {
489 0         0 $ret{$f[0]} = $self->interp($f[1], shift @unpacked);
490             } else {
491 0         0 my($v) = shift @unpacked;
492 0 0 0     0 $v = $f[1][$v] if $self->{'do_interp'} and
      0        
493             ($v == 0 or $v == 1 && $f[1][1]);
494 0         0 $ret{$f[0]} = $v;
495             }
496             }
497             }
498             }
499             } else {
500 0         0 carp "Unknown event (code $code)!";
501 0         0 $ret{'data'} = $data;
502             }
503 0         0 return %ret;
504             }
505              
506             sub pack_event {
507 0     0 1 0 my $self = shift;
508 0         0 my(%h) = @_;
509 0         0 my($code) = $h{code};
510 0 0       0 $code = $self->num('Events', $h{name}) unless exists $h{code};
511 0 0       0 $h{sequence_number} = 0 unless $h{sequence_number};
512 0 0       0 $h{synthetic} = 0 unless $h{synthetic};
513 0         0 my($data, $info);
514 0         0 my($do_seq) = 1;
515 0   0     0 $info = $self->{'events'}[$code] || $self->{'ext_events'}[$code];
516              
517 0 0       0 if ($info) {
518 0         0 my(@i) = @$info;
519 0 0       0 if (ref $i[0] eq "CODE") {
520 0         0 ($data, $do_seq) = &{$i[1]}($self, %h);
  0         0  
521             } else {
522 0         0 my($format, @fields) = @i;
523 0         0 my(@topack) = ();
524 0         0 my($f);
525 0         0 for $f (@fields) {
526 0 0       0 if (not ref $f) {
527 0         0 push @topack, $h{$f};
528             } else {
529 0         0 my(@f) = @$f;
530 0 0 0     0 if (ref $f[0] eq "CODE" or ref $f[1] eq "CODE") {
    0          
531 0 0       0 &{$f[1]}(\%h) if $f[1];
  0         0  
532             } elsif (not ref $f[1]) {
533 0         0 push @topack, $self->num($f[1], $h{$f[0]});
534             } else {
535 0         0 my($v) = $h{$f[0]};
536 0 0       0 $v = 0 if $v eq $f[1][0];
537 0 0 0     0 $v = 1 if $v eq $f[1][1] and $f[1][1];
538 0         0 push @topack, $v;
539             }
540             }
541             }
542 0         0 $data = pack($format, @topack);
543             }
544 0 0       0 substr($data, 2, 2) = pack("S", $h{sequence_number}) if $do_seq;
545 0 0       0 substr($data, 0, 1) = pack("C", $code | ($h{synthetic} ? 128 : 0));
546             } else {
547 0         0 carp "Unknown event (code $code)!";
548 0         0 return pack("Cxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", $code);
549             }
550 0         0 return $data;
551             }
552              
553             sub unpack_event_mask {
554 0     0 1 0 my $self = shift;
555 0         0 my($x) = @_;
556 0         0 my(@ans, $i);
557 0         0 for $i (@{$Const{'EventMask'}}) {
  0         0  
558 0 0       0 push @ans, $i if $x & 1;
559 0         0 $x >>= 1;
560             }
561 0         0 @ans;
562             }
563              
564             sub pack_event_mask {
565 0     0 1 0 my $self = shift;
566 0         0 my(@x) = @_;
567 0         0 my($i, $mask);
568 0         0 $mask = 0;
569 0         0 for $i (@x) {
570 0         0 $mask |= 1 << $self->num('EventMask', $i);
571             }
572 0         0 return $mask;
573             }
574              
575             sub format_error_msg {
576 0     0 0 0 my($self, $data) = @_;
577 0         0 my($type, $seq, $info, $minor_op, $major_op)
578             = unpack("xCSLSCxxxxxxxxxxxxxxxxxxxxx", $data);
579 0         0 my($t);
580 0   0     0 $t = join("", "Protocol error: bad $type (",
581             $self->do_interp('Error', $type), "); ",
582             "Sequence Number $seq\n",
583             " Opcode ($major_op, $minor_op) = ",
584             ($self->do_interp('Request', $major_op)
585             or $self->{'ext_request'}{$major_op}[$minor_op][0]), "\n");
586 0 0 0     0 if ($type == 2) {
    0          
587 0         0 $t .= " Bad value $info (" . hexi($info) . ")\n";
588             } elsif ($self->{'error_type'}[$type] == 1 or
589             $self->{'ext_error_type'}[$type] == 1) {
590 0         0 $t .= " Bad resource $info (" . hexi($info) . ")\n";
591             }
592 0         0 return $t;
593             }
594              
595             sub default_error_handler {
596 0     0 0 0 my($self, $data) = @_;
597 0         0 croak($self->format_error_msg($data));
598             }
599              
600             sub handle_input {
601 0     0 1 0 my $self = shift;
602 0         0 my($type_b, $type);
603 0         0 $self->flush;
604 0         0 $type_b = $self->get(1);
605 0         0 $type = unpack "C", $type_b;
606 0 0       0 if ($type == 0) {
    0          
607 0         0 my $data = $type_b . $self->get(31);
608 0         0 &{$self->{'error_handler'}}($self, $data);
  0         0  
609 0         0 $self->{'error_seq'} = unpack("xxSx28", $data);
610 0         0 return -1;
611             } elsif ($type > 1) {
612 0 0       0 if ($self->{'event_handler'} eq "queue") {
613 0         0 push @{$self->{'event_queue'}}, $type_b . $self->get(31);
  0         0  
614             } else {
615 0         0 &{$self->{'event_handler'}}
  0         0  
616             ($self->unpack_event($type_b . $self->get(31)));
617             }
618 0         0 return -$type;
619             } else {
620             # $type == 1
621 0         0 my($data) = $self->get(31);
622 0         0 my($seq, $len) = unpack "SL", substr($data, 1, 6);
623 0         0 $data = join("", $type_b, $data, $self->get(4 * $len));
624 0 0       0 if ($self->{'replies'}->{$seq}) {
625 0         0 ${$self->{'replies'}->{$seq}} = $data;
  0         0  
626 0         0 return $seq;
627             } else {
628 0         0 carp "Unexpected reply to request $seq",
629             " (of $self->{'sequence_num'})";
630 0         0 return $seq;
631             }
632             }
633             }
634              
635             sub handle_input_for {
636 0     0 0 0 my($self, $seq) = @_;
637 0         0 for (;;) {
638 0         0 my $stat = $self->handle_input();
639 0 0       0 return if $stat == $seq; # Normal reply for this request
640 0 0 0     0 return if $stat == -1 && $self->{'error_seq'} == $seq; # Error for this
641             }
642             }
643              
644             sub dequeue_event {
645 0     0 1 0 my $self = shift;
646 0         0 my($data) = shift @{$self->{'event_queue'}};
  0         0  
647 0 0       0 return () unless $data;
648 0         0 return $self->unpack_event($data);
649             }
650              
651             sub next_event {
652 0     0 1 0 my $self = shift;
653 0 0       0 if ($self->{'event_handler'} ne "queue") {
654 0         0 carp "Setting event_handler to 'queue' to avoid infinite loop",
655             "in next_event()";
656 0         0 $self->{'event_handler'} = "queue";
657             }
658 0         0 my(%e);
659 0         0 $self->handle_input until %e = $self->dequeue_event;
660 0         0 return %e;
661             }
662              
663             sub next_sequence {
664 0     0 0 0 my $self = shift;
665 0         0 my $ret = $self->{'sequence_num'}++;
666 0         0 $self->{'sequence_num'} &= 0xffff;
667 0         0 return $ret;
668             }
669              
670             sub add_reply {
671 0     0 1 0 my $self = shift;
672 0         0 my($seq, $var) = @_;
673 0         0 $self->{'replies'}->{$seq} = $var;
674             }
675              
676             sub delete_reply {
677 0     0 1 0 my $self = shift;
678 0         0 my($seq) = @_;
679 0         0 delete $self->{'replies'}->{$seq};
680             }
681              
682             my(@Requests) =
683             (0,
684             ['CreateWindow', sub {
685             my $self = shift;
686             my($wid, $parent, $class, $depth, $visual, $x, $y, $width,
687             $height, $border_width, %values) = @_;
688             my($mask, $i, @values);
689             $mask = 0;
690             for $i (0 .. 14) {
691             if (exists $values{$Attributes_ValueMask[$i][0]}) {
692             $mask |= (1 << $i);
693             push @values,
694             &{$Attributes_ValueMask[$i][1]}
695             ($self, $values{$Attributes_ValueMask[$i][0]});
696             }
697             }
698             $visual = 0 if $visual eq 'CopyFromParent';
699             $class = $self->num('Class', $class);
700             return pack("LLssSSSSLL", $wid, $parent, $x, $y, $width, $height,
701             $border_width, $class, $visual, $mask) .
702             join("", @values), $depth;
703             }],
704              
705             ['ChangeWindowAttributes', sub {
706             my $self = shift;
707             my($wid, %values) = @_;
708             my($mask, $i, @values);
709             $mask = 0;
710             for $i (0 .. 14) {
711             if (exists $values{$Attributes_ValueMask[$i][0]}) {
712             $mask |= (1 << $i);
713             push @values,
714             &{$Attributes_ValueMask[$i][1]}
715             ($self, $values{$Attributes_ValueMask[$i][0]});
716             }
717             }
718             return pack("LL", $wid, $mask) . join "", @values;
719             }],
720              
721             ['GetWindowAttributes', sub {
722             my $self = shift;
723             my($wid) = @_;
724             return pack "L", $wid;
725             }, sub {
726             my $self = shift;
727             my($data) = @_;
728             my($backing_store, $visual, $class, $bit_gravity, $win_gravity,
729             $backing_planes, $backing_pixel, $save_under, $map_is_installed,
730             $map_state, $override_redirect, $colormap, $all_event_masks,
731             $your_event_mask, $do_not_propagate_mask)
732             = unpack("xCxxxxxxLSCCLLCCCCLLLS", $data);
733              
734             $colormap = "None" if !$colormap and $self->{'do_interp'};
735              
736             return ("backing_store" => $self->interp('BackingStore', $backing_store),
737             "visual" => $visual,
738             "class" => $self->interp('Class', $class),
739             "bit_gravity" => $self->interp('BitGravity', $bit_gravity),
740             "win_gravity" => $self->interp('WinGravity', $win_gravity),
741             "backing_planes" => $backing_planes,
742             "backing_pixel" => $backing_pixel, "save_under" => $save_under,
743             "map_is_installed" => $map_is_installed,
744             "map_state" => $self->interp('MapState', $map_state),
745             "override_redirect" => $override_redirect,
746             "colormap" => $colormap, "all_event_masks" => $all_event_masks,
747             "your_event_mask" => $your_event_mask,
748             "do_not_propagate_mask" => $do_not_propagate_mask);
749             }],
750              
751             ['DestroyWindow', sub {
752             my $self = shift;
753             my($wid) = @_;
754             return pack "L", $wid;
755             }],
756              
757             ['DestroySubwindows', sub {
758             my $self = shift;
759             my($wid) = @_;
760             return pack "L", $wid;
761             }],
762              
763             ['ChangeSaveSet', sub {
764             my $self = shift;
765             my($mode, $wid) = @_;
766             $mode = 0 if $mode eq "Insert";
767             $mode = 1 if $mode eq "Delete";
768             return pack("L", $wid), $mode;
769             }],
770              
771             ['ReparentWindow', sub {
772             my $self = shift;
773             my($wid, $new_parent, $x, $y) = @_;
774             return pack "LLss", $wid, $new_parent, $x, $y;
775             }],
776              
777             ['MapWindow', sub {
778             my $self = shift;
779             my($wid) = @_;
780             return pack "L", $wid;
781             }],
782              
783             ['MapSubwindows', sub {
784             my $self = shift;
785             my($wid) = @_;
786             return pack "L", $wid;
787             }],
788              
789             ['UnmapWindow', sub {
790             my $self = shift;
791             my($wid) = @_;
792             return pack "L", $wid;
793             }],
794              
795             ['UnmapSubwindows', sub {
796             my $self = shift;
797             my($wid) = @_;
798             return pack "L", $wid;
799             }],
800              
801             ['ConfigureWindow', sub {
802             my $self = shift;
803             my($wid, %values) = @_;
804             my($mask, $i, @values);
805             $mask = 0;
806             for $i (0 .. 6) {
807             if (exists $values{$Configure_ValueMask[$i][0]}) {
808             $mask |= (1 << $i);
809             push @values,
810             &{$Configure_ValueMask[$i][1]}
811             ($self, $values{$Configure_ValueMask[$i][0]});
812             }
813             }
814             return pack("LSxx", $wid, $mask) . join "", @values;
815             }],
816              
817             ['CirculateWindow', sub {
818             my $self = shift;
819             my($wid, $dir) = @_;
820             $dir = $self->num('CirculateDirection', $dir);
821             return pack("L", $wid), $dir;
822             }],
823              
824             ['GetGeometry', sub {
825             my $self = shift;
826             my($drawable) = @_;
827             return pack "L", $drawable;
828             }, sub {
829             my $self = shift;
830             my($data) = @_;
831             my($depth, $root, $x, $y, $width, $height, $border_width)
832             = unpack("xCxxxxxxLssSSSxxxxxxxxxx", $data);
833              
834             return ("depth" => $depth, "root" => $root, "x" => $x, "y" => $y,
835             "width" => $width, "height" => $height,
836             "border_width" => $border_width);
837             }],
838              
839             ['QueryTree', sub {
840             my $self = shift;
841             my($wid) = @_;
842             return pack "L", $wid;
843             }, sub {
844             my $self = shift;
845             my($data) = @_;
846             my($root, $parent, $n)
847             = unpack("xxxxxxxxLLSxxxxxxxxxxxxxx", substr($data, 0, 32));
848              
849             $parent = "None" if $parent == 0 and $self->{'do_interp'};
850              
851             return ($root, $parent, unpack("L*", substr($data, 32)));
852             }],
853              
854             ['InternAtom', sub {
855             my $self = shift;
856             my($string, $only_if_exists) = @_;
857             return pack("Sxx" . padded($string), length($string), $string),
858             $only_if_exists;
859             }, sub {
860             my $self = shift;
861             my($data) = @_;
862             my($atom) = unpack("xxxxxxxxLxxxxxxxxxxxxxxxxxxxx", $data);
863             $atom = "None" if $atom == 0 and $self->{'do_interp'};
864             return $atom;
865             }],
866              
867             ['GetAtomName', sub {
868             my $self = shift;
869             my($atom) = @_;
870             return pack "L", $atom;
871             }, sub {
872             my $self = shift;
873             my($data) = @_;
874             my($len) = unpack "xxxxxxxxSxxxxxxxxxxxxxxxxxxxxxx", substr($data, 0, 32);
875             return substr($data, 32, $len);
876             }],
877              
878             ['ChangeProperty', sub {
879             my $self = shift;
880             my($window, $property, $type, $format, $mode, $data) = @_;
881             $mode = $self->num('ChangePropertyMode', $mode);
882             my($x) = $format / 8;
883             return pack("LLLCxxxL" . padded($data), $window, $property, $type,
884             $format, length($data) / $x, $data), $mode;
885             }],
886              
887             ['DeleteProperty', sub {
888             my $self = shift;
889             my($wid, $atom) = @_;
890             return pack "LL", $wid, $atom;
891             }],
892              
893             ['GetProperty', sub {
894             my $self = shift;
895             my($wid, $prop, $type, $offset, $length, $delete) = @_;
896             $type = 0 if $type eq "AnyPropertyType";
897             return pack("LLLLL", $wid, $prop, $type, $offset, $length), $delete;
898             }, sub {
899             my $self = shift;
900             my($data) = @_;
901             my($format, $type, $bytes_after, $len) =
902             unpack "xCxxxxxxLLLxxxxxxxxxxxx", substr($data, 0, 32);
903             my($m) = $format / 8;
904             my($val) = substr($data, 32, $len * $m);
905             return ($val, $type, $format, $bytes_after);
906             }],
907              
908             ['ListProperties', sub {
909             my $self = shift;
910             my($wid) = @_;
911             return pack "L", $wid;
912             }, sub {
913             my $self = shift;
914             my($data) = @_;
915             my($n) = unpack "xxxxxxxxSxxxxxxxxxxxxxxxxxxxxxx", substr($data, 0, 32);
916             return unpack "L*", substr($data, 32, $n * 4);
917             }],
918              
919             ['SetSelectionOwner', sub {
920             my $self = shift;
921             my($selection, $owner, $time) = @_;
922             $owner = 0 if $owner eq "None";
923             $time = 0 if $time eq "CurrentTime";
924             return pack "LLL", $owner, $selection, $time;
925             }],
926              
927             ['GetSelectionOwner', sub {
928             my $self = shift;
929             my($selection) = @_;
930             return pack "L", $selection;
931             }, sub {
932             my $self = shift;
933             my($data) = @_;
934             my($win) = unpack "xxxxxxxxLxxxxxxxxxxxxxxxxxxxx", $data;
935             $win = "None" if $win == 0 and $self->{'do_interp'};
936             return $win;
937             }],
938              
939             ['ConvertSelection', sub {
940             my $self = shift;
941             my($selection, $target, $prop, $requestor, $time) = @_;
942             $prop = 0 if $prop eq "None";
943             $time = 0 if $time eq "CurrentTime";
944             return pack("LLLLL", $requestor, $selection, $target, $prop, $time);
945             }],
946              
947             ['SendEvent', sub {
948             my $self = shift;
949             my($destination, $propagate, $event_mask, $event) = @_;
950             $destination = 0 if $destination eq "PointerWindow";
951             $destination = 1 if $destination eq "InputFocus";
952             return pack("LL", $destination, $event_mask) . $event, $propagate;
953             }],
954              
955             ['GrabPointer', sub {
956             my $self = shift;
957             my($window, $owner_events, $event_mask, $pointer_mode, $keybd_mode,
958             $confine_window, $cursor, $time) = @_;
959             $pointer_mode = $self->num('SyncMode', $pointer_mode);
960             $keybd_mode = $self->num('SyncMode', $keybd_mode);
961             $confine_window = 0 if $confine_window eq "None";
962             $cursor = 0 if $cursor eq "None";
963             $time = 0 if $time eq "CurrentTime";
964             return pack("LSCCLLL", $window, $event_mask, $pointer_mode, $keybd_mode,
965             $confine_window, $cursor, $time), $owner_events;
966             }, sub {
967             my $self = shift;
968             my($data) = @_;
969             my($status) = unpack("xCxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", $data);
970             return $self->interp('GrabStatus', $status);
971             }],
972              
973             ['UngrabPointer', sub {
974             my $self = shift;
975             my($time) = @_;
976             $time = 0 if $time eq 'CurrentTime';
977             return pack "L", $time;
978             }],
979              
980             ['GrabButton', sub {
981             my $self = shift;
982             my($modifiers, $button, $win, $owner_events, $mask, $p_mode, $k_mode,
983             $confine_w, $cursor) = @_;
984             $p_mode = $self->num('SyncMode', $p_mode);
985             $k_mode = $self->num('SyncMode', $k_mode);
986             $confine_w = 0 if $confine_w eq "None";
987             $cursor = 0 if $cursor eq "None";
988             $button = 0 if $button eq "AnyButton";
989             $modifiers = 0x8000 if $modifiers eq "AnyModifier";
990             return pack("LSCCLLCxS", $win, $mask, $p_mode, $k_mode, $confine_w,
991             $cursor, $button, $modifiers), $owner_events;
992             }],
993              
994             ['UngrabButton', sub {
995             my $self = shift;
996             my($modifiers, $button, $win) = @_;
997             $button = 0 if $button eq "AnyButton";
998             $modifiers = 0x8000 if $modifiers eq "AnyModifier";
999             return pack("LSxx", $win, $modifiers), $button;
1000             }],
1001              
1002             ['ChangeActivePointerGrab', sub {
1003             my $self = shift;
1004             my($mask, $cursor, $time) = @_;
1005             $cursor = 0 if $cursor eq "None";
1006             $time = 0 if $time eq "CurrentTime";
1007             return pack "LLSxx", $cursor, $time, $mask;
1008             }],
1009              
1010             ['GrabKeyboard', sub {
1011             my $self = shift;
1012             my($win, $owner_events, $p_mode, $k_mode, $time) = @_;
1013             $time = 0 if $time eq "CurrentTime";
1014             $p_mode = $self->num('SyncMode', $p_mode);
1015             $k_mode = $self->num('SyncMode', $k_mode);
1016             return pack("LLCCxx", $win, $time, $p_mode, $k_mode), $owner_events;
1017             }, sub {
1018             my $self = shift;
1019             my($data) = @_;
1020             my($status) = unpack("xCxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", $data);
1021             return $self->interp('GrabStatus', $status);
1022             }],
1023              
1024             ['UngrabKeyboard', sub {
1025             my $self = shift;
1026             my($time) = @_;
1027             $time = 0 if $time eq "CurrentTime";
1028             return pack("L", $time);
1029             }],
1030              
1031             ['GrabKey', sub {
1032             my $self = shift;
1033             my($key, $modifiers, $win, $owner_events, $p_mode, $k_mode) = @_;
1034             $modifiers = 0x8000 if $modifiers eq "AnyModifier";
1035             $key = 0 if $key eq "AnyKey";
1036             $p_mode = $self->num('SyncMode', $p_mode);
1037             $k_mode = $self->num('SyncMode', $k_mode);
1038             return pack("LSCCCxxx", $win, $modifiers, $key, $p_mode, $k_mode),
1039             $owner_events;
1040             }],
1041              
1042             ['UngrabKey', sub {
1043             my $self = shift;
1044             my($key, $modifiers, $win) = @_;
1045             $key = 0 if $key eq "AnyKey";
1046             $modifiers = 0x8000 if $modifiers eq "AnyModifier";
1047             return pack("LSxx", $win, $modifiers), $key;
1048             }],
1049              
1050             ['AllowEvents', sub {
1051             my $self = shift;
1052             my($mode, $time) = @_;
1053             $mode = $self->num('AllowEventsMode', $mode);
1054             $time = 0 if $time eq "CurrentTime";
1055             return pack("L", $time), $mode;
1056             }],
1057              
1058             ['GrabServer', sub {
1059             my $self = shift;
1060             return "";
1061             }],
1062              
1063             ['UngrabServer', sub {
1064             my $self = shift;
1065             return "";
1066             }],
1067              
1068             ['QueryPointer', sub {
1069             my $self = shift;
1070             my($window) = @_;
1071             return pack "L", $window;
1072             }, sub {
1073             my $self = shift;
1074             my($data) = @_;
1075             my($same_s, $root, $child, $root_x, $root_y, $win_x, $win_y, $mask)
1076             = unpack "xCxxxxxxLLssssSxxxxxx", $data;
1077             $child = 'None' if $child == 0 and $self->{'do_interp'};
1078             return ('same_screen' => $same_s, 'root' => $root, 'child' => $child,
1079             'root_x' => $root_x, 'root_y' => $root_y, 'win_x' => $win_x,
1080             'win_y' => $win_y, 'mask' => $mask);
1081             }],
1082              
1083             ['GetMotionEvents', sub {
1084             my $self = shift;
1085             my($start, $stop, $win) = @_;
1086             $start = 0 if $start eq "CurrentTime";
1087             $stop = 0 if $stop eq "CurrentTime";
1088             return pack "LLL", $win, $start, $stop;
1089             }, sub {
1090             my $self = shift;
1091             my($data) = @_;
1092             my($n) = unpack "xxxxxxxxLxxxxxxxxxxxxxxxxxxxx", substr($data, 0, 32);
1093             my($events) = substr($data, 32, 8 * $n);
1094             my(@ret, $off);
1095             for $off (0 .. $n - 1)
1096             {
1097             push @ret, [unpack "Lss", substr($events, 8 * $off, 8)];
1098             }
1099             return @ret;
1100             }],
1101              
1102             ['TranslateCoordinates', sub {
1103             my $self = shift;
1104             my($src_w, $dest_w, $src_x, $src_y) = @_;
1105             return pack "LLss", $src_w, $dest_w, $src_x, $src_y;
1106             }, sub {
1107             my $self = shift;
1108             my($data) = @_;
1109             my($same_screen, $child, $dest_x, $dest_y) =
1110             unpack "xCxxxxxxLssxxxxxxxxxxxxxxxx", $data;
1111             $child = "None" if $child == 0 and $self->{'do_interp'};
1112             return ($same_screen, $child, $dest_x, $dest_y);
1113             }],
1114              
1115             ['WarpPointer', sub {
1116             my $self = shift;
1117             my($src_w, $dst_w, $src_x, $src_y, $src_width, $src_height, $dst_x,
1118             $dst_y) = @_;
1119             $src_w = 0 if $src_w eq "None";
1120             $dst_w = 0 if $dst_w eq "None";
1121             return pack("LLssSSss", $src_w, $dst_w, $src_x, $src_y, $src_width,
1122             $src_height, $dst_x, $dst_y);
1123             }],
1124              
1125             ['SetInputFocus', sub {
1126             my $self = shift;
1127             my($focus, $revert_to, $time) = @_;
1128             $revert_to = $self->num('InputFocusRevertTo', $revert_to);
1129             $focus = 0 if $focus eq "None";
1130             $focus = 1 if $focus eq "ParentRoot";
1131             $time = 0 if $time eq "CurrentTime";
1132             return pack("LL", $focus, $time), $revert_to;
1133             }],
1134              
1135             ['GetInputFocus', sub {
1136             my $self = shift;
1137             return "";
1138             }, sub {
1139             my $self = shift;
1140             my($data) = @_;
1141             my($revert_to, $focus) =
1142             unpack "xCxxxxxxLxxxxxxxxxxxxxxxxxxxx", $data;
1143             $revert_to = $self->interp('InputFocusRevertTo', $revert_to);
1144             $focus = "None" if $focus == 0 and $self->{'do_interp'};
1145             $focus = "PointerRoot" if $focus == 1 and $self->{'do_interp'};
1146             return ($focus, $revert_to);
1147             }],
1148              
1149             ['QueryKeymap', sub {
1150             my $self = shift;
1151             return "";
1152             }, sub {
1153             my $self = shift;
1154             my($data) = @_;
1155             return substr($data, 8, 32);
1156             }],
1157              
1158             ['OpenFont', sub {
1159             my $self = shift;
1160             my($fid, $name) = @_;
1161             return pack("LSxx" . padded($name), $fid, length($name), $name);
1162             }],
1163              
1164             ['CloseFont', sub {
1165             my $self = shift;
1166             my($font) = @_;
1167             return pack "L", $font;
1168             }],
1169              
1170             ['QueryFont', sub {
1171             my $self = shift;
1172             my($font) = @_;
1173             return pack "L", $font;
1174             }, sub {
1175             my $self = shift;
1176             my($data) = @_;
1177             my($min_bounds) = substr($data, 8, 12);
1178             my($max_bounds) = substr($data, 24, 12);
1179             my($min_char_or_byte2, $max_char_or_byte2, $default_char, $n,
1180             $draw_direction, $min_byte1, $max_byte1, $all_chars_exist,
1181             $font_ascent, $font_descent, $m) = unpack("SSSSCCCCssL",
1182             substr($data, 40, 20));
1183             my($properties) = substr($data, 60, 8 * $n);
1184             my($char_infos) = substr($data, 60 + 8 * $n, 12 * $m);
1185             $draw_direction = $self->interp('DrawDirection', $draw_direction);
1186             my(%ret) = ('min_char_or_byte2' => $min_char_or_byte2,
1187             'max_char_or_byte2' => $max_char_or_byte2,
1188             'default_char' => $default_char,
1189             'draw_direction' => $draw_direction,
1190             'min_byte1' => $min_byte1, 'max_byte1' => $max_byte1,
1191             'all_chars_exist' => $all_chars_exist,
1192             'font_ascent' => $font_ascent,
1193             'font_descent' => $font_descent);
1194              
1195             $ret{'min_bounds'} = [unpack("sssssS", $min_bounds)];
1196             $ret{'max_bounds'} = [unpack("sssssS", $max_bounds)];
1197             my($i, @char_infos, %font_props);
1198             for $i (0 .. $m - 1) {
1199             push @char_infos, [unpack("sssssS",
1200             substr($char_infos, 12 * $i, 12))];
1201             }
1202             for $i (0 .. $n - 1) {
1203             my($atom, $value) = unpack("LL", substr($properties, 8 * $i, 8));
1204             $font_props{$atom} = $value;
1205             }
1206             $ret{'properties'} = {%font_props};
1207             $ret{'char_infos'} = [@char_infos];
1208             return %ret;
1209             }],
1210              
1211             ['QueryTextExtents', sub {
1212             my $self = shift;
1213             my($font, $string) = @_;
1214             return pack("L" . padded($string), $font, $string), (pad($string) == 2);
1215             }, sub {
1216             my $self = shift;
1217             my($data) = @_;
1218             my($draw_direction, $font_a, $font_d, $overall_a, $overall_d, $overall_w,
1219             $overall_l, $overall_r) = unpack("xCxxxxxxsssslllxxxx", $data);
1220             $draw_direction = $self->interp('DrawDirection', $draw_direction);
1221             return ('draw_direction' => $draw_direction, 'font_ascent' => $font_a,
1222             'font_descent' => $font_d, 'overall_ascent' => $overall_a,
1223             'overall_descent' => $overall_d, 'overall_width' => $overall_w,
1224             'overall_left' => $overall_l, 'overall_right' => $overall_r);
1225             }],
1226              
1227             ['ListFonts', sub {
1228             my $self = shift;
1229             my($pat, $max) = @_;
1230             return pack("SS" . padded($pat), $max, length($pat), $pat);
1231             }, sub {
1232             my $self = shift;
1233             my($data) = @_;
1234             my($n) = unpack("xxxxxxxxSxxxxxxxxxxxxxxxxxxxxxx", substr($data, 0, 32));
1235             my($list) = substr($data, 32);
1236             my(@ret, $offset, $len, $i);
1237             $offset = 0;
1238             while ($i++ < $n) {
1239             $len = unpack("C", substr($list, $offset, 1));
1240             push @ret, substr($list, $offset + 1, $len);
1241             $offset += $len + 1;
1242             }
1243             return @ret;
1244             }],
1245              
1246             ['ListFontsWithInfo', sub {
1247             my $self = shift;
1248             my($pat, $max) = @_;
1249             return pack("SS" . padded($pat), $max, length($pat), $pat);
1250             }, sub {
1251             my $self = shift;
1252             my($data) = @_;
1253             my($n) = unpack("C", substr($data, 1, 1));
1254             return () if $n == 0;
1255             my($min_bounds) = substr($data, 8, 12);
1256             my($max_bounds) = substr($data, 24, 12);
1257             my($min_char_or_byte2, $max_char_or_byte2, $default_char, $m,
1258             $draw_direction, $min_byte1, $max_byte1, $all_chars_exist,
1259             $font_ascent, $font_descent) = unpack("SSSSCCCCssxxxx",
1260             substr($data, 40, 20));
1261             my($properties) = substr($data, 60, 8 * $m);
1262             my($name) = substr($data, 60 + 8 * $m, $n);
1263             $draw_direction = $self->interp('DrawDirection', $draw_direction);
1264             my(%ret) = ('min_char_or_byte2' => $min_char_or_byte2,
1265             'max_char_or_byte2' => $max_char_or_byte2,
1266             'default_char' => $default_char,
1267             'draw_direction' => $draw_direction,
1268             'min_byte1' => $min_byte1, 'max_byte1' => $max_byte1,
1269             'all_chars_exist' => $all_chars_exist,
1270             'font_ascent' => $font_ascent,
1271             'font_descent' => $font_descent, 'name' => $name);
1272              
1273             $ret{'min_bounds'} = [unpack("sssssS", $min_bounds)];
1274             $ret{'max_bounds'} = [unpack("sssssS", $max_bounds)];
1275             my($i, %font_props);
1276             for $i (0 .. $m - 1) {
1277             my($atom, $value) = unpack("LL", substr($properties, 8 * $i, 8));
1278             $font_props{$atom} = $value;
1279             }
1280             $ret{'properties'} = {%font_props};
1281             return %ret;
1282             }, 'HASH'],
1283              
1284             ['SetFontPath', sub {
1285             my $self = shift;
1286             my(@dirs) = @_;
1287             my($n, $d, $path);
1288             for $d (@dirs) {
1289             $d = pack("C", length $d) . $d;
1290             $n++;
1291             }
1292             $path = join("", @dirs);
1293             return pack("Sxx" . padded($path), $n, $path);
1294             }],
1295              
1296             ['GetFontPath', sub {
1297             my $self = shift;
1298             return "";
1299             }, sub {
1300             my $self = shift;
1301             my($data) = @_;
1302             my($n) = unpack("xxxxxxxxSxxxxxxxxxxxxxxxxxxxxxx", substr($data, 0, 32));
1303             my($list) = substr($data, 32);
1304             my(@ret, $offset, $len, $i);
1305             $offset = 0;
1306             while ($i++ < $n) {
1307             $len = unpack("C", substr($list, $offset, 1));
1308             push @ret, substr($list, $offset + 1, $len);
1309             $offset += $len + 1;
1310             }
1311             return @ret;
1312             }],
1313              
1314             ['CreatePixmap', sub {
1315             my $self = shift;
1316             my($pixmap, $drawable, $depth, $w, $h) = @_;
1317             return pack("LLSS", $pixmap, $drawable, $w, $h), $depth;
1318             }],
1319              
1320             ['FreePixmap', sub {
1321             my $self = shift;
1322             my($pixmap) = @_;
1323             return pack "L", $pixmap;
1324             }],
1325              
1326             ['CreateGC', sub {
1327             my $self = shift;
1328             my($gc, $drawable, %values) = @_;
1329             my($i, $mask, @values);
1330             $mask = 0;
1331             for $i (0 .. $#GC_ValueMask) {
1332             if (exists $values{$GC_ValueMask[$i][0]}) {
1333             $mask |= (1 << $i);
1334             push @values,
1335             &{$GC_ValueMask[$i][1]}($self, $values{$GC_ValueMask[$i][0]});
1336             delete $values{$GC_ValueMask[$i][0]};
1337             }
1338             }
1339             croak "Invalid GC components: ", join(",", keys %values), "\n" if %values;
1340             return pack("LLL", $gc, $drawable, $mask) . join("", @values);
1341             }],
1342              
1343             ['ChangeGC', sub {
1344             my $self = shift;
1345             my($gc, %values) = @_;
1346             my($i, $mask, @values);
1347             $mask = 0;
1348             for $i (0 .. $#GC_ValueMask) {
1349             if (exists $values{$GC_ValueMask[$i][0]}) {
1350             $mask |= (1 << $i);
1351             push @values,
1352             &{$GC_ValueMask[$i][1]}($self, $values{$GC_ValueMask[$i][0]});
1353             }
1354             }
1355             return pack("LL", $gc, $mask) . join("", @values);
1356             }],
1357              
1358             ['CopyGC', sub {
1359             my $self = shift;
1360             my($src, $dst, @values) = @_;
1361             my(%values, $i, $mask);
1362             $mask = 0;
1363             @values{@values} = (1) x @values;
1364             for $i (0 .. $#GC_ValueMask) {
1365             $mask |= (1 << $i) if exists $values{$GC_ValueMask[$i][0]};
1366             }
1367             return pack "LLL", $src, $dst, $mask;
1368             }],
1369              
1370             ['SetDashes', sub {
1371             my $self = shift;
1372             my($gc, $offset, @dashes) = @_;
1373             my($dash_list) = pack("C*", @dashes);
1374             my($n) = length $dash_list;
1375             return pack("LSS" . padded($dash_list), $gc, $offset, $n, $dash_list);
1376             }],
1377              
1378             ['SetClipRectangles', sub {
1379             my $self = shift;
1380             my($gc, $clip_x_o, $clip_y_o, $ordering, @rects) = @_;
1381             $ordering = $self->num('ClipRectangleOrdering', $ordering);
1382             my($x);
1383             for $x (@rects) {
1384             $x = pack("ssSS", @$x);
1385             }
1386             return pack("Lss", $gc, $clip_x_o, $clip_y_o) . join("", @rects),
1387             $ordering;
1388             }],
1389              
1390             ['FreeGC', sub {
1391             my $self = shift;
1392             my($gc) = @_;
1393             return pack "L", $gc;
1394             }],
1395              
1396             ['ClearArea', sub {
1397             my $self = shift;
1398             my($win, $x, $y, $w, $h, $exposures) = @_;
1399             return pack("LssSS", $win, $x, $y, $w, $h), $exposures;
1400             }],
1401              
1402             ['CopyArea', sub {
1403             my $self = shift;
1404             my($src_d, $dst_d, $gc, $src_x, $src_y, $w, $h, $dst_x, $dst_y) = @_;
1405             return pack("LLLssssSS", $src_d, $dst_d, $gc, $src_x, $src_y, $dst_x,
1406             $dst_y, $w, $h);
1407             }],
1408              
1409             ['CopyPlane', sub {
1410             my $self = shift;
1411             my($src_d, $dst_d, $gc, $src_x, $src_y, $w, $h, $dst_x, $dst_y, $plane)
1412             = @_;
1413             return pack("LLLssssSSL", $src_d, $dst_d, $gc, $src_x, $src_y, $dst_x,
1414             $dst_y, $w, $h, $plane);
1415             }],
1416              
1417             ['PolyPoint', sub {
1418             my $self = shift;
1419             my($drawable, $gc, $coord_mode, @points) = @_;
1420             $coord_mode = $self->num('CoordinateMode', $coord_mode);
1421             return pack("LLs*", $drawable, $gc, @points), $coord_mode;
1422             }],
1423              
1424             ['PolyLine', sub {
1425             my $self = shift;
1426             my($drawable, $gc, $coord_mode, @points) = @_;
1427             $coord_mode = $self->num('CoordinateMode', $coord_mode);
1428             return pack("LLs*", $drawable, $gc, @points), $coord_mode;
1429             }],
1430              
1431             ['PolySegment', sub {
1432             my $self = shift;
1433             my($drawable, $gc, @points) = @_;
1434             return pack("LLs*", $drawable, $gc, @points);
1435             }],
1436              
1437             ['PolyRectangle', sub {
1438             my $self = shift;
1439             my($drawable, $gc, @rects) = @_;
1440             my($rr);
1441             for $rr (@rects) {
1442             $rr = pack("ssSS", @$rr);
1443             }
1444             return pack("LL", $drawable, $gc) . join("", @rects);
1445             }],
1446              
1447             ['PolyArc', sub {
1448             my $self = shift;
1449             my($drawable, $gc, @arcs) = @_;
1450             my($ar);
1451             for $ar (@arcs) {
1452             $ar = pack("ssSSss", @$ar);
1453             }
1454             return pack("LL", $drawable, $gc) . join("", @arcs);
1455             }],
1456              
1457             ['FillPoly', sub {
1458             my $self = shift;
1459             my($drawable, $gc, $shape, $coord_mode, @points) = @_;
1460             $shape = $self->num('PolyShape', $shape);
1461             $coord_mode = $self->num('CoordinateMode', $coord_mode);
1462             return pack("LLCCxxs*", $drawable, $gc, $shape, $coord_mode, @points);
1463             }],
1464              
1465             ['PolyFillRectangle', sub {
1466             my $self = shift;
1467             my($drawable, $gc, @rects) = @_;
1468             my($rr);
1469             for $rr (@rects) {
1470             $rr = pack("ssSS", @$rr);
1471             }
1472             return pack("LL", $drawable, $gc) . join("", @rects);
1473             }],
1474              
1475             ['PolyFillArc', sub {
1476             my $self = shift;
1477             my($drawable, $gc, @arcs) = @_;
1478             my($ar);
1479             for $ar (@arcs) {
1480             $ar = pack("ssSSss", @$ar);
1481             }
1482             return pack("LL", $drawable, $gc) . join("", @arcs);
1483             }],
1484              
1485             ['PutImage', sub {
1486             my $self = shift;
1487             my($drawable, $gc, $depth, $w, $h, $x, $y, $left_pad, $format, $data)
1488             = @_;
1489             $format = $self->num('ImageFormat', $format);
1490             return pack("LLSSssCCxx" . padded($data), $drawable, $gc, $w, $h,
1491             $x, $y, $left_pad, $depth, $data), $format;
1492             }],
1493              
1494             ['GetImage', sub {
1495             my $self = shift;
1496             my($drawable, $x, $y, $w, $h, $mask, $format) = @_;
1497             $format = $self->num('ImageFormat', $format);
1498             croak "GetImage() format must be (XY|Z)Pixmap" if $format == 0;
1499             return pack("LssSSL", $drawable, $x, $y, $w, $h, $mask), $format;
1500             }, sub {
1501             my $self = shift;
1502             my($data) = @_;
1503             my($depth, $visual) = unpack("xCxxxxxxLxxxxxxxxxxxxxxxxxxxx",
1504             substr($data, 0, 32));
1505             return ($depth, $visual, substr($data, 32));
1506             }],
1507              
1508             ['PolyText8', sub {
1509             my $self = shift;
1510             my($drawable, $gc, $x, $y, @items) = @_;
1511             my(@i, $ir, @item, $n, $r, $items);
1512             for $ir (@items) {
1513             if (not ref $ir) {
1514             push @i, pack("CN", 255, $ir);
1515             } else {
1516             @item = @$ir;
1517             $n = 0;
1518             $r = length($item[1]);
1519             while ($r > 0) {
1520             if ($r >= 254) {
1521             push @i, pack("Cc", 254, 0) . substr($item[1], $n, 254);
1522             $n += 254;
1523             $r -= 254;
1524             } else {
1525             push @i, pack("Cc", $r, $item[0]) . substr($item[1], $n);
1526             $n += $r; # Superfluous
1527             $r = 0; # $r -= $r would be more symmetrical
1528             }
1529             }
1530             }
1531             }
1532             $items = join("", @i);
1533             return pack("LLss" . padded($items), $drawable, $gc, $x, $y, $items);
1534             }],
1535              
1536             ['PolyText16', sub {
1537             my $self = shift;
1538             my($drawable, $gc, $x, $y, @items) = @_;
1539             my(@i, $ir, @item, $n, $r, $items);
1540             for $ir (@items) {
1541             if (not ref $ir) {
1542             push @i, pack("CN", 255, $ir);
1543             } else {
1544             @item = @$ir;
1545             $n = 0;
1546             $r = length($item[1]);
1547             while ($r > 0) {
1548             if ($r >= 508) {
1549             push @i, pack("Cc", 254, 0) . substr($item[1], $n, 508);
1550             $n += 508;
1551             $r -= 508;
1552             } else {
1553             push @i, pack("Cc", $r / 2, $item[0])
1554             . substr($item[1], $n);
1555             $n += $r; # Unnecessary
1556             $r = 0; # $r -= $r would be more symmetrical
1557             }
1558             }
1559             }
1560             }
1561             $items = join("", @i);
1562             return pack("LLss" . padded($items), $drawable, $gc, $x, $y, $items);
1563             }],
1564              
1565             ['ImageText8', sub {
1566             my $self = shift;
1567             my($drawable, $gc, $x, $y, $str) = @_;
1568             return pack("LLss" . padded($str), $drawable, $gc, $x, $y, $str),
1569             length($str);
1570             }],
1571              
1572             ['ImageText16', sub {
1573             my $self = shift;
1574             my($drawable, $gc, $x, $y, $str) = @_;
1575             return pack("LLss" . padded($str), $drawable, $gc, $x, $y, $str),
1576             length($str)/2;
1577             }],
1578              
1579             ['CreateColormap', sub {
1580             my $self = shift;
1581             my($mid, $visual, $win, $alloc) = @_;
1582             $alloc = 0 if $alloc eq "None";
1583             $alloc = 1 if $alloc eq "All";
1584             return pack("LLL", $mid, $win, $visual), $alloc;
1585             }],
1586              
1587             ['FreeColormap', sub {
1588             my $self = shift;
1589             my($cmap) = @_;
1590             return pack("L", $cmap);
1591             }],
1592              
1593             ['CopyColormapAndFree', sub {
1594             my $self = shift;
1595             my($mid, $src) = @_;
1596             return pack("LL", $mid, $src);
1597             }],
1598              
1599             ['InstallColormap', sub {
1600             my $self = shift;
1601             my($cmap) = @_;
1602             return pack("L", $cmap);
1603             }],
1604              
1605             ['UninstallColormap', sub {
1606             my $self = shift;
1607             my($cmap) = @_;
1608             return pack("L", $cmap);
1609             }],
1610              
1611             ['ListInstalledColormaps', sub {
1612             my $self = shift;
1613             my($win) = @_;
1614             return pack("L", $win);
1615             }, sub {
1616             my $self = shift;
1617             my($data) = @_;
1618             return unpack("L*", substr($data, 32));
1619             }],
1620              
1621             ['AllocColor', sub {
1622             my $self = shift;
1623             my($cmap, $r, $g, $b) = @_;
1624             return pack("LSSSxx", $cmap, $r, $g, $b);
1625             }, sub {
1626             my $self = shift;
1627             my($data) = @_;
1628             my($r, $g, $b, $pixel) = unpack("xxxxxxxxSSSxxLxxxxxxxxxxxx", $data);
1629             return ($pixel, $r, $g, $b);
1630             }],
1631              
1632             ['AllocNamedColor', sub {
1633             my $self = shift;
1634             my($cmap, $name) = @_;
1635             return pack("LSxx" . padded($name), $cmap, length($name), $name);
1636             }, sub {
1637             my $self = shift;
1638             my($data) = @_;
1639             return unpack("xxxxxxxxLSSSSSSxxxxxxxx", $data);
1640             }],
1641              
1642             ['AllocColorCells', sub {
1643             my $self = shift;
1644             my($cmap, $colors, $planes, $contig) = @_;
1645             return pack("LSS", $cmap, $colors, $planes), $contig;
1646             }, sub {
1647             my $self = shift;
1648             my($data) = @_;
1649             my($n,$m) = unpack("xxxxxxxxSSxxxxxxxxxxxxxxxxxxxx",substr($data, 0, 32));
1650             return ([unpack("L*", substr($data, 32, 4 * $n))],
1651             [unpack("L*", substr($data, 32 + 4 * $n, 4 * $m))]);
1652             }],
1653              
1654             ['AllocColorPlanes', sub {
1655             my $self = shift;
1656             my($cmap, $colors, $reds, $greens, $blues, $contig) = @_;
1657             return pack("LSSSS", $cmap, $colors, $reds, $greens, $blues), $contig;
1658             }, sub {
1659             my $self = shift;
1660             my($data) = @_;
1661             my($n, $r_mask, $g_mask, $b_mask) =
1662             unpack("xxxxxxxxSxxLLLxxxxxxxx", substr($data, 0, 32));
1663             return ($r_mask, $g_mask, $b_mask, unpack("L*", substr($data, 32, 4*$n)));
1664             }],
1665              
1666             ['FreeColors', sub {
1667             my $self = shift;
1668             my($cmap, $mask, @pixels) = @_;
1669             return pack("LLL*", $cmap, $mask, @pixels);
1670             }],
1671              
1672             ['StoreColors', sub {
1673             my $self = shift;
1674             my($cmap, @actions) = @_;
1675             my($l, @l);
1676             for $l (@actions) {
1677             @l = @$l;
1678             if (@l == 4) {
1679             $l = pack("LSSSCx", @l, 7);
1680             } elsif (@l == 5) {
1681             $l = pack("LSSSCx", @l);
1682             } else {
1683             croak "Wrong # of items in arg to StoreColors";
1684             }
1685             }
1686             return pack("L", $cmap) . join("", @actions);
1687             }],
1688              
1689             ['StoreNamedColor', sub {
1690             my $self = shift;
1691             my($cmap, $pixel, $name, $do) = @_;
1692             return pack("LLSxx" . padded($name), $cmap, $pixel, length($name),
1693             $name), $do;
1694             }],
1695              
1696             ['QueryColors', sub {
1697             my $self = shift;
1698             my($cmap, @pixels) = @_;
1699             return pack("LL*", $cmap, @pixels);
1700             }, sub {
1701             my $self = shift;
1702             my($data) = @_;
1703             my($n) = unpack("xxxxxxxxSxxxxxxxxxxxxxxxxxxxxxx", substr($data, 0, 32));
1704             my($i, @colors);
1705             for $i (0 .. $n - 1) {
1706             push @colors, [unpack("SSSxx", substr($data, 32 + 8 * $i, 8))];
1707             }
1708             return @colors;
1709             }],
1710              
1711             ['LookupColor', sub {
1712             my $self = shift;
1713             my($cmap, $name) = @_;
1714             return pack("LSxx" . padded($name), $cmap, length($name), $name);
1715             }, sub {
1716             my $self = shift;
1717             my($data) = @_;
1718             return unpack("xxxxxxxxSSSSSSxxxxxxxxxxxx", $data);
1719             }],
1720              
1721             ['CreateCursor', sub {
1722             my $self = shift;
1723             my($cid, $src, $mask, $fr, $fg, $fb, $br, $bg, $bb, $x, $y) = @_;
1724             $mask = 0 if $mask eq "None";
1725             return pack("LLLSSSSSSSS", $cid, $src, $mask, $fr, $fg, $fb, $br, $bg,
1726             $bb, $x, $y);
1727             }],
1728              
1729             ['CreateGlyphCursor', sub {
1730             my $self = shift;
1731             my($cid, $src_fnt, $mask_fnt, $src_ch, $mask_ch, $fr, $fg, $fb, $br,
1732             $bg, $bb) = @_;
1733             $mask_fnt = 0 if $mask_fnt eq "None";
1734             return pack("LLLSSSSSSSS", $cid, $src_fnt, $mask_fnt, $src_ch, $mask_ch,
1735             $fr, $fg, $fb, $br, $bg, $bb);
1736             }],
1737              
1738             ['FreeCursor', sub {
1739             my $self = shift;
1740             my($cursor) = @_;
1741             return pack("L", $cursor);
1742             }],
1743              
1744             ['RecolorCursor', sub {
1745             my $self = shift;
1746             my($cursor, $fr, $fg, $fb, $br, $bg, $bb) = @_;
1747             return pack("LSSSSSS", $cursor, $fr, $fg, $fb, $br, $bg, $bb);
1748             }],
1749              
1750             ['QueryBestSize', sub {
1751             my $self = shift;
1752             my($class, $drawable, $w, $h) = @_;
1753             $class = $self->num('SizeClass', $class);
1754             return pack("LSS", $drawable, $w, $h), $class;
1755             }, sub {
1756             my $self = shift;
1757             my($data) = @_;
1758             my($w, $h) = unpack("xxxxxxxxSSxxxxxxxxxxxxxxxxxxxx", $data);
1759             return ($w, $h);
1760             }],
1761              
1762             ['QueryExtension', sub {
1763             my $self = shift;
1764             my($name) = @_;
1765             return pack("Sxx" . padded($name), length($name), $name);
1766             }, sub {
1767             my $self = shift;
1768             my($data) = @_;
1769             my($present, $major, $event, $error) =
1770             unpack("xxxxxxxxCCCCxxxxxxxxxxxxxxxxxxxx", $data);
1771             return () unless $present;
1772             return ($major, $event, $error);
1773             }],
1774              
1775             ['ListExtensions', sub {
1776             my $self = shift;
1777             return "";
1778             }, sub {
1779             my $self = shift;
1780             my($data) = @_;
1781             my($num) = unpack("xCxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
1782             substr($data, 0, 32));
1783             my($list) = substr($data, 32);
1784             my(@ret, $offset, $len, $i);
1785             $offset = 0;
1786             while ($i++ < $num) {
1787             $len = unpack("C", substr($list, $offset, 1));
1788             push @ret, substr($list, $offset + 1, $len);
1789             $offset += $len + 1;
1790             }
1791             return @ret;
1792             }],
1793              
1794             ['ChangeKeyboardMapping', sub {
1795             my $self = shift;
1796             my($first, $m, @info) = @_;
1797             my($ar);
1798             for $ar (@info) {
1799             $ar = pack("L$m", @{$ar}[0 .. $m - 1]);
1800             }
1801             return pack("CCxx", $first, $m) . join("", @info), scalar(@info);
1802             }],
1803              
1804             ['GetKeyboardMapping', sub {
1805             my $self = shift;
1806             my($first, $count) = @_;
1807             return pack("CCxx", $first, $count);
1808             }, sub {
1809             my $self = shift;
1810             my($data) = @_;
1811             my($n,$l) = unpack("xCxxLxxxxxxxxxxxxxxxxxxxxxxxx", substr($data, 0, 32));
1812             my(@ret, $i);
1813             for $i (0 .. $l/$n - 1) {
1814             push @ret, [unpack("L$n", substr($data, 32 + $i * $n * 4))];
1815             }
1816             return @ret;
1817             }],
1818              
1819             ['ChangeKeyboardControl', sub {
1820             my $self = shift;
1821             my(%values) = @_;
1822             my($mask, $i, @values);
1823             $mask = 0;
1824             for $i (0 .. 7) {
1825             if (exists $values{$KeyboardControl_ValueMask[$i][0]}) {
1826             $mask |= (1 << $i);
1827             push @values,
1828             &{$KeyboardControl_ValueMask[$i][1]}
1829             ($self, $values{$KeyboardControl_ValueMask[$i][0]});
1830             }
1831             }
1832             return pack("L", $mask). join "", @values;
1833             }],
1834              
1835             ['GetKeyboardControl', sub {
1836             my $self = shift;
1837             return "";
1838             }, sub {
1839             my $self = shift;
1840             my($data) = @_;
1841             my($global_auto_repeat, $led_mask, $key_click_percent, $bell_percent,
1842             $bell_pitch, $bell_duration)
1843             = unpack("xCxxxxxxLCCSSxx", substr($data, 0, 20));
1844             my($auto_repeats) = substr($data, 20, 32);
1845             return ('global_auto_repeat' =>
1846             $self->interp('LedMode', $global_auto_repeat),
1847             'led_mask' => $led_mask,
1848             'key_click_percent' => $key_click_percent,
1849             'bell_percent' => $bell_percent, 'bell_pitch' => $bell_pitch,
1850             'bell_duration' => $bell_duration,
1851             'auto_repeats' => $auto_repeats);
1852             }],
1853              
1854             ['Bell', sub {
1855             my $self = shift;
1856             my($percent) = @_;
1857             return "", unpack("C", pack("c", $percent)); # Ick
1858             }],
1859              
1860             ['ChangePointerControl', sub {
1861             my $self = shift;
1862             my($do_accel, $do_thresh, $num, $denom, $thresh) = @_;
1863             return pack("sssCC", $num, $denom, $thresh, $do_accel, $do_thresh);
1864             }],
1865              
1866             ['GetPointerControl', sub {
1867             my $self = shift;
1868             return "";
1869             }, sub {
1870             my $self = shift;
1871             my($data) = @_;
1872             my($num, $deno, $thresh) = unpack("xxxxxxxxSSSxxxxxxxxxxxxxxxxxx", $data);
1873             return ($num, $deno, $thresh);
1874             }],
1875              
1876             ['SetScreenSaver', sub {
1877             my $self = shift;
1878             my($timeout, $interval, $pref_blank, $exposures) = @_;
1879             $pref_blank = $self->num('ScreenSaver', $pref_blank);
1880             $exposures = $self->num('ScreenSaver', $exposures);
1881             return pack("ssCCxx", $timeout, $interval, $pref_blank, $exposures);
1882             }],
1883              
1884             ['GetScreenSaver', sub {
1885             my $self = shift;
1886             return "";
1887             }, sub {
1888             my $self = shift;
1889             my($data) = @_;
1890             my($timeout, $interval, $pref_blank, $exposures)
1891             = unpack("xxxxxxxxSSCCxxxxxxxxxxxxxxxxxx", $data);
1892             $pref_blank = $self->interp('ScreenSaver', $pref_blank);
1893             $exposures = $self->interp('ScreenSaver', $exposures);
1894             return ($timeout, $interval, $pref_blank, $exposures);
1895             }],
1896              
1897             ['ChangeHosts', sub {
1898             my $self = shift;
1899             my($mode, $family, $address) = @_;
1900             $mode = $self->num('HostChangeMode', $mode);
1901             $family = $self->num('HostFamily', $family);
1902             return pack("CxS" . padded($address), $family, length($address),
1903             $address), $mode;
1904             }],
1905              
1906             ['ListHosts', sub {
1907             my $self = shift;
1908             return "";
1909             }, sub {
1910             my $self = shift;
1911             my($data) = @_;
1912             my($mode, $n) = unpack("xCxxxxxxSxxxxxxxxxxxxxxxxxxxxxx",
1913             substr($data, 0, 32));
1914             $mode = $self->interp('AccessMode', $mode);
1915             my(@ret, $fam, $off, $l);
1916             $off = 32;
1917             while ($n-- > 0) {
1918             ($fam, $l) = unpack("CxS", substr($data, $off, 4));
1919             $fam = $self->interp('HostFamily', $fam);
1920             push @ret, [$fam, substr($data, $off + 4, $l)];
1921             $off += 4 + $l + padding($l);
1922             }
1923             return ($mode, @ret);
1924             }],
1925              
1926             ['SetAccessControl', sub {
1927             my $self = shift;
1928             my($mode) = @_;
1929             $mode = $self->num('AccessMode', $mode);
1930             return "", $mode;
1931             }],
1932              
1933             ['SetCloseDownMode', sub {
1934             my $self = shift;
1935             my($mode) = @_;
1936             $mode = $self->num('CloseDownMode', $mode);
1937             return "", $mode;
1938             }],
1939              
1940             ['KillClient', sub {
1941             my $self = shift;
1942             my($rsrc) = @_;
1943             $rsrc = 0 if $rsrc eq "AllTemporary";
1944             return pack("L", $rsrc);
1945             }],
1946              
1947             ['RotateProperties', sub {
1948             my $self = shift;
1949             my($win, $delta, @atoms) = @_;
1950             return pack("LSsL*", $win, scalar(@atoms), $delta, @atoms);
1951             }],
1952              
1953             ['ForceScreenSaver', sub {
1954             my $self = shift;
1955             my($mode) = @_;
1956             $mode = $self->num('ScreenSaverAction', $mode);
1957             return "", $mode;
1958             }],
1959              
1960             ['SetPointerMapping', sub {
1961             my $self = shift;
1962             my(@map) = @_;
1963             my($map) = pack("C*", @map);
1964             return pack(padded($map), $map), length($map);
1965             }, sub {
1966             my $self = shift;
1967             my($data) = @_;
1968             my($status) = unpack("xCxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", $data);
1969             $status = $self->interp('MappingChangeStatus', $status);
1970             return $status;
1971             }],
1972              
1973             ['GetPointerMapping', sub {
1974             my $self = shift;
1975             return "";
1976             }, sub {
1977             my $self = shift;
1978             my($data) = @_;
1979             my($n) = unpack("xCxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", substr($data, 0, 32));
1980             return unpack("C*", substr($data, 32, $n));
1981             }],
1982              
1983             ['SetModifierMapping', sub {
1984             my $self = shift;
1985             my(@keycodes) = @_;
1986             my($n) = scalar(@{$keycodes[0]});
1987             my($kr);
1988             for $kr (@keycodes) {
1989             $kr = pack("C$n", @$kr, (0) x (@$kr - $n));
1990             }
1991             return join("", @keycodes), $n;
1992             }, sub {
1993             my $self = shift;
1994             my($data) = @_;
1995             my($status) = unpack("xCxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", $data);
1996             return $self->interp('MappingChangeStatus', $status);
1997             }],
1998              
1999             ['GetModifierMapping', sub {
2000             my $self = shift;
2001             return "";
2002             }, sub {
2003             my $self = shift;
2004             my($data) = @_;
2005             my($n) = unpack("xCxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", substr($data, 0, 32));
2006             my(@ret, $i);
2007             for $i (0 .. 7) {
2008             push @ret, [unpack("C$n", substr($data, 32 + $n * $i))];
2009             }
2010             return @ret;
2011             }],
2012              
2013             0, 0, 0, 0, 0, 0, 0,
2014              
2015             ['NoOperation', sub {
2016             my $self = shift;
2017             my($len) = @_;
2018             $len = 1 unless defined $len;
2019             return "\0" x (($len - 1) * 4);
2020             }]);
2021              
2022             my($i);
2023             for $i (0 .. 127) {
2024             if (ref $Requests[$i] and $Requests[$i][0]) {
2025             $Const{'Request'}[$i] = $Requests[$i][0];
2026             } else {
2027             $Const{'Request'}[$i] = "";
2028             }
2029             }
2030              
2031             sub get_request {
2032 0     0 0 0 my $self = shift;
2033 0         0 my($name) = @_;
2034 0         0 my($major, $minor);
2035 0         0 $major = $self->num('Request', $name);
2036 0 0       0 if ($major =~ /^\d+$/) { # Core request
2037 0         0 return ($self->{'requests'}[$major], $major);
2038             } else { # Extension request
2039 0 0       0 croak "Unknown request `$name'" unless
2040             exists $self->{'ext_request_num'}{$name};
2041 0         0 ($major, $minor) = @{$self->{'ext_request_num'}{$name}};
  0         0  
2042 0 0       0 croak "Unknown request `$name'" if int($major) == 0;
2043 0         0 return ($self->{'ext_request'}{$major}[$minor], $major, $minor);
2044             }
2045             }
2046              
2047             sub assemble_request {
2048 0     0 0 0 my $self = shift;
2049 0         0 my($op, $args, $major, $minor) = (@_, 0);
2050 0         0 my($data);
2051 0         0 ($data, $minor) = (&{$op->[1]}($self, @$args), $minor);
  0         0  
2052 0 0       0 $minor = 0 unless defined $minor;
2053 0         0 my($len) = (length($data) / 4) + 1;
2054 0 0       0 croak "Request too long!\n" if $len > $self->{'maximum_request_length'};
2055 0 0       0 if ($len <= 65535) {
2056 0         0 return pack("CCS", $major, $minor, $len) . $data;
2057             } else {
2058 0 0       0 croak "Can't happen" unless $self->{'ext'}{'BIG_REQUESTS'};
2059 0         0 return pack("CCSL", $major, $minor, 0, $len) . $data;
2060             }
2061             }
2062              
2063             sub req {
2064 0     0 0 0 my $self = shift;
2065 0         0 my($name, @args) = @_;
2066 0         0 my($op, $major, $minor) = $self->get_request($name);
2067 0 0       0 if (@$op == 2) { # No reply
    0          
    0          
2068 0         0 $self->give($self->assemble_request($op, \@args, $major, $minor));
2069 0         0 $self->next_sequence();
2070             } elsif (@$op == 3) { # One reply
2071 0         0 my($seq, $data);
2072 0         0 $self->give($self->assemble_request($op, \@args, $major, $minor));
2073 0         0 $seq = $self->next_sequence();
2074 0         0 $self->add_reply($seq & 0xffff, \$data);
2075 0         0 $self->handle_input_for($seq & 0xffff);
2076 0         0 $self->delete_reply($seq & 0xffff);
2077 0         0 return &{$op->[2]}($self, $data);
  0         0  
2078             } elsif (@$op == 4) { # Many replies
2079 0         0 my($seq, $data, @stuff, @ret);
2080 0         0 $self->give($self->assemble_request($op, \@args, $major, $minor));
2081 0         0 $seq = $self->next_sequence();
2082 0         0 $self->add_reply($seq & 0xffff, \$data);
2083 0         0 for (;;) {
2084 0         0 $data = 0; $self->handle_input_for($seq & 0xffff);
  0         0  
2085 0         0 @stuff = &{$op->[2]}($self, $data);
  0         0  
2086 0 0       0 last unless @stuff;
2087 0 0       0 if ($op->[3] eq "ARRAY") {
    0          
2088 0         0 push @ret, [@stuff];
2089             } elsif ($op->[3] eq "HASH") {
2090 0         0 push @ret, {@stuff};
2091             } else {
2092 0         0 push @ret, @stuff;
2093             }
2094             }
2095 0         0 $self->delete_reply($seq & 0xffff);
2096 0         0 return @ret;
2097             } else {
2098 0         0 croak "Can't handle request $name";
2099             }
2100             }
2101              
2102             sub robust_req {
2103 0     0 1 0 my $self = shift;
2104 0         0 my($name, @args) = @_;
2105 0         0 my($op, $major, $minor) = $self->get_request($name);
2106             # Luckily, ListFontsWithInfo can't cause any errors
2107 0 0       0 return [$self->req($name, @args)] if @$op == 4;
2108 0         0 my $err_data;
2109 0     0   0 local($self->{'error_handler'}) = sub { $err_data = $_[1]; };
  0         0  
2110 0         0 my($seq, $data);
2111 0         0 $self->give($self->assemble_request($op, \@args, $major, $minor));
2112 0         0 $seq = $self->next_sequence() & 0xffff;
2113 0 0       0 if (@$op == 2) {
2114             # No real reply, but fake up a request with a reply so we can
2115             # tell how long to wait before knowing the real request
2116             # succeeded
2117 0         0 my($fake_op, $fake_major) = $self->get_request("GetScreenSaver");
2118 0         0 $self->give($self->assemble_request($fake_op, [], $fake_major, 0));
2119 0         0 $seq = $self->next_sequence() & 0xffff;
2120             }
2121 0         0 $self->add_reply($seq, \$data);
2122 0         0 for (;;) {
2123 0         0 my $stat = $self->handle_input();
2124 0 0 0     0 if ($stat == $seq) {
    0          
2125 0         0 $self->delete_reply($seq);
2126 0 0       0 if (@$op == 3) {
2127 0         0 return [&{$op->[2]}($self, $data)];
  0         0  
2128             } else {
2129 0         0 return [];
2130             }
2131             } elsif ($stat == -1 && $self->{'error_seq'} == $seq) {
2132 0         0 my($type, undef, $info, $minor_op, $major_op)
2133             = unpack("xCSLSCxxxxxxxxxxxxxxxxxxxxx", $err_data);
2134 0         0 return($self->interp('Error', $type),
2135             $major_op, $minor_op, $info);
2136             }
2137             }
2138             }
2139              
2140             sub send {
2141 0     0 1 0 my $self = shift;
2142 0         0 my($name, @args) = @_;
2143 0         0 my($op, $major, $minor) = $self->get_request($name);
2144 0         0 $self->give($self->assemble_request($op, \@args, $major, $minor));
2145 0         0 return $self->next_sequence();
2146             }
2147              
2148             sub unpack_reply {
2149 0     0 1 0 my $self = shift;
2150 0         0 my($name, $data) = @_;
2151 0         0 my($op) = $self->get_request($name);
2152 0         0 return &{$op->[2]}($self, $data);
  0         0  
2153             }
2154              
2155             sub request {
2156 0     0 1 0 my $self = shift;
2157 0         0 $self->req(@_);
2158             }
2159              
2160             sub atom_name {
2161 0     0 1 0 my $self = shift;
2162 0         0 my($num) = @_;
2163 0 0       0 if ($self->{'atom_names'}->[$num]) {
2164 0         0 return $self->{'atom_names'}->[$num];
2165             } else {
2166 0         0 my($name) = $self->req('GetAtomName', $num);
2167 0         0 $self->{'atom_names'}->[$num] = $name;
2168 0         0 return $name;
2169             }
2170             }
2171              
2172             sub atom {
2173 0     0 1 0 my $self = shift;
2174 0         0 my($name) = @_;
2175 0 0       0 if (exists $self->{'atoms'}{$name}) {
2176 0         0 return $self->{'atoms'}{$name};
2177             } else {
2178 0         0 my($atom) = $self->req('InternAtom', $name, 0);
2179 0         0 $self->{'atoms'}{$name} = $atom;
2180 0         0 return $atom;
2181             }
2182             }
2183              
2184             sub choose_screen {
2185 0     0 1 0 my $self = shift;
2186 0         0 my($screen) = @_;
2187 0         0 my($k);
2188 0         0 for $k (keys %{$self->{'screens'}[$screen]}) {
  0         0  
2189 0         0 $self->{$k} = $self->{'screens'}[$screen]{$k};
2190             }
2191             }
2192              
2193             sub init_extension {
2194 0     0 1 0 my $self = shift;
2195 0         0 my($name) = @_;
2196 0 0       0 my($major, $event, $error) = $self->req('QueryExtension', $name)
2197             or return 0;
2198 0         0 $name =~ tr/-/_/;
2199 0 0       0 unless (defined eval { require("X11/Protocol/Ext/$name.pm") }) {
  0         0  
2200 0 0       0 return 0 if substr($@, 0, 30) eq "Can't locate X11/Protocol/Ext/";
2201 0         0 croak($@);
2202             }
2203 0         0 my($pkg) = "X11::Protocol::Ext::$name";
2204 0         0 my $obj = $pkg->new($self, $major, $event, $error);
2205 0 0       0 return 0 if not $obj;
2206 0         0 $self->{'ext'}{$name} = [$major, $event, $error, $obj];
2207             }
2208              
2209             sub init_extensions {
2210 0     0 1 0 my $self = shift;
2211 0         0 my($ext);
2212 0         0 for $ext ($self->req('ListExtensions')) {
2213 0         0 $self->init_extension($ext);
2214             }
2215             }
2216              
2217             sub new_rsrc {
2218 0     0 1 0 my $self = shift;
2219 0 0       0 if ($self->{'rsrc_id'} == $self->{'rsrc_max'} + 1) {
2220 0 0       0 if (exists $self->{'ext'}{'XC_MISC'}) {
2221 0         0 my($start, $count) = $self->req('XCMiscGetXIDRange');
2222 0         0 $self->{'rsrc_shift'} = 0;
2223 0         0 $self->{'rsrc_id'} = 0;
2224 0         0 $self->{'rsrc_base'} = $start;
2225 0         0 $self->{'rsrc_max'} = $count - 1;
2226             #print "Got $start $count\n";
2227             } else {
2228 0         0 croak "Out of resource IDs, and we don't have XC_MISC";
2229             }
2230             }
2231 0         0 my $ret = ($self->{'rsrc_id'}++ << $self->{'rsrc_shift'})
2232             + $self->{'rsrc_base'};
2233 0         0 return $ret;
2234             }
2235              
2236             sub new {
2237 1     1 1 62 my($class) = shift;
2238 1         2 my($host, $dispnum, $screen);
2239 0         0 my($conn, $display, $family);
2240 1 50 33     12 if (@_ == 0 or $_[0] eq '') {
2241 1 50       5 if ($main::ENV{'DISPLAY'}) {
2242 0         0 $display = $main::ENV{'DISPLAY'};
2243             } else {
2244 1         325 carp "Can't find DISPLAY -- guessing `$Default_Display:0'";
2245 1         5 $display = "$Default_Display:0";
2246             }
2247             } else {
2248 0 0       0 if (ref $_[0]) {
2249 0         0 $conn = $_[0];
2250             } else {
2251 0         0 $display = $_[0];
2252             }
2253             }
2254              
2255 1 50       4 unless ($conn) {
2256 1 50       237 $display =~ /^(?:[^:]*?\/)?(.*):(\d+)(?:.(\d+))?$/
2257             or croak "Invalid display: `$display'\n";
2258 1 50       6 $host = $Default_Display unless $host = $1;
2259 1         3 $dispnum = $2;
2260 1 50       5 $screen = 0 unless $screen = $3;
2261 1 50       6 if ($] >= 5.00301) { # IO::Socket is bundled
2262 1 50       13 if ($host eq 'unix') {
2263 1         858 require 'X11/Protocol/Connection/UNIXSocket.pm';
2264 1         10 $conn = X11::Protocol::Connection::UNIXSocket
2265             ->open($host, $dispnum);
2266 0           $host = 'localhost';
2267 0           $family = 'Local';
2268             } else {
2269 0           require 'X11/Protocol/Connection/INETSocket.pm';
2270 0           $conn = X11::Protocol::Connection::INETSocket
2271             ->open($host, $dispnum);
2272 0           $family = 'Internet';
2273             }
2274             } else { # Use FileHandle
2275 0 0         if ($host eq 'unix') {
2276 0           require 'X11/Protocol/Connection/UNIXFH.pm';
2277 0           $conn = X11::Protocol::Connection::UNIXFH
2278             ->open($host, $dispnum);
2279 0           $host = 'localhost';
2280 0           $family = 'Local';
2281             } else {
2282 0           require 'X11/Protocol/Connection/INETFH.pm';
2283 0           $conn = X11::Protocol::Connection::INETFH
2284             ->open($host, $dispnum);
2285 0           $family = 'Internet';
2286             }
2287             }
2288             }
2289              
2290 0           my $self = {};
2291 0           bless $self, $class;
2292 0           $self->{'connection'} = $conn;
2293 0           $self->{'byte_order'} = $Byte_Order;
2294 0           $self->{'protocol_major_version'} = 11;
2295 0           $self->{'protocol_minor_version'} = 0;
2296 0           $self->{'const'} = \%Const;
2297 0           $self->{'const_num'} = \%Const_num;
2298 0           $self->{'authorization_protocol_name'} = '';
2299 0           $self->{'authorization_protocol_data'} = '';
2300              
2301 0           my($auth);
2302              
2303 0 0 0       if (ref($_[1]) eq "ARRAY") {
  0 0          
2304 0           ($self->{'authorization_protocol_name'},
2305 0           $self->{'authorization_protocol_data'}) = @{$_[1]};
2306             } elsif ($display and eval {require X11::Auth}) {
2307 0 0         $auth = X11::Auth->new() and
2308             ($self->{'authorization_protocol_name'},
2309             $self->{'authorization_protocol_data'})
2310             = ($auth->get_by_host($host, $family, $dispnum), "", "");
2311             }
2312              
2313 0           $self->give(pack("A2 SSSS xx" .
2314             padded($self->{'authorization_protocol_name'}) .
2315             padded($self->{'authorization_protocol_data'}),
2316             $self->{'byte_order'},
2317             $self->{'protocol_major_version'},
2318             $self->{'protocol_minor_version'},
2319             length($self->{'authorization_protocol_name'}),
2320             length($self->{'authorization_protocol_data'}),
2321             $self->{'authorization_protocol_name'},
2322             $self->{'authorization_protocol_data'}));
2323              
2324 0           $self->flush;
2325 0           my($ret) = ord($self->get(1));
2326 0 0         if ($ret == 0) {
    0          
    0          
2327 0           my($len, $major, $minor, $xlen) = unpack("CSSS", $self->get(7));
2328 0           my($reason) = $self->get($xlen * 4);
2329 0           croak("Connection to server failed -- (version $major.$minor)\n",
2330             substr($reason, 0, $len));
2331             } elsif ($ret == 2) {
2332 0           croak("FIXME: authentication required\n");
2333             } elsif ($ret == 1) {
2334 0           my($major, $minor, $xlen) = unpack('xSSS', $self->get(7));
2335 0           ($self->{'release_number'}, $self->{'resource_id_base'},
2336             $self->{'resource_id_mask'}, $self->{'motion_buffer_size'},
2337             my($vlen), $self->{'maximum_request_length'}, my($screens),
2338             my($formats), $self->{'image_byte_order'},
2339             $self->{'bitmap_bit_order'}, $self->{'bitmap_scanline_unit'},
2340             $self->{'bitmap_scanline_pad'}, $self->{'min_keycode'},
2341             $self->{'max_keycode'})
2342             = unpack('LLLLSSCCCCCCCCxxxx', $self->get(32));
2343 0           $self->{'bitmap_bit_order'} =
2344             $self->interp('Significance', $self->{'bitmap_bit_order'});
2345 0           $self->{'image_byte_order'} =
2346             $self->interp('Significance', $self->{'image_byte_order'});
2347 0           $self->{'vendor'} = substr($self->get($vlen + padding $vlen),
2348             0, $vlen);
2349 0           $self->{'rsrc_shift'} = 0;
2350 0           my $mask = $self->{'resource_id_mask'};
2351 0           $self->{'rsrc_shift'}++ until ($mask >> $self->{'rsrc_shift'}) & 1;
2352 0           $self->{'rsrc_id'} = 0;
2353 0           $self->{'rsrc_base'} = $self->{'resource_id_base'};
2354 0           $self->{'rsrc_max'} = $mask;
2355            
2356 0           my($fmts) = $self->get(8 * $formats);
2357 0           my($n, $fmt);
2358 0           for $n (0 .. $formats - 1) {
2359 0           $fmt = substr($fmts, 8 * $n, 8);
2360 0           my($depth, $bpp, $pad) = unpack('CCC', $fmt);
2361 0           $self->{'pixmap_formats'}{$depth} = {'bits_per_pixel' => $bpp,
2362             'scanline_pad' => $pad};
2363             }
2364              
2365 0           my(@screens);
2366 0           while ($screens--) {
2367 0           my($root_wid, $def_cmap, $w_pixel, $b_pixel, $input_masks,
2368             $w_p, $h_p, $w_mm, $h_mm, $min_maps, $max_maps,
2369             $root_visual, $b_store, $s_unders, $depth, $n_depths)
2370             = unpack('LLLLLSSSSSSLCCCC', $self->get(40));
2371 0           my(%s) = ('root' => $root_wid, 'width_in_pixels' => $w_p,
2372             'height_in_pixels' => $h_p,
2373             'width_in_millimeters' => $w_mm,
2374             'height_in_millimeters' => $h_mm,
2375             'root_depth' => $depth, 'root_visual' => $root_visual,
2376             'default_colormap' => $def_cmap,
2377             'white_pixel' => $w_pixel, 'black_pixel' => $b_pixel,
2378             'min_installed_maps' => $min_maps,
2379             'max_installed_maps' => $max_maps,
2380             'backing_stores' =>
2381             $self->interp('BackingStore', $b_store),
2382             'save_unders' => $s_unders,
2383             'current_input_masks' => $input_masks);
2384 0           my($nd, @depths) = ();
2385 0           for $nd (1 .. $n_depths) {
2386 0           my($dep, $n_visuals) = unpack('CxSxxxx', $self->get(8));
2387 0           my($nv, %vt, @visuals) = ();
2388 0           for $nv (1 .. $n_visuals) {
2389 0           my($vid, $class, $bits_per_rgb, $map_ent, $red_mask,
2390             $green_mask, $blue_mask)
2391             = unpack('LCCSLLLxxxx', $self->get(24));
2392 0           $class = $self->interp('VisualClass', $class);
2393 0           %vt = ('visual_id' => $vid, 'class' => $class,
2394             'red_mask' => $red_mask,
2395             'green_mask' => $green_mask,
2396             'blue_mask' => $blue_mask,
2397             'bits_per_rgb_value' => $bits_per_rgb,
2398             'colormap_entries', => $map_ent);
2399 0           push @visuals, {%vt};
2400 0           delete $vt{'visual_id'};
2401 0           $self->{'visuals'}{$vid} = {%vt, 'depth' => $dep};
2402             }
2403 0           push @depths, {'depth' => $dep, 'visuals' => [@visuals]};
2404             }
2405 0           $s{'allowed_depths'} = [@depths];
2406 0           push @screens, {%s};
2407             }
2408 0           $self->{'screens'} = [@screens];
2409 0           $self->{'sequence_num'} = 1;
2410 0           $self->{'error_handler'} = \&default_error_handler;
2411 0     0     $self->{'event_handler'} = sub {};
  0            
2412 0           $self->{'requests'} = \@Requests;
2413 0           $self->{'events'} = \@Events;
2414             # 1 = uses rsrc/atom id field
2415 0           $self->{'error_type'} = [undef, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1,
2416             1, 0, 0, 0];
2417 0           $self->choose_screen($screen) if defined($screen)
2418 0 0 0       and $screen <= $#{$self->{'screens'}};
2419 0           $self->{'do_interp'} = 1;
2420             } else {
2421 0           croak("Unknown response");
2422             }
2423 0           $self->init_extension("XC-MISC");
2424 0           return $self;
2425             }
2426              
2427             sub AUTOLOAD {
2428 0     0     my($name) = $AUTOLOAD;
2429 0           $name =~ s/^.*:://;
2430 0 0         return if $name eq "DESTROY"; # Avoid problems during final cleanup
2431 0 0         if ($name =~ /^[A-Z]/) { # Protocol request
2432 0           my($obj) = shift;
2433              
2434             # Make this faster next time
2435 1     1   31 no strict 'refs'; # This is slightly icky
  1         2  
  1         529  
2436 0           my($op, $major, $minor) = $obj->get_request($name);
2437 0 0         if (@$op == 2) { # No reply
    0          
2438 0           *{$AUTOLOAD} = sub {
2439 0     0     my $self = shift;
2440 0           $self->give($self->assemble_request($op, \@_, $major, $minor));
2441 0           $self->next_sequence();
2442 0           };
2443             } elsif (@$op == 3) { # One reply
2444 0           *{$AUTOLOAD} = sub {
2445 0     0     my $self = shift;
2446 0           my($seq, $data);
2447 0           $self->give($self->assemble_request($op, \@_, $major, $minor));
2448 0           $seq = $self->next_sequence();
2449 0           $self->add_reply($seq & 0xffff, \$data);
2450 0           $self->handle_input_for($seq & 0xffff);
2451 0           $self->delete_reply($seq & 0xffff);
2452 0           return &{$op->[2]}($self, $data);
  0            
2453 0           };
2454             } else { # ListFontsWithInfo
2455             # Not worth it
2456             }
2457              
2458 0           return $obj->req($name, @_);
2459             } else { # Instance variable
2460 0 0         if (@_ == 1) {
    0          
2461 0           return $_[0]->{$name};
2462             } elsif (@_ == 2) {
2463 0           $_[0]->{$name} = $_[1];
2464             } else {
2465 0           croak "No such function `$name'";
2466             }
2467             }
2468             }
2469              
2470             1;
2471             __END__