#!/usr/bin/python

# Copyright (C) 2011 Noel J. Bergman <noel@devtech.com>
# Licensed under the Apache Software License v2

import dbus

class Inhibitor(object):
    '''
    Uses the Gnome SessionManager D-Bus interface to inhibit session idling and other inhibitable activities.

    References:

    http://svn.gnome.org/viewvc/gnome-session/trunk/gnome-session/org.gnome.SessionManager.xml?view=markup
    http://blogs.gnome.org/hughsie/2009/01/28/inhibits-and-the-new-world-order/
    http://git.gnome.org/browse/gnome-power-manager/tree/applets/inhibit/inhibit-applet.c?h=gnome-2-32
    http://git.gnome.org/browse/gnome-session/tree/gnome-session/gsm-manager.c
    http://en.wikibooks.org/wiki/Python_Programming/Dbus
    '''

    LOGGING_OUT=1
    USER_SWITCHING=2
    SUSPENDING=4
    IDLE=8

    def __init__(self):
        self.bus = dbus.SessionBus()
        self.session_manager = self.bus.get_object("org.gnome.SessionManager","/org/gnome/SessionManager")
        self.session_manager_interface = dbus.Interface(self.session_manager, "org.gnome.SessionManager")

    def inhibit(self, flags = 8, app_id="PyInhibit", toplevel_xid=0, reason="OnDemand"):
        self.uninhibit()
        if 0 < flags <= (Inhibitor.LOGGING_OUT + Inhibitor.USER_SWITCHING + Inhibitor.SUSPENDING + Inhibitor.IDLE):
            self.cookie = self.session_manager_interface.Inhibit(app_id, toplevel_xid, reason, flags)

    def uninhibit(self):
        if "cookie" in self.__dict__:
            self.session_manager_interface.Uninhibit(self.cookie)
            del self.cookie

    def isInhibited(self, flags):
        return self.session_manager_interface.IsInhibited(flags)

    def introspect(self):
        introspector = dbus.Interface(self.session_manager, dbus.INTROSPECTABLE_IFACE)
        interface = introspector.Introspect()
        print interface

try:
    import pygtk
    pygtk.require('2.0')

    import gtk, appindicator
except AssertionError as e:
    print "Necessary version of GTK not found: ", e
    raise SystemExit
except ImportError as e:
    print "Necessary import not found: ", e
    print "Will try running as a GNOME Applet instead of an AppIndicator"
