#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# Authors: Quinn Storm (quinn@beryl-project.org)
# Patrick Niklaus (marex@opencompositing.org)
# Copyright (C) 2007 Quinn Storm
import os
import pygtk
import gtk
import gtk.gdk
import gobject
from ccm.Constants import *
import locale
import gettext
locale.setlocale(locale.LC_ALL, "")
gettext.bindtextdomain("ccsm", DataDir + "/locale")
gettext.textdomain("ccsm")
_ = gettext.gettext
def getScreens():
screens = []
display = gtk.gdk.display_get_default()
nScreens = display.get_n_screens()
for i in range(nScreens):
screens.append(i)
return screens
class Style:
def __init__(self):
fakeWindow = gtk.Window()
styleWidget = gtk.Entry()
fakeWindow.add(styleWidget)
styleWidget.realize()
bc = styleWidget.style.bg[gtk.STATE_SELECTED]
self.BrightColor = "#%.4x%.4x%.4x" % (bc.red, bc.green, bc.blue)
bc = styleWidget.style.light[gtk.STATE_NORMAL]
self.BackgroundColor = "#%.4x%.4x%.4x" % (bc.red, bc.green, bc.blue)
styleWidget.destroy()
fakeWindow.destroy()
class Image(gtk.Image):
def __init__(self, name=None, type=ImageNone, size = 32):
gtk.Image.__init__(self)
if name != None:
if type == ImagePlugin:
iconpath = "%s/plugin-%s.svg" % (PixmapDir, name)
if not os.path.exists(iconpath):
iconpath = "%s/plugin-unknown.svg"%PixmapDir
try:
pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(iconpath, size, size)
self.set_from_pixbuf(pixbuf)
except:
self.set_from_stock(gtk.STOCK_MISSING_IMAGE, gtk.ICON_SIZE_BUTTON)
elif type == ImageCategory:
iconpath = "%s/category-%s.svg" % (PixmapDir, name)
if not os.path.exists(iconpath):
iconpath = "%s/category-uncategorized.svg" % PixmapDir
try:
pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(iconpath, size, size)
self.set_from_pixbuf(pixbuf)
except:
self.set_from_stock(gtk.STOCK_MISSING_IMAGE, gtk.ICON_SIZE_BUTTON)
elif type == ImageThemed:
iconTheme = gtk.icon_theme_get_default()
try:
pixbuf = iconTheme.load_icon(name, size, 0)
self.set_from_pixbuf(pixbuf)
except:
self.set_from_stock(gtk.STOCK_MISSING_IMAGE, gtk.ICON_SIZE_BUTTON)
elif type == ImageStock:
try:
self.set_from_stock(name, size)
except:
self.set_from_stock(gtk.STOCK_MISSING_IMAGE, gtk.ICON_SIZE_BUTTON)
class PrettyButton (gtk.Button):
__gsignals__ = {
'expose-event' : 'override',
}
def __init__ (self):
super (PrettyButton, self).__init__ ()
self.states = {
"focus" : False,
"pointer" : False
}
self.set_size_request (200, -1)
self.set_relief (gtk.RELIEF_NONE)
self.connect ("focus-in-event", self.update_state_in, "focus")
self.connect ("focus-out-event", self.update_state_out, "focus")
def update_state_in (self, *args):
widget, state = args[0], args[-1]
widget.set_state (gtk.STATE_PRELIGHT)
self.states[state] = True
def update_state_out (self, *args):
widget, state = args[0], args[-1]
self.states[state] = False
if True in self.states.values ():
widget.set_state (gtk.STATE_PRELIGHT)
else:
widget.set_state (gtk.STATE_NORMAL)
def do_expose_event (self, event):
has_focus = self.flags () & gtk.HAS_FOCUS
if has_focus:
self.unset_flags (gtk.HAS_FOCUS)
ret = super (PrettyButton, self).do_expose_event (self, event)
if has_focus:
self.set_flags (gtk.HAS_FOCUS)
return ret
class Label(gtk.Label):
def __init__(self, value = "", wrap = 160):
gtk.Label.__init__(self, value)
self.props.xalign = 0
self.props.wrap_mode = gtk.WRAP_WORD
self.set_line_wrap(True)
self.set_size_request(wrap, -1)
class NotFoundBox(gtk.Alignment):
def __init__(self, value):
gtk.Alignment.__init__(self, 0.5, 0.5, 0.0, 0.0)
box = gtk.HBox()
self.Warning = gtk.Label()
self.Markup = _("<span size=\"large\"><b>No matches found.</b> </span><span>\n\n Your filter \"<b>%s</b>\" does not match any items.</span>")
self.Warning.set_markup(self.Markup % value)
image = Image("face-surprise", ImageThemed, 48)
box.pack_start(image, False, False, 0)
box.pack_start(self.Warning, True, True, 15)
self.add(box)
def update(self, value):
self.Warning.set_markup(self.Markup % value)
# Updates all registered setting when they where changed through CompizConfig
class Updater:
def __init__(self, context):
self.VisibleSettings = []
self.NotRemoved = []
self.Context = context
gobject.timeout_add(2000, self.Update)
def Append(self, setting):
self.VisibleSettings.append(setting)
def Update(self):
changed = self.Context.ProcessEvents()
if changed:
changedSettings = self.Context.ChangedSettings
for settingWidget in self.VisibleSettings:
# Remove already destroyed widgets
if not settingWidget.Widget.get_parent():
self.VisibleSettings.remove(settingWidget)
# Exception for multi settings widgets (multi list widget, action page, etc.)
if settingWidget.Setting.__class__ != list:
if settingWidget.Setting in changedSettings:
settingWidget.Read()
changedSettings.remove(settingWidget.Setting)
else:
read = False
for setting in settingWidget.Setting:
if setting in changedSettings:
read = True
changedSettings.remove(setting)
if read:
settingWidget.Read()
# For removing non-visible settings
for oldSetting in self.NotRemoved:
if oldSetting in changedSettings:
changedSettings.remove(oldSetting)
self.NotRemoved = changedSettings
self.Context.ChangedSettings = changedSettings
return True
class PureVirtualError(Exception):
pass
def SettingSortCompare(v1, v2):
return cmp(v1.Plugin.Ranking[v1.Name], v2.Plugin.Ranking[v2.Name])
def FirstItemSortCompare(sg1, sg2):
return cmp(sg1[0], sg2[0])
def EnumSettingSortCompare(v1, v2):
return cmp(v1[1], v2[1])
def PluginSortCompare(p1, p2):
return cmp(p1.ShortDesc, p2.ShortDesc)
# singleRun is used to combine the run stages, in this case run is a list
# containing the run levels which should be used to filter the settings
def FilterSettings(settings, filter, run=0, noActions=False, singleRun=False):
if filter == None:
return settings
filteredSettings = []
for setting in settings:
if noActions and setting.Type == 'Action':
continue
# First run, only search in shortDesc and name
if run == 0 or (singleRun and run.count(0) != 0):
shortDesc = setting.ShortDesc.lower()
name = setting.Name.lower()
if shortDesc.find(filter) != -1:
filteredSettings.append(setting)
continue
elif name.find(filter) != -1:
filteredSettings.append(setting)
continue
# Then in longDesc
if run == 1 or (singleRun and run.count(1) != 0):
longDesc = setting.LongDesc.lower()
if longDesc.find(filter) != -1:
filteredSettings.append(setting)
continue
# Finally search in the option value
if run == 2 or (singleRun and run.count(2) != 0):
value = ""
# make sure enum settings work too
if setting.Type == 'Int' and len(setting.Info[2].keys()) > 0:
value = sorted(setting.Info[2].items(), EnumSettingSortCompare)[setting.Value][0]
value = value.lower()
# also make sure intDesc settings work right
elif setting.Type == 'List' and setting.Info[0] == 'Int' and len(setting.Info[1][2]) > 0:
for int in setting.Value:
for item in setting.Info[1][2].items():
if item[1] == int:
value += item[0]
value = value.lower()
# we also need actions support
elif setting.Type == 'Action':
value = str(setting.Value).lower()
else:
value = str(setting.Value).lower()
if value.find(filter) != -1:
filteredSettings.append(setting)
# Nothing was found, search also in the longDesc/value
if len(filteredSettings) == 0 and run < 2 and not singleRun:
return FilterSettings(settings, filter, run+1, noActions, False)
return filteredSettings
def HasOnlyType(settings, type):
empty = True
for setting in settings:
empty = False
if setting.Type != type:
return False
return not empty
syntax highlighted by Code2HTML, v. 0.9.1