3 # This file is part of Panucci.
4 # Copyright (c) 2008-2010 The Panucci Audiobook and Podcast Player Project
6 # Panucci is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
11 # Panucci is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with Panucci. If not, see <http://www.gnu.org/licenses/>.
19 # from services.py -- Core Services for gPodder
20 # Thomas Perl <thp@perli.net> 2007-08-24
22 # 2009-02-13 - nikosapi: made ObservableService more Panucci-esque
25 from __future__
import absolute_import
27 from logging
import getLogger
29 # the following are only needed for __headphone_watcher
30 from panucci
import util
33 class ObservableService(object):
34 def __init__(self
, signal_names
=[], log
=None):
35 self
._log
= getLogger('ObservableService') if log
is None else log
38 for signal
in signal_names
:
39 self
.observers
[signal
] = []
42 self
._log
.warning('No signal names defined...')
44 def register(self
, signal_name
, observer
):
45 if signal_name
in self
.observers
:
46 if not observer
in self
.observers
[signal_name
]:
47 self
.observers
[signal_name
].append(observer
)
48 self
._log
.debug( 'Registered "%s" as an observer for "%s"',
49 observer
.__name
__, signal_name
)
52 'Observer "%s" is already added to signal "%s"',
53 observer
.__name
__, signal_name
)
56 'Signal "%s" is not available for registration', signal_name
)
58 def unregister(self
, signal_name
, observer
):
59 if signal_name
in self
.observers
:
60 if observer
in self
.observers
[signal_name
]:
61 self
.observers
[signal_name
].remove(observer
)
62 self
._log
.debug( 'Unregistered "%s" as an observer for "%s"',
63 observer
.__name
__, signal_name
)
66 'Observer "%s" could not be removed from signal "%s"',
67 observer
.__name
__, signal_name
)
70 'Signal "%s" is not available for un-registration.',
73 def notify(self
, signal_name
, *args
, **kwargs
):
74 caller
= kwargs
.get('caller')
75 caller
= 'UnknownCaller' if caller
is None else caller
.__name
__
78 if signal_name
in self
.observers
:
80 'Sending signal "%s" for caller "%s"', signal_name
, caller
)
83 for observer
in self
.observers
[signal_name
]:
84 rtn_value
&= bool(observer( *args
))
87 'Signal "%s" (from caller "%s") is not available '
88 'for notification', signal_name
, caller
)
93 class ForwardingObservableService(ObservableService
):
94 """ An object that builds on ObservableService which provides a simple
95 way to forward/proxy a bunch of signals through an object of this
96 type. Ie: This object will call it's notify() method whenever a
97 forwarded signal from another object is emitted. """
99 def forward( self
, from_object
, signal_names
, caller
=None ):
100 """ Register signals to be forwarded
101 from_object: the object from which the signals will be emitted
102 signal_names: a string, list, or dict of signal names
103 caller: the caller to be passed to notify()
105 To forward a single signal, signal_names can just be a string
106 containing the name of the signal.
108 To forward many signals, signal_names can be a list of strings.
110 If you wish to change the name of the emitted signal (ie. if the
111 original object's signal is named "foo-bar" but you want this
112 object to emit "foo") you can do so by passing a dict to
113 signal_names. This dict must contain string pairs:
114 { "new name" : "from-object name", }
117 # bail if the from object isn't an ObservableService
118 if not isinstance( from_object
, ObservableService
):
119 self
._log
.error( "Can't forward signals for "
120 "non-ObservableService type objects")
123 signals
= {} # final list of signals to registered
125 if isinstance( signal_names
, str ):
126 signals
[signal_names
] = signal_names
128 elif isinstance( signal_names
, list ):
129 for name
in signal_names
:
132 elif isinstance( signal_names
, dict ):
133 signals
= signal_names
135 for to_name
, from_name
in signals
.iteritems():
136 from_object
.register( from_name
, self
._forward
( to_name
, caller
))
138 def _forward( self
, emitted_signal_name
, caller
):
139 """ Returns a function which calls notify() with the appropriate
142 def _callback( *args
, **kwargs
):
143 kwargs
["caller"] = caller
144 return self
.notify( emitted_signal_name
, *args
, **kwargs
)
149 HEADPHONE_SYS
= "/sys/devices/platform/gpio-switch/headphone/state"
151 class __headphone_watcher(ObservableService
):
152 """ A small service with one singnal that reports whether or not the
153 headphones are connected. Returns True if the headphones are connected,
154 False if they're not and None if it's not possible to determine the
155 headphone status. """
157 signals
= [ 'headphone-status-changed', ]
159 def __init__(self
, sys_file
):
160 self
.__log
= getLogger('panucci.serivces.__headphone_watcher')
161 ObservableService
.__init
__(self
, self
.signals
, self
.__log
)
163 self
.__is
_connected
= None
165 if util
.platform
.MAEMO
and not util
.platform
.MAEMO5
:
167 self
.__sys
_file
= open( sys_file
, 'r' )
168 self
.__is
_connected
= self
.__get
_state
_from
_fd
(self
.__sys
_file
)
169 gobject
.io_add_watch( self
.__sys
_file
, gobject
.IO_PRI
,
170 self
.__on
_status
_changed
)
172 self
.__log
.exception("Can't open headphone status file.")
175 def is_connected(self
):
176 return self
.__is
_connected
178 def __get_state_from_fd(self
, fd
):
180 state
= fd
.read().strip()
181 return state
== 'connected'
183 def __on_status_changed(self
, src
, cond
):
184 self
.__is
_connected
= self
.__get
_state
_from
_fd
( src
)
186 'Headphone state changed (is_connected=%s).', self
.__is
_connected
)
187 self
.notify( 'headphone-status-changed', self
.__is
_connected
,
188 caller
=self
.__on
_status
_changed
)
191 headphone_service
= __headphone_watcher(HEADPHONE_SYS
)