[GTKUI] Refactor gtk imports and code

* Where possible use 'from gtk import ...', i.e. if repeated often or under 10 individual imports.
 * Remove osx_check to not show svg. It's only an issue on Windows so should work fine...
 * Rearrange and deduplicate code into d.u.g.common for getting pixbuf from files.
 * Use 'from gtk.gdk import...' to make it cleaner to apply GTK3 changes in future.
 * Move generic icon code from torrent_data_funcs to common.
 * Fix pylint import warnings and add WindowsError to pylintrc file.
This commit is contained in:
Calum Lind 2016-11-11 20:43:36 +00:00
commit 0cdf0230e9
24 changed files with 233 additions and 242 deletions

View file

@ -281,7 +281,7 @@ dummy-variables-rgx=_$|dummy
# List of additional names supposed to be defined in builtins. Remember that # List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible. # you should avoid to define new builtins when possible.
additional-builtins=_,_n,__request__ additional-builtins=_,_n,__request__,WindowsError
# List of strings which can identify a callback function by name. A callback # List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings. # name must start or end with one of those strings.

View file

@ -41,7 +41,7 @@ if windows_check():
import _winreg import _winreg
try: try:
hkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, 'Software\\7-Zip') hkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, 'Software\\7-Zip')
except WindowsError: # pylint: disable=undefined-variable except WindowsError:
pass pass
else: else:
win_7z_path = os.path.join(_winreg.QueryValueEx(hkey, 'Path')[0], '7z.exe') win_7z_path = os.path.join(_winreg.QueryValueEx(hkey, 'Path')[0], '7z.exe')

View file

@ -10,9 +10,9 @@
import gtk import gtk
import deluge.component as component import deluge.component as component
from deluge.common import get_pixmap, get_version from deluge.common import get_version
from deluge.ui.client import client from deluge.ui.client import client
from deluge.ui.gtkui.common import get_deluge_icon from deluge.ui.gtkui.common import get_deluge_icon, get_pixbuf
class AboutDialog(object): class AboutDialog(object):
@ -247,7 +247,7 @@ class AboutDialog(object):
self.about.set_website_label('deluge-torrent.org') self.about.set_website_label('deluge-torrent.org')
self.about.set_icon(get_deluge_icon()) self.about.set_icon(get_deluge_icon())
self.about.set_logo(gtk.gdk.pixbuf_new_from_file(get_pixmap('deluge-about.png'))) self.about.set_logo(get_pixbuf('deluge-about.png'))
if client.connected(): if client.connected():
if not client.is_standalone(): if not client.is_standalone():

View file

