File Coverage

blib/lib/App/Chart/Gtk2/Ex/ToplevelSingleton.pm
Criterion Covered Total %
statement 22 42 52.3
branch 1 6 16.6
condition 0 3 0.0
subroutine 8 14 57.1
pod 0 5 0.0
total 31 70 44.2


line stmt bran cond sub pod time code
1             # instance per-screen ?
2             # instance per-display and move to screen ?
3             #
4             # searching through list_toplevels picks up non-instance created windows
5             # too, maybe flag those created this way ...
6             #
7             # isa() in search might rightly or wrongly pick up subclasses
8              
9              
10             # Copyright 2009, 2010 Kevin Ryde
11              
12             # This file is part of Chart.
13             #
14             # Chart is free software; you can redistribute it and/or modify
15             # it under the terms of the GNU General Public License as published by the
16             # Free Software Foundation; either version 3, or (at your option) any later
17             # version.
18             #
19             # Chart is distributed in the hope that it will be useful, but
20             # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21             # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22             # for more details.
23             #
24             # You should have received a copy of the GNU General Public License along
25             # with Chart. If not, see <http://www.gnu.org/licenses/>.
26              
27             package App::Chart::Gtk2::Ex::ToplevelSingleton;
28 1     1   97524 use 5.008;
  1         13  
29 1     1   4 use strict;
  1         2  
  1         16  
30 1     1   3 use warnings;
  1         2  
  1         20  
31 1     1   4 use List::Util;
  1         1  
  1         41  
32 1     1   266 use App::Chart::Gtk2::Ex::ToplevelBits;
  1         2  
  1         39  
33              
34             # uncomment this to run the ### lines
35             #use Smart::Comments;
36              
37             sub import {
38 1     1   6 my ($class, %options) = @_;
39 1 50       21 if (%options) {
40 1     1   5 no strict 'refs';
  1         1  
  1         203  
41 0           ${"${class}::_instance_options"} = \%options;
  0            
42             }
43             }
44              
45             # ClassName->has_instance ()
46             sub has_instance {
47 0     0 0   my $class = shift;
48 0           return $class->has_instance_for_screen (undef, @_);
49             }
50             # ClassName->has_instance_for_screen ($screen)
51             sub has_instance_for_screen {
52 0     0 0   my ($class, $screen) = @_;
53 0           $screen = App::Chart::Gtk2::Ex::ToplevelBits::_screen($screen);
54              
55             # searching like this isn't fast, but it allows a toplevel to be moved to
56             # a different screen
57 0 0   0     return List::Util::first { ($_->isa($class) && $_->get_screen == $screen) }
58 0           Gtk2::Window->list_toplevels;
59             }
60              
61             # ClassName->instance (args...)
62             sub instance {
63 0     0 0   my $class = shift;
64 0           return $class->instance_for_screen (undef, @_);
65             }
66              
67             # ClassName->instance_for_screen ($screen, args...)
68             sub instance_for_screen {
69 0     0 0   my ($class, $screen) = (shift, shift);
70              
71             return $class->has_instance_for_screen($screen)
72 0   0       || do {
73             ### ToplevelSingleton instance create
74             $class->new_instance (screen => App::Chart::Gtk2::Ex::ToplevelBits::_screen($screen),
75             @_);
76             };
77             }
78              
79             # default instance constructor
80             sub new_instance {
81 0     0 0   my ($class) = @_;
82 0           my $self = Glib::Object::new (@_);
83 1     1   6 my $options = do { no strict 'refs';
  1         2  
  1         65  
  0            
84 0           ${"${class}::_instance_options"} };
  0            
85 0 0         if ($options->{'hide_on_delete'}) {
86 0           $self->signal_connect (delete_event => \&Gtk2::Widget::hide_on_delete);
87             }
88 0           return $self;
89             }
90              
91             1;
92             __END__
93              
94              
95             # # ClassName->has_instance_for_display ($display)
96             # sub has_instance_for_display {
97             # my ($class, $display) = @_;
98             # $display = _display($display);
99             #
100             # # searching like this isn't fast, but it allows a toplevel to be moved to
101             # # a different display
102             # return List::Util::first { ($_->isa($class) && $_->get_display == $display) }
103             # Gtk2::Window->list_toplevels;
104             # }
105             # # ClassName->instance_for_display ($display, args...)
106             # sub instance_for_display {
107             # my ($class, $display) = (shift, shift);
108             #
109             # return ($class->has_instance_for_display($display)
110             # || $class->instance_for_screen($display, @_));
111             # }
112             # sub _display {
113             # my ($obj) = @_;
114             # if (! defined $obj) {
115             # return Gtk2::Gdk::Screen->get_default->get_display;
116             # }
117             # if ($obj->can('get_display')) {
118             # $obj = $obj->get_display
119             # || croak "No display for target $obj";
120             # }
121             # return $obj;
122             # }
123              
124             # return ($display->{(__PACKAGE__)}->{$class} ||= do {
125              
126             # $instance->signal_connect (destroy => \&_do_destroy, $class);
127             # sub _do_destroy {
128             # my ($instance, $class) = @_;
129             # my $display = $instance->get_display;
130             # if (($display->{(__PACKAGE__)}->{$class}||0) == $instance) {
131             # delete $display->{(__PACKAGE__)}->{$class};
132             # }
133             # }
134              
135             # use Class::Singleton 1.04; # 1.04 for has_instance()
136             # use base 'Class::Singleton';
137             #
138             # sub instance {
139             # my $class = shift;
140             # return $class->has_instance
141             # || do {
142             # my $instance = $class->SUPER::instance;
143             # $instance->signal_connect (destroy => \&_do_destroy, $ivar);
144             # $instance
145             # };
146             # }
147             #
148             # sub _do_destroy {
149             # my ($instance, $ivar) = @_;
150             # if (($instance->has_instance || 0) == $instance) {
151             # undef $ivar;
152             # }
153             # }
154              
155             =for stopwords toplevel multi
156              
157             =head1 NAME
158              
159             App::Chart::Gtk2::Ex::ToplevelSingleton -- single instance of toplevel window
160              
161             =for test_synopsis my ($toplevel)
162              
163             =head1 SYNOPSIS
164              
165             package MyToplevel;
166             use Gtk2;
167             use Glib::Object::Subclass 'Gtk2::Window';
168             use base 'App::Chart::Gtk2::Ex::ToplevelSingleton';
169              
170             use App::Chart::Gtk2::Ex::ToplevelSingleton hide_on_delete => 1;
171              
172             $toplevel = MyToplevel->instance;
173            
174             if (MyToplevel->has_instance) { do_something() }
175              
176             =head1 DESCRIPTION
177              
178             This package is designed as a multi-inheritance mix-in for subclasses of
179             C<Gtk2::Window> which normally want only a single window instance, to be
180             used throughout a program.
181              
182             After adding C<ToplevelSingleton> to your C<@ISA>,
183             C<< MyToplevel->instance >> returns a single shared instance of a
184             C<MyToplevel> window.
185              
186             =head1 SEE ALSO
187              
188             L<Class::Singleton>
189              
190             =cut