1# Copyright (C) 2010 Johannes Schwarz
2#
3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; either version 1, or (at your option)
6# any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program; if not, write to the Free Software
15# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16
17import dbus
18from gi.repository import GLib
19from gi.repository import Gtk
20
21from xl import event, providers
22from xl.nls import gettext as _
23from xlgui.widgets import dialogs, menu
24
25SHUTDOWN = None
26
27
28class Shutdown:
29    def __init__(self, exaile):
30        self.exaile = exaile
31        self.do_shutdown = False
32
33        # add menuitem to tools menu
34        providers.register(
35            'menubar-tools-menu',
36            menu.simple_separator('plugin-sep', ['track-properties']),
37        )
38
39        item = menu.check_menu_item(
40            'shutdown',
41            ['plugin-sep'],
42            _('Shutdown after Playback'),
43            #   checked func                # callback func
44            lambda *x: self.do_shutdown,
45            lambda w, n, p, c: self.on_toggled(w),
46        )
47        providers.register('menubar-tools-menu', item)
48
49        self.countdown = None
50        self.counter = 10
51
52        self.message = dialogs.MessageBar(
53            parent=exaile.gui.builder.get_object('player_box'),
54            buttons=Gtk.ButtonsType.CLOSE,
55        )
56        self.message.connect('response', self.on_response)
57
58    def on_toggled(self, menuitem):
59        """
60        Enables or disables defered shutdown
61        """
62        if menuitem.get_active():
63            self.do_shutdown = True
64            event.add_ui_callback(self.on_playback_player_end, 'playback_player_end')
65
66            self.message.show_info(
67                _('Shutdown scheduled'),
68                _('Computer will be shutdown at the end of playback.'),
69            )
70        else:
71            self.disable_shutdown()
72
73    def disable_shutdown(self):
74        self.do_shutdown = False
75        event.remove_callback(self.on_playback_player_end, 'playback_player_end')
76
77        # Stop possible countdown
78        if self.countdown is not None:
79            GLib.source_remove(self.countdown)
80            self.countdown = None
81
82        # Prepare for a new run
83        self.counter = 10
84
85        # Reset message button layout
86        self.message.hide()
87        self.message.clear_buttons()
88        self.message.add_button(Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE)
89
90    def on_playback_player_end(self, event, player, track):
91        """
92        Tries to shutdown the computer
93        """
94        self.message.set_message_type(Gtk.MessageType.INFO)
95        self.message.set_markup(_('Imminent Shutdown'))
96        self.message.clear_buttons()
97        self.message.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
98
99        if self.countdown is not None:
100            GLib.source_remove(self.countdown)
101
102        self.counter = 10
103        self.countdown = GLib.timeout_add_seconds(1, self.on_timeout)
104
105    def on_response(self, widget, response):
106        """
107        Cancels shutdown if requested
108        """
109        if response == Gtk.ResponseType.CANCEL:
110            self.disable_shutdown()
111
112    def on_timeout(self):
113        """
114        Tries to shutdown the computer
115        """
116        self.countdown = None
117        if self.counter > 0:
118            self.message.set_secondary_text(
119                _('The computer will be shut down in %d seconds.') % self.counter
120            )
121            self.message.show()
122
123            self.counter -= 1
124
125            return True
126
127        self.do_shutdown = False
128
129        bus = dbus.SystemBus()
130
131        try:
132            proxy = bus.get_object('org.freedesktop.login1', '/org/freedesktop/login1')
133            proxy.PowerOff(False, dbus_interface='org.freedesktop.login1.Manager')
134        except dbus.exceptions.DBusException:
135            try:
136                proxy = bus.get_object(
137                    'org.freedesktop.ConsoleKit', '/org/freedesktop/ConsoleKit/Manager'
138                )
139                proxy.Stop(dbus_interface='org.freedesktop.ConsoleKit.Manager')
140            except dbus.exceptions.DBusException:
141                try:
142                    proxy = bus.get_object(
143                        'org.freedesktop.Hal', '/org/freedesktop/Hal/devices/computer'
144                    )
145                    proxy.Shutdown(
146                        dbus_interface='org.freedesktop.Hal.Device.SystemPowerManagement'
147                    )
148                except dbus.exceptions.DBusException:
149                    self.message.show_warning(
150                        _('Shutdown failed'),
151                        _('Computer could not be shutdown using D-Bus.'),
152                    )
153
154    def destroy(self):
155        """
156        Cleans up
157        """
158        if self.countdown is not None:
159            GLib.source_remove(self.countdown)
160
161        event.remove_callback(self.on_playback_player_end, 'playback_player_end')
162        for item in providers.get('menubar-tools-menu'):
163            if item.name == 'shutdown':
164                providers.unregister('menubar-tools-menu', item)
165                break
166
167
168def enable(exaile):
169    if exaile.loading:
170        event.add_callback(_enable, 'exaile_loaded')
171    else:
172        _enable(None, exaile, None)
173
174
175def _enable(eventname, exaile, nothing):
176    global SHUTDOWN
177    SHUTDOWN = Shutdown(exaile)
178
179
180def disable(exaile):
181    global SHUTDOWN
182    SHUTDOWN.destroy()
183