#!/usr/bin/env python
#
# pykompiz: system tray controller for Compiz & KDE, written in Python.
#
# Version 0.1.3
#
# Copyright (C) 2006 Andrew Barr <andrew.james.barr@gmail.com>
#
#   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 2 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, write to the Free Software
#   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
#
# This program borrows code and/or ideas from:
#  - compiz-start from the compiz-vanilla-aiglx "quinn" Debian/Ubuntu package
#  - the example programs included in the PyKDE distribution
# Thank you to the authors of that code for making it available.

import os, sys, subprocess
from kdecore import KApplication, KAboutData, KIconTheme, KIcon, KCmdLineArgs
from dcopexport import DCOPExObj
from kdeui import KSystemTray, KPopupMenu, KAboutApplication
from qt import Qt, QApplication, QPixmap, QPopupMenu, QObject, QString, QMouseEvent, QCursor, SIGNAL

active_wm = QString("undefined")

class pykompizObject(DCOPExObj):
	def __init__ (self, id = 'pykompiz'):
		DCOPExObj.__init__ (self, id)
		# Rationale:
		# compiz tends to fudge up displays and cause other
		# nastiness when suspending and resuming the machine.
		# The idea is these methods are to be invoked from suspend
		# scripts. The broadcast capabilities of the command-line
		# dcop client make this ideal as suspend scripts generally
		# run as root and this stuff will be running at the user level,
		# possibly with multiple users.
		#
		# int suspend()
		#
		# saves the current active window manager, THEN switches
		# to kwin so suspend can happen. Returns 0 on success and
		# 1 on failure.
		#
		# int resume()
		#
		# activates compiz if it was active before suspend() was
		# called. Otherwise, it does nothing. Return values are the
		# same as for suspend().
		
		# FIXME: we don't care about return values but DCOP,
		# python, or some such doesn't like void identifiers
		# with no parameters.
		
		def dcop_suspend():
			try:
				app.config().writeEntry("suspendActiveWm",globals()["active_wm"])
				# FIXME: does this always need called?
				app.config().sync()
				switch_to_kwin()
				return 0
			except:
				return 1
		
		def dcop_resume():
			try:
				suspendActiveWm = app.config().readEntry("suspendActiveWm","kwin")
				if suspendActiveWm == QString("compiz"):
					start_compiz()
				return 0
			except:
				return 1
		
		self.addMethod ('int suspend()', dcop_suspend)
		self.addMethod ('int resume()', dcop_resume)
		# these don't remember what the last active WM was
		self.addMethod ('int restartCompiz()', start_compiz)
		self.addMethod ('int switchToKwin()', switch_to_kwin)

def start_compiz():
    try:
	globals()["active_wm"] = QString("compiz")
	# XXX: the kde-window-decorator isn't yet working
	os.system("killall gnome-window-decorator")
	subprocess.Popen(['gnome-window-decorator'])
	os.environ['LIBGL_ALWAYS_INDIRECT'] = 'TRUE'
	subprocess.Popen(['compiz', '--strict-binding', '--indirect-rendering', '--replace', 'gconf'])
	del os.environ['LIBGL_ALWAYS_INDIRECT']
	return 0
    except:
	    return 1	
def load_prefs_applet(self):
    subprocess.Popen(['gset-compiz'])
    
def switch_to_kwin():
    try:
	globals()["active_wm"] = QString("kwin")
	os.system("killall gnome-window-decorator")
	# This is needed since DESKTOPS except 0 are left as black 
	# and become unaccessible when switching to kwin from compiz.
	# It is avoided by executing metacity before kwin starts, 
	# although this is a really stupid way!!
	subprocess.Popen(['metacity', '--replace'])
	subprocess.Popen(['kwin', '--replace'])
	return 0
    except:
	    return 1
def about_box(self):
	box =  KAboutApplication(QApplication.desktop(),"pyKompiz",1)
	box.show()
	
def shut_down():
	# TODO: save current active WM
	app.config().writeEntry("active_wm",globals()["active_wm"])
	app.config().sync()
	
	sys.exit(0)
	
def conditional_start_compiz():
    try:
	if globals()["active_wm"] == QString("kwin"):
#		switch_to_kwin()
		return 0
	elif globals()["active_wm"] == QString("compiz"):
		start_compiz()
		return 0
    except:
		return 1

appaboutData = KAboutData("pykompiz","pyKompiz","0.1.3","Manager application for Compiz in KDE",KAboutData.License_GPL,"Copyright (C) 2006 Andrew Barr","","http://www.oakcourt.dyndns.org/projects/pykompiz","andrew.james.barr@gmail.com")

# if you hack on this feel free to add your name
appaboutData.addAuthor("Andrew Barr","main author","andrew.james.barr@gmail.com")

KCmdLineArgs.init(sys.argv,appaboutData)
app = KApplication()

icon = QPixmap ("/usr/share/pykompiz/logo24.png")

class systrayClass(KSystemTray):
	def __init__(self):
		KSystemTray.__init__(self)
	def mousePressEvent(self, mouseEvent):
		if mouseEvent.button() == Qt.LeftButton:
			systray.contextMenu().popup(QCursor.pos())
		elif mouseEvent.button() == Qt.RightButton:
			systray.contextMenu().popup(QCursor.pos())

systray = systrayClass()

systray.setPixmap(icon)

QObject.connect(systray,SIGNAL("quitSelected()"),shut_down)
QObject.connect(app,SIGNAL("shutDown()"),shut_down)

globals()["active_wm"] = app.config().readEntry("active_wm","undefined")

conditional_start_compiz()
	
dcop = app.dcopClient()
appid = dcop.registerAs('pykompiz',0)

pykompizInstance = pykompizObject('pykompiz')

systray.contextMenu().insertItem(app.iconLoader().loadIconSet("configure",KIcon.Small),"Preferences", load_prefs_applet)
systray.contextMenu().insertSeparator()
systray.contextMenu().insertItem("Switch to KWin", switch_to_kwin)
systray.contextMenu().insertItem("Restart Compiz", start_compiz)
systray.contextMenu().insertItem("About pyKompiz...", about_box)

systray.show ()

app.exec_loop()
sys.exit(0)