@ -15,14 +15,46 @@ import os
import shutil import shutil
import sys import sys
import gtk
from gobject import GError from gobject import GError
from gtk import SORT_ASCENDING, Menu, MenuItem, RadioMenuItem, SeparatorMenuItem, icon_theme_get_default
from gtk.gdk import COLORSPACE_RGB, Pixbuf, pixbuf_new_from_file, pixbuf_new_from_file_at_size
import deluge.common from deluge.common import get_pixmap, osx_check, windows_check
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
def create_blank_pixbuf(size=16):
pix = Pixbuf(COLORSPACE_RGB, True, 8, size, size)
pix.fill(0x0)
return pix
def get_pixbuf(filename):
try:
return pixbuf_new_from_file(get_pixmap(filename))
except GError as ex:
log.warning(ex)
return create_blank_pixbuf()
# Status icons.. Create them from file only once to avoid constantly re-creating them.
icon_downloading = get_pixbuf('downloading16.png')
icon_seeding = get_pixbuf('seeding16.png')
icon_inactive = get_pixbuf('inactive16.png')
icon_alert = get_pixbuf('alert16.png')
icon_queued = get_pixbuf('queued16.png')
icon_checking = get_pixbuf('checking16.png')
def get_pixbuf_at_size(filename, size):
try:
return pixbuf_new_from_file_at_size(get_pixmap(filename), size, size)
except GError as ex:
# Failed to load the pixbuf (Bad image file), so return a blank pixbuf.
log.warning(ex)
return create_blank_pixbuf(size)
def get_logo(size): def get_logo(size):
"""A Deluge logo. """A Deluge logo.
@ -33,12 +65,9 @@ def get_logo(size):
gtk.gdk.Pixbuf: deluge logo gtk.gdk.Pixbuf: deluge logo
""" """
filename = 'deluge.svg' filename = 'deluge.svg'
if deluge.common.windows_check() or deluge.common.osx_check(): if windows_check():
filename = 'deluge.png' filename = 'deluge.png'
try: return get_pixbuf_at_size(filename, size)
return gtk.gdk.pixbuf_new_from_file_at_size(deluge.common.get_pixmap(filename), size, size)
except GError as ex:
log.warning(ex)
def build_menu_radio_list(value_list, callback, pref_value=None, suffix=None, show_notset=False, def build_menu_radio_list(value_list, callback, pref_value=None, suffix=None, show_notset=False,
@ -60,7 +89,7 @@ def build_menu_radio_list(value_list, callback, pref_value=None, suffix=None, sh
Returns: Returns:
gtk.Menu: The menu radio gtk.Menu: The menu radio
""" """
menu = gtk.Menu() menu = Menu()
group = None group = None
if pref_value > -1 and pref_value not in value_list: if pref_value > -1 and pref_value not in value_list:
@ -71,7 +100,7 @@ def build_menu_radio_list(value_list, callback, pref_value=None, suffix=None, sh
item_text = str(value) item_text = str(value)
if suffix: if suffix:
item_text += ' ' + suffix item_text += ' ' + suffix
menuitem = gtk.RadioMenuItem(group=group, label=item_text) menuitem = RadioMenuItem(group=group, label=item_text)
group = menuitem group = menuitem
if pref_value and value == pref_value: if pref_value and value == pref_value:
menuitem.set_active(True) menuitem.set_active(True)
@ -80,7 +109,7 @@ def build_menu_radio_list(value_list, callback, pref_value=None, suffix=None, sh
menu.append(menuitem) menu.append(menuitem)
if show_notset: if show_notset:
menuitem = gtk.RadioMenuItem(group=group, label=notset_label) menuitem = RadioMenuItem(group=group, label=notset_label)
menuitem.set_name('unlimited') menuitem.set_name('unlimited')
if pref_value and pref_value < notset_lessthan: if pref_value and pref_value < notset_lessthan:
menuitem.set_active(True) menuitem.set_active(True)
@ -88,9 +117,9 @@ def build_menu_radio_list(value_list, callback, pref_value=None, suffix=None, sh
menu.append(menuitem) menu.append(menuitem)
if show_other: if show_other:
menuitem = gtk.SeparatorMenuItem() menuitem = SeparatorMenuItem()
menu.append(menuitem) menu.append(menuitem)
menuitem = gtk.MenuItem(_('Other...')) menuitem = MenuItem(_('Other...'))
menuitem.set_name('other') menuitem.set_name('other')
menuitem.connect('activate', callback) menuitem.connect('activate', callback)
menu.append(menuitem) menu.append(menuitem)
@ -135,11 +164,11 @@ def get_deluge_icon():
Returns: Returns:
gtk.gdk.Pixbuf: the deluge icon gtk.gdk.Pixbuf: the deluge icon
""" """
if deluge.common.windows_check(): if windows_check():
return get_logo(32) return get_logo(32)
else: else:
try: try:
icon_theme = gtk.icon_theme_get_default() icon_theme = icon_theme_get_default()
return icon_theme.load_icon('deluge', 64, 0) return icon_theme.load_icon('deluge', 64, 0)
except GError: except GError:
return get_logo(64) return get_logo(64)
@ -156,12 +185,12 @@ def associate_magnet_links(overwrite=False):
bool: True if association was set bool: True if association was set
""" """
if deluge.common.windows_check(): if windows_check():
import _winreg import _winreg
try: try:
hkey = _winreg.OpenKey(_winreg.HKEY_CLASSES_ROOT, 'Magnet') hkey = _winreg.OpenKey(_winreg.HKEY_CLASSES_ROOT, 'Magnet')
except WindowsError: # pylint: disable=undefined-variable except WindowsError:
overwrite = True overwrite = True
else: else:
_winreg.CloseKey(hkey) _winreg.CloseKey(hkey)
@ -170,7 +199,7 @@ def associate_magnet_links(overwrite=False):
deluge_exe = os.path.join(os.path.dirname(sys.executable), 'deluge.exe') deluge_exe = os.path.join(os.path.dirname(sys.executable), 'deluge.exe')
try: try:
magnet_key = _winreg.CreateKey(_winreg.HKEY_CLASSES_ROOT, 'Magnet') magnet_key = _winreg.CreateKey(_winreg.HKEY_CLASSES_ROOT, 'Magnet')
except WindowsError: # pylint: disable=undefined-variable except WindowsError:
# Could not create for all users, falling back to current user # Could not create for all users, falling back to current user
magnet_key = _winreg.CreateKey(_winreg.HKEY_CURRENT_USER, 'Software\\Classes\\Magnet') magnet_key = _winreg.CreateKey(_winreg.HKEY_CURRENT_USER, 'Software\\Classes\\Magnet')
@ -182,7 +211,7 @@ def associate_magnet_links(overwrite=False):
_winreg.CloseKey(magnet_key) _winreg.CloseKey(magnet_key)
# Don't try associate magnet on OSX see: #2420 # Don't try associate magnet on OSX see: #2420
elif not deluge.common.osx_check(): elif not osx_check():
# gconf method is only available in a GNOME environment # gconf method is only available in a GNOME environment
try: try:
import gconf import gconf
@ -280,7 +309,7 @@ def listview_replace_treestore(listview):
treestore.clear() treestore.clear()
treestore.set_default_sort_func(lambda *args: 0) treestore.set_default_sort_func(lambda *args: 0)
original_sort = treestore.get_sort_column_id() original_sort = treestore.get_sort_column_id()
treestore.set_sort_column_id(-1, gtk.SORT_ASCENDING) treestore.set_sort_column_id(-1, SORT_ASCENDING)
yield yield

View file

@ -13,8 +13,8 @@ import gtk
from twisted.internet import defer from twisted.internet import defer
import deluge.component as component import deluge.component as component
from deluge.common import get_pixmap, osx_check, windows_check from deluge.common import windows_check
from deluge.ui.gtkui.common import get_deluge_icon from deluge.ui.gtkui.common import get_deluge_icon, get_pixbuf_at_size
class BaseDialog(gtk.Dialog): class BaseDialog(gtk.Dialog):
@ -48,10 +48,9 @@ class BaseDialog(gtk.Dialog):
image = gtk.Image() image = gtk.Image()
if not gtk.stock_lookup(icon) and (icon.endswith('.svg') or icon.endswith('.png')): if not gtk.stock_lookup(icon) and (icon.endswith('.svg') or icon.endswith('.png')):
# Hack for Windows since it doesn't support svg # Hack for Windows since it doesn't support svg
if icon.endswith('.svg') and (windows_check() or osx_check()): if icon.endswith('.svg') and windows_check():
icon = icon.rpartition('.svg')[0] + '16.png' icon = icon.rpartition('.svg')[0] + '16.png'
pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(get_pixmap(icon), 32, 32) image.set_from_pixbuf(get_pixbuf_at_size(icon, 32))
image.set_from_pixbuf(pixbuf)
else: else:
image.set_from_stock(icon, gtk.ICON_SIZE_DIALOG) image.set_from_stock(icon, gtk.ICON_SIZE_DIALOG)
image.set_alignment(0.5, 0.0) image.set_alignment(0.5, 0.0)

View file

@ -14,8 +14,8 @@ import logging
import os.path import os.path
import gtk import gtk
import gtk.gdk
from gobject import TYPE_UINT64 from gobject import TYPE_UINT64
from gtk.gdk import ACTION_DEFAULT, ACTION_MOVE, BUTTON1_MASK, keyval_name # pylint: disable=ungrouped-imports
import deluge.component as component import deluge.component as component
from deluge.common import FILE_PRIORITY, open_file, show_file from deluge.common import FILE_PRIORITY, open_file, show_file
@ -193,10 +193,8 @@ class FilesTab(Tab):
self.listview.connect('button-press-event', self._on_button_press_event) self.listview.connect('button-press-event', self._on_button_press_event)
self.listview.enable_model_drag_source( self.listview.enable_model_drag_source(
gtk.gdk.BUTTON1_MASK, BUTTON1_MASK, [('text/plain', 0, 0)], ACTION_DEFAULT | ACTION_MOVE)
[('text/plain', 0, 0)], self.listview.enable_model_drag_dest([('text/plain', 0, 0)], ACTION_DEFAULT)
gtk.gdk.ACTION_DEFAULT | gtk.gdk.ACTION_MOVE)
self.listview.enable_model_drag_dest([('text/plain', 0, 0)], gtk.gdk.ACTION_DEFAULT)
self.listview.connect('drag_data_get', self._on_drag_data_get_data) self.listview.connect('drag_data_get', self._on_drag_data_get_data)
self.listview.connect('drag_data_received', self._on_drag_data_received_data) self.listview.connect('drag_data_received', self._on_drag_data_received_data)
@ -500,7 +498,7 @@ class FilesTab(Tab):
return True return True
def _on_key_press_event(self, widget, event): def _on_key_press_event(self, widget, event):
keyname = gtk.gdk.keyval_name(event.keyval) keyname = keyval_name(event.keyval)
if keyname is not None: if keyname is not None:
func = getattr(self, 'keypress_' + keyname.lower(), None) func = getattr(self, 'keypress_' + keyname.lower(), None)
selected_rows = self.listview.get_selection().get_selected_rows()[1] selected_rows = self.listview.get_selection().get_selected_rows()[1]

View file

@ -14,13 +14,14 @@ import os
import warnings import warnings
import gtk import gtk
import pango from gtk.gdk import Pixbuf
from gobject import GError from pango import ELLIPSIZE_END
import deluge.component as component import deluge.component as component
from deluge.common import TORRENT_STATE, get_pixmap, resource_filename from deluge.common import TORRENT_STATE, resource_filename
from deluge.configmanager import ConfigManager from deluge.configmanager import ConfigManager
from deluge.ui.client import client from deluge.ui.client import client
from deluge.ui.gtkui.common import get_pixbuf, get_pixbuf_at_size
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -61,7 +62,7 @@ class FilterTreeView(component.Component):
# Create the treestore # Create the treestore
# cat, value, label, count, pixmap, visible # cat, value, label, count, pixmap, visible
self.treestore = gtk.TreeStore(str, str, str, int, gtk.gdk.Pixbuf, bool) self.treestore = gtk.TreeStore(str, str, str, int, Pixbuf, bool)
# Create the column and cells # Create the column and cells
column = gtk.TreeViewColumn('Filters') column = gtk.TreeViewColumn('Filters')
@ -72,7 +73,7 @@ class FilterTreeView(component.Component):
column.add_attribute(self.cell_pix, 'pixbuf', 4) column.add_attribute(self.cell_pix, 'pixbuf', 4)
# label cell # label cell
cell_label = gtk.CellRendererText() cell_label = gtk.CellRendererText()
cell_label.set_property('ellipsize', pango.ELLIPSIZE_END) cell_label.set_property('ellipsize', ELLIPSIZE_END)
column.pack_start(cell_label, expand=True) column.pack_start(cell_label, expand=True)
column.set_cell_data_func(cell_label, self.render_cell_data, None) column.set_cell_data_func(cell_label, self.render_cell_data, None)
# count cell # count cell
@ -242,26 +243,10 @@ class FilterTreeView(component.Component):
pix = TRACKER_PIX.get(value, None) pix = TRACKER_PIX.get(value, None)
if pix: if pix:
try: return get_pixbuf('%s16.png' % pix)
return gtk.gdk.pixbuf_new_from_file(get_pixmap('%s16.png' % pix))
except GError as ex:
log.warning(ex)
return self.get_transparent_pix(16, 16)
def get_transparent_pix(self, width, height):
pix = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, width, height)
pix.fill(0x0000000)
return pix
def set_row_image(self, cat, value, filename): def set_row_image(self, cat, value, filename):
pix = None pix = get_pixbuf_at_size(filename, 16)
try: # assume we could get trashed images here..
pix = gtk.gdk.pixbuf_new_from_file_at_size(filename, 16, 16)
except Exception as ex:
log.debug(ex)
if not pix:
pix = self.get_transparent_pix(16, 16)
row = self.filters[(cat, value)] row = self.filters[(cat, value)]
self.treestore.set_value(row, 4, pix) self.treestore.set_value(row, 4, pix)
return False return False

View file

@ -6,6 +6,7 @@
# the additional special exception to link portions of this program with the OpenSSL library. # the additional special exception to link portions of this program with the OpenSSL library.
# See LICENSE for more details. # See LICENSE for more details.
# #
# pylint: disable=wrong-import-position
from __future__ import division from __future__ import division
@ -19,8 +20,9 @@ import pygtk # isort:skip (Required before gtk import).
pygtk.require('2.0') # NOQA: E402 pygtk.require('2.0') # NOQA: E402
# isort:imports-thirdparty # isort:imports-thirdparty
import gtk
from gobject import set_prgname from gobject import set_prgname
from gtk import RESPONSE_OK, RESPONSE_YES
from gtk.gdk import WINDOWING, threads_enter, threads_init, threads_leave
from twisted.internet import defer, gtk2reactor from twisted.internet import defer, gtk2reactor
from twisted.internet.error import ReactorAlreadyInstalledError from twisted.internet.error import ReactorAlreadyInstalledError
from twisted.internet.task import LoopingCall from twisted.internet.task import LoopingCall
@ -33,8 +35,8 @@ except ReactorAlreadyInstalledError as ex:
from twisted.internet import reactor from twisted.internet import reactor
# isort:imports-firstparty # isort:imports-firstparty
import deluge.common
import deluge.component as component import deluge.component as component
from deluge.common import fsize, fspeed, get_default_download_dir, osx_check, windows_check
from deluge.configmanager import ConfigManager, get_config_dir from deluge.configmanager import ConfigManager, get_config_dir
from deluge.error import AuthenticationRequired, BadLoginError, DaemonRunningError from deluge.error import AuthenticationRequired, BadLoginError, DaemonRunningError
from deluge.ui.client import client from deluge.ui.client import client
@ -103,11 +105,11 @@ DEFAULT_PREFS = {
'autoconnect_host_id': None, 'autoconnect_host_id': None,
'autostart_localhost': False, 'autostart_localhost': False,
'autoadd_queued': False, 'autoadd_queued': False,
'choose_directory_dialog_path': deluge.common.get_default_download_dir(), 'choose_directory_dialog_path': get_default_download_dir(),
'show_new_releases': True, 'show_new_releases': True,
'ntf_tray_blink': True, 'ntf_tray_blink': True,
'ntf_sound': False, 'ntf_sound': False,
'ntf_sound_path': deluge.common.get_default_download_dir(), 'ntf_sound_path': get_default_download_dir(),
'ntf_popup': False, 'ntf_popup': False,
'ntf_email': False, 'ntf_email': False,
'ntf_email_add': '', 'ntf_email_add': '',
@ -144,16 +146,15 @@ class GtkUI(object):
log.debug("OS signal 'die' caught with args: %s", args) log.debug("OS signal 'die' caught with args: %s", args)
reactor.stop() reactor.stop()
if deluge.common.windows_check(): if windows_check():
from win32api import SetConsoleCtrlHandler from win32api import SetConsoleCtrlHandler
SetConsoleCtrlHandler(on_die, True) SetConsoleCtrlHandler(on_die, True)
log.debug("Win32 'die' handler registered") log.debug("Win32 'die' handler registered")
elif deluge.common.osx_check(): elif osx_check() and WINDOWING == 'quartz':
if gtk.gdk.WINDOWING == 'quartz': import gtkosx_application
import gtkosx_application self.osxapp = gtkosx_application.gtkosx_application_get()
self.osxapp = gtkosx_application.gtkosx_application_get() self.osxapp.connect('NSApplicationWillTerminate', on_die)
self.osxapp.connect('NSApplicationWillTerminate', on_die) log.debug("OSX quartz 'die' handler registered")
log.debug("OSX quartz 'die' handler registered")
# Set process name again to fix gtk issue # Set process name again to fix gtk issue
setproctitle(getproctitle()) setproctitle(getproctitle())
@ -179,7 +180,7 @@ class GtkUI(object):
self.ipcinterface = IPCInterface(args.torrents) self.ipcinterface = IPCInterface(args.torrents)
# Initialize gdk threading # Initialize gdk threading
gtk.gdk.threads_init() threads_init()
# We make sure that the UI components start once we get a core URI # We make sure that the UI components start once we get a core URI
client.set_disconnect_callback(self.__on_disconnect) client.set_disconnect_callback(self.__on_disconnect)
@ -199,7 +200,7 @@ class GtkUI(object):
self.statusbar = StatusBar() self.statusbar = StatusBar()
self.addtorrentdialog = AddTorrentDialog() self.addtorrentdialog = AddTorrentDialog()
if deluge.common.osx_check() and gtk.gdk.WINDOWING == 'quartz': if osx_check() and WINDOWING == 'quartz':
def nsapp_open_file(osxapp, filename): def nsapp_open_file(osxapp, filename):
# Ignore command name which is raised at app launch (python opening main script). # Ignore command name which is raised at app launch (python opening main script).
if filename == sys.argv[0]: if filename == sys.argv[0]:
@ -235,11 +236,11 @@ class GtkUI(object):
reactor.callWhenRunning(self._on_reactor_start) reactor.callWhenRunning(self._on_reactor_start)
# Initialize gdk threading # Initialize gdk threading
gtk.gdk.threads_enter() threads_enter()
reactor.run() reactor.run()
# Reactor is not running. Any async callbacks (Deferreds) can no longer # Reactor is not running. Any async callbacks (Deferreds) can no longer
# be processed from this point on. # be processed from this point on.
gtk.gdk.threads_leave() threads_leave()
def shutdown(self, *args, **kwargs): def shutdown(self, *args, **kwargs):
log.debug('GTKUI shutting down...') log.debug('GTKUI shutting down...')
@ -281,10 +282,9 @@ class GtkUI(object):
delta_sent = sent - self.daemon_bps[1] delta_sent = sent - self.daemon_bps[1]
delta_recv = recv - self.daemon_bps[2] delta_recv = recv - self.daemon_bps[2]
self.daemon_bps = (t, sent, recv) self.daemon_bps = (t, sent, recv)
sent_rate = deluge.common.fspeed(delta_sent / delta_time) sent_rate = fspeed(delta_sent / delta_time)
recv_rate = deluge.common.fspeed(delta_recv / delta_time) recv_rate = fspeed(delta_recv / delta_time)
log.debug('RPC: Sent %s (%s) Recv %s (%s)', log.debug('RPC: Sent %s (%s) Recv %s (%s)', fsize(sent), sent_rate, fsize(recv), recv_rate)
deluge.common.fsize(sent), sent_rate, deluge.common.fsize(recv), recv_rate)
def _on_reactor_start(self): def _on_reactor_start(self):
log.debug('_on_reactor_start') log.debug('_on_reactor_start')
@ -292,7 +292,7 @@ class GtkUI(object):
if self.config['standalone']: if self.config['standalone']:
def on_dialog_response(response): def on_dialog_response(response):
if response != gtk.RESPONSE_YES: if response != RESPONSE_YES:
# The user does not want to turn Standalone Mode off, so just quit # The user does not want to turn Standalone Mode off, so just quit
self.mainwindow.quit() self.mainwindow.quit()
return return
@ -395,7 +395,7 @@ class GtkUI(object):
dialog = AuthenticationDialog(reason.value.message, reason.value.username) dialog = AuthenticationDialog(reason.value.message, reason.value.username)
def dialog_finished(response_id, host, port): def dialog_finished(response_id, host, port):
if response_id == gtk.RESPONSE_OK: if response_id == RESPONSE_OK:
reactor.callLater( reactor.callLater(
0.5, do_connect, try_counter - 1, 0.5, do_connect, try_counter - 1,
host, port, dialog.get_username(), host, port, dialog.get_username(),
@ -425,7 +425,7 @@ class GtkUI(object):
break break
if self.config['show_connection_manager_on_start']: if self.config['show_connection_manager_on_start']:
if deluge.common.windows_check(): if windows_check():
# Call to simulate() required to workaround showing daemon status (see #2813) # Call to simulate() required to workaround showing daemon status (see #2813)
reactor.simulate() reactor.simulate()
self.connectionmanager.show() self.connectionmanager.show()

View file

@ -144,8 +144,8 @@ class IPCInterface(component.Component):
reactor.run() reactor.run()
if self.factory.stop: if self.factory.stop:
log.info('Success sending arguments to running Deluge.') log.info('Success sending arguments to running Deluge.')
import gtk from gtk.gdk import notify_startup_complete
gtk.gdk.notify_startup_complete() notify_startup_complete()
sys.exit(0) sys.exit(0)
else: else:
if restart_tempfile: if restart_tempfile:

View file

@ -11,10 +11,11 @@ import logging
import gtk import gtk
from gobject import SIGNAL_RUN_LAST, TYPE_NONE, signal_new from gobject import SIGNAL_RUN_LAST, TYPE_NONE, signal_new
from gtk.gdk import Event # pylint: disable=ungrouped-imports
from deluge.ui.gtkui.common import load_pickled_state_file, save_pickled_state_file from deluge.ui.gtkui.common import load_pickled_state_file, save_pickled_state_file
signal_new('button-press-event', gtk.TreeViewColumn, SIGNAL_RUN_LAST, TYPE_NONE, (gtk.gdk.Event,)) signal_new('button-press-event', gtk.TreeViewColumn, SIGNAL_RUN_LAST, TYPE_NONE, (Event,))
log = logging.getLogger(__name__) log = logging.getLogger(__name__)

View file

@ -13,12 +13,13 @@ import os.path
from hashlib import sha1 as sha from hashlib import sha1 as sha
import gtk import gtk
from gtk.gdk import ACTION_COPY, WINDOW_STATE_ICONIFIED, WINDOW_STATE_MAXIMIZED, WINDOW_STATE_WITHDRAWN
from twisted.internet import reactor from twisted.internet import reactor
from twisted.internet.error import ReactorNotRunning from twisted.internet.error import ReactorNotRunning
import deluge.common
import deluge.component as component import deluge.component as component
import deluge.ui.gtkui.common import deluge.ui.gtkui.common
from deluge.common import fspeed, resource_filename
from deluge.configmanager import ConfigManager from deluge.configmanager import ConfigManager
from deluge.ui.client import client from deluge.ui.client import client
from deluge.ui.gtkui.dialogs import PasswordDialog from deluge.ui.gtkui.dialogs import PasswordDialog
@ -73,27 +74,21 @@ class MainWindow(component.Component):
"'component.get(\"MainWindow\").connect_signals()'") "'component.get(\"MainWindow\").connect_signals()'")
self.main_builder.connect_signals = patched_connect_signals self.main_builder.connect_signals = patched_connect_signals
# Get the gtk builder file for the main window # Get Gtk Builder files Main Window, New release dialog, and Tabs.
self.main_builder.add_from_file(deluge.common.resource_filename( self.main_builder.add_from_file(resource_filename('deluge.ui.gtkui', os.path.join(
'deluge.ui.gtkui', os.path.join('glade', 'main_window.ui'))) 'glade', 'main_window.ui')))
# The new release dialog self.main_builder.add_from_file(resource_filename('deluge.ui.gtkui', os.path.join(
self.main_builder.add_from_file(deluge.common.resource_filename( 'glade', 'main_window.new_release.ui')))
'deluge.ui.gtkui', os.path.join('glade', 'main_window.new_release.ui'))) self.main_builder.add_from_file(resource_filename('deluge.ui.gtkui', os.path.join(
# The tabs 'glade', 'main_window.tabs.ui')))
self.main_builder.add_from_file(deluge.common.resource_filename( self.main_builder.add_from_file(resource_filename('deluge.ui.gtkui', os.path.join(
'deluge.ui.gtkui', os.path.join('glade', 'main_window.tabs.ui'))) 'glade', 'main_window.tabs.menu_file.ui')))
# The tabs file menu self.main_builder.add_from_file(resource_filename('deluge.ui.gtkui', os.path.join(
self.main_builder.add_from_file(deluge.common.resource_filename( 'glade', 'main_window.tabs.menu_peer.ui')))
'deluge.ui.gtkui', os.path.join('glade', 'main_window.tabs.menu_file.ui')))
# The tabs peer menu
self.main_builder.add_from_file(deluge.common.resource_filename(
'deluge.ui.gtkui', os.path.join('glade', 'main_window.tabs.menu_peer.ui')))
self.window = self.main_builder.get_object('main_window') self.window = self.main_builder.get_object('main_window')
self.window.set_icon(deluge.ui.gtkui.common.get_deluge_icon()) self.window.set_icon(deluge.ui.gtkui.common.get_deluge_icon())
self.vpaned = self.main_builder.get_object('vpaned') self.vpaned = self.main_builder.get_object('vpaned')
self.initial_vpaned_position = self.config['window_pane_position'] self.initial_vpaned_position = self.config['window_pane_position']
# Load the window state # Load the window state
@ -104,7 +99,7 @@ class MainWindow(component.Component):
self.is_minimized = False self.is_minimized = False
self.restart = False self.restart = False
self.window.drag_dest_set(gtk.DEST_DEFAULT_ALL, [('text/uri-list', 0, 80)], gtk.gdk.ACTION_COPY) self.window.drag_dest_set(gtk.DEST_DEFAULT_ALL, [('text/uri-list', 0, 80)], ACTION_COPY)
# Connect events # Connect events
self.window.connect('window-state-event', self.on_window_state_event) self.window.connect('window-state-event', self.on_window_state_event)
@ -252,14 +247,14 @@ class MainWindow(component.Component):
self.config['window_height'] = event.height self.config['window_height'] = event.height
def on_window_state_event(self, widget, event): def on_window_state_event(self, widget, event):
if event.changed_mask & gtk.gdk.WINDOW_STATE_MAXIMIZED: if event.changed_mask & WINDOW_STATE_MAXIMIZED:
if event.new_window_state & gtk.gdk.WINDOW_STATE_MAXIMIZED: if event.new_window_state & WINDOW_STATE_MAXIMIZED:
log.debug('pos: %s', self.window.get_position()) log.debug('pos: %s', self.window.get_position())
self.config['window_maximized'] = True self.config['window_maximized'] = True
elif not event.new_window_state & gtk.gdk.WINDOW_STATE_WITHDRAWN: elif not event.new_window_state & WINDOW_STATE_WITHDRAWN:
self.config['window_maximized'] = False self.config['window_maximized'] = False
if event.changed_mask & gtk.gdk.WINDOW_STATE_ICONIFIED: if event.changed_mask & WINDOW_STATE_ICONIFIED:
if event.new_window_state & gtk.gdk.WINDOW_STATE_ICONIFIED: if event.new_window_state & WINDOW_STATE_ICONIFIED:
log.debug('MainWindow is minimized..') log.debug('MainWindow is minimized..')
component.pause('TorrentView') component.pause('TorrentView')
component.pause('StatusBar') component.pause('StatusBar')
@ -302,8 +297,8 @@ class MainWindow(component.Component):
def update(self): def update(self):
# Update the window title # Update the window title
def _on_get_session_status(status): def _on_get_session_status(status):
download_rate = deluge.common.fspeed(status['payload_download_rate'], precision=0, shortform=True) download_rate = fspeed(status['payload_download_rate'], precision=0, shortform=True)
upload_rate = deluge.common.fspeed(status['payload_upload_rate'], precision=0, shortform=True) upload_rate = fspeed(status['payload_upload_rate'], precision=0, shortform=True)
self.window.set_title(_('D: %s U: %s - Deluge' % (download_rate, upload_rate))) self.window.set_title(_('D: %s U: %s - Deluge' % (download_rate, upload_rate)))
if self.config['show_rate_in_title']: if self.config['show_rate_in_title']:
client.core.get_session_status(['payload_download_rate', client.core.get_session_status(['payload_download_rate',

View file

@ -7,24 +7,25 @@
# See LICENSE for more details. # See LICENSE for more details.
# #
import gtk from gtk import ACCEL_VISIBLE, SeparatorMenuItem, accel_groups_from_object
from gtk.gdk import CONTROL_MASK, META_MASK, SHIFT_MASK
from deluge.configmanager import ConfigManager from deluge.configmanager import ConfigManager
def accel_swap(item, group, skey, smod, dkey, dmod): def accel_swap(item, group, skey, smod, dkey, dmod):
item.remove_accelerator(group, ord(skey), smod) item.remove_accelerator(group, ord(skey), smod)
item.add_accelerator('activate', group, ord(dkey), dmod, gtk.ACCEL_VISIBLE) item.add_accelerator('activate', group, ord(dkey), dmod, ACCEL_VISIBLE)
def accel_meta(item, group, key): def accel_meta(item, group, key):
accel_swap(item, group, key, gtk.gdk.CONTROL_MASK, key, gtk.gdk.META_MASK) accel_swap(item, group, key, CONTROL_MASK, key, META_MASK)
def menubar_osx(gtkui, osxapp): def menubar_osx(gtkui, osxapp):
main_builder = gtkui.mainwindow.get_builder() main_builder = gtkui.mainwindow.get_builder()
menubar = main_builder.get_object('menubar') menubar = main_builder.get_object('menubar')
group = gtk.accel_groups_from_object(gtkui.mainwindow.get_window())[0] group = accel_groups_from_object(gtkui.mainwindow.get_window())[0]
config = ConfigManager('gtkui.conf') config = ConfigManager('gtkui.conf')
@ -37,8 +38,7 @@ def menubar_osx(gtkui, osxapp):
accel_meta(file_items[0], group, 'o') accel_meta(file_items[0], group, 'o')
accel_meta(file_items[1], group, 'n') accel_meta(file_items[1], group, 'n')
quit_all_item = file_items[3] quit_all_item = file_items[3]
accel_swap(quit_all_item, group, 'q', gtk.gdk.SHIFT_MASK | gtk.gdk.CONTROL_MASK, accel_swap(quit_all_item, group, 'q', SHIFT_MASK | CONTROL_MASK, 'q', SHIFT_MASK | META_MASK)
'q', gtk.gdk.SHIFT_MASK | gtk.gdk.META_MASK)
for item in range(2, len(file_items)): # remove quits for item in range(2, len(file_items)): # remove quits
file_menu.remove(file_items[item]) file_menu.remove(file_items[item])
@ -46,7 +46,7 @@ def menubar_osx(gtkui, osxapp):
edit_menu = menu_widget.get_submenu() edit_menu = menu_widget.get_submenu()
edit_items = edit_menu.get_children() edit_items = edit_menu.get_children()
pref_item = edit_items[0] pref_item = edit_items[0]
accel_swap(pref_item, group, 'p', gtk.gdk.CONTROL_MASK, ',', gtk.gdk.META_MASK) accel_swap(pref_item, group, 'p', CONTROL_MASK, ',', META_MASK)
edit_menu.remove(pref_item) edit_menu.remove(pref_item)
conn_item = edit_items[1] conn_item = edit_items[1]
@ -65,10 +65,10 @@ def menubar_osx(gtkui, osxapp):
osxapp.set_menu_bar(menubar) osxapp.set_menu_bar(menubar)
# populate app menu # populate app menu
osxapp.insert_app_menu_item(about_item, 0) osxapp.insert_app_menu_item(about_item, 0)
osxapp.insert_app_menu_item(gtk.SeparatorMenuItem(), 1) osxapp.insert_app_menu_item(SeparatorMenuItem(), 1)
osxapp.insert_app_menu_item(pref_item, 2) osxapp.insert_app_menu_item(pref_item, 2)
if not config['standalone']: if not config['standalone']:
osxapp.insert_app_menu_item(conn_item, 3) osxapp.insert_app_menu_item(conn_item, 3)
if quit_all_item.get_visible(): if quit_all_item.get_visible():
osxapp.insert_app_menu_item(gtk.SeparatorMenuItem(), 4) osxapp.insert_app_menu_item(SeparatorMenuItem(), 4)
osxapp.insert_app_menu_item(quit_all_item, 5) osxapp.insert_app_menu_item(quit_all_item, 5)

View file

@ -7,7 +7,7 @@
# See LICENSE for more details. # See LICENSE for more details.
# #
import gtk.gdk from gtk.gdk import keyval_name
import deluge.component as component import deluge.component as component
from deluge.ui.client import client from deluge.ui.client import client
@ -220,7 +220,7 @@ class OptionsTab(Tab):
self.button_apply.set_sensitive(True) self.button_apply.set_sensitive(True)
def _on_key_press_event(self, widget, event): def _on_key_press_event(self, widget, event):
keyname = gtk.gdk.keyval_name(event.keyval).lstrip('KP_').lower() keyname = keyval_name(event.keyval).lstrip('KP_').lower()
if keyname.isdigit() or keyname in ['period', 'minus', 'delete', 'backspace']: if keyname.isdigit() or keyname in ['period', 'minus', 'delete', 'backspace']:
if not self.button_apply.is_sensitive(): if not self.button_apply.is_sensitive():
self.button_apply.set_sensitive(True) self.button_apply.set_sensitive(True)

View file

@ -14,7 +14,7 @@ import os
import gtk import gtk
from gobject import SIGNAL_RUN_FIRST, TYPE_NONE, GObject, type_register from gobject import SIGNAL_RUN_FIRST, TYPE_NONE, GObject, type_register
from gtk import gdk, keysyms from gtk import gdk, keysyms # pylint: disable=ungrouped-imports
import deluge.component as component import deluge.component as component
from deluge.common import resource_filename from deluge.common import resource_filename
@ -215,8 +215,8 @@ class ValueList(object):
if event.button != 3: if event.button != 3:
# Double clicked a row, set this as the entry value # Double clicked a row, set this as the entry value
# and close the popup # and close the popup
if (double_click and event.type == gtk.gdk._2BUTTON_PRESS) or\ if (double_click and event.type == gdk._2BUTTON_PRESS) or\
(not double_click and event.type == gtk.gdk.BUTTON_PRESS): (not double_click and event.type == gdk.BUTTON_PRESS):
path = self.get_selection_path() path = self.get_selection_path()
if path: if path:
self.set_entry_value(path, popdown=True) self.set_entry_value(path, popdown=True)
@ -413,7 +413,7 @@ class StoredValuesList(ValueList):
""" """
keyval = event.keyval keyval = event.keyval
ctrl = event.get_state() & gtk.gdk.CONTROL_MASK ctrl = event.get_state() & gdk.CONTROL_MASK
# Edit selected row # Edit selected row
if (keyval in [keysyms.Left, keysyms.Right, keysyms.space]): if (keyval in [keysyms.Left, keysyms.Right, keysyms.space]):
@ -422,7 +422,7 @@ class StoredValuesList(ValueList):
self.on_edit_path(path, self.tree_column) self.on_edit_path(path, self.tree_column)
elif key_is_up_or_down(keyval): elif key_is_up_or_down(keyval):
# Swap the row value # Swap the row value
if event.get_state() & gtk.gdk.CONTROL_MASK: if event.get_state() & gdk.CONTROL_MASK:
self.handle_list_scroll(_next=key_is_down(keyval), self.handle_list_scroll(_next=key_is_down(keyval),
swap=True) swap=True)
else: else:
@ -483,7 +483,7 @@ class CompletionList(ValueList):
if ret: if ret:
return ret return ret
keyval = event.keyval keyval = event.keyval
ctrl = event.get_state() & gtk.gdk.CONTROL_MASK ctrl = event.get_state() & gdk.CONTROL_MASK
if key_is_up_or_down(keyval): if key_is_up_or_down(keyval):
self.handle_list_scroll(_next=key_is_down(keyval)) self.handle_list_scroll(_next=key_is_down(keyval))
return True return True
@ -774,8 +774,8 @@ class StoredValuesPopup(StoredValuesList, PathChooserPopup):
Handles scroll events from text entry, toggle button and treeview Handles scroll events from text entry, toggle button and treeview
""" """
swap = event.get_state() & gtk.gdk.CONTROL_MASK swap = event.get_state() & gdk.CONTROL_MASK
scroll_window = event.get_state() & gtk.gdk.SHIFT_MASK scroll_window = event.get_state() & gdk.SHIFT_MASK
self.handle_list_scroll(_next=event.direction == gdk.SCROLL_DOWN, self.handle_list_scroll(_next=event.direction == gdk.SCROLL_DOWN,
set_entry=widget != self.treeview, swap=swap, scroll_window=scroll_window) set_entry=widget != self.treeview, swap=swap, scroll_window=scroll_window)
return True return True
@ -1294,7 +1294,7 @@ class PathChooserComboBox(gtk.HBox, StoredValuesPopup, GObject):
""" """
keyval = event.keyval keyval = event.keyval
state = event.get_state() & gtk.accelerator_get_default_mod_mask() state = event.get_state() & gtk.accelerator_get_default_mod_mask()
ctrl = event.get_state() & gtk.gdk.CONTROL_MASK ctrl = event.get_state() & gdk.CONTROL_MASK
# Select new row with arrow up/down is pressed # Select new row with arrow up/down is pressed
if key_is_up_or_down(keyval): if key_is_up_or_down(keyval):
@ -1458,7 +1458,7 @@ class PathChooserComboBox(gtk.HBox, StoredValuesPopup, GObject):
return True return True
else: else:
keyval = event.keyval keyval = event.keyval
ctrl = event.get_state() & gtk.gdk.CONTROL_MASK ctrl = event.get_state() & gdk.CONTROL_MASK
if ctrl: if ctrl:
# Set show/hide hidden files # Set show/hide hidden files
if is_ascii_value(keyval, 'h'): if is_ascii_value(keyval, 'h'):

View file

@ -11,25 +11,21 @@ import logging
import os.path import os.path
from future_builtins import zip from future_builtins import zip
import gtk from gtk import (TREE_VIEW_COLUMN_FIXED, Builder, CellRendererPixbuf, CellRendererProgress, CellRendererText, ListStore,
TreeViewColumn)
from gtk.gdk import Pixbuf, pixbuf_new_from_file
import deluge.common import deluge.common
import deluge.component as component import deluge.component as component
from deluge.ui.client import client from deluge.ui.client import client
from deluge.ui.countries import COUNTRIES from deluge.ui.countries import COUNTRIES
from deluge.ui.gtkui.common import load_pickled_state_file, save_pickled_state_file from deluge.ui.gtkui.common import icon_downloading, icon_seeding, load_pickled_state_file, save_pickled_state_file
from deluge.ui.gtkui.torrentdetails import Tab from deluge.ui.gtkui.torrentdetails import Tab
from deluge.ui.gtkui.torrentview_data_funcs import cell_data_speed_down, cell_data_speed_up from deluge.ui.gtkui.torrentview_data_funcs import cell_data_peer_progress, cell_data_speed_down, cell_data_speed_up
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
def cell_data_progress(column, cell, model, row, data):
value = model.get_value(row, data) * 100
cell.set_property('value', value)
cell.set_property('text', '%i%%' % value)
class PeersTab(Tab): class PeersTab(Tab):
def __init__(self): def __init__(self):
Tab.__init__(self) Tab.__init__(self)
@ -48,18 +44,18 @@ class PeersTab(Tab):
self.listview.connect('button-press-event', self._on_button_press_event) self.listview.connect('button-press-event', self._on_button_press_event)
self.listview.connect('query-tooltip', self._on_query_tooltip) self.listview.connect('query-tooltip', self._on_query_tooltip)
# country pixbuf, ip, client, downspeed, upspeed, country code, int_ip, seed/peer icon, progress # country pixbuf, ip, client, downspeed, upspeed, country code, int_ip, seed/peer icon, progress
self.liststore = gtk.ListStore(gtk.gdk.Pixbuf, str, str, int, int, str, float, gtk.gdk.Pixbuf, float) self.liststore = ListStore(Pixbuf, str, str, int, int, str, float, Pixbuf, float)
self.cached_flag_pixbufs = {} self.cached_flag_pixbufs = {}
self.seed_pixbuf = gtk.gdk.pixbuf_new_from_file(deluge.common.get_pixmap('seeding16.png')) self.seed_pixbuf = icon_seeding
self.peer_pixbuf = gtk.gdk.pixbuf_new_from_file(deluge.common.get_pixmap('downloading16.png')) self.peer_pixbuf = icon_downloading
# key is ip address, item is row iter # key is ip address, item is row iter
self.peers = {} self.peers = {}
# Country column # Country column
column = gtk.TreeViewColumn() column = TreeViewColumn()
render = gtk.CellRendererPixbuf() render = CellRendererPixbuf()
column.pack_start(render, False) column.pack_start(render, False)
column.add_attribute(render, 'pixbuf', 0) column.add_attribute(render, 'pixbuf', 0)
column.set_sort_column_id(5) column.set_sort_column_id(5)
@ -71,11 +67,11 @@ class PeersTab(Tab):
self.listview.append_column(column) self.listview.append_column(column)
# Address column # Address column
column = gtk.TreeViewColumn(_('Address')) column = TreeViewColumn(_('Address'))
render = gtk.CellRendererPixbuf() render = CellRendererPixbuf()
column.pack_start(render, False) column.pack_start(render, False)
column.add_attribute(render, 'pixbuf', 7) column.add_attribute(render, 'pixbuf', 7)
render = gtk.CellRendererText() render = CellRendererText()
column.pack_start(render, False) column.pack_start(render, False)
column.add_attribute(render, 'text', 1) column.add_attribute(render, 'text', 1)
column.set_sort_column_id(6) column.set_sort_column_id(6)
@ -87,8 +83,8 @@ class PeersTab(Tab):
self.listview.append_column(column) self.listview.append_column(column)
# Client column # Client column
column = gtk.TreeViewColumn(_('Client')) column = TreeViewColumn(_('Client'))
render = gtk.CellRendererText() render = CellRendererText()
column.pack_start(render, False) column.pack_start(render, False)
column.add_attribute(render, 'text', 2) column.add_attribute(render, 'text', 2)
column.set_sort_column_id(2) column.set_sort_column_id(2)
@ -100,10 +96,10 @@ class PeersTab(Tab):
self.listview.append_column(column) self.listview.append_column(column)
# Progress column # Progress column
column = gtk.TreeViewColumn(_('Progress')) column = TreeViewColumn(_('Progress'))
render = gtk.CellRendererProgress() render = CellRendererProgress()
column.pack_start(render, True) column.pack_start(render, True)
column.set_cell_data_func(render, cell_data_progress, 8) column.set_cell_data_func(render, cell_data_peer_progress, 8)
column.set_sort_column_id(8) column.set_sort_column_id(8)
column.set_clickable(True) column.set_clickable(True)
column.set_resizable(True) column.set_resizable(True)
@ -113,8 +109,8 @@ class PeersTab(Tab):
self.listview.append_column(column) self.listview.append_column(column)
# Down Speed column # Down Speed column
column = gtk.TreeViewColumn(_('Down Speed')) column = TreeViewColumn(_('Down Speed'))
render = gtk.CellRendererText() render = CellRendererText()
column.pack_start(render, False) column.pack_start(render, False)
column.set_cell_data_func(render, cell_data_speed_down, 3) column.set_cell_data_func(render, cell_data_speed_down, 3)
column.set_sort_column_id(3) column.set_sort_column_id(3)
@ -126,8 +122,8 @@ class PeersTab(Tab):
self.listview.append_column(column) self.listview.append_column(column)
# Up Speed column # Up Speed column
column = gtk.TreeViewColumn(_('Up Speed')) column = TreeViewColumn(_('Up Speed'))
render = gtk.CellRendererText() render = CellRendererText()
column.pack_start(render, False) column.pack_start(render, False)
column.set_cell_data_func(render, cell_data_speed_up, 4) column.set_cell_data_func(render, cell_data_speed_up, 4)
column.set_sort_column_id(4) column.set_sort_column_id(4)
@ -181,7 +177,7 @@ class PeersTab(Tab):
cname = column.get_title() cname = column.get_title()
if cname in state['columns']: if cname in state['columns']:
cstate = state['columns'][cname] cstate = state['columns'][cname]
column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) column.set_sizing(TREE_VIEW_COLUMN_FIXED)
column.set_fixed_width(cstate['width'] if cstate['width'] > 0 else 10) column.set_fixed_width(cstate['width'] if cstate['width'] > 0 else 10)
if state['sort_id'] == index and state['sort_order'] is not None: if state['sort_id'] == index and state['sort_order'] is not None:
column.set_sort_indicator(True) column.set_sort_indicator(True)
@ -220,7 +216,7 @@ class PeersTab(Tab):
if country not in self.cached_flag_pixbufs: if country not in self.cached_flag_pixbufs:
# We haven't created a pixbuf for this country yet # We haven't created a pixbuf for this country yet
try: try:
self.cached_flag_pixbufs[country] = gtk.gdk.pixbuf_new_from_file( self.cached_flag_pixbufs[country] = pixbuf_new_from_file(
deluge.common.resource_filename( deluge.common.resource_filename(
'deluge', 'deluge',
os.path.join('ui', 'data', 'pixmaps', 'flags', country.lower() + '.png'))) os.path.join('ui', 'data', 'pixmaps', 'flags', country.lower() + '.png')))
@ -330,7 +326,7 @@ class PeersTab(Tab):
def _on_menuitem_add_peer_activate(self, menuitem): def _on_menuitem_add_peer_activate(self, menuitem):
"""This is a callback for manually adding a peer""" """This is a callback for manually adding a peer"""
log.debug('on_menuitem_add_peer') log.debug('on_menuitem_add_peer')
builder = gtk.Builder() builder = Builder()
builder.add_from_file(deluge.common.resource_filename( builder.add_from_file(deluge.common.resource_filename(
'deluge.ui.gtkui', os.path.join('glade', 'connect_peer_dialog.ui') 'deluge.ui.gtkui', os.path.join('glade', 'connect_peer_dialog.ui')
)) ))

View file

@ -11,27 +11,28 @@ from __future__ import division
from math import pi from math import pi
import gtk
import pango
import pangocairo
from cairo import FORMAT_ARGB32, Context, ImageSurface from cairo import FORMAT_ARGB32, Context, ImageSurface
from gtk import DrawingArea, ProgressBar
from gtk.gdk import colormap_get_system
from pango import SCALE, WEIGHT_BOLD
from pangocairo import CairoContext
from deluge.configmanager import ConfigManager from deluge.configmanager import ConfigManager
COLOR_STATES = ['missing', 'waiting', 'downloading', 'completed'] COLOR_STATES = ['missing', 'waiting', 'downloading', 'completed']
class PiecesBar(gtk.DrawingArea): class PiecesBar(DrawingArea):
# Draw in response to an expose-event # Draw in response to an expose-event
__gsignals__ = {'expose-event': 'override'} __gsignals__ = {'expose-event': 'override'}
def __init__(self): def __init__(self):
gtk.DrawingArea.__init__(self) DrawingArea.__init__(self)
# Get progress bar styles, in order to keep font consistency # Get progress bar styles, in order to keep font consistency
pb = gtk.ProgressBar() pb = ProgressBar()
pb_style = pb.get_style() pb_style = pb.get_style()
self.text_font = pb_style.font_desc self.text_font = pb_style.font_desc
self.text_font.set_weight(pango.WEIGHT_BOLD) self.text_font.set_weight(WEIGHT_BOLD)
# Done with the ProgressBar styles, don't keep refs of it # Done with the ProgressBar styles, don't keep refs of it
del pb, pb_style del pb, pb_style
@ -48,7 +49,7 @@ class PiecesBar(gtk.DrawingArea):
self.cr = None self.cr = None
self.connect('size-allocate', self.do_size_allocate_event) self.connect('size-allocate', self.do_size_allocate_event)
self.set_colormap(gtk.gdk.colormap_get_system()) self.set_colormap(colormap_get_system())
self.show() self.show()
def do_size_allocate_event(self, widget, size): def do_size_allocate_event(self, widget, size):
@ -151,14 +152,14 @@ class PiecesBar(gtk.DrawingArea):
# Need to recreate the cache drawing # Need to recreate the cache drawing
self.text_overlay = ImageSurface(FORMAT_ARGB32, self.width, self.height) self.text_overlay = ImageSurface(FORMAT_ARGB32, self.width, self.height)
ctx = Context(self.text_overlay) ctx = Context(self.text_overlay)
pg = pangocairo.CairoContext(ctx) pg = CairoContext(ctx)
pl = pg.create_layout() pl = pg.create_layout()
pl.set_font_description(self.text_font) pl.set_font_description(self.text_font)
pl.set_width(-1) # No text wrapping pl.set_width(-1) # No text wrapping
pl.set_text(self.text) pl.set_text(self.text)
plsize = pl.get_size() plsize = pl.get_size()
text_width = plsize[0] // pango.SCALE text_width = plsize[0] // SCALE
text_height = plsize[1] // pango.SCALE text_height = plsize[1] // SCALE
area_width_without_text = self.width - text_width area_width_without_text = self.width - text_width
area_height_without_text = self.height - text_height area_height_without_text = self.height - text_height
ctx.move_to(area_width_without_text // 2, area_height_without_text // 2) ctx.move_to(area_width_without_text // 2, area_height_without_text // 2)

View file

@ -13,6 +13,7 @@ import os
from hashlib import sha1 as sha from hashlib import sha1 as sha
import gtk import gtk
from gtk.gdk import Color
import deluge.common import deluge.common
import deluge.component as component import deluge.component as component
@ -1163,7 +1164,7 @@ class Preferences(component.Component):
def __set_color(self, state, from_config=False): def __set_color(self, state, from_config=False):
if from_config: if from_config:
color = gtk.gdk.Color(*self.gtkui_config['pieces_color_%s' % state]) color = Color(*self.gtkui_config['pieces_color_%s' % state])
log.debug('Setting %r color state from config to %s', state, (color.red, color.green, color.blue)) log.debug('Setting %r color state from config to %s', state, (color.red, color.green, color.blue))
self.builder.get_object('%s_color' % state).set_color(color) self.builder.get_object('%s_color' % state).set_color(color)
else: else:
@ -1178,6 +1179,6 @@ class Preferences(component.Component):
def __revert_color(self, state, from_config=False): def __revert_color(self, state, from_config=False):
log.debug('Reverting %r color state', state) log.debug('Reverting %r color state', state)
self.builder.get_object('%s_color' % state).set_color(gtk.gdk.Color(*self.COLOR_DEFAULTS[state])) self.builder.get_object('%s_color' % state).set_color(Color(*self.COLOR_DEFAULTS[state]))
self.builder.get_object('revert_color_%s' % state).set_sensitive(False) self.builder.get_object('revert_color_%s' % state).set_sensitive(False)
self.gtkui_config.apply_set_functions('pieces_colors') self.gtkui_config.apply_set_functions('pieces_colors')

View file

@ -10,8 +10,8 @@
import logging import logging
import os.path import os.path
import gtk
from gobject import timeout_add from gobject import timeout_add
from gtk import STOCK_SORT_DESCENDING, Builder, CellRendererText, ListStore, TreeViewColumn
import deluge.common import deluge.common
import deluge.component as component import deluge.component as component
@ -29,7 +29,7 @@ class QueuedTorrents(component.Component):
self.status_item = None self.status_item = None
self.config = ConfigManager('gtkui.conf') self.config = ConfigManager('gtkui.conf')
self.builder = gtk.Builder() self.builder = Builder()
self.builder.add_from_file(deluge.common.resource_filename( self.builder.add_from_file(deluge.common.resource_filename(
'deluge.ui.gtkui', os.path.join('glade', 'queuedtorrents.ui'))) 'deluge.ui.gtkui', os.path.join('glade', 'queuedtorrents.ui')))
self.builder.get_object('chk_autoadd').set_active(self.config['autoadd_queued']) self.builder.get_object('chk_autoadd').set_active(self.config['autoadd_queued'])
@ -45,10 +45,9 @@ class QueuedTorrents(component.Component):
}) })
self.treeview = self.builder.get_object('treeview') self.treeview = self.builder.get_object('treeview')
self.treeview.append_column( self.treeview.append_column(TreeViewColumn(_('Torrent'), CellRendererText(), text=0))
gtk.TreeViewColumn(_('Torrent'), gtk.CellRendererText(), text=0))
self.liststore = gtk.ListStore(str, str) self.liststore = ListStore(str, str)
self.treeview.set_model(self.liststore) self.treeview.set_model(self.liststore)
self.treeview.set_tooltip_column(1) self.treeview.set_tooltip_column(1)
@ -120,7 +119,7 @@ class QueuedTorrents(component.Component):
# have already been added. # have already been added.
if self.status_item is None: if self.status_item is None:
self.status_item = component.get('StatusBar').add_item( self.status_item = component.get('StatusBar').add_item(
stock=gtk.STOCK_SORT_DESCENDING, stock=STOCK_SORT_DESCENDING,
text=label, text=label,
callback=self.on_statusbar_click) callback=self.on_statusbar_click)
else: else:

View file

@ -10,7 +10,7 @@
import logging import logging
import gtk from gtk import POLICY_AUTOMATIC, Label, ScrolledWindow
import deluge.component as component import deluge.component as component
from deluge.configmanager import ConfigManager from deluge.configmanager import ConfigManager
@ -58,10 +58,10 @@ class SideBar(component.Component):
"""Adds a tab object to the notebook.""" """Adds a tab object to the notebook."""
log.debug('add tab: %s', tab_name) log.debug('add tab: %s', tab_name)
self.tabs[tab_name] = widget self.tabs[tab_name] = widget
scrolled = gtk.ScrolledWindow() scrolled = ScrolledWindow()
scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scrolled.set_policy(POLICY_AUTOMATIC, POLICY_AUTOMATIC)
scrolled.add(widget) scrolled.add(widget)
self.notebook.insert_page(scrolled, gtk.Label(label), -1) self.notebook.insert_page(scrolled, Label(label), -1)
scrolled.show_all() scrolled.show_all()
self.after_update() self.after_update()

View file

@ -10,11 +10,11 @@
import logging import logging
import os import os
import gtk from gtk import (Builder, RadioMenuItem, status_icon_new_from_icon_name, status_icon_new_from_pixbuf,
status_icon_position_menu)
import deluge.common
import deluge.component as component import deluge.component as component
from deluge.common import fspeed from deluge.common import fspeed, get_pixmap, osx_check, resource_filename, windows_check
from deluge.configmanager import ConfigManager from deluge.configmanager import ConfigManager
from deluge.ui.client import client from deluge.ui.client import client
from deluge.ui.gtkui import dialogs from deluge.ui.gtkui import dialogs
@ -63,9 +63,9 @@ class SystemTray(component.Component):
def enable(self): def enable(self):
"""Enables the system tray icon.""" """Enables the system tray icon."""
self.builder = gtk.Builder() self.builder = Builder()
self.builder.add_from_file(deluge.common.resource_filename( self.builder.add_from_file(resource_filename('deluge.ui.gtkui', os.path.join(
'deluge.ui.gtkui', os.path.join('glade', 'tray_menu.ui'))) 'glade', 'tray_menu.ui')))
self.builder.connect_signals({ self.builder.connect_signals({
'on_menuitem_show_deluge_activate': self.on_menuitem_show_deluge_activate, 'on_menuitem_show_deluge_activate': self.on_menuitem_show_deluge_activate,
@ -103,18 +103,16 @@ class SystemTray(component.Component):
else: else:
log.debug('Enabling the system tray icon..') log.debug('Enabling the system tray icon..')
if deluge.common.windows_check() or deluge.common.osx_check(): if windows_check():
self.tray = gtk.status_icon_new_from_pixbuf(get_logo(32)) self.tray = status_icon_new_from_pixbuf(get_logo(32))
else: else:
self.tray = gtk.status_icon_new_from_icon_name('deluge') self.tray = status_icon_new_from_icon_name('deluge')
self.tray.connect('activate', self.on_tray_clicked) self.tray.connect('activate', self.on_tray_clicked)
self.tray.connect('popup-menu', self.on_tray_popup) self.tray.connect('popup-menu', self.on_tray_popup)
self.builder.get_object('download-limit-image').set_from_file( self.builder.get_object('download-limit-image').set_from_file(get_pixmap('downloading16.png'))
deluge.common.get_pixmap('downloading16.png')) self.builder.get_object('upload-limit-image').set_from_file(get_pixmap('seeding16.png'))
self.builder.get_object('upload-limit-image').set_from_file(
deluge.common.get_pixmap('seeding16.png'))
client.register_event_handler('ConfigValueChangedEvent', self.config_value_changed) client.register_event_handler('ConfigValueChangedEvent', self.config_value_changed)
if client.connected(): if client.connected():
@ -319,8 +317,8 @@ class SystemTray(component.Component):
else: else:
self.builder.get_object('menuitem_show_deluge').set_active(False) self.builder.get_object('menuitem_show_deluge').set_active(False)
popup_function = gtk.status_icon_position_menu popup_function = status_icon_position_menu
if deluge.common.windows_check() or deluge.common.osx_check(): if windows_check() or osx_check():
popup_function = None popup_function = None
button = 0 button = 0
self.tray_menu.popup(None, None, popup_function, button, activate_time, status_icon) self.tray_menu.popup(None, None, popup_function, button, activate_time, status_icon)
@ -353,7 +351,7 @@ class SystemTray(component.Component):
self.mainwindow.quit(shutdown=True) self.mainwindow.quit(shutdown=True)
def on_tray_setbwdown(self, widget, data=None): def on_tray_setbwdown(self, widget, data=None):
if isinstance(widget, gtk.RadioMenuItem): if isinstance(widget, RadioMenuItem):
# ignore previous radiomenuitem value # ignore previous radiomenuitem value
if not widget.get_active(): if not widget.get_active():
return return
@ -362,7 +360,7 @@ class SystemTray(component.Component):
'downloading.svg') 'downloading.svg')
def on_tray_setbwup(self, widget, data=None): def on_tray_setbwup(self, widget, data=None):
if isinstance(widget, gtk.RadioMenuItem): if isinstance(widget, RadioMenuItem):
# ignore previous radiomenuitem value # ignore previous radiomenuitem value
if not widget.get_active(): if not widget.get_active():
return return

View file

@ -9,7 +9,7 @@
import logging import logging
import gtk from gtk import SeparatorToolItem, ToolButton
import deluge.component as component import deluge.component as component
from deluge.configmanager import ConfigManager from deluge.configmanager import ConfigManager
@ -71,7 +71,7 @@ class ToolBar(component.Component):
def add_toolbutton(self, callback, label=None, image=None, stock=None, tooltip=None): def add_toolbutton(self, callback, label=None, image=None, stock=None, tooltip=None):
"""Adds a toolbutton to the toolbar""" """Adds a toolbutton to the toolbar"""
toolbutton = gtk.ToolButton() toolbutton = ToolButton()
if stock is not None: if stock is not None:
toolbutton.set_stock_id(stock) toolbutton.set_stock_id(stock)
if label is not None: if label is not None:
@ -89,7 +89,7 @@ class ToolBar(component.Component):
def add_separator(self, position=None): def add_separator(self, position=None):
"""Adds a separator toolitem""" """Adds a separator toolitem"""
sep = gtk.SeparatorToolItem() sep = SeparatorToolItem()
if position is not None: if position is not None:
self.toolbar.insert(sep, position) self.toolbar.insert(sep, position)
else: else:

View file

@ -12,7 +12,7 @@
import logging import logging
import gtk from gtk import CheckMenuItem, Menu, SeparatorMenuItem
import deluge.component as component import deluge.component as component
from deluge.ui.client import client from deluge.ui.client import client
@ -266,9 +266,9 @@ class TorrentDetails(component.Component):
def generate_menu(self): def generate_menu(self):
"""Generates the checklist menu for all the tabs and attaches it""" """Generates the checklist menu for all the tabs and attaches it"""
menu = gtk.Menu() menu = Menu()
# Create 'All' menuitem and a separator # Create 'All' menuitem and a separator
menuitem = gtk.CheckMenuItem(self.translate_tabs['All'], True) menuitem = CheckMenuItem(self.translate_tabs['All'], True)
menuitem.set_name('All') menuitem.set_name('All')
all_tabs = True all_tabs = True
@ -281,7 +281,7 @@ class TorrentDetails(component.Component):
menu.append(menuitem) menu.append(menuitem)
menuitem = gtk.SeparatorMenuItem() menuitem = SeparatorMenuItem()
menu.append(menuitem) menu.append(menuitem)
# Create a list in order of tabs to create menu # Create a list in order of tabs to create menu
@ -291,7 +291,7 @@ class TorrentDetails(component.Component):
menuitem_list.sort() menuitem_list.sort()
for pos, name in menuitem_list: for pos, name in menuitem_list:
menuitem = gtk.CheckMenuItem(self.translate_tabs[name], True) menuitem = CheckMenuItem(self.translate_tabs[name], True)
menuitem.set_name(name) menuitem.set_name(name)
menuitem.set_active(self.tabs[name].is_visible) menuitem.set_active(self.tabs[name].is_visible)
menuitem.connect('toggled', self._on_menuitem_toggled) menuitem.connect('toggled', self._on_menuitem_toggled)

View file

@ -12,8 +12,9 @@
import logging import logging
from locale import strcoll from locale import strcoll
import gtk
from gobject import TYPE_UINT64, idle_add from gobject import TYPE_UINT64, idle_add
from gtk import ENTRY_ICON_SECONDARY
from gtk.gdk import SHIFT_MASK, keyval_name
from twisted.internet import reactor from twisted.internet import reactor
import deluge.component as component import deluge.component as component
@ -210,7 +211,7 @@ class SearchBox(object):
self.search_pending = reactor.callLater(0.7, self.torrentview.update) self.search_pending = reactor.callLater(0.7, self.torrentview.update)
def on_search_torrents_entry_icon_press(self, entry, icon, event): def on_search_torrents_entry_icon_press(self, entry, icon, event):
if icon != gtk.ENTRY_ICON_SECONDARY: if icon != ENTRY_ICON_SECONDARY:
return return
self.clear_search() self.clear_search()
@ -705,7 +706,7 @@ class TorrentView(ListView, component.Component):
# Handle keyboard shortcuts # Handle keyboard shortcuts
def on_key_press_event(self, widget, event): def on_key_press_event(self, widget, event):
keyname = gtk.gdk.keyval_name(event.keyval) keyname = keyval_name(event.keyval)
if keyname is not None: if keyname is not None:
func = getattr(self, 'keypress_' + keyname.lower(), None) func = getattr(self, 'keypress_' + keyname.lower(), None)
if func: if func:
@ -715,7 +716,7 @@ class TorrentView(ListView, component.Component):
log.debug('keypress_delete') log.debug('keypress_delete')
torrents = self.get_selected_torrents() torrents = self.get_selected_torrents()
if torrents: if torrents:
if event.state & gtk.gdk.SHIFT_MASK: if event.get_state() & SHIFT_MASK:
RemoveTorrentDialog(torrents, delete_files=True).run() RemoveTorrentDialog(torrents, delete_files=True).run()
else: else:
RemoveTorrentDialog(torrents).run() RemoveTorrentDialog(torrents).run()

View file

@ -12,20 +12,10 @@ from __future__ import print_function
import warnings import warnings
from functools import partial from functools import partial
import gtk
from gobject import GError
import deluge.common as common import deluge.common as common
import deluge.component as component import deluge.component as component
from deluge.ui.gtkui.common import (create_blank_pixbuf, get_pixbuf_at_size, icon_alert, icon_checking,
# Status icons.. Create them from file only once to avoid constantly icon_downloading, icon_inactive, icon_queued, icon_seeding)
# re-creating them.
icon_downloading = gtk.gdk.pixbuf_new_from_file(common.get_pixmap('downloading16.png'))
icon_seeding = gtk.gdk.pixbuf_new_from_file(common.get_pixmap('seeding16.png'))
icon_inactive = gtk.gdk.pixbuf_new_from_file(common.get_pixmap('inactive16.png'))
icon_alert = gtk.gdk.pixbuf_new_from_file(common.get_pixmap('alert16.png'))
icon_queued = gtk.gdk.pixbuf_new_from_file(common.get_pixmap('queued16.png'))
icon_checking = gtk.gdk.pixbuf_new_from_file(common.get_pixmap('checking16.png'))
# Holds the info for which status icon to display based on TORRENT_STATE # Holds the info for which status icon to display based on TORRENT_STATE
ICON_STATE = { ICON_STATE = {
@ -58,6 +48,7 @@ func_last_value = {
'cell_data_statusicon': None, 'cell_data_statusicon': None,
'cell_data_queue': None, 'cell_data_queue': None,
'cell_data_progress': [None, None], 'cell_data_progress': [None, None],
'cell_data_peer_progress': None
} }
@ -84,23 +75,12 @@ def cell_data_statusicon(column, cell, model, row, data):
pass pass
def create_blank_pixbuf(): def set_tracker_icon(tracker_icon, cell):
i = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, 16, 16) if tracker_icon:
i.fill(0x00000000) pixbuf = tracker_icon.get_cached_icon()
return i
def set_icon(icon, cell):
if icon:
pixbuf = icon.get_cached_icon()
if pixbuf is None: if pixbuf is None:
try: pixbuf = get_pixbuf_at_size(tracker_icon.get_filename(), 16)
pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(icon.get_filename(), 16, 16) tracker_icon.set_cached_icon(pixbuf)
except GError:
# Failed to load the pixbuf (Bad image file), so set a blank pixbuf
pixbuf = create_blank_pixbuf()
finally:
icon.set_cached_icon(pixbuf)
else: else:
pixbuf = create_blank_pixbuf() pixbuf = create_blank_pixbuf()
@ -118,15 +98,15 @@ def cell_data_trackericon(column, cell, model, row, data):
if host: if host:
if not component.get('TrackerIcons').has(host): if not component.get('TrackerIcons').has(host):
# Set blank icon while waiting for the icon to be loaded # Set blank icon while waiting for the icon to be loaded
set_icon(None, cell) set_tracker_icon(None, cell)
component.get('TrackerIcons').fetch(host) component.get('TrackerIcons').fetch(host)
func_last_value['cell_data_trackericon'] = None func_last_value['cell_data_trackericon'] = None
else: else:
set_icon(component.get('TrackerIcons').get(host), cell) set_tracker_icon(component.get('TrackerIcons').get(host), cell)
# Only set the last value when we have found the icon # Only set the last value when we have found the icon
func_last_value['cell_data_trackericon'] = host func_last_value['cell_data_trackericon'] = host
else: else:
set_icon(None, cell) set_tracker_icon(None, cell)
func_last_value['cell_data_trackericon'] = None func_last_value['cell_data_trackericon'] = None
@ -147,6 +127,14 @@ def cell_data_progress(column, cell, model, row, data):
cell.set_property('text', textstr) cell.set_property('text', textstr)
def cell_data_peer_progress(column, cell, model, row, data):
value = model.get_value(row, data) * 100
if func_last_value['cell_data_peer_progress'] != value:
func_last_value['cell_data_peer_progress'] = value
cell.set_property('value', value)
cell.set_property('text', '%i%%' % value)
def cell_data_queue(column, cell, model, row, data): def cell_data_queue(column, cell, model, row, data):
value = model.get_value(row, data) value = model.get_value(row, data)