#!/usr/bin/env python

# This file is part of Window-Switch.
# Copyright (c) 2009-2013 Antoine Martin <antoine@nagafix.co.uk>
# Window-Switch is released under the terms of the GNU GPL v3

from winswitch.util.simple_logger import Logger

logger = Logger("config_applet")
debug_import = logger.get_debug_import()


debug_import("sys/os..")
import os
debug_import("gobject/gtk..")
import pygtk
pygtk.require("2.0")
import gtk
import gobject

debug_import("consts")
from winswitch.consts import APPLICATION_NAME, AVATAR_ICON_SIZE, SPEEDS, SPEED_NAMES, DEFAULT_INTERNET_SPEED, DEFAULT_LAN_SPEED, MINIMUM_LAN_SPEED, MENU_SIZES, \
		XPRA_TYPE, NX_TYPE, SCREEN_TYPE, SSH_TYPE, VNC_TYPE, WINDOWS_TYPE, VIRTUALBOX_TYPE, GSTVIDEO_TYPE, TYPE_NAMES, \
		PROTOCOLS_DOC_URL, OPEN_LOCALLY, OPEN_NEW_SESSION, OPEN_EXISTING_SESSION
debug_import("globals")
from winswitch.globals import WIN32, OSX
debug_import("commands_util")
from winswitch.util.commands_util import KEYGEN_COMMAND
debug_import("distro_util")
from winswitch.util.distro_packaging_util import get_distro_helper
debug_import("simple_logger")
from winswitch.util.simple_logger import set_loggers_debug
debug_import("icon_util")
from winswitch.util.icon_util import get_icon_from_data, get_data_from_icon
debug_import("common")
from winswitch.util.common import load_binary_file
debug_import("config_common")
from winswitch.ui.config_common import table_init, check_number, add_tableline, add_table_sep, keyfile_entry, file_select, set_file_select_change_cb, set_filename, get_filename, TabbedConfigureWindow
debug_import("modifierkey_common")
from winswitch.ui.modifierkey_common import MODIFIER_KEY_TO_GDKMASK
debug_import("config_servers")
from winswitch.ui.config_servers import get_selected_server, create_treeview, populate_view, clear_treeview
debug_import("global_settings")
from winswitch.objects.global_settings import WRAPPER_MODIFIER_OPTIONS, TRAY_ICON_NAMES
debug_import("session")
from winswitch.objects.session import do_get_available_session_types
debug_import("server_config")
from winswitch.objects.server_config import ServerConfig
debug_import("objects.common")
from winswitch.objects.common import ALLOW_PRINTER_SHARING, ALLOW_FILE_SHARING
debug_import("tz_util")
from winswitch.util.tz_util import get_tz_util
debug_import("edit_server_config")
from winswitch.ui.config_server import edit_server_config
debug_import("quick_connect")
from winswitch.ui.quick_connect import show_quick_connect
debug_import("icons")
from winswitch.ui import icons
debug_import("startmenu/config")
from winswitch.util import startmenu, config
debug_import("ssh_key_util")
from winswitch.util.ssh_key_util import generate_new_key
debug_import("sound_util")
from winswitch.util.gstreamer_util import get_default_gst_sound_sink_module_options, get_default_gst_sound_source_module_options, get_default_gst_sound_clone_module_options, AUDIO_CODECS
debug_import("all done!")


