File Coverage

blib/lib/Test/Without/Gtk2Things.pm
Criterion Covered Total %
statement 65 312 20.8
branch 3 90 3.3
condition 2 11 18.1
subroutine 18 43 41.8
pod 0 10 0.0
total 88 466 18.8


line stmt bran cond sub pod time code
1             # Copyright 2010, 2011, 2012 Kevin Ryde
2              
3             # Gtk2-Ex-WidgetBits is shared by several distributions.
4             #
5             # Gtk2-Ex-WidgetBits is free software; you can redistribute it and/or modify
6             # it under the terms of the GNU General Public License as published by the
7             # Free Software Foundation; either version 3, or (at your option) any later
8             # version.
9             #
10             # Gtk2-Ex-WidgetBits is distributed in the hope that it will be useful, but
11             # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12             # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13             # for more details.
14             #
15             # You should have received a copy of the GNU General Public License along
16             # with Gtk2-Ex-WidgetBits. If not, see .
17              
18             package Test::Without::Gtk2Things;
19 1     1   785 use 5.008;
  1         4  
  1         39  
20 1     1   5 use strict;
  1         2  
  1         28  
21 1     1   4 use warnings;
  1         3  
  1         280  
22              
23             # uncomment this to run the ### lines
24             #use Smart::Comments;
25              
26             our $VERSION = 48;
27              
28             our $VERBOSE = 0;
29              
30             # Not sure the without_foo methods are a good idea. Might prefer a hash of
31             # names so can associate a gtk version number to a without-ness, to have a
32             # "without version 2.x" option etc.
33             #
34             # FIXME: deleting the whole glob with "undef *Foo::Bar::func" is probably
35             # not a good idea. Maybe let Sub::Delete do the work.
36             #
37              
38             sub import {
39 1     1   482 my $class = shift;
40 1         2 my $count = 0;
41              
42 1         2 foreach my $thing (@_) {
43 2 100 66     13 if ($thing eq '-verbose' || $thing eq 'verbose') {
    50          
44 1         2 $VERBOSE++;
45              
46             } elsif ($thing eq 'all') {
47 1         3 foreach my $method ($class->all_without_methods) {
48 1         3 $class->$method;
49 0         0 $count++;
50             }
51              
52             } else {
53 0         0 (my $method = "without_$thing") =~ tr/-/_/;
54 0 0       0 if (! $class->can($method)) {
55 0         0 die "Unknown thing to disable: $thing";
56             }
57 0         0 $class->$method;
58 0         0 $count++;
59             }
60             }
61 0 0       0 if ($VERBOSE) {
62 0 0       0 print STDERR
63             "Test::Without::Gtk2Things -- count without $count thing",
64             ($count==1?'':'s'), "\n";
65             }
66             }
67              
68             # search @ISA with a view to subclasses, but is it a good idea?
69             sub all_without_methods {
70 2     2 0 2382 my ($class) = @_;
71             ### all_without_methods(): $class
72 2         3 my @methods;
73 1     1   4 no strict 'refs';
  1         2  
  1         181  
74 2         3 my @classes = ($class, @{"${class}::ISA"});
  2         12  
75             ### @classes
76 2         7 while (@classes) {
77 2         3 my $c = shift @classes;
78             ### $c
79             # my @keys = keys %{"${c}::"};
80             # ### keys: @keys
81 2         3 push @methods, grep {/^without_/} keys %{"${c}::"};
  44         74  
  2         17  
82 2         4 push @classes, grep {/^Test/} @{$c::ISA};
  0         0  
  2         24  
83             ### @classes
84             }
85             ### @methods
86 2         9 return @methods;
87             }
88              
89             # our @ISA = ('TestX');
90             # {
91             # package TestX;
92             # our @ISA = ('TestY');
93             # }
94             # print __PACKAGE__->all_without_methods();
95              
96             #------------------------------------------------------------------------------
97             # withouts
98              
99             sub without_blank_cursor {
100 0     0 0 0 require Gtk2;
101 0 0       0 if ($VERBOSE) {
102 0         0 print STDERR "Test::Without::Gtk2Things -- without CursorType blank-cursor, per Gtk before 2.16\n";
103             }
104              
105 1     1   5 no warnings 'redefine', 'once';
  1         16  
  1         817  
106             {
107 0         0 my $orig = Glib::Type->can('list_values');
  0         0  
108             *Glib::Type::list_values = sub {
109 0     0   0 my ($class, $package) = @_;
110 0         0 my @result = &$orig (@_);
111 0 0       0 if ($package eq 'Gtk2::Gdk::CursorType') {
112 0         0 @result = grep {$_->{'nick'} ne 'blank-cursor'} @result;
  0         0  
113             }
114 0         0 return @result;
115 0         0 };
116             }
117 0         0 foreach my $func ('new', 'new_for_display') {
118 0         0 my $orig = Gtk2::Gdk::Cursor->can($func);
119             my $new = sub {
120 0     0   0 my $cursor_type = $_[-1];
121 0 0       0 if ($cursor_type eq 'blank-cursor') {
122 0         0 require Carp;
123 0         0 Carp::croak ('Test::Without::Gtk2Things -- no blank-cursor');
124             }
125 0         0 goto $orig;
126 0         0 };
127 0         0 my $func = "Gtk2::Gdk::Cursor::$func";
128 1     1   6 no strict 'refs';
  1         1  
  1         766  
129 0         0 *$func = $new;
130             }
131             }
132              
133             sub without_cell_layout_get_cells {
134 0     0 0 0 require Gtk2;
135 0 0       0 if ($VERBOSE) {
136 0         0 print STDERR "Test::Without::Gtk2Things -- without Gtk2::CellLayout get_cells() method, per Gtk before 2.12\n";
137             }
138              
139 0         0 _without_methods ('Gtk2::CellLayout', 'get_cells');
140             }
141              
142             sub without_draw_as_radio {
143 0     0 0 0 require Gtk2;
144 0 0       0 if ($VERBOSE) {
145 0         0 print STDERR "Test::Without::Gtk2Things -- without Gtk2::CheckMenuItem/ToggleAction draw-as-radio property, per Gtk before 2.4\n";
146             }
147 0         0 _without_properties ('Gtk2::CheckMenuItem', 'draw-as-radio');
148 0         0 _without_properties ('Gtk2::ToggleAction', 'draw-as-radio');
149              
150             # check the desired effect ...
151             {
152 0 0       0 if (eval { Gtk2::CheckMenuItem->Glib::Object::new (draw_as_radio => 1) }) {
  0         0  
  0         0  
153 0         0 die 'Oops, Gtk2::CheckMenuItem create with Glib::Object::new and draw-as-radio still succeeds';
154             }
155 0 0       0 if (Gtk2::CheckMenuItem->find_property ('draw_as_radio')) {
156 0         0 die 'Oops, Gtk2::CheckMenuItem find_property("draw_as_radio") still succeeds';
157             }
158 0         0 my $action = Gtk2::ToggleAction->new (name => 'Test-Without-Gtk2Things');
159 0 0       0 if (eval { $action->get_draw_as_radio() }) {
  0         0  
160 0         0 die 'Oops, Gtk2::ToggleAction get_draw_as_radio() still available';
161             }
162             }
163             }
164              
165             sub without_insert_with_values {
166 0     0 0 0 require Gtk2;
167 0 0       0 if ($VERBOSE) {
168 0         0 print STDERR "Test::Without::Gtk2Things -- without ListStore,TreeStore insert_with_values(), per Gtk before 2.6\n";
169             }
170              
171 0         0 _without_methods ('Gtk2::ListStore', 'insert_with_values');
172 0         0 _without_methods ('Gtk2::TreeStore', 'insert_with_values');
173              
174             # check the desired effect ...
175             {
176 0         0 my $store = Gtk2::ListStore->new ('Glib::String');
  0         0  
177 0 0       0 if (eval { $store->insert_with_values(0, 0=>'foo'); 1 }) {
  0         0  
  0         0  
178 0         0 die 'Oops, Gtk2::ListStore call store->insert_with_values() still succeeds';
179             }
180             }
181             {
182 0         0 my $store = Gtk2::TreeStore->new ('Glib::String');
  0         0  
183 0 0       0 if (eval { $store->insert_with_values(undef, 0, 0=>'foo'); 1 }) {
  0         0  
  0         0  
184 0         0 die 'Oops, Gtk2::TreeStore call store->insert_with_values() still succeeds';
185             }
186             }
187             }
188              
189             sub without_menuitem_label_property {
190 1     1 0 504 require Gtk2;
191 0 0         if ($VERBOSE) {
192 0           print STDERR "Test::Without::Gtk2Things -- without Gtk2::MenuItem label and use-underline properties, per Gtk before 2.16\n";
193             }
194 0           _without_properties ('Gtk2::MenuItem', 'label', 'use-underline');
195              
196             # check the desired effect ...
197             {
198 0 0         if (eval { Gtk2::MenuItem->Glib::Object::new (label => 'hello') }) {
  0            
  0            
199 0           die 'Oops, Gtk2::MenuItem create with Glib::Object::new and label still succeeds';
200             }
201 0 0         if (eval { Gtk2::MenuItem->Glib::Object::new ('use-underline' => 1) }) {
  0            
202 0           die 'Oops, Gtk2::MenuItem create with Glib::Object::new and use-underline still succeeds';
203             }
204 0 0         if (Gtk2::MenuItem->can('get_label')) {
205 0           die 'Oops, Gtk2::MenuItem still can("get_label")';
206             }
207             }
208             }
209              
210             sub without_warp_pointer {
211 0     0 0   require Gtk2;
212 0 0         if ($VERBOSE) {
213 0           print STDERR "Test::Without::Gtk2Things -- without Gtk2::Gdk::Display warp_pointer() method, per Gtk before 2.8\n";
214             }
215              
216 0           _without_methods ('Gtk2::Gdk::Display', 'warp_pointer');
217              
218             # check the desired effect ...
219 0 0         if (Gtk2::Gdk::Display->can('get_default')) { # new in Gtk 2.2
220 0 0         if (my $display = Gtk2::Gdk::Display->get_default) {
221 0 0         if (my $coderef = $display->can('warp_pointer')) {
222 0           die "Oops, display->can(warp_pointer) still true: $coderef";
223             }
224             }
225             }
226             }
227              
228             sub without_widget_tooltip {
229 0     0 0   require Gtk2;
230 0 0         if ($VERBOSE) {
231 0           print STDERR "Test::Without::Gtk2Things -- without Gtk2::Widget tooltips, per Gtk before 2.12\n";
232             }
233 0           _without_properties ('Gtk2::Widget',
234             'tooltip-text', 'tooltip-markup', 'has-tooltip');
235 0           _without_methods ('Gtk2::Widget',
236             'get_tooltip_text', 'set_tooltip_text',
237             'get_tooltip_markup', 'set_tooltip_markup',
238             'get_has_tooltip', 'set_has_tooltip',);
239 0           _without_signals ('Gtk2::Widget', 'query-tooltip');
240             }
241              
242             sub without_gdkdisplay {
243 0     0 0   require Gtk2;
244 0 0         if ($VERBOSE) {
245 0           print STDERR "Test::Without::Gtk2Things -- without Gdk2::Gdk::Display and Gtk2::Gdk::Screen, per Gtk 2.0.x\n";
246             }
247              
248             # In Gtk 2.2 up Gtk2::Gdk->get_default_root_window() gives a g_log()
249             # warning if no Gtk2->init() yet. Wrap it to quietly give undef the same
250             # as in Gtk 2.0.0.
251             #
252             # Something in recent Gtk or Perl-Gtk or Perl doesn't like running the
253             # Gtk2::Gdk::Screen->get_default when that package has otherwise been
254             # killed. How to cleanly test for init-ed?
255             #
256             {
257 0           my $get_default_screen = Gtk2::Gdk::Screen->can('get_default');
  0            
258 0   0       my $orig = Gtk2::Gdk->can('get_default_root_window') || die;
259 1     1   5 no warnings 'redefine';
  1         2  
  1         380  
260             *Gtk2::Gdk::get_default_root_window = sub {
261 0     0     local $SIG{__WARN__} = sub {};
  0            
262 0           return &$orig(@_);
263            
264             # ### Without get_default_root_window() ...
265             # my $x = Gtk2::Gdk::Screen->$get_default_screen();
266             # print "$x\n";
267             # if (! Gtk2::Gdk::Screen->$get_default_screen()) {
268             # return undef;
269             # }
270             # # this could have been "goto $orig" but have seen trouble in 5.8.9
271             # # jumping to an XSUB like that
272             # return &$orig(@_);
273 0           };
274             }
275              
276 0           _without_packages ('Gtk2::Gdk::Display', 'Gtk2::Gdk::Screen');
277              
278 0           _without_methods ('Gtk2::Gdk',
279             'get_display_arg_name',
280             'text_property_to_text_list_for_display',
281             'text_property_to_utf8_list_for_display',
282             'utf8_to_compound_text_for_display');
283 0           _without_methods ('Gtk2::Gdk::Cursor',
284             'get_display',
285             'new_for_display','new_from_name','new_from_pixbuf');
286 0           _without_methods ('Gtk2::Gdk::Colormap', 'get_screen');
287 0           _without_methods ('Gtk2::Gdk::Drawable', 'get_display', 'get_screen');
288 0           _without_methods ('Gtk2::Gdk::Font', 'get_display');
289 0           _without_methods ('Gtk2::Gdk::GC', 'get_screen');
290 0           _without_methods ('Gtk2::Gdk::Event', 'get_screen','set_screen',
291             'send_client_message_for_display');
292 0           _without_methods ('Gtk2::Gdk::Visual', 'get_screen');
293              
294             # mangle the base Gtk2::Widget class so can() is false for subclasses
295 0           _without_methods ('Gtk2::Widget', 'get_display', 'get_screen',
296             'has_screen');
297 0           _without_signals ('Gtk2::Widget', 'screen-changed');
298              
299 0           _without_methods ('Gtk2::Clipboard', 'get_display', 'get_for_display');
300 0           _without_methods ('Gtk2::Invisible', 'get_screen','set_screen',
301             'new_for_screen');
302 0           _without_methods ('Gtk2::Menu', 'set_screen');
303 0           _without_methods ('Gtk2::MountOperation','get_screen');
304 0           _without_methods ('Gtk2::StatusIcon', 'get_screen','set_screen');
305 0           _without_methods ('Gtk2::Window', 'get_screen','set_screen');
306 0           _without_properties ('Gtk2::Window', 'screen');
307              
308             # check the desired effect ...
309 0 0         if (my $coderef = Gtk2::Gdk::Display->can('get_default')) {
310 0           die "Oops, Gtk2::Gdk::Display->can(get_default) still true: $coderef";
311             }
312 0 0         if (my $coderef = Gtk2::Gdk::Screen->can('get_display')) {
313 0           die "Oops, Gtk2::Gdk::Screen->can(get_display) still true: $coderef";
314             }
315             }
316              
317             sub without_builder {
318 0     0 0   require Gtk2;
319 0 0         if ($VERBOSE) {
320 0           print STDERR "Test::Without::Gtk2Things -- without Gtk2::Builder and Buildable interface, per Gtk before 2.12\n";
321             }
322 0           _without_packages ('Gtk2::Builder');
323 0           _without_interfaces ('Gtk2::Buildable');
324             }
325              
326             #------------------------------------------------------------------------------
327             # removing stuff
328              
329             sub _without_interfaces {
330 0     0     _without_packages (@_);
331              
332             {
333 1     1   4 no warnings 'redefine', 'once';
  1         2  
  1         117  
  0            
334 0           my %without;
335 0           @without{@_} = (); # hash slice
336 0           my $orig = UNIVERSAL->can('isa');
337              
338             *UNIVERSAL::isa = sub {
339 0     0     my ($class_or_instance, $type) = @_;
340 0 0         if (exists $without{$type}) {
341 0           return !1; # false
342             }
343 0           goto $orig;
344 0           };
345             }
346             }
347              
348             sub _without_packages {
349 0     0     foreach my $package (@_) {
350 0           $package->can('something'); # finish lazy loading, or some such
351 1     1   4 no strict 'refs';
  1         6  
  1         121  
352 0           foreach my $name (%{"${package}::"}) {
  0            
353 0           my $fullname = "${package}::$name";
354 0           undef *$fullname;
355             }
356             }
357             }
358              
359             sub _without_methods {
360 0     0     my $class = shift;
361 0           foreach my $method (@_) {
362             # force autoload ... umm, or something
363 0           $class->can($method);
364              
365 0           my $fullname = "${class}::$method";
366 1     1   6 { no strict 'refs'; undef *$fullname; }
  1         1  
  1         169  
  0            
  0            
367             }
368              
369             # check the desired effect ...
370 0           foreach my $method (@_) {
371 0 0         if (my $coderef = $class->can($method)) {
372 0           die "Oops, $class->can($method) still true: $coderef";
373             }
374             }
375             }
376              
377             sub _without_properties {
378 0     0     my ($without_class, @without_pnames) = @_;
379              
380 0           foreach my $without_pname (@without_pnames) {
381 0           (my $method = $without_pname) =~ tr/-/_/;
382 0           _without_methods ($without_class, "get_$method", "set_$method");
383             }
384              
385 0           my %without_pnames;
386 0           @without_pnames{@without_pnames} = (1) x scalar(@without_pnames); # slice
387              
388 1     1   4 no warnings 'redefine', 'once';
  1         1  
  1         403  
389             {
390 0           my $orig = Glib::Object->can('list_properties');
  0            
391             *Glib::Object::list_properties = sub {
392 0     0     my ($class) = @_;
393 0 0         if ($class->isa($without_class)) {
394 0           return grep {! $without_pnames{$_->get_name}} &$orig (@_);
  0            
395             }
396 0           goto $orig;
397 0           };
398             }
399             {
400 0           my $orig = Glib::Object->can('find_property');
  0            
401             *Glib::Object::find_property = sub {
402 0     0     my ($class, $pname) = @_;
403 0 0 0       if ($class->isa($without_class)
404             && _pnames_match ($pname, \%without_pnames)) {
405             ### wrapped find_property() exclude
406 0           return undef;
407             }
408 0           goto $orig;
409 0           };
410             }
411 0           foreach my $func ('get', 'get_property') {
412 0           my $orig = Glib::Object->can($func);
413             my $new = sub {
414 0 0   0     if ($_[0]->isa($without_class)) {
415 0           for (my $i = 1; $i < @_; $i++) {
416 0           my $pname = $_[$i];
417 0 0         if (_pnames_match ($pname, \%without_pnames)) {
418 0           require Carp;
419 0           Carp::croak ("Test-Without-Gtk2Things: no get property $pname");
420             }
421             }
422             }
423 0           goto $orig;
424 0           };
425 0           my $func = "Glib::Object::$func";
426 1     1   6 no strict 'refs';
  1         2  
  1         200  
427 0           *$func = $new;
428             }
429 0           foreach my $func ('new', 'set', 'set_property') {
430 0           my $orig = Glib::Object->can($func); # force autoload
431             my $new = sub {
432 0 0   0     if ($_[0]->isa($without_class)) {
433 0           for (my $i = 1; $i < @_; $i += 2) {
434 0           my $pname = $_[$i];
435 0 0         if (_pnames_match ($pname, \%without_pnames)) {
436 0           require Carp;
437 0           Carp::croak ("Test-Without-Gtk2Things: no set property $pname");
438             }
439             }
440             }
441 0           goto $orig;
442 0           };
443 0           my $func = "Glib::Object::$func";
444 1     1   5 no strict 'refs';
  1         2  
  1         251  
445 0           *$func = $new;
446             }
447              
448              
449             # check the desired effect ...
450 0           foreach my $without_pname (@without_pnames) {
451 0 0         if (my $pspec = $without_class->find_property($without_pname)) {
452 0           die "Oops, $without_class->find_property() still finds $without_pname: $pspec";
453             }
454 0 0         if (my @pspecs = grep {$_->get_name eq $without_pname}
  0            
455             $without_class->list_properties) {
456 0           local $, = ' ';
457 0           die "Oops, $without_class->list_properties() still finds $without_pname: @pspecs";
458             }
459             }
460             }
461              
462             sub _pnames_match {
463 0     0     my ($pname, $without_pnames) = @_;
464             ### $pname
465 0           $pname =~ tr/_/-/;
466 0           return $without_pnames->{$pname};
467             }
468              
469             sub _without_signals {
470 0     0     my ($without_class, @without_signames) = @_;
471              
472 0           my %without_signames;
473 0           @without_signames{@without_signames} # hash slice
474             = (1) x scalar(@without_signames);
475              
476 1     1   5 no warnings 'redefine', 'once';
  1         2  
  1         405  
477             {
478 0           require Glib;
  0            
479 0           my $orig = Glib::Type->can('list_signals');
480             *Glib::Type::list_signals = sub {
481 0     0     my (undef, $list_class) = @_;
482 0 0         if ($list_class->isa($without_class)) {
483 0           return grep {! $without_signames{$_->{'signal_name'}}} &$orig (@_);
  0            
484             }
485 0           goto $orig;
486 0           };
487             }
488             {
489 0           my $orig = Glib::Object->can('signal_query');
  0            
490             *Glib::Object::signal_query = sub {
491 0     0     my ($class, $signame) = @_;
492 0 0 0       if ($class->isa($without_class)
493             && _pnames_match ($signame, \%without_signames)) {
494             ### wrapped signal_query() exclude
495 0           return undef;
496             }
497 0           goto $orig;
498 0           };
499             }
500 0           foreach my $func ('signal_connect',
501             'signal_connect_after',
502             'signal_connect_swapped',
503             'signal_emit',
504             'signal_add_emission_hook',
505             'signal_remove_emission_hook',
506             'signal_stop_emission_by_name') {
507 0           my $orig = Glib::Object->can($func);
508             my $new = sub {
509 0     0     my ($obj, $signame) = @_;
510 0 0         if ($obj->isa($without_class)) {
511 0 0         if (_pnames_match ($signame, \%without_signames)) {
512 0           require Carp;
513 0           Carp::croak ("Test-Without-Gtk2Things: no signal $signame");
514             }
515             }
516 0           goto $orig;
517 0           };
518 0           my $func = "Glib::Object::$func";
519 1     1   6 no strict 'refs';
  1         2  
  1         179  
520 0           *$func = $new;
521             }
522              
523              
524             # check the desired effect ...
525 0           foreach my $without_signame (@without_signames) {
526 0 0         if (my $siginfo = $without_class->signal_query($without_signame)) {
527 0           die "Oops, $without_class->signal_query() still finds $without_signame: $siginfo";
528             }
529 0 0         if (my @siginfos = grep {$_->{'signal_name'} eq $without_signame}
  0            
530             Glib::Type->list_signals($without_class)) {
531 0           local $, = ' ';
532 0           die "Oops, Glib::Type->list_signals($without_class) still finds $without_signame: @siginfos";
533             }
534             }
535             }
536              
537             1;
538             __END__