#!/usr/bin/env python3

# Copyright (C) 2007-2014 by Clement Lefebvre <root@linuxmint.com>
# Copyright (C) 2015 Martin Wimpress <code@ubuntu-mate.org>
#
# 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.

import errno
import gettext
import getpass
import gi
import glob
import mmap
import os
import shutil
import signal
import subprocess
import string
import sys

from configobj import ConfigObj
from ctypes import cdll, byref, create_string_buffer
from subprocess import DEVNULL, PIPE

from gi.repository import Gdk
from gi.repository import GdkPixbuf
from gi.repository import GdkX11
from gi.repository import Gio
from gi.repository import GObject
from gi.repository import Gtk
from gi.repository import Notify
from gi.repository import GLib

# Workaround introspection bug, gnome bug 622084
signal.signal(signal.SIGINT, signal.SIG_DFL)

__VERSION__ = '3.5.2a'

# i18n
gettext.install('mate-tweak', os.path.join('/','usr','share','locale'))

def set_proc_title(name=None):
    '''Set the process title'''

    if not name:
        name = os.path.basename(sys.argv[0])

    libc = cdll.LoadLibrary('libc.so.6')
    buff = create_string_buffer(len(name)+1)
    buff.value = name.encode("UTF-8")
    ret = libc.prctl(15, byref(buff), 0, 0, 0)

    if ret != 0:
        print("Failed to set process title")

    return ret

class SidePage:
    def __init__(self, notebook_index, name, icon):
        self.notebook_index = notebook_index
        self.name = name
        self.icon = icon

