File Coverage

blib/lib/Image/Base/X11/Protocol/Window.pm
Criterion Covered Total %
statement 14 158 8.8
branch 0 76 0.0
condition 0 120 0.0
subroutine 5 18 27.7
pod 7 8 87.5
total 26 380 6.8


line stmt bran cond sub pod time code
1             # Copyright 2010, 2011, 2012, 2013 Kevin Ryde
2              
3             # This file is part of Image-Base-X11-Protocol.
4             #
5             # Image-Base-X11-Protocol is free software; you can redistribute it and/or
6             # modify it under the terms of the GNU General Public License as published
7             # by the Free Software Foundation; either version 3, or (at your option) any
8             # later version.
9             #
10             # Image-Base-X11-Protocol is distributed in the hope that it will be useful,
11             # but WITHOUT ANY WARRANTY; without even the implied warranty of
12             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13             # Public License for more details.
14             #
15             # You should have received a copy of the GNU General Public License along
16             # with Image-Base-X11-Protocol. If not, see .
17              
18              
19             # X11::Protocol::Ext::SHAPE
20             # /usr/share/doc/x11proto-xext-dev/shape.txt.gz
21             # /usr/share/doc/x11proto-core-dev/x11protocol.txt.gz
22             #
23              
24             package Image::Base::X11::Protocol::Window;
25 2     2   41186 use 5.004;
  2         10  
26 2     2   12 use strict;
  2         6  
  2         48  
27 2     2   13 use Carp;
  2         5  
  2         133  
28 2     2   14 use vars '@ISA', '$VERSION';
  2         5  
  2         119  
29              
30 2     2   1095 use Image::Base::X11::Protocol::Drawable;
  2         6  
  2         2574  
