Bump to 1.0.6
[watersofshiloah] / src / watersofshiloah_gtk.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 """
5 @todo Reverse order option.  Toggle between playing ascending/descending chronological order
6 """
7
8 from __future__ import with_statement
9
10 import os
11 import gc
12 import logging
13 import logging.handlers
14 import ConfigParser
15
16 import gobject
17 import dbus
18 import dbus.mainloop.glib
19 import gtk
20
21 try:
22         import osso as _osso
23         osso = _osso
24 except ImportError:
25         osso = None
26
27 import constants
28 import hildonize
29 import util.misc as misc_utils
30
31 import imagestore
32 import player
33 import stream_index
34 import windows
35
36
37 _moduleLogger = logging.getLogger(__name__)
38 PROFILE_STARTUP = False
39
40
41 class WatersOfShiloahProgram(hildonize.get_app_class()):
42
43         def __init__(self):
44                 super(WatersOfShiloahProgram, self).__init__()
45                 currentPath = os.path.abspath(__file__)
46                 for dirName in ["share", "data"]:
47                         storePath = os.path.join(os.path.split(os.path.dirname(currentPath))[0], dirName)
48                         if os.path.isdir(storePath):
49                                 break
50                 self._store = imagestore.ImageStore(storePath, constants._cache_path_)
51                 self._index = stream_index.AudioIndex()
52                 self._player = player.Player(self._index)
53
54                 self._store.start()
55                 self._index.start()
56                 try:
57                         if not hildonize.IS_HILDON_SUPPORTED:
58                                 _moduleLogger.info("No hildonization support")
59
60                         if osso is not None:
61                                 self._osso_c = osso.Context(constants.__app_name__, constants.__version__, False)
62                                 self._deviceState = osso.DeviceState(self._osso_c)
63                                 self._deviceState.set_device_state_callback(self._on_device_state_change, 0)
64                         else:
65                                 _moduleLogger.info("No osso support")
66                                 self._osso_c = None
67                                 self._deviceState = None
68
69                         self._sourceSelector = windows.source.SourceSelector(self, self._player, self._store, self._index)
70                         self._sourceSelector.window.connect("destroy", self._on_destroy)
71                         self._sourceSelector.window.set_default_size(400, 800)
72                         self._sourceSelector.show()
73                         self._load_settings()
74                 except:
75                         self._index.stop()
76                         self._store.stop()
77                         raise
78
79         def _save_settings(self):
80                 config = ConfigParser.SafeConfigParser()
81
82                 self._sourceSelector.save_settings(config, "Windows")
83
84                 with open(constants._user_settings_, "wb") as configFile:
85                         config.write(configFile)
86
87         def _load_settings(self):
88                 config = ConfigParser.SafeConfigParser()
89                 config.read(constants._user_settings_)
90
91                 self._sourceSelector.load_settings(config, "Windows")
92
93         @misc_utils.log_exception(_moduleLogger)
94         def _on_device_state_change(self, shutdown, save_unsaved_data, memory_low, system_inactivity, message, userData):
95                 """
96                 For system_inactivity, we have no background tasks to pause
97
98                 @note Hildon specific
99                 """
100                 if memory_low:
101                         gc.collect()
102
103                 if save_unsaved_data or shutdown:
104                         self._save_settings()
105
106         @misc_utils.log_exception(_moduleLogger)
107         def _on_destroy(self, widget = None, data = None):
108                 try:
109                         self.quit()
110                 finally:
111                         gtk.main_quit()
112
113         def quit(self):
114                 try:
115                         self._save_settings()
116                 except Exception:
117                         _moduleLogger.exception("Error saving settigns")
118
119                 try:
120                         self._player.stop()
121                 except Exception:
122                         _moduleLogger.exception("Error stopping player")
123                 try:
124                         self._index.stop()
125                 except Exception:
126                         _moduleLogger.exception("Error stopping index")
127                 try:
128                         self._store.stop()
129                 except Exception:
130                         _moduleLogger.exception("Error stopping store")
131
132                 try:
133                         self._deviceState.close()
134                 except AttributeError:
135                         pass # Either None or close was removed (in Fremantle)
136                 except Exception:
137                         _moduleLogger.exception("Error closing device state")
138                 try:
139                         self._osso_c.close()
140                 except AttributeError:
141                         pass # Either None or close was removed (in Fremantle)
142                 except Exception:
143                         _moduleLogger.exception("Error closing osso state")
144
145
146 def run():
147         try:
148                 os.makedirs(constants._data_path_)
149         except OSError, e:
150                 if e.errno != 17:
151                         raise
152
153         try:
154                 os.makedirs(constants._cache_path_)
155         except OSError, e:
156                 if e.errno != 17:
157                         raise
158
159         logFormat = '(%(relativeCreated)5d) %(levelname)-5s %(threadName)s.%(name)s.%(funcName)s: %(message)s'
160         logging.basicConfig(level=logging.DEBUG, format=logFormat)
161         rotating = logging.handlers.RotatingFileHandler(constants._user_logpath_, maxBytes=512*1024, backupCount=1)
162         rotating.setFormatter(logging.Formatter(logFormat))
163         root = logging.getLogger()
164         root.addHandler(rotating)
165         _moduleLogger.info("%s %s-%s" % (constants.__app_name__, constants.__version__, constants.__build__))
166         _moduleLogger.info("OS: %s" % (os.uname()[0], ))
167         _moduleLogger.info("Kernel: %s (%s) for %s" % os.uname()[2:])
168         _moduleLogger.info("Hostname: %s" % os.uname()[1])
169
170         gobject.threads_init()
171         gtk.gdk.threads_init()
172         l = dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
173
174         # HACK Playback while silent on Maemo 5
175         hildonize.set_application_name("FMRadio")
176
177         app = WatersOfShiloahProgram()
178         if not PROFILE_STARTUP:
179                 try:
180                         gtk.main()
181                 except KeyboardInterrupt:
182                         app.quit()
183                         raise
184         else:
185                 app.quit()
186
187
188 if __name__ == "__main__":
189         logging.basicConfig(level=logging.DEBUG)
190         run()