else:
    class InhibitIndicator(object):
        """
        AppIndicator UI for the Inhibitor.  Conditionally built and executed if the appindicator package is present.
        You can set this to run at session startup (Preferences->Startup Applications), or run it manually (e.g., ALT-F2).

        References:

        http://design.canonical.com/2010/04/notification-area/
        https://wiki.ubuntu.com/DesktopExperienceTeam/ApplicationIndicators
        http://www.eurion.net/python-snippets/snippet/Create%20an%20Application%20Indicator.html
        http://blog.strycore.com/2010/01/using-the-application-indicator-in-python/
        http://www.jonobacon.org/2009/12/17/application-indicators-in-python/
        http://people.canonical.com/~ted/libappindicator/current/AppIndicator.html
        """

        def __init__(self):
            self.ind = appindicator.Indicator ("inhibit-indicator-menu", "gpm-inhibit", appindicator.CATEGORY_SYSTEM_SERVICES)
            self.ind.set_status (appindicator.STATUS_ACTIVE)
            # self.ind.set_icon("gpm-inhibit") -- redundant with constructor

            # create a menu
            self.menu = gtk.Menu()

            # create items for the menu
            check = gtk.CheckMenuItem("Inhibit Logout")
            check.connect("activate", self.inhibit, Inhibitor.LOGGING_OUT)
            check.show()
            self.menu.append(check)

            check = gtk.CheckMenuItem("Inhibit User Switching")
            check.connect("activate", self.inhibit, Inhibitor.USER_SWITCHING)
            check.show()
            self.menu.append(check)

            check = gtk.CheckMenuItem("Inhibit Suspending")
            check.connect("activate", self.inhibit, Inhibitor.SUSPENDING)
            check.show()
            self.menu.append(check)

            check = gtk.CheckMenuItem("Inhibit Idle")
            check.connect("activate", self.inhibit, Inhibitor.IDLE)
            check.show()
            self.menu.append(check)

            item = gtk.ImageMenuItem(gtk.STOCK_QUIT)
            item.connect("activate", self.quit)
            item.show()
            self.menu.append(item)

            self.flags = 0
            self.inhibitor = Inhibitor()

        def inhibit(self, widget, data = None):
            self.flags += data if widget.active else -data
            self.inhibitor.inhibit(self.flags)
            # self.reportStatus()

        def reportStatus(self):
            with open("/tmp/inhibitlog", "a") as log:
                print >> log, "Logging out {0} inhibited.".format("is" if self.inhibitor.isInhibited(Inhibitor.LOGGING_OUT) else "is not")
                print >> log, "User switching {0} inhibited.".format("is" if self.inhibitor.isInhibited(Inhibitor.USER_SWITCHING) else "is not")
                print >> log, "Suspending {0} inhibited.".format("is" if self.inhibitor.isInhibited(Inhibitor.SUSPENDING) else "is not")
                print >> log, "Session idle {0} inhibited.".format("is" if self.inhibitor.isInhibited(Inhibitor.IDLE) else "is not")

        def quit(self, widget, data=None):
            gtk.main_quit()

        def run(self):
            self.menu.show()
            self.ind.set_menu(self.menu)
            gtk.main()
    
    if __name__ == "__main__":
        indicator = InhibitIndicator()
        indicator.run()
        raise SystemExit

try:
    import gnomeapplet, sys, os.path
except ImportError as e:
    print "Necessary import not found: ", e