class MateTweak:
    def on_checkbox_toggled(self, widget, schema_id, key):
        # If Maximus is being tweaked, replace it to make the settings effective.
        if schema_id == "org.mate.maximus" and (key == "undecorate" or key == "no-maximize"):
            subprocess.Popen(['mate-maximus', '--replace'], stdout=DEVNULL, stderr=DEVNULL)

            # When changing undecorate state replace the window manager
            # to ensure there are no rendering or strut issues.
            if key == 'undecorate':
                self.replace_windowmanager(self.current_wm, False)

    def set_string(self, schema, path, key, value):
        if path: settings = Gio.Settings.new_with_path(schema, path)
        else: settings = Gio.Settings.new(schema)
        try:
            settings.set_string(key, value)
        except:
            print('Unable set ' + key + ' with ' + value + ' in ' + schema)
            pass

    def get_string(self, schema, path, key):
        if path: settings = Gio.Settings.new_with_path(schema, path)
        else: settings = Gio.Settings.new(schema)
        return settings.get_string(key)

    def set_bool(self, schema, path, key, value):
        if path: settings = Gio.Settings.new_with_path(schema, path)
        else: settings = Gio.Settings.new(schema)
        settings.set_boolean(key, value)

    def get_bool(self, schema, path, key):
        if path: settings = Gio.Settings.new_with_path(schema, path)
        else: settings = Gio.Settings.new(schema)
        return settings.get_boolean(key)

    def init_checkbox(self, schema_id, key, name):
        source = Gio.SettingsSchemaSource.get_default()
        schema = source.lookup(schema_id, True)
        if schema:
            settings = Gio.Settings.new_full(schema)
            widget = self.builder.get_object(name)

            settings.bind(key, widget, "active", Gio.SettingsBindFlags.DEFAULT)
            widget.connect("toggled", self.on_checkbox_toggled, schema_id, key)

    def init_combobox(self, schema, key, name):
        source = Gio.SettingsSchemaSource.get_default()
        if source.lookup(schema, True) != None:
            widget = self.builder.get_object(name)
            conf = self.get_string(schema, None, key)
            index = 0
            for row in widget.get_model():
                if(conf == row[1]):
                    widget.set_active(index)
                    break
                index = index +1
            widget.connect("changed", self.combo_fallback, schema, key)

    def update_combobox(self, schema, key, name):
        source = Gio.SettingsSchemaSource.get_default()
        if source.lookup(schema, True) != None:
            widget = self.builder.get_object(name)
            conf = self.get_string(schema, None, key)
            index = 0
            for row in widget.get_model():
                if(conf == row[1]):
                    widget.set_active(index)
                    break
                index = index +1

    def find_on_path(self, command):
        """Is command on the executable search path?"""
        if 'PATH' not in os.environ:
            return False
        path = os.environ['PATH']
        for element in path.split(os.pathsep):
            if not element:
                continue
            filename = os.path.join(element, command)
            if os.path.isfile(filename) and os.access(filename, os.X_OK):
                return True
        return False

    def mkdir_p(self, path):
        try:
            os.makedirs(path)
        except OSError as exc: # Python >2.5
            if exc.errno == errno.EEXIST and os.path.isdir(path):
                pass
            else:
                raise

    def check_wm_features(self):
        screen = Gdk.Screen.get_default()
        current_wm = GdkX11.X11Screen.get_window_manager_name(screen)

        # Order is important because Marco actually advertises itself
        # as 'Marco (Metacity)'.
        if ('Marco' in current_wm):
            self.current_wm = 'marco'
        elif ('Metacity' in current_wm):
            self.current_wm = 'metacity'
        elif ('Muffin' in current_wm):
            self.current_wm = 'muffin'
        elif ('Mutter' in current_wm):
            self.current_wm = 'mutter'
        elif ('Compiz' in current_wm):
            self.current_wm = 'compiz'
        else:
            self.current_wm = 'Unknown'

        print('Window Manager is: ' + self.current_wm)

        self.compiz_capable = False
        self.compton_capable = False
        self.marco_capable = False
        self.metacity_capable = False
        self.muffin_capable = False
        self.mutter_capable = False

        if self.find_on_path('compiz'):
            if not self.software_rasterizer and self.texture_from_pixmap:
                 self.compiz_capable = True

        if self.find_on_path('compton'):
            self.compton_capable = True

        if self.find_on_path('marco'):
            self.marco_capable = True

        if self.find_on_path('metacity'):
            self.metacity_capable = True

        # Not stable under MATE
        #if self.find_on_path('muffin'):
        #    if not self.software_rasterizer and self.texture_from_pixmap:
        #        self.muffin_capable = True

        if self.find_on_path('mutter'):
            if not self.software_rasterizer and self.texture_from_pixmap:
                self.mutter_capable = True

    def update_cursor_theme(self, theme):
        home_dir = GLib.get_home_dir()
        self.mkdir_p(os.path.join(home_dir, '.icons', 'default'))
        config = ConfigObj()
        config.filename = os.path.join(home_dir, '.icons', 'default', 'index.theme')
        config['icon theme'] = {}
        config['icon theme']['Inherits'] = theme
        config.write()

    def replace_windowmanager(self, new_wm, notify):
        # Make sure Compiz, Metacity and Mutter use the same theme as
        # Marco to prevent theme/xcursor changes when switching themes.
        if new_wm == 'compiz' or new_wm == 'metacity' or new_wm == 'mutter':
            mate_theme = self.get_string('org.mate.interface', None, 'gtk-theme')
            mate_cursor_theme = self.get_string('org.mate.peripherals-mouse', None, 'cursor-theme')

            schemasource = Gio.SettingsSchemaSource.get_default()
            gnome_desktop_schema = schemasource.lookup('org.gnome.desktop', False)
            if gnome_desktop_schema:
                self.set_string('org.gnome.desktop.wm.preferences', None, 'theme', mate_theme)
                self.set_string('org.gnome.desktop.interface', None, 'cursor-theme', mate_cursor_theme)

            # metacity >= 3.16 - this schema may not be installed
            metacity_schema = schemasource.lookup('org.gnome.metacity', False)
            if metacity_schema:
                self.set_string('org.gnome.metacity', None, 'theme', mate_theme)

            self.update_cursor_theme(mate_cursor_theme)

        if new_wm == 'compiz':
            subprocess.Popen([new_wm, '--replace', 'ccp'], stdout=DEVNULL, stderr=DEVNULL)
        else:
            subprocess.Popen([new_wm, '--replace'], stdout=DEVNULL, stderr=DEVNULL)

        # Sometimes the outgoing window manager is left running and
        # replace mate-panel to avoid strut issues.
        subprocess.call(['killall', self.current_wm], stdout=DEVNULL, stderr=DEVNULL)
        subprocess.Popen(['mate-panel', '--replace'], stdout=DEVNULL, stderr=DEVNULL)

        # Update current_wm to the new one.
        self.current_wm = new_wm

        if notify:
            Notify.init(_('Window Manager Replaced'))
            replace_windowmanager_notify=Notify.Notification.new (_('Window Manager Replaced'),_('Your window manager has been replaced with ' + new_wm),'dialog-information')
            replace_windowmanager_notify.show()

    def run_dock(self):
        subprocess.Popen([self.dock], stdout=DEVNULL, stderr=DEVNULL)

    def kill_dock(self):
        subprocess.call(['killall', self.dock], stdout=DEVNULL, stderr=DEVNULL)

    def enable_dock(self):
        config_dir = GLib.get_user_config_dir()
        self.mkdir_p(os.path.join(config_dir, 'autostart/'))
        shutil.copy2(os.path.join('/','usr','share','applications', self.dock + '.desktop'), os.path.join(config_dir, 'autostart/'))

        # Docks require compositing
        if self.current_wm == 'marco':
            schema = 'org.mate.Marco.general'
        elif self.current_wm == 'metacity':
            schema = 'org.gnome.metacity'
        else:
            schema = None

        if schema is not None:
            self.set_bool(schema, None, 'compositing-manager', True)
            subprocess.Popen([self.current_wm, '--replace'], stdout=DEVNULL, stderr=DEVNULL)

        # Launch the dock, if it is not already enabled.
        if not self.dock_enabled:
            self.run_dock()
            self.dock_enabled = True

    def disable_dock(self):
        config_dir = GLib.get_user_config_dir()
        if os.path.exists(os.path.join(config_dir, 'autostart/') + self.dock + '.desktop'):
            os.remove(os.path.join(config_dir, 'autostart/') + self.dock + '.desktop')
        self.kill_dock()
        self.dock_enabled = False

    def enable_mate_volume_applet(self):
        subprocess.Popen(['mate-volume-control-applet'], stdout=DEVNULL, stderr=DEVNULL)

        # If the system autostart is missing create a user autostart.
        if not os.path.exists('/etc/xdg/autostart/mate-volume-control-applet.desktop'):
            config_dir = GLib.get_user_config_dir()
            self.mkdir_p(os.path.join(config_dir, 'autostart/'))
            shutil.copy2('/usr/share/mate-tweak/mate-volume-control-applet.desktop', os.path.join(config_dir, 'autostart/'))

    def disable_mate_volume_applet(self):
        subprocess.call(['killall', 'mate-volume-control-applet'], stdout=DEVNULL, stderr=DEVNULL)

        # If a system or user autostart exists, remove it.
        config_dir = GLib.get_user_config_dir()
        if os.path.exists(os.path.join(config_dir, 'autostart/') + 'mate-volume-control-applet.desktop'):
            os.remove(os.path.join(config_dir, 'autostart/') + 'mate-volume-control-applet.desktop')
        if os.path.exists('/etc/xdg/autostart/mate-volume-control-applet.desktop'):
            subprocess.call(['pkexec', '/usr/lib/mate-tweak/disable-mate-volume-applet'], stdout=DEVNULL, stderr=DEVNULL)

    def panel_layout_uses_indicators(self, panel_layout):
        with open(os.path.join('/','usr','share','mate-panel','layouts', panel_layout + '.layout'), 'rb', 0) as file, \
            mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_READ) as s:
            if s.find(b'IndicatorApplet') != -1:
                return True
        return False

    def update_panel_layout_features(self, panel_layout):
        # If the selected panel layout has MATE Menu and Indicators then
        # make those options visible.
        if self.panel_layout_exists(panel_layout + '-fresh') and \
           self.panel_layout_exists(panel_layout + '-indicators') and \
           self.panel_layout_exists(panel_layout + '-indicators-fresh'):
            self.builder.get_object('frame_panel_features').props.sensitive = True
        else:
            self.builder.get_object('frame_panel_features').props.sensitive = False

    def replace_panel_layout(self, panel_layout):
        self.update_panel_layout_features(panel_layout)

        new_layout = panel_layout
        if self.builder.get_object('checkbutton_indicators').get_active() and \
           self.builder.get_object('checkbutton_advanced_menu').get_active():
            new_layout += '-indicators-fresh'
        elif self.builder.get_object('checkbutton_indicators').get_active():
            new_layout += '-indicators'
        elif self.builder.get_object('checkbutton_advanced_menu').get_active():
            new_layout += '-fresh'

        if not self.panel_layout_exists(new_layout):
            new_layout = panel_layout

        print('Switching to: ' + new_layout)

        subprocess.call(['killall', 'mate-panel'], stdout=DEVNULL, stderr=DEVNULL)
        subprocess.call(['dconf', 'reset', '-f', '/org/mate/panel/objects/'], stdout=DEVNULL, stderr=DEVNULL)
        subprocess.call(['dconf', 'reset', '-f', '/org/mate/panel/toplevels/'], stdout=DEVNULL, stderr=DEVNULL)
        # If we have a custom panel layout just replace the dconf dump.
        if os.path.exists(os.path.join('/','usr','share','mate-panel','layouts', new_layout + '.panel')):
            print('Loading additional panel configuration for ' + panel_layout)
            cmd = 'dconf load /org/mate/panel/ < /usr/share/mate-panel/layouts/' + new_layout + '.panel'
            os.system(cmd)
        else:
            subprocess.call(['mate-panel', '--layout', new_layout, '--reset'], stdout=DEVNULL, stderr=DEVNULL)

        subprocess.Popen(['mate-panel', '--replace'], stdout=DEVNULL, stderr=DEVNULL)

        # Indicator enabled layouts auto-load the sound-indicator.
        # Therefore, make sure mate-volume-control-applet is killed or
        # started accordingly.
        if self.panel_layout_uses_indicators(new_layout):
            self.disable_mate_volume_applet()
        else:
            self.enable_mate_volume_applet()

        thumbnail_schema_id = "org.compiz.thumbnail"
        thumbnail_profile_path = '/org/compiz/profiles/mate/plugins/thumbnail/'

        # Determine if the dock should be enabled
        if new_layout.startswith('eleven') and self.dock is not None:
            if 'compiz' in self.current_wm:
                # https://bugs.launchpad.net/ubuntu-mate/+bug/1437611
                self.set_bool(thumbnail_schema_id, thumbnail_profile_path, 'current-viewport', False)
            self.enable_dock()
        elif new_layout.find('-tweak') != -1 and self.dock_enabled:
            if 'compiz' in self.current_wm:
                # https://bugs.launchpad.net/ubuntu-mate/+bug/1437611
                self.set_bool(thumbnail_schema_id, thumbnail_profile_path, 'current-viewport', False)
        elif not new_layout.startswith('eleven'):
            if 'compiz' in self.current_wm:
                # https://bugs.launchpad.net/ubuntu-mate/+bug/1437611
                self.set_bool(thumbnail_schema_id, thumbnail_profile_path, 'current-viewport', True)
            self.disable_dock()

    def get_panel_layout(self):
        self.current_layout = self.get_string('org.mate.panel', None, 'default-layout')
        self.base_layout = self.current_layout.replace('-indicators','').replace('-fresh','')

    def init_panel_features(self):
        self.get_panel_layout()
        print('Base layout: ' + self.base_layout)
        print ('Current layout: ' + self.current_layout)

        if 'indicators' in self.current_layout:
            self.builder.get_object('checkbutton_indicators').set_active(True)
        else:
            self.builder.get_object('checkbutton_indicators').set_active(False)

        if 'fresh' in self.current_layout:
            self.builder.get_object('checkbutton_advanced_menu').set_active(True)
        else:
            self.builder.get_object('checkbutton_advanced_menu').set_active(False)

        self.update_panel_layout_features(self.base_layout)

        source = Gio.SettingsSchemaSource.get_default()
        if source.lookup('org.mate.panel', True) != None:
            widget = self.builder.get_object('combobox_panels')
            index = 0
            for row in widget.get_model():
                if(self.base_layout == row[1]):
                    widget.set_active(index)
                    break
                index = index +1
            widget.connect("changed", self.combo_fallback, 'org.mate.panel', 'default-layout')

    def toggle_panel_features(self, widget):
        self.get_panel_layout()
        self.replace_panel_layout(self.base_layout)

    def panel_layout_exists(self, panel_layout):
        return os.path.exists('/usr/share/mate-panel/layouts/' + panel_layout + '.layout')

    def check_glx_features(self):
        if self.find_on_path('glxinfo'):
            process = subprocess.Popen(['glxinfo'], stdout=PIPE)
            out = process.communicate()[0].decode("UTF-8")
            if out.count("Software Rasterizer") == 0:
                self.software_rasterizer = False
            else:
                self.software_rasterizer = True

            if out.count("texture_from_pixmap") > 2:
                self.texture_from_pixmap = True
            else:
                self.texture_from_pixmap = False
        else:
            self.software_rasterizer = False
            self.texture_from_pixmap = False

    def additional_tweaks(self, schema, key, value):
        if schema == "org.mate.Marco.general" and key == "button-layout":
            # If the button-layout is changed in MATE reflect that change
            # for GTK3 and GNOME.
            self.set_string("org.mate.interface", None, "gtk-decoration-layout", value)
            self.set_string("org.gnome.desktop.wm.preferences", None, "button-layout", value)
        elif schema == "org.mate.session.required-components" and key == "windowmanager":
            wm = value

            # If the window manager is being changed, replace it now!
            self.replace_windowmanager(wm, True)

            # Update the widget based on the selected window manager.
            if wm == 'marco' or  wm == 'metacity':
                self.builder.get_object('frame_performance').props.sensitive = True
                self.builder.get_object('frame_behaviour').props.sensitive = True
                if wm == 'marco':
                    self.init_checkbox('org.mate.Marco.general', 'reduced-resources', 'checkbox_resources')
                    self.init_checkbox('org.mate.Marco.general', 'compositing-manager', 'checkbox_compositing')
                    self.init_checkbox('org.mate.Marco.general', 'side-by-side-tiling', 'checkbox_snapping')
                elif wm == 'metacity':
                    self.init_checkbox('org.gnome.metacity', 'reduced-resources', 'checkbox_resources')
                    self.init_checkbox('org.gnome.metacity', 'compositing-manager', 'checkbox_compositing')
                    self.init_checkbox('org.gnome.metacity', 'edge-tiling', 'checkbox_snapping')
            elif wm == 'mutter':
                self.builder.get_object('frame_performance').props.sensitive = False
                self.builder.get_object('frame_behaviour').props.sensitive = True
                self.init_checkbox('org.gnome.mutter', 'edge-tiling', 'checkbox_snapping')
            else:
                self.builder.get_object('frame_performance').props.sensitive = False
                self.builder.get_object('frame_behaviour').props.sensitive = False

            if wm == 'compiz':
               self.builder.get_object('button_compiz_reset').show()
            else:
               self.builder.get_object('button_compiz_reset').hide()

        elif schema == "org.mate.panel" and key == "default-layout":
            # If the panel layout is being changed, replace it now!
            panel_layout = value
            self.replace_panel_layout(panel_layout)

    def combo_fallback(self, widget, schema, key):
        act = widget.get_active()
        value = widget.get_model()[act]
        self.set_string(schema, None, key, value[1])

        # Process any additional changes required for the schema and key
        self.additional_tweaks(schema, key, value[1])

    # Change pages
    def side_view_nav(self, param):
        treePaths = param.get_selected_items()
        if (len(treePaths) > 0):
            treePath = treePaths[0]
            index = int("%s" % treePath) #Hack to turn treePath into an int
            target = self.sidePages[index].notebook_index
            self.builder.get_object("notebook1").set_current_page(target)

    def check_dock_features(self):
        config_dir = GLib.get_user_config_dir()

        # Order matters. Plank is preferred.
        if self.find_on_path('plank') and \
            os.path.exists(os.path.join('/','usr','share','applications', 'plank.desktop')):
            self.dock = 'plank'
        elif self.find_on_path('docky') and \
            os.path.exists(os.path.join('/','usr','share','applications', 'docky.desktop')):
            self.dock = 'docky'
        else:
            self.dock = None

        if self.dock is not None and os.path.exists(os.path.join(config_dir, 'autostart', self.dock + '.desktop')):
            self.dock_enabled = True
        else:
            self.dock_enabled = False

    def check_panel_features(self):
        # Determine what panel features are available
        self.gnome_menu_available = False
        self.indicators_available = False
        self.mageia_cc_available = False
        self.mate_menu_available = False
        self.maximus_available = False
        self.mint_menu_available = False
        self.volume_applet_enabled = False

        if os.path.exists('/usr/lib/gnome-main-menu/main-menu'):
            self.gnome_menu_available = True

        if os.path.exists('/usr/lib/indicators/7/libapplication.so') and \
           os.path.exists('/usr/lib/indicator-sound-gtk2/indicator-sound-service') and \
           os.path.exists('/usr/share/mate-panel/applets/org.ayatana.panel.IndicatorApplet.mate-panel-applet'):
            self.indicators_available = True

        if os.path.exists('/usr/share/applications/mageia-drakconf.desktop'):
            self.mageia_cc_available = True

        if os.path.exists('/usr/lib/mate-menu/mate-menu.py'):
            self.mate_menu_available = True

        if os.path.exists('/usr/bin/mate-maximus') and \
           os.path.exists('/usr/lib/mate-netbook/mate-window-picker-applet'):
            self.maximus_available = True

        if os.path.exists('usr/lib/linuxmint/mintMenu/mintMenu.py'):
            self.mint_menu_available = True

        config_dir = GLib.get_user_config_dir()
        if os.path.exists('/etc/xdg/autostart/mate-volume-control-applet.desktop') or \
           os.path.exists(os.path.join(config_dir, 'autostart/') + 'mate-volume-control-applet.desktop'):
            self.volume_applet_enabled = True


    def make_list_of_panel_layouts(self):
        if self.indicators_available or self.mate_menu_available:
            self.builder.get_object('frame_panel_features').props.sensitive = True
            if not self.indicators_available:
                self.builder.get_object('checkbutton_indicators').props.sensitive = False
            else:
                self.builder.get_object('checkbutton_indicators').props.sensitive = True
            if not self.mate_menu_available:
                self.builder.get_object('checkbutton_advanced_menu').props.sensitive = False
            else:
                self.builder.get_object('checkbutton_advanced_menu').props.sensitive = True
        else:
            self.builder.get_object('frame_panel_features').props.sensitive = False

        # Panel layouts
        panels = Gtk.ListStore(str, str)

        # Add any saved panel layouts first.
        layouts = os.path.join('/','usr','share','mate-panel','layouts','*-tweak.layout')
        for layout in glob.glob(layouts):
            current_layout = layout.replace('.layout', '').replace('/usr/share/mate-panel/layouts/', '');
            panels.append([_('Custom: ') + current_layout, current_layout])

        if self.dock is not None:
            if self.panel_layout_exists('eleven'):
                panels.append([_("Cupertino"), "eleven"])

        if self.panel_layout_exists('fedora'):
            panels.append([_("Fedora"), "fedora"])

        if self.panel_layout_exists('default'):
            panels.append([_("GNOME2"), "default"])

        if self.panel_layout_exists('linuxmint') and self.mint_menu_available:
            panels.append([_("Linux Mint"), "linuxmint"])

        if self.panel_layout_exists('mageia') and self.mageia_cc_available:
            panels.append([_("Mageia"), "mageia"])

        if self.panel_layout_exists('netbook') and self.maximus_available:
            panels.append([_("Netbook"), "netbook"])

        if self.panel_layout_exists('opensuse') and self.gnome_menu_available:
            panels.append([_("openSUSE"), "opensuse"])

        if self.panel_layout_exists('redmond'):
            panels.append([_("Redmond"), "redmond"])

        if self.panel_layout_exists('ubuntu-mate'):
            panels.append([_("Ubuntu MATE"), "ubuntu-mate"])

        self.builder.get_object("combobox_panels").set_model(panels)

    def save_panels(self, widget):
        layoutname = getpass.getuser()
        subprocess.call(['/usr/lib/mate-tweak/mate-panel-backup', layoutname], stdout=DEVNULL, stderr=DEVNULL)
        subprocess.call(['pkexec', '/usr/lib/mate-tweak/install-mate-panel-layout', layoutname], stdout=DEVNULL, stderr=DEVNULL)
        Notify.init(_('Panel Layout Saved'))
        save_panels_notify=Notify.Notification.new (_('Panel Layout Saved'),_('Your panel layout has been saved as /usr/share/mate-panel/layouts/' + layoutname +'-tweak.layout'),'dialog-information')
        save_panels_notify.show()
        self.set_string('org.mate.panel', None, 'default-layout', layoutname + '-tweak')
        self.make_list_of_panel_layouts()
        self.update_combobox('org.mate.panel', 'default-layout', 'combobox_panels')

    def compiz_reset(self, widget):
        # Switch to Marco. Purge all Compiz config and cache. Switch to Compiz.
        self.replace_windowmanager('marco', False)
        subprocess.call(['dconf', 'reset', '-f', '/org/compiz/'], stdout=DEVNULL, stderr=DEVNULL)
        config_compiz = os.path.join(GLib.get_user_config_dir(), 'compiz-1')
        cache_compiz = os.path.join(GLib.get_user_cache_dir(), 'compizconfg1')
        if os.path.exists(config_compiz):
            shutil.rmtree(config_compiz)
        if os.path.exists(cache_compiz):
            shutil.rmtree(cache_compiz)
        self.replace_windowmanager('compiz', False)
        Notify.init(_('Compiz Reset'))
        compiz_reset_notify=Notify.Notification.new (_('Compiz Reset'),_('Your Compiz configuration has been reset to factory defaults.'),'dialog-information')
        compiz_reset_notify.show()

    ''' Create the UI '''
    def __init__(self):
        # Check for glx, panel, dock and wm features
        self.check_glx_features()
        self.check_dock_features()
        self.check_panel_features()
        self.check_wm_features()

        # Load the Glade UI file
        self.builder = Gtk.Builder()
        self.builder.add_from_file('/usr/lib/mate-tweak/mate-tweak.ui')

        self.window = self.builder.get_object( "main_window" )
        self.builder.get_object("main_window").connect("destroy", Gtk.main_quit)
        self.builder.get_object("button_save_panels").connect("clicked", self.save_panels)
        self.builder.get_object("button_compiz_reset").connect("clicked", self.compiz_reset)

        side_desktop_options = SidePage(0, _("Desktop"), "user-desktop")
        side_windows = SidePage(1, _("Windows"), "preferences-system-windows")
        side_interface = SidePage(2, _("Interface"), "preferences-desktop")
        self.sidePages = [side_desktop_options, side_windows, side_interface]

        # create the backing store for the side nav-view.
        theme = Gtk.IconTheme.get_default()
        self.store = Gtk.ListStore(str, GdkPixbuf.Pixbuf)
        for sidePage in self.sidePages:
            img = theme.load_icon(sidePage.icon, 36, 0)
            self.store.append([sidePage.name, img])

        target = self.sidePages[0].notebook_index
        self.builder.get_object("notebook1").set_current_page(target)

        # Do not show Performance or Window behaviour configuration
        # options when Marco or Metacity are not currently running.
        if not self.current_wm == "marco" and not self.current_wm == "metacity":
            self.builder.get_object('frame_performance').props.sensitive = False
            self.builder.get_object('checkbox_snapping').props.sensitive = False
        elif self.current_wm == 'mutter':
            self.builder.get_object('frame_performance').props.sensitive = False
            self.builder.get_object('checkbox_snapping').props.sensitive = True

        if not self.current_wm == "compiz":
            self.builder.get_object('button_compiz_reset').hide()

        if not self.maximus_available:
            self.builder.get_object('checkbox_undecorate').props.sensitive = False
            self.builder.get_object('checkbox_always_maximize').props.sensitive = False
        else:
            self.init_checkbox("org.mate.maximus", "undecorate", "checkbox_undecorate")
            self.init_checkbox("org.mate.maximus", "no-maximize", "checkbox_always_maximize")

        # set up the side view - navigation.
        self.builder.get_object("side_view").set_text_column(0)
        self.builder.get_object("side_view").set_pixbuf_column(1)
        self.builder.get_object("side_view").set_model(self.store)
        self.builder.get_object("side_view").select_path(Gtk.TreePath.new_first())
        self.builder.get_object("side_view").connect("selection_changed", self.side_view_nav)

        # set up larger components.
        self.builder.get_object("main_window").set_title(_("MATE Tweak"))

        # i18n
        self.builder.get_object("label_desktop_icons").set_markup("<b>" + _("Desktop icons") + "</b>")
        self.builder.get_object("label_performance").set_markup("<b>" + _("Performance") + "</b>")
        self.builder.get_object("label_behaviour").set_markup("<b>" + _("Window Behaviour") + "</b>")
        self.builder.get_object("label_appearance").set_markup("<b>" + _("Appearance") + "</b>")
        self.builder.get_object("label_icons").set_markup("<b>" + _("Icons") + "</b>")
        self.builder.get_object("label_context_menus").set_markup("<b>" + _("Context menus") + "</b>")
        self.builder.get_object("label_toolbars").set_markup("<b>" + _("Toolbars") + "</b>")
        self.builder.get_object("label_window_manager").set_markup("<b>" + _("Window manager") + "</b>")

        self.builder.get_object("caption_desktop_icons").set_markup("<small>" + _("Select the items you want to see on the desktop:") + "</small>")

        self.builder.get_object("checkbox_computer").set_label(_("Computer"))
        self.builder.get_object("checkbox_home").set_label(_("Home"))
        self.builder.get_object("checkbox_network").set_label(_("Network"))
        self.builder.get_object("checkbox_trash").set_label(_("Trash"))
        self.builder.get_object("checkbox_volumes").set_label(_("Mounted Volumes"))

        self.builder.get_object("checkbox_resources").set_label(_("Use less resources"))
        self.builder.get_object("checkbox_compositing").set_label(_("Use compositing"))

        self.builder.get_object("checkbox_undecorate").set_label(_("Undecorate maximized windows"))
        self.builder.get_object("checkbox_always_maximize").set_label(_("Do not auto-maximize new windows"))

        self.builder.get_object("label_window_control").set_markup("<small>" + _("Window control placement.") + "</small>")

        self.builder.get_object("checkbutton_menuicon").set_label(_("Show icons on menus"))
        self.builder.get_object("checkbutton_button_icons").set_label(_("Show icons on buttons"))
        self.builder.get_object("checkbutton_im_menu").set_label(_("Show Input Methods menu in context menus"))
        self.builder.get_object("checkbutton_unicode").set_label(_("Show Unicode Control Character menu in context menus"))

        self.builder.get_object("label_toolbar_style").set_text(_("Style:"))
        self.builder.get_object("label_toolbar_icon_size").set_text(_("Icon size:"))

        # Desktop page
        self.init_checkbox("org.mate.caja.desktop", "computer-icon-visible", "checkbox_computer")
        self.init_checkbox("org.mate.caja.desktop", "home-icon-visible", "checkbox_home")
        self.init_checkbox("org.mate.caja.desktop", "network-icon-visible", "checkbox_network")
        self.init_checkbox("org.mate.caja.desktop", "trash-icon-visible", "checkbox_trash")
        self.init_checkbox("org.mate.caja.desktop", "volumes-visible", "checkbox_volumes")

        # Window Manager page
        if self.current_wm == "marco":
            self.init_checkbox('org.mate.Marco.general', 'reduced-resources', 'checkbox_resources')
            self.init_checkbox('org.mate.Marco.general', 'compositing-manager', 'checkbox_compositing')
            self.init_checkbox('org.mate.Marco.general', 'side-by-side-tiling', 'checkbox_snapping')
        elif self.current_wm == "metacity":
            self.init_checkbox('org.gnome.metacity', 'reduced-resources', 'checkbox_resources')
            self.init_checkbox('org.gnome.metacity', 'compositing-manager', 'checkbox_compositing')
            self.init_checkbox('org.gnome.metacity', 'edge-tiling', 'checkbox_snapping')
        elif self.current_wm == "mutter":
            self.init_checkbox('org.gnome.mutter', 'edge-tiling', 'checkbox_snapping')

        # interface page
        self.init_checkbox("org.mate.interface", "menus-have-icons", "checkbutton_menuicon")
        self.init_checkbox("org.mate.interface", "show-input-method-menu","checkbutton_im_menu")
        self.init_checkbox("org.mate.interface", "show-unicode-menu", "checkbutton_unicode")
        self.init_checkbox("org.mate.interface", "buttons-have-icons", "checkbutton_button_icons")

        iconSizes = Gtk.ListStore(str, str)
        iconSizes.append([_("Small"), "small-toolbar"])
        iconSizes.append([_("Large"), "large-toolbar"])
        self.builder.get_object("combobox_toolbar_icon_size").set_model(iconSizes)
        self.init_combobox("org.mate.interface", "toolbar-icons-size", "combobox_toolbar_icon_size")

        # Window control button
        layouts = Gtk.ListStore(str, str)
        layouts.append([_("Traditional (Right)"), "menu:minimize,maximize,close"])
        layouts.append([_("Contemporary (Left)"), "close,minimize,maximize:"])
        self.builder.get_object("combobox_window_control").set_model(layouts)
        self.init_combobox("org.mate.Marco.general", "button-layout", "combobox_window_control")

        # Window manager
        wms = Gtk.ListStore(str, str)

        if self.marco_capable:
            wms.append([_("Marco (Simple desktop effects)"), 'marco'])
        if self.metacity_capable:
            wms.append([_("Metacity (Simple desktop effects)"), 'metacity'])
        if self.muffin_capable:
            wms.append([_("Muffin (Elegant GPU accelerated desktop effects)"), 'muffin'])
        if self.mutter_capable:
            wms.append([_("Mutter (Elegant GPU accelerated desktop effects)"), 'mutter'])
        if self.compiz_capable:
            wms.append([_("Compiz (Advanced GPU accelerated desktop effects)"), 'compiz'])

        self.builder.get_object("combobox_window_manager").set_model(wms)
        self.builder.get_object("combobox_window_manager").set_tooltip_text(_("The new window manager will be activated upon selection."))
        self.builder.get_object("caption_window_manager").set_markup("<small>" + _("Select a window manager.") + "</small>")
        self.init_combobox("org.mate.session.required-components", "windowmanager", "combobox_window_manager")

        # Panel layouts
        self.make_list_of_panel_layouts()
        self.builder.get_object("caption_panels").set_markup("<small>" + _("Select a panel layout to change the user interface.") + "</small>")
        self.builder.get_object("combobox_panels").set_tooltip_text(_("The new panel layout will be activated on selection and destroy any customisations you might have made."))
        self.init_panel_features()
        self.builder.get_object("checkbutton_indicators").connect("toggled", self.toggle_panel_features)
        self.builder.get_object("checkbutton_advanced_menu").connect("toggled", self.toggle_panel_features)

        # toolbar icon styles
        iconStyles = Gtk.ListStore(str, str)
        iconStyles.append([_("Text below items"), "both"])
        iconStyles.append([_("Text beside items"), "both-horiz"])
        iconStyles.append([_("Icons only"), "icons"])
        iconStyles.append([_("Text only"), "text"])
        self.builder.get_object("combobox_toolbar_style").set_model(iconStyles)
        self.init_combobox("org.mate.interface", "toolbar-style", "combobox_toolbar_style")
        self.builder.get_object("main_window").show()

if __name__ == "__main__":
    set_proc_title()
    MateTweak()
    Gtk.main()
