summaryrefslogtreecommitdiffstats
path: root/FusionIcon
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-03-13 03:34:10 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-03-13 03:34:10 +0000
commit6a8e496233a6f6d632bdc7551a5fbda3543c27bb (patch)
tree28479fd17cf5a19838108ab4a17b6f3fb1e5cd88 /FusionIcon
downloadfusion-icon-6a8e496233a6f6d632bdc7551a5fbda3543c27bb.tar.gz
fusion-icon-6a8e496233a6f6d632bdc7551a5fbda3543c27bb.zip
Added KDE3 version of fusion-icon for Compiz
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/fusion-icon@1102634 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'FusionIcon')
-rw-r--r--FusionIcon/__init__.py1
-rw-r--r--FusionIcon/data.py116
-rw-r--r--FusionIcon/environment.py146
-rw-r--r--FusionIcon/execute.py58
-rw-r--r--FusionIcon/interface.py89
-rw-r--r--FusionIcon/interface_gtk/__init__.py3
-rw-r--r--FusionIcon/interface_gtk/main.py214
-rw-r--r--FusionIcon/interface_qt4/__init__.py3
-rw-r--r--FusionIcon/interface_qt4/main.py80
-rw-r--r--FusionIcon/parser.py57
-rw-r--r--FusionIcon/start.py68
-rw-r--r--FusionIcon/util.py419
12 files changed, 1254 insertions, 0 deletions
diff --git a/FusionIcon/__init__.py b/FusionIcon/__init__.py
new file mode 100644
index 0000000..f685b36
--- /dev/null
+++ b/FusionIcon/__init__.py
@@ -0,0 +1 @@
+# Fusion Icon
diff --git a/FusionIcon/data.py b/FusionIcon/data.py
new file mode 100644
index 0000000..639b46c
--- /dev/null
+++ b/FusionIcon/data.py
@@ -0,0 +1,116 @@
+# This file is part of Fusion-icon.
+
+# Fusion-icon 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.
+#
+# Fusion-icon 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 Publaic License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Author(s): crdlb
+# Copyright 2007 Christopher Williams <christopherw@verizon.net>
+
+import os
+
+mesa_libgl_locations = (
+ # ubuntu
+ '/usr/lib/fglrx/libGL.so.1.2.xlibmesa',
+ '/usr/lib/nvidia/libGL.so.1.2.xlibmesa',
+ # gentoo
+ '/usr/lib/opengl/xorg-x11/lib/libGL.so.1.2',
+ # archlinux
+ '/opt/mesa-xgl/lib/libGL.so.1.2',
+ '/lib/mesa/libGL.so.1.2',
+ # debian
+ '/usr/lib/fglrx/diversions/libGL.so.1.2',
+ '/usr/share/nvidia-glx/diversions/libGL.so.1.2',
+)
+
+compiz_args = ['--replace', '--sm-disable', '--ignore-desktop-hints', 'ccp']
+
+config_home = os.environ.get('XDG_CONFIG_HOME',
+ os.path.join(os.environ['HOME'], '.config'))
+
+config_folder = os.path.join(config_home, 'compiz')
+
+config_file = os.path.join(config_folder, 'fusion-icon')
+
+# Key:
+# identifier (for wms, this is what gets written to the config file)
+# Value:
+# O - base command (for wms and decorators), config file option name
+# 1 - full command, actual compiz argument
+# 2 - display name
+# 3 - desktop environment for which it should be the fallback/default
+# 4 - list of extra properties:
+# noreplace: lacks working --replace switch
+# 5 - Extra command to run before killing
+
+apps = {
+ 'ccsm':
+ ('ccsm', ['ccsm'],
+ 'Settings Manager'),
+ 'emerald theme manager':
+ ('emerald-theme-manager', ['emerald-theme-manager'],
+ 'Emerald Theme Manager'),
+}
+
+wms = {
+ 'metacity':
+ ('metacity', ['metacity', '--replace'],
+ 'Metacity', 'gnome', None, None,),
+
+ 'kwin':
+ ('kwin', ['kwin', '--replace'],
+ 'KWin', 'kde', None, ['dcop', 'kwin', 'KWinInterface', 'stopKompmgr']),
+
+ 'xfwm4':
+ ('xfwm4', ['xfwm4'],
+ 'Xfwm4', 'xfce', ['noreplace'], ['killall', 'xfwm4']),
+
+ 'openbox':
+ ('openbox', ['openbox', '--replace'],
+ 'Openbox', None, None, None),
+
+ 'blackbox':
+ ('blackbox', ['blackbox', '--replace'],
+ 'Blackbox', None, None, None),
+
+ 'fvwm':
+ ('fvwm', ['fvwm', '--replace'],
+ 'FVWM', None, None, None),
+
+ 'icewm':
+ ('icewm', ['icewm', '--replace'],
+ 'IceWM', None, None, None),
+
+}
+
+decorators = {
+ 'emerald':
+ ('emerald', 'emerald --replace',
+ 'Emerald', None),
+
+ 'gwd':
+ ('gtk-window-decorator', 'gtk-window-decorator --replace',
+ 'GTK Window Decorator', 'gnome'),
+
+ 'kwd':
+ ('kde-window-decorator', 'kde-window-decorator --replace',
+ 'KDE Window Decorator', 'kde'),
+}
+
+options = {
+ 'indirect rendering':
+ (None, '--indirect-rendering', 'Indirect Rendering'),
+
+ 'loose binding':
+ (None, '--loose-binding', 'Loose Binding'),
+}
+
diff --git a/FusionIcon/environment.py b/FusionIcon/environment.py
new file mode 100644
index 0000000..9423098
--- /dev/null
+++ b/FusionIcon/environment.py
@@ -0,0 +1,146 @@
+# This file is part of Fusion-icon.
+
+# Fusion-icon 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.
+#
+# Fusion-icon 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/>.
+#
+# Author(s): crdlb, nesl247
+#
+# Copyright 2007 Christopher Williams <christopherw@verizon.net>
+
+import os
+from execute import run
+
+tfp = 'GLX_EXT_texture_from_pixmap'
+GDSID = 'GNOME_DESKTOP_SESSION_ID'
+
+class Environment:
+
+ '''Detects properties of the enviroment, and provides a set() method that uses this information to export environment variables needed to start compiz.'''
+
+
+ def __init__(self):
+
+ '''desktop: current desktop enviroment used to choose interface, fallback wm, and default decorator
+
+failsafe: boolean, True if in a failsafe session, currently only supports gnome failsafe mode.
+
+glxinfo: output of glxinfo command
+
+indirect_glxinfo: output of glxinfo with LIBGL_ALWAYS_INDIRECT
+
+xvinfo: output of xvinfo
+
+glx_vendor: 'client glx vendor:' usually one of SGI (for mesa-based drivers), NVIDIA Corporation, or ATI.
+
+tfp: 'direct' if texture_from_pixmap is present with direct rendering (implying presence with indirect as well), 'indirect' if only present with indirect context, False if not present at all
+
+Xgl: True in Xgl'''
+
+ # Check gnome- and kde-specific vars, then try generic 'DESKTOP_SESSION'
+ if GDSID in os.environ:
+ self.desktop = 'gnome'
+
+ elif 'KDE_FULL_SESSION' in os.environ:
+ self.desktop = 'kde'
+
+ else:
+ self.desktop = os.environ.get('DESKTOP_SESSION', 'unknown')
+
+ self.failsafe = False
+ if self.desktop == 'gnome' and GDSID in os.environ and os.environ[GDSID] == 'failsafe':
+ self.failsafe = True
+
+ if self.failsafe:
+ failsafe_str = 'failsafe '
+ else:
+ failsafe_str = ''
+
+ print ' * Detected Session: %s%s' %(failsafe_str, self.desktop)
+
+
+ ## Save the output of glxinfo and xvinfo for later use:
+
+ # don't try to run glxinfo unless it's installed
+ if run(['which', 'glxinfo'], 'call', quiet=True) == 0:
+ self.glxinfo = run('glxinfo', 'output')
+ else:
+ raise SystemExit, ' * Error: glxinfo not installed!'
+
+ # make a temp environment
+ indirect_environ = os.environ.copy()
+ indirect_environ['LIBGL_ALWAYS_INDIRECT'] = '1'
+ self.indirect_glxinfo = run('glxinfo', 'output', env=indirect_environ)
+
+ if run(['which', 'xvinfo'], 'call', quiet=True) == 0:
+ self.xvinfo = run('xvinfo', 'output')
+ else:
+ raise SystemExit, ' * Error: xvinfo not installed!'
+
+ line = [l for l in self.glxinfo.splitlines() if 'client glx vendor string:' in l]
+ if line:
+ self.glx_vendor = ' '.join(line[0].split()[4:])
+ else:
+ self.glx_vendor = ''
+
+ ## Texture From Pixmap / Indirect
+ self.tfp = False
+ if self.glxinfo.count(tfp) < 3:
+ if self.indirect_glxinfo.count(tfp) == 3:
+ self.tfp = 'indirect'
+ else:
+ self.tfp = 'direct'
+
+ ## Xgl
+ if 'Xgl' in self.xvinfo:
+ self.Xgl = True
+
+ else:
+ self.Xgl = False
+
+ def set(self):
+
+ '''Trigger all environment checks'''
+
+ # Check for Intel and export INTEL_BATCH
+ if 'Intel' in self.glxinfo:
+ print ' * Intel detected, exporting: INTEL_BATCH=1'
+ os.environ['INTEL_BATCH'] = '1'
+
+ # Check TFP and export LIBGL_ALWAYS_INDIRECT if needed
+ if self.tfp != 'direct':
+ print ' * No %s with direct rendering context' %tfp
+ if self.tfp == 'indirect':
+ print ' ... present with indirect rendering, exporting: LIBGL_ALWAYS_INDIRECT=1'
+ os.environ['LIBGL_ALWAYS_INDIRECT'] = '1'
+ else:
+ print ' ... nor with indirect rendering, this isn\'t going to work!'
+
+ # If using Xgl with a proprietary driver, exports LD_PRELOAD=<mesa libGL>
+ if self.Xgl and self.glx_vendor != 'SGI':
+ print ' * Non-mesa driver on Xgl detected'
+ from data import mesa_libgl_locations
+ location = [l for l in mesa_libgl_locations if os.path.exists(l)]
+ if location:
+ print ' ... exporting: LD_PRELOAD=%s' %location[0]
+ os.environ['LD_PRELOAD'] = location[0]
+ else:
+ # kindly let the user know... but don't abort (maybe it will work :> )
+ print ' ... no mesa libGL found for preloading, this may not work!'
+
+ # Check for nvidia on Xorg
+ if not self.Xgl and self.glx_vendor == 'NVIDIA Corporation':
+ print ' * NVIDIA on Xorg detected, exporting: __GL_YIELD=NOTHING'
+ os.environ['__GL_YIELD'] = 'NOTHING'
+
+env = Environment()
+
diff --git a/FusionIcon/execute.py b/FusionIcon/execute.py
new file mode 100644
index 0000000..5615cd1
--- /dev/null
+++ b/FusionIcon/execute.py
@@ -0,0 +1,58 @@
+# This file is part of Fusion-icon.
+
+# Fusion-icon 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.
+#
+# Fusion-icon 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/>.
+#
+# Author(s): crdlb, nesl247
+#
+# Copyright 2007 Christopher Williams <christopherw@verizon.net>
+
+import subprocess, signal, os
+
+# avoid zombies
+signal.signal(signal.SIGCHLD, signal.SIG_IGN)
+
+def run(command, mode='spawn', quiet=False, env=None):
+ 'Simple wrapper for the subprocess module. Supported modes: spawn, call, and output'
+
+ if mode == 'spawn':
+ if not quiet:
+ popen_object = subprocess.Popen(command)
+ else:
+ popen_object = subprocess.Popen(command, stdout=open(os.devnull, 'w'))
+
+ return popen_object
+
+ elif mode == 'call':
+ # restore normal child handling
+ signal.signal(signal.SIGCHLD, signal.SIG_DFL)
+ if not quiet:
+ exitcode = subprocess.call(command, stderr=subprocess.PIPE)
+ else:
+ exitcode = subprocess.call(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+ # turn zombie protection back on
+ signal.signal(signal.SIGCHLD, signal.SIG_IGN)
+
+ return exitcode
+
+ elif mode == 'output':
+ signal.signal(signal.SIGCHLD, signal.SIG_DFL)
+ if not env:
+ output = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=open(os.devnull, 'w')).communicate()[0]
+ else:
+ output = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=open(os.devnull, 'w'), env=env).communicate()[0]
+
+ signal.signal(signal.SIGCHLD, signal.SIG_IGN)
+
+ return output
diff --git a/FusionIcon/interface.py b/FusionIcon/interface.py
new file mode 100644
index 0000000..450a7f9
--- /dev/null
+++ b/FusionIcon/interface.py
@@ -0,0 +1,89 @@
+# This file is part of Fusion-icon.
+
+# Fusion-icon 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.
+#
+# Fusion-icon 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/>.
+#
+# Author(s): crdlb, nesl247
+#
+# Copyright 2007 Christopher Williams <christopherw@verizon.net>
+
+import sys
+from util import env
+import start
+
+interfaces={
+ 'gtk': 'GTK',
+ 'qt4': 'Qt4',
+ 'qt3': 'Qt3',
+}
+
+def import_interface(interface):
+ try:
+ if interface in interfaces:
+ print ' * Using the', interfaces[interface], 'Interface'
+ __import__('FusionIcon.interface_%s' %interface)
+
+ else:
+ print ' *** Error: "%s" interface is invalid, this should not happen' %interface
+ raise SystemExit
+
+ except ImportError, e:
+ if [i for i in interfaces if 'interface_%s' %i in str(e)]:
+ print ' * Interface not installed'
+ else:
+ print ' *', e
+
+ #doesn't work so remove it from the dict
+ del interfaces[interface]
+ if interfaces:
+ print ' ... Trying another interface'
+ choose_interface()
+ else:
+ print ' *** Error: All interfaces failed, aborting!'
+ raise SystemExit
+
+def choose_interface(try_first=None):
+
+ chosen_interface = None
+
+ # handle explicit choice first
+ if try_first:
+ if try_first in interfaces:
+ chosen_interface = try_first
+ else:
+ raise SystemExit, ' *** Error: No such interface: %s' %try_first
+ else:
+
+# gtk for everybody for now
+ # use qt for kde; gtk for everything else:
+# if 'qt4' in interfaces and env.desktop == 'kde':
+# chosen_interface = 'qt4'
+
+# elif 'qt3' in interfaces and env.desktop == 'kde':
+# chosen_interface = 'qt3'
+
+ if 'gtk' in interfaces:
+ chosen_interface = 'gtk'
+
+ # try qt* for non-kde:
+ elif 'qt4' in interfaces:
+ chosen_interface = 'qt4'
+ elif 'qt3' in interfaces:
+ chosen_interface = 'qt3'
+
+ # interfaces is empty
+ else:
+ raise SystemExit, ' *** no available interfaces, this should not happen'
+
+ import_interface(chosen_interface)
+
diff --git a/FusionIcon/interface_gtk/__init__.py b/FusionIcon/interface_gtk/__init__.py
new file mode 100644
index 0000000..82a12c4
--- /dev/null
+++ b/FusionIcon/interface_gtk/__init__.py
@@ -0,0 +1,3 @@
+# Fusion Icon
+
+import main
diff --git a/FusionIcon/interface_gtk/main.py b/FusionIcon/interface_gtk/main.py
new file mode 100644
index 0000000..6cf1f5a
--- /dev/null
+++ b/FusionIcon/interface_gtk/main.py
@@ -0,0 +1,214 @@
+# This file is part of Fusion-icon.
+
+# Fusion-icon 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.
+#
+# Fusion-icon 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/>.
+#
+# Based on compiz-icon, Copyright 2007 Felix Bellanger <keeguon@gmail.com>
+#
+# Author(s): crdlb
+# Copyright 2007 Christopher Williams <christopherw@verizon.net>
+
+import os
+import gtk
+if gtk.pygtk_version < (2,10,0):
+ # raise an ImportError here to trigger the Except statement in interface.py
+ raise ImportError, 'PyGtk 2.10.0 or later required'
+
+import time
+from FusionIcon.start import wms, apps, options, decorators, init
+
+class TrayMenu(gtk.Menu):
+
+ def __init__(self):
+ gtk.Menu.__init__(self)
+
+ #CCSM
+ if 'ccsm' in apps:
+ item = ApplicationItem('ccsm')
+ item.set_image(gtk.image_new_from_stock('gtk-preferences', gtk.ICON_SIZE_MENU))
+ self.append(item)
+
+ #Emerald Theme Manager
+ if 'emerald theme manager' in apps:
+ item = ApplicationItem('emerald theme manager')
+ item.set_image(gtk.image_new_from_icon_name('emerald-theme-manager-icon', gtk.ICON_SIZE_MENU))
+ self.append(item)
+
+ if 'ccsm' in apps or 'emerald theme manager' in apps:
+ item = gtk.SeparatorMenuItem()
+ self.append(item)
+
+ #Reload
+ item = gtk.ImageMenuItem('Reload Window Manager')
+ item.connect('activate', self.reload_activate)
+ item.set_image(gtk.image_new_from_stock('gtk-refresh', gtk.ICON_SIZE_MENU))
+ if not wms:
+ item.set_sensitive(False)
+ self.append(item)
+
+ #Window Manager
+ item = gtk.ImageMenuItem('Select Window Manager')
+ item.set_image(gtk.image_new_from_stock('gtk-index', gtk.ICON_SIZE_MENU))
+ submenu = WindowManagerMenu()
+ item.set_submenu(submenu)
+ if not wms:
+ item.set_sensitive(False)
+ self.append(item)
+
+ #Compiz Options
+ item = gtk.ImageMenuItem('Compiz Options')
+ item.set_image(gtk.image_new_from_stock('gtk-properties', gtk.ICON_SIZE_MENU))
+ submenu = CompizOptionMenu()
+ item.set_submenu(submenu)
+ if not options:
+ item.set_sensitive(False)
+ self.append(item)
+
+ #Window Decorator
+ item = gtk.ImageMenuItem('Select Window Decorator')
+ item.set_image(gtk.image_new_from_stock('gtk-select-color', gtk.ICON_SIZE_MENU))
+ submenu = CompizDecoratorMenu()
+ item.set_submenu(submenu)
+ if not decorators:
+ item.set_sensitive(False)
+ self.append(item)
+
+ item = gtk.SeparatorMenuItem()
+ self.append(item)
+
+ item = gtk.ImageMenuItem(stock_id=gtk.STOCK_QUIT)
+ item.connect('activate', self.quit_activate)
+ self.append(item)
+
+ def show_menu(self, widget, button, time):
+ self.show_all()
+ self.popup(None, None, gtk.status_icon_position_menu, button, time, icon)
+
+ def reload_activate(self, widget):
+ wms.restart()
+
+ def quit_activate(self, widget):
+ gtk.main_quit()
+
+class ApplicationItem(gtk.ImageMenuItem):
+
+ def __init__(self, app):
+ gtk.ImageMenuItem.__init__(self, apps[app].label)
+
+ self.app = app
+ if app not in apps:
+ self.set_sensitive(False)
+ self.connect('activate', self.activate)
+
+ def activate(self, widget):
+ apps[self.app].launch()
+
+class WindowManagerItem(gtk.RadioMenuItem):
+
+ def __init__(self, wm, first_item=None):
+ gtk.RadioMenuItem.__init__(self, label=' %s' %wms[wm].label)
+
+ self.wm = wm
+ if first_item:
+ self.set_group(first_item)
+ if wms.active == wm:
+ self.set_active(True)
+ self.connect('activate', self.activate)
+
+ def activate(self, widget):
+ if widget.get_active():
+ wms.active = self.wm
+ wms.start()
+
+class WindowManagerMenu(gtk.Menu):
+
+ def __init__(self):
+ gtk.Menu.__init__(self)
+
+ first = True
+ for wm in wms.ordered_list:
+ if first:
+ first_item = WindowManagerItem(wm)
+ self.append(first_item)
+ first = False
+ else:
+ item = WindowManagerItem(wm, first_item)
+ self.append(item)
+
+class CompizOptionItem(gtk.CheckMenuItem):
+
+ def __init__(self, option):
+ gtk.CheckMenuItem.__init__(self, label=' %s' %options[option].label)
+
+ self.option = option
+ self.set_active(options[option].enabled)
+ if not options[option].sensitive:
+ self.set_sensitive(False)
+ self.connect('activate', self.activate)
+
+ def activate(self, widget):
+ options[self.option].enabled = widget.get_active()
+ if wms.active == 'compiz':
+ wms.start()
+
+class CompizOptionMenu(gtk.Menu):
+
+ def __init__(self):
+ gtk.Menu.__init__(self)
+
+ for option in options:
+ item = CompizOptionItem(option)
+ self.append(item)
+
+class CompizDecoratorItem(gtk.RadioMenuItem):
+
+ def __init__(self, decorator, first_item=None):
+ gtk.RadioMenuItem.__init__(self, label=' %s' %decorators[decorator].label)
+
+ self.decorator = decorator
+ if first_item:
+ self.set_group(first_item)
+ if decorators.active == decorator:
+ self.set_active(True)
+ self.connect('activate', self.activate)
+
+ def activate(self, widget):
+ if widget.get_active():
+ decorators[self.decorator].kill_others()
+ time.sleep(0.5)
+ decorators.active = self.decorator
+
+class CompizDecoratorMenu(gtk.Menu):
+
+ def __init__(self):
+ gtk.Menu.__init__(self)
+
+ first = True
+ for decorator in decorators:
+ if first:
+ first_item = CompizDecoratorItem(decorator)
+ self.append(first_item)
+ first = False
+ else:
+ item = CompizDecoratorItem(decorator, first_item)
+ self.append(item)
+
+icon = gtk.status_icon_new_from_icon_name('fusion-icon')
+icon.set_tooltip('Compiz Fusion Icon')
+menu = TrayMenu()
+icon.connect('popup-menu', menu.show_menu)
+
+# active wm (possibly) starts here
+init()
+gtk.main()
+
diff --git a/FusionIcon/interface_qt4/__init__.py b/FusionIcon/interface_qt4/__init__.py
new file mode 100644
index 0000000..82a12c4
--- /dev/null
+++ b/FusionIcon/interface_qt4/__init__.py
@@ -0,0 +1,3 @@
+# Fusion Icon
+
+import main
diff --git a/FusionIcon/interface_qt4/main.py b/FusionIcon/interface_qt4/main.py
new file mode 100644
index 0000000..91fb63f
--- /dev/null
+++ b/FusionIcon/interface_qt4/main.py
@@ -0,0 +1,80 @@
+# This file is part of Fusion-icon.
+
+# Fusion-icon 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.
+#
+# Fusion-icon 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/>.
+
+# Author(s): xsacha
+
+import sys, os, time
+from PyQt4 import QtGui, QtCore
+from FusionIcon.start import wms, apps, options, decorators, init
+
+class Build(QtGui.QApplication):
+ def reload_wm(self):
+ wms.restart()
+ def toggleWM(self, wm):
+ if wms.active != wm:
+ wms.active = wm
+ wms.start()
+ def toggleOP(self, option):
+ options[option].enabled = not options[option].enabled
+ if wms.active == 'compiz':
+ wms.start()
+ def toggleWD(self, decorator):
+ decorators[decorator].kill_others()
+ time.sleep(0.5)
+ decorators.active = decorator
+ def __init__(self, parent=None):
+ QtCore.QObject.__init__(self, parent)
+ # Qt sucks (I'm aware this breaks if prefix != /usr...)
+ self.Tray = QtGui.QSystemTrayIcon(QtGui.QIcon('/usr/share/icons/hicolor/22x22/apps/fusion-icon.png'))
+ self.Tray.setToolTip('Compiz Fusion Icon')
+ self.Tray.managerMenu = QtGui.QMenu()
+ self.Tray.optionsMenu = QtGui.QMenu()
+ self.Tray.decoratorMenu = QtGui.QMenu()
+ self.groupManager = QtGui.QActionGroup(self.Tray.managerMenu)
+ self.groupDecorator = QtGui.QActionGroup(self.Tray.decoratorMenu)
+ for wm in wms.ordered_list:
+ actionWM = self.groupManager.addAction(self.Tray.managerMenu.addAction(wms[wm].label, lambda val=wm : self.toggleWM(val)))
+ actionWM.setCheckable(True)
+ if wms.active == wm:
+ actionWM.setChecked(True)
+ for option in options:
+ actionOP = self.Tray.optionsMenu.addAction(options[option].label, lambda val=option: self.toggleOP(val))
+ actionOP.setCheckable(True)
+ if not options[option].sensitive:
+ actionOP.setEnabled(False)
+ actionOP.setChecked(options[option].enabled)
+ for decorator in decorators:
+ actionWD = self.groupDecorator.addAction(self.Tray.decoratorMenu.addAction(decorators[decorator].label, lambda val=decorator: self.toggleWD(val)))
+ actionWD.setCheckable(True)
+ if decorators.active == decorator:
+ actionWD.setChecked(True)
+ self.Tray.menu = QtGui.QMenu()
+ if 'ccsm' in apps:
+ self.Tray.menu.addAction(apps['ccsm'].label, lambda: run(['ccsm']))
+ if 'emerald theme manager' in apps:
+ self.Tray.menu.addAction(apps['emerald theme manager'].label, lambda: run(apps['emerald theme manager'].command))
+ if 'ccsm' in apps or 'emerald theme manager' in apps:
+ self.Tray.menu.addSeparator()
+ self.Tray.menu.addAction("Reload Window Manager", self.reload_wm)
+ self.Tray.menu.addAction("Select Window Manager").setMenu(self.Tray.managerMenu)
+ self.Tray.menu.addAction("Compiz Options").setMenu(self.Tray.optionsMenu)
+ self.Tray.menu.addAction("Select Window Decorator").setMenu(self.Tray.decoratorMenu)
+ self.Tray.menu.addSeparator()
+ self.Tray.menu.addAction("Quit", self.quit)
+ self.Tray.setContextMenu(self.Tray.menu)
+ self.Tray.show()
+ init()
+Build(sys.argv).exec_()
+
diff --git a/FusionIcon/parser.py b/FusionIcon/parser.py
new file mode 100644
index 0000000..9b58145
--- /dev/null
+++ b/FusionIcon/parser.py
@@ -0,0 +1,57 @@
+# This file is part of Fusion-icon.
+
+# Fusion-icon 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.
+#
+# Fusion-icon 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/>.
+#
+# Author(s): crdlb
+# Copyright 2007 Christopher Williams <christopherw@verizon.net>
+
+from optparse import OptionParser, OptionGroup
+
+parser = OptionParser(usage='usage: %prog [options|action]', version='%prog-0.0.0')
+
+parser.add_option('--reset', action='store_true', dest='reset',
+ help='remove configuration file and exit')
+
+parser.add_option('-s', '--sleep', type='int', dest='seconds',
+ help='Sleep before launching')
+
+parser.add_option('-v', '--verbose', action='store_true', dest='verbose',
+ help='Print extra output')
+
+interface_group = OptionGroup(parser, 'Interface Options')
+
+interface_group.add_option('-i', '--interface', dest='interface',
+ help='Try a certain interface first')
+
+interface_group.add_option('-u', '--no-interface', action='store_true', dest='no_interface',
+ help='Do not use any interface')
+
+parser.add_option_group(interface_group)
+
+startup_group = OptionGroup(parser, 'Startup Options')
+
+startup_group.add_option('-f', '--force-compiz', action='store_true', dest='force_compiz',
+ help='Start compiz regardless of environment or configuration')
+
+startup_group.add_option('-n', '--no-start', action='store_true', dest='no_start',
+ help='Run, but do not start a window manager')
+
+parser.add_option_group(startup_group)
+
+options, args = parser.parse_args()
+
+# fusion-icon accepts no arguments
+if args:
+ parser.error('no such argument: %s' %args[0])
+
diff --git a/FusionIcon/start.py b/FusionIcon/start.py
new file mode 100644
index 0000000..7dafdad
--- /dev/null
+++ b/FusionIcon/start.py
@@ -0,0 +1,68 @@
+# This file is part of Fusion-icon.
+
+# Fusion-icon 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.
+#
+# Fusion-icon 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/>.
+#
+# Author(s): crdlb, nesl247
+#
+# Copyright 2007 Christopher Williams <christopherw@verizon.net>
+
+from parser import options as parser_options
+from util import env, config, apps, options, wms, decorators
+
+def init():
+ 'Final start function, should be called once when fusion-icon starts'
+
+ if not parser_options.no_start:
+ # Do not restart the wm if it's already running
+ if wms.active == wms.active == wms.old != 'compiz':
+ #always restart compiz since we can't know compiz was started correctly
+ print ' * %s is already running' %wms[wms.active].label
+ else:
+ print ' * Starting %s' %wms[wms.active].label
+ wms.start()
+
+config.check()
+
+# Make some changes
+
+if not parser_options.force_compiz:
+ if wms.active not in wms:
+ print ' * "%s" not installed' %wms.active
+ if wms.fallback:
+ print ' ... setting to fallback...'
+ else:
+ print ' ... No fallback window manager chosen'
+ wms.active = wms.fallback
+# if in a failsafe session, don't start with compiz (provides an easy way to make sure metacity starts for gnome users if compiz breaks)
+ if wms.active == 'compiz' and env.failsafe:
+ if wms.fallback:
+ print ' * Failsafe session, setting to fallback...'
+ else:
+ print ' ... No fallback window manager chosen'
+
+ wms.active = wms.fallback
+
+elif 'compiz' in wms:
+ wms.active = 'compiz'
+
+else:
+ raise SystemExit, ' *** Error: "--force-compiz" used and compiz not installed!'
+
+# Set True if using Xorg AIGLX since the '--indirect-rendering' option has no effect in that situation.
+env.set()
+if env.tfp == 'indirect' and 'indirect rendering' in options:
+ options['indirect rendering'].sensitive = False
+ if not options['indirect rendering'].enabled:
+ options['indirect rendering'].enabled = True
+
diff --git a/FusionIcon/util.py b/FusionIcon/util.py
new file mode 100644
index 0000000..d121334
--- /dev/null
+++ b/FusionIcon/util.py
@@ -0,0 +1,419 @@
+# This file is part of Fusion-icon.
+
+# Fusion-icon 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.
+#
+# Fusion-icon 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/>.
+#
+# Based on compiz-icon, Copyright 2007 Felix Bellanger <keeguon@gmail.com>
+#
+# Author(s): crdlb
+# Copyright 2007 Christopher Williams <christopherw@verizon.net>
+
+import os, compizconfig, ConfigParser, time
+import data as _data
+from parser import options as parser_options
+from environment import env
+from execute import run
+import subprocess, signal
+
+def is_running(app):
+ 'Use pgrep to determine if an app is running'
+
+ if run(['pgrep', app], 'call', quiet=True) == 0:
+ return True
+
+
+class Application(object):
+
+ def __init__(self, name, apps, installed):
+
+ self.name = name
+ self.apps = apps
+
+ self.base = installed.apps[name][0]
+ self.command = installed.apps[name][1]
+ self.label = installed.apps[name][2]
+
+ def launch(self):
+ print ' * Launching %s' %self.label
+ run(self.command)
+
+class Applications(dict):
+
+ def __init__(self, installed):
+ for app in installed.apps:
+ self[app] = Application(app, self, installed)
+
+class CompizOption(object):
+
+ def __init__(self, name, options, installed, config):
+
+ self.options = options
+ self.config = config
+
+ self.name = name
+ self.switch = installed.options[name][1]
+ self.label = installed.options[name][2]
+ self.sensitive = True
+
+ def __get(self):
+ return self.config.getboolean('compiz options', self.name)
+
+ def __set(self, value):
+ print ' * Setting option %s to %s' %(self.label, value)
+ self.config.set('compiz options', self.name, str(bool(value)).lower())
+ self.config.write(open(self.config.config_file, 'w'))
+
+ enabled = property(__get, __set)
+
+class CompizOptions(dict):
+
+ def __init__(self, installed, config):
+ for option in installed.options:
+ self[option] = CompizOption(option, self, installed, config)
+
+class WindowManager(object):
+
+ def __init__(self, name, wms, installed):
+
+ self.wms = wms
+ self.name = name
+ self.base = installed.wms[name][0]
+ self.command = installed.wms[name][1]
+ self.label = installed.wms[name][2]
+ self.desktop = installed.wms[name][3]
+ if installed.wms[name][4]:
+ self.flags = installed.wms[name][4]
+ else:
+ self.flags = []
+ self.killcmd = installed.wms[name][5]
+
+class WindowManagers(dict):
+
+ def __init__(self, installed, config):
+
+ self.config = config
+
+ for wm in installed.wms:
+ self[wm] = WindowManager(wm, self, installed)
+
+ self.fallback = None
+ wm = [w for w in self if self[w].desktop == env.desktop]
+ if wm:
+ self.fallback = wm[0]
+
+ elif self:
+ self.fallback = self.keys()[0]
+
+ self.__set_old()
+
+ self.ordered_list = []
+ for wm in ('compiz', self.fallback):
+ if wm in self:
+ self.ordered_list.append(wm)
+ self.ordered_list.extend([wm for wm in self if wm not in self.ordered_list])
+
+ def __get(self):
+ return self.config.get('window manager', 'active wm')
+
+ def __set(self, value):
+
+ if value in wms:
+ print ' * Setting window manager to', wms[value].label
+ elif not value:
+ print ' * Setting window manager to empty value'
+
+ self.config.set('window manager', 'active wm', str(value))
+ self.config.write(open(self.config.config_file, 'w'))
+
+ def __set_old(self):
+
+ self.old = None
+ running_wm = [wm for wm in self if is_running(wm)]
+ if running_wm:
+ # not perfect, but good enough
+ self.old = running_wm[0]
+
+ def start(self):
+ 'Start the active window manager'
+
+ self.__set_old()
+
+ if self.active == 'compiz' and self.old and self[self.old].killcmd:
+ run(self[self.old].killcmd, 'call')
+ time.sleep(1)
+
+ if self.active and self.old and 'noreplace' in self[self.active].flags:
+ run(['killall', self[self.old].base], 'call')
+ time.sleep(1)
+
+ if self.active == 'compiz':
+ # use a copy, not the original
+ compiz_command = self['compiz'].command[:]
+ for option in options:
+ if options[option].enabled:
+ compiz_command.append(options[option].switch)
+
+ kill_list = ['killall']
+ for decorator in decorators:
+ kill_list.append(decorators[decorator].base)
+ run(kill_list, 'call')
+
+ time.sleep(0.5)
+
+ # do it
+ print ' ... executing:', ' '.join(compiz_command)
+ run(compiz_command, quiet=False)
+
+ elif self.active:
+ run(self[self.active].command)
+
+ else:
+ print ' * No active WM set; not going to do anything.'
+
+ def restart(self):
+ if wms.active:
+ print ' * Reloading %s' %wms.active
+ self.start()
+
+ else:
+ print ' * Not reloading, no active window manager set'
+
+ active = property(__get, __set)
+
+class CompizDecorator(object):
+
+ def __init__(self, name, decorators, installed):
+
+ self.decorators = decorators
+ self.name = name
+ self.base = installed.decorators[name][0]
+ self.command = installed.decorators[name][1]
+ self.label = installed.decorators[name][2]
+ self.desktop = installed.decorators[name][3]
+
+ def kill_others(self):
+ killall = ['killall']
+ for decorator in [x for x in self.decorators if x != self.name]:
+ killall.append(self.decorators[decorator].base)
+ run(killall, 'call')
+
+class CompizDecorators(dict):
+
+ def __init__(self, installed):
+
+ # Open CompizConfig context
+ if parser_options.verbose:
+ print ' * Opening CompizConfig context'
+
+ try:
+ context = compizconfig.Context( \
+ plugins=['decoration'], basic_metadata=True)
+
+ except:
+ context = compizconfig.Context()
+
+ self.command = context.Plugins['decoration'].Display['command']
+
+ for decorator in installed.decorators:
+ self[decorator] = CompizDecorator(decorator, self, installed)
+
+ self.default = None
+ decorator = [d for d in self if self[d].desktop == env.desktop]
+ if decorator:
+ self.default = decorator[0]
+
+ elif 'emerald' in self:
+ self.default = 'emerald'
+
+ elif self:
+ self.default = self.keys()[0]
+
+ def __set(self, decorator):
+ if decorator in self:
+ self.command.Plugin.Context.ProcessEvents()
+ print ' * Setting decorator to %s ("%s")' \
+ %(self[decorator].label, self[decorator].command)
+ self.command.Value = self[decorator].command
+ self.command.Plugin.Context.Write()
+ elif not decorator:
+ print ' * Not setting decorator to none'
+
+ def __get(self):
+ _decorator = [d for d in self if self.command.Value == self[d].command]
+ if _decorator:
+ decorator = _decorator[0]
+ else:
+ print ' * Decorator "%s" is invalid.' %self.command.Value
+ self.active = self.default
+ decorator = self.command.Value
+ return decorator
+
+ active = property(__get, __set)
+
+class Installed(object):
+
+ def __init__(self, data):
+ print ' * Searching for installed applications...'
+
+ ### Compiz Detection
+ bins = {}
+ for name in ('compiz', 'compiz.real'):
+ bin = run(['which', name], 'output')
+ if bin:
+ bins[name] = bin
+
+ if 'compiz' in bins and 'compiz.real' in bins:
+ if bins['compiz'].split(os.sep)[:-1] == bins['compiz.real'].split(os.sep)[:-1]:
+ compiz = 'compiz.real'
+ else:
+ compiz = 'compiz'
+
+ elif 'compiz.real' in bins:
+ compiz = 'compiz.real'
+
+ elif 'compiz' in bins:
+ compiz = 'compiz'
+
+ else:
+ compiz = None
+
+ output = ''
+
+ for name in bins:
+ if len(bins) > 1 and name == compiz:
+ selected = ' <*>'
+ else:
+ selected = ''
+ output += ' -- %s%s' %(bins[name], selected)
+
+ ### Everything Else
+ self.wms = data.wms.copy()
+ for wm in data.wms:
+ which = run(['which', data.wms[wm][0]], 'output')
+ if which:
+ output += ' -- %s' %which
+ else:
+ del self.wms[wm]
+
+ if compiz:
+ data.compiz_args.insert(0, compiz)
+ self.wms['compiz'] = (compiz, data.compiz_args, 'Compiz', None, None, None)
+
+ self.decorators = data.decorators.copy()
+ for decorator in data.decorators:
+ which = run(['which', data.decorators[decorator][0]], 'output')
+ if which:
+ output += ' -- %s' %which
+ else:
+ del self.decorators[decorator]
+
+ self.apps = data.apps.copy()
+ for app in data.apps:
+ which = run(['which', data.apps[app][0]], 'output')
+ if which:
+ output += ' -- %s' %which
+ else:
+ del self.apps[app]
+
+ if parser_options.verbose:
+ print output.rstrip()
+
+ compiz_optionlist = []
+
+ self.options = data.options.copy()
+
+ if compiz:
+ compiz_help = run([compiz, '--help'], 'output')
+ for item in compiz_help.split():
+ item = item[1:].replace(']', '')
+ if item.startswith('--'):
+ compiz_optionlist.append(item)
+
+ for option in data.options:
+ if data.options[option][1] not in compiz_optionlist:
+ del self.options[option]
+
+class Configuration(ConfigParser.ConfigParser):
+
+ def __init__(self, data):
+
+ ConfigParser.ConfigParser.__init__(self)
+ self.config_folder = data.config_folder
+ self.config_file = data.config_file
+
+ def check(self):
+
+ # Configuration file setup
+ if not os.path.exists(self.config_folder):
+ if parser_options.verbose:
+ print ' * Creating configuration folder...'
+ os.makedirs(self.config_folder)
+
+ if not os.path.exists(self.config_file):
+ if parser_options.verbose:
+ print ' * Creating configuration file...'
+ self.create_config_file()
+
+ try:
+ # Read the file
+ self.read(self.config_file)
+ # Validate the file by trying to read all values
+ for option in options:
+ value = options[option].enabled
+ value = wms.active
+
+ except:
+ # back it up and make a new one
+ print ' * Configuration file (%s) invalid' %self.config_file
+ self.reset_config_file()
+ print ' * Generating new configuration file'
+ self.create_config_file()
+
+ def create_config_file(self):
+ 'Set default values for configuration file'
+
+ def prune(section, optlist):
+ for option in [o for o in self.options(section) if o not in optlist]:
+ self.remove_option(section, option)
+
+ for section in ('compiz options', 'window manager'):
+ if not self.has_section(section):
+ self.add_section(section)
+
+ for option in options:
+ self.set('compiz options', option, 'false')
+ self.set('window manager', 'active wm', 'compiz')
+
+ prune('compiz options', options)
+ prune('window manager', ['active wm'])
+ self.write(open(self.config_file, 'w'))
+
+ def reset_config_file(self):
+ 'Backup configuration file'
+
+ if os.path.exists(self.config_file):
+ config_backup = '%s.backup.%s' \
+ %(self.config_file, time.strftime('%Y%m%d%H%M%S'))
+ os.rename(self.config_file, config_backup)
+ print ' ... backed up to:', config_backup
+ else:
+ print ' ... no configuration file found'
+
+# Instantiate...
+_installed = Installed(_data)
+config = Configuration(_data)
+apps = Applications(_installed)
+options = CompizOptions(_installed, config)
+wms = WindowManagers(_installed, config)
+decorators = CompizDecorators(_installed)
+