[Xfce4-commits] <eatmonkey:aria2-xml-rpc> First draft is finally in

Mike Massonnet noreply at xfce.org
Sat Jan 23 12:10:04 CET 2010


Updating branch refs/heads/aria2-xml-rpc
         to 78325d6ff76362fbf28790d7f5bdc1f56126577a (commit)
       from b22028ada2c68e6b8595bb6affd5eb3e312a8d58 (commit)

commit 78325d6ff76362fbf28790d7f5bdc1f56126577a
Author: Mike Massonnet <mmassonnet at xfce.org>
Date:   Sat Jan 23 12:06:46 2010 +0100

    First draft is finally in
    
    Written in Ruby, it depends on the ruby-gnome2 project for the GTK+
    bindings.

 po/eatmonkey.pot   |  169 +++++++++++
 src/eat.rb         |   27 ++
 src/eataria2.rb    |  617 ++++++++++++++++++++++++++++++++++++++++
 src/eatmanager.rb  |  302 ++++++++++++++++++++
 src/eatsettings.rb |  223 +++++++++++++++
 src/manager.ui     |  792 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/settings.ui    |  770 ++++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 2900 insertions(+), 0 deletions(-)

diff --git a/po/eatmonkey.pot b/po/eatmonkey.pot
new file mode 100644
index 0000000..457967a
--- /dev/null
+++ b/po/eatmonkey.pot
@@ -0,0 +1,169 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL at ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-01-23 11:01+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
+"Language-Team: LANGUAGE <LL at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../eatmonkey.desktop.in.h:1
+msgid "Download Manager"
+msgstr ""
+
+#: ../eatmonkey.desktop.in.h:2 ../src/manager.ui.h:2
+msgid "Eatmonkey"
+msgstr ""
+
+#: ../eatmonkey.desktop.in.h:3
+msgid "Stupid download manager for monkeys and Capuchins!"
+msgstr ""
+
+#: ../src/manager.ui.h:1
+msgid "E_dit"
+msgstr ""
+
+#: ../src/manager.ui.h:3
+msgid "H_elp"
+msgstr ""
+
+#: ../src/manager.ui.h:4
+msgid "New download"
+msgstr ""
+
+#: ../src/manager.ui.h:5
+msgid "Open from URI/File"
+msgstr ""
+
+#: ../src/manager.ui.h:6
+msgid "Select a file - Torrents, Metalinks"
+msgstr ""
+
+#: ../src/manager.ui.h:7
+msgid "Select from clipboard"
+msgstr ""
+
+#: ../src/manager.ui.h:8
+msgid "Select from file"
+msgstr ""
+
+#: ../src/manager.ui.h:9
+msgid "_Compact View"
+msgstr ""
+
+#: ../src/manager.ui.h:10
+msgid "_Details View"
+msgstr ""
+
+#: ../src/manager.ui.h:11
+msgid "_File"
+msgstr ""
+
+#: ../src/manager.ui.h:12
+msgid "_History"
+msgstr ""
+
+#: ../src/manager.ui.h:13
+msgid "_Log"
+msgstr ""
+
+#: ../src/manager.ui.h:14
+msgid "_View"
+msgstr ""
+
+#: ../src/settings.ui.h:1
+msgid "(0=infinite)"
+msgstr ""
+
+#: ../src/settings.ui.h:2
+msgid "Always require encryption"
+msgstr ""
+
+#: ../src/settings.ui.h:3
+msgid "Authentication"
+msgstr ""
+
+#: ../src/settings.ui.h:4
+msgid "BitTorrent"
+msgstr ""
+
+#: ../src/settings.ui.h:5
+msgid "Distributed Hash Table allows to use torrents without a working tracker"
+msgstr ""
+
+#: ../src/settings.ui.h:6
+msgid "Download Options"
+msgstr ""
+
+#: ../src/settings.ui.h:7
+msgid "Download directory:"
+msgstr ""
+
+#: ../src/settings.ui.h:8
+msgid "Enable DHT (Distributed Hash Table)"
+msgstr ""
+
+#: ../src/settings.ui.h:9
+msgid "Enable PEX (Peer Exchange)"
+msgstr ""
+
+#: ../src/settings.ui.h:10
+msgid "General"
+msgstr ""
+
+#: ../src/settings.ui.h:11
+msgid "Host:"
+msgstr ""
+
+#: ../src/settings.ui.h:12
+msgid "KiB/s"
+msgstr ""
+
+#: ../src/settings.ui.h:13
+msgid "Maximum download speed:"
+msgstr ""
+
+#: ../src/settings.ui.h:14
+msgid "Maximum number of concurrent downloads:"
+msgstr ""
+
+#: ../src/settings.ui.h:15
+msgid "Maximum number of peers:"
+msgstr ""
+
+#: ../src/settings.ui.h:16
+msgid "Maximum upload speed:"
+msgstr ""
+
+#: ../src/settings.ui.h:17
+msgid "Password:"
+msgstr ""
+
+#: ../src/settings.ui.h:18
+msgid "Peer Exchange helps finding more peers through connected peers"
+msgstr ""
+
+#: ../src/settings.ui.h:19
+msgid "Seed ratio:"
+msgstr ""
+
+#: ../src/settings.ui.h:20
+msgid "Settings"
+msgstr ""
+
+#: ../src/settings.ui.h:21
+msgid "Username:"
+msgstr ""
+
+#: ../src/settings.ui.h:22
+msgid "aria2 XML-RPC Server"
+msgstr ""
diff --git a/src/eat.rb b/src/eat.rb
new file mode 100644
index 0000000..f8bfb7a
--- /dev/null
+++ b/src/eat.rb
@@ -0,0 +1,27 @@
+#!/usr/bin/ruby -w
+
+$stderr.reopen('/dev/null', 'w')
+require "glib2"
+require "gtk2"
+$stderr=STDOUT
+
+require "eataria2"
+require "eatmanager"
+
+include Gtk
+
+if __FILE__ == $0
+	aria2 = Eat::Aria2Listener.instance
+	settings = Eat::Settings.instance
+	if settings["custom-server"]
+		aria2.use_custom_server(settings["xmlrpc-host"], settings["xmlrpc-port"], settings["xmlrpc-user"], settings["xmlrpc-passwd"])
+	end
+	aria2.connect
+	puts "Version: aria2 %s" % aria2.version
+
+	manager = Eat::Manager.new
+	manager.show
+
+	main
+end
+
diff --git a/src/eataria2.rb b/src/eataria2.rb
new file mode 100644
index 0000000..477d025
--- /dev/null
+++ b/src/eataria2.rb
@@ -0,0 +1,617 @@
+#!/usr/bin/ruby -w
+
+require "xmlrpc/client"
+require "fileutils"
+require "singleton"
+require "timeout"
+require "pp"
+
+require "glib2"
+
+def debug(*args)
+	return if false
+	pp args
+end
+
+
+
+module Eat
+end
+
+
+
+class Eat::Aria2 < GLib::Object
+
+	DEFAULT_PORT = 6801
+	DEFAULT_HOST = '127.0.0.1'
+
+	attr_accessor :user
+	attr_accessor :password
+	attr_accessor :hostname
+	attr_accessor :port
+
+	attr_reader :is_connected
+	attr_reader :version
+
+	private
+
+	type_register
+
+	signal_new("download_status", GLib::Signal::RUN_FIRST, nil,
+			nil,					# Return type: void
+			String)					# Parameters: gid
+	signal_new("download_completed", GLib::Signal::RUN_FIRST, nil,
+			nil,					# Return type: void
+			String)					# Parameters: gid
+	signal_new("download_removed", GLib::Signal::RUN_FIRST, nil,
+			nil,					# Return type: void
+			String)					# Parameters: gid
+	signal_new("download_stopped", GLib::Signal::RUN_FIRST, nil,
+			nil,					# Return type: void
+			String)					# Parameters: gid
+
+	def signal_do_download_status(gid)
+	end
+	def signal_do_download_completed(gid)
+	end
+	def signal_do_download_removed(gid)
+	end
+	def signal_do_download_stopped(gid)
+	end
+
+	def initialize(hostname = DEFAULT_HOST, port = DEFAULT_PORT, user = nil, password = nil)
+		super(nil)
+
+		@new_downloads = []
+
+		@confdir = ENV['XDG_CONFIG_HOME']
+		@confdir = ENV['HOME']+"/.config" if @confdir == nil
+		@confdir += "/eatmonkey"
+
+		@hostname, @port, @user, @password = hostname, port, user, password
+		@is_connected = false
+		@use_local_server = true
+		@version = "n/a"
+		@@client = nil if !defined? @@client
+
+		if !defined? @@pid
+			begin
+				@@pid = File.open(@confdir+"/aria2.pid").readline.strip.to_i
+				Process.kill("CONT", @@pid)
+			rescue
+				@@pid = 0
+			end
+		end
+	end
+
+=begin
+	start_server:
+	Returns negative values on error, -1 if a service is already listening
+	on the port and -2 if there was a problem during the creaton of the
+	server. It returns the pid of the server on success or 0 if no server
+	should be run (see use_local_server).
+=end
+	def start_server()
+		return 0 if @use_local_server == false
+		begin
+			TCPSocket.new(@hostname, @port).close
+			return -1
+		rescue
+			begin
+				# Create config file
+				FileUtils.mkdir_p(@confdir, :mode => 0700)
+				FileUtils.touch(@confdir+"/aria2.conf")
+				# Cleanup log file
+				FileUtils.rm(@confdir+"/aria2.log", :force => true)
+				# Launch aria2c process
+				command = "aria2c --disable-ipv6=true --enable-xml-rpc --xml-rpc-listen-port=#{@port} " \
+					"--conf-path=#{@confdir}/aria2.conf --log=#{@confdir}/aria2.log --log-level=notice " \
+					"--dht-file-path=#{@confdir}/dht.dat --lowest-speed-limit=1K"
+				debug("start server", command)
+				@@pid = Process.spawn(command, :pgroup=>true, :chdir=>ENV['HOME'],
+						STDOUT=>"/dev/null", STDIN=>"/dev/null")
+				Process.detach(@@pid)
+				# Wait for the server to respond properly to requests
+				begin
+					debug("test request")
+					begin
+						result = @@client.call("aria2.getVersion")
+					rescue
+					end
+					sleep 1 if result == nil
+				end while result == nil
+				# Store pid in a file
+				begin
+					File.open(@confdir+"/aria2.pid", "w").puts(@@pid)
+				rescue
+					p $!
+				end
+				puts "Started aria2 XML-RPC Server (pid #{@@pid.to_s})..."
+				return @@pid
+			rescue
+				return -2
+			end
+		end
+	end
+
+	def call(method, *args)
+		begin
+			result = @@client.call(method, *args)
+		rescue XMLRPC::FaultException => e
+			# Unsupported/Bad XMLRPC request
+			debug("XMLRPC server didn't support the request")
+			puts e.message
+		rescue Errno::EPIPE => e
+			# Connection interrupted/timed out/server shutdown
+			return nil if !@is_connected
+			connect(true)
+			result = call(method, args)
+		rescue Errno::ECONNREFUSED => e
+			# Connection refused
+			return nil if start_server < 0
+			result = call(method, args)
+		rescue Exception => e
+			# Unhandled exception
+			puts $!, e.message
+		end
+		result
+	end
+
+	public
+
+=begin
+	connect:
+	Creates an XMLRPC::Client instance and sends a first request that will
+	make sure we can talk to the server.
+=end
+	def connect(force=false)
+		return if @@client and force == false
+		@is_connected = false
+		begin
+			@@client = XMLRPC::Client.new3({:host => @hostname, :path => "/rpc",
+					:port => @port, :user => @user, :password => @password,
+					:timeout => 60})
+			debug("call")
+			result = nil
+			Timeout::timeout(5) do
+				result = call("aria2.getVersion")
+			end
+			raise Exception.new("Unable to get an appropriate response to our request") if result == nil
+			@version = result["version"]
+			@is_connected = true
+		rescue Exception => e
+			@@client = nil
+			puts "Can't establish a connection"
+			debug(e.message)
+		end
+	end
+
+=begin
+	use_custom_server:
+	Sets aria2 to connect to a custom server.
+=end
+	def use_custom_server(hostname, port, user, password)
+		@use_local_server = false
+		@hostname = hostname
+		@port = port
+		@user = user.to_s if !user.empty?
+		@password = password.to_s if !password.empty?
+	end
+
+=begin
+	use_local_server:
+	Sets aria2 to connect to a local (self-managed) server.
+=end
+	def use_local_server()
+		@use_local_server = true
+		@hostname = DEFAULT_HOST
+		@port = DEFAULT_PORT
+		@user = nil
+		@password = nil
+	end
+
+	def use_local_server?()
+		@use_local_server and @@pid > 0
+	end
+
+=begin
+	shutdown:
+	Disconnect and terminates the local server if it exists.
+=end
+	def shutdown()
+		debug("shutdown", @@pid)
+		begin
+			if @@pid > 0
+				FileUtils.rm(@confdir+"/aria2.pid", :force => true)
+				Process.kill("TERM", @@pid)
+				sleep 1 while Process.kill("CONT", @@pid)
+			end
+		rescue Errno::ESRCH
+			# Process does no more exist
+		rescue
+			p $!
+		end
+		@@pid = 0
+		@@client = nil
+		@is_connected = false
+	end
+
+	# Adds new HTTP(S)/FTP/BitTorrent/Magnet URI.
+	def add_uri(uris, options = nil, position = nil)
+		uris = [ uris ] if uris.class == String
+		gid = call("aria2.addUri", uris)
+		@new_downloads << gid if gid != nil
+		gid
+	end
+
+	# Adds BitTorrent download by uploading .torrent file.
+	def add_torrent(torrent, uris = nil, options = nil, position = nil)
+		data = read(torrent)
+		gid = call("aria2.addTorrent", XMLRPC::Base64.new(data))
+		@new_downloads << gid if gid != nil
+		gid
+	end
+
+	# Adds Metalink download by uploading .metalink file.
+	def add_metalink(metalink, options = nil, position = nil)
+		data = read(metalink)
+		gid = call("aria2.addMetalink", XMLRPC::Base64.new(data))
+		@new_downloads << gid if gid != nil
+		gid
+	end
+
+	# Removes the download denoted by @gid.
+	def remove(gid)
+		call("aria2.remove", gid)
+	end
+
+	# Returns download progress of the download denoted by @gid.
+	def tell_status(gid)
+		result = call("aria2.tellStatus", gid)
+		result = [] if result == nil
+		result
+	end
+
+	# Returns URIs used in the download denoted by @gid.
+	def get_uris(gid)
+		call("aria2.getUris", gid)
+	end
+
+	# Returns file list of the download denoted by @gid.
+	def get_files(gid)
+		call("aria2.getFiles", gid)
+	end
+
+	# Returns peer list of the download denoted by @gid.
+	def get_peers(gid)
+		call("aria2.getPeers", gid)
+	end
+
+	# Returns the list of active downloads.
+	def tell_active()
+		result = call("aria2.tellActive")
+		result = [] if !result
+		result
+	end
+
+	# Returns the list of waiting download.
+	def tell_waiting(offset, num)
+		result = call("aria2.tellWaiting", offset, num)
+		result = [] if !result
+		result
+	end
+
+	# Returns the list of stopped download.
+	def tell_stopped(offset, num)
+		return nil if @version < "1.8"
+		result = call("aria2.tellStopped", offset, num)
+		result = [] if result == nil
+		result
+	end
+
+	# Changes the position of the download denoted by @gid.
+	def change_position(gid, pos, from_current = false)
+		return nil if @version < "1.8"
+		how = from_current ? "POS_CUR" : "POS_RET"
+		call("aria2.changePosition", gid, pos, how)
+	end
+
+	# Returns options of the download denoted by @gid.
+	def get_options(gid)
+		return nil if @version < "1.8"
+		call("aria2.getOption", gid)
+	end
+
+	# Changes options of the download denoted by @gid dynamically.
+	def change_options(gid, options)
+		call("aria2.changeOption", gid, options)
+	end
+
+	# Returns global options.
+	def get_global_options()
+		return nil if @version < "1.8"
+		call("aria2.getGlobalOption")
+	end
+
+	# Changes global options dynamically.
+	def change_global_options(options)
+		call("aria2.changeGlobalOption", options)
+	end
+
+	# Purges completed/error/removed downloads to free memory.
+	def purge_download_result()
+		call("aria2.purgeDownloadResult")
+	end
+
+end
+
+
+
+class Eat::Aria2Listener < Eat::Aria2
+
+	include Singleton
+
+	def initialize()
+		super
+		@downloads = []
+		start
+	end
+
+	def start()
+		GLib::Timeout.add_seconds(1) do
+
+			active_downloads = []
+
+			if @is_connected
+
+				# Emit status signal for each active download
+				tell_active.each do |res|
+					gid = res["gid"]
+					@downloads << gid if !@downloads.find_index(gid)
+					active_downloads << gid
+					signal_emit("download_status", gid)
+				end
+
+				# Check/Cleanup unhandled new downloads
+				(@new_downloads - active_downloads).each do |gid|
+					@downloads << gid
+				end
+				@new_downloads.clear
+
+				# Emit specific signal for each inactive download
+				(@downloads - active_downloads).each do |gid|
+					# Get status
+					status = tell_status(gid)
+					status_msg = status["status"]
+					case status["status"]
+						when "complete" then signal_emit("download_completed", gid)
+						when "removed" then signal_emit("download_removed", gid)
+						when "error"
+							if status["errorCode"] == "5"
+								# Download was aborted due to "pause"
+								debug "pause lasted too long, download %s dropped" % gid
+							else
+								puts "Unhandled error (%s: %s)" % [gid, status["errorCode"]]
+							end
+						else puts "Unhandled status (%s: %s)" % [gid, status_msg]
+					end
+				end
+
+			end
+
+			@downloads = active_downloads
+			true
+		end
+	end
+
+end
+
+
+
+class Eat::Aria2Config
+
+	attr_reader :filename
+	attr_accessor :values
+
+	def initialize(filename="aria2.conf")
+		@filename = filename
+		@values = {}
+		parse
+	end
+
+	private
+
+	def default_values()
+		# Basic options
+		#@values["dir"] = "." # directory to store downloaded files
+		@values["log"] = "-" # file name of the log file, - means STDOUT
+		@values["max-concurrent-downloads"] = 5 # maximum number of parallel downloads for every static URI
+		@values["check-integrity"] = false # check file integrity, effect only in BitTorrent and Metalink
+
+		# HTTP/FTP options
+		#@values["all-proxy"] = "" # proxy server for all protocols
+		@values["connect-timeout"] = 60 # timeout to establish a connection
+		@values["lowest-speed-limit"] = 0 # close connection if download speed is lower than this value
+		@values["max-file-not-found"] = 0 # number of times to try a file reporting 404 before giving up
+		@values["max-tries"] = 5 # number of tries
+		@values["proxy-method"] = "get" # specify method to use in proxy request, get or tunnel
+		@values["remote-time"] = false # applies the file timestamp from the remote server
+		@values["split"] = 5 # number of connections to use for downloading a file
+		@values["timeout"] = 60 # timeout in seconds
+
+		# HTTP options
+		#@values["ca-certificate"] = "" # file name of certificate authorities to use
+		#@values["certificate"] = "" # file name of client certificate
+		@values["check-certificate"] = true # verify the peer using certificates
+		@values["http-auth-challenge"] = false # send auth header only when it is requested by the server
+		@values["http-user"] = "" # HTTP user
+		@values["http-passwd"] = "" # HTTP password
+		#@values["http-proxy"] = "" # proxy server for HTTP
+		#@values["https-proxy"] = "" # proxy server for HTTPS
+		#@values["private-key"] = "" # file name of private key to use
+		@values["referer"] = "" # set referer
+		@values["enable-http-keep-alive"] = true # enable HTTP/1.1 persistent connection
+		@values["enable-http-pipelining"] = false # enable HTTP/1.1 pipelining
+		@values["header"] = "" # header to append to HTTP request, can be used repeatedly
+		@values["load-cookies"] = "" # cookies file name to use, supports Firefox3 (sqlite) and Netscape
+		@values["save-cookies"] = "" # save cookies to file name in Netscape format
+		@values["use-head"] = false # use HEAD method for first request
+		@values["user-agent"] = "Eatmonkey/0.1.0 aria2/1.8.0"
+
+		# FTP options
+		@values["ftp-user"] = "anonymous" # FTP user
+		@values["ftp-passwd"] = "ARIA2USER@" # FTP password
+		@values["ftp-pasv"] = true # use passive mode
+		#@values["ftp-proxy"] = "" # proxy server for FTP
+		@values["ftp-type"] = "binary" # transfer type
+		@values["ftp-reuse-connection"] = true # reuse connection
+
+		# BitTorrent options
+		@values["bt-external-ip"] = "" # report IP address to tracker
+		@values["bt-hash-check-seed"] = true # continue to seed after file is complete and check integrity
+		@values["bt-max-open-files"] = 100 # number of files to open in each download
+		@values["bt-max-peers"] = 55 # number of maximum peers, 0 means unlimited
+		@values["bt-min-crypto-level"] = "plain" # minimum level of encryption, plain or arc4
+		@values["bt-prioritize-piece"] = "" # can contain head,tail useful for previewing files
+		@values["bt-require-crypto"] = false # accept and establish connection with crypto only
+		@values["bt-request-peer-speed-limit"] = "50K" # tries more peers if download speed is under value
+		@values["bt-save-metadata"] = false # save metadata to .torrent file
+		@values["bt-seed-unverified"] = false # seed without verifying piece hashes
+		@values["bt-stop-timeout"] = 0 # stop download if speed is 0 during given seconds, 0 does nothing
+		@values["bt-tracker-interval"] = 0 # interval in seconds between tracker requests, 0 does nothing
+		#@values["dht-entry-point"] = "" # set HOST:PORT as entry point to DHT network
+		#@values["dht-file-path"] = "" # file name of DHT routing table, $XDG_CONFIG_HOME/eatmonkey/dht.dat
+		@values["dht-listen-port"] = "6881-6999" # UDP listening port for DHT
+		@values["enable-dht"] = true # enable DHT functionality
+		@values["enable-peer-exchange"] = true # enable PEX extension
+		@values["follow-torrent"] = true # parse .torrent file and downloads mentionned files, can be mem
+		@values["listen-port"] = "6881-6999" # TCP listening port for BitTorrent
+		@values["max-overall-upload-limit"] = 0 # max overall upload speed in B/s, 0 means unlimited
+		@values["max-upload-limit"] = 0 # max upload speed per each download, 0 means unlimited
+		@values["peer-id-prefix"] = "Eatmonkey/0.1.0" # set peer ID, max 20 bytes
+		@values["seed-ratio"] = 1.0 # specify share ratio
+
+		# Metalink options
+		@values["follow-metalink"] = true # parse .metalink file and downloads mentionned files, can be mem
+		@values["metalink-servers"] = 5 # number of servers to connect to simultaneously
+		@values["metalink-language"] = "" # language of the file to download
+		@values["metalink-location"] = "" # preferred location of the server to use, can be JP,US
+		@values["metalink-os"] = "" # operating system of the file to download
+		@values["metalink-version"] = "" # version of the file to download
+		@values["metalink-preferred-protocol"] = "none" # preferred protocol to use, can be http,https,ftp
+		@values["metalink-enable-unique-protocol"] = true # use only one type of protocol for download
+
+		# XML-RPC options
+		@values["enable-xml-rpc"] = false
+		@values["xml-rpc-listen-all"] = false
+		@values["xml-rpc-listen-port"] = 6800
+		@values["xml-rpc-max-request-size"] = "2M"
+		@values["xml-rpc-passwd"] = ""
+		@values["xml-rpc-user"] = ""
+
+		# Advanced options
+		@values["allow-overwrite"] = false # re-download the file even if file exists
+		@values["allow-piece-length-change"] = false # continue download even if piece length is different from control file
+		@values["async-dns"] = true # asynchronous DNS
+		@values["auto-file-renaming"] = true # rename filename if file already exists
+		@values["auto-save-interval"] = 60 # save a .aria2 control file every SEC seconds
+		@values["conf-path"] = "" # change the configuration file path
+		@values["daemon"] = false # run as daemon
+		@values["disable-ipv6"] = false # disable IPv6
+		@values["enable-direct-io"] = true # enable direct I/O to lower CPU cycles while allocating/checking files
+		@values["file-allocation"] = "prealloc" # file allocation method, can be none, prealloc, falloc
+		@values["interface"] = "" # bind sockets to given interface, can be interface name, IP and hostname
+		@values["log-level"] = "debug" # log level, can be debug,info,notice,warn,error
+		@values["on-download-complete"] = "" # command to execute when download completes, cf. start
+		@values["on-download-error"] = "" # command to execute when download aborts, cf. start
+		@values["on-download-start"] = "" # command to execute when download starts, GID is passed to command
+		@values["on-download-stop"] = "" # command to execute when download stops, not executed if complete/error is set
+		@values["summary-interval"] = 60 # interval in seconds to output summary, 0 to supress the output
+		@values["force-sequential"] = false # download one URI after another
+		@values["max-overall-download-limit"] = 0 # max overall download speed in B/s, 0 means unlimited
+		@values["max-download-limit"] = 0 # max download speed per each download in B/s, 0 means unlimited
+		@values["no-file-allocation-limit"] = "5K" # no file allocation for files smaller than value
+		@values["parameterized-uri"] = false # enable parameterized URI support, e.g. {file1,file2} file[0-9]
+		@values["quiet"] = false # no console output
+		@values["realtime-chunk-checksum"] = true # validate chunk of data while downloading if checksums are provided
+	end
+
+	def parse()
+		@values.clear
+		default_values
+		begin
+			file = File.open(@filename)
+			while !file.eof and line = file.readline
+				next if line !~ /^([a-zA-Z0-9-]+)=(.*)$/
+				key = $1
+				val = $2.strip
+				if val == "true"
+					val = true
+				elsif val == "false"
+					val = false
+				elsif val =~ /^[0-9]+$/
+					val = val.to_i
+				elsif val =~ /^[0-9]+\.[0-9]+$/
+					val = val.to_f
+				end
+				@values[key] = val
+			end
+			file.close
+		rescue
+		end
+	end
+
+	public
+
+	def [](key)
+		@values[key]
+	end
+
+	def []=(key, val)
+		@values[key] = val
+	end
+
+	def filename=(filename)
+		@filename = filename
+		parse
+	end
+
+	def save()
+		begin
+			file = File.open(@filename, "w")
+			@values.each do |key,val|
+				file.puts("#{key}=#{val}")
+			end
+			file.close
+		rescue
+			p $!
+		end
+	end
+
+end
+
+
+
+if __FILE__ == $0
+	aria2 = Eat::Aria2.new
+	exit if !aria2.is_connected
+	puts "Version: aria2 "+aria2.version
+	#aria2.add_uri(["http://dlc.sun.com/torrents/info/osol-0906-x86.iso.torrent"])
+	begin
+		aria2.tell_active.each do |res|
+			gid = res["gid"]
+			puts " *** Set download max rate to 16KB ***"
+			aria2.change_options(gid, "max-download-limit" => "16000")
+			puts " *** Get status ***"
+			pp aria2.tell_status(gid)
+			puts " *** Get uris ***"
+			pp aria2.get_uris(gid)
+			puts " *** Get files ***"
+			pp aria2.get_files(gid)
+			puts " *** Get peers ***"
+			pp aria2.get_peers(gid).length
+		end
+		sleep 5
+	end while true
+end
+
diff --git a/src/eatmanager.rb b/src/eatmanager.rb
new file mode 100644
index 0000000..333e257
--- /dev/null
+++ b/src/eatmanager.rb
@@ -0,0 +1,302 @@
+#!/usr/bin/ruby -w
+
+require "gtk2"
+require "pango"
+
+require "eataria2"
+require "eatsettings"
+
+include Gtk
+
+
+
+module Eat
+end
+
+
+
+class Eat::Manager
+
+	def initialize()
+		# Setup aria2 listener
+		@aria2 = Eat::Aria2Listener.instance
+		@aria2.signal_connect("download_status") { |this, gid| update_row(gid) }
+		@aria2.signal_connect("download_completed") { |this, gid| update_row(gid) }
+		@aria2.signal_connect("download_removed") { |this, gid| update_row(gid) }
+
+		# Retrieve GUI widgets
+		builder = Builder.new
+		builder << "manager.ui"
+
+		@window = builder["window-manager"]
+		@treeview = builder["treeview-manager"]
+		@liststore = builder["liststore-manager"]
+		@statusbar = builder["statusbar-manager"]
+
+		@newdl_dialog = builder["dialog-new-download"]
+		@custom_uri = builder["custom-uri"]
+		@select_file = builder["select-file"]
+		@select_file_dialog = builder["filechooserdialog-new-download"]
+
+		# Setup actions
+		builder["action-add"].signal_connect("activate") { action_add }
+		builder["action-pause"].signal_connect("activate") { action_pause }
+		builder["action-resume"].signal_connect("activate") { action_resume }
+		builder["action-remove"].signal_connect("activate") { action_remove }
+		builder["action-settings"].signal_connect("activate") { show_settings_dialog }
+		builder["action-quit"].signal_connect("activate") { action_quit }
+		builder["action-about"].signal_connect("activate") { show_about_dialog }
+
+		# Setup window
+		@window.signal_connect('delete-event') { action_quit }
+
+		# Setup tree view
+		cell = CellRendererText.new
+		cell.ellipsize = Pango::ELLIPSIZE_END
+		column = builder["treeviewcolumn-completed"]
+		column.pack_start(cell, true)
+		column.add_attribute(cell, :text, 8)
+		cell = CellRendererText.new
+		cell.ellipsize = Pango::ELLIPSIZE_END
+		column = builder["treeviewcolumn-filepath"]
+		column.pack_start(cell, true)
+		column.add_attribute(cell, :text, 9)
+
+		# Setup statusbar
+		@statuscontext = { "main" => @statusbar.get_context_id("main context"),
+				"menu" => @statusbar.get_context_id("menu context") }
+		@statusbar.push(@statuscontext["main"], "Eatmonkey 0.1.0 - aria2 #{@aria2.version}")
+
+#		builder["menuitem-add"].signal_connect("select") do
+#			@statusbar.push(@statuscontext["menu"], "Add a new download")
+#		end
+#		builder["menuitem-add"].signal_connect("deselect") do
+#			@statusbar.pop(@statuscontext["menu"])
+#		end
+
+		# Setup new download dialog
+		file_filter = builder["filefilter-new-download"]
+		file_filter.name = "Torrents, Metalinks"
+		file_filter.add_pattern("*.torrent")
+		file_filter.add_pattern("*.metalink")
+		@select_file_dialog.filter = file_filter
+		@select_file.signal_connect('clicked') do
+			@select_file_dialog.unselect_all
+			res = @select_file_dialog.run
+			@custom_uri.text = @select_file_dialog.filename if res == Gtk::Dialog::RESPONSE_ACCEPT
+			@select_file_dialog.hide
+		end
+	end
+
+	def show()
+		@window.show_all
+	end
+
+	def update_row(gid)
+		row_iter = nil
+		gid_i = gid.to_i
+
+		result = @aria2.tell_status(gid)
+		return if result.empty?
+
+		@liststore.each do |model, path, iter|
+			next unless iter.get_value(0) == gid_i
+			row_iter = iter
+			break
+		end
+
+		if !row_iter
+			# Avoid adding rows with incomplete information
+			return if result["totalLength"] == "0" or result["status"] != "active"
+
+			# Add unknown active download to liststore
+			row_iter = @liststore.append
+			@liststore.set_value(row_iter, 0, gid_i)
+			uris = @aria2.get_uris(gid)
+			p uris
+			begin
+				# TODO Torrent downloads don't have a URI
+				@liststore.set_value(row_iter, 10, uris[0]["uri"])
+			rescue
+			end
+		end
+
+		case result["status"]
+		when "active" then
+			@liststore.set_value(row_iter, 1, result["connections"].to_i)
+			@liststore.set_value(row_iter, 2, result["completedLength"].to_i)
+			@liststore.set_value(row_iter, 3, result["uploadLength"].to_i)
+			@liststore.set_value(row_iter, 4, result["totalLength"].to_i)
+			@liststore.set_value(row_iter, 5, result["downloadSpeed"].to_i)
+			@liststore.set_value(row_iter, 6, result["uploadSpeed"].to_i)
+			@liststore.set_value(row_iter, 7, result["infoHash"])
+
+			completed = result["completedLength"].to_i
+			total = result["totalLength"].to_i
+			percent = total > 0 ? 100 * completed / total : 0
+			@liststore.set_value(row_iter, 8, percent)
+
+			result = @aria2.get_files(gid.to_s)
+			if result != nil and !result[0]["path"].empty?
+				@liststore.set_value(row_iter, 9, File.basename(result[0]["path"]))
+			end
+		when "complete" then
+			@liststore.set_value(row_iter, 8, 100)
+			# Update the name, useful for very small files for which
+			# this callback didn't run with the "active" state.
+			result = @aria2.get_files(gid.to_s)
+			if result != nil and !result[0]["path"].empty?
+				@liststore.set_value(row_iter, 9, File.basename(result[0]["path"]))
+			end
+		when "removed" then
+			@liststore.remove(row_iter)
+		when "error" then
+			@liststore.set_value(row_iter, 8, -1)
+		end
+	end
+
+	def show_about_dialog()
+		logo = Gdk::Pixbuf.new("/usr/share/pixmaps/eatmonkey-logo.png")
+		AboutDialog.show(@window,
+				"program-name" => "Eatmonkey",
+				"version" => "0.1.0",
+				"copyright" => "Copyright 2010 \xC2\xA9 Mike Massonnet",
+				"logo" => logo,
+				"comments" => "Stupid download manager for monkeys and Capuchins!" \
+				"\n\n" \
+				"Eatmonkey is a download manager that works exclusively with " \
+				"aria2, the ultra fast download utility. It has support for " \
+				"HTTP(s)/FTP, BitTorrent and Metalink files.")
+	end
+
+	def show_settings_dialog()
+		used_local_server = @aria2.use_local_server?
+
+		dialog = Eat::SettingsDialog.new(@window)
+		res = dialog.run
+
+		if res == Dialog::RESPONSE_OK
+
+			settings = Eat::Settings.instance
+
+			if settings["custom-server"]
+				# Switch to custom server
+				debug("switch to custom server")
+				@aria2.use_custom_server(settings["xmlrpc-host"], settings["xmlrpc-port"],
+						settings["xmlrpc-user"], settings["xmlrpc-passwd"])
+				@aria2.shutdown if used_local_server # TODO prevent stopping unfinished downloads
+				@aria2.connect(true)
+			else
+				# Switch to local server
+				if used_local_server
+					# TODO need to store active downloads to effectively restart them
+					# and avoid gid conflicts between old and new/readded downloads
+					res = 0
+					count = @aria2.tell_active.count
+					if count > 0
+						dialog = MessageDialog.new(@window,
+								Dialog::DESTROY_WITH_PARENT | Dialog::NO_SEPARATOR,
+								MessageDialog::QUESTION, MessageDialog::BUTTONS_YES_NO,
+								"Restart the aria2 XML-RPC Server?")
+						dialog.secondary_text = "To take the new changes into account aria2 has to be " \
+								"restarted, this will stop/resume the current downloads."
+						res = dialog.run
+						dialog.destroy
+					end
+					if res == Dialog::RESPONSE_YES or count == 0
+						debug("restart local server")
+						@aria2.shutdown
+						@aria2.connect(true)
+					end
+				else
+					debug("switch to local server")
+					@aria2.use_local_server
+					@aria2.connect(true)
+				end
+			end
+
+		end
+	end
+
+	private
+
+	def action_quit()
+		@aria2.shutdown # TODO make this optional
+		main_quit
+	end
+
+	def action_add()
+		@custom_uri.text = ""
+		@custom_uri.grab_focus
+		res = @newdl_dialog.run
+		@newdl_dialog.hide
+		uri = @custom_uri.text
+		if res == Dialog::RESPONSE_OK and !uri.empty?
+			# TODO check if it is a uri or a torrent/metalink file and use the right
+			# method addUri/addTorrent/addMetalink
+			puts "download file %s" % uri
+			gid = @aria2.add_uri(uri)
+			if gid != nil
+				puts "gid: %s" % gid
+
+				# Add new row to liststore
+				row_iter = @liststore.append
+				@liststore.set_value(row_iter, 0, gid.to_i)
+				@liststore.set_value(row_iter, 9, File.basename(uri))
+				@liststore.set_value(row_iter, 10, uri)
+			end
+		end
+	end
+
+	def action_pause()
+		# TODO stop the download and on resume start it again at position 0 to put
+		# it in the front of the queue => drop the lowest-speed-limit hack
+
+		# This is sorta a hack around aria2, the download speed limit
+		# is drown under the lowest-speed-limit option and will thus be
+		# stopped. After a short while it will render an error code 5
+		# and will need to be restarted, cf. action_resume().
+		@treeview.selection.selected_each do |model, path, iter|
+			gid = iter.get_value(0)
+			@aria2.change_options(gid.to_s,
+					"max-download-limit" => "500",
+					"max-upload-limit" => "500")
+		end
+	end
+
+	def action_resume()
+		@treeview.selection.selected_each do |model, path, iter|
+			gid = iter.get_value(0).to_s
+			status = @aria2.tell_status(gid)
+			case status["status"]
+			when "active"
+				@aria2.change_options(gid,
+						"max-download-limit" => "0",
+						"max-upload-limit" => "0")
+			when "error"
+				next if status["errorCode"] != "5"
+				# Restart the download and delete current row as new gid will be created
+				@aria2.add_uri(iter.get_value(10))
+				@liststore.remove(iter)
+			end
+		end
+	end
+
+	def action_remove()
+		@treeview.selection.selected_each do |model, path, iter|
+			gid = iter.get_value(0)
+			@aria2.remove(gid.to_s)
+			@liststore.remove(iter)
+		end
+	end
+
+end
+
+
+
+if __FILE__ == $0
+	manager = Eat::Manager.new
+	manager.show
+	main
+end
+
diff --git a/src/eatsettings.rb b/src/eatsettings.rb
new file mode 100644
index 0000000..397cdce
--- /dev/null
+++ b/src/eatsettings.rb
@@ -0,0 +1,223 @@
+#!/usr/bin/ruby -w
+
+require "gtk2"
+require "singleton"
+
+require "eataria2"
+
+include Gtk
+
+module Eat
+end
+
+
+
+class Eat::Settings
+
+	include Singleton
+
+	attr_reader :aria2
+	attr_accessor :values
+
+	def initialize()
+		@conf_dir = ENV["XDG_CONFIG_HOME"]+"/eatmonkey/"
+		@aria2 = Eat::Aria2Config.new(@conf_dir+"aria2.conf")
+		@values = {}
+		parse
+	end
+
+	private
+
+	def default_values()
+		# Download Directory
+		# g_get_user_special_dir(G_USER_DIRECTORY_DOWNLOAD) or how not to waste time
+		if @aria2["dir"] == nil
+			if ENV["XDG_DOWNLOAD_DIR"] != nil
+				@aria2["dir"] = ENV["XDG_DOWNLOAD_DIR"]
+			else
+				dir = nil
+				begin
+					File.open(ENV["XDG_CONFIG_HOME"]+"/user-dirs.dirs") do |f|
+						f.grep(/^XDG_DOWNLOAD_DIR=/) do |line|
+							dir = line.sub(/^XDG_DOWNLOAD_DIR="(.*)"\n$/, '\1').sub('$HOME', ENV['HOME'])
+						end
+					end
+				rescue
+				end
+
+				if dir != nil
+					@aria2["dir"] = dir
+				elsif Dir.exists?(ENV["HOME"]+"/Downloads")
+					@aria2["dir"] = ENV["HOME"]+"/Downloads"
+				else
+					@aria2["dir"] = ENV["HOME"]
+				end
+			end
+		end
+
+		# XML-RPC Server
+		@values["custom-server"] = false
+		@values["xmlrpc-host"] = "127.0.0.1"
+		@values["xmlrpc-port"] = 6800
+	end
+
+	def parse()
+		@values.clear
+		default_values
+		begin
+			file = File.open(@conf_dir+"eatmonkeyrc")
+			while !file.eof and line = file.readline
+				next if line !~ /^([a-zA-Z0-9-]+)=(.*)$/
+				key = $1
+				val = $2.strip
+				if val == "true"
+					val = true
+				elsif val == "false"
+					val = false
+				elsif val =~ /^[0-9]+$/
+					val = val.to_i
+				end
+				@values[key] = val
+			end
+			file.close
+		rescue
+		end
+	end
+
+	public
+
+	def [](key)
+		@values[key]
+	end
+
+	def []=(key, val)
+		@values[key] = val
+	end
+
+	def save()
+		aria2.save
+		begin
+			file = File.open(@conf_dir+"eatmonkeyrc", "w")
+			@values.each do |key,val|
+				file.puts("#{key}=#{val}")
+			end
+			file.close
+		rescue
+			p $!
+		end
+	end
+
+end
+
+
+
+class Eat::SettingsDialog
+
+	attr_reader :dialog
+
+	def initialize(parent_window = nil)
+		builder = Builder.new
+		builder << "settings.ui"
+
+		@dialog = builder["dialog-settings"]
+		@xmlrpc = Hash.new
+		@xmlrpc[:vbox] = builder["xmlrpc-vbox"]
+		@xmlrpc[:custom_server] = builder["action-custom-server"]
+		@xmlrpc[:host] = builder["xmlrpc-host"]
+		@xmlrpc[:port] = builder["xmlrpc-port"]
+		@xmlrpc[:user] = builder["xmlrpc-user"]
+		@xmlrpc[:passwd] = builder["xmlrpc-passwd"]
+		@basic_options = Hash.new
+		@basic_options[:frame] = builder["basic-options-frame"]
+		@basic_options[:max_concurrent_downloads] = builder["max-concurrent-downloads"]
+		@basic_options[:max_download_speed] = builder["max-download-speed"]
+		@basic_options[:download_dir_button] = builder["download-dir-button"]
+		@bittorrent = Hash.new
+		@bittorrent[:frame] = builder["bittorrent-frame"]
+		@bittorrent[:max_upload_speed] = builder["max-upload-speed"]
+		@bittorrent[:max_peers] = builder["max-peers"]
+		@bittorrent[:seed_ratio] = builder["seed-ratio"]
+		@bittorrent[:enable_dht] = builder["enable-dht"]
+		@bittorrent[:enable_pex] = builder["enable-pex"]
+		@bittorrent[:require_encryption] = builder["require-encryption"]
+
+		# Setup parent window
+		@dialog.set_transient_for(parent_window)
+
+		# Setup actions
+		builder["action-custom-server"].signal_connect("toggled") { action_custom_server }
+
+		# Setup values
+		@settings = Eat::Settings.instance
+		@xmlrpc[:custom_server].active = @settings["custom-server"]
+		@xmlrpc[:host].text = @settings["xmlrpc-host"] if @settings["xmlrpc-host"] != nil
+		@xmlrpc[:port].value = @settings["xmlrpc-port"] if @settings["xmlrpc-port"] != nil
+		@xmlrpc[:user].text = @settings["xmlrpc-user"] if @settings["xmlrpc-user"] != nil
+		@xmlrpc[:passwd].text = @settings["xmlrpc-passwd"] if @settings["xmlrpc-passwd"] != nil
+		@basic_options[:max_concurrent_downloads].value = @settings.aria2["max-concurrent-downloads"]
+		@basic_options[:max_download_speed].value = @settings.aria2["max-overall-download-limit"]
+		@basic_options[:download_dir_button].current_folder = @settings.aria2["dir"]
+		@bittorrent[:max_upload_speed].value = @settings.aria2["max-overall-upload-limit"]
+		@bittorrent[:max_peers].value = @settings.aria2["bt-max-peers"]
+		@bittorrent[:seed_ratio].value = @settings.aria2["seed-ratio"]
+		@bittorrent[:enable_dht].active = @settings.aria2["enable-dht"]
+		@bittorrent[:enable_pex].active = @settings.aria2["enable-peer-exchange"]
+		@bittorrent[:require_encryption].active = @settings.aria2["bt-require-crypto"]
+
+		@dialog.vbox.show_all
+	end
+
+	def show()
+		@dialog.show_all
+	end
+
+	def run()
+		# Run dialog
+		res = @dialog.run
+
+		# Update settings
+		if res == Dialog::RESPONSE_OK
+			@settings["custom-server"] = @xmlrpc[:custom_server].active?
+			@settings["xmlrpc-host"] = @xmlrpc[:host].text
+			@settings["xmlrpc-port"] = @xmlrpc[:port].value_as_int
+			@settings["xmlrpc-user"] = @xmlrpc[:user].text
+			@settings["xmlrpc-passwd"] = @xmlrpc[:passwd].text
+			@settings.aria2["max-concurrent-downloads"] = @basic_options[:max_concurrent_downloads].value_as_int
+			@settings.aria2["max-overall-download-limit"] = @basic_options[:max_download_speed].value_as_int
+			@settings.aria2["dir"] = @basic_options[:download_dir_button].current_folder
+			@settings.aria2["max-overall-upload-limit"] = @bittorrent[:max_upload_speed].value_as_int
+			@settings.aria2["bt-max-peers"] = @bittorrent[:max_peers].value_as_int
+			@settings.aria2["seed-ratio"] = @bittorrent[:seed_ratio].value
+			@settings.aria2["enable-dht"] = @bittorrent[:enable_dht].active?
+			@settings.aria2["enable-peer-exchange"] = @bittorrent[:enable_pex].active?
+			@settings.aria2["bt-require-crypto"] = @bittorrent[:require_encryption].active?
+			@settings.save
+		end
+
+		begin
+			yield res
+		rescue
+		end
+		@dialog.hide
+
+		res
+	end
+
+	private
+
+	def action_custom_server()
+		active = @xmlrpc[:custom_server].active?
+		@xmlrpc[:vbox].set_sensitive(active)
+		@basic_options[:frame].set_sensitive(!active)
+		@bittorrent[:frame].set_sensitive(!active)
+	end
+
+end
+
+
+
+if __FILE__ == $0
+	dialog = Eat::SettingsDialog.new
+	dialog.run
+end
+
diff --git a/src/manager.ui b/src/manager.ui
new file mode 100644
index 0000000..ac19766
--- /dev/null
+++ b/src/manager.ui
@@ -0,0 +1,792 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkListStore" id="liststore-manager">
+    <columns>
+      <!-- column-name gid -->
+      <column type="gint"/>
+      <!-- column-name connections -->
+      <column type="gint"/>
+      <!-- column-name completed -->
+      <column type="gint"/>
+      <!-- column-name uploaded -->
+      <column type="gint"/>
+      <!-- column-name total -->
+      <column type="gint"/>
+      <!-- column-name download_speed -->
+      <column type="gint"/>
+      <!-- column-name upload_speed -->
+      <column type="gint"/>
+      <!-- column-name info_hash -->
+      <column type="gchararray"/>
+      <!-- column-name file_length -->
+      <column type="gint"/>
+      <!-- column-name file_path -->
+      <column type="gchararray"/>
+      <!-- column-name uri -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkListStore" id="liststore1"/>
+  <object class="GtkWindow" id="window-manager">
+    <property name="title" translatable="yes">Eatmonkey</property>
+    <property name="default_width">420</property>
+    <property name="default_height">320</property>
+    <child>
+      <object class="GtkVBox" id="vbox-manager">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkMenuBar" id="menubar-manager">
+            <property name="visible">True</property>
+            <child>
+              <object class="GtkMenuItem" id="menuitem-file">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">_File</property>
+                <property name="use_underline">True</property>
+                <child type="submenu">
+                  <object class="GtkMenu" id="menu-file">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkImageMenuItem" id="menuitem-add">
+                        <property name="visible">True</property>
+                        <property name="related_action">action-add</property>
+                        <property name="use_action_appearance">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkImageMenuItem" id="menuitem-pause">
+                        <property name="visible">True</property>
+                        <property name="related_action">action-pause</property>
+                        <property name="use_action_appearance">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkImageMenuItem" id="menuitem-resume">
+                        <property name="label">_Resume</property>
+                        <property name="visible">True</property>
+                        <property name="related_action">action-resume</property>
+                        <property name="use_underline">True</property>
+                        <property name="image">image1</property>
+                        <property name="use_stock">False</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkImageMenuItem" id="menuitem-remove">
+                        <property name="visible">True</property>
+                        <property name="related_action">action-remove</property>
+                        <property name="use_action_appearance">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkSeparatorMenuItem" id="separatormenuitem1">
+                        <property name="visible">True</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkImageMenuItem" id="menuitem-quit">
+                        <property name="visible">True</property>
+                        <property name="related_action">action-quit</property>
+                        <property name="use_action_appearance">True</property>
+                        <property name="accel_path"><Manager>/File/Quit</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkMenuItem" id="menuitem-edit">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">E_dit</property>
+                <property name="use_underline">True</property>
+                <child type="submenu">
+                  <object class="GtkMenu" id="menu-edit">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkImageMenuItem" id="menuitem-settings">
+                        <property name="visible">True</property>
+                        <property name="related_action">action-settings</property>
+                        <property name="use_action_appearance">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkMenuItem" id="menuitem-view">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">_View</property>
+                <property name="use_underline">True</property>
+                <child type="submenu">
+                  <object class="GtkMenu" id="menu-view">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkCheckMenuItem" id="menuitem-showmenubar">
+                        <property name="visible">True</property>
+                        <property name="related_action">toggleaction-showmenubar</property>
+                        <property name="use_action_appearance">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="active">True</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkCheckMenuItem" id="menuitem-showtoolbar">
+                        <property name="visible">True</property>
+                        <property name="related_action">toggleaction-showtoolbar</property>
+                        <property name="use_action_appearance">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="active">True</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkSeparatorMenuItem" id="separatormenuitem2">
+                        <property name="visible">True</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkRadioMenuItem" id="menuitem-compactview">
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                        <property name="label" translatable="yes">_Compact View</property>
+                        <property name="use_underline">True</property>
+                        <property name="active">True</property>
+                        <property name="draw_as_radio">True</property>
+                        <property name="group">menuitem-detailview</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkRadioMenuItem" id="menuitem-detailview">
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                        <property name="label" translatable="yes">_Details View</property>
+                        <property name="use_underline">True</property>
+                        <property name="draw_as_radio">True</property>
+                        <property name="group">menuitem-compactview</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkRadioMenuItem" id="menuitem-history">
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                        <property name="label" translatable="yes">_History</property>
+                        <property name="use_underline">True</property>
+                        <property name="draw_as_radio">True</property>
+                        <property name="group">menuitem-compactview</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkRadioMenuItem" id="menuitem-log">
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                        <property name="label" translatable="yes">_Log</property>
+                        <property name="use_underline">True</property>
+                        <property name="draw_as_radio">True</property>
+                        <property name="group">menuitem-compactview</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkMenuItem" id="menuitem4">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">H_elp</property>
+                <property name="use_underline">True</property>
+                <child type="submenu">
+                  <object class="GtkMenu" id="menu3">
+                    <property name="visible">True</property>
+                    <child>
+                      <object class="GtkImageMenuItem" id="menuitem-about">
+                        <property name="visible">True</property>
+                        <property name="related_action">action-about</property>
+                        <property name="use_action_appearance">True</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkToolbar" id="toolbar-manager">
+            <property name="visible">True</property>
+            <child>
+              <object class="GtkToolButton" id="toolbutton-add">
+                <property name="visible">True</property>
+                <property name="related_action">action-add</property>
+                <property name="use_action_appearance">True</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolButton" id="toolbutton-pause">
+                <property name="visible">True</property>
+                <property name="related_action">action-pause</property>
+                <property name="use_action_appearance">True</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolButton" id="toolbutton-resume">
+                <property name="visible">True</property>
+                <property name="related_action">action-resume</property>
+                <property name="use_action_appearance">True</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolButton" id="toolbutton-remove">
+                <property name="visible">True</property>
+                <property name="related_action">action-remove</property>
+                <property name="use_action_appearance">True</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkSeparatorToolItem" id="toolbutton-sep1">
+                <property name="visible">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolButton" id="toolbutton-settings">
+                <property name="visible">True</property>
+                <property name="related_action">action-settings</property>
+                <property name="use_action_appearance">True</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolButton" id="toolbutton-about">
+                <property name="visible">True</property>
+                <property name="related_action">action-about</property>
+                <property name="use_action_appearance">True</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolButton" id="toolbutton-quit">
+                <property name="visible">True</property>
+                <property name="related_action">action-quit</property>
+                <property name="use_action_appearance">True</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkScrolledWindow" id="scrolledwindow-manager">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hscrollbar_policy">automatic</property>
+            <property name="vscrollbar_policy">automatic</property>
+            <child>
+              <object class="GtkTreeView" id="treeview-manager">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="model">liststore-manager</property>
+                <property name="headers_clickable">False</property>
+                <property name="search_column">0</property>
+                <child>
+                  <object class="GtkTreeViewColumn" id="treeviewcolumn-filepath">
+                    <property name="resizable">True</property>
+                    <property name="title">File path</property>
+                    <property name="expand">True</property>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkTreeViewColumn" id="treeviewcolumn-completed">
+                    <property name="resizable">True</property>
+                    <property name="title">Completed</property>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkStatusbar" id="statusbar-manager">
+            <property name="visible">True</property>
+            <property name="spacing">2</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">3</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+  <object class="GtkAction" id="action-add">
+    <property name="stock_id">gtk-add</property>
+  </object>
+  <object class="GtkAction" id="action-pause">
+    <property name="stock_id">gtk-media-pause</property>
+  </object>
+  <object class="GtkAction" id="action-remove">
+    <property name="stock_id">gtk-remove</property>
+  </object>
+  <object class="GtkAction" id="action-resume">
+    <property name="label">_Resume</property>
+    <property name="stock_id">gtk-media-play</property>
+  </object>
+  <object class="GtkImage" id="image1">
+    <property name="visible">True</property>
+    <property name="stock">gtk-media-play</property>
+  </object>
+  <object class="GtkAction" id="action-settings">
+    <property name="stock_id">gtk-preferences</property>
+  </object>
+  <object class="GtkAction" id="action-quit">
+    <property name="stock_id">gtk-quit</property>
+  </object>
+  <object class="GtkAction" id="action-about">
+    <property name="stock_id">gtk-about</property>
+  </object>
+  <object class="GtkToggleAction" id="toggleaction-showmenubar">
+    <property name="label">Show _menu bar</property>
+    <property name="sensitive">False</property>
+    <property name="active">True</property>
+  </object>
+  <object class="GtkToggleAction" id="toggleaction-showtoolbar">
+    <property name="label">Show _toolbar</property>
+    <property name="sensitive">False</property>
+    <property name="active">True</property>
+  </object>
+  <object class="GtkDialog" id="dialog-new-download">
+    <property name="title" translatable="yes">New download</property>
+    <property name="modal">True</property>
+    <property name="window_position">center-on-parent</property>
+    <property name="destroy_with_parent">True</property>
+    <property name="icon_name">list-add</property>
+    <property name="type_hint">normal</property>
+    <property name="skip_taskbar_hint">True</property>
+    <property name="skip_pager_hint">True</property>
+    <property name="transient_for">window-manager</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkNotebook" id="notebook1">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="border_width">6</property>
+            <property name="show_tabs">False</property>
+            <child>
+              <object class="GtkVBox" id="vbox1">
+                <property name="visible">True</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkComboBox" id="combobox1">
+                    <property name="model">liststore1</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkFrame" id="frame1">
+                    <property name="border_width">6</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">none</property>
+                    <child>
+                      <object class="GtkAlignment" id="alignment1">
+                        <property name="visible">True</property>
+                        <property name="top_padding">6</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <object class="GtkHBox" id="hbox3">
+                            <property name="visible">True</property>
+                            <child>
+                              <object class="GtkFileChooserButton" id="filechooserbutton1">
+                                <property name="visible">True</property>
+                                <property name="create_folders">False</property>
+                              </object>
+                              <packing>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child type="label">
+                      <object class="GtkLabel" id="label4">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Select from file</property>
+                        <property name="use_markup">True</property>
+                        <attributes>
+                          <attribute name="weight" value="bold"/>
+                        </attributes>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkFrame" id="frame3">
+                    <property name="visible">True</property>
+                    <property name="border_width">6</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">none</property>
+                    <child>
+                      <object class="GtkAlignment" id="alignment3">
+                        <property name="visible">True</property>
+                        <property name="top_padding">6</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <object class="GtkHBox" id="hbox1">
+                            <property name="visible">True</property>
+                            <property name="spacing">4</property>
+                            <child>
+                              <object class="GtkEntry" id="custom-uri">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="invisible_char">&#x2022;</property>
+                              </object>
+                              <packing>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkButton" id="select-file">
+                                <property name="label">...</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">True</property>
+                                <property name="image">image2</property>
+                                <property name="image_position">right</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child type="label">
+                      <object class="GtkLabel" id="label6">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Open from URI/File</property>
+                        <property name="use_markup">True</property>
+                        <attributes>
+                          <attribute name="weight" value="bold"/>
+                        </attributes>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+              </object>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="label1">
+                <property name="visible">True</property>
+                <property name="label">page 1</property>
+              </object>
+              <packing>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkFrame" id="frame2">
+                <property name="border_width">6</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">none</property>
+                <child>
+                  <object class="GtkAlignment" id="alignment2">
+                    <property name="visible">True</property>
+                    <property name="top_padding">6</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <object class="GtkVBox" id="vbox2">
+                        <property name="visible">True</property>
+                        <property name="orientation">vertical</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <object class="GtkScrolledWindow" id="scrolledwindow1">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="hscrollbar_policy">automatic</property>
+                            <property name="shadow_type">in</property>
+                            <child>
+                              <object class="GtkTreeView" id="treeview1">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkHBox" id="hbox2">
+                            <property name="visible">True</property>
+                            <child>
+                              <object class="GtkButton" id="button3">
+                                <property name="label">gtk-clear</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">True</property>
+                                <property name="relief">none</property>
+                                <property name="use_stock">True</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="pack_type">end</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child type="label">
+                  <object class="GtkLabel" id="label5">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">Select from clipboard</property>
+                    <property name="use_markup">True</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                    </attributes>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="label2">
+                <property name="visible">True</property>
+                <property name="label">page 2</property>
+              </object>
+              <packing>
+                <property name="position">1</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="label3">
+                <property name="visible">True</property>
+                <property name="label">page 3</property>
+              </object>
+              <packing>
+                <property name="position">2</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="button2">
+                <property name="label">gtk-add</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="button1">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-5">button2</action-widget>
+      <action-widget response="-6">button1</action-widget>
+    </action-widgets>
+  </object>
+  <object class="GtkImage" id="image2">
+    <property name="visible">True</property>
+    <property name="stock">gtk-open</property>
+    <property name="icon-size">1</property>
+  </object>
+  <object class="GtkFileChooserDialog" id="filechooserdialog-new-download">
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Select a file - Torrents, Metalinks</property>
+    <property name="window_position">center-on-parent</property>
+    <property name="destroy_with_parent">True</property>
+    <property name="icon_name">document-open</property>
+    <property name="type_hint">normal</property>
+    <property name="skip_taskbar_hint">True</property>
+    <property name="skip_pager_hint">True</property>
+    <property name="transient_for">dialog-new-download</property>
+    <property name="has_separator">False</property>
+    <property name="use_preview_label">False</property>
+    <property name="filter">filefilter-new-download</property>
+    <property name="create_folders">False</property>
+    <property name="preview_widget_active">False</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox2">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child>
+          <placeholder/>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area2">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="button4">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="button5">
+                <property name="label">gtk-open</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-6">button4</action-widget>
+      <action-widget response="-3">button5</action-widget>
+    </action-widgets>
+  </object>
+  <object class="GtkFileFilter" id="filefilter-new-download"/>
+</interface>
diff --git a/src/settings.ui b/src/settings.ui
new file mode 100644
index 0000000..43494cf
--- /dev/null
+++ b/src/settings.ui
@@ -0,0 +1,770 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkDialog" id="dialog-settings">
+    <property name="title" translatable="yes">Settings</property>
+    <property name="resizable">False</property>
+    <property name="modal">True</property>
+    <property name="window_position">center-on-parent</property>
+    <property name="destroy_with_parent">True</property>
+    <property name="icon_name">preferences-other</property>
+    <property name="type_hint">normal</property>
+    <property name="skip_taskbar_hint">True</property>
+    <property name="skip_pager_hint">True</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkNotebook" id="notebook1">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="border_width">6</property>
+            <property name="show_border">False</property>
+            <child>
+              <object class="GtkVBox" id="vbox1">
+                <property name="visible">True</property>
+                <property name="border_width">6</property>
+                <property name="orientation">vertical</property>
+                <property name="spacing">6</property>
+                <child>
+                  <object class="GtkFrame" id="frame1">
+                    <property name="visible">True</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">none</property>
+                    <child>
+                      <object class="GtkAlignment" id="alignment1">
+                        <property name="visible">True</property>
+                        <property name="top_padding">6</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <object class="GtkVBox" id="vbox2">
+                            <property name="visible">True</property>
+                            <property name="orientation">vertical</property>
+                            <property name="spacing">6</property>
+                            <child>
+                              <object class="GtkCheckButton" id="checkbutton-custom-server">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="related_action">action-custom-server</property>
+                                <property name="use_action_appearance">True</property>
+                                <property name="draw_indicator">True</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkAlignment" id="xmlrpc-alignment">
+                                <property name="visible">True</property>
+                                <property name="left_padding">12</property>
+                                <child>
+                                  <object class="GtkVBox" id="xmlrpc-vbox">
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="orientation">vertical</property>
+                                    <property name="spacing">6</property>
+                                    <child>
+                                      <object class="GtkHBox" id="hbox1">
+                                        <property name="visible">True</property>
+                                        <property name="spacing">4</property>
+                                        <child>
+                                          <object class="GtkLabel" id="label3">
+                                            <property name="visible">True</property>
+                                            <property name="label" translatable="yes">Host:</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">0</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkEntry" id="xmlrpc-host">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="invisible_char">&#x2022;</property>
+                                          </object>
+                                          <packing>
+                                            <property name="position">1</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkSpinButton" id="xmlrpc-port">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="max_length">5</property>
+                                            <property name="invisible_char">&#x2022;</property>
+                                            <property name="adjustment">adjustment1</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">2</property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">False</property>
+                                        <property name="position">0</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkExpander" id="expander1">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="spacing">6</property>
+                                        <child>
+                                          <object class="GtkVBox" id="vbox3">
+                                            <property name="visible">True</property>
+                                            <property name="orientation">vertical</property>
+                                            <property name="spacing">6</property>
+                                            <child>
+                                              <object class="GtkHBox" id="hbox2">
+                                                <property name="visible">True</property>
+                                                <property name="spacing">4</property>
+                                                <child>
+                                                  <object class="GtkLabel" id="label4">
+                                                    <property name="visible">True</property>
+                                                    <property name="label" translatable="yes">Username:</property>
+                                                  </object>
+                                                  <packing>
+                                                    <property name="expand">False</property>
+                                                    <property name="fill">False</property>
+                                                    <property name="position">0</property>
+                                                  </packing>
+                                                </child>
+                                                <child>
+                                                  <object class="GtkEntry" id="xmlrpc-user">
+                                                    <property name="visible">True</property>
+                                                    <property name="can_focus">True</property>
+                                                    <property name="invisible_char">&#x2022;</property>
+                                                  </object>
+                                                  <packing>
+                                                    <property name="position">1</property>
+                                                  </packing>
+                                                </child>
+                                              </object>
+                                              <packing>
+                                                <property name="expand">False</property>
+                                                <property name="fill">False</property>
+                                                <property name="position">0</property>
+                                              </packing>
+                                            </child>
+                                            <child>
+                                              <object class="GtkHBox" id="hbox3">
+                                                <property name="visible">True</property>
+                                                <property name="spacing">4</property>
+                                                <child>
+                                                  <object class="GtkLabel" id="label5">
+                                                    <property name="visible">True</property>
+                                                    <property name="label" translatable="yes">Password:</property>
+                                                  </object>
+                                                  <packing>
+                                                    <property name="expand">False</property>
+                                                    <property name="fill">False</property>
+                                                    <property name="position">0</property>
+                                                  </packing>
+                                                </child>
+                                                <child>
+                                                  <object class="GtkEntry" id="xmlrpc-passwd">
+                                                    <property name="visible">True</property>
+                                                    <property name="can_focus">True</property>
+                                                    <property name="visibility">False</property>
+                                                    <property name="invisible_char">&#x2022;</property>
+                                                  </object>
+                                                  <packing>
+                                                    <property name="position">1</property>
+                                                  </packing>
+                                                </child>
+                                              </object>
+                                              <packing>
+                                                <property name="expand">False</property>
+                                                <property name="fill">False</property>
+                                                <property name="position">1</property>
+                                              </packing>
+                                            </child>
+                                          </object>
+                                        </child>
+                                        <child type="label">
+                                          <object class="GtkLabel" id="label6">
+                                            <property name="visible">True</property>
+                                            <property name="label" translatable="yes">Authentication</property>
+                                          </object>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="position">1</property>
+                                      </packing>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child type="label">
+                      <object class="GtkLabel" id="label2">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">aria2 XML-RPC Server</property>
+                        <attributes>
+                          <attribute name="weight" value="bold"/>
+                        </attributes>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkFrame" id="basic-options-frame">
+                    <property name="visible">True</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">none</property>
+                    <child>
+                      <object class="GtkAlignment" id="alignment2">
+                        <property name="visible">True</property>
+                        <property name="top_padding">6</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <object class="GtkVBox" id="basic-options-vbox">
+                            <property name="visible">True</property>
+                            <property name="orientation">vertical</property>
+                            <property name="spacing">6</property>
+                            <child>
+                              <object class="GtkHBox" id="hbox4">
+                                <property name="visible">True</property>
+                                <property name="spacing">4</property>
+                                <child>
+                                  <object class="GtkLabel" id="label8">
+                                    <property name="visible">True</property>
+                                    <property name="label" translatable="yes">Maximum number of concurrent downloads:</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkSpinButton" id="max-concurrent-downloads">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="invisible_char">&#x2022;</property>
+                                    <property name="adjustment">adjustment2</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkHBox" id="hbox6">
+                                <property name="visible">True</property>
+                                <property name="spacing">4</property>
+                                <child>
+                                  <object class="GtkLabel" id="label11">
+                                    <property name="visible">True</property>
+                                    <property name="label" translatable="yes">Maximum download speed:</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkSpinButton" id="max-download-speed">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="invisible_char">&#x2022;</property>
+                                    <property name="adjustment">adjustment-max-download-speed</property>
+                                    <property name="numeric">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="label13">
+                                    <property name="visible">True</property>
+                                    <property name="label" translatable="yes">KiB/s</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="label20">
+                                    <property name="visible">True</property>
+                                    <property name="label" translatable="yes">(0=infinite)</property>
+                                    <attributes>
+                                      <attribute name="size" value="7500"/>
+                                    </attributes>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">3</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkHBox" id="hbox5">
+                                <property name="visible">True</property>
+                                <property name="spacing">4</property>
+                                <child>
+                                  <object class="GtkLabel" id="label9">
+                                    <property name="visible">True</property>
+                                    <property name="label" translatable="yes">Download directory:</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkFileChooserButton" id="download-dir-button">
+                                    <property name="visible">True</property>
+                                    <property name="action">select-folder</property>
+                                    <property name="create_folders">False</property>
+                                    <property name="width_chars">14</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="position">2</property>
+                              </packing>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child type="label">
+                      <object class="GtkLabel" id="label7">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Download Options</property>
+                        <attributes>
+                          <attribute name="weight" value="bold"/>
+                        </attributes>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="label1">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">General</property>
+              </object>
+              <packing>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkFrame" id="bittorrent-frame">
+                <property name="visible">True</property>
+                <property name="border_width">6</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">none</property>
+                <child>
+                  <object class="GtkAlignment" id="alignment4">
+                    <property name="visible">True</property>
+                    <property name="top_padding">6</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <object class="GtkVBox" id="vbox5">
+                        <property name="visible">True</property>
+                        <property name="orientation">vertical</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <object class="GtkHBox" id="hbox7">
+                            <property name="visible">True</property>
+                            <property name="spacing">4</property>
+                            <child>
+                              <object class="GtkLabel" id="label12">
+                                <property name="visible">True</property>
+                                <property name="label" translatable="yes">Maximum upload speed:</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkSpinButton" id="max-upload-speed">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="invisible_char">&#x2022;</property>
+                                <property name="adjustment">adjustment-max-upload-speed</property>
+                                <property name="numeric">True</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="label14">
+                                <property name="visible">True</property>
+                                <property name="label" translatable="yes">KiB/s</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">2</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="label19">
+                                <property name="visible">True</property>
+                                <property name="label" translatable="yes">(0=infinite)</property>
+                                <attributes>
+                                  <attribute name="size" value="7500"/>
+                                </attributes>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">3</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkHBox" id="hbox9">
+                            <property name="visible">True</property>
+                            <property name="spacing">4</property>
+                            <child>
+                              <object class="GtkLabel" id="label17">
+                                <property name="visible">True</property>
+                                <property name="label" translatable="yes">Maximum number of peers:</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkSpinButton" id="max-peers">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="invisible_char">&#x2022;</property>
+                                <property name="adjustment">adjustment-max-peers</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="label18">
+                                <property name="visible">True</property>
+                                <property name="label" translatable="yes">(0=infinite)</property>
+                                <attributes>
+                                  <attribute name="size" value="7500"/>
+                                </attributes>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">2</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkHBox" id="hbox8">
+                            <property name="visible">True</property>
+                            <property name="spacing">4</property>
+                            <child>
+                              <object class="GtkLabel" id="label10">
+                                <property name="visible">True</property>
+                                <property name="label" translatable="yes">Seed ratio:</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkSpinButton" id="seed-ratio">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="invisible_char">&#x2022;</property>
+                                <property name="adjustment">adjustment-seed-ratio</property>
+                                <property name="digits">2</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="label21">
+                                <property name="visible">True</property>
+                                <property name="label" translatable="yes">(0=infinite)</property>
+                                <attributes>
+                                  <attribute name="size" value="7500"/>
+                                </attributes>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">2</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">2</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkHSeparator" id="hseparator1">
+                            <property name="visible">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="position">3</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkCheckButton" id="enable-dht">
+                            <property name="label" translatable="yes">Enable DHT (Distributed Hash Table)</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="tooltip_text" translatable="yes">Distributed Hash Table allows to use torrents without a working tracker</property>
+                            <property name="draw_indicator">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">4</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkCheckButton" id="enable-pex">
+                            <property name="label" translatable="yes">Enable PEX (Peer Exchange)</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="tooltip_text" translatable="yes">Peer Exchange helps finding more peers through connected peers</property>
+                            <property name="draw_indicator">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">5</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkHSeparator" id="hseparator2">
+                            <property name="visible">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="position">6</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkCheckButton" id="require-encryption">
+                            <property name="label" translatable="yes">Always require encryption</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="draw_indicator">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">7</property>
+                          </packing>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child type="label">
+                  <object class="GtkLabel" id="label16">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">BitTorrent</property>
+                    <property name="use_markup">True</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                    </attributes>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="label15">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">BitTorrent</property>
+              </object>
+              <packing>
+                <property name="position">1</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+            <child type="tab">
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="button2">
+                <property name="label">gtk-ok</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="button1">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-5">button2</action-widget>
+      <action-widget response="-6">button1</action-widget>
+    </action-widgets>
+  </object>
+  <object class="GtkAdjustment" id="adjustment1">
+    <property name="value">6800</property>
+    <property name="lower">1</property>
+    <property name="upper">65535</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkToggleAction" id="action-custom-server">
+    <property name="label">Connect to custom server</property>
+  </object>
+  <object class="GtkAdjustment" id="adjustment2">
+    <property name="value">5</property>
+    <property name="lower">1</property>
+    <property name="upper">100</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkAdjustment" id="adjustment-max-download-speed">
+    <property name="upper">9999</property>
+    <property name="step_increment">4</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkAdjustment" id="adjustment-max-upload-speed">
+    <property name="upper">9999</property>
+    <property name="step_increment">4</property>
+    <property name="page_increment">10</property>
+  </object>
+  <object class="GtkAdjustment" id="adjustment-seed-ratio">
+    <property name="value">1</property>
+    <property name="upper">99</property>
+    <property name="step_increment">0.1</property>
+    <property name="page_increment">0.1</property>
+  </object>
+  <object class="GtkAdjustment" id="adjustment-max-peers">
+    <property name="value">55</property>
+    <property name="upper">9999</property>
+    <property name="step_increment">5</property>
+    <property name="page_increment">10</property>
+  </object>
+</interface>



More information about the Xfce4-commits mailing list