else:
    class InhibitApplet(gnomeapplet.Applet):
        '''
        GNOME Applet UI for the Inhibitor.

        References:

        http://www.znasibov.info/blog/post/gnome-applet-with-python-part-1.html
        http://saravananthirumuruganathan.wordpress.com/2010/01/15/creating-gnome-panel-applets-in-python/
        http://www.pygtk.org/articles/applets_arturogf/
        http://cafbit.com/resource/ffselect.py
        http://www.mythtv.org/wiki/Mythstatus.py
        '''

        def __init__(self, applet, iid):
            self.flags = 0
            self.inhibitor = Inhibitor()
            self.applet = applet

            icon = gtk.Image()
            try:
                pixbuf = gtk.gdk.pixbuf_new_from_file("/usr/share/gnome-power-manager/icons/hicolor/scalable/status/gpm-inhibit.svg")
            except gobject.GError:
                icon = None
            else:
                scaled_buf = pixbuf.scale_simple(24,24,gtk.gdk.INTERP_BILINEAR)
                icon.set_from_pixbuf(scaled_buf)
                icon.show()

            if icon:
                self.applet.add(icon)
            else:
                label = gtk.Label("Inhibit")
                self.applet.add(label)

            self.setup_menu()
            self.applet.show_all()

        def setup_menu(self):
            xml = '<popup name="button3">'
            xml += '<menuitem name="ItemLogout" verb="LogoutOff" label="Inhibit _Logout" />' if not (self.flags & Inhibitor.LOGGING_OUT) else '<menuitem name="ItemLogout" verb="LogoutOn" label="Allow _Logout" />'
            xml += '<menuitem name="ItemSwitch" verb="SwitchOff" label="Inhibit S_witch" />' if not (self.flags & Inhibitor.USER_SWITCHING) else '<menuitem name="ItemSwitch" verb="SwitchOn" label="Allow S_witch" />'
            xml += '<menuitem name="ItemSuspend" verb="SuspendOff" label="Inhibit _Suspend" />' if not (self.flags & Inhibitor.SUSPENDING) else '<menuitem name="ItemSuspend" verb="SuspendOn" label="Allow _Suspend" />'
            xml += '<menuitem name="ItemIdle" verb="IdleOff" label="Inhibit _Idle" />' if not (self.flags & Inhibitor.IDLE) else '<menuitem name="ItemIdle" verb="IdleOn" label="Allow _Idle" />'
            xml += '</popup>'

            verbs = [('LogoutOff', self.inhibit), ('SwitchOff', self.inhibit), ('SuspendOff', self.inhibit), ('IdleOff', self.inhibit),
                     ('LogoutOn', self.inhibit), ('SwitchOn', self.inhibit), ('SuspendOn', self.inhibit), ('IdleOn', self.inhibit)]
            self.applet.setup_menu(xml, verbs, None)

        def inhibit(self, obj, verb, *data):
            flag = {'LogoutOff': Inhibitor.LOGGING_OUT, 'SwitchOff': Inhibitor.USER_SWITCHING, 'SuspendOff': Inhibitor.SUSPENDING, 'IdleOff': Inhibitor.IDLE,
                     'LogoutOn': -Inhibitor.LOGGING_OUT, 'SwitchOn': -Inhibitor.USER_SWITCHING, 'SuspendOn': -Inhibitor.SUSPENDING, 'IdleOn': -Inhibitor.IDLE }
            self.flags += flag[verb]
            self.inhibitor.inhibit(self.flags)
            self.setup_menu()

        @staticmethod
        def applet_factory(applet, iid):   
            InhibitApplet(applet, iid)
            return True
            
    import sys

    if __name__ == "__main__":
        if not os.path.exists("/usr/lib/bonobo/servers/InhibitApplet.server"):
            oaf = '''
<oaf_info>
  <oaf_server iid="OAFIID:InhibitApplet_Factory" type="exe" location="''' + os.path.abspath(sys.argv[0]) + '''">
    <oaf_attribute name="repo_ids" type="stringv">
      <item value="IDL:Bonobo/GenericFactory:1.0"/>
      <item value="IDL:Bonobo/Unknown:1.0"/>
      </oaf_attribute><oaf_attribute name="name" type="string" value="Inhibit Applet Factory"/>
      <oaf_attribute name="description" type="string" value="Inhibit Applet's factory that launches the applet"/>
  </oaf_server>
  <oaf_server iid="OAFIID:InhibitApplet" type="factory" location="OAFIID:InhibitApplet_Factory">
    <oaf_attribute name="repo_ids" type="stringv">
      <item value="IDL:GNOME/Vertigo/PanelAppletShell:1.0"/>
      <item value="IDL:Bonobo/Control:1.0"/>
      <item value="IDL:Bonobo/Unknown:1.0"/>
      </oaf_attribute><oaf_attribute name="name" type="string" value="Inhibit Applet"/>
      <oaf_attribute name="description" type="string" value="Control Gnome Session Manager Inhibit Settings"/>
      <oaf_attribute name="panel:category" type="string" value="Utility"/>
      <oaf_attribute name="panel:icon" type="string" value="/usr/share/gnome-power-manager/icons/hicolor/scalable/status/gpm-inhibit.svg"/>
  </oaf_server>
</oaf_info>
'''

            try:
                with open("/usr/lib/bonobo/servers/InhibitApplet.server", "w") as oaf_file:
                    oaf_file.write(oaf)
            except Exception as e:
                print "Cannot register applet -- try running as root:", e
            else:
                print "Registered applet.  You must restart gnome-panel, e.g., killall gnome-panel"
        elif len(sys.argv) > 1 and sys.argv[1] == '-d':
            mainWindow = gtk.Window()
            mainWindow.set_title('Applet window')
            mainWindow.connect('destroy', gtk.main_quit)
            applet = gnomeapplet.Applet()
            InhibitApplet.applet_factory(applet, None)
            applet.reparent(mainWindow)
            mainWindow.show_all()
            gtk.main()
            sys.exit()
        else:
            gnomeapplet.bonobo_factory('OAFIID:InhibitApplet_Factory', gnomeapplet.Applet.__gtype__, 'Inhibit Applet', '1.0', InhibitApplet.applet_factory)
