PyGTK: ShutdownLater [update]

Posted on 15 December 2009 - 20:53 in Programming - Comments (2)

Shutdown, reboot, hibernate or suspend your computer later!

GTK GUI which lets the user choose between shutdown, reboot, hibernate or suspend
after a specified amount of time.
Runs on UPower-DBus calls, which surpasses the need for root access.
Working on Ubuntu 10.04, ArchLinux 2009.08 (Maybe other GTK, DBus, DeviceKit systems too).

Version 1.1 released:
- gnome-desktop 2.30 fixes (Ubuntu 10.04 compatible).

shutdownlater_conf
Configuration

shutdownlater_run
Running

Code below or here

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# GTK GUI which executes shutdown, reboot, hibernate or suspend after a given time.
# DBus, UPower and ConsoleKit handles the stuff under the hood.
# If the methodes are allowed, no root access is required.
#
# Version: 1.1
# Requires: gnome-desktop 2.30
#
# NOTE: UPower-Suspend/Hibernate do not give a reply through dbus. This programm
# does ignore that, but if you try to suspend/hibernate after a wake up
# it takes about 20sec till the non existing reply gets recognized.
# TODO: Check if dbus requests are allowed (CanStop(), CanRestart()).
# Support older backends (Hal, DeviceKit-Power, SessionManager).
#
# Version History:
# 1.0 - Initial Release
# 1.1 - Gnome-Desktop 2.30 fixes: UPower replaces DeviceKit-Power,
# ConsoleKit replaces SessionManager
#
# Copyright (C) 2010 wag@wag-net.ch
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
 
 
import gtk, gobject, dbus, dbus.mainloop.glib
gobject.threads_init()
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
 
 
class C_ShutdownLater():
    def __init__(self):
        self.loop = gobject.MainLoop()
        self.do = "shutdown"
        self.win_conf()
 
 
    def win_conf(self):
        """Create configuration window"""
        win = gtk.Window(gtk.WINDOW_TOPLEVEL)
        win.connect("destroy", self.quit)
        win.set_title("ShutdownLater")
        win.set_border_width(20)
 
 
        # Box, Table
        vb_main = gtk.VBox(False, 0)
        win.add(vb_main)
 
        t_rb = gtk.Table(2, 2, False)
        win.set_geometry_hints(t_rb, min_width=200, min_height=70)
        t_rb.set_row_spacings(5)
        t_rb.set_col_spacings(5)
 
        f_rb = gtk.Frame(" Initiate : ")
        f_rb.set_border_width(4)
        f_rb.add(t_rb)
        vb_main.pack_start(f_rb)
 
 
        # RadioButtons
        rb_shutdown = gtk.RadioButton(None, "Shutdown")
        rb_shutdown.set_border_width(5)
        rb_shutdown.connect("toggled", self.rb_callback, "shutdown")
        t_rb.attach(rb_shutdown, 0, 1, 0, 1)
 
        rb_reboot = gtk.RadioButton(rb_shutdown, "Reboot")
        rb_reboot.set_border_width(5)
        rb_reboot.connect("toggled", self.rb_callback, "reboot")
        t_rb.attach(rb_reboot, 1, 2, 0, 1)
 
        rb_hibernate = gtk.RadioButton(rb_shutdown, "Hibernate")
        rb_hibernate.set_border_width(5)
        rb_hibernate.connect("toggled", self.rb_callback, "hibernate")
        t_rb.attach(rb_hibernate, 0, 1, 1, 2)
 
        rb_suspend = gtk.RadioButton(rb_shutdown, "Suspend")
        rb_suspend.set_border_width(5)
        rb_suspend.connect("toggled", self.rb_callback, "suspend")
        t_rb.attach(rb_suspend, 1, 2, 1, 2)
 
 
        # Table, Labels
        t_sp = gtk.Table(3, 2, False)
        t_sp.set_row_spacings(10)
        t_sp.set_col_spacings(10)
 
        f_sp = gtk.Frame(" After : ")
        f_sp.set_border_width(4)
        f_sp.add(t_sp)
        vb_main.pack_start(f_sp)
 
        l_h = gtk.Label("Hours")
        l_h.set_padding(3, 3)
        t_sp.attach(l_h, 0, 1, 0, 1)
        l_m = gtk.Label("Minutes")
        t_sp.attach(l_m, 1, 2, 0, 1)
        l_s = gtk.Label("Seconds")
        t_sp.attach(l_s, 2, 3, 0, 1)
 
 
        # SpinBoxes
        sp_h_adj = gtk.Adjustment(0, 0, 999, 1, 10, 0)
        self.sp_h = gtk.SpinButton(sp_h_adj, 1, 0)
        self.sp_h.set_numeric(True)
        self.sp_h.set_size_request(50, 27)
        t_sp.attach(self.sp_h, 0, 1, 1, 2, False)
 
        sp_m_adj = gtk.Adjustment(0, 0, 59, 1, 10, 0)
        self.sp_m = gtk.SpinButton(sp_m_adj, 1, 0)
        self.sp_m.set_numeric(True)
        self.sp_m.set_size_request(45, 27)
        t_sp.attach(self.sp_m, 1, 2, 1, 2, False)
 
        sp_s_adj = gtk.Adjustment(0, 0, 59, 1, 10, 0)
        self.sp_s = gtk.SpinButton(sp_s_adj, 1, 0)
        self.sp_s.set_numeric(True)
        self.sp_s.set_size_request(45, 27)
        t_sp.attach(self.sp_s, 2, 3, 1, 2, False)
 
 
        # Table, Buttons
        t_b = gtk.Table(2, 1, False)
        t_b.set_row_spacings(10)
        t_b.set_col_spacings(10)
        vb_main.pack_start(t_b)
 
        b_start = gtk.Button("Start")
        b_start.set_border_width(4)
        t_b.attach(b_start, 0, 1, 0, 1)
        b_start.connect("clicked", self.start, win)
 
        b_quit = gtk.Button(" Quit ")
        b_quit.set_border_width(4)
        t_b.attach(b_quit, 1, 2, 0, 1)
        b_quit.connect("clicked", self.quit)
 
        win.show_all()
        gtk.main()
 
 
    def win_run(self, main):
        """Create running window"""
        win_conf = main
        win = gtk.Window(gtk.WINDOW_TOPLEVEL)
        win.connect("destroy", self.cancel, win_conf, win)
        win.set_title("ShutdownLater")
        win.set_border_width(20)
 
 
        # Box, ProgBar
        vb_main = gtk.VBox(False, 0)
        win.add(vb_main)
 
        pb_adj = gtk.Adjustment(1, 0, 1, 1, 5, 0)
        self.pb_time = gtk.ProgressBar(pb_adj)
        self.pb_time.set_size_request(200, 30)
 
        af_pb = gtk.Frame(" %s in : " % self.do.capitalize())
        af_pb.set_border_width(4)
        af_pb.add(self.pb_time)
        vb_main.pack_start(af_pb)
 
 
        # Table, Buttons
        t_b = gtk.Table(2, 1, False)
        t_b.set_row_spacings(10)
        t_b.set_col_spacings(10)
        vb_main.pack_start(t_b)
 
        b_pause = gtk.ToggleButton("Pause")
        b_pause.set_border_width(4)
        t_b.attach(b_pause, 0, 1, 0, 1)
        b_pause.connect("toggled", self.pause)
 
        b_cancel = gtk.Button("Cancel")
        b_cancel.set_border_width(4)
        t_b.attach(b_cancel, 1, 2, 0, 1)
        b_cancel.connect("clicked", self.cancel, win_conf, win)
 
        win.show_all()
 
 
    def quit(self, data=None):
        self.loop.quit()
        gtk.main_quit()
 
 
    def start(self, widget, data):
        """Start choosen process"""
        win_conf = data
        # Get spinbutton values as int, calculate total and current time
        h = self.sp_h.get_value_as_int()
        m = self.sp_m.get_value_as_int()
        s = self.sp_s.get_value_as_int()
 
        self.t_total = (h*3600)+(m*60)+s
        self.t_current = (h*3600)+(m*60)+s
 
        # Hide main window and show run window
        win_conf.hide()
        self.win_run(data)
 
        self.timer(h, m, s)
 
 
    def rb_callback(self, widget, data=None):
        """Set do variable from user input"""
        if widget.get_active():
            self.do = data
 
 
    def pause(self, widget):
        """Pause process"""
        # Kill or start timer
        if self.t_current != 0:
            if widget.get_active():
                gobject.source_remove(self.g_id)
            else:
                self.g_id = gobject.timeout_add(1000, self.count)
 
 
    def cancel(self, widget, win_conf, win_run):
        """Cancel process"""
        # Remove timer, destroy run window, show main window again
        gobject.source_remove(self.g_id)
        win_run.destroy()
        win_conf.show()
 
 
    def timer(self, h, m, s):
        """Call counter every second"""
        self.pb_time.set_text("%02i:%02i:%02i" % (h, m, s))
        self.g_id = gobject.timeout_add(1000, self.count)
 
 
    def count(self):
        """Countdown and rewrite progressbar"""
        # Countdown, calculate and update
        if self.t_current != 0:
            self.t_current -= 1
            pb_percent = float(self.t_current)/float(self.t_total)
 
            pb_h = self.t_current/3600
            pb_m = self.t_current%3600/60
            pb_s = self.t_current%3600%60
 
            self.pb_time.set_fraction(pb_percent)
            self.pb_time.set_text("%02i:%02i:%02i" % (pb_h, pb_m, pb_s))
 
            # Again, and again, and again...
            return True
        else:
            self.initiate()
 
 
    def initiate(self):
        """Send dbus messages"""
        # Shutdown with ConsoleKit
        if self.do == 'shutdown':
            bus = dbus.SystemBus()
            proxy = bus.get_object('org.freedesktop.ConsoleKit', '/org/freedesktop/ConsoleKit/Manager')
            iface = dbus.Interface(proxy, 'org.freedesktop.ConsoleKit.Manager')
            iface.Stop()
 
 
        # Reboot with ConsoleKit
        elif self.do == 'reboot':
            bus = dbus.SystemBus()
            proxy = bus.get_object('org.freedesktop.ConsoleKit', '/org/freedesktop/ConsoleKit/Manager')
            iface = dbus.Interface(proxy, 'org.freedesktop.ConsoleKit.Manager')
            iface.Restart()
 
 
        # Hibernate with UPower
        elif self.do == 'hibernate':
            bus = dbus.SystemBus()
            proxy = bus.get_object('org.freedesktop.UPower', '/org/freedesktop/UPower')
            iface = dbus.Interface(proxy, 'org.freedesktop.UPower')
            iface.Hibernate(ignore_reply=True)
 
 
        # Suspend with UPower
        elif self.do == 'suspend':
            bus = dbus.SystemBus()
            proxy = bus.get_object('org.freedesktop.UPower', '/org/freedesktop/UPower')
            iface = dbus.Interface(proxy, 'org.freedesktop.UPower')
            iface.Suspend(ignore_reply=True)
 
 
        self.loop.run()
 
 
sdl = C_ShutdownLater()

2 Comments »

  1. #1 — Comment by Mark — 25 January 2010 - 06:19

    I love it! Thanks!


  2. #2 — Comment by jeremy — 10 May 2010 - 17:35

    Thank you sooooo much. I’ve been looking for just this functionality. Well done !


RSS Comments - TrackBack URL

Leave a comment

This work is licensed under a Creative Commons Attribution 2.5 Switzerland License
Powered by WordPress