31             @ISA = ('Image::Base::X11::Protocol::Drawable');
32              
33             # uncomment this to run the ### lines
34             # use Smart::Comments;
35              
36             $VERSION = 15;
37              
38              
39             sub new {
40 0     0 1   my ($class, %params) = @_;
41             ### X11-Protocol-Window new()
42              
43             # lookup -colormap from -window if not supplied
44 0 0         if (! defined $params{'-colormap'}) {
45 0           my %attrs = $params{'-X'}->GetWindowAttributes ($params{'-window'});
46 0           $params{'-colormap'} = $attrs{'colormap'};
47             }
48              
49             # alias -window to -drawable
50 0 0         if (my $win = delete $params{'-window'}) {
51 0           $params{'-drawable'} = $win;
52             }
53              
54 0           return $class->SUPER::new (%params);
55             }
56              
57             sub DESTROY {
58 0     0     my ($self) = @_;
59             ### X11-Protocol-Window DESTROY
60 0           _free_bitmap_gc($self);
61 0           shift->SUPER::DESTROY (@_);
62             }
63             sub _free_bitmap_gc {
64 0     0     my ($self) = @_;
65 0 0         if (my $bitmap_gc = delete $self->{'_bitmap_gc'}) {
66             ### FreeGC bitmap_gc: $bitmap_gc
67 0           $self->{'-X'}->FreeGC ($bitmap_gc);
68             }
69             }
70              
71             my %get_window_attributes = (-colormap => 1,
72             -visual => 1);
73             sub _get {
74 0     0     my ($self, $key) = @_;
75             ### X11-Protocol-Window _get(): $key
76              
77 0 0         if (! exists $self->{$key}) {
78 0 0         if ($get_window_attributes{$key}) {
79 0   0       my $attr = ($self->{'_during_get'}->{'GetWindowAttributes'} ||= do {
80 0           my %attr = $self->{'-X'}->GetWindowAttributes ($self->{'-drawable'});
81 0           foreach my $field ('visual') {
82 0 0         if (! exists $self->{"-$field"}) { # unchanging
83 0           $self->{"-$field"} = $attr{$field};
84             }
85             }
86 0           \%attr
87             });
88 0           return $attr->{substr($key,1)};
89             }
90             }
91 0           return $self->SUPER::_get($key);
92             }
93              
94             sub set {
95 0     0 1   my ($self, %params) = @_;
96              
97 0 0         if (exists $params{'-drawable'}) {
98 0           _free_bitmap_gc ($self);
99 0           delete $self->{'-visual'}; # must be refetched, or provided in %params
100             }
101              
102 0           my $width = delete $params{'-width'};
103 0           my $height = delete $params{'-height'};
104              
105             # set -drawable before applying -width and -height
106 0           $self->SUPER::set (%params);
107              
108 0 0 0       if (defined $width || defined $height) {
109             $self->{'-X'}->ConfigureWindow
110 0 0         ($self->{'-drawable'},
    0          
111             (defined $width ? (width => $width) : ()),
112             (defined $height ? (height => $height) : ()));
113             }
114             }
115              
116             #------------------------------------------------------------------------------
117             # drawing
118              
119             sub xy {
120 0     0 1   my ($self, $x, $y, $colour) = @_;
121             ### Window xy(): "$x, $y".(@_>=4 && ", $colour")
122              
123 0 0         if ((my $X = $self->{'-X'})->{'ext'}->{'SHAPE'}) {
124              
125             # don't overflow INT16 in requests
126 0 0 0       if ($x < 0 || $y < 0 || $x > 0x7FFF || $y > 0x7FFF) {
      0        
      0        
127             ### entirely outside max possible drawable ...
128 0           return undef; # fetch or store
129             }
130              
131 0 0         if (@_ >= 4) {
132 0 0         if ($colour eq 'None') {
133             ### Window xy() subtract shape ...
134 0           $X->ShapeRectangles ($self->{'-drawable'},
135             'Bounding',
136             'Subtract',
137             0,0, # offset
138             'YXBanded',
139             [ $x,$y, 1,1 ]);
140 0           return;
141             }
142             } else {
143             ### Window xy() fetch shape ...
144 0           my ($ordering, @rects) = $X->ShapeGetRectangles ($self->{'-drawable'},
145             'Bounding');
146             ### @rects
147 0 0         if (! _rects_contain_xy($x,$y,@rects)) {
148 0           return 'None';
149             }
150             }
151             }
152 0           shift->SUPER::xy (@_);
153             }
154              
155             sub line {
156 0     0 1   my ($self, $x1,$y1, $x2,$y2, $colour) = @_;
157             ### X11-Protocol-Window line(): $x1,$y1, $x2,$y2, $colour
158              
159 0 0 0       if ($colour eq 'None'
160             && (my $X = $self->{'-X'}) ->{'ext'}->{'SHAPE'}) {
161              
162 0 0         unless (Image::Base::X11::Protocol::Drawable::_line_any_positive($x1,$y1, $x2,$y2)) {
163             ### nothing positive ...
164 0           return;
165             }
166 0           my $bitmap_width = abs($x2-$x1)+1;
167 0           my $bitmap_height = abs($y2-$y1)+1;
168 0 0 0       if ($bitmap_width > 0x7FFF || $bitmap_height > 0x7FFF
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
169             || $x1 < -0x8000 || $x2 < -0x8000
170             || $x1 > 0x7FFF || $x2 > 0x7FFF
171             || $y1 < -0x8000 || $y2 < -0x8000
172             || $y1 > 0x7FFF || $y2 > 0x7FFF) {
173             ### coordinates would overflow, use superclass ...
174 0           shift->SUPER::line(@_);
175 0           return;
176             }
177              
178 0           my ($bitmap, $bitmap_gc) = _make_bitmap_and_gc
179             ($self, $bitmap_width , $bitmap_height);
180              
181 0 0         my $xmin = ($x1 < $x2 ? $x1 : $x2);
182 0 0         my $ymin = ($y1 < $y2 ? $y1 : $y2);
183 0           $X->PolySegment ($bitmap, $bitmap_gc,
184             $x1-$xmin,$y1-$ymin, $x2-$xmin,$y2-$ymin);
185 0           $X->ShapeMask ($self->{'-drawable'},
186             'Bounding',
187             'Subtract',
188             $xmin,$ymin, # offset
189             $bitmap);
190 0           $X->FreePixmap ($bitmap);
191             } else {
192 0           shift->SUPER::line (@_);
193             }
194             }
195              
196             sub rectangle {
197 0     0 1   my ($self, $x1, $y1, $x2, $y2, $colour, $fill) = @_;
198             ### Window rectangle: $x1, $y1, $x2, $y2, $colour, $fill
199 0 0 0       if ($colour eq 'None'
200             && (my $X = $self->{'-X'}) ->{'ext'}->{'SHAPE'}) {
201              
202 0 0 0       unless ($x2 >= 0 && $y2 >= 0 && $x1 <= 0x7FFF && $y1 <= 0x7FFF) {
      0        
      0        
203             ### entirely outside max possible drawable ...
204 0           return;
205             }
206              
207             # don't underflow INT16 -0x8000 x,y in request
208             # retain negativeness so as not to bring unfilled sides into view
209 0 0         if ($x1 < -1) { $x1 = -1; }
  0            
210 0 0         if ($y1 < -1) { $y1 = -1; }
  0            
211              
212             # don't overflow CARD16 width,height in request
213 0 0         if ($x2 > 0x7FFF) { $x2 = 0x7FFF; }
  0            
214 0 0         if ($y2 > 0x7FFF) { $y2 = 0x7FFF; }
  0            
215              
216 0           my @rects;
217 0           my $width = $x2 - $x1 + 1;
218 0           my $height = $y2 - $y1 + 1;
219 0 0 0       if ($fill
      0        
220             || $width <= 2
221             || $height <= 2) {
222             # filled, or unfilled 2xN or Nx2 as one rectangle
223 0           @rects = ([ $x1, $y1, $width, $height ]);
224             } else {
225             # unfilled, line segments
226 0           @rects = ([ $x1, $y1, $width, 1 ], # top
227             [ $x1,$y1+1, 1, $height-2 ], # left
228             [ $x2,$y1+1, 1, $height-2 ], # right
229             [ $x1, $y2, $width, 1 ]); # bottom
230             }
231 0           $X->ShapeRectangles ($self->{'-drawable'},
232             'Bounding',
233             'Subtract',
234             0,0, # offset
235             'YXBanded', @rects);
236              
237             } else {
238 0           $self->SUPER::rectangle ($x1, $y1, $x2, $y2, $colour, $fill);
239             }
240             }
241             sub Image_Base_Other_rectangles {
242             ### X11-Protocol-Window rectangles() ...
243 0     0 0   my $self = shift;
244 0           my $colour = shift;
245 0           my $fill = shift;
246              
247             # ENHANCE-ME: multiple rectangles at once to ShapeRectangles()
248             ### rectangles: @_
249 0           while (@_) {
250 0           $self->rectangle (shift,shift,shift,shift, $colour, $fill);
251             }
252             }
253              
254             sub ellipse {
255 0     0 1   my ($self, $x1,$y1, $x2,$y2, $colour, $fill) = @_;
256             ### Window ellipse(): $x1,$y1, $x2,$y2, $colour
257 0 0 0       if ($colour eq 'None'
258             && (my $X = $self->{'-X'}) ->{'ext'}->{'SHAPE'}) {
259             ### use shape ...
260              
261 0 0 0       unless ($x2 >= 0 && $y2 >= 0 && $x1 <= 0x7FFF && $y1 <= 0x7FFF) {
      0        
      0        
262             ### entirely outside max possible drawable ...
263 0           return;
264             }
265 0 0 0       if ($x1 < -0x8000 || $x2 > 0x7FFF || $y1 < -0x8000 || $y2 > 0x7FFF) {
      0        
      0        
266             ### coordinates would overflow, use superclass ...
267 0           shift->SUPER::ellipse(@_);
268 0           return;
269             }
270              
271 0           my $win = $self->{'-drawable'};
272 0           my $w = $x2 - $x1;
273 0           my $h = $y2 - $y1;
274 0 0 0       if ($w <= 1 || $h <= 1) {
275 0           $X->ShapeRectangles ($win,
276             'Bounding',
277             'Subtract',
278             0,0, # offset
279             'YXBanded',
280             [ $x1, $y1, $w+1, $h+1 ]);
281             } else {
282 0           my ($bitmap, $bitmap_gc) = _make_bitmap_and_gc ($self, $w+1, $h+1);
283              
284             # fill+outline per comments in Drawable.pm
285 0           my @args = ($bitmap, $bitmap_gc, [ 0, 0, $w, $h, 0, 365*64 ]);
286 0 0         if ($fill) {
287 0           $X->PolyFillArc (@args);
288             }
289 0           $X->PolyArc (@args);
290              
291 0           $X->ShapeMask ($self->{'-drawable'},
292             'Bounding',
293             'Subtract',
294             $x1,$y1, # offset
295             $bitmap);
296 0           $X->FreePixmap ($bitmap);
297             }
298             } else {
299 0           shift->SUPER::ellipse (@_);
300             }
301             }
302              
303             sub diamond {
304 0     0 1   my ($self, $x1,$y1, $x2,$y2, $colour, $fill) = @_;
305             ### Window diamond(): $x1,$y1, $x2,$y2, $colour
306              
307 0 0 0       if ($colour eq 'None'
308             && (my $X = $self->{'-X'}) ->{'ext'}->{'SHAPE'}) {
309             ### use shape ...
310              
311 0 0 0       if ($x1==$x2 && $y1==$y2) {
312             # 1x1 polygon draws nothing, do it as a point instead
313 0           $self->xy ($x1,$y1, $colour);
314 0           return;
315             }
316              
317 0 0 0       unless ($x2 >= 0 && $y2 >= 0 && $x1 <= 0x7FFF && $y1 <= 0x7FFF) {
      0        
      0        
318             ### entirely outside max possible drawable ...
319 0           return;
320             }
321 0 0 0       if ($x1 < -0x8000 || $x2 > 0x7FFF || $y1 < -0x8000 || $y2 > 0x7FFF) {
      0        
      0        
322             ### coordinates would overflow, use superclass ...
323 0           shift->SUPER::diamond(@_);
324 0           return;
325             }
326              
327 0           my $drawable = $self->{'-drawable'};
328              
329 0           $x2 -= $x1; # offset so 0,0 to x2,y2
330 0           $y2 -= $y1;
331 0           my ($bitmap, $bitmap_gc)
332             = _make_bitmap_and_gc ($self, $x2+1, $y2+1); # width,height
333 0           Image::Base::X11::Protocol::Drawable::_diamond_drawable
334             ($X, $bitmap, $bitmap_gc, 0,0, $x2,$y2, $fill);
335 0           $X->ShapeMask ($drawable,
336             'Bounding',
337             'Subtract',
338             $x1,$y1, # offset
339             $bitmap);
340 0           $X->FreePixmap ($bitmap);
341              
342             } else {
343 0           shift->SUPER::diamond (@_);
344             }
345             }
346              
347             #------------------------------------------------------------------------------
348             sub _make_bitmap_and_gc {
349 0     0     my ($self, $width, $height) = @_;
350             ### _make_bitmap_and_gc(): "$width,$height"
351 0           my $X = $self->{'-X'};
352              
353 0           my $bitmap = $X->new_rsrc;
354             ### CreatePixmap of bitmap: $bitmap
355 0           $X->CreatePixmap ($bitmap, $self->{'-drawable'}, 1, $width, $height);
356              
357 0           my $bitmap_gc = $self->{'_bitmap_gc'};
358 0 0         if ($bitmap_gc) {
359 0           $X->ChangeGC ($bitmap_gc, foreground => 0);
360             } else {
361 0           $bitmap_gc = $X->new_rsrc;
362 0           $X->CreateGC ($bitmap_gc, $bitmap, foreground => 0);
363             }
364 0           $X->PolyFillRectangle ($bitmap, $bitmap_gc, [0,0, $width,$height]);
365 0           $X->ChangeGC ($bitmap_gc, foreground => 1);
366 0           return ($bitmap, $bitmap_gc);
367             }
368              
369             #------------------------------------------------------------------------------
370              
371             # _rects_contain_xy($x,$y, [$rx,$ry,$rw,$rh],...) returns true if pixel
372             # $x,$y is within any of the given rectangle arrayrefs.
373             #
374             # For any order except Unsorted could stop searching when $ry > $y, if that
375             # was worth the extra code.
376             #
377             sub _rects_contain_xy {
378             ### _rects_contain_xy() ...
379 0     0     my $x = shift;
380 0           my $y = shift;
381 0           while (@_) {
382 0           my ($rx,$ry,$width,$height) = @{(shift)};
  0            
383 0 0 0       if ($rx <= $x && $rx+$width > $x
      0        
      0        
384             && $ry <= $y && $ry+$height > $y) {
385             ### found: "$x,$y in $rx,$ry, $width,$height"
386 0           return 1;
387             }
388             }
389             ### not found ...
390 0           return 0;
391             }
392              
393              
394             1;
395             __END__