class ConfigureAppletWindow(TabbedConfigureWindow):

	def __init__(self, applet):
		TabbedConfigureWindow.__init__(self, "Configure "+APPLICATION_NAME)
		self.applet = applet
		self.settings.avatar_changed = False
		self.new_avatar = None
		self.default_avatars = []
		for name in ["user", "group", "linux", "windows", "bsd_icon", "osx", "openbsd",
					"unknown",
					"fat_penguin", "baby_penguin",
					"cheguevara_icon",
					"bender", "laptop", "server", "workstation"]:
			self.default_avatars.append(icons.get(name))
		self.current_default = -1
		self.session_types = None
		self.desktop_types = None
		self.create()

	def show(self):
		TabbedConfigureWindow.show(self)
		def clear_view(*args):
			clear_treeview(self.servers_treeview)
		self.window.connect("destroy-event", clear_view)

	def add_file_select(self, table, name, patterns, any_file=True, x_factor=1):
		return	add_tableline(self, table, "%s Tool" % name, file_select(name, patterns, any_file), "Location of the %s tool binary program" % name, x_factor=x_factor)

	def make_protocol_icon_label_box(self, session_type):
		label_box = gtk.HBox(False, 12)
		enable_label = self.ui_util.make_label(TYPE_NAMES.get(session_type))
		proto_image = gtk.Image()
		proto_image.set_from_pixbuf(self.ui_util.scale_icon(icons.get(session_type), 16))
		label_box.pack_start(proto_image)
		label_box.pack_start(enable_label)
		return label_box

	def add_protocol_file_select(self, table, session_type, name, patterns, any_file=True, tool_name=None, x_offset=0, x_factor=1, row_inc=True):
		dh = get_distro_helper()
		install_command = dh.get_install_action(session_type)
		pagename = session_type
		if (session_type==WINDOWS_TYPE):
			pagename = "rdp"
		help_url = self.protocol_help_url(pagename)
		if tool_name is None:
			tool_name = "%s Tool" % name
		enable_button = gtk.CheckButton()
		enable_button.connect("toggled", lambda button : self.file_enabled_changed(file_entry, button))
		file_entry = file_select(name, patterns, any_file)
		file_entry.set_tooltip_text("Location of the %s executable program" % tool_name)
		box = gtk.HBox(False, 12)
		box.pack_start(enable_button)
		box.pack_start(file_entry)
		dh_button = None
		def file_input_changed(*args):
			filename = get_filename(file_entry)
			exists = (filename is not None) and os.path.exists(filename)
			self.sdebug("dh_button=%s, filename=%s, exists=%s" % (dh_button, filename, exists), *args)
			enable_button.set_sensitive(exists)
			enable_button.set_active(exists)
			if dh_button:
				dh_button.set_sensitive(not exists)
			self.touch()
		if install_command:
			def dh_locate(*args):
				""" re-try to locate the command """
				located = dh.find_command(session_type)
				self.sdebug("located(%s)=%s" % (name, located))
				if located:
					set_filename(file_entry, located)
					file_input_changed()
			def dh_install(*args):
				""" call the install command, then try dh_locate again """
				self.sdebug("install_command=%s" % install_command)
				install_command(dh_locate)
			def dh_setup(*args):
				located = dh.find_command(session_type)
				if located:
					def ok_new_location():
						set_filename(file_entry, located)
					self.dialog_util.ask("Located %s in %s" % (name, located),
										"Click OK to use this new location\n"
										"or cancel to try to install the appropriate package", dh_install, ok_new_location)
				else:
					dh_install()
			dh_button = self.ui_util.make_imagebutton(None, "download", "Locate or install %s using %s" % (name, dh.manager), dh_setup, 24)
			box.pack_start(dh_button)
		if help_url:
			box.pack_start(self.make_help_url_button("About %s" % name, help_url))
		enable_label = self.ui_util.make_label("%s Mode" % name)
		label_box = self.make_protocol_icon_label_box(session_type)
		add_tableline(self, table, label_box, box, "Enable %s mode" % name, x_offset=x_offset, entry_x_factor=3, row_inc=row_inc)
		set_file_select_change_cb(file_entry, file_input_changed)
		return	(enable_label, enable_button, file_entry)

	def protocol_help_url(self, proto):
		return "%s/%s.html" % (PROTOCOLS_DOC_URL, proto)

	def make_help_url_button(self, title, url):
		def help_clicked(*args):
			import webbrowser
			webbrowser.open_new_tab(url)
		return self.ui_util.make_imagebutton(None, "information", title, help_clicked, 16)

	def file_enabled_changed(self, entry, button):
		self.repopulate_pref_list()
		self.touch()

	def add_button_with_label(self, box, title, icon_name, tooltip=None):
		button = self.ui_util.make_imagebutton(title, icon_name, tooltip, icon_size=48)
		box.pack_start(button)
		return	button


	def create_tabs(self):
		tabs = []
		#GENERAL
		self.general_button = self.ui_util.make_imagebutton("General", "configure")
		self.general_box = self.ui_util.make_title_box("General")
		table = table_init(self, columns=4)
		(_, self.name_entry) = add_tableline(self, table, "Your Name", gtk.Entry(max=32), "As shown to other connected users", x_factor=2)
		avatar_box = gtk.HBox()
		self.avatar_entry = gtk.Button()
		self.avatar_image = gtk.Image()
		self.avatar_entry.add(self.avatar_image)
		self.avatar_entry.connect('clicked', self.select_avatar)
		avatar_box.add(self.avatar_entry)
		avatar_box.add(self.ui_util.make_imagebutton(None, "retry", None, self.next_default_avatar, 24))
		add_tableline(self, table, "Your Avatar", avatar_box, "This icon will be shown to other connected users", x_factor=2)
		add_table_sep(self, table, cols=4, preinc=1)
		if OSX:
			self.auto_start_button = None
			x_offset = 0
			x_factor = 2
		else:
			(_, self.auto_start_button) = add_tableline(self, table, "Start Applet on Login", gtk.CheckButton(),
												"Start this applet automatically when you login", row_inc=False)
			x_offset = 2
			x_factor = 1
		(_, self.start_server_button) = add_tableline(self, table, "Start Local Server", gtk.CheckButton(),
												"Start a local server if one is not present already", x_offset=x_offset, x_factor=x_factor)
		#auto-connect:
		(_, self.mdns_auto_connect_button) = add_tableline(self, table, "Connect automatically", gtk.CheckButton(),
												"Attempt to connect to newly discovered local servers automatically", row_inc=False)
		self.mdns_auto_connect_button.connect("toggled", self.auto_connect_toggled)
		match_username_box = gtk.HBox()
		self.mdns_match_username_button = gtk.CheckButton()
		self.mdns_match_username_button.connect("toggled", self.match_username_toggled)
		self.mdns_match_username_entry = gtk.Entry(max=100)
		match_username_box.add(self.mdns_match_username_button)
		match_username_box.add(self.mdns_match_username_entry)
		add_tableline(self, table, "Match Username", match_username_box,
												"Only connect automatically to servers with a matching username", x_offset=2)
		add_table_sep(self, table, cols=4, postinc=1)
		(_, self.default_server_combo) = add_tableline(self, table, "Default Server", gtk.OptionMenu(),
												"The default server to use when opening files from the file explorer", x_factor=2)
		(_, self.advanced_button) = add_tableline(self, table, "Advanced options", gtk.CheckButton(),
												"Shows more configuration options for more advanced users", row_inc=False)
		self.advanced_button.connect("toggled", self.advanced_toggled)
		(self.debug_label, self.debug_button) = add_tableline(self, table, "Debugging", gtk.CheckButton(),
												"Adds more information to the log file", x_offset=2)
		self.add_main_area(self.general_box, table)
		tabs.append((self.general_button, self.general_box))
		self.register_changes(self.name_entry,
							self.auto_start_button, self.mdns_auto_connect_button, self.start_server_button,
							self.mdns_match_username_button, self.mdns_match_username_button, self.mdns_match_username_entry,
							self.default_server_combo, self.advanced_button, self.debug_button)

		#SECURITY
		self.security_button = self.ui_util.make_imagebutton("Security", "lock")
		self.security_box = self.ui_util.make_title_box("Security")
		table = table_init(self)
		self.key_fingerprint_label = self.ui_util.make_label("", "courier 8", True)
		add_tableline(self, table, "Your Key Fingerprint", self.key_fingerprint_label, "The public fingerprint which uniquely identifies this configuration")
		(_, self.version_check_button) = add_tableline(self, table, "Check for new versions", gtk.CheckButton(), "Checks online for updated versions of this software")
		#creates: self.tunnel_printer_label, self.tunnel_printer_button, self.tunnel_fs_label, self.tunnel_fs_button, self.tunnel_sink_label, self.tunnel_sink_button, self.tunnel_source_label, self.tunnel_source_button
		self.add_tunnel_printfs_options(table)
		if WIN32:
			(self.idle_label, self.idle_timeout) = add_tableline(self, table, "Idle Sessions", gtk.CheckButton(), "Mark sessions as idle when the screensaver is activated")
		else:
			(self.idle_label, self.idle_timeout) = add_tableline(self, table, "Idle Sessions Delay (minutes)", gtk.Entry(max=5), "Mark sessions as idle after this delay of inactivity - 0 to disable")
			self.idle_timeout.set_width_chars(5)
		(_, self.open_urls_combo) = add_tableline(self, table, "Open remote URLs", gtk.combo_box_new_text(), "Action to take when a remote application attempts to open a URL")
		(_, self.open_files_combo) = add_tableline(self, table, "Open remote files", gtk.combo_box_new_text(), "Action to take when a remote application attempts to open a file")
		ssh_box = gtk.HBox(False, 10)
		self.keyfile_entry = keyfile_entry(False)
		ssh_box.pack_start(self.keyfile_entry)
		self.create_ssh_key_button = self.ui_util.make_imagebutton("Create a new SSH key", None, None, self.create_ssh_key)
		ssh_box.pack_start(self.create_ssh_key_button)
		add_tableline(self, table, "Default SSH private key", ssh_box, "Your private SSH key file for password-less authentication")
		(_, self.pub_keyfile_entry) = add_tableline(self, table, "Default SSH public key", keyfile_entry(True), "Your public SSH key file for password-less authentication")
		(_, self.internet_speed_combo) = add_tableline(self, table, "Internet Line Speed", gtk.combo_box_new_text(), "Your average connection speed to the internet")
		(self.lan_speed_label, self.lan_speed_combo) = add_tableline(self, table, "Local Network Line Speed", gtk.combo_box_new_text(), "Your average speed on you local aread network")
		self.add_main_area(self.security_box, table)
		tabs.append((self.security_button, self.security_box))
		self.register_changes(self.version_check_button,
							self.tunnel_fs_button,
							self.tunnel_printer_button,
							self.idle_timeout,
							self.open_urls_combo, self.open_files_combo,
							self.keyfile_entry)

		#SOUND
		self.sound_button = self.ui_util.make_imagebutton("Sound", "speaker_on")
		self.sound_box = self.ui_util.make_title_box("Sound Sharing")
		table = table_init(self)
		self.add_tunnel_sound_options(table, True)
		(_, self.default_gstaudio_codec_combo) = add_tableline(self, table, "Default Audio Codec", gtk.combo_box_new_text(), "The default audio codec to use for sound compression")
		self.add_main_area(self.sound_box, table)
		tabs.append((self.sound_button, self.sound_box))
		self.register_changes(self.tunnel_sink_button, self.sound_sink_combo, self.sound_sink_device_combo,
							self.tunnel_source_button, self.sound_source_combo, self.sound_source_device_combo,
							self.tunnel_clone_button, self.clone_combo, self.clone_device_combo,
							self.default_gstaudio_codec_combo)

		#USER INTERFACE
		self.ui_button = self.ui_util.make_imagebutton("User Interface", "lightbulb", "Configure the appearance of this application")
		self.ui_box = self.ui_util.make_title_box("User Interface")
		table = table_init(self, columns=4)
		(_, self.menu_size_combo) = add_tableline(self, table, "Menu Size", gtk.combo_box_new_text(), "The size of the drop down menu", row_inc=False)
		(_, self.tray_icon_combo) = add_tableline(self, table, "Tray Icon", gtk.combo_box_new_text(), "The colour to use for the tray icon", x_offset=2)
		add_table_sep(self, table, cols=4)

		def add_pair(label1, widget1, tooltip1, label2, widget2, tooltip2):
			(l1, w1) = add_tableline(self, table, label1, widget1, tooltip1, x_offset=0, row_inc=False)
			(l2, w2) = add_tableline(self, table, label2, widget2, tooltip2, x_offset=2, row_inc=True)
			return	(l1, w1, l2, w2)
		(self.menu_icons_label, self.menu_icons_button, self.button_icons_label, self.button_icons_button) = \
				add_pair("Show icons in menus", gtk.CheckButton(), "Include an icon in all menu items",
						"Show icons in buttons", gtk.CheckButton(), "Include an icon in all buttons show in forms")
		(_, self.show_deep_menus_button, _, self.notifications_button) = \
				add_pair("Use Nested Menus", gtk.CheckButton(), "Use deep nested menus rather than dialog windows",
						"System Notifications", gtk.CheckButton(), "Display notification bubbles when important events occur")
		self.show_deep_menus_button.connect("toggled", self.show_deep_menus_toggled)
		if WIN32:
			(_, self.start_menu_button) = add_tableline(self, table, "Create Start Menu folders", gtk.CheckButton(), "Creates entries in the Windows Start menu for each server connected", x_factor=2)
		else:
			self.start_menu_button = None
		add_table_sep(self, table, cols=4)
		(self.modifier_label, self.modifier_required, self.modifier_key_label, self.modifier_key_combo) = \
				add_pair("Modifier Key Required", gtk.CheckButton(), "Whether the extra options are shown or hidden by the modifier key",
						"Modifier Key", gtk.combo_box_new_text(), "Which 'magic' key will make extra options dialog appear when starting sessions")
		(self.wrapper_modifier_action_label, self.wrapper_modifier_action_combo) = \
				add_tableline(self, table, "Modified wrapper action ", gtk.combo_box_new_text(), "What action to take when the modifier key is held whilst the winswitch_command_wrapper is used", x_offset=2)
		(self.max_session_label, self.max_session_entry, self.max_user_label, self.max_user_entry) = \
				add_pair("Sessions in menu", gtk.Entry(max=2), "Create a sub-menu when there are too many sessions to show",
						"Users in menu", gtk.Entry(max=2), "Create a sub-menu when there are too many users to show")
		self.max_session_entry.set_width_chars(2)
		self.max_user_entry.set_width_chars(2)
		(self.max_command_label, self.max_command_entry, self.max_entry_length_label, self.max_entry_length_entry) = \
				add_pair("Commands in menu", gtk.Entry(max=2), "Create a sub-menu when there are too many commands to show",
						"Menu entry length", gtk.Entry(max=3), "Menu entries longer than this will be trimmed to fit")
		self.max_command_entry.set_width_chars(2)
		self.max_entry_length_entry.set_width_chars(3)
		add_table_sep(self, table, cols=4)
		(self.show_user_host_label, self.show_user_host_button, self.show_self_label, self.show_self_button) = \
				add_pair("Show user's host", gtk.CheckButton(), "Show what host each user connected from",
						"Show yourself", gtk.CheckButton(), "Show your own user in the menus and options")
		self.add_main_area(self.ui_box, table)
		tabs.append((self.ui_button, self.ui_box))
		self.register_changes(
							self.menu_icons_button,
							self.button_icons_button, self.show_deep_menus_button,
							self.notifications_button, self.start_menu_button,
							self.modifier_required, self.modifier_key_combo, self.wrapper_modifier_action_combo,
							self.menu_size_combo,
							self.tray_icon_combo,
							self.max_session_entry, self.max_user_entry, self.max_command_entry, self.max_entry_length_entry,
							self.show_user_host_button, self.show_self_button)

		#PROTOCOLS:
		self.protocols_button = self.ui_util.make_imagebutton("Protocols", "passport", "Configure which protocols are enabled")
		self.protocols_box = self.ui_util.make_title_box("Protocols")
		table = table_init(self, columns=4)
		(self.hide_suboptimal_label, self.hide_suboptimal) = add_tableline(self, table, "Hide suboptimal protocols", gtk.CheckButton(), "Hide protocols which are less suitable", x_factor=2)
		self.add_session_type_options(table, True)	#creates all 4: preferred_[desktop,session]_type_[combo,warning]
		self.hide_suboptimal.connect("toggled", self.repopulate_pref_list)
		(_, self.timezone_combo) = add_tableline(self, table, "Default Timezone", self.ui_util.text_combo(), "The timezone used when starting a session (this cannot be changed once started)", row_inc=False)
		(_, self.screen_size_combo) = add_tableline(self, table, "Default Screen Size", self.ui_util.text_combo(), "The default screen size for new desktop sessions", x_offset=2, row_inc=True)
		add_table_sep(self, table, cols=4)
		gst_box = gtk.HBox()
		self.gstvideo_enabled = gtk.CheckButton()
		gst_box.add(self.gstvideo_enabled)
		gst_box.add(self.make_help_url_button("About GStreamer", self.protocol_help_url("gstreamer")))
		gstreamer_label_box = self.make_protocol_icon_label_box(GSTVIDEO_TYPE)
		(self.gstvideo_label, _) = add_tableline(self, table, gstreamer_label_box, gst_box, row_inc=False)
		vbox_box = gtk.HBox()
		self.virtualbox_enabled = gtk.CheckButton()
		vbox_box.add(self.virtualbox_enabled)
		vbox_box.add(self.make_help_url_button("About VirtualBox", self.protocol_help_url("virtualbox")))
		virtualbox_label_box = self.make_protocol_icon_label_box(VIRTUALBOX_TYPE)
		(self.virtualbox_label, _) = add_tableline(self, table, virtualbox_label_box, vbox_box, x_offset=2)
		(_, self.xpra_enabled, self.xpra_entry) = self.add_protocol_file_select(table, XPRA_TYPE, "Xpra", ["xpra.exe", "xpra*.exe", "xpra.bat"], x_factor=2)
		(_, self.nx_enabled, self.nxproxy_entry) = self.add_protocol_file_select(table, NX_TYPE, "NX Proxy", ["nxproxy.exe", "nx*.exe"], x_factor=2)
		(_, self.vnc_enabled, self.vnc_entry) = self.add_protocol_file_select(table, VNC_TYPE, "VNC Viewer", ["vncviewer.exe", "vnc*.exe"], x_factor=2)
		(_, self.rdp_enabled, self.rdp_entry) = self.add_protocol_file_select(table, WINDOWS_TYPE, "RDP Viewer", ["mstsc.exe", "rdesktop.exe", "rdesktop*.exe"], x_factor=2)
		if WIN32:
			(self.xming_label, self.xming_entry) = self.add_file_select(table, "Xming", ["Xming.exe", "X*.exe"], x_factor=2)
		else:
			(self.xming_label, self.xming_entry) = (None, None)
		(_, self.ssh_enabled, self.ssh_command_entry) = self.add_protocol_file_select(table, SSH_TYPE, "SSH", ["Plink.exe", "TortoisePlink.exe"], x_factor=2)
		self.ssh_enabled.connect("toggled", self.repopulate_pref_list)
		if not WIN32:
			(_, self.screen_enabled, self.xterm_entry) = self.add_protocol_file_select(table, SCREEN_TYPE, "Screen", ["xterm", "xterm.exe", "xterm*.exe"], tool_name="Screen Display/Container (xterm, etc)", x_factor=2)
		else:
			self.screen_enabled, self.xterm_entry = None, None

		self.add_main_area(self.protocols_box, table)
		tabs.append((self.protocols_button, self.protocols_box))
		self.register_changes(self.hide_suboptimal,
							self.preferred_desktop_type_combo, self.preferred_session_type_combo,
							self.screen_size_combo, self.timezone_combo,
							self.gstvideo_enabled, self.virtualbox_enabled,
							self.xpra_enabled, self.xpra_entry,
							self.nx_enabled, self.nxproxy_entry,
							self.vnc_enabled, self.vnc_entry,
							self.rdp_enabled, self.rdp_entry,
							self.xming_entry,
							self.ssh_enabled, self.ssh_command_entry,
							self.screen_enabled, self.xterm_entry,
							self.internet_speed_combo, self.lan_speed_combo
							)

		#SERVERS:
		self.servers_button = self.ui_util.make_imagebutton("Servers", "servers", "The list of servers to connect to")
		self.servers_box = self.ui_util.make_title_box("Servers")
		area = gtk.VBox(False, 0)
		self.servers_scroll = gtk.ScrolledWindow()
		self.servers_scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
		self.servers_scroll.set_size_request(self.width-50, self.height-150)			#couldn't find a better way to make it use more space, even when not full
		self.servers_scroll_viewport = gtk.Viewport()
		self.servers_scroll.add(self.servers_scroll_viewport)
		self.servers_treeview = create_treeview(self.applet.servers, self.edit_server_clicked, self.delete_server_clicked)
		self.servers_scroll_viewport.add(self.servers_treeview)
		area.add(self.servers_scroll)
		create_server_buttons = gtk.HBox()
		self.new_server_button = self.ui_util.make_imagebutton("New Server", "plus", None, self.create_server_clicked)
		create_server_buttons.pack_start(self.new_server_button)
		self.quick_connect_button = self.ui_util.make_imagebutton("Quick Setup", "connect", None, self.quick_connect_clicked)
		create_server_buttons.pack_start(self.quick_connect_button)
		area.add(create_server_buttons)
		self.add_main_area(self.servers_box, area)
		self.servers_box.show_all()
		tabs.append((self.servers_button, self.servers_box))
		return	tabs

	def advanced_toggled(self, *args):
		advanced = self.advanced_button.get_active()
		ADVANCED_OPTIONS = [self.debug_label, self.debug_button,
						self.menu_icons_label, self.menu_icons_button,
						self.button_icons_label, self.button_icons_button,
						self.idle_label, self.idle_timeout,
						self.mdns_match_username_entry,
						self.max_session_label, self.max_session_entry,
						self.max_user_label, self.max_user_entry,
						self.max_command_label, self.max_command_entry,
						self.max_entry_length_label, self.max_entry_length_entry,
						self.show_self_label, self.show_self_button,
						self.xpra_entry,
						self.nxproxy_entry,
						self.vnc_entry,
						self.rdp_entry,
						self.ssh_command_entry,
						self.xterm_entry,
						self.xming_label, self.xming_entry,
						self.lan_speed_label, self.lan_speed_combo]

		for widget in ADVANCED_OPTIONS:
			if not widget:
				continue
			if advanced:
				widget.show()
			else:
				widget.hide()
		self.calculate_tabs_size()

	def auto_connect_toggled(self, *args):
		self.mdns_match_username_button.set_sensitive(self.mdns_auto_connect_button.get_active())
		self.match_username_toggled(*args)

	def match_username_toggled(self, *args):
		self.mdns_match_username_entry.set_sensitive(self.mdns_match_username_button.get_active() and self.mdns_auto_connect_button.get_active())

	def show_deep_menus_toggled(self, *args):
		keymod = self.show_deep_menus_button.get_active()
		for widget in [self.modifier_label, self.modifier_required,
						self.max_user_label, self.max_user_entry,
						self.max_command_label, self.max_command_entry
						]:
			if keymod:
				widget.show()
			else:
				widget.hide()

	def get_avail_sess_types(self, desktop_only, hide_suboptimal):
		xpra_enabled = self.xpra_enabled.get_active()
		ssh_enabled = self.ssh_enabled.get_active()
		rdp_enabled = False						#disabled: when available, it is the only one available (on win32), so no need to make it a (crappy) global default
		return	do_get_available_session_types(xpra_enabled, xpra_enabled,		#this is just for global preferences (xpra may not be available as desktop-mode on some servers
											self.nx_enabled.get_active(),
											ssh_enabled, ssh_enabled,			#as above
											self.vnc_enabled.get_active(),
											False,								#no libvirt shown
											False,								#no virtualbox shown
											rdp_enabled, rdp_enabled,
											desktop_only, hide_suboptimal)

	def repopulate_pref_list(self, *args):
		if self.populate_lock:
			return
		hide_suboptimal = self.hide_suboptimal.get_active()
		#session_type
		pref = self.settings.preferred_session_type
		if self.session_types:	#session types is defined, so the combo was shown:
			active = self.preferred_session_type_combo.get_history()
			if active>=0 and active<len(self.session_types):
				pref = self.session_types[active]
		self.session_types = self.get_avail_sess_types(False, hide_suboptimal)
		#self.sdebug("preferred_session_type_combo=%s, session_types=%s, pref=%s" % (self.preferred_session_type_combo, self.session_types, pref))
		self.populate_option_line(self.preferred_session_type_combo, self.session_types, pref, self.preferred_session_type_warning, "None available!\nCheck paths and\nenable at least one protocol")
		#desktop_type
		pref = self.settings.preferred_desktop_type
		if self.desktop_types:	#desktop types is defined, so the combo was shown:
			active = self.preferred_desktop_type_combo.get_history()
			if active>=0 and active<len(self.desktop_types):
				pref = self.desktop_types[active]
		self.desktop_types = self.get_avail_sess_types(True, hide_suboptimal)
		#self.sdebug("preferred_session_type_combo=%s, session_types=%s, pref=%s" % (self.preferred_desktop_type_combo, self.desktop_types, pref))
		self.populate_option_line(self.preferred_desktop_type_combo, self.desktop_types, pref, self.preferred_desktop_type_warning, "None available!\nCheck paths and\nenable NX or VNC")

	def do_populate_form(self):
		settings = self.settings

		# Global
		self.name_entry.set_text(settings.name)
		self.populate_avatar()
		if self.auto_start_button:
			self.auto_start_button.set_active(startmenu.get_auto_start_state())
		self.start_server_button.set_active(settings.start_local_server)
		self.mdns_auto_connect_button.set_active(settings.mdns_auto_connect)
		self.mdns_match_username_button.set_active(settings.mdns_match_username)
		self.mdns_match_username_entry.set_text(settings.mdns_match_username_string)

		#default server:
		index = 0
		self.server_uuids = []
		server_menu = gtk.Menu()
		selected_index = -1
		#sessions = sorted(server.get_live_sessions(False, ignore=[]), key=lambda session: session.name.lower())
		servers = sorted(self.applet.servers, key=lambda server: server.name.lower())
		for server in servers:
			#self.debug("populate_form() adding row for %s" % server)
			icon = self.ui_util.get_server_type_icon(server.type)
			server_option = self.ui_util.menuitem(server.name, icon, None, None)
			server_menu.append(server_option)
			self.server_uuids.append(server.ID)
			if settings.default_server and settings.default_server == server.ID:
				selected_index = index
			index += 1
		server_menu.show_all()
		self.default_server_combo.set_menu(server_menu)
		if selected_index>=0:
			self.default_server_combo.set_history(selected_index)

		self.advanced_button.set_active(settings.advanced)
		self.debug_button.set_active(settings.debug_mode)

		# Security
		self.key_fingerprint_label.set_text(settings.get_key_fingerprint())
		self.version_check_button.set_active(settings.version_update_check)
		self.tunnel_fs_button.set_sensitive(ALLOW_FILE_SHARING)
		self.tunnel_fs_button.set_active(settings.tunnel_fs and ALLOW_FILE_SHARING)
		# Idle
		try:
			cancheck = self.applet.wm_util.can_check_for_idle()
			self.idle_label.set_sensitive(cancheck)
			self.idle_timeout.set_sensitive(cancheck)
			if not cancheck:
				settings.idle_timeout = 0
		except:
			pass
		if WIN32:
			self.idle_timeout.set_active(settings.idle_timeout>0)
		else:
			self.idle_timeout.set_text("%s" % settings.idle_timeout)

		self.open_urls_combo.get_model().clear()
		i = 0
		for opt in [OPEN_LOCALLY, OPEN_NEW_SESSION, OPEN_EXISTING_SESSION]:
			self.open_urls_combo.append_text(opt)
			if settings.open_urls==opt:
				self.open_urls_combo.set_active(i)
			i += 1
		i = 0
		for opt in [OPEN_NEW_SESSION, OPEN_EXISTING_SESSION]:
			self.open_files_combo.append_text(opt)
			if settings.open_files==opt:
				self.open_files_combo.set_active(i)
			i += 1

		#Sound:
		def populate_button_and_combo(button, combo, dev_label, dev_combo, active, modules, selected_module):
			button.set_active(active)
			#list of options:
			dev_shown = active
			if combo:
				item_index = 0
				for name,module in modules:
					combo.append_text(name)
					if module==selected_module or (not selected_module and item_index==0):
						combo.set_active(item_index)
					item_index += 1
				if len(modules)==0:
					button.set_tooltip_text("Cannot be enabled - No valid options found!")
					button.set_sensitive(False)
					button.set_active(False)
					dev_shown = False
					combo.set_sensitive(False)
				else:
					combo.set_sensitive(active)
					dev_shown = active and len(dev_combo.get_model())>0
			for x in [dev_label, dev_combo]:
				if x is not None:
					x.set_sensitive(dev_shown)
		populate_button_and_combo(self.tunnel_sink_button, self.sound_sink_combo, self.sound_sink_device_label, self.sound_sink_device_combo,
								settings.tunnel_sink and settings.supports_sound, get_default_gst_sound_sink_module_options(),
								settings.gst_sound_sink_module)
		populate_button_and_combo(self.tunnel_source_button, self.sound_source_combo, self.sound_source_device_label, self.sound_source_device_combo,
								settings.tunnel_source and settings.supports_sound, get_default_gst_sound_source_module_options(),
								settings.gst_sound_source_module)
		populate_button_and_combo(self.tunnel_clone_button, self.clone_combo, self.clone_device_combo, self.clone_device_combo,
								settings.tunnel_clone and settings.supports_sound, get_default_gst_sound_clone_module_options(),
								settings.gst_sound_clone_module)
		self.default_gstaudio_codec_combo.get_model().clear()
		index = 0
		for codec in AUDIO_CODECS:
			self.default_gstaudio_codec_combo.append_text(codec)
			if codec==settings.default_gstaudio_codec:
				self.default_gstaudio_codec_combo.set_active(index)

		if self.tunnel_printer_button:
			self.tunnel_printer_button.set_sensitive(ALLOW_PRINTER_SHARING)
			self.tunnel_printer_button.set_active(settings.tunnel_printer and ALLOW_PRINTER_SHARING)
		set_filename(self.keyfile_entry, settings.ssh_keyfile, True)
		set_filename(self.pub_keyfile_entry, settings.ssh_pub_keyfile, True)
		self.create_ssh_key_button.set_sensitive(os.path.exists(KEYGEN_COMMAND))
		set_filename(self.ssh_command_entry, settings.ssh_command)

		# protocols
		self.hide_suboptimal.set_active(settings.hide_suboptimal_protocols)
		set_filename(self.xming_entry, settings.xming_command)
		set_filename(self.xterm_entry, settings.xterm_command)
		can_gstvideo = settings.test_supports_gstvideo()
		self.gstvideo_enabled.set_active(settings.supports_gstvideo and can_gstvideo)
		self.virtualbox_enabled.set_active(settings.supports_virtualbox)
		self.xpra_enabled.set_active(settings.supports_xpra)
		set_filename(self.xpra_entry, settings.xpra_command)
		self.nx_enabled.set_active(settings.supports_nx)
		set_filename(self.nxproxy_entry, settings.nxproxy_command)
		self.vnc_enabled.set_active(settings.supports_vnc)
		set_filename(self.vnc_entry, settings.vnc_command)
		self.rdp_enabled.set_active(settings.supports_rdp)
		set_filename(self.rdp_entry, settings.rdesktop_command)
		for widget in [self.gstvideo_label, self.gstvideo_enabled]:
			widget.set_sensitive(can_gstvideo)
			if can_gstvideo:
				widget.set_tooltip_text("Support GStreamer Screen Streaming")
			else:
				widget.set_tooltip_text("The required GStreamer video and TCP plugins are not available")


		self.ssh_enabled.set_active(settings.supports_ssh)
		if self.screen_enabled:
			self.screen_enabled.set_active(settings.supports_screen)

		#LINESPEED
		index = 0
		lan_index = 0
		#make sure the value matches one of the values in the drop downs
		if settings.default_internet_speed not in SPEED_NAMES:
			settings.default_internet_speed = DEFAULT_INTERNET_SPEED
		if settings.default_lan_speed not in SPEED_NAMES:
			settings.default_lan_speed = DEFAULT_LAN_SPEED
		for speed in sorted(SPEED_NAMES.keys()):
			text = SPEED_NAMES[speed]
			self.internet_speed_combo.append_text(text)
			if settings.default_internet_speed == speed:
				self.internet_speed_combo.set_active(index)
			index += 1
			if speed>=MINIMUM_LAN_SPEED:
				self.lan_speed_combo.append_text(text)
				if settings.default_lan_speed == speed:
					self.lan_speed_combo.set_active(lan_index)
				lan_index += 1

		#default screen size
		self.screen_size_combo.append_text("")
		screen_index = 0
		index = 1
		for w,h in settings.get_desktop_sizes():
			size = "%s x %s" % (w,h)
			self.screen_size_combo.append_text(size)
			if settings.default_desktop_size==size:
				screen_index = index
			index += 1
		self.screen_size_combo.set_active(screen_index)

		#default timezone:
		local_tz = get_tz_util().get_local_timezone()
		if local_tz and local_tz in settings.timezone_options:
			self.timezone_combo.append_text(local_tz)
		else:
			self.timezone_combo.append_text("")
		timezone_index = 1
		index = 1
		for tz in settings.timezone_options:
			self.timezone_combo.append_text(tz)
			if settings.default_timezone==tz:
				timezone_index = index
			index += 1
		self.timezone_combo.set_active(timezone_index)

		#menu size
		index = 0
		for size in sorted(MENU_SIZES.keys()):
			text = MENU_SIZES[size]
			self.menu_size_combo.append_text(text)
			if size == settings.menu_size:
				self.menu_size_combo.set_active(index)
			index += 1
		#tray icon
		index = 0
		for name,value in TRAY_ICON_NAMES.items():
			self.tray_icon_combo.append_text(name)
			if value==settings.tray_icon_name:
				self.tray_icon_combo.set_active(index)
			index += 1
		#UI
		self.menu_icons_button.set_active(settings.icons_in_menus)
		self.button_icons_button.set_active(settings.icons_in_buttons)
		self.show_deep_menus_button.set_active(settings.show_deep_menus)
		self.notifications_button.set_active(settings.notifications)
		if self.start_menu_button:
			self.start_menu_button.set_active(settings.create_start_menu_folders)

		self.max_session_entry.set_text("%s" % settings.max_session_menu_items)
		self.max_user_entry.set_text("%s" % settings.max_user_menu_items)
		self.max_command_entry.set_text("%s" % settings.max_command_menu_items)
		self.max_entry_length_entry.set_text("%s" % settings.max_menu_entry_length)
		self.modifier_required.set_active(settings.modifier_required)
		self.modifier_key_combo.get_model().clear()
		index = 0
		for key in MODIFIER_KEY_TO_GDKMASK.keys():
			self.modifier_key_combo.append_text(key)
			if self.settings.modifier_key == key:
				self.modifier_key_combo.set_active(index)
			index += 1
		index = 0
		for key in WRAPPER_MODIFIER_OPTIONS:
			self.wrapper_modifier_action_combo.append_text(key)
			if self.settings.wrapper_modifier_action == key:
				self.wrapper_modifier_action_combo.set_active(index)
			index += 1

		self.show_self_button.set_active(settings.show_send_to_self)
		self.show_user_host_button.set_active(settings.show_user_host)
		#preferred session type (do this last as it depends on the state of the other buttons)
		self.repopulate_pref_list()

		self.populate_servers_list()
		self.advanced_toggled()
		self.show_deep_menus_toggled()
		self.untouch()
		#populate_lock will be released when this method returns, then we can call
		gobject.idle_add(self.repopulate_pref_list)

	def populate_servers_list(self):
		self.sdebug()
		#so we can try to preserve the scroll location:
		va = self.servers_scroll_viewport.get_vadjustment().value
		servers = sorted(self.applet.servers, key=lambda server: server.name.lower())
		populate_view(self.servers_treeview, servers)
		vadj = self.servers_scroll_viewport.get_vadjustment()
		vadj.set_value(max(min(va, vadj.upper), vadj.lower))

	def delete_server_clicked(self, *args):
		self.slog()
		server = get_selected_server(self.servers_treeview)
		self.sdebug("selected server=%s" % server)
		if server:
			self.applet.remove_server(server)
			self.populate_servers_list()
			self.refresh()

	def edit_server_clicked(self, *args):
		server = get_selected_server(self.servers_treeview)
		self.sdebug("selected server=%s" % server)
		self.edit_server(server)

	def schedule_servers_list_repopulate(self, *args):
		""" called from quick connect and create below, we populate later because the actual adding/removing/updating of the server details
			may happen during the same event (click) but after the callback is called! """
		self.sdebug(None, *args)
		gobject.timeout_add(0, self.populate_servers_list)

	def edit_server(self, server):
		if not server:
			return
		self.sdebug(None, server)
		edit_server_config(self.applet, server, self.schedule_servers_list_repopulate, False)

	def quick_connect_clicked(self, *args):
		self.sdebug(None, args)
		show_quick_connect(self.applet, None, self.schedule_servers_list_repopulate, "Configure New Connection")

	def create_server_clicked(self, *args):
		self.sdebug(None, *args)
		new_server = ServerConfig()
		new_server.ssh_tunnel = True		#probably needed if we add it by hand
		edit_server_config(self.applet, new_server, self.schedule_servers_list_repopulate, True)

	def populate_avatar(self):
		icon = None
		if self.new_avatar:
			icon = get_icon_from_data(self.new_avatar)
		if not icon:
			icon = self.settings.get_avatar_icon()
		if not icon:
			icon = icons.get("user")
		#scale it
		if icon.get_width()!=AVATAR_ICON_SIZE or icon.get_height()>AVATAR_ICON_SIZE:
			icon = icon.scale_simple(AVATAR_ICON_SIZE, AVATAR_ICON_SIZE, gtk.gdk.INTERP_HYPER)
		self.avatar_image.set_from_pixbuf(icon)

	def select_avatar(self, *args):
		chooser = gtk.FileChooserDialog(title="Select Avatar",
									action=gtk.FILE_CHOOSER_ACTION_SAVE,
									buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
		image_filter = gtk.FileFilter()
		image_filter.set_name("Image")
		image_filter.add_pattern("*.png")
		image_filter.add_pattern("*.jpg")
		image_filter.add_pattern("*.jpeg")
		image_filter.add_pattern("*.gif")
		chooser.add_filter(image_filter)
		response = chooser.run()
		if response == gtk.RESPONSE_OK:
			new_avatar = chooser.get_filename()
			chooser.destroy()
			data = load_binary_file(new_avatar)
			l = 0
			if data:
				l = len(data)
			self.sdebug("new avatar filename=%s, size=%d" % (new_avatar, l), args)
			if l>0:
				icon = get_icon_from_data(data)
				if icon:
					self.set_avatar_from_icon(icon)
					self.touch()
		else:
			chooser.destroy()

	def set_avatar_from_icon(self, icon):
		w = icon.get_width()
		h = icon.get_height()
		if w>AVATAR_ICON_SIZE or h>AVATAR_ICON_SIZE:
			self.sdebug("new avatar is too large (%d x %d), scaling it to %d x %d." % (w, h, AVATAR_ICON_SIZE, AVATAR_ICON_SIZE), icon)
			icon = icon.scale_simple(AVATAR_ICON_SIZE, AVATAR_ICON_SIZE, gtk.gdk.INTERP_HYPER)
		data = get_data_from_icon(icon)
		self.new_avatar = data
		self.settings.avatar_changed = True
		self.populate_avatar()

	def next_default_avatar(self, *args):
		self.current_default += 1
		icon = self.default_avatars[self.current_default % len(self.default_avatars)]
		self.set_avatar_from_icon(icon)
		self.touch()

	def create_ssh_key(self, widget):
		self.sdebug()
		existing_private = get_filename(self.keyfile_entry)
		existing_public = get_filename(self.pub_keyfile_entry)
		if (existing_private and os.path.isfile(existing_private)) or (existing_public and os.path.isfile(existing_public)):
			self.dialog_util.ask("A seemingly valid SSH key file already exists",
							"Are you sure you want to create a new key in a different location?", None, self.do_create_ssh_key,
							UUID="KEY_ALREADY_EXISTS")
		else:
			self.do_create_ssh_key()

	def do_create_ssh_key(self):
		generate_new_key(self.key_created)

	def key_created(self, priv_filename, pub_filename):
		self.slog(None, priv_filename, pub_filename)
		if self.window and self.keyfile_entry and priv_filename:
			gobject.idle_add(self.set_key_created, self.keyfile_entry, priv_filename)
			self.touch()
		if self.window and self.pub_keyfile_entry and pub_filename:
			gobject.idle_add(self.set_key_created, self.pub_keyfile_entry, pub_filename)
			self.touch()

	def set_key_created(self, widget, filename):
		widget.set_filename(filename)
		return	False

	def do_apply_changes(self):
		settings = self.settings
		# Globals
		settings.name = self.name_entry.get_text()
		if self.new_avatar:
			settings.set_avatar_icon_data(self.new_avatar)
			config.save_avatar(settings)
		# auto-start
		if self.auto_start_button:
			startmenu.set_auto_start_state(self.auto_start_button.get_active())

		# start local server
		settings.start_local_server = self.start_server_button.get_active()
		#auto connect
		settings.mdns_auto_connect = self.mdns_auto_connect_button.get_active()
		settings.mdns_match_username = self.mdns_match_username_button.get_active()
		settings.mdns_match_username_string = self.mdns_match_username_entry.get_text()
		# desktop protocol
		settings.preferred_desktop_type = self.get_selected_option(self.preferred_desktop_type_combo, self.desktop_types)
		# preferred session type
		settings.preferred_session_type = self.get_selected_option(self.preferred_session_type_combo, self.session_types)
		# default server
		active = self.default_server_combo.get_history()
		if active < 0 or active>=len(self.server_uuids):
			settings.default_server = None
		else:
			settings.default_server = self.server_uuids[active]
		settings.advanced = self.advanced_button.get_active()
		settings.debug_mode = self.debug_button.get_active()
		set_loggers_debug(settings.debug_mode)


		#SECURITY
		settings.version_update_check = self.version_check_button.get_active()
		settings.tunnel_fs = self.tunnel_fs_button.get_active()
		# Idle
		if WIN32:
			if self.idle_timeout.get_active():
				settings.idle_timeout = 1
			else:
				settings.idle_timeout = 0
		else:
			(valid, settings.idle_timeout) = check_number("Idle Timeout", self.idle_timeout.get_text(), settings.idle_timeout)
			if not valid:
				self.idle_timeout.grab_focus()
				return
		settings.open_urls = self.open_urls_combo.get_active_text()
		settings.open_files = self.open_files_combo.get_active_text()

		settings.tunnel_printer = self.tunnel_printer_button and self.tunnel_printer_button.get_active()
		settings.ssh_keyfile = get_filename(self.keyfile_entry)
		settings.ssh_pub_keyfile = get_filename(self.pub_keyfile_entry)

		#SOUND
		settings.tunnel_sink = self.tunnel_sink_button.get_active()
		settings.tunnel_source = self.tunnel_source_button.get_active()
		settings.tunnel_clone = self.tunnel_clone_button.get_active()
		def get_module_and_options(active, module_combo, device_combo, module_options, device_options):
			""" module_options is a list of gst sound modules: (name,module)
				device_options is a dict() of devices: (name,description)
			"""
			module = ""
			settings = {}
			if not active or not module_combo:
				return	(module, settings)
			""" find the module matching the name shown in the module_combo: """
			if module_combo.get_active_text():
				for _name,_module in module_options:
					if _name==module_combo.get_active_text():
						module = _module
						break
			if not module or not device_options:
				return	(module, settings)
			""" find the device matching the description shown in the device_combo: """
			dev = device_combo.get_active_text()
			for name,descr in device_options.items():
				if descr==dev:
					settings["device"] = name
			return	(module, settings)

		(settings.gst_sound_sink_module, settings.gst_sound_sink_options) = get_module_and_options(settings.tunnel_sink, self.sound_sink_combo,
									self.sound_sink_device_combo, get_default_gst_sound_sink_module_options(), self.get_sound_sink_device_options())
		(settings.gst_sound_source_module, settings.gst_sound_source_options) = get_module_and_options(settings.tunnel_source, self.sound_source_combo,
									self.sound_source_device_combo, get_default_gst_sound_source_module_options(), self.get_sound_source_device_options())
		(settings.gst_sound_clone_module, settings.gst_sound_clone_options) = get_module_and_options(settings.tunnel_clone, self.clone_combo,
									self.clone_device_combo, get_default_gst_sound_clone_module_options(), self.get_clone_device_options())
		settings.default_gstaudio_codec = self.default_gstaudio_codec_combo.get_active_text()

		#Protocols
		settings.hide_suboptimal_protocols = self.hide_suboptimal.get_active()
		settings.xpra_command = get_filename(self.xpra_entry)
		settings.nxproxy_command = get_filename(self.nxproxy_entry)
		settings.vnc_command = get_filename(self.vnc_entry)
		settings.rdesktop_command = get_filename(self.rdp_entry)
		settings.xming_command = get_filename(self.xming_entry)
		settings.ssh_command = get_filename(self.ssh_command_entry)
		settings.xterm_command = get_filename(self.xterm_entry)
		settings.supports_xpra = self.xpra_enabled.get_active()
		settings.supports_nx = self.nx_enabled.get_active()
		settings.supports_vnc = self.vnc_enabled.get_active()
		settings.supports_rdp = self.rdp_enabled.get_active()
		settings.supports_gstvideo = self.gstvideo_enabled.get_active()
		settings.supports_virtualbox = self.virtualbox_enabled.get_active()
		settings.supports_ssh = self.ssh_enabled.get_active()
		if self.screen_enabled:
			settings.supports_screen = self.screen_enabled.get_active()
		self.settings.disable_flags_for_missing_commands()
		if WIN32:
			settings.supports_ssh |= settings.xming_command and os.path.exists(settings.xming_command)
		#line speed:
		settings.default_internet_speed = SPEEDS.get(self.internet_speed_combo.get_active_text())
		settings.default_lan_speed = SPEEDS.get(self.lan_speed_combo.get_active_text())
		#screen size:
		settings.default_desktop_size = self.screen_size_combo.get_active_text()
		#timezone:
		settings.default_timezone = self.timezone_combo.get_active_text()
		#ensure a value is set (use default if something is wrong)
		if not settings.default_internet_speed:
			settings.default_internet_speed = DEFAULT_INTERNET_SPEED
		if not settings.default_lan_speed:
			settings.default_lan_speed = DEFAULT_LAN_SPEED


		settings.icons_in_menus = self.menu_icons_button.get_active()
		settings.icons_in_buttons = self.button_icons_button.get_active()
		#ensure this gets re-applied asap:
		settings.reset_workrounds()

		settings.show_deep_menus = self.show_deep_menus_button.get_active()
		settings.notifications = self.notifications_button.get_active()
		if self.start_menu_button:
			settings.create_start_menu_folders = self.start_menu_button.get_active()

		settings.menu_size = sorted(MENU_SIZES.keys())[self.menu_size_combo.get_active()]
		settings.tray_icon_name = TRAY_ICON_NAMES.get(self.tray_icon_combo.get_active_text(), "auto")
		(valid, settings.max_session_menu_items) = check_number("Session in menu", self.max_session_entry.get_text(), 5)
		if not valid:
			self.max_session_entry.grab_focus()
			return
		(valid, settings.max_user_menu_items) = check_number("Users in menu", self.max_user_entry.get_text(), 3)
		if not valid:
			self.max_user_entry.grab_focus()
			return
		(valid, settings.max_command_menu_items) = check_number("Commands in menu", self.max_command_entry.get_text(), 5)
		if not valid:
			self.max_command_entry.grab_focus()
			return
		(valid, settings.max_menu_entry_length) = check_number("Menu Entry Length", self.max_entry_length_entry.get_text(), 70, 30, 200)
		if not valid:
			self.max_entry_length_entry.grab_focus()
			return

		settings.modifier_required = self.modifier_required.get_active()
		settings.modifier_key = self.modifier_key_combo.get_active_text()
		settings.wrapper_modifier_action = self.wrapper_modifier_action_combo.get_active_text()
		settings.show_send_to_self = self.show_self_button.get_active()
		settings.show_user_host = self.show_user_host_button.get_active()
		settings.touch()
		self.applet.settings_modified()


	def do_commit_changes(self, *args):
		self.window.destroy()
		#don't delay the UI with pure I/O:
		import thread
		thread.start_new_thread(config.save_settings, (self.settings,))
