#!/usr/bin/python3

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GdkX11, Gio, GLib
import sys
import subprocess
import shlex
import argparse
import syslog
import signal
import os
import psutil

signal.signal(signal.SIGINT, signal.SIG_DFL)

class XScreensaverPlugin:
    def __init__(self):
        parser = argparse.ArgumentParser(description="Cinnamon Screensaver XScreensaver Plugin")
        parser.add_argument("--standalone", action="store_true", help="run as standalone window instead of embedded in screensaver", dest="standalone")
        parser.add_argument("--dir", action="store", help="directory to search for xscreensaver hacks")
        parser.add_argument("--hack", action="store", help="xscreensaver hack to load")
        self.args = parser.parse_args()

        try:
            self.ensure_config_file()
        except:
            pass

        GLib.unix_signal_add(GLib.PRIORITY_HIGH, signal.SIGTERM, self.on_terminate)

        self.proc = None
        self.hack = None

        if self.args.standalone:
            self.plug = Gtk.Window()
        else:
            self.plug = Gtk.Plug()

        c = Gdk.RGBA(0, 0, 0, 0)
        self.plug.override_background_color (Gtk.StateFlags.NORMAL, c);

        self.plug.draw_id = self.plug.connect("draw", self.load_hack)
        self.plug.connect("delete-event", Gtk.main_quit)

        self.plug.show_all()

        self.xid = self.plug.get_window().get_xid()
        print("WINDOW ID=" + str(self.xid))
        sys.stdout.flush()

    def load_hack (self, plug, data=None):
        self.plug.disconnect(self.plug.draw_id)

        directories = ["/usr/lib/xscreensaver/",
                       "/usr/lib/misc/xscreensaver/",
                       "/usr/libexec/xscreensaver/",
                       "/usr/local/lib/xscreensaver/",
                       "/usr/local/libexec/xscreensaver/"]

        if self.args.dir:
            directories.append(self.args.dir)

        if (self.args.hack):
            hack = self.args.hack
        else:
            settings = Gio.Settings.new(schema_id="org.cinnamon.desktop.screensaver")
            hack = settings.get_string("xscreensaver-hack")

        success = False

        for direc in directories:
            try:
                path = shlex.split(direc + hack)
                if os.path.exists(path[0]):
                    sc_path = self.get_safechild_path()

                    if sc_path == None:
                        raise Exception("Cannot find safechild subprocess wrapper, exiting")

                    path.insert(0, sc_path)
                    path.append("-window-id")
                    path.append(str(self.xid))

                    self.hack = hack

                    try:
                        self.proc = Gio.Subprocess.new(path, Gio.SubprocessFlags.STDIN_PIPE)
                        success = True
                    except GLib.Error as e:
                        print("Error spawning screensaver hack: %s" % e.message)
            except Exception as e:
                print(e)

        if not success:
            syslog.syslog("cinnamon-screensaver: Screensaver '%s' not found" % hack)
            color = Gdk.RGBA()
            color.red = 0
            color.green = 0
            color.blue = 0
            color.alpha = 1
            label = Gtk.Label()
            label.override_background_color(Gtk.StateFlags.NORMAL, color)
            label.show()
            self.plug.add(label)

    def kill_plugin(self):
        if self.proc:
            self.proc.force_exit()
            self.proc = None

        for proc in psutil.process_iter():
            if proc.name() == self.hack:
                proc.kill()

    def on_terminate(self, data=None):
        self.kill_plugin()
        self.plug.destroy()
        Gtk.main_quit()

    def get_safechild_path(self):
        datadirs = GLib.get_system_data_dirs()

        for datadir in datadirs:
            try_path = os.path.join(datadir,
                                    "cinnamon-screensaver",
                                    "screensavers",
                                    "xscreensaver@cinnamon.org",
                                    "safechild")

            if os.path.exists(try_path):
                return try_path

        return None

    def ensure_config_file(self):
        """
        Check for a .xscreensaver file in the user home folder.  If it doesn't exist,
        we'll place a simple one there.  This just ensures a few sane defaults (such as
        where to grab random pictures from for hacks that use them, rather than using
        test images.)
        """
        home = GLib.get_home_dir()
        config_path = os.path.join(home, ".xscreensaver")

        if os.path.exists(config_path):
            return

        images_path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_PICTURES)
        if images_path == None:
            images_path = home

        from datetime import datetime

        with open(config_path, "w") as f:
            f.write("""
# XScreenSaver Preferences File
# Generated: %s
# by the xscreensaver plugin for cinnamon-screensaver
# Use xscreensaver-demo to customize

visualID:   default
installColormap:    True
font:       *-medium-r-*-140-*-m-*

grabDesktopImages:  False
grabVideoFrames:    False
chooseRandomImages: True
imageDirectory: %s

mode:       random
selected:   -1

textMode:   literal
textLiteral:    Cinnamon
textFile:
textProgram:    fortune

pointerPollTime:    0:00:05
pointerHysteresis:  10
GetViewPortIsFullOfLies:False
procInterrupts: True

""" % (str(datetime.now()), images_path))

if __name__ == "__main__":
    XScreensaverPlugin()
    Gtk.main()

